[
  {
    "path": ".cargo/config.toml",
    "content": "[target.aarch64-unknown-linux-musl]\nrustflags = [\n    \"-Ctarget-feature=+lse,+crt-static\",\n    \"-Ctarget-cpu=neoverse-n1\",\n    \"-Zunstable-options\",\n    \"-Cpanic=immediate-abort\",\n    \"-Zpanic_abort_tests\",\n    \"-Zthreads=8\",\n]\nlinker = \"./linker/cc-aarch64-linux-musl\"\nar = \"./linker/ar\"\n\n\n[target.x86_64-unknown-linux-musl]\nrustflags = [\n    \"-Ctarget-feature=+crt-static\",\n    \"-Ctarget-cpu=haswell\",\n    \"-Zunstable-options\",\n    \"-Cpanic=immediate-abort\",\n    \"-Zpanic_abort_tests\",\n    \"-Zthreads=8\",\n]\nlinker = \"./linker/cc-x86_64-linux-musl\"\nar = \"./linker/ar\"\n\n[env]\nCC_aarch64_apple_darwin = \"/usr/bin/clang\"\nCC_x86_64_apple_darwin = \"/usr/bin/clang\"\nCXX_aarch64_apple_darwin = \"/usr/bin/clang\"\nCXX_x86_64_apple_darwin = \"/usr/bin/clang\"\n\n[unstable]\nbuild-std = [\"core\", \"compiler_builtins\", \"alloc\", \"std\", \"panic_abort\"]\n"
  },
  {
    "path": ".fleet/settings.json",
    "content": "{\n  \"backend.maxHeapSizeMb\": 2048\n}\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where the package manifests are located.\n# Please see the documentation for all configuration options:\n# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates\n\nversion: 2\nupdates:\n  # Maintain dependencies for GitHub Actions\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: weekly\n\n  # Maintain dependencies for JS\n  - package-ecosystem: \"npm\"\n    directory: \"/\" # Location of package manifests\n    schedule:\n      interval: monthly\n    groups:\n      \"@types\":\n        patterns:\n          - \"@types*\"\n        update-types:\n          - \"minor\"\n          - \"patch\"\n      \"@aws-sdk\":\n        patterns:\n          - \"@aws-sdk*\"\n        update-types:\n          - \"minor\"\n          - \"patch\"\n      aws-cdk:\n        patterns:\n          - \"aws-cdk\"\n          - \"aws-cdk-lib\"\n        update-types:\n          - \"minor\"\n          - \"patch\"\n\n  # Maintain dependencies for Rust\n  - package-ecosystem: cargo\n    directory: \"/\"\n    schedule:\n      interval: daily\n    groups:\n      rustcrypto:\n        patterns:\n          - \"aes*\"\n          - \"cbc\"\n          - \"const-oid\"\n          - \"ctr\"\n          - \"der\"\n          - \"ecdsa\"\n          - \"elliptic-curve\"\n          - \"md-5\"\n          - \"hmac\"\n          - \"p256\"\n          - \"p384\"\n          - \"p521\"\n          - \"pkcs8\"\n          - \"rsa\"\n          - \"spki\"\n          - \"x25519-dalek\"\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "### Issue # (if available)\n\n<!--  **Please post the link to the resolved issue** -->\n\n### Description of changes\n\n<!-- **Please explain what your changes does** -->\n\n### Checklist\n\n- [ ] Created unit tests in `tests/unit` and/or in Rust for my feature if needed\n- [ ] Ran `make fix` to format JS and apply Clippy auto fixes\n- [ ] Made sure my code didn't add any additional warnings: `make check`\n- [ ] Added relevant type info in `types/` directory\n- [ ] Updated documentation if needed ([API.md](API.md)/[README.md](README.md)/Other)\n\n_By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._\n"
  },
  {
    "path": ".github/workflows/build-modules.yml",
    "content": "name: Setup, Build & Test modules\non:\n  workflow_call:\n    inputs:\n      os:\n        required: true\n        type: string\n      platform:\n        required: true\n        type: string\n      arch:\n        required: true\n        type: string\n      toolchain:\n        required: true\n        type: string\n      crypto:\n        required: false\n        type: string\n        default: \"ring\"\n\npermissions:\n  contents: read\n\njobs:\n  build:\n    name: ${{ inputs.arch }}-${{ inputs.platform }}-${{ inputs.crypto }}\n    runs-on: ${{ inputs.os }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n      - name: Setup Rust\n        uses: actions-rust-lang/setup-rust-toolchain@v1\n        with:\n          toolchain: ${{ inputs.toolchain }}\n      - name: Install Windows OpenSSL\n        if: inputs.platform == 'windows' && inputs.crypto == 'openssl'\n        uses: msys2/setup-msys2@v2\n        with:\n          msystem: MINGW64\n          update: true\n          path-type: inherit\n          install: >-\n            mingw-w64-x86_64-gcc\n            mingw-w64-x86_64-openssl\n            mingw-w64-x86_64-pkgconf\n      - name: Set OpenSSL env for Windows\n        if: inputs.platform == 'windows' && inputs.crypto == 'openssl'\n        shell: bash\n        run: |\n          echo \"OPENSSL_DIR=D:/a/_temp/msys64/mingw64\" >> $GITHUB_ENV\n          echo \"OPENSSL_LIB_DIR=D:/a/_temp/msys64/mingw64/lib\" >> $GITHUB_ENV\n          echo \"OPENSSL_INCLUDE_DIR=D:/a/_temp/msys64/mingw64/include\" >> $GITHUB_ENV\n      - name: Map crypto feature to TLS and crypto features\n        id: features\n        shell: bash\n        run: |\n          case \"${{ inputs.crypto }}\" in\n            graviola)\n              echo \"tls_feature=tls-graviola\" >> $GITHUB_OUTPUT\n              echo \"crypto_feature=crypto-graviola\" >> $GITHUB_OUTPUT\n              ;;\n            ring)\n              echo \"tls_feature=tls-ring\" >> $GITHUB_OUTPUT\n              echo \"crypto_feature=crypto-ring\" >> $GITHUB_OUTPUT\n              ;;\n            openssl)\n              echo \"tls_feature=tls-openssl\" >> $GITHUB_OUTPUT\n              echo \"crypto_feature=crypto-openssl\" >> $GITHUB_OUTPUT\n              if [ \"${{ inputs.platform }}\" != \"windows\" ]; then\n                echo \"extra_features=,openssl-vendored\" >> $GITHUB_OUTPUT\n              fi\n              ;;\n            aws-lc)\n              echo \"tls_feature=tls-aws-lc\" >> $GITHUB_OUTPUT\n              echo \"crypto_feature=crypto-ring\" >> $GITHUB_OUTPUT\n              ;;\n            *)\n              echo \"Unknown crypto feature: ${{ inputs.crypto }}\"\n              exit 1\n              ;;\n          esac\n      - name: Run build crates\n        shell: bash\n        env:\n          RUSTFLAGS: \"\"\n          TLS_FEATURE: ${{ steps.features.outputs.tls_feature }}\n          CRYPTO_FEATURE: ${{ steps.features.outputs.crypto_feature }}\n        run: |\n          crates=$(cargo metadata --no-deps --format-version 1 --quiet | jq -r '.packages[] | select(.manifest_path | contains(\"modules/\")) | .name')\n          for crate in $crates; do\n            echo \"Compiling crate: $crate\"\n            if [ \"$crate\" = \"llrt_fetch\" ]; then\n              cargo build -p \"$crate\" --no-default-features --features \"http1,http2,webpki-roots,compression-rust,$TLS_FEATURE\"\n            elif [ \"$crate\" = \"llrt_http\" ]; then\n              cargo build -p \"$crate\" --no-default-features --features \"http1,http2,webpki-roots,$TLS_FEATURE\"\n            elif [ \"$crate\" = \"llrt_crypto\" ]; then\n              cargo build -p \"$crate\" --no-default-features --features \"$CRYPTO_FEATURE\"\n            else\n              cargo build -p \"$crate\"\n            fi\n          done\n      - name: Run build all\n        shell: bash\n        env:\n          TLS_FEATURE: ${{ steps.features.outputs.tls_feature }}\n          CRYPTO_FEATURE: ${{ steps.features.outputs.crypto_feature }}\n          EXTRA_FEATURES: ${{ steps.features.outputs.extra_features }}\n        run: |\n          cargo build -p llrt_modules --no-default-features --features \"base,$TLS_FEATURE,$CRYPTO_FEATURE$EXTRA_FEATURES\"\n      - name: Run tests all\n        shell: bash\n        env:\n          TLS_FEATURE: ${{ steps.features.outputs.tls_feature }}\n          CRYPTO_FEATURE: ${{ steps.features.outputs.crypto_feature }}\n          EXTRA_FEATURES: ${{ steps.features.outputs.extra_features }}\n        run: |\n          cargo test -p llrt_modules --no-default-features --features \"base,$TLS_FEATURE,$CRYPTO_FEATURE$EXTRA_FEATURES\"\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: Setup, Build & Test\non:\n  workflow_call:\n    inputs:\n      os:\n        required: true\n        type: string\n      platform:\n        required: true\n        type: string\n      arch:\n        required: true\n        type: string\n      release:\n        required: false\n        type: string\n      toolchain:\n        required: false\n        type: string\n        default: \"nightly\"\n      crypto:\n        required: false\n        type: string\n        default: \"\"\n\njobs:\n  build:\n    runs-on: ${{ inputs.os }}\n    name: build ${{ inputs.arch }}-${{ inputs.platform }}${{ inputs.crypto && format('-{0}', inputs.crypto) || '' }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n      - name: Checkout submodules\n        run: git submodule update --init --checkout\n      - name: Setup Node.js\n        uses: actions/setup-node@v6\n        with:\n          cache: yarn\n          node-version: lts/*\n      - name: Install Linux dependencies\n        if: inputs.platform == 'linux'\n        run: |\n          sudo apt-get -y update\n          sudo apt-get -y install make nodejs\n          sudo snap install zig --classic --beta\n      - name: Install MacOS dependencies\n        if: inputs.platform == 'darwin'\n        env:\n          HOMEBREW_NO_AUTO_UPDATE: 1\n        run: |\n          /bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"\n          brew install zig make\n      - name: Install zig on windows\n        if: inputs.platform == 'windows'\n        shell: pwsh\n        run: |\n          Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser\n          iex \"& {$(irm get.scoop.sh)} -RunAsAdmin\"\n          scoop install zig\n      - name: Install Windows dependencies\n        if: inputs.platform == 'windows'\n        uses: msys2/setup-msys2@v2\n        with:\n          msystem: MINGW64\n          update: true\n          path-type: inherit\n          install: >-\n            mingw-w64-x86_64-make\n            mingw-w64-x86_64-cmake\n            mingw-w64-x86_64-gcc\n            mingw-w64-x86_64-clang\n            mingw-w64-x86_64-perl\n            zip\n            zstd\n            patch\n            unzip\n\n      - name: Install JavaScript dependencies\n        run: |\n          corepack enable\n          yarn\n      - name: Setup Rust\n        uses: actions-rust-lang/setup-rust-toolchain@v1\n        with:\n          toolchain: ${{ inputs.toolchain }}\n      - name: Map crypto to features\n        id: features\n        if: inputs.crypto != ''\n        shell: bash\n        run: |\n          case \"${{ inputs.crypto }}\" in\n            graviola)\n              echo \"cargo_features=--no-default-features --features macro,crypto-graviola-rust,tls-graviola\" >> $GITHUB_OUTPUT\n              ;;\n            ring)\n              echo \"cargo_features=--no-default-features --features macro,crypto-ring-rust,tls-ring\" >> $GITHUB_OUTPUT\n              ;;\n            openssl)\n              if [ \"${{ inputs.platform }}\" = \"windows\" ]; then\n                echo \"cargo_features=--no-default-features --features macro,crypto-openssl,tls-openssl\" >> $GITHUB_OUTPUT\n              else\n                echo \"cargo_features=--no-default-features --features macro,crypto-openssl,tls-openssl,openssl-vendored\" >> $GITHUB_OUTPUT\n              fi\n              ;;\n            aws-lc)\n              echo \"cargo_features=--no-default-features --features macro,crypto-rust,tls-aws-lc\" >> $GITHUB_OUTPUT\n              ;;\n            *)\n              echo \"Unknown crypto: ${{ inputs.crypto }}\"\n              exit 1\n              ;;\n          esac\n      - name: Run tests\n        if: inputs.platform != 'windows'\n        env:\n          CARGO_FEATURES: ${{ steps.features.outputs.cargo_features }}\n        run: |\n          make test-ci 2>&1\n      - name: Run tests on windows\n        if: inputs.platform == 'windows'\n        shell: msys2 {0}\n        env:\n          CARGO_FEATURES: ${{ steps.features.outputs.cargo_features }}\n        run: |\n          set -e\n          make test-ci 2>&1\n      - name: Build Linux binaries\n        if: inputs.release && inputs.platform == 'linux'\n        run: |\n          make libs-${{ inputs.release }}\n          make release-aws-${{ inputs.release }}\n          make release-aws-${{ inputs.release }}-no-sdk\n          make release-aws-${{ inputs.release }}-full-sdk\n      - name: Build Darwin binaries\n        if: inputs.release && inputs.platform == 'darwin'\n        run: |\n          make llrt-darwin-${{ inputs.release }}.zip\n          make llrt-darwin-${{ inputs.release }}-no-sdk.zip\n          make llrt-darwin-${{ inputs.release }}-full-sdk.zip\n      - name: Build Windows binaries\n        if: inputs.release && inputs.platform == 'windows'\n        shell: msys2 {0}\n        run: |\n          # HACK: Add scoop/shims to PATH\n          export PATH=\"$PATH:/c/Users/$USER/scoop/shims\"\n          make stdlib\n          rm -rf target/ || true\n          make llrt-windows-${{ inputs.release }}.zip\n          make llrt-windows-${{ inputs.release }}-no-sdk.zip\n          make llrt-windows-${{ inputs.release }}-full-sdk.zip\n      - name: Upload artifacts\n        if: inputs.release\n        uses: actions/upload-artifact@v7\n        with:\n          name: artifacts-${{ inputs.platform }}-${{ inputs.arch }}\n          path: |\n            *.zip\n            llrt-container-arm64*\n            llrt-container-x64*\n      - name: Upload changelog\n        if: inputs.release && inputs.platform == 'linux' && inputs.arch == 'x86_64'\n        uses: actions/upload-artifact@v7\n        with:\n          name: changelog\n          path: CHANGELOG.md\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: LLRT CI\non:\n  push:\n    branches:\n      - \"main\"\n  pull_request:\n\n# Only run on the latest ref\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\njobs:\n  check:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n      - name: Setup Rust\n        uses: actions-rust-lang/setup-rust-toolchain@v1\n        with:\n          toolchain: stable\n          components: clippy, rustfmt\n      - name: Format\n        run: cargo fmt --all -- --check\n      - name: Clippy\n        run: | #create mock js files\n          mkdir -p bundle/js\n          for i in {1..5}; do\n            echo \"console.log(123);\" > \"bundle/js/test$i.js\"\n          done\n          cargo clippy --all-targets -- -D warnings\n  build:\n    needs:\n      - check\n    strategy:\n      fail-fast: ${{ startsWith(github.ref, 'refs/tags/') }}\n      matrix:\n        include:\n          # Ubuntu x64\n          - os: ubuntu-latest\n            platform: linux\n            arch: x86_64\n            toolchain: nightly\n            crypto: ring\n          - os: ubuntu-latest\n            platform: linux\n            arch: x86_64\n            toolchain: nightly\n            crypto: aws-lc\n          - os: ubuntu-latest\n            platform: linux\n            arch: x86_64\n            toolchain: nightly\n            crypto: graviola\n          - os: ubuntu-latest\n            platform: linux\n            arch: x86_64\n            toolchain: nightly\n            crypto: openssl\n          # Ubuntu arm64\n          - os: ubuntu-24.04-arm\n            platform: linux\n            arch: aarch64\n            toolchain: nightly\n            crypto: ring\n          - os: ubuntu-24.04-arm\n            platform: linux\n            arch: aarch64\n            toolchain: nightly\n            crypto: aws-lc\n          - os: ubuntu-24.04-arm\n            platform: linux\n            arch: aarch64\n            toolchain: nightly\n            crypto: graviola\n          - os: ubuntu-24.04-arm\n            platform: linux\n            arch: aarch64\n            toolchain: nightly\n            crypto: openssl\n          # macOS arm64\n          - os: macos-latest\n            platform: darwin\n            arch: aarch64\n            toolchain: nightly\n            crypto: ring\n          - os: macos-latest\n            platform: darwin\n            arch: aarch64\n            toolchain: nightly\n            crypto: aws-lc\n          - os: macos-latest\n            platform: darwin\n            arch: aarch64\n            toolchain: nightly\n            crypto: graviola\n          - os: macos-latest\n            platform: darwin\n            arch: aarch64\n            toolchain: nightly\n            crypto: openssl\n          # Windows x64 (ring, openssl, graviola - no aws-lc)\n          - os: windows-latest\n            platform: windows\n            arch: x86_64\n            toolchain: nightly-x86_64-pc-windows-gnu\n            crypto: ring\n          - os: windows-latest\n            platform: windows\n            arch: x86_64\n            toolchain: nightly-x86_64-pc-windows-gnu\n            crypto: openssl\n          - os: windows-latest\n            platform: windows\n            arch: x86_64\n            toolchain: nightly-x86_64-pc-windows-gnu\n            crypto: graviola\n    uses: ./.github/workflows/build.yml\n    with:\n      os: ${{ matrix.os }}\n      platform: ${{ matrix.platform }}\n      arch: ${{ matrix.arch }}\n      toolchain: ${{ matrix.toolchain }}\n      crypto: ${{ matrix.crypto }}\n  modules:\n    needs:\n      - check\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          # Ubuntu x64\n          - os: ubuntu-latest\n            platform: linux\n            arch: x86_64\n            toolchain: stable\n            crypto: ring\n          - os: ubuntu-latest\n            platform: linux\n            arch: x86_64\n            toolchain: stable\n            crypto: aws-lc\n          - os: ubuntu-latest\n            platform: linux\n            arch: x86_64\n            toolchain: stable\n            crypto: graviola\n          - os: ubuntu-latest\n            platform: linux\n            arch: x86_64\n            toolchain: stable\n            crypto: openssl\n          # Ubuntu arm64\n          - os: ubuntu-24.04-arm\n            platform: linux\n            arch: aarch64\n            toolchain: stable\n            crypto: ring\n          - os: ubuntu-24.04-arm\n            platform: linux\n            arch: aarch64\n            toolchain: stable\n            crypto: aws-lc\n          - os: ubuntu-24.04-arm\n            platform: linux\n            arch: aarch64\n            toolchain: stable\n            crypto: graviola\n          - os: ubuntu-24.04-arm\n            platform: linux\n            arch: aarch64\n            toolchain: stable\n            crypto: openssl\n          # macOS arm64\n          - os: macos-latest\n            platform: darwin\n            arch: aarch64\n            toolchain: stable\n            crypto: ring\n          - os: macos-latest\n            platform: darwin\n            arch: aarch64\n            toolchain: stable\n            crypto: aws-lc\n          - os: macos-latest\n            platform: darwin\n            arch: aarch64\n            toolchain: stable\n            crypto: graviola\n          - os: macos-latest\n            platform: darwin\n            arch: aarch64\n            toolchain: stable\n            crypto: openssl\n          # Windows x64 (ring, openssl, graviola - no aws-lc)\n          - os: windows-latest\n            platform: windows\n            arch: x86_64\n            toolchain: stable-x86_64-pc-windows-gnu\n            crypto: ring\n          - os: windows-latest\n            platform: windows\n            arch: x86_64\n            toolchain: stable-x86_64-pc-windows-gnu\n            crypto: openssl\n          - os: windows-latest\n            platform: windows\n            arch: x86_64\n            toolchain: stable-x86_64-pc-windows-gnu\n            crypto: graviola\n    uses: ./.github/workflows/build-modules.yml\n    with:\n      os: ${{ matrix.os }}\n      platform: ${{ matrix.platform }}\n      arch: ${{ matrix.arch }}\n      toolchain: ${{ matrix.toolchain }}\n      crypto: ${{ matrix.crypto }}\n"
  },
  {
    "path": ".github/workflows/publish.yml",
    "content": "name: Publish crates\non:\n  workflow_call:\n    inputs:\n      ref:\n        required: true\n        type: string\n    secrets:\n      CRATES_IO_TOKEN:\n        required: true\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n        with:\n          ref: ${{ inputs.ref }}\n      - name: Setup Rust\n        uses: actions-rust-lang/setup-rust-toolchain@v1\n        with:\n          toolchain: stable\n      - name: Publish utils\n        working-directory: ./llrt_utils\n        run: |\n          cargo publish\n          sleep 10\n        env:\n          CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}\n      - name: Publish modules\n        working-directory: ./llrt_modules\n        run: |\n          cargo publish\n        env:\n          CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: LLRT Release\non:\n  push:\n    tags:\n      - \"v*.*.*\"\n\njobs:\n  build:\n    strategy:\n      fail-fast: ${{ startsWith(github.ref, 'refs/tags/') }}\n      matrix:\n        include:\n          - os: windows-latest\n            platform: windows\n            arch: x86_64\n            release: x64\n            toolchain: nightly-x86_64-pc-windows-gnu\n          - os: ubuntu-latest\n            platform: linux\n            arch: x86_64\n            release: x64\n          - os: ubuntu-24.04-arm\n            platform: linux\n            arch: aarch64\n            release: arm64\n          - os: macos-latest\n            platform: darwin\n            arch: x86_64\n            release: x64\n          - os: macos-latest\n            platform: darwin\n            arch: aarch64\n            release: arm64\n\n    uses: ./.github/workflows/build.yml\n    with:\n      os: ${{ matrix.os }}\n      platform: ${{ matrix.platform }}\n      arch: ${{ matrix.arch }}\n      release: ${{ matrix.release }}\n      toolchain: ${{ matrix.toolchain }}\n  release:\n    permissions:\n      contents: write\n      discussions: write\n    runs-on: ubuntu-latest\n    needs:\n      - build\n    steps:\n      - name: Download artifacts\n        uses: actions/download-artifact@v8\n        with:\n          merge-multiple: true\n      - name: Fix permissions\n        run: |\n          chmod 755 ./llrt-container-x64*\n          chmod 755 ./llrt-container-arm64*\n      - name: Release\n        uses: softprops/action-gh-release@v2\n        with:\n          body_path: ./CHANGELOG.md\n          preserve_order: true\n          prerelease: contains(github.ref, 'beta') || contains(github.ref, 'alpha') || contains(github.ref, 'rc')\n          files: |\n            ./llrt-lambda-x64.zip\n            ./llrt-lambda-x64-no-sdk.zip\n            ./llrt-lambda-x64-full-sdk.zip\n            ./llrt-lambda-arm64.zip\n            ./llrt-lambda-arm64-no-sdk.zip\n            ./llrt-lambda-arm64-full-sdk.zip\n            ./llrt-container-x64\n            ./llrt-container-x64-no-sdk\n            ./llrt-container-x64-full-sdk\n            ./llrt-container-arm64\n            ./llrt-container-arm64-no-sdk\n            ./llrt-container-arm64-full-sdk\n            ./llrt-linux-x64.zip\n            ./llrt-linux-x64-no-sdk.zip\n            ./llrt-linux-x64-full-sdk.zip\n            ./llrt-linux-arm64.zip\n            ./llrt-linux-arm64-no-sdk.zip\n            ./llrt-linux-arm64-full-sdk.zip\n            ./llrt-darwin-x64.zip\n            ./llrt-darwin-x64-no-sdk.zip\n            ./llrt-darwin-x64-full-sdk.zip\n            ./llrt-darwin-arm64.zip\n            ./llrt-darwin-arm64-no-sdk.zip\n            ./llrt-darwin-arm64-full-sdk.zip\n            ./llrt-windows-x64.zip\n            ./llrt-windows-x64-no-sdk.zip\n            ./llrt-windows-x64-full-sdk.zip\n  publish:\n    needs:\n      - build\n    uses: ./.github/workflows/publish.yml\n    with:\n      ref: ${{ github.ref }}\n    secrets:\n      CRATES_IO_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n.idea\n.yarn\n.pnp*\n.tmp-llrt-aws-sdk\n\n/lib\n/target\n/llrt_core/target\n/llrt_core/src/bytecode_cache.rs\n/example/functions/build\n/slask\n/VERSION\n/bundle\n\n*.zip\ncdk.out\nflamegraph.svg\nout.stacks\nyarn-error.log\nllrt-container-*\nbootstrap\n\nnode_modules\n!/fixtures/node_modules\n\ntests/wpt/revision\n/wpt\nwpt_errors.tmp\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"zstd\"]\n\tpath = zstd\n\turl = https://github.com/facebook/zstd.git\n\tupdate = none # Workaround for https://github.com/rust-lang/cargo/issues/4247\n\n[submodule \"wpt\"]\n\tpath = wpt\n\turl = https://github.com/web-platform-tests/wpt\n\tbranch = master\n\tupdate = none # Workaround for https://github.com/rust-lang/cargo/issues/4247\n"
  },
  {
    "path": ".prettierignore",
    "content": "# Ignore web-platform-tests to avoid collisions!\n/wpt\n**/node_modules\n"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"type\": \"lldb\",\n      \"request\": \"launch\",\n      \"name\": \"Debug executable 'llrt'\",\n      \"cargo\": {\n        \"args\": [\"build\"],\n        \"filter\": {\n          \"name\": \"llrt\",\n          \"kind\": \"bin\"\n        }\n      },\n      \"env\": {\n        \"AWS_LAMBDA_FUNCTION_NAME\": \"n/a\",\n        \"AWS_LAMBDA_FUNCTION_MEMORY_SIZE\": \"1\",\n        \"AWS_LAMBDA_FUNCTION_VERSION\": \"1\",\n        //\"AWS_LAMBDA_RUNTIME_API\": \"localhost:3000\",\n        \"_EXIT_LOOP\": \"1\",\n        \"RUST_LOG\": \"llrt=trace,hyper::http=trace\",\n        //\"_HANDLER\": \"index.handler\",\n        \"ISENGARD_PRODUCTION_ACCOUNT\": \"false\",\n        \"AWS_ACCESS_KEY_ID\": \"\",\n        \"AWS_SECRET_ACCESS_KEY\": \"\",\n        \"AWS_SESSION_TOKEN\": \"\"\n      },\n      \"args\": [\"index.mjs\"],\n      \"cwd\": \"${workspaceFolder}\"\n    },\n    {\n      \"type\": \"lldb\",\n      \"request\": \"launch\",\n      \"name\": \"Debug tests 'llrt'\",\n      \"cargo\": {\n        \"args\": [\"build\"],\n        \"filter\": {\n          \"name\": \"llrt\",\n          \"kind\": \"bin\"\n        }\n      },\n      \"env\": {\n        \"AWS_LAMBDA_FUNCTION_NAME\": \"n/a\",\n        \"AWS_LAMBDA_FUNCTION_MEMORY_SIZE\": \"1\",\n        \"AWS_LAMBDA_FUNCTION_VERSION\": \"1\",\n        \"_AWS_LAMBDA_RUNTIME_API\": \"http://localhost:3000\",\n        \"_EXIT_LOOP\": \"1\",\n        \"RUST_LOG\": \"llrt=trace,hyper::http=trace\",\n        //\"_HANDLER\": \"index.handler\",\n        \"ISENGARD_PRODUCTION_ACCOUNT\": \"false\",\n        \"AWS_ACCESS_KEY_ID\": \"\",\n        \"AWS_SECRET_ACCESS_KEY\": \"\",\n        \"AWS_SESSION_TOKEN\": \"\"\n      },\n      \"args\": [\"test\", \"-d\", \"bundle\"],\n      \"cwd\": \"${workspaceFolder}\"\n    }\n  ]\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"cSpell.words\": [\"Abortable\", \"rquickjs\", \"LLRT\", \"llrt\"],\n  \"cmake.configureOnOpen\": false,\n  \"rust-analyzer.showUnlinkedFileNotification\": false,\n  \"editor.formatOnPaste\": true,\n  \"editor.formatOnSave\": true,\n  \"yaml.format.singleQuote\": false\n}\n"
  },
  {
    "path": ".yarnrc.yml",
    "content": "nodeLinker: node-modules\n"
  },
  {
    "path": "API.md",
    "content": "# API documentation\n\n> [!NOTE]\n> The long term goal for LLRT is to become [WinterTC compliant](https://min-common-api.proposal.wintertc.org/). Not every API from Node.js will be supported.\n\n# Node.js API\n\n## assert\n\n[ok](https://nodejs.org/api/assert.html#assertokvalue-message)\n\n## async_hooks\n\n### Static methods\n\n[createHook](https://nodejs.org/api/async_hooks.html#async_hookscreatehookcallbacks)\n\n[currentId](https://nodejs.org/api/async_hooks.html#async_hooksexecutionasyncid)\n\n[executionAsyncId](https://nodejs.org/api/async_hooks.html#async_hooksexecutionasyncid)\n\n[triggerAsyncId](https://nodejs.org/api/async_hooks.html#async_hookstriggerasyncid)\n\n### Class: AsyncHook\n\n[enable](https://nodejs.org/api/async_hooks.html#asynchookenable)\n\n[disable](https://nodejs.org/api/async_hooks.html#asynchookdisable)\n\n#### Hook callbacks\n\n[init](https://nodejs.org/api/async_hooks.html#initasyncid-type-triggerasyncid-resource)\n\n[before](https://nodejs.org/api/async_hooks.html#beforeasyncid)\n\n[after](https://nodejs.org/api/async_hooks.html#afterasyncid)\n\n[destroy](https://nodejs.org/api/async_hooks.html#destroyasyncid)\n\n[promiseResolve](https://nodejs.org/api/async_hooks.html#promiseresolveasyncid)\n\n## buffer\n\n### Static methods\n\n[alloc](https://nodejs.org/api/buffer.html#static-method-bufferallocsize-fill-encoding)\n\n[allocUnsafe](https://nodejs.org/api/buffer.html#static-method-bufferallocunsafesize)\n\n[allocUnsafeSlow](https://nodejs.org/api/buffer.html#static-method-bufferallocunsafeslowsize)\n\n[byteLength](https://nodejs.org/api/buffer.html#static-method-bufferbytelengthstring-encoding)\n\n[concat](https://nodejs.org/api/buffer.html#static-method-bufferconcatlist-totallength)\n\n[from](https://nodejs.org/api/buffer.html#static-method-bufferfromarray)\n\n[isBuffer](https://nodejs.org/api/buffer.html#static-method-bufferisbufferobj)\n\n[isEncoding](https://nodejs.org/api/buffer.html#static-method-bufferisencodingencoding)\n\n### Prototype methods\n\n[copy](https://nodejs.org/api/buffer.html#bufcopytarget-targetstart-sourcestart-sourceend)\n\n[readBigInt64BE](https://nodejs.org/api/buffer.html#bufreadbigint64beoffset)\n\n[readBigInt64LE](https://nodejs.org/api/buffer.html#bufreadbigint64leoffset)\n\n[readDoubleBE](https://nodejs.org/api/buffer.html#bufreaddoublebeoffset)\n\n[readDoubleLE](https://nodejs.org/api/buffer.html#bufreaddoubleleoffset)\n\n[readFloatBE](https://nodejs.org/api/buffer.html#bufreadfloatbeoffset)\n\n[readFloatLE](https://nodejs.org/api/buffer.html#bufreadfloatleoffset)\n\n[readInt8](https://nodejs.org/api/buffer.html#bufreadint8offset)\n\n[readInt16BE](https://nodejs.org/api/buffer.html#bufreadint16beoffset)\n\n[readInt16LE](https://nodejs.org/api/buffer.html#bufreadint16leoffset)\n\n[readInt32BE](https://nodejs.org/api/buffer.html#bufreadint32beoffset)\n\n[readInt32LE](https://nodejs.org/api/buffer.html#bufreadint32leoffset)\n\n[readUInt8](https://nodejs.org/api/buffer.html#bufreaduint8offset)\n\n[readUInt16BE](https://nodejs.org/api/buffer.html#bufreaduint16beoffset)\n\n[readUInt16LE](https://nodejs.org/api/buffer.html#bufreaduint16leoffset)\n\n[readUInt32BE](https://nodejs.org/api/buffer.html#bufreaduint32beoffset)\n\n[readUInt32LE](https://nodejs.org/api/buffer.html#bufreaduint32leoffset)\n\n[subarray](https://nodejs.org/api/buffer.html#bufsubarraystart-end)\n\n[toString](https://nodejs.org/api/buffer.html#buftostringencoding-start-end)\n\n[write](https://nodejs.org/api/buffer.html#bufwritestring-offset-length-encoding)\n\n[writeBigInt64BE](https://nodejs.org/api/buffer.html#bufwritebigint64bevalue-offset)\n\n[writeBigInt64LE](https://nodejs.org/api/buffer.html#bufwritebigint64levalue-offset)\n\n[writeDoubleBE](https://nodejs.org/api/buffer.html#bufwritedoublebevalue-offset)\n\n[writeDoubleLE](https://nodejs.org/api/buffer.html#bufwritedoublelevalue-offset)\n\n[writeFloatBE](https://nodejs.org/api/buffer.html#bufwritefloatbevalue-offset)\n\n[writeFloatLE](https://nodejs.org/api/buffer.html#bufwritefloatlevalue-offset)\n\n[writeInt8](https://nodejs.org/api/buffer.html#bufwriteint8value-offset)\n\n[writeInt16BE](https://nodejs.org/api/buffer.html#bufwriteint16bevalue-offset)\n\n[writeInt16LE](https://nodejs.org/api/buffer.html#bufwriteint16levalue-offset)\n\n[writeInt32BE](https://nodejs.org/api/buffer.html#bufwriteint32bevalue-offset)\n\n[writeInt32LE](https://nodejs.org/api/buffer.html#bufwriteint32levalue-offset)\n\n[writeUInt8](https://nodejs.org/api/buffer.html#bufwriteuint8value-offset)\n\n[writeUInt16BE](https://nodejs.org/api/buffer.html#bufwriteuint16bevalue-offset)\n\n[writeUInt16LE](https://nodejs.org/api/buffer.html#bufwriteuint16levalue-offset)\n\n[writeUInt32BE](https://nodejs.org/api/buffer.html#bufwriteuint32bevalue-offset)\n\n[writeUInt32LE](https://nodejs.org/api/buffer.html#bufwriteuint32levalue-offset)\n\n### Constants\n\n[constants.MAX_LENGTH](https://nodejs.org/api/buffer.html#bufferconstantsmax_length)\n\n[constants.MAX_STRING_LENGTH](https://nodejs.org/api/buffer.html#bufferconstantsmax_string_length)\n\nEverything else inherited from [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array)\n\n## child_process\n\n> [!WARNING]\n> `spawn` uses native streams that is not 100% compatible with the Node.js Streams API.\n\n[spawn](https://nodejs.org/api/child_process.html#child_processspawncommand-args-options)\n\n## console\n\n[Console](https://nodejs.org/api/console.html#class-console)\n\n## crypto\n\n[createHash](https://nodejs.org/api/crypto.html#cryptocreatehashalgorithm-options)\n\n[createHmac](https://nodejs.org/api/crypto.html#cryptocreatehmacalgorithm-key-options)\n\n[getRandomValues](https://nodejs.org/api/crypto.html#cryptogetrandomvaluestypedarray)\n\n[randomBytes](https://nodejs.org/api/crypto.html#cryptorandombytessize-callback)\n\n[randomFill](https://nodejs.org/api/crypto.html#cryptorandomfillbuffer-offset-size-callback)\n\n[randomFillSync](https://nodejs.org/api/crypto.html#cryptorandomfillsyncbuffer-offset-size)\n\n[randomInt](https://nodejs.org/api/crypto.html#cryptorandomintmin-max-callback)\n\n[randomUUID](https://nodejs.org/api/crypto.html#cryptorandomuuidoptions)\n\n[webcrypto](https://nodejs.org/api/crypto.html#cryptowebcrypto)\n\n### LLRT specific hash classes\n\nLightweight and fast hash classes for LLRT.\n\n- `Md5`\n- `Sha1`\n- `Sha256`\n- `Sha384`\n- `Sha512`\n- `Crc32`\n- `Crc32c`\n\n## crypto.subtle\n\n[subtle.decrypt](https://nodejs.org/api/webcrypto.html#subtledecryptalgorithm-key-data)\n\n[subtle.deriveBits](https://nodejs.org/api/webcrypto.html#subtlederivebitsalgorithm-basekey-length)\n\n[subtle.digest](https://nodejs.org/api/webcrypto.html#subtledigestalgorithm-data)\n\n[subtle.encrypt](https://nodejs.org/api/webcrypto.html#subtleencryptalgorithm-key-data)\n\n[subtle.exportKey](https://nodejs.org/api/webcrypto.html#subtleexportkeyformat-key)\n\n[subtle.generateKey](https://nodejs.org/api/webcrypto.html#subtlegeneratekeyalgorithm-extractable-keyusages)\n\n[subtle.importKey](https://nodejs.org/api/webcrypto.html#subtleimportkeyformat-keydata-algorithm-extractable-keyusages)\n\n[subtle.sign](https://nodejs.org/api/webcrypto.html#subtlesignalgorithm-key-data)\n\n[subtle.verify](https://nodejs.org/api/webcrypto.html#subtleverifyalgorithm-key-signature-datah)\n\n## dgram\n\n[createSocket](https://nodejs.org/api/dgram.html#dgramcreatesocketoptions-callback)\n\n### Class: dgram.Socket\n\n[address](https://nodejs.org/api/dgram.html#socketaddress)\n\n[bind](https://nodejs.org/api/dgram.html#socketbindport-address-callback)\n\n[close](https://nodejs.org/api/dgram.html#socketclosecallback)\n\n[ref](https://nodejs.org/api/dgram.html#socketref)\n\n[send](https://nodejs.org/api/dgram.html#socketsendmsg-offset-length-port-address-callback)\n\n[unref](hhttps://nodejs.org/api/dgram.html#socketunref)\n\n## dns\n\n[lookup](https://nodejs.org/api/dns.html#dnslookuphostname-options-callback)\n\n## events\n\n[EventEmitter](https://nodejs.org/api/events.html#class-eventemitter)\n\n## fs\n\n[accessSync](https://nodejs.org/api/fs.html#fsaccesssyncpath-mode)\n\n[constants](https://nodejs.org/api/fs.html#file-access-constants)\n\n[lstatSync](https://nodejs.org/api/fs.html#fslstatsyncpath-options)\n\n[mkdirSync](https://nodejs.org/api/fs.html#fsmkdirsyncpath-options)\n\n[mkdtempSync](https://nodejs.org/api/fs.html#fsmkdtempsyncprefix-options)\n\n[readdirSync](https://nodejs.org/api/fs.html#fsreaddirsyncpath-options)\n\n[readFileSync](https://nodejs.org/api/fs.html#fsreadfilesyncpath-options)\n\n[rmdirSync](https://nodejs.org/api/fs.html#fsrmdirsyncpath-options)\n\n[rmSync](https://nodejs.org/api/fs.html#fsrmsyncpath-options)\n\n[statSync](https://nodejs.org/api/fs.html#fsstatsyncpath-options)\n\n[writeFileSync](https://nodejs.org/api/fs.html#fswritefilesyncfile-data-options)\n\n[chmodSync](https://nodejs.org/api/fs.html#fschmodsyncpath-mode)\n\n[renameSync](https://nodejs.org/api/fs.html#fsrenamesyncoldpath-newpath)\n\n[symlinkSync](https://nodejs.org/api/fs.html#fssymlinksynctarget-path-type)\n\n## fs/promises\n\n[access](https://nodejs.org/api/fs.html#fsstatpath-options-callback)\n\n[constants](https://nodejs.org/api/fs.html#file-access-constants)\n\n[lstat](https://nodejs.org/api/fs.html#fspromiseslstatpath-options)\n\n[mkdir](https://nodejs.org/api/fs.html#fsmkdirpath-options-callback)\n\n[mkdtemp](https://nodejs.org/api/fs.html#fsmkdtempprefix-options-callback)\n\n[open](https://nodejs.org/api/fs.html#fspromisesopenpath-flags-mode)\n\n[readdir](https://nodejs.org/api/fs.html#fspromisesreaddirpath-options)\n\n[readFile](https://nodejs.org/api/fs.html#filehandlereadfileoptions)\n\n[rm](https://nodejs.org/api/fs.html#fsrmpath-options-callback)\n\n[rmdir](https://nodejs.org/api/fs.html#fsrmdirpath-options-callback)\n\n[stat](https://nodejs.org/api/fs.html#fsstatpath-options-callback)\n\n[writeFile](https://nodejs.org/api/fs.html#fspromiseswritefilefile-data-options)\n\n[chmod](https://nodejs.org/api/fs.html#fspromiseschmodpath-mode)\n\n[rename](https://nodejs.org/api/fs.html#fspromisesrenameoldpath-newpath)\n\n[symlink](https://nodejs.org/api/fs.html#fspromisessymlinktarget-path-type)\n\n## https\n\n[Agent](https://nodejs.org/api/https.html#class-httpsagent)\n\n## module\n\n[builtinModules](https://nodejs.org/api/module.html#modulebuiltinmodules)\n\n[createRequire](https://nodejs.org/api/module.html#modulecreaterequirefilename)\n\n> [!NOTE]\n> `require` is available from esm modules natively. This function is just for compatibility\n\n[isBuiltin](https://nodejs.org/api/module.html#moduleisbuiltinmodulename)\n\n[registerHooks](https://nodejs.org/api/module.html#moduleregisterhooksoptions)\n\n## net\n\n> [!WARNING]\n> These APIs uses native streams that is not 100% compatible with the Node.js Streams API. Server APIs like `createSever` provides limited functionality useful for testing purposes. Serverless applications typically don't expose servers. Some server options are not supported:\n> `highWaterMark`, `pauseOnConnect`, `keepAlive`, `noDelay`, `keepAliveInitialDelay`\n\n[connect](https://nodejs.org/api/net.html#netconnect)\n\n[createConnection](https://nodejs.org/api/net.html#netcreateconnection)\n\n[createServer](https://nodejs.org/api/net.html#netcreateserveroptions-connectionlistener)\n\n## os\n\n[arch](https://nodejs.org/api/os.html#osarch)\n\n[availableParallelism](https://nodejs.org/api/os.html#osavailableparallelism)\n\n[cpus](https://nodejs.org/api/os.html#oscpus)\n\n[devNull](https://nodejs.org/api/os.html#osdevnull)\n\n[endianness](https://nodejs.org/api/os.html#osendianness)\n\n[EOL](https://nodejs.org/api/os.html#oseol)\n\n[freemem](https://nodejs.org/api/os.html#osfreemem)\n\n[getPriority](https://nodejs.org/api/os.html#osgetprioritypid)\n\n[homedir](https://nodejs.org/api/os.html#oshomedir)\n\n[hostname](https://nodejs.org/api/os.html#oshostname)\n\n[loadavg](https://nodejs.org/api/os.html#osloadavg)\n\n[machine](https://nodejs.org/api/os.html#osmachine)\n\n[networkInterfaces](https://nodejs.org/api/os.html#osnetworkinterfaces)\n\n[platform](https://nodejs.org/api/os.html#osplatform)\n\n[release](https://nodejs.org/api/os.html#osrelease)\n\n[setPriority](https://nodejs.org/api/os.html#ossetprioritypid-priority)\n\n[tmpdir](https://nodejs.org/api/os.html#osplatform)\n\n[totalmem](https://nodejs.org/api/os.html#ostotalmem)\n\n[type](https://nodejs.org/api/os.html#ostype)\n\n[uptime](https://nodejs.org/api/os.html#osuptime)\n\n[userInfo](https://nodejs.org/api/os.html#osuserinfooptions)\n\n[version](https://nodejs.org/api/os.html#osversion)\n\n## path\n\n[basename](https://nodejs.org/api/path.html#pathbasenamepath-suffix)\n\n[delimiter](https://nodejs.org/api/path.html#pathdelimiter)\n\n[dirname](https://nodejs.org/api/path.html#pathdirnamepath)\n\n[extname](https://nodejs.org/api/path.html#pathextnamepath)\n\n[format](https://nodejs.org/api/path.html#pathformatpathobject)\n\n[isAbsolute](https://nodejs.org/api/path.html#pathisabsolutepath)\n\n[join](https://nodejs.org/api/path.html#pathjoinpaths)\n\n[normalize](https://nodejs.org/api/path.html#pathnormalizepath)\n\n[parse](https://nodejs.org/api/path.html#pathparsepath)\n\n[relative](https://nodejs.org/api/path.html#pathrelativefrom-to)\n\n[resolve](https://nodejs.org/api/path.html#pathresolvepaths)\n\n## perf_hooks\n\n_performance is available globally_\n\n[performance.now](https://nodejs.org/api/perf_hooks.html#performancenow)\n\n## process\n\n_process is available globally_\n\n[arch](https://nodejs.org/api/process.html#processarch)\n\n[argv](https://nodejs.org/api/process.html#processargv)\n\n[argv0](https://nodejs.org/api/process.html#processargv0)\n\n[cwd](https://nodejs.org/api/process.html#processcwd)\n\n[env](https://nodejs.org/api/process.html#processenv)\n\n[exit](https://nodejs.org/api/process.html#processexitcode)\n\n[exitCode](https://nodejs.org/api/process.html#processexitcode-1)\n\n[getegid](https://nodejs.org/api/process.html#processgetegid)\n\n[geteuid](https://nodejs.org/api/process.html#processgeteuid)\n\n[getgid](https://nodejs.org/api/process.html#processgetgid)\n\n[getuid](https://nodejs.org/api/process.html#processgetuid)\n\n[hrtime](https://nodejs.org/api/process.html#processhrtime)\n\n[id](https://nodejs.org/api/process.html#processpid)\n\n[kill](https://nodejs.org/api/process.html#processkillpid-signal)\n\n[platform](https://nodejs.org/api/process.html#processplatform)\n\n[release](https://nodejs.org/api/process.html#processrelease)\n\n[setegid](https://nodejs.org/api/process.html#processsetegidgid)\n\n[seteuid](https://nodejs.org/api/process.html#processseteuiduid)\n\n[setgid](https://nodejs.org/api/process.html#processsetgidgid)\n\n[setuid](https://nodejs.org/api/process.html#processsetuiduid)\n\n[version](https://nodejs.org/api/process.html#processversion)\n\n[versions](https://nodejs.org/api/process.html#processversions)\n\n## stream\n\n[Duplex](https://nodejs.org/api/stream.html#class-streamduplex)\n\n[PassThrough](https://nodejs.org/api/stream.html#class-streampassthrough)\n\n[Readable](https://nodejs.org/api/stream.html#class-streamreadable)\n\n[Stream](https://nodejs.org/api/stream.html#class-stream)\n\n[Transform](https://nodejs.org/api/stream.html#class-streamtransform)\n\n[Writable](https://nodejs.org/api/stream.html#class-streamwritable)\n\n[finished](https://nodejs.org/api/stream.html#streamfinishedstream-options-callback)\n\n[pipeline](https://nodejs.org/api/stream.html#streampipelinestreams-callback)\n\n## stream/promises\n\n[finished](https://nodejs.org/api/stream.html#streamfinishedstream-options-callback)\n\n[pipeline](https://nodejs.org/api/stream.html#streampipelinestreams-callback)\n\n## string_decoder\n\n[StringDecoder](https://nodejs.org/api/string_decoder.html#class-stringdecoder)\n\n## timers\n\n_Also available globally_\n\n[clearImmediate](https://nodejs.org/api/timers.html#clearimmediateimmediate)\n\n[clearInterval](https://nodejs.org/api/timers.html#clearintervaltimeout)\n\n[clearTimeout](https://nodejs.org/api/timers.html#cleartimeouttimeout)\n\n[setImmediate](https://nodejs.org/api/timers.html#setimmediatecallback-args)\n\n[setInterval](https://nodejs.org/api/timers.html#setintervalcallback-delay-args)\n\n[setTimeout](https://nodejs.org/api/timers.html#settimeoutcallback-delay-args)\n\n## tty\n\n[isatty](https://nodejs.org/api/tty.html#ttyisattyfd)\n\n## url\n\n### Class\n\n[URL](https://nodejs.org/api/url.html#class-url)\n\n[URLSearchParams](https://nodejs.org/api/url.html#class-urlsearchparams)\n\n### Prototype methods\n\n[domainToASCII](https://nodejs.org/api/url.html#urldomaintoasciidomain)\n\n[domainToUnicode](https://nodejs.org/api/url.html#urldomaintounicodedomain)\n\n[fileURLToPath](https://nodejs.org/api/url.html#urlfileurltopathurl-options)\n\n[format](https://nodejs.org/api/url.html#urlformaturl-options)\n\n[pathToFileURL](https://nodejs.org/api/url.html#urlpathtofileurlpath-options)\n\n[urlToHttpOptions](https://nodejs.org/api/url.html#urlurltohttpoptionsurl)\n\n## util\n\n> [!IMPORTANT]\n> Supported encodings: hex, base64, utf-8, utf-16le, windows-1252 and their aliases.\n\n[format](https://nodejs.org/api/util.html#utilformatformat-args)\n\n[inherits](https://nodejs.org/api/util.html#utilinheritsconstructor-superconstructor)\n\n[TextDecoder](https://nodejs.org/api/util.html#class-utiltextdecoder)\n\n[TextEncoder](https://nodejs.org/api/util.html#class-utiltextdecoder)\n\n## zlib\n\n### Convenience methods\n\n[deflate](https://nodejs.org/api/zlib.html#zlibdeflatebuffer-options-callback)\n\n[deflateSync](https://nodejs.org/api/zlib.html#zlibdeflatesyncbuffer-options)\n\n[deflateRaw](https://nodejs.org/api/zlib.html#zlibdeflaterawbuffer-options-callback)\n\n[deflateRawSync](https://nodejs.org/api/zlib.html#zlibdeflaterawsyncbuffer-options)\n\n[gzip](https://nodejs.org/api/zlib.html#zlibgzipbuffer-options-callback)\n\n[gzipSync](https://nodejs.org/api/zlib.html#zlibgzipsyncbuffer-options)\n\n[inflate](https://nodejs.org/api/zlib.html#zlibinflatebuffer-options-callback)\n\n[inflateSync](https://nodejs.org/api/zlib.html#zlibinflatesyncbuffer-options)\n\n[inflateRaw](https://nodejs.org/api/zlib.html#zlibinflaterawbuffer-options-callback)\n\n[inflateRawSync](https://nodejs.org/api/zlib.html#zlibinflaterawsyncbuffer-options)\n\n[gunzip](https://nodejs.org/api/zlib.html#zlibgunzipbuffer-options-callback)\n\n[gunzipSync](https://nodejs.org/api/zlib.html#zlibgunzipsyncbuffer-options)\n\n[brotliCompress](https://nodejs.org/api/zlib.html#zlibbrotlicompressbuffer-options-callback)\n\n[brotliCompressSync](https://nodejs.org/api/zlib.html#zlibbrotlicompresssyncbuffer-options)\n\n[brotliDecompress](https://nodejs.org/api/zlib.html#zlibbrotlidecompressbuffer-options-callback)\n\n[brotliDecompressSync](https://nodejs.org/api/zlib.html#zlibbrotlidecompresssyncbuffer-options)\n\n[zstdCompress](https://nodejs.org/api/zlib.html#zlibzstdcompressbuffer-options-callback)\n\n[zstdCompressSync](https://nodejs.org/api/zlib.html#zlibzstdcompresssyncbuffer-options)\n\n[zstdDecompress](https://nodejs.org/api/zlib.html#zlibzstddecompressbuffer-options-callback)\n\n[zstdDecompressSync](https://nodejs.org/api/zlib.html#zlibzstddecompresssyncbuffer-options)\n\n# LLRT API\n\n## llrt:hex\n\n```typescript\nexport function encode(\n  value: string | Array | ArrayBuffer | Uint8Array\n): string;\nexport function decode(value: string): Uint8Array;\n```\n\n## llrt:timezone\n\nLightweight timezone support for LLRT. Provides timezone offset calculations and a minimal `Intl.DateTimeFormat` implementation for dayjs and similar library compatibility.\n\n```typescript\ninterface Timezone {\n  /**\n   * Get the UTC offset in minutes for a timezone at a given time.\n   * Returns a positive value for timezones ahead of UTC (e.g., 540 for Asia/Tokyo)\n   * and a negative value for timezones behind UTC (e.g., -420 for America/Denver).\n   * Automatically handles DST transitions.\n   */\n  getOffset(timezone: string, epochMs: number): number;\n\n  /**\n   * List all available IANA timezone names.\n   */\n  list(): string[];\n}\n\ndeclare var Timezone: Timezone;\n\nexport { Timezone };\n```\n\n### Example\n\n```javascript\nimport { Timezone } from \"llrt:timezone\";\n\n// Get current offset for Denver (handles DST automatically)\nconst offset = Timezone.getOffset(\"America/Denver\", Date.now());\n// Returns -420 (UTC-7) in winter, -360 (UTC-6) in summer\n\n// Check DST transition\nconst beforeDst = new Date(\"2024-03-09T12:00:00Z\").getTime();\nconst afterDst = new Date(\"2024-03-11T12:00:00Z\").getTime();\nconsole.log(Timezone.getOffset(\"America/Denver\", beforeDst)); // -420\nconsole.log(Timezone.getOffset(\"America/Denver\", afterDst)); // -360\n\n// List all available timezones\nconst zones = Timezone.list();\n```\n\n### Intl.DateTimeFormat\n\nLLRT provides a minimal `Intl.DateTimeFormat` implementation focused on timezone support. This enables libraries like dayjs to work with timezone conversions transparently.\n\n```javascript\n// Create a formatter for a specific timezone\nconst formatter = new Intl.DateTimeFormat(\"en-US\", {\n  timeZone: \"America/Denver\",\n  hour12: false,\n  year: \"numeric\",\n  month: \"2-digit\",\n  day: \"2-digit\",\n  hour: \"2-digit\",\n  minute: \"2-digit\",\n  second: \"2-digit\",\n});\n\n// Format a date\nconst date = new Date(\"2022-03-02T15:45:34Z\");\nconsole.log(formatter.format(date)); // \"03/02/2022, 08:45:34\"\n\n// Get formatted parts\nconst parts = formatter.formatToParts(date);\n// [{ type: \"month\", value: \"03\" }, { type: \"literal\", value: \"/\" }, ...]\n\n// Get resolved options\nconst options = formatter.resolvedOptions();\nconsole.log(options.timeZone); // \"America/Denver\"\n```\n\n### Date.prototype.toLocaleString with timezone\n\n`Date.prototype.toLocaleString` is enhanced to support the `timeZone` option:\n\n```javascript\nconst date = new Date(\"2022-03-02T15:45:34Z\");\n\n// Convert to Denver time\nconsole.log(date.toLocaleString(\"en-US\", { timeZone: \"America/Denver\" }));\n// \"03/02/2022, 8:45:34 AM\"\n\n// Convert to Tokyo time\nconsole.log(date.toLocaleString(\"en-US\", { timeZone: \"Asia/Tokyo\" }));\n// \"03/03/2022, 12:45:34 AM\"\n```\n\n### Using with dayjs\n\nThe timezone module enables dayjs timezone support without polyfills:\n\n```javascript\nconst dayjs = require(\"dayjs\");\nconst utc = require(\"dayjs/plugin/utc\");\nconst timezone = require(\"dayjs/plugin/timezone\");\n\ndayjs.extend(utc);\ndayjs.extend(timezone);\n\n// Convert between timezones\nconst date = dayjs(\"2022-03-02T15:45:34Z\");\nconsole.log(date.tz(\"America/Denver\").format()); // \"2022-03-02T08:45:34-07:00\"\nconsole.log(date.tz(\"Asia/Tokyo\").format()); // \"2022-03-03T00:45:34+09:00\"\n\n// Get start of day in a specific timezone\nconst denver = date.tz(\"America/Denver\");\nconsole.log(denver.startOf(\"day\").format()); // \"2022-03-02T00:00:00-07:00\"\n```\n\n## llrt:qjs\n\n```typescript\ninterface MemoryInfo {\n  malloc_size: number;\n  malloc_limit: number;\n  memory_used_size: number;\n  malloc_count: number;\n  memory_used_count: number;\n  atom_count: number;\n  atom_size: number;\n  str_count: number;\n  str_size: number;\n  obj_count: number;\n  obj_size: number;\n  prop_count: number;\n  prop_size: number;\n  shape_count: number;\n  shape_size: number;\n  js_func_count: number;\n  js_func_size: number;\n  js_func_code_size: number;\n  js_func_pc2line_count: number;\n  js_func_pc2line_size: number;\n  c_func_count: number;\n  array_count: number;\n  fast_array_count: number;\n  fast_array_elements: number;\n  binary_object_count: number;\n  binary_object_size: number;\n}\nexport function ComputeMemoryUsage(): MemoryInfo;\n```\n\n## llrt:xml\n\nA lightweight and fast XML parser and builder\n\n```typescript\nexport class XmlText {\n  constructor(text: string);\n  toString(): string;\n}\n\nexport class XmlNode {\n  constructor(name: string);\n  withName(name: string): this;\n  addAttribute(name: string, value: string): this;\n  addChildNode(node: XmlNode | XmlText): this;\n  removeAttribute(name: string): this;\n  toString(): string;\n}\n\ntype XmlParserOptions = {\n    ignoreAttributes?: boolean;\n    attributeNamePrefix?: string;\n    textNodeName?: string;\n    attributeValueProcessor?: (attrName: string, attrValue: string, jpath: string) => unknown;\n    tagValueProcessor?: (attrName: string, attrValue: string, jpath: string, hasAttributes: boolean) => unknown;\n}\nexport class XMLParser(options?: XmlParserOptions){\n    parse(xml:string):object\n}\n```\n\n\n## llrt:util\n\n```typescript\nexport function dimensions(): [number, number];\nexport function load(path: string): any;\nexport function print(value: any): void;\n```\n\n\n# Web Platform API\n\n## CONSOLE\n\n[Console](https://developer.mozilla.org/en-US/docs/Web/API/console)\n\n## DOM\n\n[AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)\n\n[AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal)\n\n[CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent)\n\n[Event](https://developer.mozilla.org/en-US/docs/Web/API/Event)\n\n[EventTarget](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget)\n\n## ECMASCRIPT\n\n[globalThis](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis)\n\n## ENCODING\n\n[TextDecoder](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder)\n\n[TextEncoder](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder)\n\n## FETCH\n\n[Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers)\n\n[Request](https://developer.mozilla.org/en-US/docs/Web/API/Request)\n\n[Response](https://developer.mozilla.org/en-US/docs/Web/API/Response)\n\n[fetch](https://developer.mozilla.org/en-US/docs/Web/API/Headers)\n\n> [!IMPORTANT]\n> There are some differences with the [WHATWG standard](https://fetch.spec.whatwg.org). Mainly browser specific behavior is removed:\n>\n> - `keepalive` is always true\n> - `request.body` can only be `string`, `Array`, `ArrayBuffer` or `Uint8Array`\n> - `response.body` returns `null`. Use `response.text()`, `response.json()` etc\n> - `mode`, `credentials`, `referrerPolicy`, `priority`, `cache` is not available/applicable\n\n## FILEAPI\n\n[Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob)\n\n[File](https://developer.mozilla.org/en-US/docs/Web/API/File)\n\n## HR-TIME\n\n[performance.now](https://developer.mozilla.org/en-US/docs/Web/API/Performance/now)\n\n[performance.timeOrigin](https://developer.mozilla.org/en-US/docs/Web/API/Performance/timeOrigin)\n\n## HTML\n\n[atob](https://developer.mozilla.org/en-US/docs/Web/API/atob)\n\n[btoa](https://developer.mozilla.org/en-US/docs/Web/API/btoa)\n\n[clearInterval](https://developer.mozilla.org/en-US/docs/Web/API/Window/clearInterval)\n\n[clearTimeout](https://developer.mozilla.org/en-US/docs/Web/API/Window/clearTimeout)\n\n[navigator](https://developer.mozilla.org/en-US/docs/Web/API/Window/navigator)\n\n[queueMicrotask](https://developer.mozilla.org/en-US/docs/Web/API/Window/queueMicrotask)\n\n[setInterval](https://developer.mozilla.org/en-US/docs/Web/API/Window/setInterval)\n\n[setTimeout](https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout)\n\n[structuredClone](https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone)\n\n[userAgent](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/userAgent)\n\n## STREAMS\n\n[ByteLengthQueuingStrategy](https://developer.mozilla.org/en-US/docs/Web/API/ByteLengthQueuingStrategy)\n\n[CountQueuingStrategy](https://developer.mozilla.org/en-US/docs/Web/API/CountQueuingStrategy)\n\n[ReadableByteStreamController](https://developer.mozilla.org/en-US/docs/Web/API/ReadableByteStreamController)\n\n[ReadableStream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)\n\n[ReadableStreamBYOBReader](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamBYOBReader)\n\n[ReadableStreamBYOBRequest](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamBYOBRequest)\n\n[ReadableStreamDefaultController](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultController)\n\n[ReadableStreamDefaultReader](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader)\n\n[WritableStream](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream)\n\n[WritableStreamDefaultController](https://developer.mozilla.org/en-US/docs/Web/API/WritableStreamDefaultController)\n\n[WritableStreamDefaultWriter](https://developer.mozilla.org/en-US/docs/Web/API/WritableStreamDefaultWriter)\n\n## URL\n\n[URL](https://developer.mozilla.org/en-US/docs/Web/API/URL)\n\n[URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)\n\n## WEBCRYPTO\n\n[Crypto](https://developer.mozilla.org/en-US/docs/Web/API/Crypto)\n\n[CryptoKey](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey)\n\n[SubtleCrypto](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto)\n\n## WEBIDL\n\n[DOMException](https://developer.mozilla.org/en-US/docs/Web/API/DOMException)\n\n## XHR\n\n[FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData)\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "### Features\n  - Added dgram (UDP socket) module support (@chessbyte, @richarddavison)\n  - Added timezone support with minimal Intl.DateTimeFormat (@chessbyte, @richarddavison)\n  - Added Symbol.toStringTag to Web API classes (@chessbyte)\n  - Added Symbol.toStringTag to Crypto and SubtleCrypto (@chessbyte)\n  - Implemented `symlink` and `symlinkSync` in fs module (@kyubisation, @richarddavison)\n  - Exposed FormData in fetch (@nabetti1720)\n  - Exposed `module.registerHooks()` (@nabetti1720, @richarddavison)\n  - Exposed `llrt:qjs` module (@nabetti1720)\n  - Added modular crypto with multiple backend options (@richarddavison)\n  - Eliminated `ring` dependency from pure-rust crypto backend (@nabetti1720)\n  - Exported Md5, Sha1, Sha256, Sha384, Sha512 hash classes (@richarddavison)\n  - Improved performance interface compatibility in perf_hooks (@nabetti1720)\n  - Simplified child_process signal handling and detachment (@richarddavison)\n  - Added custom inspect functions for Map, Set, DataView, and ArrayBuffer (@richarddavison)\n  - Added basic Agent support (@Sytten)\n  - Transitioned from `chrono/chrono-tz` to `jiff` (@nabetti1720)\n\n### Fixes\n  - Fix Proxy object handling JSON and console modules\n  - Fix S3 endpoint resolution issue in new SDK version (@richarddavison)\n  - Fix suite hook handling in TestAgent (@richarddavison)\n  - Handle secret param in Hash constructors for SDK signing (@richarddavison)\n  - Fix Headers keys and values methods to return iterable values (@richarddavison)\n  - Improve encoding handling in Hash and Hmac implementations (@richarddavison)\n  - Fix Buffer from utf16le (@Sytten)\n  - Buffer improvements (@Sytten)\n  - Use Latin-1 encoding for atob() per WHATWG spec (@chessbyte, @richarddavison)\n  - Fix buffer offsets when repeating subarray (@nabetti1720, @richarddavison)\n  - Fix stream/web primordials used before initialization (@nabetti1720)\n  - Correctly handle 'require' with parent directory specification (@nabetti1720, @richarddavison)\n  - Register and run test hooks in correct order (@kyubisation, @richarddavison)\n  - Fix & simplify json escape (@richarddavison)\n  - Require primordials to be initialized from module once to avoid data race (@richarddavison)\n  - Ignore init for global clients not in us-east-1 (@perpil)\n  - Improve support for dns lookup (@Sytten)\n  - Remove zstd WriteBuf dependency for byte slice conversion (@chessbyte)\n  - Disable `mlkem` in rustls-graviola (@nabetti1720)\n  - Optional webpki (@Sytten)\n\n### Maintenance\n  - Upgrade rquickjs to 0.11 (@nabetti1720)\n  - Upgrade rquickjs to 0.10.0 (@mohebifar, @richarddavison)\n  - Eliminate use of `jwalk` for directory recursion (@nabetti1720)\n  - Update SDK dependencies and remove UUID module (@richarddavison)\n  - Dependency upgrades\n\nThanks for all the reports and contributors\n\nFull list of changes:\nhttps://github.com/awslabs/llrt/compare/v0.7.0-beta...v0.8.1-beta\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "## Code of Conduct\n\nThis project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).\nFor more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact\nopensource-codeofconduct@amazon.com with any additional questions or comments.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing Guidelines\n\nThank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional\ndocumentation, we greatly value feedback and contributions from our community.\n\nPlease read through this document before submitting any issues or pull requests to ensure we have all the necessary\ninformation to effectively respond to your bug report or contribution.\n\n## Reporting Bugs/Feature Requests\n\nWe welcome you to use the GitHub issue tracker to report bugs or suggest features.\n\nWhen filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already\nreported the issue. Please try to include as much information as you can. Details like these are incredibly useful:\n\n- A reproducible test case or series of steps\n- The version of our code being used\n- Any modifications you've made relevant to the bug\n- Anything unusual about your environment or deployment\n\n## Contributing via Pull Requests\n\nContributions via pull requests are much appreciated. Before sending us a pull request, please ensure that:\n\n1. You are working against the latest source on the _main_ branch.\n2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already.\n3. You open an issue to discuss any significant work - we would hate for your time to be wasted.\n\nTo send us a pull request, please:\n\n1. Fork the repository.\n2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change.\n3. Ensure local tests pass.\n4. Commit to your fork using clear commit messages.\n5. Send us a pull request, answering any default questions in the pull request interface.\n6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.\n\nGitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and\n[creating a pull request](https://help.github.com/articles/creating-a-pull-request/).\n\n## Finding contributions to work on\n\nLooking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start.\n\n## Code of Conduct\n\nThis project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).\nFor more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact\n<opensource-codeofconduct@amazon.com> with any additional questions or comments.\n\n## Security issue notifications\n\nIf you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue.\n\n## Licensing\n\nSee the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution.\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[workspace]\nresolver = \"2\"\n\nmembers = [\n  \"libs/llrt_build\",\n  \"libs/llrt_compression\",\n  \"libs/llrt_context\",\n  \"libs/llrt_encoding\",\n  \"libs/llrt_json\",\n  \"libs/llrt_numbers\",\n  \"libs/llrt_test\",\n  \"libs/llrt_test_tls\",\n  \"libs/llrt_utils\",\n  \"modules/llrt_abort\",\n  \"modules/llrt_async_hooks\",\n  \"modules/llrt_buffer\",\n  \"modules/llrt_child_process\",\n  \"modules/llrt_console\",\n  \"modules/llrt_crypto\",\n  \"modules/llrt_dgram\",\n  \"modules/llrt_events\",\n  \"modules/llrt_exceptions\",\n  \"modules/llrt_fetch\",\n  \"modules/llrt_fs\",\n  \"modules/llrt_http\",\n  \"modules/llrt_intl\",\n  \"modules/llrt_navigator\",\n  \"modules/llrt_net\",\n  \"modules/llrt_os\",\n  \"modules/llrt_path\",\n  \"modules/llrt_perf_hooks\",\n  \"modules/llrt_process\",\n  \"modules/llrt_stream\",\n  \"modules/llrt_stream_web\",\n  \"modules/llrt_string_decoder\",\n  \"modules/llrt_temporal\",\n  \"modules/llrt_timers\",\n  \"modules/llrt_tls\",\n  \"modules/llrt_tty\",\n  \"modules/llrt_url\",\n  \"modules/llrt_util\",\n  \"modules/llrt_zlib\",\n  \"llrt_modules\",\n  \"llrt_core\",\n  \"llrt\",\n]\n\n[profile.flame]\ninherits = \"release\"\nstrip = false\ndebug = true\n\n[profile.release]\nstrip = true\nlto = true\ncodegen-units = 1\nopt-level = 3\npanic = \"abort\"\n\n[profile.test]\nopt-level = 3\n"
  },
  {
    "path": "GOVERNANCE.md",
    "content": "# Project Governance (Very Minimal Governance model)\n\nThis open source project is managed by a Steering Committee composed of the maintainers of this project. Maintainers are\ndefined as individuals with full commit access to the project repositories.\n\n## Steering Committee\n\nThe Steering Committee will be responsible for oversight of all technical, project, approval, and policy matters for the\nproject. This notably includes brand and trademark management.\n\nThe Steering Committee members are listed in the MAINTAINERS.md file in the repository. New maintainers (and accordingly,\nSteering Committee members) may be added or removed by no less than 3/4 affirmative vote of the Steering Committee. The\nSteering Committee will appoint a Chair responsible for organizing Steering Committee activity. If the Steering Committee\nChair is removed from the Committee (or the Chair steps down from that role), it is the responsibility of the Steering\nCommitte to appoint a new Chair.\n\nThe Steering Committee may, at its discretion, add or remove members who are not maintainers.\n\n## Voting\n\nThe Steering Committee will strive for all decisions to be made by consensus. While explicit agreement of the entire\nSteering Committee is preferred, it is not required for consensus. Rather, the Steering Committee will determine\nconsensus based on their good faith consideration of a number of factors, including the dominant view of the Steering\nCommittee and nature of support and objections. The Steering Committee will document evidence of consensus in accordance\nwith these requirements. If consensus cannot be reached, the Steering Committee will make the decision by a vote.\n\nThe Steering Committee Chair will call a vote with reasonable notice to the Steering Committee, setting out a discussion\nperiod and a separate voting period. Any discussion may be conducted in person or electronically by text, voice, or video.\nThe discussion will be open to the public, with the notable exception of discussions involving embargoed security issues\nor the addition or removal of maintainers, which will be private. In any vote, each voting representative will have one\nvote. Except as specifically noted elsewhere in this document, decisions by vote require a simple majority vote of all\nvoting members.\n\n## Termination of Membership\n\nA maintainer’s access (and accordingly, their position on the Steering Committee) will be removed if any of the following\noccur:\n\n- Resignation: Written notice of resignation to the Steering Committee\n- Steering Committee Vote: 3/4 affirmative vote of the Steering Committee to remove a member\n- Unreachable Member: If a member is unresponsive for more than six months, the remaining active members of the Steering\n  Committee may vote to remove the member\n\n## License of this document\n\nThis document is a modified work of the GitHub Minimal Viable Governance model, located here: ﻿\n[https://github.com/github/MVG/﻿](https://github.com/github/MVG/)\nThis document may be used, modified, and/or distributed under the terms of the ﻿\n[Creative Commons Attribution 4.0 International (CC-BY) license﻿](https://creativecommons.org/licenses/by/4.0/legalcode).\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": "MAINTAINERS.md",
    "content": "<!--  markdownlint-disable MD043 -->\n\n## Table of contents <!-- omit in toc -->\n\n- [Overview](#overview)\n- [Current Maintainers](#current-maintainers)\n- [Labels](#labels)\n- [Maintainer Responsibilities](#maintainer-responsibilities)\n  - [Uphold Code of Conduct](#uphold-code-of-conduct)\n  - [Prioritize Security](#prioritize-security)\n  - [Review Pull Requests](#review-pull-requests)\n  - [Triage New Issues](#triage-new-issues)\n\n## Overview\n\n> **Please treat this content as a living document.**\n\nThis is document explains who the maintainers are (see below), what they do in this repo, and how they should be doing it. If you're interested in contributing, see [CONTRIBUTING](CONTRIBUTING.md).\n\n## Current Maintainers\n\n| Maintainer      | GitHub ID                                           | Affiliation |\n| --------------- | --------------------------------------------------- | ----------- |\n| Richard Davison | [richarddavison](https://github.com/richarddavison) | Amazon      |\n| Nik Pinski      | [nikp](https://github.com/nikp)                     | Amazon      |\n| Harold Sun      | [bnusunny](https://github.com/bnusunny)             | Amazon      |\n| Iain Maitland   | [imaitland](https://github.com/imaitland)           | Amazon      |\n\n## Labels\n\n> WORK IN PROGRESS\n\n## Maintainer Responsibilities\n\nMaintainers are active and visible members of the community, and have [maintain-level permissions on a repository](https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-permission-levels-for-an-organization). Use those privileges to serve the community and evolve code as follows.\n\nBe aware of recurring ambiguous situations and [document them](#common-scenarios) to help your fellow maintainers.\n\n### Uphold Code of Conduct\n\nModel the behavior set forward by the [Code of Conduct](CODE_OF_CONDUCT.md) and raise any violations to other maintainers and admins. There could be unusual circumstances where inappropriate behavior does not immediately fall within the [Code of Conduct](CODE_OF_CONDUCT.md).\n\nThese might be nuanced and should be handled with extra care - when in doubt, do not engage and reach out to other maintainers and admins.\n\n### Prioritize Security\n\nSecurity is your number one priority. Maintainer's Github keys must be password protected securely and any reported security vulnerabilities are addressed before features or bugs.\n\nNote that this repository is monitored and supported 24/7 by Amazon Security, see [Reporting a Vulnerability](CONTRIBUTING.md#security-issue-notifications) for details.\n\n### Review Pull Requests\n\nReview pull requests regularly, comment, suggest, reject, merge and close. Accept only high quality pull-requests. Provide code reviews and guidance on incoming pull requests.\n\nPRs are [labeled](#labels) based on file changes and semantic title. Pay attention to whether labels reflect the current state of the PR and correct accordingly.\n\nUse and enforce [semantic versioning](https://semver.org/) pull request titles, as these will be used for [CHANGELOG](CHANGELOG.md) and [Release notes](https://github.com/awslabs/llrt/releases) - make sure they communicate their intent at the human level.\n\nSee [Common scenarios](#common-scenarios) section for additional guidance.\n\n### Triage New Issues\n\nManage [labels](#labels), review issues regularly, and create new labels as needed by the project. Remove `triage` label when you're able to confirm the validity of a request, a bug can be reproduced, etc. Give priority to the original author for implementation, unless it is a sensitive task that is best handled by maintainers.\n\nMake sure issues are assigned to our [board of activities](https://github.com/orgs/awslabs/projects/145/)\n\nUse our [labels](#labels) to signal good first issues to new community members, and to set expectation that this might need additional feedback from the author, other customers, experienced community members and/or maintainers.\n\n> WORK IN PROGRESS\n"
  },
  {
    "path": "Makefile",
    "content": "TARGET_linux_x86_64 = x86_64-unknown-linux-musl\nTARGET_linux_arm64 = aarch64-unknown-linux-musl\nTARGET_darwin_x86_64 = x86_64-apple-darwin\nTARGET_darwin_arm64 = aarch64-apple-darwin\nTARGET_windows_x86_64 = x86_64-pc-windows-gnu\nTARGET_windows_arm64 = aarch64-is-not-yet-supported\nRUST_VERSION = nightly\nTOOLCHAIN = +$(RUST_VERSION)\nBUILD_ARG = $(TOOLCHAIN) build -r\nBUILD_DIR = ./target/release\nBUNDLE_DIR = bundle\n\nTS_SOURCES = $(wildcard llrt_core/src/modules/js/*.ts) $(wildcard llrt_core/src/modules/js/@llrt/test/*.ts) $(wildcard llrt_core/src/modules/js/@llrt/*.ts) $(wildcard tests/unit/*.ts)\nSTD_JS_FILE = $(BUNDLE_DIR)/js/@llrt/std.js\n\nRELEASE_ARCH_NAME_x64 = x86_64\nRELEASE_ARCH_NAME_arm64 = arm64\n\nLAMBDA_PREFIX = llrt-lambda\nRELEASE_TARGETS = arm64 x64\nRELEASE_ZIPS = $(addprefix $(LAMBDA_PREFIX)-,$(RELEASE_TARGETS))\n\nifeq ($(OS),Windows_NT)\n\tDETECTED_OS := windows\n\tARCH = x86_64\nelse\n\tDETECTED_OS := $(shell uname | tr A-Z a-z)\n\tARCH = $(shell uname -m)\nendif\n\nifeq ($(ARCH),aarch64)\n\tARCH = arm64\nendif\n\nZSTD_LIB_CC_ARGS = -s -O3 -flto\nZSTD_LIB_ARGS = -j lib-nomt UNAME=Linux ZSTD_LIB_COMPRESSION=0 ZSTD_LIB_DICTBUILDER=0 AR=\"zig ar\"\nifeq ($(DETECTED_OS),windows)\nZSTD_LIB_CC_x64 = CC=\"zig cc -target x86_64-windows-gnu $(ZSTD_LIB_CC_ARGS)\"\nelse\nZSTD_LIB_CC_arm64 = CC=\"zig cc -target aarch64-linux-musl $(ZSTD_LIB_CC_ARGS)\"\nZSTD_LIB_CC_x64 = CC=\"zig cc -target x86_64-linux-musl $(ZSTD_LIB_CC_ARGS)\"\nendif\n\nCURRENT_TARGET ?= $(TARGET_$(DETECTED_OS)_$(ARCH))\n\nexport CC_aarch64_unknown_linux_musl = $(CURDIR)/linker/cc-aarch64-linux-musl\nexport CXX_aarch64_unknown_linux_musl = $(CURDIR)/linker/cxx-aarch64-linux-musl\nexport AR_aarch64_unknown_linux_musl = $(CURDIR)/linker/ar\nexport CC_x86_64_unknown_linux_musl = $(CURDIR)/linker/cc-x86_64-linux-musl\nexport CXX_x86_64_unknown_linux_musl = $(CURDIR)/linker/cxx-x86_64-linux-musl\nexport AR_x86_64_unknown_linux_musl = $(CURDIR)/linker/ar\n\ndefine alias_template\nrelease${1}: llrt-$(DETECTED_OS)-$(ARCH)${1}.zip\n\nllrt-linux-x86_64${1}.zip: llrt-linux-x64${1}.zip\nllrt-windows-x86_64${1}.zip: llrt-windows-x64${1}.zip\nllrt-darwin-x86_64${1}.zip: llrt-darwin-x64${1}.zip\nendef\n\n$(eval $(call alias_template,-full-sdk))\n$(eval $(call alias_template,))\n$(eval $(call alias_template,-no-sdk))\n\ndefine release_template\nrelease-aws-${1}${2}: | llrt-lambda-${1}${2}.zip llrt-container-${1}${2} llrt-linux-${1}${2}.zip\n\nllrt-lambda-${1}${2}.zip: export SDK_BUNDLE_MODE = ${3}\nllrt-lambda-${1}${2}.zip: | clean-js js\n\tcargo $$(BUILD_ARG) --target $$(TARGET_linux_$$(RELEASE_ARCH_NAME_${1})) --features lambda\n\t./pack target/$$(TARGET_linux_$$(RELEASE_ARCH_NAME_${1}))/release/llrt target/$$(TARGET_linux_$$(RELEASE_ARCH_NAME_${1}))/release/bootstrap\n\t@rm -rf $$@\n\tzip -j $$@ target/$$(TARGET_linux_$$(RELEASE_ARCH_NAME_${1}))/release/bootstrap\n\nllrt-container-${1}${2}: export SDK_BUNDLE_MODE = ${3}\nllrt-container-${1}${2}: | clean-js js\n\tcargo $$(BUILD_ARG) --target $$(TARGET_linux_$$(RELEASE_ARCH_NAME_${1})) --features lambda,uncompressed\n\tmv target/$$(TARGET_linux_$$(RELEASE_ARCH_NAME_${1}))/release/llrt $$@\n\nllrt-linux-${1}${2}.zip: export SDK_BUNDLE_MODE = ${3}\nllrt-linux-${1}${2}.zip: | clean-js js\n\tcargo $$(BUILD_ARG) --target $$(TARGET_linux_$$(RELEASE_ARCH_NAME_${1}))\n\t@rm -rf $$@\n\tzip -j $$@ target/$$(TARGET_linux_$$(RELEASE_ARCH_NAME_${1}))/release/llrt\n\nllrt-darwin-${1}${2}.zip: export SDK_BUNDLE_MODE = ${3}\nllrt-darwin-${1}${2}.zip: | clean-js js\n\tcargo $$(BUILD_ARG) --target $$(TARGET_darwin_$$(RELEASE_ARCH_NAME_${1}))\n\t@rm -rf $$@\n\tzip -j $$@ target/$$(TARGET_darwin_$$(RELEASE_ARCH_NAME_${1}))/release/llrt\n\n# llrt-windows-arm64* is automatically generated, but not currently supported.\nllrt-windows-${1}${2}.zip: export SDK_BUNDLE_MODE = ${3}\nllrt-windows-${1}${2}.zip: | clean-js js\n\tcargo $$(BUILD_ARG) --target $$(TARGET_windows_$$(RELEASE_ARCH_NAME_${1}))\n\tzip -j $$@ target/$$(TARGET_windows_$$(RELEASE_ARCH_NAME_${1}))/release/llrt.exe\nendef\n\n$(foreach target,$(RELEASE_TARGETS),$(eval $(call release_template,$(target),-full-sdk,FULL)))\n$(foreach target,$(RELEASE_TARGETS),$(eval $(call release_template,$(target),,STD)))\n$(foreach target,$(RELEASE_TARGETS),$(eval $(call release_template,$(target),-no-sdk,NONE)))\n\nbuild: js\n\tcargo $(BUILD_ARG) --target $(CURRENT_TARGET)\n\nifeq ($(DETECTED_OS),windows)\nstdlib:\n\trustup toolchain install $(RUST_VERSION) --target $(TARGET_windows_x86_64)\n\trustup target add $(TARGET_windows_x86_64)\n\trustup component add rust-src --toolchain $(RUST_VERSION) --target $(TARGET_windows_x86_64)\nelse\nstdlib-x64:\n\trustup toolchain install $(RUST_VERSION) --target $(TARGET_linux_x86_64)\n\trustup target add $(TARGET_linux_x86_64)\n\trustup component add rust-src --toolchain $(RUST_VERSION) --target $(TARGET_linux_x86_64)\n\nstdlib-arm64:\n\trustup toolchain install $(RUST_VERSION) --target $(TARGET_linux_arm64)\n\trustup target add $(TARGET_linux_arm64)\n\trustup component add rust-src --toolchain $(RUST_VERSION) --target $(TARGET_linux_arm64)\n\nstdlib: | stdlib-x64 stdlib-arm64\nendif\n\ntoolchain:\n\trustup toolchain install $(RUST_VERSION) --target $(CURRENT_TARGET)\n\trustup target add $(CURRENT_TARGET)\n\trustup component add rust-src --toolchain $(RUST_VERSION) --target $(CURRENT_TARGET)\n\nclean-js:\n\trm -rf ./bundle\n\nclean: clean-js\n\trm -rf ./target\n\trm -rf ./lib\n\njs: $(STD_JS_FILE)\n\nbundle/js/%.js: $(TS_SOURCES)\n\tnode build.mjs\n\nfix:\n\tnpx pretty-quick\n\tcargo fix --allow-dirty\n\tcargo clippy --fix --allow-dirty\n\tcargo fmt\n\nbloat: js\n\tcargo build --profile=flame --target $(CURRENT_TARGET)\n\tcargo bloat --profile=flame --crates\n\nrun: export AWS_LAMBDA_FUNCTION_NAME = n/a\nrun: export AWS_LAMBDA_FUNCTION_MEMORY_SIZE = 1\nrun: export AWS_LAMBDA_FUNCTION_VERSION = 1\nrun: export AWS_LAMBDA_RUNTIME_API = localhost:3000\nrun: export _EXIT_ITERATIONS = 1\nrun: export JS_MINIFY = 0\nrun: export RUST_LOG = llrt=trace\nrun: export _HANDLER = index.handler\nrun:\n\tcargo run -vv\n\nrun-ssr: export AWS_LAMBDA_RUNTIME_API = localhost:3000\nrun-ssr: export TABLE_NAME=quickjs-table\nrun-ssr: export AWS_REGION = us-east-1\nrun-ssr: export _HANDLER = index.handler\nrun-ssr: js\n\tcargo build\n\tcd example/functions && yarn build && cd build && ../../../target/debug/llrt\n\nflame:\n\tcargo flamegraph --profile flame -- index.mjs\n\nrun-cli: export RUST_LOG = llrt=trace\nrun-cli: js\n\tcargo run\n\ntest: export JS_MINIFY = 0\ntest: export TEST_SUB_DIR = unit\ntest: export LLRT_ASYNC_HOOKS = 1\ntest: js\n\tcargo run -- test -d bundle/js/__tests__/$(TEST_SUB_DIR)\n\ninit-wpt:\n\tcd wpt && \\\n\tgit sparse-checkout init --no-cone && \\\n\tgit sparse-checkout set \\\n\t\t/README.md \\\n\t\t/console \\\n\t\t/docs \\\n\t\t/encoding \\\n\t\t/FileAPI \\\n\t\t/fetch \\\n\t\t/hr-time \\\n\t\t/streams \\\n\t\t/tools \\\n\t\t/url \\\n\t\t/WebCryptoAPI \\\n\t\t/webidl \\\n\t\t/wpt \\\n\t\t/xhr\n\nupdate-wpt:\n\t( cd wpt && git fetch origin master && git reset --hard FETCH_HEAD && git log -1 --oneline > ../tests/wpt/revision )\n\ntest-wpt: export JS_MINIFY = 0\ntest-wpt: export TEST_SUB_DIR = wpt\ntest-wpt: js\n\tnpx pretty-quick --pattern \"tests/wpt/**/*.{js,ts,json}\"\n\tcargo run -- test -d bundle/js/__tests__/$(TEST_SUB_DIR) 2> wpt_errors.tmp\n\ntidyup-wpt:\n\tsed -E 's/\\x1b\\[[0-9;]*m//g' wpt_errors.tmp \\\n\t| sed '1,/^$$/d' \\\n\t| sed -E '/^ ?[^ ]/s|^.*__tests__/|🧪/|' \\\n\t> wpt_errors.txt\n\ntest-e2e: export JS_MINIFY = 0\ntest-e2e: export TEST_TIMEOUT = 60000\ntest-e2e: export SDK_BUNDLE_MODE = STD\ntest-e2e: export TEST_SUB_DIR = e2e\ntest-e2e: js\n\tcargo run -- test -d bundle/js/__tests__/$(TEST_SUB_DIR)\n\ntest-ci: export JS_MINIFY = 0\ntest-ci: export RUST_BACKTRACE = 1\ntest-ci: export TEST_SUB_DIR = unit\ntest-ci: export LLRT_ASYNC_HOOKS = 1\ntest-ci: clean-js | toolchain js\nifdef CARGO_FEATURES\n\tcargo $(TOOLCHAIN) -Z build-std -Z build-std-features test --target $(CURRENT_TARGET) $(CARGO_FEATURES) -- --nocapture --show-output\n\tcargo $(TOOLCHAIN) run -r --target $(CURRENT_TARGET) $(CARGO_FEATURES) -- test -d bundle/js/__tests__/$(TEST_SUB_DIR)\nelse\n\tcargo $(TOOLCHAIN) -Z build-std -Z build-std-features test --target $(CURRENT_TARGET) --features lambda -- --nocapture --show-output\n\tcargo $(TOOLCHAIN) run -r --target $(CURRENT_TARGET) -- test -d bundle/js/__tests__/$(TEST_SUB_DIR)\nendif\n\nlibs-arm64: lib/arm64/libzstd.a lib/zstd.h lib/zstd_errors.h\nlibs-x64: lib/x64/libzstd.a lib/zstd.h lib/zstd_errors.h\n\nlibs: | libs-arm64 libs-x64\n\nlib/zstd.h:\n\tcp zstd/lib/zstd.h $@\n\nlib/zstd_errors.h:\n\tcp zstd/lib/zstd_errors.h $@\n\nlib/arm64/libzstd.a:\n\tmkdir -p $(dir $@)\n\trm -f zstd/lib/-.o\n\tcd zstd/lib && make clean && make $(ZSTD_LIB_ARGS) $(ZSTD_LIB_CC_arm64)\n\tcp zstd/lib/libzstd.a $@\n\nlib/x64/libzstd.a:\n\tmkdir -p $(dir $@)\n\trm -f zstd/lib/-.o\n\tcd zstd/lib && make clean && make $(ZSTD_LIB_ARGS) $(ZSTD_LIB_CC_x64)\n\tcp zstd/lib/libzstd.a $@\n\nbench:\n\tcargo build -r\n\thyperfine -N --warmup=100 \"node fixtures/hello.js\" \"deno run fixtures/hello.js\" \"bun fixtures/hello.js\" \"$(BUILD_DIR)/llrt fixtures/hello.js\" \"qjs fixtures/hello.js\"\n\ndeploy:\n\tcd example/infrastructure && yarn deploy --require-approval never\n\ncheck:\n\tcargo clippy --all-targets --no-default-features --features \"lambda,macro,no-sdk,uncompressed,crypto-rust,tls-ring\" -- -D warnings\n\ntest-rs:\n\tcargo test --all-targets --no-default-features --features \"lambda,macro,no-sdk,uncompressed,crypto-rust,tls-ring\"\n\ncheck-crates:\n\tcargo metadata --no-deps --format-version 1 --quiet | \\\n\tjq -r '.packages[] | select(.manifest_path | contains(\"modules/\")) | .name' | \\\n\twhile read crate; do \\\n\t  echo \"Checking crate: $$crate\"; \\\n\t  cargo check -p \"$$crate\"; \\\n\tdone\n\n.PHONY: libs check check-all check-crates libs-arm64 libs-x64 toolchain clean-js release-linux release-darwin release-windows lambda stdlib stdlib-x64 stdlib-arm64 test test-ci run js run-release build release clean flame deploy\n"
  },
  {
    "path": "NOTICE",
    "content": "LLRT\nCopyright Amazon.com, Inc. or its affiliates. All Rights Reserved. "
  },
  {
    "path": "README.md",
    "content": "[![LLRT CI](https://github.com/awslabs/llrt/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/awslabs/llrt/actions/workflows/ci.yml) [![LLRT Release](https://github.com/awslabs/llrt/actions/workflows/release.yml/badge.svg)](https://github.com/awslabs/llrt/actions/workflows/release.yml)\n\nLLRT (**L**ow **L**atency **R**un**t**ime) is a lightweight JavaScript runtime designed to address the growing demand for fast and efficient Serverless applications. LLRT offers up to over **10x** faster startup and up to **2x** overall lower cost compared to other JavaScript runtimes running on **AWS Lambda**\n\nIt's built in Rust, utilizing QuickJS as JavaScript engine, ensuring efficient memory usage and swift startup.\n\n> [!WARNING]\n> LLRT is an **experimental** package. It is subject to change and intended only for evaluation purposes.\n\n<sub>LLRT - [DynamoDB Put, ARM, 128MB](example/functions/src/v3-lib.mjs):<sub>\n![DynamoDB Put LLRT](./benchmarks/llrt-ddb-put.png \"LLRT DynamoDB Put\")\n\n<sub>Node.js 20 - [DynamoDB Put, ARM, 128MB](example/functions/src/v3-lib.mjs):<sub>\n![DynamoDB Put Node20](./benchmarks/node20-ddb-put.png \"Node20 DynamoDB Put\")\n\nHTTP benchmarks measured in **round trip time** for a cold start ([why?](#benchmark-methodology))\n\n## Configure Lambda functions to use LLRT\n\nDownload the last LLRT release from <https://github.com/awslabs/llrt/releases>\n\n### Option 1: Custom runtime (recommended)\n\nChoose `Custom Runtime on Amazon Linux 2023` and package the LLRT `bootstrap` binary together with your JS code.\n\n### Option 2: Use a layer\n\nChoose `Custom Runtime on Amazon Linux 2023`, upload `llrt-lambda-arm64.zip` or `llrt-lambda-x64.zip` as a layer and add to your function\n\n### Option 3: Package LLRT in a container image\n\nSee our [AWS SAM example](./example/llrt-sam-container-image) or:\n\n```dockerfile\nFROM --platform=arm64 busybox\nWORKDIR /var/task/\nCOPY app.mjs ./\nADD https://github.com/awslabs/llrt/releases/latest/download/llrt-container-arm64 /usr/bin/llrt\nRUN chmod +x /usr/bin/llrt\n\nENV LAMBDA_HANDLER \"app.handler\"\n\nCMD [ \"llrt\" ]\n```\n\n### Option 4: AWS SAM\n\nThe following [example project](example/llrt-sam/) sets up a lambda\ninstrumented with a layer containing the llrt runtime.\n\n### Option 5: AWS CDK\n\nYou can use [`cdk-lambda-llrt` construct library](https://github.com/tmokmss/cdk-lambda-llrt) to deploy LLRT Lambda functions with AWS CDK.\n\n```ts\nimport { LlrtFunction } from \"cdk-lambda-llrt\";\n\nconst handler = new LlrtFunction(this, \"Handler\", {\n  entry: \"lambda/index.ts\",\n});\n```\n\nSee [Construct Hub](https://constructs.dev/packages/cdk-lambda-llrt/) and [its examples](https://github.com/tmokmss/cdk-lambda-llrt/tree/main/example) for more details.\n\nThat's it 🎉\n\n> [!IMPORTANT]\n> Even though LLRT supports [ES2023](https://262.ecma-international.org/14.0/) it's **NOT** a drop in replacement for Node.js. Consult [Compatibility matrix](#compatibility-matrix) and [API](API.md) for more details.\n> All dependencies should be bundled for a `browser` platform and mark included `@aws-sdk` packages as external.\n\n## Testing & ensuring compatibility\n\nThe best way to ensure your code is compatible with LLRT is to write tests and execute them using the built-in test runner. The test runner currently supports Jest/Chai assertions. There are three main types of tests you can create:\n\nUnit Tests\n\n- Useful for validating specific modules and functions in isolation\n- Allow focused testing of individual components\n\nEnd-to-End (E2E) Tests\n\n- Validate overall compatibility with AWS SDK and WinterTC compliance\n- Test the integration between all components\n- Confirm expected behavior from end-user perspective\n- For more information about the E2E Tests and how to run them, see [here](tests/e2e/README.md).\n\nWeb Platform Tests (WPT)\n\n- Useful for validating LLRT’s behavior against standardized browser APIs and runtime expectations\n- Ensure compatibility with web standards and cross-runtime environments\n- Help verify alignment with WinterTC and broader JavaScript ecosystem\n- For setup instructions and how to run WPT in LLRT, see [here](tests/wpt/README.md).\n\n### Test runner\n\nTest runner uses a lightweight Jest-like API and supports Jest/Chai assertions. For examples on how to implement tests for LLRT see the `/tests` folder of this repository.\n\nTo run tests, execute the `llrt test` command. LLRT scans the current directory and sub-directories for files that ends with `*.test.js` or `*.test.mjs`. You can also provide a specific test directory to scan by using the `llrt test -d <directory>` option.\n\nThe test runner also has support for filters. Using filters is as simple as adding additional command line arguments, i.e: `llrt test crypto` will only run tests that match the filename containing `crypto`.\n\n## Compatibility matrix\n\n> [!NOTE]\n> LLRT only support a fraction of the Node.js APIs. It is **NOT** a drop in replacement for Node.js, nor will it ever be. Below is a high level overview of partially supported APIs and modules. For more details consult the [API](API.md) documentation\n\n| [Node.js API](https://nodejs.org/api/index.html) | Node.js | LLRT  |\n| ------------------------------------------------ | ------- | ----- |\n| node:assert                                      | ✔︎       | ✔︎️⚠️   |\n| node:async_hooks                                 | ✔︎       | ✔︎️⚠️   |\n| node:buffer                                      | ✔︎       | ✔︎️⚠️   |\n| node:child_process                               | ✔︎       | ✔︎⚠️   |\n| node:cluster                                     | ✔︎       | ✘     |\n| node:console                                     | ✔︎       | ✔︎⚠️   |\n| node:crypto                                      | ✔︎       | ✔︎⚠️   |\n| node:dgram                                       | ✔︎       | ✘     |\n| node:diagnostics_channel                         | ✔︎       | ✘     |\n| node:dns                                         | ✔︎       | ✔︎⚠️   |\n| node:events                                      | ✔︎       | ✔︎⚠️   |\n| node:fs                                          | ✔︎       | ✔︎⚠️   |\n| node:fs/promises                                 | ✔︎       | ✔︎⚠️   |\n| node:http                                        | ✔︎       | ✘⏱    |\n| node:http2                                       | ✔︎       | ✘     |\n| node:https                                       | ✔︎       | ✘⏱    |\n| node:inspector                                   | ✔︎       | ✘     |\n| node:inspector/promises                          | ✔︎       | ✘     |\n| node:module                                      | ✔︎       | ✔︎⚠️   |\n| node:net                                         | ✔︎       | ✔︎⚠️   |\n| node:os                                          | ✔︎       | ✔︎⚠️   |\n| node:path                                        | ✔︎       | ✔︎⚠️   |\n| node:perf_hooks                                  | ✔︎       | ✔︎⚠️   |\n| node:process                                     | ✔︎       | ✔︎⚠️   |\n| node:querystring                                 | ✔︎       | ✘     |\n| node:readline                                    | ✔︎       | ✘     |\n| node:readline/promises                           | ✔︎       | ✘     |\n| node:repl                                        | ✔︎       | ✘     |\n| node:sqlite                                      | ✔︎       | ✘     |\n| node:stream                                      | ✔︎       | ✔︎\\*   |\n| node:stream/promises                             | ✔︎       | ✔︎\\*   |\n| node:stream/web                                  | ✔︎       | ✔︎⚠️   |\n| node:string_decoder                              | ✔︎       | ✔︎     |\n| node:test                                        | ✔︎       | ✘     |\n| node:timers                                      | ✔︎       | ✔︎⚠️   |\n| node:tls                                         | ✔︎       | ✘⏱    |\n| node:tty                                         | ✔︎       | ✔︎⚠️   |\n| node:url                                         | ✔︎       | ✔︎⚠️   |\n| node:util                                        | ✔︎       | ✔︎⚠️   |\n| node:v8                                          | ✔︎       | ✘\\*\\* |\n| node:vm                                          | ✔︎       | ✘     |\n| node:wasi                                        | ✔︎       | ✘     |\n| node:worker_threads                              | ✔︎       | ✘     |\n| node:zlib                                        | ✔︎       | ✔︎⚠️   |\n\n| [LLRT API](https://github.com/awslabs/llrt/blob/main/API.md) | Node.js | LLRT |\n| ------------------------------------------------------------ | ------- | ---- |\n| llrt:hex                                                     | ✘       | ✔︎    |\n| llrt:qjs                                                     | ✘       | ✔︎    |\n| llrt:util                                                    | ✘       | ✔︎    |\n| llrt:xml                                                     | ✘       | ✔︎    |\n\n| [Web Platform API](https://min-common-api.proposal.wintertc.org/) | LLRT |\n| ----------------------------------------------------------------- | ---- |\n| COMPRESSION                                                       | ✘⏱   |\n| CONSOLE                                                           | ✔︎⚠️  |\n| DOM                                                               | ✔︎⚠️  |\n| ECMASCRIPT                                                        | ✔︎⚠️  |\n| ENCODING                                                          | ✔︎⚠️  |\n| FETCH                                                             | ✔︎⚠️  |\n| FILEAPI                                                           | ✔︎⚠️  |\n| HR-TIME                                                           | ✔︎    |\n| HTML                                                              | ✔︎⚠️  |\n| STREAMS                                                           | ✔︎⚠️  |\n| URL                                                               | ✔︎    |\n| URLPATTERN                                                        | ✘⏱   |\n| WASM-JS-API-2                                                     | ✘    |\n| WASM-WEB-API-2                                                    | ✘    |\n| WEBCRYPTO                                                         | ✔︎⚠️  |\n| WEBIDL                                                            | ✔︎⚠️  |\n| XHR                                                               | ✔︎⚠️  |\n\n| Other features | LLRT |\n| -------------- | ---- |\n| async/await    | ✔︎    |\n| esm            | ✔︎    |\n| cjs            | ✔︎    |\n| Intl           | ✔︎⚠️  |\n| Temporal       | ✔︎⚠️  |\n\n_⚠️ = partially supported in LLRT_<br />\n_⏱ = planned partial support_<br />\n_\\* = Not native_<br />\n_\\*\\* = The `module.registerHooks()` API allows you to emulate some functionality. See also `example/register-hooks`._<br />\n\n## Using node_modules (dependencies) with LLRT\n\nSince LLRT is meant for performance critical application it's not recommended to deploy `node_modules` without bundling, minification and tree-shaking.\n\nLLRT can work with any bundler of your choice. Below are some configurations for popular bundlers:\n\n> [!WARNING]\n> LLRT implements native modules that are largely compatible with the following external packages.\n> By implementing the following conversions in the bundler's alias function, your application may be faster, but we recommend that you test thoroughly as they are not fully compatible.\n\n| Node.js         | LLRT     |\n| --------------- | -------- |\n| fast-xml-parser | llrt:xml |\n\n### ESBuild\n\n```shell\nesbuild index.js --platform=browser --target=es2023 --format=esm --bundle --minify --external:@aws-sdk --external:@smithy\n```\n\n### Rollup\n\n```javascript\nimport resolve from \"@rollup/plugin-node-resolve\";\nimport commonjs from \"@rollup/plugin-commonjs\";\nimport terser from \"@rollup/plugin-terser\";\n\nexport default {\n  input: \"index.js\",\n  output: {\n    file: \"dist/bundle.js\",\n    format: \"esm\",\n    sourcemap: true,\n    target: \"es2023\",\n  },\n  plugins: [resolve(), commonjs(), terser()],\n  external: [\"@aws-sdk\", \"@smithy\"],\n};\n```\n\n### Webpack\n\n```javascript\nimport TerserPlugin from \"terser-webpack-plugin\";\nimport nodeExternals from \"webpack-node-externals\";\n\nexport default {\n  entry: \"./index.js\",\n  output: {\n    path: \"dist\",\n    filename: \"bundle.js\",\n    libraryTarget: \"module\",\n  },\n  target: \"web\",\n  mode: \"production\",\n  resolve: {\n    extensions: [\".js\"],\n  },\n  externals: [nodeExternals(), \"@aws-sdk\", \"@smithy\"],\n  optimization: {\n    minimize: true,\n    minimizer: [\n      new TerserPlugin({\n        terserOptions: {\n          ecma: 2023,\n        },\n      }),\n    ],\n  },\n};\n```\n\n## Using AWS SDK (v3) with LLRT\n\nLLRT includes many AWS SDK clients and utils as part of the runtime, built into the executable. These SDK Clients have been specifically fine-tuned to offer best performance while not compromising on compatibility. LLRT replaces some JavaScript dependencies used by the AWS SDK by native ones such as Hash calculations and XML parsing.\nV3 SDK packages not included in the list below have to be bundled with your source code. For an example on how to use a non-included SDK, see [this example build script (buildExternalSdkFunction)](example/functions/build.mjs)\n\nLLRT supports the following three bundles by default. Bundle types and suffixes are as follows.\n\n| Bundle Type | Suffix      | Purpose of Use                                            |\n| ----------- | ----------- | --------------------------------------------------------- |\n| no-sdk      | \\*-no-sdk   | Suitable for workloads that do not use `@aws-sdk`.        |\n| std-sdk     | (none)      | Suitable for workloads that utilize the major `@aws-sdk`. |\n| full-sdk    | \\*-full-sdk | Suitable for workloads that utilize any `@aws-sdk`.       |\n\nThe relationship between the supported packages for each bundle type is as follows.\n\n| Analytics                            | no-sdk | std-sdk | full-sdk |\n| ------------------------------------ | ------ | ------- | -------- |\n| @aws-sdk/client-athena               |        |         | ✔︎        |\n| @aws-sdk/client-firehose             |        |         | ✔︎        |\n| @aws-sdk/client-glue                 |        |         | ✔︎        |\n| @aws-sdk/client-kinesis              |        |         | ✔︎        |\n| @aws-sdk/client-opensearch           |        |         | ✔︎        |\n| @aws-sdk/client-opensearchserverless |        |         | ✔︎        |\n\n| Application integration     | no-sdk | std-sdk | full-sdk |\n| --------------------------- | ------ | ------- | -------- |\n| @aws-sdk/client-eventbridge |        | ✔︎       | ✔︎        |\n| @aws-sdk/client-scheduler   |        |         | ✔︎        |\n| @aws-sdk/client-sfn         |        | ✔︎       | ✔︎        |\n| @aws-sdk/client-sns         |        | ✔︎       | ✔︎        |\n| @aws-sdk/client-sqs         |        | ✔︎       | ✔︎        |\n\n| Business applications | no-sdk | std-sdk | full-sdk |\n| --------------------- | ------ | ------- | -------- |\n| @aws-sdk/client-ses   |        | ✔︎       | ✔︎        |\n| @aws-sdk/client-sesv2 |        |         | ✔︎        |\n\n| Compute services             | no-sdk | std-sdk | full-sdk |\n| ---------------------------- | ------ | ------- | -------- |\n| @aws-sdk/client-auto-scaling |        |         | ✔︎        |\n| @aws-sdk/client-batch        |        |         | ✔︎        |\n| @aws-sdk/client-ec2          |        |         | ✔︎        |\n| @aws-sdk/client-lambda       |        |         | ✔︎        |\n\n| Containers                       | no-sdk | std-sdk | full-sdk |\n| -------------------------------- | ------ | ------- | -------- |\n| @aws-sdk/client-ecr              |        |         | ✔︎        |\n| @aws-sdk/client-ecs              |        |         | ✔︎        |\n| @aws-sdk/client-eks              |        |         | ✔︎        |\n| @aws-sdk/client-servicediscovery |        |         | ✔︎        |\n\n| Databases                        | no-sdk | std-sdk | full-sdk |\n| -------------------------------- | ------ | ------- | -------- |\n| @aws-sdk/client-dynamodb         |        | ✔︎       | ✔︎        |\n| @aws-sdk/client-dynamodb-streams |        |         | ✔︎        |\n| @aws-sdk/client-elasticache      |        |         | ✔︎        |\n| @aws-sdk/client-rds              |        |         | ✔︎        |\n| @aws-sdk/client-rds-data         |        |         | ✔︎        |\n\n| Developer tools      | no-sdk | std-sdk | full-sdk |\n| -------------------- | ------ | ------- | -------- |\n| @aws-sdk/client-xray |        | ✔︎       | ✔︎        |\n\n| Front-end web and mobile services | no-sdk | std-sdk | full-sdk |\n| --------------------------------- | ------ | ------- | -------- |\n| @aws-sdk/client-amplify           |        |         | ✔︎        |\n| @aws-sdk/client-appsync           |        |         | ✔︎        |\n| @aws-sdk/client-location          |        |         | ✔︎        |\n\n| Machine Learning (ML) and Artificial Intelligence (AI) | no-sdk | std-sdk | full-sdk |\n| ------------------------------------------------------ | ------ | ------- | -------- |\n| @aws-sdk/client-bedrock                                |        |         | ✔︎        |\n| @aws-sdk/client-bedrock-runtime                        |        |         | ✔︎        |\n| @aws-sdk/client-bedrock-agent                          |        |         | ✔︎        |\n| @aws-sdk/client-bedrock-agent-runtime                  |        |         | ✔︎        |\n| @aws-sdk/client-polly                                  |        |         | ✔︎        |\n| @aws-sdk/client-rekognition                            |        |         | ✔︎        |\n| @aws-sdk/client-textract                               |        |         | ✔︎        |\n| @aws-sdk/client-translate                              |        |         | ✔︎        |\n\n| Management and governance         | no-sdk | std-sdk | full-sdk |\n| --------------------------------- | ------ | ------- | -------- |\n| @aws-sdk/client-appconfig         |        |         | ✔︎        |\n| @aws-sdk/client-appconfigdata     |        |         | ✔︎        |\n| @aws-sdk/client-cloudformation    |        |         | ✔︎        |\n| @aws-sdk/client-cloudwatch        |        |         | ✔︎        |\n| @aws-sdk/client-cloudwatch-events |        | ✔︎       | ✔︎        |\n| @aws-sdk/client-cloudwatch-logs   |        | ✔︎       | ✔︎        |\n| @aws-sdk/client-service-catalog   |        |         | ✔︎        |\n| @aws-sdk/client-ssm               |        | ✔︎       | ✔︎        |\n\n| Media                        | no-sdk | std-sdk | full-sdk |\n| ---------------------------- | ------ | ------- | -------- |\n| @aws-sdk/client-mediaconvert |        |         | ✔︎        |\n\n| Networking and content delivery           | no-sdk | std-sdk | full-sdk |\n| ----------------------------------------- | ------ | ------- | -------- |\n| @aws-sdk/client-api-gateway               |        |         | ✔︎        |\n| @aws-sdk/client-apigatewayv2              |        |         | ✔︎        |\n| @aws-sdk/client-elastic-load-balancing-v2 |        |         | ✔︎        |\n\n| Security, identity, and compliance        | no-sdk | std-sdk | full-sdk |\n| ----------------------------------------- | ------ | ------- | -------- |\n| @aws-sdk/client-acm                       |        |         | ✔︎        |\n| @aws-sdk/client-cognito-identity          |        | ✔︎       | ✔︎        |\n| @aws-sdk/client-cognito-identity-provider |        | ✔︎       | ✔︎        |\n| @aws-sdk/client-iam                       |        |         | ✔︎        |\n| @aws-sdk/client-kms                       |        | ✔︎       | ✔︎        |\n| @aws-sdk/client-secrets-manager           |        | ✔︎       | ✔︎        |\n| @aws-sdk/client-sso                       |        |         | ✔︎        |\n| @aws-sdk/client-sso-admin                 |        |         | ✔︎        |\n| @aws-sdk/client-sso-oidc                  |        |         | ✔︎        |\n| @aws-sdk/client-sts                       |        | ✔︎       | ✔︎        |\n| @aws-sdk/client-verifiedpermissions       |        |         | ✔︎        |\n\n| Storage             | no-sdk | std-sdk | full-sdk |\n| ------------------- | ------ | ------- | -------- |\n| @aws-sdk/client-efs |        |         | ✔︎        |\n| @aws-sdk/client-s3  |        | ✔︎       | ✔︎        |\n\n| Other bundled packages           | no-sdk | std-sdk | full-sdk |\n| -------------------------------- | ------ | ------- | -------- |\n| @aws-crypto                      |        | ✔︎       | ✔︎        |\n| @aws-sdk/credential-providers    |        | ✔︎       | ✔︎        |\n| @aws-sdk/lib-dynamodb            |        | ✔︎       | ✔︎        |\n| @aws-sdk/lib-storage             |        | ✔︎       | ✔︎        |\n| @aws-sdk/s3-presigned-post       |        | ✔︎       | ✔︎        |\n| @aws-sdk/s3-request-presigner    |        | ✔︎       | ✔︎        |\n| @aws-sdk/util-dynamodb           |        | ✔︎       | ✔︎        |\n| @aws-sdk/util-user-agent-browser |        | ✔︎       | ✔︎        |\n| @smithy                          |        | ✔︎       | ✔︎        |\n\n> [!IMPORTANT]\n> LLRT currently does not support returning streams from SDK responses. Use `response.Body.transformToString();` or `response.Body.transformToByteArray();` as shown below.\n>\n> ```javascript\n> const response = await client.send(command);\n> // or 'transformToByteArray()'\n> const str = await response.Body.transformToString();\n> ```\n\n## Running TypeScript with LLRT\n\nSame principle as dependencies applies when using TypeScript. TypeScript must be bundled and transpiled into ES2023 JavaScript.\n\n> [!NOTE]\n> LLRT will not support running TypeScript without transpilation. This is by design for performance reasons. Transpiling requires CPU and memory that adds latency and cost during execution. This can be avoided if done ahead of time during deployment.\n\n## Rationale\n\nWhat justifies the introduction of another JavaScript runtime in light of existing options such as [Node.js](https://nodejs.org/en), [Bun](https://bun.sh) & [Deno](https://deno.com/)?\n\nNode.js, Bun, and Deno represent highly proficient JavaScript runtimes. However, they are designed with general-purpose applications in mind. These runtimes were not specifically tailored for the demands of a Serverless environment, characterized by short-lived runtime instances. They each depend on a ([Just-In-Time compiler (JIT)](https://en.wikipedia.org/wiki/Just-in-time_compilation) for dynamic code compilation and optimization during execution. While JIT compilation offers substantial long-term performance advantages, it carries a computational and memory overhead.\n\nIn contrast, LLRT distinguishes itself by not incorporating a JIT compiler, a strategic decision that yields two significant advantages:\n\nA) JIT compilation is a notably sophisticated technological component, introducing increased system complexity and contributing substantially to the runtime's overall size.\n\nB) Without the JIT overhead, LLRT conserves both CPU and memory resources that can be more efficiently allocated to code execution tasks, thereby reducing application startup times.\n\n## Limitations\n\nThere are many cases where LLRT shows notable performance drawbacks compared with JIT-powered runtimes, such as large data processing, Monte Carlo simulations or performing tasks with hundreds of thousands or millions of iterations. LLRT is most effective when applied to smaller Serverless functions dedicated to tasks such as data transformation, real time processing, AWS service integrations, authorization, validation etc. It is designed to complement existing components rather than serve as a comprehensive replacement for everything. Notably, given its supported APIs are based on Node.js specification, transitioning back to alternative solutions requires minimal code adjustments.\n\n## Building from source\n\n1. Clone code and cd to directory\n\n```\ngit clone git@github.com:awslabs/llrt.git\ncd llrt\n```\n\n2. Install git submodules\n\n```\ngit submodule update --init --checkout\n```\n\n3. Install rust\n\n```\ncurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | bash -s -- -y\nsource \"$HOME/.cargo/env\"\n```\n\n4. Install dependencies\n\n```\n# MacOS\nbrew install zig make cmake zstd node corepack\n\n# Ubuntu\nsudo apt -y install make zstd\nsudo snap install zig --classic --beta\n\n# Windows WSL2 (requires systemd to be enabled*)\nsudo apt -y install cmake g++ gcc make zip zstd\nsudo snap install zig --classic --beta\n\n# Windows WSL2 (If Node.js is not yet installed)\nsudo curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash\nnvm install --lts\n```\n\n_\\* See [Microsoft Devblogs](https://devblogs.microsoft.com/commandline/systemd-support-is-now-available-in-wsl/#how-can-you-get-systemd-on-your-machine)_\n\n5. Install Node.js packages\n\n```\ncorepack enable\nyarn\n```\n\n6. Install generate libs and setup rust targets & toolchains\n\n```\nmake stdlib && make libs\n```\n\n> [!NOTE]\n> If these commands exit with an error that says `can't cd to zstd/lib`,\n> you've not cloned this repository recursively. Run `git submodule update --init` to download the submodules and run the commands above again.\n\n7. Build binaries for Lambda (Per bundle type and architecture desired)\n\n```\n# for arm64, use\nmake llrt-lambda-arm64.zip\nmake llrt-lambda-arm64-no-sdk.zip\nmake llrt-lambda-arm64-full-sdk.zip\n# or for x86-64, use\nmake llrt-lambda-x64.zip\nmake llrt-lambda-x64-no-sdk.zip\nmake llrt-lambda-x64-full-sdk.zip\n```\n\n8. Build binaries for Container (Per bundle type and architecture desired)\n\n```\n# for arm64, use\nmake llrt-container-arm64\nmake llrt-container-arm64-no-sdk\nmake llrt-container-arm64-full-sdk\n# or for x86-64, use\nmake llrt-container-x64\nmake llrt-container-x64-no-sdk\nmake llrt-container-x64-full-sdk\n```\n\n9. Optionally build for your local machine (Mac or Linux)\n\n```\nmake release\nmake release-no-sdk\nmake release-full-sdk\n```\n\nYou should now have a `llrt-lambda-arm64*.zip` or `llrt-lambda-x64*.zip`. You can manually upload this as a Lambda layer or use it via your Infrastructure-as-code pipeline\n\n## Crypto and TLS Backend Options\n\nLLRT supports multiple cryptographic backends for both the crypto module and TLS connections. These can be configured via Cargo features.\n\n### Crypto Provider Features\n\n| Feature                 | Description                                                       |\n| ----------------------- | ----------------------------------------------------------------- |\n| `crypto-rust` (default) | Pure Rust crypto using RustCrypto crates                          |\n| `crypto-ring`           | Ring-only crypto (limited algorithm support)                      |\n| `crypto-ring-rust`      | Ring for hashing/HMAC, RustCrypto for everything else             |\n| `crypto-graviola`       | Graviola-only crypto (limited algorithm support)                  |\n| `crypto-graviola-rust`  | Graviola for hashing/HMAC/AES-GCM, RustCrypto for everything else |\n| `crypto-openssl`        | OpenSSL-based crypto                                              |\n\n### TLS Backend Features\n\n| Feature              | Description                                   |\n| -------------------- | --------------------------------------------- |\n| `tls-ring` (default) | rustls with ring crypto                       |\n| `tls-aws-lc`         | rustls with AWS-LC crypto (optimized for AWS) |\n| `tls-graviola`       | rustls with graviola crypto                   |\n| `tls-openssl`        | OpenSSL for TLS                               |\n\n### Building with Different Backends\n\n```bash\n# Default (crypto-rust + tls-ring)\ncargo build --release\n\n# Using AWS-LC for TLS\ncargo build --release --no-default-features --features \"macro,tls-aws-lc\"\n\n# Using OpenSSL for both crypto and TLS\ncargo build --release --no-default-features --features \"macro,crypto-openssl,tls-openssl\"\n\n# Using Graviola for both crypto and TLS\ncargo build --release --no-default-features --features \"macro,crypto-graviola-rust,tls-graviola\"\n```\n\n## Running Lambda emulator\n\nPlease note that in order to run the example you will need:\n\n- Valid AWS credentials via a `~/.aws/credentials` or via environment variables.\n\n```bash\nexport AWS_ACCESS_KEY_ID=XXX\nexport AWS_SECRET_ACCESS_KEY=YYY\nexport AWS_REGION=us-east-1\n```\n\n- A DynamoDB table (with `id` as the partition key) on `us-east-1`\n- The `dynamodb:PutItem` IAM permission on this table. You can use this policy (don't forget to modify <YOUR_ACCOUNT_ID>):\n\n```json\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Sid\": \"putItem\",\n      \"Effect\": \"Allow\",\n      \"Action\": \"dynamodb:PutItem\",\n      \"Resource\": \"arn:aws:dynamodb:us-east-1:<YOUR_ACCOUNT_ID>:table/quickjs-table\"\n    }\n  ]\n}\n```\n\nStart the `lambda-server.js` in a separate terminal\n\n    node lambda-server.js\n\nThen run llrt:\n\n    make run\n\n## Environment Variables\n\n### `LLRT_ASYNC_HOOKS=value`\n\nWhen using asynchronous hooks, the hooking function inside QuickJS is activated. This is disabled by default as there is concern that it may have a significant impact on performance.\n\nBy setting this environment variable to `1`, the asynchronous hook function can be enabled, allowing you to track asynchronous processing using the `async_hooks` module.\n\n### `LLRT_EXTRA_CA_CERTS=file`\n\nLoad extra certificate authorities from a PEM encoded file\n\n### `LLRT_GC_THRESHOLD_MB=value`\n\nSet a memory threshold in MB for garbage collection. Default threshold is 20MB\n\n### `LLRT_HTTP_VERSION=value`\n\nExtends the HTTP request version. By default, only HTTP/1.1 is enabled. Specifying '2' will enable HTTP/1.1 and HTTP/2.\n\n### `LLRT_LOG=[target][=][level][,...]`\n\nFilter the log output by target module, level, or both (using `=`). Log levels are case-insensitive and will also enable any higher priority logs.\n\nLog levels in descending priority order:\n\n- `Error`\n- `Warn | Warning`\n- `Info`\n- `Debug`\n- `Trace`\n\nExample filters:\n\n- `warn` will enable all warning and error logs\n- `llrt_core::vm=trace` will enable all logs in the `llrt_core::vm` module\n- `warn,llrt_core::vm=trace` will enable all logs in the `llrt_core::vm` module and all warning and error logs in other modules\n\n### `LLRT_NET_ALLOW=\"host[ ...]\"`\n\nSpace-delimited list of hosts or socket paths which should be allowed for network connections. Network connections will be denied for any host or socket path missing from this list. Set an empty list to deny all connections\n\n### `LLRT_NET_DENY=\"host[ ...]\"`\n\nSpace-delimited list of hosts or socket paths which should be denied for network connections\n\n### `LLRT_NET_POOL_IDLE_TIMEOUT=value`\n\nSet a timeout in seconds for idle sockets being kept-alive. Default timeout is 15 seconds\n\n### `LLRT_PLATFORM=value`\n\nUsed to explicitly specify a preferred platform for the Node.js package resolver. The default is `browser`. If `node` is specified, \"node\" takes precedence in the search path. If a value other than `browser` or `node` is specified, it will behave as if \"browser\" was specified.\n\n### `LLRT_REGISTER_HOOKS=file`\n\nIf you want to enable a hooking mechanism that is mostly compatible with Node.js's `module.registerHooks()`, specify the js file name in this environment variable.\n\nWe provide a concrete example in `example/register-hooks`.\n\n> [!NOTE]\n> This environment variable is only effective when running on AWS Lambda.\n> When using the LLRT CLI, hook files must be specified using the --import option instead of this environment variable.\n\n### `LLRT_SDK_CONNECTION_WARMUP=1`\n\nInitializes TLS connections in parallel during function init which significantly reduces cold starts due. Enabled by default, can be disabled with value `0` or `false`\n\n### `LLRT_TLS_VERSION=value`\n\nSet the TLS version to be used for network connections. By default only TLS 1.2 is enabled. TLS 1.3 can also be enabled by setting this variable to `1.3`\n\n## Benchmark Methodology\n\nAlthough Init Duration [reported by Lambda](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtime-environment.html) is commonly used to understand cold start impact on overall request latency, this metric does not include the time needed to copy code into the Lambda sandbox.\n\nThe technical definition of Init Duration ([source](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-logging.html#node-logging-output)):\n\n> For the first request served, the amount of time it took the runtime to load the function and run code outside of the handler method.\n\nMeasuring round-trip request duration provides a more complete picture of user facing cold-start latency.\n\nLambda invocation results (λ-labeled row) report the sum total of Init Duration + Function Duration.\n\n## Security\n\nSee [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information.\n\n## License\n\nThis library is licensed under the Apache-2.0 License. See the [LICENSE](LICENSE) file.\n"
  },
  {
    "path": "THIRD_PARTY_LICENSES",
    "content": "**  zstd; version zstd -- http://facebook.github.io/zstd/\nCopyright (c) 2016-present, Facebook, Inc. All rights reserved.\n \nRedistribution and use in source and binary forms, with or without modification,\nare 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 name Facebook nor the names of its contributors may be used to\n   endorse or promote products derived from this software without specific\n   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------\n\n** quickjs; version 2021-03-27 -- https://bellard.org/quickjs/\nCopyright 2020 Fabrice Bellard and Charlie Gordon.\n** rquickjs; version v0.4.0 -- https://github.com/DelSkayn/rquickjs\nCopyright (c) 2020 Mees Delzenne\n \nMIT License\n\nCopyright (c) <year> <copyright holders>\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\n** esbuild; version 0.19.12 -- github.com/evanw/esbuild\nCopyright (c) 2020 Evan Wallace\n \nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "benchmarks/v8-v7/README.txt",
    "content": "V8 Benchmark Suite\n==================\n\nThis is the V8 benchmark suite: A collection of pure JavaScript\nbenchmarks that we have used to tune V8. The licenses for the\nindividual benchmarks are included in the JavaScript files.\n\nIn addition to the benchmarks, the suite consists of the benchmark\nframework (base.js), which must be loaded before any of the individual\nbenchmark files, and two benchmark runners: An HTML version (run.html)\nand a standalone JavaScript version (run.js).\n\n\nChanges From Version 1 To Version 2\n===================================\n\nFor version 2 the crypto benchmark was fixed.  Previously, the\ndecryption stage was given plaintext as input, which resulted in an\nerror.  Now, the decryption stage is given the output of the\nencryption stage as input.  The result is checked against the original\nplaintext.  For this to give the correct results the crypto objects\nare reset for each iteration of the benchmark.  In addition, the size\nof the plain text has been increased a little and the use of\nMath.random() and new Date() to build an RNG pool has been removed.\n\nOther benchmarks were fixed to do elementary verification of the\nresults of their calculations.  This is to avoid accidentally\nobtaining scores that are the result of an incorrect JavaScript engine\noptimization.\n\n\nChanges From Version 2 To Version 3\n===================================\n\nVersion 3 adds a new benchmark, RegExp.  The RegExp benchmark is\ngenerated by loading 50 of the most popular pages on the web and\nlogging all regexp operations performed.  Each operation is given a\nweight that is calculated from an estimate of the popularity of the\npages where it occurs and the number of times it is executed while\nloading each page.  Finally the literal letters in the data are\nencoded using ROT13 in a way that does not affect how the regexps\nmatch their input.\n\n\nChanges from Version 3 to Version 4\n===================================\n\nThe Splay benchmark is a newcomer in version 4.  It manipulates a\nsplay tree by adding and removing data nodes, thus exercising the\nmemory management subsystem of the JavaScript engine.\n\nFurthermore, all the unused parts of the Prototype library were\nremoved from the RayTrace benchmark. This does not affect the running\nof the benchmark.\n\n\nChanges from Version 4 to Version 5\n===================================\n\nRemoved duplicate line in random seed code, and changed the name of\nthe Object.prototype.inherits function in the DeltaBlue benchmark to\ninheritsFrom to avoid name clashes when running in Chromium with\nextensions enabled.\n\n\nChanges from Version 5 to Version 6\n===================================\n\nRemoved dead code from the RayTrace benchmark and fixed a couple of\ntypos in the DeltaBlue implementation. Changed the Splay benchmark to\navoid converting the same numeric key to a string over and over again\nand to avoid inserting and removing the same element repeatedly thus\nincreasing pressure on the memory subsystem. Changed the RegExp\nbenchmark to exercise the regular expression engine on different\ninput strings.\n\nFurthermore, the benchmark runner was changed to run the benchmarks\nfor at least a few times to stabilize the reported numbers on slower\nmachines.\n\n\nChanges from Version 6 to Version 7\n===================================\n\nAdded the Navier-Stokes benchmark, a 2D differential equation solver\nthat stresses arithmetic computations on double arrays.\n"
  },
  {
    "path": "benchmarks/v8-v7/base.js",
    "content": "// Copyright 2012 the V8 project authors. All rights reserved.\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\n//       disclaimer in the documentation and/or other materials provided\n//       with the distribution.\n//     * Neither the name of Google Inc. nor the names of its\n//       contributors may be used to endorse or promote products derived\n//       from 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// Simple framework for running the benchmark suites and\n// computing a score based on the timing measurements.\n\n// A benchmark has a name (string) and a function that will be run to\n// do the performance measurement. The optional setup and tearDown\n// arguments are functions that will be invoked before and after\n// running the benchmark, but the running time of these functions will\n// not be accounted for in the benchmark score.\nfunction Benchmark(name, run, setup, tearDown) {\n  this.name = name;\n  this.run = run;\n  this.Setup = setup ? setup : function () {};\n  this.TearDown = tearDown ? tearDown : function () {};\n}\n\n// Benchmark results hold the benchmark and the measured time used to\n// run the benchmark. The benchmark score is computed later once a\n// full benchmark suite has run to completion.\nfunction BenchmarkResult(benchmark, time) {\n  this.benchmark = benchmark;\n  this.time = time;\n}\n\n// Automatically convert results to numbers. Used by the geometric\n// mean computation.\nBenchmarkResult.prototype.valueOf = function () {\n  return this.time;\n};\n\n// Suites of benchmarks consist of a name and the set of benchmarks in\n// addition to the reference timing that the final score will be based\n// on. This way, all scores are relative to a reference run and higher\n// scores implies better performance.\nfunction BenchmarkSuite(name, reference, benchmarks) {\n  this.name = name;\n  this.reference = reference;\n  this.benchmarks = benchmarks;\n  BenchmarkSuite.suites.push(this);\n}\n\n// Keep track of all declared benchmark suites.\nBenchmarkSuite.suites = [];\n\n// Scores are not comparable across versions. Bump the version if\n// you're making changes that will affect that scores, e.g. if you add\n// a new benchmark or change an existing one.\nBenchmarkSuite.version = \"7\";\n\n// To make the benchmark results predictable, we replace Math.random\n// with a 100% deterministic alternative.\nMath.random = (function () {\n  var seed = 49734321;\n  return function () {\n    // Robert Jenkins' 32 bit integer hash function.\n    seed = (seed + 0x7ed55d16 + (seed << 12)) & 0xffffffff;\n    seed = (seed ^ 0xc761c23c ^ (seed >>> 19)) & 0xffffffff;\n    seed = (seed + 0x165667b1 + (seed << 5)) & 0xffffffff;\n    seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff;\n    seed = (seed + 0xfd7046c5 + (seed << 3)) & 0xffffffff;\n    seed = (seed ^ 0xb55a4f09 ^ (seed >>> 16)) & 0xffffffff;\n    return (seed & 0xfffffff) / 0x10000000;\n  };\n})();\n\n// Runs all registered benchmark suites and optionally yields between\n// each individual benchmark to avoid running for too long in the\n// context of browsers. Once done, the final score is reported to the\n// runner.\nBenchmarkSuite.RunSuites = function (runner) {\n  var continuation = null;\n  var suites = BenchmarkSuite.suites;\n  var length = suites.length;\n  BenchmarkSuite.scores = [];\n  var index = 0;\n  function RunStep() {\n    while (continuation || index < length) {\n      if (continuation) {\n        continuation = continuation();\n      } else {\n        var suite = suites[index++];\n        if (runner.NotifyStart) runner.NotifyStart(suite.name);\n        continuation = suite.RunStep(runner);\n      }\n      if (continuation && typeof window != \"undefined\" && window.setTimeout) {\n        window.setTimeout(RunStep, 25);\n        return;\n      }\n    }\n    if (runner.NotifyScore) {\n      var score = BenchmarkSuite.GeometricMean(BenchmarkSuite.scores);\n      var formatted = BenchmarkSuite.FormatScore(100 * score);\n      runner.NotifyScore(formatted);\n    }\n  }\n  RunStep();\n};\n\n// Counts the total number of registered benchmarks. Useful for\n// showing progress as a percentage.\nBenchmarkSuite.CountBenchmarks = function () {\n  var result = 0;\n  var suites = BenchmarkSuite.suites;\n  for (var i = 0; i < suites.length; i++) {\n    result += suites[i].benchmarks.length;\n  }\n  return result;\n};\n\n// Computes the geometric mean of a set of numbers.\nBenchmarkSuite.GeometricMean = function (numbers) {\n  var log = 0;\n  for (var i = 0; i < numbers.length; i++) {\n    log += Math.log(numbers[i]);\n  }\n  return Math.pow(Math.E, log / numbers.length);\n};\n\n// Converts a score value to a string with at least three significant\n// digits.\nBenchmarkSuite.FormatScore = function (value) {\n  if (value > 100) {\n    return value.toFixed(0);\n  } else {\n    return value.toPrecision(3);\n  }\n};\n\n// Notifies the runner that we're done running a single benchmark in\n// the benchmark suite. This can be useful to report progress.\nBenchmarkSuite.prototype.NotifyStep = function (result) {\n  this.results.push(result);\n  if (this.runner.NotifyStep) this.runner.NotifyStep(result.benchmark.name);\n};\n\n// Notifies the runner that we're done with running a suite and that\n// we have a result which can be reported to the user if needed.\nBenchmarkSuite.prototype.NotifyResult = function () {\n  var mean = BenchmarkSuite.GeometricMean(this.results);\n  var score = this.reference / mean;\n  BenchmarkSuite.scores.push(score);\n  if (this.runner.NotifyResult) {\n    var formatted = BenchmarkSuite.FormatScore(100 * score);\n    this.runner.NotifyResult(this.name, formatted);\n  }\n};\n\n// Notifies the runner that running a benchmark resulted in an error.\nBenchmarkSuite.prototype.NotifyError = function (error) {\n  if (this.runner.NotifyError) {\n    this.runner.NotifyError(this.name, error);\n  }\n  if (this.runner.NotifyStep) {\n    this.runner.NotifyStep(this.name);\n  }\n};\n\n// Runs a single benchmark for at least a second and computes the\n// average time it takes to run a single iteration.\nBenchmarkSuite.prototype.RunSingleBenchmark = function (benchmark, data) {\n  function Measure(data) {\n    var elapsed = 0;\n    var start = new Date();\n    for (var n = 0; elapsed < 1000; n++) {\n      benchmark.run();\n      elapsed = new Date() - start;\n    }\n    if (data != null) {\n      data.runs += n;\n      data.elapsed += elapsed;\n    }\n  }\n\n  if (data == null) {\n    // Measure the benchmark once for warm up and throw the result\n    // away. Return a fresh data object.\n    Measure(null);\n    return { runs: 0, elapsed: 0 };\n  } else {\n    Measure(data);\n    // If we've run too few iterations, we continue for another second.\n    if (data.runs < 32) return data;\n    var usec = (data.elapsed * 1000) / data.runs;\n    this.NotifyStep(new BenchmarkResult(benchmark, usec));\n    return null;\n  }\n};\n\n// This function starts running a suite, but stops between each\n// individual benchmark in the suite and returns a continuation\n// function which can be invoked to run the next benchmark. Once the\n// last benchmark has been executed, null is returned.\nBenchmarkSuite.prototype.RunStep = function (runner) {\n  this.results = [];\n  this.runner = runner;\n  var length = this.benchmarks.length;\n  var index = 0;\n  var suite = this;\n  var data;\n\n  // Run the setup, the actual benchmark, and the tear down in three\n  // separate steps to allow the framework to yield between any of the\n  // steps.\n\n  function RunNextSetup() {\n    if (index < length) {\n      try {\n        suite.benchmarks[index].Setup();\n      } catch (e) {\n        suite.NotifyError(e);\n        return null;\n      }\n      return RunNextBenchmark;\n    }\n    suite.NotifyResult();\n    return null;\n  }\n\n  function RunNextBenchmark() {\n    try {\n      data = suite.RunSingleBenchmark(suite.benchmarks[index], data);\n    } catch (e) {\n      suite.NotifyError(e);\n      return null;\n    }\n    // If data is null, we're done with this benchmark.\n    return data == null ? RunNextTearDown : RunNextBenchmark();\n  }\n\n  function RunNextTearDown() {\n    try {\n      suite.benchmarks[index++].TearDown();\n    } catch (e) {\n      suite.NotifyError(e);\n      return null;\n    }\n    return RunNextSetup;\n  }\n\n  // Start out running the setup.\n  return RunNextSetup();\n};\n"
  },
  {
    "path": "benchmarks/v8-v7/crypto.js",
    "content": "/*\n * Copyright (c) 2003-2005  Tom Wu\n * All Rights Reserved.\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS-IS\" AND WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY\n * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.\n *\n * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,\n * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER\n * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF\n * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT\n * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n * In addition, the following condition applies:\n *\n * All redistributions must retain an intact copy of this copyright notice\n * and disclaimer.\n */\n\n// The code has been adapted for use as a benchmark by Google.\nvar Crypto = new BenchmarkSuite(\"Crypto\", 266181, [\n  new Benchmark(\"Encrypt\", encrypt),\n  new Benchmark(\"Decrypt\", decrypt),\n]);\n\n// Basic JavaScript BN library - subset useful for RSA encryption.\n\n// Bits per digit\nvar dbits;\nvar BI_DB;\nvar BI_DM;\nvar BI_DV;\n\nvar BI_FP;\nvar BI_FV;\nvar BI_F1;\nvar BI_F2;\n\n// JavaScript engine analysis\nvar canary = 0xdeadbeefcafe;\nvar j_lm = (canary & 0xffffff) == 0xefcafe;\n\n// (public) Constructor\nfunction BigInteger(a, b, c) {\n  this.array = new Array();\n  if (a != null)\n    if (\"number\" == typeof a) this.fromNumber(a, b, c);\n    else if (b == null && \"string\" != typeof a) this.fromString(a, 256);\n    else this.fromString(a, b);\n}\n\n// return new, unset BigInteger\nfunction nbi() {\n  return new BigInteger(null);\n}\n\n// am: Compute w_j += (x*this_i), propagate carries,\n// c is initial carry, returns final carry.\n// c < 3*dvalue, x < 2*dvalue, this_i < dvalue\n// We need to select the fastest one that works in this environment.\n\n// am1: use a single mult and divide to get the high bits,\n// max digit bits should be 26 because\n// max internal value = 2*dvalue^2-2*dvalue (< 2^53)\nfunction am1(i, x, w, j, c, n) {\n  var this_array = this.array;\n  var w_array = w.array;\n  while (--n >= 0) {\n    var v = x * this_array[i++] + w_array[j] + c;\n    c = Math.floor(v / 0x4000000);\n    w_array[j++] = v & 0x3ffffff;\n  }\n  return c;\n}\n\n// am2 avoids a big mult-and-extract completely.\n// Max digit bits should be <= 30 because we do bitwise ops\n// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)\nfunction am2(i, x, w, j, c, n) {\n  var this_array = this.array;\n  var w_array = w.array;\n  var xl = x & 0x7fff,\n    xh = x >> 15;\n  while (--n >= 0) {\n    var l = this_array[i] & 0x7fff;\n    var h = this_array[i++] >> 15;\n    var m = xh * l + h * xl;\n    l = xl * l + ((m & 0x7fff) << 15) + w_array[j] + (c & 0x3fffffff);\n    c = (l >>> 30) + (m >>> 15) + xh * h + (c >>> 30);\n    w_array[j++] = l & 0x3fffffff;\n  }\n  return c;\n}\n\n// Alternately, set max digit bits to 28 since some\n// browsers slow down when dealing with 32-bit numbers.\nfunction am3(i, x, w, j, c, n) {\n  var this_array = this.array;\n  var w_array = w.array;\n\n  var xl = x & 0x3fff,\n    xh = x >> 14;\n  while (--n >= 0) {\n    var l = this_array[i] & 0x3fff;\n    var h = this_array[i++] >> 14;\n    var m = xh * l + h * xl;\n    l = xl * l + ((m & 0x3fff) << 14) + w_array[j] + c;\n    c = (l >> 28) + (m >> 14) + xh * h;\n    w_array[j++] = l & 0xfffffff;\n  }\n  return c;\n}\n\n// This is tailored to VMs with 2-bit tagging. It makes sure\n// that all the computations stay within the 29 bits available.\nfunction am4(i, x, w, j, c, n) {\n  var this_array = this.array;\n  var w_array = w.array;\n\n  var xl = x & 0x1fff,\n    xh = x >> 13;\n  while (--n >= 0) {\n    var l = this_array[i] & 0x1fff;\n    var h = this_array[i++] >> 13;\n    var m = xh * l + h * xl;\n    l = xl * l + ((m & 0x1fff) << 13) + w_array[j] + c;\n    c = (l >> 26) + (m >> 13) + xh * h;\n    w_array[j++] = l & 0x3ffffff;\n  }\n  return c;\n}\n\n// am3/28 is best for SM, Rhino, but am4/26 is best for v8.\n// Kestrel (Opera 9.5) gets its best result with am4/26.\n// IE7 does 9% better with am3/28 than with am4/26.\n// Firefox (SM) gets 10% faster with am3/28 than with am4/26.\n\nsetupEngine = function (fn, bits) {\n  BigInteger.prototype.am = fn;\n  dbits = bits;\n\n  BI_DB = dbits;\n  BI_DM = (1 << dbits) - 1;\n  BI_DV = 1 << dbits;\n\n  BI_FP = 52;\n  BI_FV = Math.pow(2, BI_FP);\n  BI_F1 = BI_FP - dbits;\n  BI_F2 = 2 * dbits - BI_FP;\n};\n\n// Digit conversions\nvar BI_RM = \"0123456789abcdefghijklmnopqrstuvwxyz\";\nvar BI_RC = new Array();\nvar rr, vv;\nrr = \"0\".charCodeAt(0);\nfor (vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;\nrr = \"a\".charCodeAt(0);\nfor (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;\nrr = \"A\".charCodeAt(0);\nfor (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;\n\nfunction int2char(n) {\n  return BI_RM.charAt(n);\n}\nfunction intAt(s, i) {\n  var c = BI_RC[s.charCodeAt(i)];\n  return c == null ? -1 : c;\n}\n\n// (protected) copy this to r\nfunction bnpCopyTo(r) {\n  var this_array = this.array;\n  var r_array = r.array;\n\n  for (var i = this.t - 1; i >= 0; --i) r_array[i] = this_array[i];\n  r.t = this.t;\n  r.s = this.s;\n}\n\n// (protected) set from integer value x, -DV <= x < DV\nfunction bnpFromInt(x) {\n  var this_array = this.array;\n  this.t = 1;\n  this.s = x < 0 ? -1 : 0;\n  if (x > 0) this_array[0] = x;\n  else if (x < -1) this_array[0] = x + DV;\n  else this.t = 0;\n}\n\n// return bigint initialized to value\nfunction nbv(i) {\n  var r = nbi();\n  r.fromInt(i);\n  return r;\n}\n\n// (protected) set from string and radix\nfunction bnpFromString(s, b) {\n  var this_array = this.array;\n  var k;\n  if (b == 16) k = 4;\n  else if (b == 8) k = 3;\n  else if (b == 256)\n    k = 8; // byte array\n  else if (b == 2) k = 1;\n  else if (b == 32) k = 5;\n  else if (b == 4) k = 2;\n  else {\n    this.fromRadix(s, b);\n    return;\n  }\n  this.t = 0;\n  this.s = 0;\n  var i = s.length,\n    mi = false,\n    sh = 0;\n  while (--i >= 0) {\n    var x = k == 8 ? s[i] & 0xff : intAt(s, i);\n    if (x < 0) {\n      if (s.charAt(i) == \"-\") mi = true;\n      continue;\n    }\n    mi = false;\n    if (sh == 0) this_array[this.t++] = x;\n    else if (sh + k > BI_DB) {\n      this_array[this.t - 1] |= (x & ((1 << (BI_DB - sh)) - 1)) << sh;\n      this_array[this.t++] = x >> (BI_DB - sh);\n    } else this_array[this.t - 1] |= x << sh;\n    sh += k;\n    if (sh >= BI_DB) sh -= BI_DB;\n  }\n  if (k == 8 && (s[0] & 0x80) != 0) {\n    this.s = -1;\n    if (sh > 0) this_array[this.t - 1] |= ((1 << (BI_DB - sh)) - 1) << sh;\n  }\n  this.clamp();\n  if (mi) BigInteger.ZERO.subTo(this, this);\n}\n\n// (protected) clamp off excess high words\nfunction bnpClamp() {\n  var this_array = this.array;\n  var c = this.s & BI_DM;\n  while (this.t > 0 && this_array[this.t - 1] == c) --this.t;\n}\n\n// (public) return string representation in given radix\nfunction bnToString(b) {\n  var this_array = this.array;\n  if (this.s < 0) return \"-\" + this.negate().toString(b);\n  var k;\n  if (b == 16) k = 4;\n  else if (b == 8) k = 3;\n  else if (b == 2) k = 1;\n  else if (b == 32) k = 5;\n  else if (b == 4) k = 2;\n  else return this.toRadix(b);\n  var km = (1 << k) - 1,\n    d,\n    m = false,\n    r = \"\",\n    i = this.t;\n  var p = BI_DB - ((i * BI_DB) % k);\n  if (i-- > 0) {\n    if (p < BI_DB && (d = this_array[i] >> p) > 0) {\n      m = true;\n      r = int2char(d);\n    }\n    while (i >= 0) {\n      if (p < k) {\n        d = (this_array[i] & ((1 << p) - 1)) << (k - p);\n        d |= this_array[--i] >> (p += BI_DB - k);\n      } else {\n        d = (this_array[i] >> (p -= k)) & km;\n        if (p <= 0) {\n          p += BI_DB;\n          --i;\n        }\n      }\n      if (d > 0) m = true;\n      if (m) r += int2char(d);\n    }\n  }\n  return m ? r : \"0\";\n}\n\n// (public) -this\nfunction bnNegate() {\n  var r = nbi();\n  BigInteger.ZERO.subTo(this, r);\n  return r;\n}\n\n// (public) |this|\nfunction bnAbs() {\n  return this.s < 0 ? this.negate() : this;\n}\n\n// (public) return + if this > a, - if this < a, 0 if equal\nfunction bnCompareTo(a) {\n  var this_array = this.array;\n  var a_array = a.array;\n\n  var r = this.s - a.s;\n  if (r != 0) return r;\n  var i = this.t;\n  r = i - a.t;\n  if (r != 0) return r;\n  while (--i >= 0) if ((r = this_array[i] - a_array[i]) != 0) return r;\n  return 0;\n}\n\n// returns bit length of the integer x\nfunction nbits(x) {\n  var r = 1,\n    t;\n  if ((t = x >>> 16) != 0) {\n    x = t;\n    r += 16;\n  }\n  if ((t = x >> 8) != 0) {\n    x = t;\n    r += 8;\n  }\n  if ((t = x >> 4) != 0) {\n    x = t;\n    r += 4;\n  }\n  if ((t = x >> 2) != 0) {\n    x = t;\n    r += 2;\n  }\n  if ((t = x >> 1) != 0) {\n    x = t;\n    r += 1;\n  }\n  return r;\n}\n\n// (public) return the number of bits in \"this\"\nfunction bnBitLength() {\n  var this_array = this.array;\n  if (this.t <= 0) return 0;\n  return (\n    BI_DB * (this.t - 1) + nbits(this_array[this.t - 1] ^ (this.s & BI_DM))\n  );\n}\n\n// (protected) r = this << n*DB\nfunction bnpDLShiftTo(n, r) {\n  var this_array = this.array;\n  var r_array = r.array;\n  var i;\n  for (i = this.t - 1; i >= 0; --i) r_array[i + n] = this_array[i];\n  for (i = n - 1; i >= 0; --i) r_array[i] = 0;\n  r.t = this.t + n;\n  r.s = this.s;\n}\n\n// (protected) r = this >> n*DB\nfunction bnpDRShiftTo(n, r) {\n  var this_array = this.array;\n  var r_array = r.array;\n  for (var i = n; i < this.t; ++i) r_array[i - n] = this_array[i];\n  r.t = Math.max(this.t - n, 0);\n  r.s = this.s;\n}\n\n// (protected) r = this << n\nfunction bnpLShiftTo(n, r) {\n  var this_array = this.array;\n  var r_array = r.array;\n  var bs = n % BI_DB;\n  var cbs = BI_DB - bs;\n  var bm = (1 << cbs) - 1;\n  var ds = Math.floor(n / BI_DB),\n    c = (this.s << bs) & BI_DM,\n    i;\n  for (i = this.t - 1; i >= 0; --i) {\n    r_array[i + ds + 1] = (this_array[i] >> cbs) | c;\n    c = (this_array[i] & bm) << bs;\n  }\n  for (i = ds - 1; i >= 0; --i) r_array[i] = 0;\n  r_array[ds] = c;\n  r.t = this.t + ds + 1;\n  r.s = this.s;\n  r.clamp();\n}\n\n// (protected) r = this >> n\nfunction bnpRShiftTo(n, r) {\n  var this_array = this.array;\n  var r_array = r.array;\n  r.s = this.s;\n  var ds = Math.floor(n / BI_DB);\n  if (ds >= this.t) {\n    r.t = 0;\n    return;\n  }\n  var bs = n % BI_DB;\n  var cbs = BI_DB - bs;\n  var bm = (1 << bs) - 1;\n  r_array[0] = this_array[ds] >> bs;\n  for (var i = ds + 1; i < this.t; ++i) {\n    r_array[i - ds - 1] |= (this_array[i] & bm) << cbs;\n    r_array[i - ds] = this_array[i] >> bs;\n  }\n  if (bs > 0) r_array[this.t - ds - 1] |= (this.s & bm) << cbs;\n  r.t = this.t - ds;\n  r.clamp();\n}\n\n// (protected) r = this - a\nfunction bnpSubTo(a, r) {\n  var this_array = this.array;\n  var r_array = r.array;\n  var a_array = a.array;\n  var i = 0,\n    c = 0,\n    m = Math.min(a.t, this.t);\n  while (i < m) {\n    c += this_array[i] - a_array[i];\n    r_array[i++] = c & BI_DM;\n    c >>= BI_DB;\n  }\n  if (a.t < this.t) {\n    c -= a.s;\n    while (i < this.t) {\n      c += this_array[i];\n      r_array[i++] = c & BI_DM;\n      c >>= BI_DB;\n    }\n    c += this.s;\n  } else {\n    c += this.s;\n    while (i < a.t) {\n      c -= a_array[i];\n      r_array[i++] = c & BI_DM;\n      c >>= BI_DB;\n    }\n    c -= a.s;\n  }\n  r.s = c < 0 ? -1 : 0;\n  if (c < -1) r_array[i++] = BI_DV + c;\n  else if (c > 0) r_array[i++] = c;\n  r.t = i;\n  r.clamp();\n}\n\n// (protected) r = this * a, r != this,a (HAC 14.12)\n// \"this\" should be the larger one if appropriate.\nfunction bnpMultiplyTo(a, r) {\n  var this_array = this.array;\n  var r_array = r.array;\n  var x = this.abs(),\n    y = a.abs();\n  var y_array = y.array;\n\n  var i = x.t;\n  r.t = i + y.t;\n  while (--i >= 0) r_array[i] = 0;\n  for (i = 0; i < y.t; ++i)\n    r_array[i + x.t] = x.am(0, y_array[i], r, i, 0, x.t);\n  r.s = 0;\n  r.clamp();\n  if (this.s != a.s) BigInteger.ZERO.subTo(r, r);\n}\n\n// (protected) r = this^2, r != this (HAC 14.16)\nfunction bnpSquareTo(r) {\n  var x = this.abs();\n  var x_array = x.array;\n  var r_array = r.array;\n\n  var i = (r.t = 2 * x.t);\n  while (--i >= 0) r_array[i] = 0;\n  for (i = 0; i < x.t - 1; ++i) {\n    var c = x.am(i, x_array[i], r, 2 * i, 0, 1);\n    if (\n      (r_array[i + x.t] += x.am(\n        i + 1,\n        2 * x_array[i],\n        r,\n        2 * i + 1,\n        c,\n        x.t - i - 1\n      )) >= BI_DV\n    ) {\n      r_array[i + x.t] -= BI_DV;\n      r_array[i + x.t + 1] = 1;\n    }\n  }\n  if (r.t > 0) r_array[r.t - 1] += x.am(i, x_array[i], r, 2 * i, 0, 1);\n  r.s = 0;\n  r.clamp();\n}\n\n// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)\n// r != q, this != m.  q or r may be null.\nfunction bnpDivRemTo(m, q, r) {\n  var pm = m.abs();\n  if (pm.t <= 0) return;\n  var pt = this.abs();\n  if (pt.t < pm.t) {\n    if (q != null) q.fromInt(0);\n    if (r != null) this.copyTo(r);\n    return;\n  }\n  if (r == null) r = nbi();\n  var y = nbi(),\n    ts = this.s,\n    ms = m.s;\n  var pm_array = pm.array;\n  var nsh = BI_DB - nbits(pm_array[pm.t - 1]); // normalize modulus\n  if (nsh > 0) {\n    pm.lShiftTo(nsh, y);\n    pt.lShiftTo(nsh, r);\n  } else {\n    pm.copyTo(y);\n    pt.copyTo(r);\n  }\n  var ys = y.t;\n\n  var y_array = y.array;\n  var y0 = y_array[ys - 1];\n  if (y0 == 0) return;\n  var yt = y0 * (1 << BI_F1) + (ys > 1 ? y_array[ys - 2] >> BI_F2 : 0);\n  var d1 = BI_FV / yt,\n    d2 = (1 << BI_F1) / yt,\n    e = 1 << BI_F2;\n  var i = r.t,\n    j = i - ys,\n    t = q == null ? nbi() : q;\n  y.dlShiftTo(j, t);\n\n  var r_array = r.array;\n  if (r.compareTo(t) >= 0) {\n    r_array[r.t++] = 1;\n    r.subTo(t, r);\n  }\n  BigInteger.ONE.dlShiftTo(ys, t);\n  t.subTo(y, y); // \"negative\" y so we can replace sub with am later\n  while (y.t < ys) y_array[y.t++] = 0;\n  while (--j >= 0) {\n    // Estimate quotient digit\n    var qd =\n      r_array[--i] == y0\n        ? BI_DM\n        : Math.floor(r_array[i] * d1 + (r_array[i - 1] + e) * d2);\n    if ((r_array[i] += y.am(0, qd, r, j, 0, ys)) < qd) {\n      // Try it out\n      y.dlShiftTo(j, t);\n      r.subTo(t, r);\n      while (r_array[i] < --qd) r.subTo(t, r);\n    }\n  }\n  if (q != null) {\n    r.drShiftTo(ys, q);\n    if (ts != ms) BigInteger.ZERO.subTo(q, q);\n  }\n  r.t = ys;\n  r.clamp();\n  if (nsh > 0) r.rShiftTo(nsh, r); // Denormalize remainder\n  if (ts < 0) BigInteger.ZERO.subTo(r, r);\n}\n\n// (public) this mod a\nfunction bnMod(a) {\n  var r = nbi();\n  this.abs().divRemTo(a, null, r);\n  if (this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r, r);\n  return r;\n}\n\n// Modular reduction using \"classic\" algorithm\nfunction Classic(m) {\n  this.m = m;\n}\nfunction cConvert(x) {\n  if (x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);\n  else return x;\n}\nfunction cRevert(x) {\n  return x;\n}\nfunction cReduce(x) {\n  x.divRemTo(this.m, null, x);\n}\nfunction cMulTo(x, y, r) {\n  x.multiplyTo(y, r);\n  this.reduce(r);\n}\nfunction cSqrTo(x, r) {\n  x.squareTo(r);\n  this.reduce(r);\n}\n\nClassic.prototype.convert = cConvert;\nClassic.prototype.revert = cRevert;\nClassic.prototype.reduce = cReduce;\nClassic.prototype.mulTo = cMulTo;\nClassic.prototype.sqrTo = cSqrTo;\n\n// (protected) return \"-1/this % 2^DB\"; useful for Mont. reduction\n// justification:\n//         xy == 1 (mod m)\n//         xy =  1+km\n//   xy(2-xy) = (1+km)(1-km)\n// x[y(2-xy)] = 1-k^2m^2\n// x[y(2-xy)] == 1 (mod m^2)\n// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2\n// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.\n// JS multiply \"overflows\" differently from C/C++, so care is needed here.\nfunction bnpInvDigit() {\n  var this_array = this.array;\n  if (this.t < 1) return 0;\n  var x = this_array[0];\n  if ((x & 1) == 0) return 0;\n  var y = x & 3; // y == 1/x mod 2^2\n  y = (y * (2 - (x & 0xf) * y)) & 0xf; // y == 1/x mod 2^4\n  y = (y * (2 - (x & 0xff) * y)) & 0xff; // y == 1/x mod 2^8\n  y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16\n  // last step - calculate inverse mod DV directly;\n  // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints\n  y = (y * (2 - ((x * y) % BI_DV))) % BI_DV; // y == 1/x mod 2^dbits\n  // we really want the negative inverse, and -DV < y < DV\n  return y > 0 ? BI_DV - y : -y;\n}\n\n// Montgomery reduction\nfunction Montgomery(m) {\n  this.m = m;\n  this.mp = m.invDigit();\n  this.mpl = this.mp & 0x7fff;\n  this.mph = this.mp >> 15;\n  this.um = (1 << (BI_DB - 15)) - 1;\n  this.mt2 = 2 * m.t;\n}\n\n// xR mod m\nfunction montConvert(x) {\n  var r = nbi();\n  x.abs().dlShiftTo(this.m.t, r);\n  r.divRemTo(this.m, null, r);\n  if (x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r, r);\n  return r;\n}\n\n// x/R mod m\nfunction montRevert(x) {\n  var r = nbi();\n  x.copyTo(r);\n  this.reduce(r);\n  return r;\n}\n\n// x = x/R mod m (HAC 14.32)\nfunction montReduce(x) {\n  var x_array = x.array;\n  while (x.t <= this.mt2)\n    // pad x so am has enough room later\n    x_array[x.t++] = 0;\n  for (var i = 0; i < this.m.t; ++i) {\n    // faster way of calculating u0 = x[i]*mp mod DV\n    var j = x_array[i] & 0x7fff;\n    var u0 =\n      (j * this.mpl +\n        (((j * this.mph + (x_array[i] >> 15) * this.mpl) & this.um) << 15)) &\n      BI_DM;\n    // use am to combine the multiply-shift-add into one call\n    j = i + this.m.t;\n    x_array[j] += this.m.am(0, u0, x, i, 0, this.m.t);\n    // propagate carry\n    while (x_array[j] >= BI_DV) {\n      x_array[j] -= BI_DV;\n      x_array[++j]++;\n    }\n  }\n  x.clamp();\n  x.drShiftTo(this.m.t, x);\n  if (x.compareTo(this.m) >= 0) x.subTo(this.m, x);\n}\n\n// r = \"x^2/R mod m\"; x != r\nfunction montSqrTo(x, r) {\n  x.squareTo(r);\n  this.reduce(r);\n}\n\n// r = \"xy/R mod m\"; x,y != r\nfunction montMulTo(x, y, r) {\n  x.multiplyTo(y, r);\n  this.reduce(r);\n}\n\nMontgomery.prototype.convert = montConvert;\nMontgomery.prototype.revert = montRevert;\nMontgomery.prototype.reduce = montReduce;\nMontgomery.prototype.mulTo = montMulTo;\nMontgomery.prototype.sqrTo = montSqrTo;\n\n// (protected) true iff this is even\nfunction bnpIsEven() {\n  var this_array = this.array;\n  return (this.t > 0 ? this_array[0] & 1 : this.s) == 0;\n}\n\n// (protected) this^e, e < 2^32, doing sqr and mul with \"r\" (HAC 14.79)\nfunction bnpExp(e, z) {\n  if (e > 0xffffffff || e < 1) return BigInteger.ONE;\n  var r = nbi(),\n    r2 = nbi(),\n    g = z.convert(this),\n    i = nbits(e) - 1;\n  g.copyTo(r);\n  while (--i >= 0) {\n    z.sqrTo(r, r2);\n    if ((e & (1 << i)) > 0) z.mulTo(r2, g, r);\n    else {\n      var t = r;\n      r = r2;\n      r2 = t;\n    }\n  }\n  return z.revert(r);\n}\n\n// (public) this^e % m, 0 <= e < 2^32\nfunction bnModPowInt(e, m) {\n  var z;\n  if (e < 256 || m.isEven()) z = new Classic(m);\n  else z = new Montgomery(m);\n  return this.exp(e, z);\n}\n\n// protected\nBigInteger.prototype.copyTo = bnpCopyTo;\nBigInteger.prototype.fromInt = bnpFromInt;\nBigInteger.prototype.fromString = bnpFromString;\nBigInteger.prototype.clamp = bnpClamp;\nBigInteger.prototype.dlShiftTo = bnpDLShiftTo;\nBigInteger.prototype.drShiftTo = bnpDRShiftTo;\nBigInteger.prototype.lShiftTo = bnpLShiftTo;\nBigInteger.prototype.rShiftTo = bnpRShiftTo;\nBigInteger.prototype.subTo = bnpSubTo;\nBigInteger.prototype.multiplyTo = bnpMultiplyTo;\nBigInteger.prototype.squareTo = bnpSquareTo;\nBigInteger.prototype.divRemTo = bnpDivRemTo;\nBigInteger.prototype.invDigit = bnpInvDigit;\nBigInteger.prototype.isEven = bnpIsEven;\nBigInteger.prototype.exp = bnpExp;\n\n// public\nBigInteger.prototype.toString = bnToString;\nBigInteger.prototype.negate = bnNegate;\nBigInteger.prototype.abs = bnAbs;\nBigInteger.prototype.compareTo = bnCompareTo;\nBigInteger.prototype.bitLength = bnBitLength;\nBigInteger.prototype.mod = bnMod;\nBigInteger.prototype.modPowInt = bnModPowInt;\n\n// \"constants\"\nBigInteger.ZERO = nbv(0);\nBigInteger.ONE = nbv(1);\n// Copyright (c) 2005  Tom Wu\n// All Rights Reserved.\n// See \"LICENSE\" for details.\n\n// Extended JavaScript BN functions, required for RSA private ops.\n\n// (public)\nfunction bnClone() {\n  var r = nbi();\n  this.copyTo(r);\n  return r;\n}\n\n// (public) return value as integer\nfunction bnIntValue() {\n  var this_array = this.array;\n  if (this.s < 0) {\n    if (this.t == 1) return this_array[0] - BI_DV;\n    else if (this.t == 0) return -1;\n  } else if (this.t == 1) return this_array[0];\n  else if (this.t == 0) return 0;\n  // assumes 16 < DB < 32\n  return ((this_array[1] & ((1 << (32 - BI_DB)) - 1)) << BI_DB) | this_array[0];\n}\n\n// (public) return value as byte\nfunction bnByteValue() {\n  var this_array = this.array;\n  return this.t == 0 ? this.s : (this_array[0] << 24) >> 24;\n}\n\n// (public) return value as short (assumes DB>=16)\nfunction bnShortValue() {\n  var this_array = this.array;\n  return this.t == 0 ? this.s : (this_array[0] << 16) >> 16;\n}\n\n// (protected) return x s.t. r^x < DV\nfunction bnpChunkSize(r) {\n  return Math.floor((Math.LN2 * BI_DB) / Math.log(r));\n}\n\n// (public) 0 if this == 0, 1 if this > 0\nfunction bnSigNum() {\n  var this_array = this.array;\n  if (this.s < 0) return -1;\n  else if (this.t <= 0 || (this.t == 1 && this_array[0] <= 0)) return 0;\n  else return 1;\n}\n\n// (protected) convert to radix string\nfunction bnpToRadix(b) {\n  if (b == null) b = 10;\n  if (this.signum() == 0 || b < 2 || b > 36) return \"0\";\n  var cs = this.chunkSize(b);\n  var a = Math.pow(b, cs);\n  var d = nbv(a),\n    y = nbi(),\n    z = nbi(),\n    r = \"\";\n  this.divRemTo(d, y, z);\n  while (y.signum() > 0) {\n    r = (a + z.intValue()).toString(b).substr(1) + r;\n    y.divRemTo(d, y, z);\n  }\n  return z.intValue().toString(b) + r;\n}\n\n// (protected) convert from radix string\nfunction bnpFromRadix(s, b) {\n  this.fromInt(0);\n  if (b == null) b = 10;\n  var cs = this.chunkSize(b);\n  var d = Math.pow(b, cs),\n    mi = false,\n    j = 0,\n    w = 0;\n  for (var i = 0; i < s.length; ++i) {\n    var x = intAt(s, i);\n    if (x < 0) {\n      if (s.charAt(i) == \"-\" && this.signum() == 0) mi = true;\n      continue;\n    }\n    w = b * w + x;\n    if (++j >= cs) {\n      this.dMultiply(d);\n      this.dAddOffset(w, 0);\n      j = 0;\n      w = 0;\n    }\n  }\n  if (j > 0) {\n    this.dMultiply(Math.pow(b, j));\n    this.dAddOffset(w, 0);\n  }\n  if (mi) BigInteger.ZERO.subTo(this, this);\n}\n\n// (protected) alternate constructor\nfunction bnpFromNumber(a, b, c) {\n  if (\"number\" == typeof b) {\n    // new BigInteger(int,int,RNG)\n    if (a < 2) this.fromInt(1);\n    else {\n      this.fromNumber(a, c);\n      if (!this.testBit(a - 1))\n        // force MSB set\n        this.bitwiseTo(BigInteger.ONE.shiftLeft(a - 1), op_or, this);\n      if (this.isEven()) this.dAddOffset(1, 0); // force odd\n      while (!this.isProbablePrime(b)) {\n        this.dAddOffset(2, 0);\n        if (this.bitLength() > a)\n          this.subTo(BigInteger.ONE.shiftLeft(a - 1), this);\n      }\n    }\n  } else {\n    // new BigInteger(int,RNG)\n    var x = new Array(),\n      t = a & 7;\n    x.length = (a >> 3) + 1;\n    b.nextBytes(x);\n    if (t > 0) x[0] &= (1 << t) - 1;\n    else x[0] = 0;\n    this.fromString(x, 256);\n  }\n}\n\n// (public) convert to bigendian byte array\nfunction bnToByteArray() {\n  var this_array = this.array;\n  var i = this.t,\n    r = new Array();\n  r[0] = this.s;\n  var p = BI_DB - ((i * BI_DB) % 8),\n    d,\n    k = 0;\n  if (i-- > 0) {\n    if (p < BI_DB && (d = this_array[i] >> p) != (this.s & BI_DM) >> p)\n      r[k++] = d | (this.s << (BI_DB - p));\n    while (i >= 0) {\n      if (p < 8) {\n        d = (this_array[i] & ((1 << p) - 1)) << (8 - p);\n        d |= this_array[--i] >> (p += BI_DB - 8);\n      } else {\n        d = (this_array[i] >> (p -= 8)) & 0xff;\n        if (p <= 0) {\n          p += BI_DB;\n          --i;\n        }\n      }\n      if ((d & 0x80) != 0) d |= -256;\n      if (k == 0 && (this.s & 0x80) != (d & 0x80)) ++k;\n      if (k > 0 || d != this.s) r[k++] = d;\n    }\n  }\n  return r;\n}\n\nfunction bnEquals(a) {\n  return this.compareTo(a) == 0;\n}\nfunction bnMin(a) {\n  return this.compareTo(a) < 0 ? this : a;\n}\nfunction bnMax(a) {\n  return this.compareTo(a) > 0 ? this : a;\n}\n\n// (protected) r = this op a (bitwise)\nfunction bnpBitwiseTo(a, op, r) {\n  var this_array = this.array;\n  var a_array = a.array;\n  var r_array = r.array;\n  var i,\n    f,\n    m = Math.min(a.t, this.t);\n  for (i = 0; i < m; ++i) r_array[i] = op(this_array[i], a_array[i]);\n  if (a.t < this.t) {\n    f = a.s & BI_DM;\n    for (i = m; i < this.t; ++i) r_array[i] = op(this_array[i], f);\n    r.t = this.t;\n  } else {\n    f = this.s & BI_DM;\n    for (i = m; i < a.t; ++i) r_array[i] = op(f, a_array[i]);\n    r.t = a.t;\n  }\n  r.s = op(this.s, a.s);\n  r.clamp();\n}\n\n// (public) this & a\nfunction op_and(x, y) {\n  return x & y;\n}\nfunction bnAnd(a) {\n  var r = nbi();\n  this.bitwiseTo(a, op_and, r);\n  return r;\n}\n\n// (public) this | a\nfunction op_or(x, y) {\n  return x | y;\n}\nfunction bnOr(a) {\n  var r = nbi();\n  this.bitwiseTo(a, op_or, r);\n  return r;\n}\n\n// (public) this ^ a\nfunction op_xor(x, y) {\n  return x ^ y;\n}\nfunction bnXor(a) {\n  var r = nbi();\n  this.bitwiseTo(a, op_xor, r);\n  return r;\n}\n\n// (public) this & ~a\nfunction op_andnot(x, y) {\n  return x & ~y;\n}\nfunction bnAndNot(a) {\n  var r = nbi();\n  this.bitwiseTo(a, op_andnot, r);\n  return r;\n}\n\n// (public) ~this\nfunction bnNot() {\n  var this_array = this.array;\n  var r = nbi();\n  var r_array = r.array;\n\n  for (var i = 0; i < this.t; ++i) r_array[i] = BI_DM & ~this_array[i];\n  r.t = this.t;\n  r.s = ~this.s;\n  return r;\n}\n\n// (public) this << n\nfunction bnShiftLeft(n) {\n  var r = nbi();\n  if (n < 0) this.rShiftTo(-n, r);\n  else this.lShiftTo(n, r);\n  return r;\n}\n\n// (public) this >> n\nfunction bnShiftRight(n) {\n  var r = nbi();\n  if (n < 0) this.lShiftTo(-n, r);\n  else this.rShiftTo(n, r);\n  return r;\n}\n\n// return index of lowest 1-bit in x, x < 2^31\nfunction lbit(x) {\n  if (x == 0) return -1;\n  var r = 0;\n  if ((x & 0xffff) == 0) {\n    x >>= 16;\n    r += 16;\n  }\n  if ((x & 0xff) == 0) {\n    x >>= 8;\n    r += 8;\n  }\n  if ((x & 0xf) == 0) {\n    x >>= 4;\n    r += 4;\n  }\n  if ((x & 3) == 0) {\n    x >>= 2;\n    r += 2;\n  }\n  if ((x & 1) == 0) ++r;\n  return r;\n}\n\n// (public) returns index of lowest 1-bit (or -1 if none)\nfunction bnGetLowestSetBit() {\n  var this_array = this.array;\n  for (var i = 0; i < this.t; ++i)\n    if (this_array[i] != 0) return i * BI_DB + lbit(this_array[i]);\n  if (this.s < 0) return this.t * BI_DB;\n  return -1;\n}\n\n// return number of 1 bits in x\nfunction cbit(x) {\n  var r = 0;\n  while (x != 0) {\n    x &= x - 1;\n    ++r;\n  }\n  return r;\n}\n\n// (public) return number of set bits\nfunction bnBitCount() {\n  var r = 0,\n    x = this.s & BI_DM;\n  for (var i = 0; i < this.t; ++i) r += cbit(this_array[i] ^ x);\n  return r;\n}\n\n// (public) true iff nth bit is set\nfunction bnTestBit(n) {\n  var this_array = this.array;\n  var j = Math.floor(n / BI_DB);\n  if (j >= this.t) return this.s != 0;\n  return (this_array[j] & (1 << n % BI_DB)) != 0;\n}\n\n// (protected) this op (1<<n)\nfunction bnpChangeBit(n, op) {\n  var r = BigInteger.ONE.shiftLeft(n);\n  this.bitwiseTo(r, op, r);\n  return r;\n}\n\n// (public) this | (1<<n)\nfunction bnSetBit(n) {\n  return this.changeBit(n, op_or);\n}\n\n// (public) this & ~(1<<n)\nfunction bnClearBit(n) {\n  return this.changeBit(n, op_andnot);\n}\n\n// (public) this ^ (1<<n)\nfunction bnFlipBit(n) {\n  return this.changeBit(n, op_xor);\n}\n\n// (protected) r = this + a\nfunction bnpAddTo(a, r) {\n  var this_array = this.array;\n  var a_array = a.array;\n  var r_array = r.array;\n  var i = 0,\n    c = 0,\n    m = Math.min(a.t, this.t);\n  while (i < m) {\n    c += this_array[i] + a_array[i];\n    r_array[i++] = c & BI_DM;\n    c >>= BI_DB;\n  }\n  if (a.t < this.t) {\n    c += a.s;\n    while (i < this.t) {\n      c += this_array[i];\n      r_array[i++] = c & BI_DM;\n      c >>= BI_DB;\n    }\n    c += this.s;\n  } else {\n    c += this.s;\n    while (i < a.t) {\n      c += a_array[i];\n      r_array[i++] = c & BI_DM;\n      c >>= BI_DB;\n    }\n    c += a.s;\n  }\n  r.s = c < 0 ? -1 : 0;\n  if (c > 0) r_array[i++] = c;\n  else if (c < -1) r_array[i++] = BI_DV + c;\n  r.t = i;\n  r.clamp();\n}\n\n// (public) this + a\nfunction bnAdd(a) {\n  var r = nbi();\n  this.addTo(a, r);\n  return r;\n}\n\n// (public) this - a\nfunction bnSubtract(a) {\n  var r = nbi();\n  this.subTo(a, r);\n  return r;\n}\n\n// (public) this * a\nfunction bnMultiply(a) {\n  var r = nbi();\n  this.multiplyTo(a, r);\n  return r;\n}\n\n// (public) this / a\nfunction bnDivide(a) {\n  var r = nbi();\n  this.divRemTo(a, r, null);\n  return r;\n}\n\n// (public) this % a\nfunction bnRemainder(a) {\n  var r = nbi();\n  this.divRemTo(a, null, r);\n  return r;\n}\n\n// (public) [this/a,this%a]\nfunction bnDivideAndRemainder(a) {\n  var q = nbi(),\n    r = nbi();\n  this.divRemTo(a, q, r);\n  return new Array(q, r);\n}\n\n// (protected) this *= n, this >= 0, 1 < n < DV\nfunction bnpDMultiply(n) {\n  var this_array = this.array;\n  this_array[this.t] = this.am(0, n - 1, this, 0, 0, this.t);\n  ++this.t;\n  this.clamp();\n}\n\n// (protected) this += n << w words, this >= 0\nfunction bnpDAddOffset(n, w) {\n  var this_array = this.array;\n  while (this.t <= w) this_array[this.t++] = 0;\n  this_array[w] += n;\n  while (this_array[w] >= BI_DV) {\n    this_array[w] -= BI_DV;\n    if (++w >= this.t) this_array[this.t++] = 0;\n    ++this_array[w];\n  }\n}\n\n// A \"null\" reducer\nfunction NullExp() {}\nfunction nNop(x) {\n  return x;\n}\nfunction nMulTo(x, y, r) {\n  x.multiplyTo(y, r);\n}\nfunction nSqrTo(x, r) {\n  x.squareTo(r);\n}\n\nNullExp.prototype.convert = nNop;\nNullExp.prototype.revert = nNop;\nNullExp.prototype.mulTo = nMulTo;\nNullExp.prototype.sqrTo = nSqrTo;\n\n// (public) this^e\nfunction bnPow(e) {\n  return this.exp(e, new NullExp());\n}\n\n// (protected) r = lower n words of \"this * a\", a.t <= n\n// \"this\" should be the larger one if appropriate.\nfunction bnpMultiplyLowerTo(a, n, r) {\n  var r_array = r.array;\n  var a_array = a.array;\n  var i = Math.min(this.t + a.t, n);\n  r.s = 0; // assumes a,this >= 0\n  r.t = i;\n  while (i > 0) r_array[--i] = 0;\n  var j;\n  for (j = r.t - this.t; i < j; ++i)\n    r_array[i + this.t] = this.am(0, a_array[i], r, i, 0, this.t);\n  for (j = Math.min(a.t, n); i < j; ++i) this.am(0, a_array[i], r, i, 0, n - i);\n  r.clamp();\n}\n\n// (protected) r = \"this * a\" without lower n words, n > 0\n// \"this\" should be the larger one if appropriate.\nfunction bnpMultiplyUpperTo(a, n, r) {\n  var r_array = r.array;\n  var a_array = a.array;\n  --n;\n  var i = (r.t = this.t + a.t - n);\n  r.s = 0; // assumes a,this >= 0\n  while (--i >= 0) r_array[i] = 0;\n  for (i = Math.max(n - this.t, 0); i < a.t; ++i)\n    r_array[this.t + i - n] = this.am(\n      n - i,\n      a_array[i],\n      r,\n      0,\n      0,\n      this.t + i - n\n    );\n  r.clamp();\n  r.drShiftTo(1, r);\n}\n\n// Barrett modular reduction\nfunction Barrett(m) {\n  // setup Barrett\n  this.r2 = nbi();\n  this.q3 = nbi();\n  BigInteger.ONE.dlShiftTo(2 * m.t, this.r2);\n  this.mu = this.r2.divide(m);\n  this.m = m;\n}\n\nfunction barrettConvert(x) {\n  if (x.s < 0 || x.t > 2 * this.m.t) return x.mod(this.m);\n  else if (x.compareTo(this.m) < 0) return x;\n  else {\n    var r = nbi();\n    x.copyTo(r);\n    this.reduce(r);\n    return r;\n  }\n}\n\nfunction barrettRevert(x) {\n  return x;\n}\n\n// x = x mod m (HAC 14.42)\nfunction barrettReduce(x) {\n  x.drShiftTo(this.m.t - 1, this.r2);\n  if (x.t > this.m.t + 1) {\n    x.t = this.m.t + 1;\n    x.clamp();\n  }\n  this.mu.multiplyUpperTo(this.r2, this.m.t + 1, this.q3);\n  this.m.multiplyLowerTo(this.q3, this.m.t + 1, this.r2);\n  while (x.compareTo(this.r2) < 0) x.dAddOffset(1, this.m.t + 1);\n  x.subTo(this.r2, x);\n  while (x.compareTo(this.m) >= 0) x.subTo(this.m, x);\n}\n\n// r = x^2 mod m; x != r\nfunction barrettSqrTo(x, r) {\n  x.squareTo(r);\n  this.reduce(r);\n}\n\n// r = x*y mod m; x,y != r\nfunction barrettMulTo(x, y, r) {\n  x.multiplyTo(y, r);\n  this.reduce(r);\n}\n\nBarrett.prototype.convert = barrettConvert;\nBarrett.prototype.revert = barrettRevert;\nBarrett.prototype.reduce = barrettReduce;\nBarrett.prototype.mulTo = barrettMulTo;\nBarrett.prototype.sqrTo = barrettSqrTo;\n\n// (public) this^e % m (HAC 14.85)\nfunction bnModPow(e, m) {\n  var e_array = e.array;\n  var i = e.bitLength(),\n    k,\n    r = nbv(1),\n    z;\n  if (i <= 0) return r;\n  else if (i < 18) k = 1;\n  else if (i < 48) k = 3;\n  else if (i < 144) k = 4;\n  else if (i < 768) k = 5;\n  else k = 6;\n  if (i < 8) z = new Classic(m);\n  else if (m.isEven()) z = new Barrett(m);\n  else z = new Montgomery(m);\n\n  // precomputation\n  var g = new Array(),\n    n = 3,\n    k1 = k - 1,\n    km = (1 << k) - 1;\n  g[1] = z.convert(this);\n  if (k > 1) {\n    var g2 = nbi();\n    z.sqrTo(g[1], g2);\n    while (n <= km) {\n      g[n] = nbi();\n      z.mulTo(g2, g[n - 2], g[n]);\n      n += 2;\n    }\n  }\n\n  var j = e.t - 1,\n    w,\n    is1 = true,\n    r2 = nbi(),\n    t;\n  i = nbits(e_array[j]) - 1;\n  while (j >= 0) {\n    if (i >= k1) w = (e_array[j] >> (i - k1)) & km;\n    else {\n      w = (e_array[j] & ((1 << (i + 1)) - 1)) << (k1 - i);\n      if (j > 0) w |= e_array[j - 1] >> (BI_DB + i - k1);\n    }\n\n    n = k;\n    while ((w & 1) == 0) {\n      w >>= 1;\n      --n;\n    }\n    if ((i -= n) < 0) {\n      i += BI_DB;\n      --j;\n    }\n    if (is1) {\n      // ret == 1, don't bother squaring or multiplying it\n      g[w].copyTo(r);\n      is1 = false;\n    } else {\n      while (n > 1) {\n        z.sqrTo(r, r2);\n        z.sqrTo(r2, r);\n        n -= 2;\n      }\n      if (n > 0) z.sqrTo(r, r2);\n      else {\n        t = r;\n        r = r2;\n        r2 = t;\n      }\n      z.mulTo(r2, g[w], r);\n    }\n\n    while (j >= 0 && (e_array[j] & (1 << i)) == 0) {\n      z.sqrTo(r, r2);\n      t = r;\n      r = r2;\n      r2 = t;\n      if (--i < 0) {\n        i = BI_DB - 1;\n        --j;\n      }\n    }\n  }\n  return z.revert(r);\n}\n\n// (public) gcd(this,a) (HAC 14.54)\nfunction bnGCD(a) {\n  var x = this.s < 0 ? this.negate() : this.clone();\n  var y = a.s < 0 ? a.negate() : a.clone();\n  if (x.compareTo(y) < 0) {\n    var t = x;\n    x = y;\n    y = t;\n  }\n  var i = x.getLowestSetBit(),\n    g = y.getLowestSetBit();\n  if (g < 0) return x;\n  if (i < g) g = i;\n  if (g > 0) {\n    x.rShiftTo(g, x);\n    y.rShiftTo(g, y);\n  }\n  while (x.signum() > 0) {\n    if ((i = x.getLowestSetBit()) > 0) x.rShiftTo(i, x);\n    if ((i = y.getLowestSetBit()) > 0) y.rShiftTo(i, y);\n    if (x.compareTo(y) >= 0) {\n      x.subTo(y, x);\n      x.rShiftTo(1, x);\n    } else {\n      y.subTo(x, y);\n      y.rShiftTo(1, y);\n    }\n  }\n  if (g > 0) y.lShiftTo(g, y);\n  return y;\n}\n\n// (protected) this % n, n < 2^26\nfunction bnpModInt(n) {\n  var this_array = this.array;\n  if (n <= 0) return 0;\n  var d = BI_DV % n,\n    r = this.s < 0 ? n - 1 : 0;\n  if (this.t > 0)\n    if (d == 0) r = this_array[0] % n;\n    else for (var i = this.t - 1; i >= 0; --i) r = (d * r + this_array[i]) % n;\n  return r;\n}\n\n// (public) 1/this % m (HAC 14.61)\nfunction bnModInverse(m) {\n  var ac = m.isEven();\n  if ((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;\n  var u = m.clone(),\n    v = this.clone();\n  var a = nbv(1),\n    b = nbv(0),\n    c = nbv(0),\n    d = nbv(1);\n  while (u.signum() != 0) {\n    while (u.isEven()) {\n      u.rShiftTo(1, u);\n      if (ac) {\n        if (!a.isEven() || !b.isEven()) {\n          a.addTo(this, a);\n          b.subTo(m, b);\n        }\n        a.rShiftTo(1, a);\n      } else if (!b.isEven()) b.subTo(m, b);\n      b.rShiftTo(1, b);\n    }\n    while (v.isEven()) {\n      v.rShiftTo(1, v);\n      if (ac) {\n        if (!c.isEven() || !d.isEven()) {\n          c.addTo(this, c);\n          d.subTo(m, d);\n        }\n        c.rShiftTo(1, c);\n      } else if (!d.isEven()) d.subTo(m, d);\n      d.rShiftTo(1, d);\n    }\n    if (u.compareTo(v) >= 0) {\n      u.subTo(v, u);\n      if (ac) a.subTo(c, a);\n      b.subTo(d, b);\n    } else {\n      v.subTo(u, v);\n      if (ac) c.subTo(a, c);\n      d.subTo(b, d);\n    }\n  }\n  if (v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;\n  if (d.compareTo(m) >= 0) return d.subtract(m);\n  if (d.signum() < 0) d.addTo(m, d);\n  else return d;\n  if (d.signum() < 0) return d.add(m);\n  else return d;\n}\n\nvar lowprimes = [\n  2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,\n  73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,\n  157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233,\n  239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317,\n  331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,\n  421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503,\n  509,\n];\nvar lplim = (1 << 26) / lowprimes[lowprimes.length - 1];\n\n// (public) test primality with certainty >= 1-.5^t\nfunction bnIsProbablePrime(t) {\n  var i,\n    x = this.abs();\n  var x_array = x.array;\n  if (x.t == 1 && x_array[0] <= lowprimes[lowprimes.length - 1]) {\n    for (i = 0; i < lowprimes.length; ++i)\n      if (x_array[0] == lowprimes[i]) return true;\n    return false;\n  }\n  if (x.isEven()) return false;\n  i = 1;\n  while (i < lowprimes.length) {\n    var m = lowprimes[i],\n      j = i + 1;\n    while (j < lowprimes.length && m < lplim) m *= lowprimes[j++];\n    m = x.modInt(m);\n    while (i < j) if (m % lowprimes[i++] == 0) return false;\n  }\n  return x.millerRabin(t);\n}\n\n// (protected) true if probably prime (HAC 4.24, Miller-Rabin)\nfunction bnpMillerRabin(t) {\n  var n1 = this.subtract(BigInteger.ONE);\n  var k = n1.getLowestSetBit();\n  if (k <= 0) return false;\n  var r = n1.shiftRight(k);\n  t = (t + 1) >> 1;\n  if (t > lowprimes.length) t = lowprimes.length;\n  var a = nbi();\n  for (var i = 0; i < t; ++i) {\n    a.fromInt(lowprimes[i]);\n    var y = a.modPow(r, this);\n    if (y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {\n      var j = 1;\n      while (j++ < k && y.compareTo(n1) != 0) {\n        y = y.modPowInt(2, this);\n        if (y.compareTo(BigInteger.ONE) == 0) return false;\n      }\n      if (y.compareTo(n1) != 0) return false;\n    }\n  }\n  return true;\n}\n\n// protected\nBigInteger.prototype.chunkSize = bnpChunkSize;\nBigInteger.prototype.toRadix = bnpToRadix;\nBigInteger.prototype.fromRadix = bnpFromRadix;\nBigInteger.prototype.fromNumber = bnpFromNumber;\nBigInteger.prototype.bitwiseTo = bnpBitwiseTo;\nBigInteger.prototype.changeBit = bnpChangeBit;\nBigInteger.prototype.addTo = bnpAddTo;\nBigInteger.prototype.dMultiply = bnpDMultiply;\nBigInteger.prototype.dAddOffset = bnpDAddOffset;\nBigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo;\nBigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo;\nBigInteger.prototype.modInt = bnpModInt;\nBigInteger.prototype.millerRabin = bnpMillerRabin;\n\n// public\nBigInteger.prototype.clone = bnClone;\nBigInteger.prototype.intValue = bnIntValue;\nBigInteger.prototype.byteValue = bnByteValue;\nBigInteger.prototype.shortValue = bnShortValue;\nBigInteger.prototype.signum = bnSigNum;\nBigInteger.prototype.toByteArray = bnToByteArray;\nBigInteger.prototype.equals = bnEquals;\nBigInteger.prototype.min = bnMin;\nBigInteger.prototype.max = bnMax;\nBigInteger.prototype.and = bnAnd;\nBigInteger.prototype.or = bnOr;\nBigInteger.prototype.xor = bnXor;\nBigInteger.prototype.andNot = bnAndNot;\nBigInteger.prototype.not = bnNot;\nBigInteger.prototype.shiftLeft = bnShiftLeft;\nBigInteger.prototype.shiftRight = bnShiftRight;\nBigInteger.prototype.getLowestSetBit = bnGetLowestSetBit;\nBigInteger.prototype.bitCount = bnBitCount;\nBigInteger.prototype.testBit = bnTestBit;\nBigInteger.prototype.setBit = bnSetBit;\nBigInteger.prototype.clearBit = bnClearBit;\nBigInteger.prototype.flipBit = bnFlipBit;\nBigInteger.prototype.add = bnAdd;\nBigInteger.prototype.subtract = bnSubtract;\nBigInteger.prototype.multiply = bnMultiply;\nBigInteger.prototype.divide = bnDivide;\nBigInteger.prototype.remainder = bnRemainder;\nBigInteger.prototype.divideAndRemainder = bnDivideAndRemainder;\nBigInteger.prototype.modPow = bnModPow;\nBigInteger.prototype.modInverse = bnModInverse;\nBigInteger.prototype.pow = bnPow;\nBigInteger.prototype.gcd = bnGCD;\nBigInteger.prototype.isProbablePrime = bnIsProbablePrime;\n\n// BigInteger interfaces not implemented in jsbn:\n\n// BigInteger(int signum, byte[] magnitude)\n// double doubleValue()\n// float floatValue()\n// int hashCode()\n// long longValue()\n// static BigInteger valueOf(long val)\n// prng4.js - uses Arcfour as a PRNG\n\nfunction Arcfour() {\n  this.i = 0;\n  this.j = 0;\n  this.S = new Array();\n}\n\n// Initialize arcfour context from key, an array of ints, each from [0..255]\nfunction ARC4init(key) {\n  var i, j, t;\n  for (i = 0; i < 256; ++i) this.S[i] = i;\n  j = 0;\n  for (i = 0; i < 256; ++i) {\n    j = (j + this.S[i] + key[i % key.length]) & 255;\n    t = this.S[i];\n    this.S[i] = this.S[j];\n    this.S[j] = t;\n  }\n  this.i = 0;\n  this.j = 0;\n}\n\nfunction ARC4next() {\n  var t;\n  this.i = (this.i + 1) & 255;\n  this.j = (this.j + this.S[this.i]) & 255;\n  t = this.S[this.i];\n  this.S[this.i] = this.S[this.j];\n  this.S[this.j] = t;\n  return this.S[(t + this.S[this.i]) & 255];\n}\n\nArcfour.prototype.init = ARC4init;\nArcfour.prototype.next = ARC4next;\n\n// Plug in your RNG constructor here\nfunction prng_newstate() {\n  return new Arcfour();\n}\n\n// Pool size must be a multiple of 4 and greater than 32.\n// An array of bytes the size of the pool will be passed to init()\nvar rng_psize = 256;\n// Random number generator - requires a PRNG backend, e.g. prng4.js\n\n// For best results, put code like\n// <body onClick='rng_seed_time();' onKeyPress='rng_seed_time();'>\n// in your main HTML document.\n\nvar rng_state;\nvar rng_pool;\nvar rng_pptr;\n\n// Mix in a 32-bit integer into the pool\nfunction rng_seed_int(x) {\n  rng_pool[rng_pptr++] ^= x & 255;\n  rng_pool[rng_pptr++] ^= (x >> 8) & 255;\n  rng_pool[rng_pptr++] ^= (x >> 16) & 255;\n  rng_pool[rng_pptr++] ^= (x >> 24) & 255;\n  if (rng_pptr >= rng_psize) rng_pptr -= rng_psize;\n}\n\n// Mix in the current time (w/milliseconds) into the pool\nfunction rng_seed_time() {\n  // Use pre-computed date to avoid making the benchmark\n  // results dependent on the current date.\n  rng_seed_int(1122926989487);\n}\n\n// Initialize the pool with junk if needed.\nif (rng_pool == null) {\n  rng_pool = new Array();\n  rng_pptr = 0;\n  var t;\n  while (rng_pptr < rng_psize) {\n    // extract some randomness from Math.random()\n    t = Math.floor(65536 * Math.random());\n    rng_pool[rng_pptr++] = t >>> 8;\n    rng_pool[rng_pptr++] = t & 255;\n  }\n  rng_pptr = 0;\n  rng_seed_time();\n  //rng_seed_int(window.screenX);\n  //rng_seed_int(window.screenY);\n}\n\nfunction rng_get_byte() {\n  if (rng_state == null) {\n    rng_seed_time();\n    rng_state = prng_newstate();\n    rng_state.init(rng_pool);\n    for (rng_pptr = 0; rng_pptr < rng_pool.length; ++rng_pptr)\n      rng_pool[rng_pptr] = 0;\n    rng_pptr = 0;\n    //rng_pool = null;\n  }\n  // TODO: allow reseeding after first request\n  return rng_state.next();\n}\n\nfunction rng_get_bytes(ba) {\n  var i;\n  for (i = 0; i < ba.length; ++i) ba[i] = rng_get_byte();\n}\n\nfunction SecureRandom() {}\n\nSecureRandom.prototype.nextBytes = rng_get_bytes;\n// Depends on jsbn.js and rng.js\n\n// convert a (hex) string to a bignum object\nfunction parseBigInt(str, r) {\n  return new BigInteger(str, r);\n}\n\nfunction linebrk(s, n) {\n  var ret = \"\";\n  var i = 0;\n  while (i + n < s.length) {\n    ret += s.substring(i, i + n) + \"\\n\";\n    i += n;\n  }\n  return ret + s.substring(i, s.length);\n}\n\nfunction byte2Hex(b) {\n  if (b < 0x10) return \"0\" + b.toString(16);\n  else return b.toString(16);\n}\n\n// PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint\nfunction pkcs1pad2(s, n) {\n  if (n < s.length + 11) {\n    alert(\"Message too long for RSA\");\n    return null;\n  }\n  var ba = new Array();\n  var i = s.length - 1;\n  while (i >= 0 && n > 0) ba[--n] = s.charCodeAt(i--);\n  ba[--n] = 0;\n  var rng = new SecureRandom();\n  var x = new Array();\n  while (n > 2) {\n    // random non-zero pad\n    x[0] = 0;\n    while (x[0] == 0) rng.nextBytes(x);\n    ba[--n] = x[0];\n  }\n  ba[--n] = 2;\n  ba[--n] = 0;\n  return new BigInteger(ba);\n}\n\n// \"empty\" RSA key constructor\nfunction RSAKey() {\n  this.n = null;\n  this.e = 0;\n  this.d = null;\n  this.p = null;\n  this.q = null;\n  this.dmp1 = null;\n  this.dmq1 = null;\n  this.coeff = null;\n}\n\n// Set the public key fields N and e from hex strings\nfunction RSASetPublic(N, E) {\n  if (N != null && E != null && N.length > 0 && E.length > 0) {\n    this.n = parseBigInt(N, 16);\n    this.e = parseInt(E, 16);\n  } else alert(\"Invalid RSA public key\");\n}\n\n// Perform raw public operation on \"x\": return x^e (mod n)\nfunction RSADoPublic(x) {\n  return x.modPowInt(this.e, this.n);\n}\n\n// Return the PKCS#1 RSA encryption of \"text\" as an even-length hex string\nfunction RSAEncrypt(text) {\n  var m = pkcs1pad2(text, (this.n.bitLength() + 7) >> 3);\n  if (m == null) return null;\n  var c = this.doPublic(m);\n  if (c == null) return null;\n  var h = c.toString(16);\n  if ((h.length & 1) == 0) return h;\n  else return \"0\" + h;\n}\n\n// Return the PKCS#1 RSA encryption of \"text\" as a Base64-encoded string\n//function RSAEncryptB64(text) {\n//  var h = this.encrypt(text);\n//  if(h) return hex2b64(h); else return null;\n//}\n\n// protected\nRSAKey.prototype.doPublic = RSADoPublic;\n\n// public\nRSAKey.prototype.setPublic = RSASetPublic;\nRSAKey.prototype.encrypt = RSAEncrypt;\n//RSAKey.prototype.encrypt_b64 = RSAEncryptB64;\n// Depends on rsa.js and jsbn2.js\n\n// Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext\nfunction pkcs1unpad2(d, n) {\n  var b = d.toByteArray();\n  var i = 0;\n  while (i < b.length && b[i] == 0) ++i;\n  if (b.length - i != n - 1 || b[i] != 2) return null;\n  ++i;\n  while (b[i] != 0) if (++i >= b.length) return null;\n  var ret = \"\";\n  while (++i < b.length) ret += String.fromCharCode(b[i]);\n  return ret;\n}\n\n// Set the private key fields N, e, and d from hex strings\nfunction RSASetPrivate(N, E, D) {\n  if (N != null && E != null && N.length > 0 && E.length > 0) {\n    this.n = parseBigInt(N, 16);\n    this.e = parseInt(E, 16);\n    this.d = parseBigInt(D, 16);\n  } else alert(\"Invalid RSA private key\");\n}\n\n// Set the private key fields N, e, d and CRT params from hex strings\nfunction RSASetPrivateEx(N, E, D, P, Q, DP, DQ, C) {\n  if (N != null && E != null && N.length > 0 && E.length > 0) {\n    this.n = parseBigInt(N, 16);\n    this.e = parseInt(E, 16);\n    this.d = parseBigInt(D, 16);\n    this.p = parseBigInt(P, 16);\n    this.q = parseBigInt(Q, 16);\n    this.dmp1 = parseBigInt(DP, 16);\n    this.dmq1 = parseBigInt(DQ, 16);\n    this.coeff = parseBigInt(C, 16);\n  } else alert(\"Invalid RSA private key\");\n}\n\n// Generate a new random private key B bits long, using public expt E\nfunction RSAGenerate(B, E) {\n  var rng = new SecureRandom();\n  var qs = B >> 1;\n  this.e = parseInt(E, 16);\n  var ee = new BigInteger(E, 16);\n  for (;;) {\n    for (;;) {\n      this.p = new BigInteger(B - qs, 1, rng);\n      if (\n        this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) ==\n          0 &&\n        this.p.isProbablePrime(10)\n      )\n        break;\n    }\n    for (;;) {\n      this.q = new BigInteger(qs, 1, rng);\n      if (\n        this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) ==\n          0 &&\n        this.q.isProbablePrime(10)\n      )\n        break;\n    }\n    if (this.p.compareTo(this.q) <= 0) {\n      var t = this.p;\n      this.p = this.q;\n      this.q = t;\n    }\n    var p1 = this.p.subtract(BigInteger.ONE);\n    var q1 = this.q.subtract(BigInteger.ONE);\n    var phi = p1.multiply(q1);\n    if (phi.gcd(ee).compareTo(BigInteger.ONE) == 0) {\n      this.n = this.p.multiply(this.q);\n      this.d = ee.modInverse(phi);\n      this.dmp1 = this.d.mod(p1);\n      this.dmq1 = this.d.mod(q1);\n      this.coeff = this.q.modInverse(this.p);\n      break;\n    }\n  }\n}\n\n// Perform raw private operation on \"x\": return x^d (mod n)\nfunction RSADoPrivate(x) {\n  if (this.p == null || this.q == null) return x.modPow(this.d, this.n);\n\n  // TODO: re-calculate any missing CRT params\n  var xp = x.mod(this.p).modPow(this.dmp1, this.p);\n  var xq = x.mod(this.q).modPow(this.dmq1, this.q);\n\n  while (xp.compareTo(xq) < 0) xp = xp.add(this.p);\n  return xp\n    .subtract(xq)\n    .multiply(this.coeff)\n    .mod(this.p)\n    .multiply(this.q)\n    .add(xq);\n}\n\n// Return the PKCS#1 RSA decryption of \"ctext\".\n// \"ctext\" is an even-length hex string and the output is a plain string.\nfunction RSADecrypt(ctext) {\n  var c = parseBigInt(ctext, 16);\n  var m = this.doPrivate(c);\n  if (m == null) return null;\n  return pkcs1unpad2(m, (this.n.bitLength() + 7) >> 3);\n}\n\n// Return the PKCS#1 RSA decryption of \"ctext\".\n// \"ctext\" is a Base64-encoded string and the output is a plain string.\n//function RSAB64Decrypt(ctext) {\n//  var h = b64tohex(ctext);\n//  if(h) return this.decrypt(h); else return null;\n//}\n\n// protected\nRSAKey.prototype.doPrivate = RSADoPrivate;\n\n// public\nRSAKey.prototype.setPrivate = RSASetPrivate;\nRSAKey.prototype.setPrivateEx = RSASetPrivateEx;\nRSAKey.prototype.generate = RSAGenerate;\nRSAKey.prototype.decrypt = RSADecrypt;\n//RSAKey.prototype.b64_decrypt = RSAB64Decrypt;\n\nnValue =\n  \"a5261939975948bb7a58dffe5ff54e65f0498f9175f5a09288810b8975871e99af3b5dd94057b0fc07535f5f97444504fa35169d461d0d30cf0192e307727c065168c788771c561a9400fb49175e9e6aa4e23fe11af69e9412dd23b0cb6684c4c2429bce139e848ab26d0829073351f4acd36074eafd036a5eb83359d2a698d3\";\neValue = \"10001\";\ndValue =\n  \"8e9912f6d3645894e8d38cb58c0db81ff516cf4c7e5a14c7f1eddb1459d2cded4d8d293fc97aee6aefb861859c8b6a3d1dfe710463e1f9ddc72048c09751971c4a580aa51eb523357a3cc48d31cfad1d4a165066ed92d4748fb6571211da5cb14bc11b6e2df7c1a559e6d5ac1cd5c94703a22891464fba23d0d965086277a161\";\npValue =\n  \"d090ce58a92c75233a6486cb0a9209bf3583b64f540c76f5294bb97d285eed33aec220bde14b2417951178ac152ceab6da7090905b478195498b352048f15e7d\";\nqValue =\n  \"cab575dc652bb66df15a0359609d51d1db184750c00c6698b90ef3465c99655103edbf0d54c56aec0ce3c4d22592338092a126a0cc49f65a4a30d222b411e58f\";\ndmp1Value =\n  \"1a24bca8e273df2f0e47c199bbf678604e7df7215480c77c8db39f49b000ce2cf7500038acfff5433b7d582a01f1826e6f4d42e1c57f5e1fef7b12aabc59fd25\";\ndmq1Value =\n  \"3d06982efbbe47339e1f6d36b1216b8a741d410b0c662f54f7118b27b9a4ec9d914337eb39841d8666f3034408cf94f5b62f11c402fc994fe15a05493150d9fd\";\ncoeffValue =\n  \"3a3e731acd8960b7ff9eb81a7ff93bd1cfa74cbd56987db58b4594fb09c09084db1734c8143f98b602b981aaa9243ca28deb69b5b280ee8dcee0fd2625e53250\";\n\nsetupEngine(am3, 28);\n\nvar TEXT =\n  \"The quick brown fox jumped over the extremely lazy frog! \" +\n  \"Now is the time for all good men to come to the party.\";\nvar encrypted;\n\nfunction encrypt() {\n  var RSA = new RSAKey();\n  RSA.setPublic(nValue, eValue);\n  RSA.setPrivateEx(\n    nValue,\n    eValue,\n    dValue,\n    pValue,\n    qValue,\n    dmp1Value,\n    dmq1Value,\n    coeffValue\n  );\n  encrypted = RSA.encrypt(TEXT);\n}\n\nfunction decrypt() {\n  var RSA = new RSAKey();\n  RSA.setPublic(nValue, eValue);\n  RSA.setPrivateEx(\n    nValue,\n    eValue,\n    dValue,\n    pValue,\n    qValue,\n    dmp1Value,\n    dmq1Value,\n    coeffValue\n  );\n  var decrypted = RSA.decrypt(encrypted);\n  if (decrypted != TEXT) {\n    throw new Error(\"Crypto operation failed\");\n  }\n}\n"
  },
  {
    "path": "benchmarks/v8-v7/deltablue.js",
    "content": "// Copyright 2008 the V8 project authors. All rights reserved.\n// Copyright 1996 John Maloney and Mario Wolczko.\n\n// This program is free software; you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation; either version 2 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program; if not, write to the Free Software\n// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n\n// This implementation of the DeltaBlue benchmark is derived\n// from the Smalltalk implementation by John Maloney and Mario\n// Wolczko. Some parts have been translated directly, whereas\n// others have been modified more aggresively to make it feel\n// more like a JavaScript program.\n\nvar DeltaBlue = new BenchmarkSuite(\"DeltaBlue\", 66118, [\n  new Benchmark(\"DeltaBlue\", deltaBlue),\n]);\n\n/**\n * A JavaScript implementation of the DeltaBlue constraint-solving\n * algorithm, as described in:\n *\n * \"The DeltaBlue Algorithm: An Incremental Constraint Hierarchy Solver\"\n *   Bjorn N. Freeman-Benson and John Maloney\n *   January 1990 Communications of the ACM,\n *   also available as University of Washington TR 89-08-06.\n *\n * Beware: this benchmark is written in a grotesque style where\n * the constraint model is built by side-effects from constructors.\n * I've kept it this way to avoid deviating too much from the original\n * implementation.\n */\n\n/* --- O b j e c t   M o d e l --- */\n\nObject.prototype.inheritsFrom = function (shuper) {\n  function Inheriter() {}\n  Inheriter.prototype = shuper.prototype;\n  this.prototype = new Inheriter();\n  this.superConstructor = shuper;\n};\n\nfunction OrderedCollection() {\n  this.elms = new Array();\n}\n\nOrderedCollection.prototype.add = function (elm) {\n  this.elms.push(elm);\n};\n\nOrderedCollection.prototype.at = function (index) {\n  return this.elms[index];\n};\n\nOrderedCollection.prototype.size = function () {\n  return this.elms.length;\n};\n\nOrderedCollection.prototype.removeFirst = function () {\n  return this.elms.pop();\n};\n\nOrderedCollection.prototype.remove = function (elm) {\n  var index = 0,\n    skipped = 0;\n  for (var i = 0; i < this.elms.length; i++) {\n    var value = this.elms[i];\n    if (value != elm) {\n      this.elms[index] = value;\n      index++;\n    } else {\n      skipped++;\n    }\n  }\n  for (var i = 0; i < skipped; i++) this.elms.pop();\n};\n\n/* --- *\n * S t r e n g t h\n * --- */\n\n/**\n * Strengths are used to measure the relative importance of constraints.\n * New strengths may be inserted in the strength hierarchy without\n * disrupting current constraints.  Strengths cannot be created outside\n * this class, so pointer comparison can be used for value comparison.\n */\nfunction Strength(strengthValue, name) {\n  this.strengthValue = strengthValue;\n  this.name = name;\n}\n\nStrength.stronger = function (s1, s2) {\n  return s1.strengthValue < s2.strengthValue;\n};\n\nStrength.weaker = function (s1, s2) {\n  return s1.strengthValue > s2.strengthValue;\n};\n\nStrength.weakestOf = function (s1, s2) {\n  return this.weaker(s1, s2) ? s1 : s2;\n};\n\nStrength.strongest = function (s1, s2) {\n  return this.stronger(s1, s2) ? s1 : s2;\n};\n\nStrength.prototype.nextWeaker = function () {\n  switch (this.strengthValue) {\n    case 0:\n      return Strength.WEAKEST;\n    case 1:\n      return Strength.WEAK_DEFAULT;\n    case 2:\n      return Strength.NORMAL;\n    case 3:\n      return Strength.STRONG_DEFAULT;\n    case 4:\n      return Strength.PREFERRED;\n    case 5:\n      return Strength.REQUIRED;\n  }\n};\n\n// Strength constants.\nStrength.REQUIRED = new Strength(0, \"required\");\nStrength.STONG_PREFERRED = new Strength(1, \"strongPreferred\");\nStrength.PREFERRED = new Strength(2, \"preferred\");\nStrength.STRONG_DEFAULT = new Strength(3, \"strongDefault\");\nStrength.NORMAL = new Strength(4, \"normal\");\nStrength.WEAK_DEFAULT = new Strength(5, \"weakDefault\");\nStrength.WEAKEST = new Strength(6, \"weakest\");\n\n/* --- *\n * C o n s t r a i n t\n * --- */\n\n/**\n * An abstract class representing a system-maintainable relationship\n * (or \"constraint\") between a set of variables. A constraint supplies\n * a strength instance variable; concrete subclasses provide a means\n * of storing the constrained variables and other information required\n * to represent a constraint.\n */\nfunction Constraint(strength) {\n  this.strength = strength;\n}\n\n/**\n * Activate this constraint and attempt to satisfy it.\n */\nConstraint.prototype.addConstraint = function () {\n  this.addToGraph();\n  planner.incrementalAdd(this);\n};\n\n/**\n * Attempt to find a way to enforce this constraint. If successful,\n * record the solution, perhaps modifying the current dataflow\n * graph. Answer the constraint that this constraint overrides, if\n * there is one, or nil, if there isn't.\n * Assume: I am not already satisfied.\n */\nConstraint.prototype.satisfy = function (mark) {\n  this.chooseMethod(mark);\n  if (!this.isSatisfied()) {\n    if (this.strength == Strength.REQUIRED)\n      alert(\"Could not satisfy a required constraint!\");\n    return null;\n  }\n  this.markInputs(mark);\n  var out = this.output();\n  var overridden = out.determinedBy;\n  if (overridden != null) overridden.markUnsatisfied();\n  out.determinedBy = this;\n  if (!planner.addPropagate(this, mark)) alert(\"Cycle encountered\");\n  out.mark = mark;\n  return overridden;\n};\n\nConstraint.prototype.destroyConstraint = function () {\n  if (this.isSatisfied()) planner.incrementalRemove(this);\n  else this.removeFromGraph();\n};\n\n/**\n * Normal constraints are not input constraints.  An input constraint\n * is one that depends on external state, such as the mouse, the\n * keybord, a clock, or some arbitraty piece of imperative code.\n */\nConstraint.prototype.isInput = function () {\n  return false;\n};\n\n/* --- *\n * U n a r y   C o n s t r a i n t\n * --- */\n\n/**\n * Abstract superclass for constraints having a single possible output\n * variable.\n */\nfunction UnaryConstraint(v, strength) {\n  UnaryConstraint.superConstructor.call(this, strength);\n  this.myOutput = v;\n  this.satisfied = false;\n  this.addConstraint();\n}\n\nUnaryConstraint.inheritsFrom(Constraint);\n\n/**\n * Adds this constraint to the constraint graph\n */\nUnaryConstraint.prototype.addToGraph = function () {\n  this.myOutput.addConstraint(this);\n  this.satisfied = false;\n};\n\n/**\n * Decides if this constraint can be satisfied and records that\n * decision.\n */\nUnaryConstraint.prototype.chooseMethod = function (mark) {\n  this.satisfied =\n    this.myOutput.mark != mark &&\n    Strength.stronger(this.strength, this.myOutput.walkStrength);\n};\n\n/**\n * Returns true if this constraint is satisfied in the current solution.\n */\nUnaryConstraint.prototype.isSatisfied = function () {\n  return this.satisfied;\n};\n\nUnaryConstraint.prototype.markInputs = function (mark) {\n  // has no inputs\n};\n\n/**\n * Returns the current output variable.\n */\nUnaryConstraint.prototype.output = function () {\n  return this.myOutput;\n};\n\n/**\n * Calculate the walkabout strength, the stay flag, and, if it is\n * 'stay', the value for the current output of this constraint. Assume\n * this constraint is satisfied.\n */\nUnaryConstraint.prototype.recalculate = function () {\n  this.myOutput.walkStrength = this.strength;\n  this.myOutput.stay = !this.isInput();\n  if (this.myOutput.stay) this.execute(); // Stay optimization\n};\n\n/**\n * Records that this constraint is unsatisfied\n */\nUnaryConstraint.prototype.markUnsatisfied = function () {\n  this.satisfied = false;\n};\n\nUnaryConstraint.prototype.inputsKnown = function () {\n  return true;\n};\n\nUnaryConstraint.prototype.removeFromGraph = function () {\n  if (this.myOutput != null) this.myOutput.removeConstraint(this);\n  this.satisfied = false;\n};\n\n/* --- *\n * S t a y   C o n s t r a i n t\n * --- */\n\n/**\n * Variables that should, with some level of preference, stay the same.\n * Planners may exploit the fact that instances, if satisfied, will not\n * change their output during plan execution.  This is called \"stay\n * optimization\".\n */\nfunction StayConstraint(v, str) {\n  StayConstraint.superConstructor.call(this, v, str);\n}\n\nStayConstraint.inheritsFrom(UnaryConstraint);\n\nStayConstraint.prototype.execute = function () {\n  // Stay constraints do nothing\n};\n\n/* --- *\n * E d i t   C o n s t r a i n t\n * --- */\n\n/**\n * A unary input constraint used to mark a variable that the client\n * wishes to change.\n */\nfunction EditConstraint(v, str) {\n  EditConstraint.superConstructor.call(this, v, str);\n}\n\nEditConstraint.inheritsFrom(UnaryConstraint);\n\n/**\n * Edits indicate that a variable is to be changed by imperative code.\n */\nEditConstraint.prototype.isInput = function () {\n  return true;\n};\n\nEditConstraint.prototype.execute = function () {\n  // Edit constraints do nothing\n};\n\n/* --- *\n * B i n a r y   C o n s t r a i n t\n * --- */\n\nvar Direction = new Object();\nDirection.NONE = 0;\nDirection.FORWARD = 1;\nDirection.BACKWARD = -1;\n\n/**\n * Abstract superclass for constraints having two possible output\n * variables.\n */\nfunction BinaryConstraint(var1, var2, strength) {\n  BinaryConstraint.superConstructor.call(this, strength);\n  this.v1 = var1;\n  this.v2 = var2;\n  this.direction = Direction.NONE;\n  this.addConstraint();\n}\n\nBinaryConstraint.inheritsFrom(Constraint);\n\n/**\n * Decides if this constraint can be satisfied and which way it\n * should flow based on the relative strength of the variables related,\n * and record that decision.\n */\nBinaryConstraint.prototype.chooseMethod = function (mark) {\n  if (this.v1.mark == mark) {\n    this.direction =\n      this.v2.mark != mark &&\n      Strength.stronger(this.strength, this.v2.walkStrength)\n        ? Direction.FORWARD\n        : Direction.NONE;\n  }\n  if (this.v2.mark == mark) {\n    this.direction =\n      this.v1.mark != mark &&\n      Strength.stronger(this.strength, this.v1.walkStrength)\n        ? Direction.BACKWARD\n        : Direction.NONE;\n  }\n  if (Strength.weaker(this.v1.walkStrength, this.v2.walkStrength)) {\n    this.direction = Strength.stronger(this.strength, this.v1.walkStrength)\n      ? Direction.BACKWARD\n      : Direction.NONE;\n  } else {\n    this.direction = Strength.stronger(this.strength, this.v2.walkStrength)\n      ? Direction.FORWARD\n      : Direction.BACKWARD;\n  }\n};\n\n/**\n * Add this constraint to the constraint graph\n */\nBinaryConstraint.prototype.addToGraph = function () {\n  this.v1.addConstraint(this);\n  this.v2.addConstraint(this);\n  this.direction = Direction.NONE;\n};\n\n/**\n * Answer true if this constraint is satisfied in the current solution.\n */\nBinaryConstraint.prototype.isSatisfied = function () {\n  return this.direction != Direction.NONE;\n};\n\n/**\n * Mark the input variable with the given mark.\n */\nBinaryConstraint.prototype.markInputs = function (mark) {\n  this.input().mark = mark;\n};\n\n/**\n * Returns the current input variable\n */\nBinaryConstraint.prototype.input = function () {\n  return this.direction == Direction.FORWARD ? this.v1 : this.v2;\n};\n\n/**\n * Returns the current output variable\n */\nBinaryConstraint.prototype.output = function () {\n  return this.direction == Direction.FORWARD ? this.v2 : this.v1;\n};\n\n/**\n * Calculate the walkabout strength, the stay flag, and, if it is\n * 'stay', the value for the current output of this\n * constraint. Assume this constraint is satisfied.\n */\nBinaryConstraint.prototype.recalculate = function () {\n  var ihn = this.input(),\n    out = this.output();\n  out.walkStrength = Strength.weakestOf(this.strength, ihn.walkStrength);\n  out.stay = ihn.stay;\n  if (out.stay) this.execute();\n};\n\n/**\n * Record the fact that this constraint is unsatisfied.\n */\nBinaryConstraint.prototype.markUnsatisfied = function () {\n  this.direction = Direction.NONE;\n};\n\nBinaryConstraint.prototype.inputsKnown = function (mark) {\n  var i = this.input();\n  return i.mark == mark || i.stay || i.determinedBy == null;\n};\n\nBinaryConstraint.prototype.removeFromGraph = function () {\n  if (this.v1 != null) this.v1.removeConstraint(this);\n  if (this.v2 != null) this.v2.removeConstraint(this);\n  this.direction = Direction.NONE;\n};\n\n/* --- *\n * S c a l e   C o n s t r a i n t\n * --- */\n\n/**\n * Relates two variables by the linear scaling relationship: \"v2 =\n * (v1 * scale) + offset\". Either v1 or v2 may be changed to maintain\n * this relationship but the scale factor and offset are considered\n * read-only.\n */\nfunction ScaleConstraint(src, scale, offset, dest, strength) {\n  this.direction = Direction.NONE;\n  this.scale = scale;\n  this.offset = offset;\n  ScaleConstraint.superConstructor.call(this, src, dest, strength);\n}\n\nScaleConstraint.inheritsFrom(BinaryConstraint);\n\n/**\n * Adds this constraint to the constraint graph.\n */\nScaleConstraint.prototype.addToGraph = function () {\n  ScaleConstraint.superConstructor.prototype.addToGraph.call(this);\n  this.scale.addConstraint(this);\n  this.offset.addConstraint(this);\n};\n\nScaleConstraint.prototype.removeFromGraph = function () {\n  ScaleConstraint.superConstructor.prototype.removeFromGraph.call(this);\n  if (this.scale != null) this.scale.removeConstraint(this);\n  if (this.offset != null) this.offset.removeConstraint(this);\n};\n\nScaleConstraint.prototype.markInputs = function (mark) {\n  ScaleConstraint.superConstructor.prototype.markInputs.call(this, mark);\n  this.scale.mark = this.offset.mark = mark;\n};\n\n/**\n * Enforce this constraint. Assume that it is satisfied.\n */\nScaleConstraint.prototype.execute = function () {\n  if (this.direction == Direction.FORWARD) {\n    this.v2.value = this.v1.value * this.scale.value + this.offset.value;\n  } else {\n    this.v1.value = (this.v2.value - this.offset.value) / this.scale.value;\n  }\n};\n\n/**\n * Calculate the walkabout strength, the stay flag, and, if it is\n * 'stay', the value for the current output of this constraint. Assume\n * this constraint is satisfied.\n */\nScaleConstraint.prototype.recalculate = function () {\n  var ihn = this.input(),\n    out = this.output();\n  out.walkStrength = Strength.weakestOf(this.strength, ihn.walkStrength);\n  out.stay = ihn.stay && this.scale.stay && this.offset.stay;\n  if (out.stay) this.execute();\n};\n\n/* --- *\n * E q u a l i t  y   C o n s t r a i n t\n * --- */\n\n/**\n * Constrains two variables to have the same value.\n */\nfunction EqualityConstraint(var1, var2, strength) {\n  EqualityConstraint.superConstructor.call(this, var1, var2, strength);\n}\n\nEqualityConstraint.inheritsFrom(BinaryConstraint);\n\n/**\n * Enforce this constraint. Assume that it is satisfied.\n */\nEqualityConstraint.prototype.execute = function () {\n  this.output().value = this.input().value;\n};\n\n/* --- *\n * V a r i a b l e\n * --- */\n\n/**\n * A constrained variable. In addition to its value, it maintain the\n * structure of the constraint graph, the current dataflow graph, and\n * various parameters of interest to the DeltaBlue incremental\n * constraint solver.\n **/\nfunction Variable(name, initialValue) {\n  this.value = initialValue || 0;\n  this.constraints = new OrderedCollection();\n  this.determinedBy = null;\n  this.mark = 0;\n  this.walkStrength = Strength.WEAKEST;\n  this.stay = true;\n  this.name = name;\n}\n\n/**\n * Add the given constraint to the set of all constraints that refer\n * this variable.\n */\nVariable.prototype.addConstraint = function (c) {\n  this.constraints.add(c);\n};\n\n/**\n * Removes all traces of c from this variable.\n */\nVariable.prototype.removeConstraint = function (c) {\n  this.constraints.remove(c);\n  if (this.determinedBy == c) this.determinedBy = null;\n};\n\n/* --- *\n * P l a n n e r\n * --- */\n\n/**\n * The DeltaBlue planner\n */\nfunction Planner() {\n  this.currentMark = 0;\n}\n\n/**\n * Attempt to satisfy the given constraint and, if successful,\n * incrementally update the dataflow graph.  Details: If satifying\n * the constraint is successful, it may override a weaker constraint\n * on its output. The algorithm attempts to resatisfy that\n * constraint using some other method. This process is repeated\n * until either a) it reaches a variable that was not previously\n * determined by any constraint or b) it reaches a constraint that\n * is too weak to be satisfied using any of its methods. The\n * variables of constraints that have been processed are marked with\n * a unique mark value so that we know where we've been. This allows\n * the algorithm to avoid getting into an infinite loop even if the\n * constraint graph has an inadvertent cycle.\n */\nPlanner.prototype.incrementalAdd = function (c) {\n  var mark = this.newMark();\n  var overridden = c.satisfy(mark);\n  while (overridden != null) overridden = overridden.satisfy(mark);\n};\n\n/**\n * Entry point for retracting a constraint. Remove the given\n * constraint and incrementally update the dataflow graph.\n * Details: Retracting the given constraint may allow some currently\n * unsatisfiable downstream constraint to be satisfied. We therefore collect\n * a list of unsatisfied downstream constraints and attempt to\n * satisfy each one in turn. This list is traversed by constraint\n * strength, strongest first, as a heuristic for avoiding\n * unnecessarily adding and then overriding weak constraints.\n * Assume: c is satisfied.\n */\nPlanner.prototype.incrementalRemove = function (c) {\n  var out = c.output();\n  c.markUnsatisfied();\n  c.removeFromGraph();\n  var unsatisfied = this.removePropagateFrom(out);\n  var strength = Strength.REQUIRED;\n  do {\n    for (var i = 0; i < unsatisfied.size(); i++) {\n      var u = unsatisfied.at(i);\n      if (u.strength == strength) this.incrementalAdd(u);\n    }\n    strength = strength.nextWeaker();\n  } while (strength != Strength.WEAKEST);\n};\n\n/**\n * Select a previously unused mark value.\n */\nPlanner.prototype.newMark = function () {\n  return ++this.currentMark;\n};\n\n/**\n * Extract a plan for resatisfaction starting from the given source\n * constraints, usually a set of input constraints. This method\n * assumes that stay optimization is desired; the plan will contain\n * only constraints whose output variables are not stay. Constraints\n * that do no computation, such as stay and edit constraints, are\n * not included in the plan.\n * Details: The outputs of a constraint are marked when it is added\n * to the plan under construction. A constraint may be appended to\n * the plan when all its input variables are known. A variable is\n * known if either a) the variable is marked (indicating that has\n * been computed by a constraint appearing earlier in the plan), b)\n * the variable is 'stay' (i.e. it is a constant at plan execution\n * time), or c) the variable is not determined by any\n * constraint. The last provision is for past states of history\n * variables, which are not stay but which are also not computed by\n * any constraint.\n * Assume: sources are all satisfied.\n */\nPlanner.prototype.makePlan = function (sources) {\n  var mark = this.newMark();\n  var plan = new Plan();\n  var todo = sources;\n  while (todo.size() > 0) {\n    var c = todo.removeFirst();\n    if (c.output().mark != mark && c.inputsKnown(mark)) {\n      plan.addConstraint(c);\n      c.output().mark = mark;\n      this.addConstraintsConsumingTo(c.output(), todo);\n    }\n  }\n  return plan;\n};\n\n/**\n * Extract a plan for resatisfying starting from the output of the\n * given constraints, usually a set of input constraints.\n */\nPlanner.prototype.extractPlanFromConstraints = function (constraints) {\n  var sources = new OrderedCollection();\n  for (var i = 0; i < constraints.size(); i++) {\n    var c = constraints.at(i);\n    if (c.isInput() && c.isSatisfied())\n      // not in plan already and eligible for inclusion\n      sources.add(c);\n  }\n  return this.makePlan(sources);\n};\n\n/**\n * Recompute the walkabout strengths and stay flags of all variables\n * downstream of the given constraint and recompute the actual\n * values of all variables whose stay flag is true. If a cycle is\n * detected, remove the given constraint and answer\n * false. Otherwise, answer true.\n * Details: Cycles are detected when a marked variable is\n * encountered downstream of the given constraint. The sender is\n * assumed to have marked the inputs of the given constraint with\n * the given mark. Thus, encountering a marked node downstream of\n * the output constraint means that there is a path from the\n * constraint's output to one of its inputs.\n */\nPlanner.prototype.addPropagate = function (c, mark) {\n  var todo = new OrderedCollection();\n  todo.add(c);\n  while (todo.size() > 0) {\n    var d = todo.removeFirst();\n    if (d.output().mark == mark) {\n      this.incrementalRemove(c);\n      return false;\n    }\n    d.recalculate();\n    this.addConstraintsConsumingTo(d.output(), todo);\n  }\n  return true;\n};\n\n/**\n * Update the walkabout strengths and stay flags of all variables\n * downstream of the given constraint. Answer a collection of\n * unsatisfied constraints sorted in order of decreasing strength.\n */\nPlanner.prototype.removePropagateFrom = function (out) {\n  out.determinedBy = null;\n  out.walkStrength = Strength.WEAKEST;\n  out.stay = true;\n  var unsatisfied = new OrderedCollection();\n  var todo = new OrderedCollection();\n  todo.add(out);\n  while (todo.size() > 0) {\n    var v = todo.removeFirst();\n    for (var i = 0; i < v.constraints.size(); i++) {\n      var c = v.constraints.at(i);\n      if (!c.isSatisfied()) unsatisfied.add(c);\n    }\n    var determining = v.determinedBy;\n    for (var i = 0; i < v.constraints.size(); i++) {\n      var next = v.constraints.at(i);\n      if (next != determining && next.isSatisfied()) {\n        next.recalculate();\n        todo.add(next.output());\n      }\n    }\n  }\n  return unsatisfied;\n};\n\nPlanner.prototype.addConstraintsConsumingTo = function (v, coll) {\n  var determining = v.determinedBy;\n  var cc = v.constraints;\n  for (var i = 0; i < cc.size(); i++) {\n    var c = cc.at(i);\n    if (c != determining && c.isSatisfied()) coll.add(c);\n  }\n};\n\n/* --- *\n * P l a n\n * --- */\n\n/**\n * A Plan is an ordered list of constraints to be executed in sequence\n * to resatisfy all currently satisfiable constraints in the face of\n * one or more changing inputs.\n */\nfunction Plan() {\n  this.v = new OrderedCollection();\n}\n\nPlan.prototype.addConstraint = function (c) {\n  this.v.add(c);\n};\n\nPlan.prototype.size = function () {\n  return this.v.size();\n};\n\nPlan.prototype.constraintAt = function (index) {\n  return this.v.at(index);\n};\n\nPlan.prototype.execute = function () {\n  for (var i = 0; i < this.size(); i++) {\n    var c = this.constraintAt(i);\n    c.execute();\n  }\n};\n\n/* --- *\n * M a i n\n * --- */\n\n/**\n * This is the standard DeltaBlue benchmark. A long chain of equality\n * constraints is constructed with a stay constraint on one end. An\n * edit constraint is then added to the opposite end and the time is\n * measured for adding and removing this constraint, and extracting\n * and executing a constraint satisfaction plan. There are two cases.\n * In case 1, the added constraint is stronger than the stay\n * constraint and values must propagate down the entire length of the\n * chain. In case 2, the added constraint is weaker than the stay\n * constraint so it cannot be accomodated. The cost in this case is,\n * of course, very low. Typical situations lie somewhere between these\n * two extremes.\n */\nfunction chainTest(n) {\n  planner = new Planner();\n  var prev = null,\n    first = null,\n    last = null;\n\n  // Build chain of n equality constraints\n  for (var i = 0; i <= n; i++) {\n    var name = \"v\" + i;\n    var v = new Variable(name);\n    if (prev != null) new EqualityConstraint(prev, v, Strength.REQUIRED);\n    if (i == 0) first = v;\n    if (i == n) last = v;\n    prev = v;\n  }\n\n  new StayConstraint(last, Strength.STRONG_DEFAULT);\n  var edit = new EditConstraint(first, Strength.PREFERRED);\n  var edits = new OrderedCollection();\n  edits.add(edit);\n  var plan = planner.extractPlanFromConstraints(edits);\n  for (var i = 0; i < 100; i++) {\n    first.value = i;\n    plan.execute();\n    if (last.value != i) alert(\"Chain test failed.\");\n  }\n}\n\n/**\n * This test constructs a two sets of variables related to each\n * other by a simple linear transformation (scale and offset). The\n * time is measured to change a variable on either side of the\n * mapping and to change the scale and offset factors.\n */\nfunction projectionTest(n) {\n  planner = new Planner();\n  var scale = new Variable(\"scale\", 10);\n  var offset = new Variable(\"offset\", 1000);\n  var src = null,\n    dst = null;\n\n  var dests = new OrderedCollection();\n  for (var i = 0; i < n; i++) {\n    src = new Variable(\"src\" + i, i);\n    dst = new Variable(\"dst\" + i, i);\n    dests.add(dst);\n    new StayConstraint(src, Strength.NORMAL);\n    new ScaleConstraint(src, scale, offset, dst, Strength.REQUIRED);\n  }\n\n  change(src, 17);\n  if (dst.value != 1170) alert(\"Projection 1 failed\");\n  change(dst, 1050);\n  if (src.value != 5) alert(\"Projection 2 failed\");\n  change(scale, 5);\n  for (var i = 0; i < n - 1; i++) {\n    if (dests.at(i).value != i * 5 + 1000) alert(\"Projection 3 failed\");\n  }\n  change(offset, 2000);\n  for (var i = 0; i < n - 1; i++) {\n    if (dests.at(i).value != i * 5 + 2000) alert(\"Projection 4 failed\");\n  }\n}\n\nfunction change(v, newValue) {\n  var edit = new EditConstraint(v, Strength.PREFERRED);\n  var edits = new OrderedCollection();\n  edits.add(edit);\n  var plan = planner.extractPlanFromConstraints(edits);\n  for (var i = 0; i < 10; i++) {\n    v.value = newValue;\n    plan.execute();\n  }\n  edit.destroyConstraint();\n}\n\n// Global variable holding the current planner.\nvar planner = null;\n\nfunction deltaBlue() {\n  chainTest(100);\n  projectionTest(100);\n}\n"
  },
  {
    "path": "benchmarks/v8-v7/earley-boyer.js",
    "content": "// This file is automatically generated by scheme2js, except for the\n// benchmark harness code at the beginning and end of the file.\n\nvar EarleyBoyer = new BenchmarkSuite(\"EarleyBoyer\", 666463, [\n  new Benchmark(\"Earley\", function () {\n    BgL_earleyzd2benchmarkzd2();\n  }),\n  new Benchmark(\"Boyer\", function () {\n    BgL_nboyerzd2benchmarkzd2();\n  }),\n]);\n\n/************* GENERATED FILE - DO NOT EDIT *************/\n/************* GENERATED FILE - DO NOT EDIT *************/\n/************* GENERATED FILE - DO NOT EDIT *************/\n/************* GENERATED FILE - DO NOT EDIT *************/\n/************* GENERATED FILE - DO NOT EDIT *************/\n/************* GENERATED FILE - DO NOT EDIT *************/\n/************* GENERATED FILE - DO NOT EDIT *************/\n/************* GENERATED FILE - DO NOT EDIT *************/\n/*\n * To use write/prints/... the default-output port has to be set first.\n * Simply setting SC_DEFAULT_OUT and SC_ERROR_OUT to the desired values\n * should do the trick.\n * In the following example the std-out and error-port are redirected to\n * a DIV.\nfunction initRuntime() {\n    function escapeHTML(s) {\n\tvar tmp = s;\n\ttmp = tmp.replace(/&/g, \"&amp;\");\n\ttmp = tmp.replace(/</g, \"&lt;\");\n\ttmp = tmp.replace(/>/g, \"&gt;\");\n\ttmp = tmp.replace(/ /g, \"&nbsp;\");\n\ttmp = tmp.replace(/\\n/g, \"<br />\");\n\ttmp = tmp.replace(/\\t/g, \"&nbsp;&nbsp;&nbsp;&nbsp\");\n\treturn tmp;\n\t\n    }\n\n    document.write(\"<div id='stdout'></div>\");\n    SC_DEFAULT_OUT = new sc_GenericOutputPort(\n\tfunction(s) {\n\t    var stdout = document.getElementById('stdout');\n\t    stdout.innerHTML = stdout.innerHTML + escapeHTML(s);\n\t});\n    SC_ERROR_OUT = SC_DEFAULT_OUT;\n}\n*/\n\nfunction sc_print_debug() {\n  sc_print.apply(null, arguments);\n}\n/*** META ((export *js*)) */\nvar sc_JS_GLOBALS = this;\n\nvar __sc_LINE = -1;\nvar __sc_FILE = \"\";\n\n/*** META ((export #t)) */\nfunction sc_alert() {\n  var len = arguments.length;\n  var s = \"\";\n  var i;\n\n  for (i = 0; i < len; i++) {\n    s += sc_toDisplayString(arguments[i]);\n  }\n\n  return alert(s);\n}\n\n/*** META ((export #t)) */\nfunction sc_typeof(x) {\n  return typeof x;\n}\n\n/*** META ((export #t)) */\nfunction sc_error() {\n  var a = [sc_jsstring2symbol(\"*error*\")];\n  for (var i = 0; i < arguments.length; i++) {\n    a[i + 1] = arguments[i];\n  }\n  throw a;\n}\n\n/*** META ((export #t)\n           (peephole (prefix \"throw \")))\n*/\nfunction sc_raise(obj) {\n  throw obj;\n}\n\n/*** META ((export with-handler-lambda)) */\nfunction sc_withHandlerLambda(handler, body) {\n  try {\n    return body();\n  } catch (e) {\n    if (!e._internalException) return handler(e);\n    else throw e;\n  }\n}\n\nvar sc_properties = new Object();\n\n/*** META ((export #t)) */\nfunction sc_putpropBang(sym, key, val) {\n  var ht = sc_properties[sym];\n  if (!ht) {\n    ht = new Object();\n    sc_properties[sym] = ht;\n  }\n  ht[key] = val;\n}\n\n/*** META ((export #t)) */\nfunction sc_getprop(sym, key) {\n  var ht = sc_properties[sym];\n  if (ht) {\n    if (key in ht) return ht[key];\n    else return false;\n  } else return false;\n}\n\n/*** META ((export #t)) */\nfunction sc_rempropBang(sym, key) {\n  var ht = sc_properties[sym];\n  if (ht) delete ht[key];\n}\n\n/*** META ((export #t)) */\nfunction sc_any2String(o) {\n  return jsstring2string(sc_toDisplayString(o));\n}\n\n/*** META ((export #t)\n           (peephole (infix 2 2 \"===\"))\n           (type bool))\n*/\nfunction sc_isEqv(o1, o2) {\n  return o1 === o2;\n}\n\n/*** META ((export #t)\n           (peephole (infix 2 2 \"===\"))\n           (type bool))\n*/\nfunction sc_isEq(o1, o2) {\n  return o1 === o2;\n}\n\n/*** META ((export #t)\n           (type bool))\n*/\nfunction sc_isNumber(n) {\n  return typeof n === \"number\";\n}\n\n/*** META ((export #t)\n           (type bool))\n*/\nfunction sc_isComplex(n) {\n  return sc_isNumber(n);\n}\n\n/*** META ((export #t)\n           (type bool))\n*/\nfunction sc_isReal(n) {\n  return sc_isNumber(n);\n}\n\n/*** META ((export #t)\n           (type bool))\n*/\nfunction sc_isRational(n) {\n  return sc_isReal(n);\n}\n\n/*** META ((export #t)\n           (type bool))\n*/\nfunction sc_isInteger(n) {\n  return parseInt(n) === n;\n}\n\n/*** META ((export #t)\n           (type bool)\n           (peephole (postfix \", false\")))\n*/\n// we don't have exact numbers...\nfunction sc_isExact(n) {\n  return false;\n}\n\n/*** META ((export #t)\n           (peephole (postfix \", true\"))\n\t   (type bool))\n*/\nfunction sc_isInexact(n) {\n  return true;\n}\n\n/*** META ((export = =fx =fl)\n           (type bool)\n           (peephole (infix 2 2 \"===\")))\n*/\nfunction sc_equal(x) {\n  for (var i = 1; i < arguments.length; i++)\n    if (x !== arguments[i]) return false;\n  return true;\n}\n\n/*** META ((export < <fx <fl)\n           (type bool)\n           (peephole (infix 2 2 \"<\")))\n*/\nfunction sc_less(x) {\n  for (var i = 1; i < arguments.length; i++) {\n    if (x >= arguments[i]) return false;\n    x = arguments[i];\n  }\n  return true;\n}\n\n/*** META ((export > >fx >fl)\n           (type bool)\n           (peephole (infix 2 2 \">\")))\n*/\nfunction sc_greater(x, y) {\n  for (var i = 1; i < arguments.length; i++) {\n    if (x <= arguments[i]) return false;\n    x = arguments[i];\n  }\n  return true;\n}\n\n/*** META ((export <= <=fx <=fl)\n           (type bool)\n           (peephole (infix 2 2 \"<=\")))\n*/\nfunction sc_lessEqual(x, y) {\n  for (var i = 1; i < arguments.length; i++) {\n    if (x > arguments[i]) return false;\n    x = arguments[i];\n  }\n  return true;\n}\n\n/*** META ((export >= >=fl >=fx)\n           (type bool)\n           (peephole (infix 2 2 \">=\")))\n*/\nfunction sc_greaterEqual(x, y) {\n  for (var i = 1; i < arguments.length; i++) {\n    if (x < arguments[i]) return false;\n    x = arguments[i];\n  }\n  return true;\n}\n\n/*** META ((export #t)\n           (type bool)\n           (peephole (postfix \"=== 0\")))\n*/\nfunction sc_isZero(x) {\n  return x === 0;\n}\n\n/*** META ((export #t)\n           (type bool)\n           (peephole (postfix \"> 0\")))\n*/\nfunction sc_isPositive(x) {\n  return x > 0;\n}\n\n/*** META ((export #t)\n           (type bool)\n           (peephole (postfix \"< 0\")))\n*/\nfunction sc_isNegative(x) {\n  return x < 0;\n}\n\n/*** META ((export #t)\n           (type bool)\n           (peephole (postfix \"%2===1\")))\n*/\nfunction sc_isOdd(x) {\n  return x % 2 === 1;\n}\n\n/*** META ((export #t)\n           (type bool)\n           (peephole (postfix \"%2===0\")))\n*/\nfunction sc_isEven(x) {\n  return x % 2 === 0;\n}\n\n/*** META ((export #t)) */\nvar sc_max = Math.max;\n/*** META ((export #t)) */\nvar sc_min = Math.min;\n\n/*** META ((export + +fx +fl)\n           (peephole (infix 0 #f \"+\" \"0\")))\n*/\nfunction sc_plus() {\n  var sum = 0;\n  for (var i = 0; i < arguments.length; i++) sum += arguments[i];\n  return sum;\n}\n\n/*** META ((export * *fx *fl)\n           (peephole (infix 0 #f \"*\" \"1\")))\n*/\nfunction sc_multi() {\n  var product = 1;\n  for (var i = 0; i < arguments.length; i++) product *= arguments[i];\n  return product;\n}\n\n/*** META ((export - -fx -fl)\n           (peephole (minus)))\n*/\nfunction sc_minus(x) {\n  if (arguments.length === 1) return -x;\n  else {\n    var res = x;\n    for (var i = 1; i < arguments.length; i++) res -= arguments[i];\n    return res;\n  }\n}\n\n/*** META ((export / /fl)\n           (peephole (div)))\n*/\nfunction sc_div(x) {\n  if (arguments.length === 1) return 1 / x;\n  else {\n    var res = x;\n    for (var i = 1; i < arguments.length; i++) res /= arguments[i];\n    return res;\n  }\n}\n\n/*** META ((export #t)) */\nvar sc_abs = Math.abs;\n\n/*** META ((export quotient /fx)\n           (peephole (hole 2 \"parseInt(\" x \"/\" y \")\")))\n*/\nfunction sc_quotient(x, y) {\n  return parseInt(x / y);\n}\n\n/*** META ((export #t)\n           (peephole (infix 2 2 \"%\")))\n*/\nfunction sc_remainder(x, y) {\n  return x % y;\n}\n\n/*** META ((export #t)\n           (peephole (modulo)))\n*/\nfunction sc_modulo(x, y) {\n  var remainder = x % y;\n  // if they don't have the same sign\n  if (remainder * y < 0) return remainder + y;\n  else return remainder;\n}\n\nfunction sc_euclid_gcd(a, b) {\n  var temp;\n  if (a === 0) return b;\n  if (b === 0) return a;\n  if (a < 0) {\n    a = -a;\n  }\n  if (b < 0) {\n    b = -b;\n  }\n  if (b > a) {\n    temp = a;\n    a = b;\n    b = temp;\n  }\n  while (true) {\n    a %= b;\n    if (a === 0) {\n      return b;\n    }\n    b %= a;\n    if (b === 0) {\n      return a;\n    }\n  }\n  return b;\n}\n\n/*** META ((export #t)) */\nfunction sc_gcd() {\n  var gcd = 0;\n  for (var i = 0; i < arguments.length; i++)\n    gcd = sc_euclid_gcd(gcd, arguments[i]);\n  return gcd;\n}\n\n/*** META ((export #t)) */\nfunction sc_lcm() {\n  var lcm = 1;\n  for (var i = 0; i < arguments.length; i++) {\n    var f = Math.round(arguments[i] / sc_euclid_gcd(arguments[i], lcm));\n    lcm *= Math.abs(f);\n  }\n  return lcm;\n}\n\n// LIMITATION: numerator and denominator don't make sense in floating point world.\n//var SC_MAX_DECIMALS = 1000000\n//\n// function sc_numerator(x) {\n//     var rounded = Math.round(x * SC_MAX_DECIMALS);\n//     return Math.round(rounded / sc_euclid_gcd(rounded, SC_MAX_DECIMALS));\n// }\n\n// function sc_denominator(x) {\n//     var rounded = Math.round(x * SC_MAX_DECIMALS);\n//     return Math.round(SC_MAX_DECIMALS / sc_euclid_gcd(rounded, SC_MAX_DECIMALS));\n// }\n\n/*** META ((export #t)) */\nvar sc_floor = Math.floor;\n/*** META ((export #t)) */\nvar sc_ceiling = Math.ceil;\n/*** META ((export #t)) */\nvar sc_truncate = parseInt;\n/*** META ((export #t)) */\nvar sc_round = Math.round;\n\n// LIMITATION: sc_rationalize doesn't make sense in a floating point world.\n\n/*** META ((export #t)) */\nvar sc_exp = Math.exp;\n/*** META ((export #t)) */\nvar sc_log = Math.log;\n/*** META ((export #t)) */\nvar sc_sin = Math.sin;\n/*** META ((export #t)) */\nvar sc_cos = Math.cos;\n/*** META ((export #t)) */\nvar sc_tan = Math.tan;\n/*** META ((export #t)) */\nvar sc_asin = Math.asin;\n/*** META ((export #t)) */\nvar sc_acos = Math.acos;\n/*** META ((export #t)) */\nvar sc_atan = Math.atan;\n\n/*** META ((export #t)) */\nvar sc_sqrt = Math.sqrt;\n/*** META ((export #t)) */\nvar sc_expt = Math.pow;\n\n// LIMITATION: we don't have complex numbers.\n// LIMITATION: the following functions are hence not implemented.\n// LIMITATION: make-rectangular, make-polar, real-part, imag-part, magnitude, angle\n// LIMITATION: 2 argument atan\n\n/*** META ((export #t)\n           (peephole (id)))\n*/\nfunction sc_exact2inexact(x) {\n  return x;\n}\n\n/*** META ((export #t)\n           (peephole (id)))\n*/\nfunction sc_inexact2exact(x) {\n  return x;\n}\n\nfunction sc_number2jsstring(x, radix) {\n  if (radix) return x.toString(radix);\n  else return x.toString();\n}\n\nfunction sc_jsstring2number(s, radix) {\n  if (s === \"\") return false;\n\n  if (radix) {\n    var t = parseInt(s, radix);\n    if (!t && t !== 0) return false;\n    // verify that each char is in range. (parseInt ignores leading\n    // white and trailing chars)\n    var allowedChars = \"01234567890abcdefghijklmnopqrstuvwxyz\".substring(\n      0,\n      radix + 1\n    );\n    if (new RegExp(\"^[\" + allowedChars + \"]*$\", \"i\").test(s)) return t;\n    else return false;\n  } else {\n    var t = +s; // does not ignore trailing chars.\n    if (!t && t !== 0) return false;\n    // simply verify that first char is not whitespace.\n    var c = s.charAt(0);\n    // if +c is 0, but the char is not \"0\", then we have a whitespace.\n    if (+c === 0 && c !== \"0\") return false;\n    return t;\n  }\n}\n\n/*** META ((export #t)\n           (type bool)\n           (peephole (not)))\n*/\nfunction sc_not(b) {\n  return b === false;\n}\n\n/*** META ((export #t)\n           (type bool))\n*/\nfunction sc_isBoolean(b) {\n  return b === true || b === false;\n}\n\nfunction sc_Pair(car, cdr) {\n  this.car = car;\n  this.cdr = cdr;\n}\n\nsc_Pair.prototype.toString = function () {\n  return sc_toDisplayString(this);\n};\nsc_Pair.prototype.sc_toWriteOrDisplayString = function (writeOrDisplay) {\n  var current = this;\n\n  var res = \"(\";\n\n  while (true) {\n    res += writeOrDisplay(current.car);\n    if (sc_isPair(current.cdr)) {\n      res += \" \";\n      current = current.cdr;\n    } else if (current.cdr !== null) {\n      res += \" . \" + writeOrDisplay(current.cdr);\n      break;\n    } // current.cdr == null\n    else break;\n  }\n\n  res += \")\";\n\n  return res;\n};\nsc_Pair.prototype.sc_toDisplayString = function () {\n  return this.sc_toWriteOrDisplayString(sc_toDisplayString);\n};\nsc_Pair.prototype.sc_toWriteString = function () {\n  return this.sc_toWriteOrDisplayString(sc_toWriteString);\n};\n// sc_Pair.prototype.sc_toWriteCircleString in IO.js\n\n/*** META ((export #t)\n           (type bool)\n           (peephole (postfix \" instanceof sc_Pair\")))\n*/\nfunction sc_isPair(p) {\n  return p instanceof sc_Pair;\n}\n\nfunction sc_isPairEqual(p1, p2, comp) {\n  return comp(p1.car, p2.car) && comp(p1.cdr, p2.cdr);\n}\n\n/*** META ((export #t)\n           (peephole (hole 2 \"new sc_Pair(\" car \", \" cdr \")\")))\n*/\nfunction sc_cons(car, cdr) {\n  return new sc_Pair(car, cdr);\n}\n\n/*** META ((export cons*)) */\nfunction sc_consStar() {\n  var res = arguments[arguments.length - 1];\n  for (var i = arguments.length - 2; i >= 0; i--)\n    res = new sc_Pair(arguments[i], res);\n  return res;\n}\n\n/*** META ((export #t)\n           (peephole (postfix \".car\")))\n*/\nfunction sc_car(p) {\n  return p.car;\n}\n\n/*** META ((export #t)\n           (peephole (postfix \".cdr\")))\n*/\nfunction sc_cdr(p) {\n  return p.cdr;\n}\n\n/*** META ((export #t)\n           (peephole (hole 2 p \".car = \" val)))\n*/\nfunction sc_setCarBang(p, val) {\n  p.car = val;\n}\n\n/*** META ((export #t)\n           (peephole (hole 2 p \".cdr = \" val)))\n*/\nfunction sc_setCdrBang(p, val) {\n  p.cdr = val;\n}\n\n/*** META ((export #t)\n           (peephole (postfix \".car.car\")))\n*/\nfunction sc_caar(p) {\n  return p.car.car;\n}\n/*** META ((export #t)\n           (peephole (postfix \".cdr.car\")))\n*/\nfunction sc_cadr(p) {\n  return p.cdr.car;\n}\n/*** META ((export #t)\n           (peephole (postfix \".car.cdr\")))\n*/\nfunction sc_cdar(p) {\n  return p.car.cdr;\n}\n/*** META ((export #t)\n           (peephole (postfix \".cdr.cdr\")))\n*/\nfunction sc_cddr(p) {\n  return p.cdr.cdr;\n}\n/*** META ((export #t)\n           (peephole (postfix \".car.car.car\")))\n*/\nfunction sc_caaar(p) {\n  return p.car.car.car;\n}\n/*** META ((export #t)\n           (peephole (postfix \".car.cdr.car\")))\n*/\nfunction sc_cadar(p) {\n  return p.car.cdr.car;\n}\n/*** META ((export #t)\n           (peephole (postfix \".cdr.car.car\")))\n*/\nfunction sc_caadr(p) {\n  return p.cdr.car.car;\n}\n/*** META ((export #t)\n           (peephole (postfix \".cdr.cdr.car\")))\n*/\nfunction sc_caddr(p) {\n  return p.cdr.cdr.car;\n}\n/*** META ((export #t)\n           (peephole (postfix \".car.car.cdr\")))\n*/\nfunction sc_cdaar(p) {\n  return p.car.car.cdr;\n}\n/*** META ((export #t)\n           (peephole (postfix \".cdr.car.cdr\")))\n*/\nfunction sc_cdadr(p) {\n  return p.cdr.car.cdr;\n}\n/*** META ((export #t)\n           (peephole (postfix \".car.cdr.cdr\")))\n*/\nfunction sc_cddar(p) {\n  return p.car.cdr.cdr;\n}\n/*** META ((export #t)\n           (peephole (postfix \".cdr.cdr.cdr\")))\n*/\nfunction sc_cdddr(p) {\n  return p.cdr.cdr.cdr;\n}\n/*** META ((export #t)\n           (peephole (postfix \".car.car.car.car\")))\n*/\nfunction sc_caaaar(p) {\n  return p.car.car.car.car;\n}\n/*** META ((export #t)\n           (peephole (postfix \".car.cdr.car.car\")))\n*/\nfunction sc_caadar(p) {\n  return p.car.cdr.car.car;\n}\n/*** META ((export #t)\n           (peephole (postfix \".cdr.car.car.car\")))\n*/\nfunction sc_caaadr(p) {\n  return p.cdr.car.car.car;\n}\n/*** META ((export #t)\n           (peephole (postfix \".cdr.cdr.car.car\")))\n*/\nfunction sc_caaddr(p) {\n  return p.cdr.cdr.car.car;\n}\n/*** META ((export #t)\n           (peephole (postfix \".car.car.car.cdr\")))\n*/\nfunction sc_cdaaar(p) {\n  return p.car.car.car.cdr;\n}\n/*** META ((export #t)\n           (peephole (postfix \".car.cdr.car.cdr\")))\n*/\nfunction sc_cdadar(p) {\n  return p.car.cdr.car.cdr;\n}\n/*** META ((export #t)\n           (peephole (postfix \".cdr.car.car.cdr\")))\n*/\nfunction sc_cdaadr(p) {\n  return p.cdr.car.car.cdr;\n}\n/*** META ((export #t)\n           (peephole (postfix \".cdr.cdr.car.cdr\")))\n*/\nfunction sc_cdaddr(p) {\n  return p.cdr.cdr.car.cdr;\n}\n/*** META ((export #t)\n           (peephole (postfix \".car.car.cdr.car\")))\n*/\nfunction sc_cadaar(p) {\n  return p.car.car.cdr.car;\n}\n/*** META ((export #t)\n           (peephole (postfix \".car.cdr.cdr.car\")))\n*/\nfunction sc_caddar(p) {\n  return p.car.cdr.cdr.car;\n}\n/*** META ((export #t)\n           (peephole (postfix \".cdr.car.cdr.car\")))\n*/\nfunction sc_cadadr(p) {\n  return p.cdr.car.cdr.car;\n}\n/*** META ((export #t)\n           (peephole (postfix \".cdr.cdr.cdr.car\")))\n*/\nfunction sc_cadddr(p) {\n  return p.cdr.cdr.cdr.car;\n}\n/*** META ((export #t)\n           (peephole (postfix \".car.car.cdr.cdr\")))\n*/\nfunction sc_cddaar(p) {\n  return p.car.car.cdr.cdr;\n}\n/*** META ((export #t)\n           (peephole (postfix \".car.cdr.cdr.cdr\")))\n*/\nfunction sc_cdddar(p) {\n  return p.car.cdr.cdr.cdr;\n}\n/*** META ((export #t)\n           (peephole (postfix \".cdr.car.cdr.cdr\")))\n*/\nfunction sc_cddadr(p) {\n  return p.cdr.car.cdr.cdr;\n}\n/*** META ((export #t)\n           (peephole (postfix \".cdr.cdr.cdr.cdr\")))\n*/\nfunction sc_cddddr(p) {\n  return p.cdr.cdr.cdr.cdr;\n}\n\n/*** META ((export #t)) */\nfunction sc_lastPair(l) {\n  if (!sc_isPair(l)) sc_error(\"sc_lastPair: pair expected\");\n  var res = l;\n  var cdr = l.cdr;\n  while (sc_isPair(cdr)) {\n    res = cdr;\n    cdr = res.cdr;\n  }\n  return res;\n}\n\n/*** META ((export #t)\n           (type bool)\n           (peephole (postfix \" === null\")))\n*/\nfunction sc_isNull(o) {\n  return o === null;\n}\n\n/*** META ((export #t)\n           (type bool))\n*/\nfunction sc_isList(o) {\n  var rabbit;\n  var turtle;\n\n  var rabbit = o;\n  var turtle = o;\n  while (true) {\n    if (rabbit === null || (rabbit instanceof sc_Pair && rabbit.cdr === null))\n      return true; // end of list\n    else if (rabbit instanceof sc_Pair && rabbit.cdr instanceof sc_Pair) {\n      rabbit = rabbit.cdr.cdr;\n      turtle = turtle.cdr;\n      if (rabbit === turtle) return false; // cycle\n    } else return false; // not pair\n  }\n}\n\n/*** META ((export #t)) */\nfunction sc_list() {\n  var res = null;\n  var a = arguments;\n  for (var i = a.length - 1; i >= 0; i--) res = new sc_Pair(a[i], res);\n  return res;\n}\n\n/*** META ((export #t)) */\nfunction sc_iota(num, init) {\n  var res = null;\n  if (!init) init = 0;\n  for (var i = num - 1; i >= 0; i--) res = new sc_Pair(i + init, res);\n  return res;\n}\n\n/*** META ((export #t)) */\nfunction sc_makeList(nbEls, fill) {\n  var res = null;\n  for (var i = 0; i < nbEls; i++) res = new sc_Pair(fill, res);\n  return res;\n}\n\n/*** META ((export #t)) */\nfunction sc_length(l) {\n  var res = 0;\n  while (l !== null) {\n    res++;\n    l = l.cdr;\n  }\n  return res;\n}\n\n/*** META ((export #t)) */\nfunction sc_remq(o, l) {\n  var dummy = { cdr: null };\n  var tail = dummy;\n  while (l !== null) {\n    if (l.car !== o) {\n      tail.cdr = sc_cons(l.car, null);\n      tail = tail.cdr;\n    }\n    l = l.cdr;\n  }\n  return dummy.cdr;\n}\n\n/*** META ((export #t)) */\nfunction sc_remqBang(o, l) {\n  var dummy = { cdr: null };\n  var tail = dummy;\n  var needsAssig = true;\n  while (l !== null) {\n    if (l.car === o) {\n      needsAssig = true;\n    } else {\n      if (needsAssig) {\n        tail.cdr = l;\n        needsAssig = false;\n      }\n      tail = l;\n    }\n    l = l.cdr;\n  }\n  tail.cdr = null;\n  return dummy.cdr;\n}\n\n/*** META ((export #t)) */\nfunction sc_delete(o, l) {\n  var dummy = { cdr: null };\n  var tail = dummy;\n  while (l !== null) {\n    if (!sc_isEqual(l.car, o)) {\n      tail.cdr = sc_cons(l.car, null);\n      tail = tail.cdr;\n    }\n    l = l.cdr;\n  }\n  return dummy.cdr;\n}\n\n/*** META ((export #t)) */\nfunction sc_deleteBang(o, l) {\n  var dummy = { cdr: null };\n  var tail = dummy;\n  var needsAssig = true;\n  while (l !== null) {\n    if (sc_isEqual(l.car, o)) {\n      needsAssig = true;\n    } else {\n      if (needsAssig) {\n        tail.cdr = l;\n        needsAssig = false;\n      }\n      tail = l;\n    }\n    l = l.cdr;\n  }\n  tail.cdr = null;\n  return dummy.cdr;\n}\n\nfunction sc_reverseAppendBang(l1, l2) {\n  var res = l2;\n  while (l1 !== null) {\n    var tmp = res;\n    res = l1;\n    l1 = l1.cdr;\n    res.cdr = tmp;\n  }\n  return res;\n}\n\nfunction sc_dualAppend(l1, l2) {\n  if (l1 === null) return l2;\n  if (l2 === null) return l1;\n  var rev = sc_reverse(l1);\n  return sc_reverseAppendBang(rev, l2);\n}\n\n/*** META ((export #t)) */\nfunction sc_append() {\n  if (arguments.length === 0) return null;\n  var res = arguments[arguments.length - 1];\n  for (var i = arguments.length - 2; i >= 0; i--)\n    res = sc_dualAppend(arguments[i], res);\n  return res;\n}\n\nfunction sc_dualAppendBang(l1, l2) {\n  if (l1 === null) return l2;\n  if (l2 === null) return l1;\n  var tmp = l1;\n  while (tmp.cdr !== null) tmp = tmp.cdr;\n  tmp.cdr = l2;\n  return l1;\n}\n\n/*** META ((export #t)) */\nfunction sc_appendBang() {\n  var res = null;\n  for (var i = 0; i < arguments.length; i++)\n    res = sc_dualAppendBang(res, arguments[i]);\n  return res;\n}\n\n/*** META ((export #t)) */\nfunction sc_reverse(l1) {\n  var res = null;\n  while (l1 !== null) {\n    res = sc_cons(l1.car, res);\n    l1 = l1.cdr;\n  }\n  return res;\n}\n\n/*** META ((export #t)) */\nfunction sc_reverseBang(l) {\n  return sc_reverseAppendBang(l, null);\n}\n\n/*** META ((export #t)) */\nfunction sc_listTail(l, k) {\n  var res = l;\n  for (var i = 0; i < k; i++) {\n    res = res.cdr;\n  }\n  return res;\n}\n\n/*** META ((export #t)) */\nfunction sc_listRef(l, k) {\n  return sc_listTail(l, k).car;\n}\n\n/* // unoptimized generic versions\nfunction sc_memX(o, l, comp) {\n    while (l != null) {\n\tif (comp(l.car, o))\n\t    return l;\n\tl = l.cdr;\n    }\n    return false;\n}\nfunction sc_memq(o, l) { return sc_memX(o, l, sc_isEq); }\nfunction sc_memv(o, l) { return sc_memX(o, l, sc_isEqv); }\nfunction sc_member(o, l) { return sc_memX(o, l, sc_isEqual); }\n*/\n\n/* optimized versions */\n/*** META ((export #t)) */\nfunction sc_memq(o, l) {\n  while (l !== null) {\n    if (l.car === o) return l;\n    l = l.cdr;\n  }\n  return false;\n}\n/*** META ((export #t)) */\nfunction sc_memv(o, l) {\n  while (l !== null) {\n    if (l.car === o) return l;\n    l = l.cdr;\n  }\n  return false;\n}\n/*** META ((export #t)) */\nfunction sc_member(o, l) {\n  while (l !== null) {\n    if (sc_isEqual(l.car, o)) return l;\n    l = l.cdr;\n  }\n  return false;\n}\n\n/* // generic unoptimized versions\nfunction sc_assX(o, al, comp) {\n    while (al != null) {\n\tif (comp(al.car.car, o))\n\t    return al.car;\n\tal = al.cdr;\n    }\n    return false;\n}\nfunction sc_assq(o, al) { return sc_assX(o, al, sc_isEq); }\nfunction sc_assv(o, al) { return sc_assX(o, al, sc_isEqv); }\nfunction sc_assoc(o, al) { return sc_assX(o, al, sc_isEqual); }\n*/\n// optimized versions\n/*** META ((export #t)) */\nfunction sc_assq(o, al) {\n  while (al !== null) {\n    if (al.car.car === o) return al.car;\n    al = al.cdr;\n  }\n  return false;\n}\n/*** META ((export #t)) */\nfunction sc_assv(o, al) {\n  while (al !== null) {\n    if (al.car.car === o) return al.car;\n    al = al.cdr;\n  }\n  return false;\n}\n/*** META ((export #t)) */\nfunction sc_assoc(o, al) {\n  while (al !== null) {\n    if (sc_isEqual(al.car.car, o)) return al.car;\n    al = al.cdr;\n  }\n  return false;\n}\n\n/* can be used for mutable strings and characters */\nfunction sc_isCharStringEqual(cs1, cs2) {\n  return cs1.val === cs2.val;\n}\nfunction sc_isCharStringLess(cs1, cs2) {\n  return cs1.val < cs2.val;\n}\nfunction sc_isCharStringGreater(cs1, cs2) {\n  return cs1.val > cs2.val;\n}\nfunction sc_isCharStringLessEqual(cs1, cs2) {\n  return cs1.val <= cs2.val;\n}\nfunction sc_isCharStringGreaterEqual(cs1, cs2) {\n  return cs1.val >= cs2.val;\n}\nfunction sc_isCharStringCIEqual(cs1, cs2) {\n  return cs1.val.toLowerCase() === cs2.val.toLowerCase();\n}\nfunction sc_isCharStringCILess(cs1, cs2) {\n  return cs1.val.toLowerCase() < cs2.val.toLowerCase();\n}\nfunction sc_isCharStringCIGreater(cs1, cs2) {\n  return cs1.val.toLowerCase() > cs2.val.toLowerCase();\n}\nfunction sc_isCharStringCILessEqual(cs1, cs2) {\n  return cs1.val.toLowerCase() <= cs2.val.toLowerCase();\n}\nfunction sc_isCharStringCIGreaterEqual(cs1, cs2) {\n  return cs1.val.toLowerCase() >= cs2.val.toLowerCase();\n}\n\nfunction sc_Char(c) {\n  var cached = sc_Char.lazy[c];\n  if (cached) return cached;\n  this.val = c;\n  sc_Char.lazy[c] = this;\n  // add return, so FF does not complain.\n  return undefined;\n}\nsc_Char.lazy = new Object();\n// thanks to Eric\nsc_Char.char2readable = {\n  \"\\000\": \"#\\\\null\",\n  \"\\007\": \"#\\\\bell\",\n  \"\\010\": \"#\\\\backspace\",\n  \"\\011\": \"#\\\\tab\",\n  \"\\012\": \"#\\\\newline\",\n  \"\\014\": \"#\\\\page\",\n  \"\\015\": \"#\\\\return\",\n  \"\\033\": \"#\\\\escape\",\n  \"\\040\": \"#\\\\space\",\n  \"\\177\": \"#\\\\delete\",\n\n  /* poeticless names */\n  \"\\001\": \"#\\\\soh\",\n  \"\\002\": \"#\\\\stx\",\n  \"\\003\": \"#\\\\etx\",\n  \"\\004\": \"#\\\\eot\",\n  \"\\005\": \"#\\\\enq\",\n  \"\\006\": \"#\\\\ack\",\n\n  \"\\013\": \"#\\\\vt\",\n  \"\\016\": \"#\\\\so\",\n  \"\\017\": \"#\\\\si\",\n\n  \"\\020\": \"#\\\\dle\",\n  \"\\021\": \"#\\\\dc1\",\n  \"\\022\": \"#\\\\dc2\",\n  \"\\023\": \"#\\\\dc3\",\n  \"\\024\": \"#\\\\dc4\",\n  \"\\025\": \"#\\\\nak\",\n  \"\\026\": \"#\\\\syn\",\n  \"\\027\": \"#\\\\etb\",\n\n  \"\\030\": \"#\\\\can\",\n  \"\\031\": \"#\\\\em\",\n  \"\\032\": \"#\\\\sub\",\n  \"\\033\": \"#\\\\esc\",\n  \"\\034\": \"#\\\\fs\",\n  \"\\035\": \"#\\\\gs\",\n  \"\\036\": \"#\\\\rs\",\n  \"\\037\": \"#\\\\us\",\n};\n\nsc_Char.readable2char = {\n  null: \"\\000\",\n  bell: \"\\007\",\n  backspace: \"\\010\",\n  tab: \"\\011\",\n  newline: \"\\012\",\n  page: \"\\014\",\n  return: \"\\015\",\n  escape: \"\\033\",\n  space: \"\\040\",\n  delete: \"\\000\",\n  soh: \"\\001\",\n  stx: \"\\002\",\n  etx: \"\\003\",\n  eot: \"\\004\",\n  enq: \"\\005\",\n  ack: \"\\006\",\n  bel: \"\\007\",\n  bs: \"\\010\",\n  ht: \"\\011\",\n  nl: \"\\012\",\n  vt: \"\\013\",\n  np: \"\\014\",\n  cr: \"\\015\",\n  so: \"\\016\",\n  si: \"\\017\",\n  dle: \"\\020\",\n  dc1: \"\\021\",\n  dc2: \"\\022\",\n  dc3: \"\\023\",\n  dc4: \"\\024\",\n  nak: \"\\025\",\n  syn: \"\\026\",\n  etb: \"\\027\",\n  can: \"\\030\",\n  em: \"\\031\",\n  sub: \"\\032\",\n  esc: \"\\033\",\n  fs: \"\\034\",\n  gs: \"\\035\",\n  rs: \"\\036\",\n  us: \"\\037\",\n  sp: \"\\040\",\n  del: \"\\177\",\n};\n\nsc_Char.prototype.toString = function () {\n  return this.val;\n};\n// sc_toDisplayString == toString\nsc_Char.prototype.sc_toWriteString = function () {\n  var entry = sc_Char.char2readable[this.val];\n  if (entry) return entry;\n  else return \"#\\\\\" + this.val;\n};\n\n/*** META ((export #t)\n           (type bool)\n           (peephole (postfix \"instanceof sc_Char\")))\n*/\nfunction sc_isChar(c) {\n  return c instanceof sc_Char;\n}\n\n/*** META ((export char=?)\n           (type bool)\n           (peephole (hole 2 c1 \".val === \" c2 \".val\")))\n*/\nvar sc_isCharEqual = sc_isCharStringEqual;\n/*** META ((export char<?)\n           (type bool)\n           (peephole (hole 2 c1 \".val < \" c2 \".val\")))\n*/\nvar sc_isCharLess = sc_isCharStringLess;\n/*** META ((export char>?)\n           (type bool)\n           (peephole (hole 2 c1 \".val > \" c2 \".val\")))\n*/\nvar sc_isCharGreater = sc_isCharStringGreater;\n/*** META ((export char<=?)\n           (type bool)\n           (peephole (hole 2 c1 \".val <= \" c2 \".val\")))\n*/\nvar sc_isCharLessEqual = sc_isCharStringLessEqual;\n/*** META ((export char>=?)\n           (type bool)\n           (peephole (hole 2 c1 \".val >= \" c2 \".val\")))\n*/\nvar sc_isCharGreaterEqual = sc_isCharStringGreaterEqual;\n/*** META ((export char-ci=?)\n           (type bool)\n           (peephole (hole 2 c1 \".val.toLowerCase() === \" c2 \".val.toLowerCase()\")))\n*/\nvar sc_isCharCIEqual = sc_isCharStringCIEqual;\n/*** META ((export char-ci<?)\n           (type bool)\n           (peephole (hole 2 c1 \".val.toLowerCase() < \" c2 \".val.toLowerCase()\")))\n*/\nvar sc_isCharCILess = sc_isCharStringCILess;\n/*** META ((export char-ci>?)\n           (type bool)\n           (peephole (hole 2 c1 \".val.toLowerCase() > \" c2 \".val.toLowerCase()\")))\n*/\nvar sc_isCharCIGreater = sc_isCharStringCIGreater;\n/*** META ((export char-ci<=?)\n           (type bool)\n           (peephole (hole 2 c1 \".val.toLowerCase() <= \" c2 \".val.toLowerCase()\")))\n*/\nvar sc_isCharCILessEqual = sc_isCharStringCILessEqual;\n/*** META ((export char-ci>=?)\n           (type bool)\n           (peephole (hole 2 c1 \".val.toLowerCase() >= \" c2 \".val.toLowerCase()\")))\n*/\nvar sc_isCharCIGreaterEqual = sc_isCharStringCIGreaterEqual;\n\nvar SC_NUMBER_CLASS = \"0123456789\";\nvar SC_WHITESPACE_CLASS = \" \\r\\n\\t\\f\";\nvar SC_LOWER_CLASS = \"abcdefghijklmnopqrstuvwxyz\";\nvar SC_UPPER_CLASS = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\n\nfunction sc_isCharOfClass(c, cl) {\n  return cl.indexOf(c) != -1;\n}\n/*** META ((export #t)\n           (type bool))\n*/\nfunction sc_isCharAlphabetic(c) {\n  return (\n    sc_isCharOfClass(c.val, SC_LOWER_CLASS) ||\n    sc_isCharOfClass(c.val, SC_UPPER_CLASS)\n  );\n}\n/*** META ((export #t)\n           (type bool)\n           (peephole (hole 1 \"SC_NUMBER_CLASS.indexOf(\" c \".val) != -1\")))\n*/\nfunction sc_isCharNumeric(c) {\n  return sc_isCharOfClass(c.val, SC_NUMBER_CLASS);\n}\n/*** META ((export #t)\n           (type bool))\n*/\nfunction sc_isCharWhitespace(c) {\n  var tmp = c.val;\n  return (\n    tmp === \" \" || tmp === \"\\r\" || tmp === \"\\n\" || tmp === \"\\t\" || tmp === \"\\f\"\n  );\n}\n/*** META ((export #t)\n           (type bool)\n           (peephole (hole 1 \"SC_UPPER_CLASS.indexOf(\" c \".val) != -1\")))\n*/\nfunction sc_isCharUpperCase(c) {\n  return sc_isCharOfClass(c.val, SC_UPPER_CLASS);\n}\n/*** META ((export #t)\n           (type bool)\n           (peephole (hole 1 \"SC_LOWER_CLASS.indexOf(\" c \".val) != -1\")))\n*/\nfunction sc_isCharLowerCase(c) {\n  return sc_isCharOfClass(c.val, SC_LOWER_CLASS);\n}\n\n/*** META ((export #t)\n           (peephole (postfix \".val.charCodeAt(0)\")))\n*/\nfunction sc_char2integer(c) {\n  return c.val.charCodeAt(0);\n}\n/*** META ((export #t)\n           (peephole (hole 1 \"new sc_Char(String.fromCharCode(\" n \"))\")))\n*/\nfunction sc_integer2char(n) {\n  return new sc_Char(String.fromCharCode(n));\n}\n\n/*** META ((export #t)\n           (peephole (hole 1 \"new sc_Char(\" c \".val.toUpperCase())\")))\n*/\nfunction sc_charUpcase(c) {\n  return new sc_Char(c.val.toUpperCase());\n}\n/*** META ((export #t)\n           (peephole (hole 1 \"new sc_Char(\" c \".val.toLowerCase())\")))\n*/\nfunction sc_charDowncase(c) {\n  return new sc_Char(c.val.toLowerCase());\n}\n\nfunction sc_makeJSStringOfLength(k, c) {\n  var fill;\n  if (c === undefined) fill = \" \";\n  else fill = c;\n  var res = \"\";\n  var len = 1;\n  // every round doubles the size of fill.\n  while (k >= len) {\n    if (k & len) res = res.concat(fill);\n    fill = fill.concat(fill);\n    len *= 2;\n  }\n  return res;\n}\n\nfunction sc_makejsString(k, c) {\n  var fill;\n  if (c) fill = c.val;\n  else fill = \" \";\n  return sc_makeJSStringOfLength(k, fill);\n}\n\nfunction sc_jsstring2list(s) {\n  var res = null;\n  for (var i = s.length - 1; i >= 0; i--)\n    res = sc_cons(new sc_Char(s.charAt(i)), res);\n  return res;\n}\n\nfunction sc_list2jsstring(l) {\n  var a = new Array();\n  while (l !== null) {\n    a.push(l.car.val);\n    l = l.cdr;\n  }\n  return \"\".concat.apply(\"\", a);\n}\n\nvar sc_Vector = Array;\n\nsc_Vector.prototype.sc_toWriteOrDisplayString = function (writeOrDisplay) {\n  if (this.length === 0) return \"#()\";\n\n  var res = \"#(\" + writeOrDisplay(this[0]);\n  for (var i = 1; i < this.length; i++) res += \" \" + writeOrDisplay(this[i]);\n  res += \")\";\n  return res;\n};\nsc_Vector.prototype.sc_toDisplayString = function () {\n  return this.sc_toWriteOrDisplayString(sc_toDisplayString);\n};\nsc_Vector.prototype.sc_toWriteString = function () {\n  return this.sc_toWriteOrDisplayString(sc_toWriteString);\n};\n\n/*** META ((export vector? array?)\n           (type bool)\n           (peephole (postfix \" instanceof sc_Vector\")))\n*/\nfunction sc_isVector(v) {\n  return v instanceof sc_Vector;\n}\n\n// only applies to vectors\nfunction sc_isVectorEqual(v1, v2, comp) {\n  if (v1.length !== v2.length) return false;\n  for (var i = 0; i < v1.length; i++) if (!comp(v1[i], v2[i])) return false;\n  return true;\n}\n\n/*** META ((export make-vector make-array)) */\nfunction sc_makeVector(size, fill) {\n  var a = new sc_Vector(size);\n  if (fill !== undefined) sc_vectorFillBang(a, fill);\n  return a;\n}\n\n/*** META ((export vector array)\n           (peephole (vector)))\n*/\nfunction sc_vector() {\n  var a = new sc_Vector();\n  for (var i = 0; i < arguments.length; i++) a.push(arguments[i]);\n  return a;\n}\n\n/*** META ((export vector-length array-length)\n           (peephole (postfix \".length\")))\n*/\nfunction sc_vectorLength(v) {\n  return v.length;\n}\n\n/*** META ((export vector-ref array-ref)\n           (peephole (hole 2 v \"[\" pos \"]\")))\n*/\nfunction sc_vectorRef(v, pos) {\n  return v[pos];\n}\n\n/*** META ((export vector-set! array-set!)\n           (peephole (hole 3 v \"[\" pos \"] = \" val)))\n*/\nfunction sc_vectorSetBang(v, pos, val) {\n  v[pos] = val;\n}\n\n/*** META ((export vector->list array->list)) */\nfunction sc_vector2list(a) {\n  var res = null;\n  for (var i = a.length - 1; i >= 0; i--) res = sc_cons(a[i], res);\n  return res;\n}\n\n/*** META ((export list->vector list->array)) */\nfunction sc_list2vector(l) {\n  var a = new sc_Vector();\n  while (l !== null) {\n    a.push(l.car);\n    l = l.cdr;\n  }\n  return a;\n}\n\n/*** META ((export vector-fill! array-fill!)) */\nfunction sc_vectorFillBang(a, fill) {\n  for (var i = 0; i < a.length; i++) a[i] = fill;\n}\n\n/*** META ((export #t)) */\nfunction sc_copyVector(a, len) {\n  if (len <= a.length) return a.slice(0, len);\n  else {\n    var tmp = a.concat();\n    tmp.length = len;\n    return tmp;\n  }\n}\n\n/*** META ((export #t)\n           (peephole (hole 3 a \".slice(\" start \",\" end \")\")))\n*/\nfunction sc_vectorCopy(a, start, end) {\n  return a.slice(start, end);\n}\n\n/*** META ((export #t)) */\nfunction sc_vectorCopyBang(target, tstart, source, sstart, send) {\n  if (!sstart) sstart = 0;\n  if (!send) send = source.length;\n\n  // if target == source we don't want to overwrite not yet copied elements.\n  if (tstart <= sstart) {\n    for (var i = tstart, j = sstart; j < send; i++, j++) {\n      target[i] = source[j];\n    }\n  } else {\n    var diff = send - sstart;\n    for (var i = tstart + diff - 1, j = send - 1; j >= sstart; i--, j--) {\n      target[i] = source[j];\n    }\n  }\n  return target;\n}\n\n/*** META ((export #t)\n           (type bool)\n           (peephole (hole 1 \"typeof \" o \" === 'function'\")))\n*/\nfunction sc_isProcedure(o) {\n  return typeof o === \"function\";\n}\n\n/*** META ((export #t)) */\nfunction sc_apply(proc) {\n  var args = new Array();\n  // first part of arguments are not in list-form.\n  for (var i = 1; i < arguments.length - 1; i++) args.push(arguments[i]);\n  var l = arguments[arguments.length - 1];\n  while (l !== null) {\n    args.push(l.car);\n    l = l.cdr;\n  }\n  return proc.apply(null, args);\n}\n\n/*** META ((export #t)) */\nfunction sc_map(proc, l1) {\n  if (l1 === undefined) return null;\n  // else\n  var nbApplyArgs = arguments.length - 1;\n  var applyArgs = new Array(nbApplyArgs);\n  var revres = null;\n  while (l1 !== null) {\n    for (var i = 0; i < nbApplyArgs; i++) {\n      applyArgs[i] = arguments[i + 1].car;\n      arguments[i + 1] = arguments[i + 1].cdr;\n    }\n    revres = sc_cons(proc.apply(null, applyArgs), revres);\n  }\n  return sc_reverseAppendBang(revres, null);\n}\n\n/*** META ((export #t)) */\nfunction sc_mapBang(proc, l1) {\n  if (l1 === undefined) return null;\n  // else\n  var l1_orig = l1;\n  var nbApplyArgs = arguments.length - 1;\n  var applyArgs = new Array(nbApplyArgs);\n  while (l1 !== null) {\n    var tmp = l1;\n    for (var i = 0; i < nbApplyArgs; i++) {\n      applyArgs[i] = arguments[i + 1].car;\n      arguments[i + 1] = arguments[i + 1].cdr;\n    }\n    tmp.car = proc.apply(null, applyArgs);\n  }\n  return l1_orig;\n}\n\n/*** META ((export #t)) */\nfunction sc_forEach(proc, l1) {\n  if (l1 === undefined) return undefined;\n  // else\n  var nbApplyArgs = arguments.length - 1;\n  var applyArgs = new Array(nbApplyArgs);\n  while (l1 !== null) {\n    for (var i = 0; i < nbApplyArgs; i++) {\n      applyArgs[i] = arguments[i + 1].car;\n      arguments[i + 1] = arguments[i + 1].cdr;\n    }\n    proc.apply(null, applyArgs);\n  }\n  // add return so FF does not complain.\n  return undefined;\n}\n\n/*** META ((export #t)) */\nfunction sc_filter(proc, l1) {\n  var dummy = { cdr: null };\n  var tail = dummy;\n  while (l1 !== null) {\n    if (proc(l1.car) !== false) {\n      tail.cdr = sc_cons(l1.car, null);\n      tail = tail.cdr;\n    }\n    l1 = l1.cdr;\n  }\n  return dummy.cdr;\n}\n\n/*** META ((export #t)) */\nfunction sc_filterBang(proc, l1) {\n  var head = sc_cons(\"dummy\", l1);\n  var it = head;\n  var next = l1;\n  while (next !== null) {\n    if (proc(next.car) !== false) {\n      it.cdr = next;\n      it = next;\n    }\n    next = next.cdr;\n  }\n  it.cdr = null;\n  return head.cdr;\n}\n\nfunction sc_filterMap1(proc, l1) {\n  var revres = null;\n  while (l1 !== null) {\n    var tmp = proc(l1.car);\n    if (tmp !== false) revres = sc_cons(tmp, revres);\n    l1 = l1.cdr;\n  }\n  return sc_reverseAppendBang(revres, null);\n}\nfunction sc_filterMap2(proc, l1, l2) {\n  var revres = null;\n  while (l1 !== null) {\n    var tmp = proc(l1.car, l2.car);\n    if (tmp !== false) revres = sc_cons(tmp, revres);\n    l1 = l1.cdr;\n    l2 = l2.cdr;\n  }\n  return sc_reverseAppendBang(revres, null);\n}\n\n/*** META ((export #t)) */\nfunction sc_filterMap(proc, l1, l2, l3) {\n  if (l2 === undefined) return sc_filterMap1(proc, l1);\n  else if (l3 === undefined) return sc_filterMap2(proc, l1, l2);\n  // else\n  var nbApplyArgs = arguments.length - 1;\n  var applyArgs = new Array(nbApplyArgs);\n  var revres = null;\n  while (l1 !== null) {\n    for (var i = 0; i < nbApplyArgs; i++) {\n      applyArgs[i] = arguments[i + 1].car;\n      arguments[i + 1] = arguments[i + 1].cdr;\n    }\n    var tmp = proc.apply(null, applyArgs);\n    if (tmp !== false) revres = sc_cons(tmp, revres);\n  }\n  return sc_reverseAppendBang(revres, null);\n}\n\n/*** META ((export #t)) */\nfunction sc_any(proc, l) {\n  var revres = null;\n  while (l !== null) {\n    var tmp = proc(l.car);\n    if (tmp !== false) return tmp;\n    l = l.cdr;\n  }\n  return false;\n}\n\n/*** META ((export any?)\n           (peephole (hole 2 \"sc_any(\" proc \",\" l \") !== false\")))\n*/\nfunction sc_anyPred(proc, l) {\n  return sc_any(proc, l) !== false;\n}\n\n/*** META ((export #t)) */\nfunction sc_every(proc, l) {\n  var revres = null;\n  var tmp = true;\n  while (l !== null) {\n    tmp = proc(l.car);\n    if (tmp === false) return false;\n    l = l.cdr;\n  }\n  return tmp;\n}\n\n/*** META ((export every?)\n           (peephole (hole 2 \"sc_every(\" proc \",\" l \") !== false\")))\n*/\nfunction sc_everyPred(proc, l) {\n  var tmp = sc_every(proc, l);\n  if (tmp !== false) return true;\n  return false;\n}\n\n/*** META ((export #t)\n           (peephole (postfix \"()\")))\n*/\nfunction sc_force(o) {\n  return o();\n}\n\n/*** META ((export #t)) */\nfunction sc_makePromise(proc) {\n  var isResultReady = false;\n  var result = undefined;\n  return function () {\n    if (!isResultReady) {\n      var tmp = proc();\n      if (!isResultReady) {\n        isResultReady = true;\n        result = tmp;\n      }\n    }\n    return result;\n  };\n}\n\nfunction sc_Values(values) {\n  this.values = values;\n}\n\n/*** META ((export #t)\n           (peephole (values)))\n*/\nfunction sc_values() {\n  if (arguments.length === 1) return arguments[0];\n  else return new sc_Values(arguments);\n}\n\n/*** META ((export #t)) */\nfunction sc_callWithValues(producer, consumer) {\n  var produced = producer();\n  if (produced instanceof sc_Values)\n    return consumer.apply(null, produced.values);\n  else return consumer(produced);\n}\n\n/*** META ((export #t)) */\nfunction sc_dynamicWind(before, thunk, after) {\n  before();\n  try {\n    var res = thunk();\n    return res;\n  } finally {\n    after();\n  }\n}\n\n// TODO: eval/scheme-report-environment/null-environment/interaction-environment\n\n// LIMITATION: 'load' doesn't exist without files.\n// LIMITATION: transcript-on/transcript-off doesn't exist without files.\n\nfunction sc_Struct(name) {\n  this.name = name;\n}\nsc_Struct.prototype.sc_toDisplayString = function () {\n  return \"#<struct\" + sc_hash(this) + \">\";\n};\nsc_Struct.prototype.sc_toWriteString = sc_Struct.prototype.sc_toDisplayString;\n\n/*** META ((export #t)\n           (peephole (hole 1 \"new sc_Struct(\" name \")\")))\n*/\nfunction sc_makeStruct(name) {\n  return new sc_Struct(name);\n}\n\n/*** META ((export #t)\n           (type bool)\n           (peephole (postfix \" instanceof sc_Struct\")))\n*/\nfunction sc_isStruct(o) {\n  return o instanceof sc_Struct;\n}\n\n/*** META ((export #t)\n           (type bool)\n           (peephole (hole 2 \"(\" 1 \" instanceof sc_Struct) && ( \" 1 \".name === \" 0 \")\")))\n*/\nfunction sc_isStructNamed(name, s) {\n  return s instanceof sc_Struct && s.name === name;\n}\n\n/*** META ((export struct-field)\n           (peephole (hole 3 0 \"[\" 2 \"]\")))\n*/\nfunction sc_getStructField(s, name, field) {\n  return s[field];\n}\n\n/*** META ((export struct-field-set!)\n           (peephole (hole 4 0 \"[\" 2 \"] = \" 3)))\n*/\nfunction sc_setStructFieldBang(s, name, field, val) {\n  s[field] = val;\n}\n\n/*** META ((export #t)\n           (peephole (prefix \"~\")))\n*/\nfunction sc_bitNot(x) {\n  return ~x;\n}\n\n/*** META ((export #t)\n           (peephole (infix 2 2 \"&\")))\n*/\nfunction sc_bitAnd(x, y) {\n  return x & y;\n}\n\n/*** META ((export #t)\n           (peephole (infix 2 2 \"|\")))\n*/\nfunction sc_bitOr(x, y) {\n  return x | y;\n}\n\n/*** META ((export #t)\n           (peephole (infix 2 2 \"^\")))\n*/\nfunction sc_bitXor(x, y) {\n  return x ^ y;\n}\n\n/*** META ((export #t)\n           (peephole (infix 2 2 \"<<\")))\n*/\nfunction sc_bitLsh(x, y) {\n  return x << y;\n}\n\n/*** META ((export #t)\n           (peephole (infix 2 2 \">>\")))\n*/\nfunction sc_bitRsh(x, y) {\n  return x >> y;\n}\n\n/*** META ((export #t)\n           (peephole (infix 2 2 \">>>\")))\n*/\nfunction sc_bitUrsh(x, y) {\n  return x >>> y;\n}\n\n/*** META ((export js-field js-property)\n           (peephole (hole 2 o \"[\" field \"]\")))\n*/\nfunction sc_jsField(o, field) {\n  return o[field];\n}\n\n/*** META ((export js-field-set! js-property-set!)\n           (peephole (hole 3 o \"[\" field \"] = \" val)))\n*/\nfunction sc_setJsFieldBang(o, field, val) {\n  return (o[field] = val);\n}\n\n/*** META ((export js-field-delete! js-property-delete!)\n           (peephole (hole 2 \"delete\" o \"[\" field \"]\")))\n*/\nfunction sc_deleteJsFieldBang(o, field) {\n  delete o[field];\n}\n\n/*** META ((export #t)\n           (peephole (jsCall)))\n*/\nfunction sc_jsCall(o, fun) {\n  var args = new Array();\n  for (var i = 2; i < arguments.length; i++) args[i - 2] = arguments[i];\n  return fun.apply(o, args);\n}\n\n/*** META ((export #t)\n           (peephole (jsMethodCall)))\n*/\nfunction sc_jsMethodCall(o, field) {\n  var args = new Array();\n  for (var i = 2; i < arguments.length; i++) args[i - 2] = arguments[i];\n  return o[field].apply(o, args);\n}\n\n/*** META ((export new js-new)\n           (peephole (jsNew)))\n*/\nfunction sc_jsNew(c) {\n  var evalStr = \"new c(\";\n  evalStr += arguments.length > 1 ? \"arguments[1]\" : \"\";\n  for (var i = 2; i < arguments.length; i++)\n    evalStr += \", arguments[\" + i + \"]\";\n  evalStr += \")\";\n  return eval(evalStr);\n}\n\n// ======================== RegExp ====================\n/*** META ((export #t)) */\nfunction sc_pregexp(re) {\n  return new RegExp(sc_string2jsstring(re));\n}\n\n/*** META ((export #t)) */\nfunction sc_pregexpMatch(re, s) {\n  var reg = re instanceof RegExp ? re : sc_pregexp(re);\n  var tmp = reg.exec(sc_string2jsstring(s));\n\n  if (tmp == null) return false;\n\n  var res = null;\n  for (var i = tmp.length - 1; i >= 0; i--) {\n    if (tmp[i] !== null) {\n      res = sc_cons(sc_jsstring2string(tmp[i]), res);\n    } else {\n      res = sc_cons(false, res);\n    }\n  }\n  return res;\n}\n\n/*** META ((export #t)) */\nfunction sc_pregexpReplace(re, s1, s2) {\n  var reg;\n  var jss1 = sc_string2jsstring(s1);\n  var jss2 = sc_string2jsstring(s2);\n\n  if (re instanceof RegExp) {\n    if (re.global) reg = re;\n    else reg = new RegExp(re.source);\n  } else {\n    reg = new RegExp(sc_string2jsstring(re));\n  }\n\n  return jss1.replace(reg, jss2);\n}\n\n/*** META ((export pregexp-replace*)) */\nfunction sc_pregexpReplaceAll(re, s1, s2) {\n  var reg;\n  var jss1 = sc_string2jsstring(s1);\n  var jss2 = sc_string2jsstring(s2);\n\n  if (re instanceof RegExp) {\n    if (re.global) reg = re;\n    else reg = new RegExp(re.source, \"g\");\n  } else {\n    reg = new RegExp(sc_string2jsstring(re), \"g\");\n  }\n\n  return jss1.replace(reg, jss2);\n}\n\n/*** META ((export #t)) */\nfunction sc_pregexpSplit(re, s) {\n  var reg = re instanceof RegExp ? re : new RegExp(sc_string2jsstring(re));\n  var jss = sc_string2jsstring(s);\n  var tmp = jss.split(reg);\n\n  if (tmp == null) return false;\n\n  return sc_vector2list(tmp);\n}\n\n/* =========================================================================== */\n/* Other library stuff */\n/* =========================================================================== */\n\n/*** META ((export #t)\n           (peephole (hole 1 \"Math.floor(Math.random()*\" 'n \")\")))\n*/\nfunction sc_random(n) {\n  return Math.floor(Math.random() * n);\n}\n\n/*** META ((export current-date)\n           (peephole (hole 0 \"new Date()\")))\n*/\nfunction sc_currentDate() {\n  return new Date();\n}\n\nfunction sc_Hashtable() {}\nsc_Hashtable.prototype.toString = function () {\n  return \"#{%hashtable}\";\n};\n// sc_toWriteString == sc_toDisplayString == toString\n\nfunction sc_HashtableElement(key, val) {\n  this.key = key;\n  this.val = val;\n}\n\n/*** META ((export #t)\n           (peephole (hole 0 \"new sc_Hashtable()\")))\n*/\nfunction sc_makeHashtable() {\n  return new sc_Hashtable();\n}\n\n/*** META ((export #t)) */\nfunction sc_hashtablePutBang(ht, key, val) {\n  var hash = sc_hash(key);\n  ht[hash] = new sc_HashtableElement(key, val);\n}\n\n/*** META ((export #t)) */\nfunction sc_hashtableGet(ht, key) {\n  var hash = sc_hash(key);\n  if (hash in ht) return ht[hash].val;\n  else return false;\n}\n\n/*** META ((export #t)) */\nfunction sc_hashtableForEach(ht, f) {\n  for (var v in ht) {\n    if (ht[v] instanceof sc_HashtableElement) f(ht[v].key, ht[v].val);\n  }\n}\n\n/*** META ((export hashtable-contains?)\n           (peephole (hole 2 \"sc_hash(\" 1 \") in \" 0)))\n*/\nfunction sc_hashtableContains(ht, key) {\n  var hash = sc_hash(key);\n  if (hash in ht) return true;\n  else return false;\n}\n\nvar SC_HASH_COUNTER = 0;\n\nfunction sc_hash(o) {\n  if (o === null) return \"null\";\n  else if (o === undefined) return \"undefined\";\n  else if (o === true) return \"true\";\n  else if (o === false) return \"false\";\n  else if (typeof o === \"number\") return \"num-\" + o;\n  else if (typeof o === \"string\") return \"jsstr-\" + o;\n  else if (o.sc_getHash) return o.sc_getHash();\n  else return sc_counterHash.call(o);\n}\nfunction sc_counterHash() {\n  if (!this.sc_hash) {\n    this.sc_hash = \"hash-\" + SC_HASH_COUNTER;\n    SC_HASH_COUNTER++;\n  }\n  return this.sc_hash;\n}\n\nfunction sc_Trampoline(args, maxTailCalls) {\n  this[\"__trampoline return__\"] = true;\n  this.args = args;\n  this.MAX_TAIL_CALLs = maxTailCalls;\n}\n// TODO: call/cc stuff\nsc_Trampoline.prototype.restart = function () {\n  var o = this;\n  while (true) {\n    // set both globals.\n    SC_TAIL_OBJECT.calls = o.MAX_TAIL_CALLs - 1;\n    var fun = o.args.callee;\n    var res = fun.apply(SC_TAIL_OBJECT, o.args);\n    if (res instanceof sc_Trampoline) o = res;\n    else return res;\n  }\n};\n\n/*** META ((export bind-exit-lambda)) */\nfunction sc_bindExitLambda(proc) {\n  var escape_obj = new sc_BindExitException();\n  var escape = function (res) {\n    escape_obj.res = res;\n    throw escape_obj;\n  };\n  try {\n    return proc(escape);\n  } catch (e) {\n    if (e === escape_obj) {\n      return e.res;\n    }\n    throw e;\n  }\n}\nfunction sc_BindExitException() {\n  this._internalException = true;\n}\n\nvar SC_SCM2JS_GLOBALS = new Object();\n\n// default tail-call depth.\n// normally the program should set it again. but just in case...\nvar SC_TAIL_OBJECT = new Object();\nSC_SCM2JS_GLOBALS.TAIL_OBJECT = SC_TAIL_OBJECT;\n// ======================== I/O =======================\n\n/*------------------------------------------------------------------*/\n\nfunction sc_EOF() {}\nvar SC_EOF_OBJECT = new sc_EOF();\n\nfunction sc_Port() {}\n\n/* --------------- Input ports -------------------------------------*/\n\nfunction sc_InputPort() {}\nsc_InputPort.prototype = new sc_Port();\n\nsc_InputPort.prototype.peekChar = function () {\n  if (!(\"peeked\" in this)) this.peeked = this.getNextChar();\n  return this.peeked;\n};\nsc_InputPort.prototype.readChar = function () {\n  var tmp = this.peekChar();\n  delete this.peeked;\n  return tmp;\n};\nsc_InputPort.prototype.isCharReady = function () {\n  return true;\n};\nsc_InputPort.prototype.close = function () {\n  // do nothing\n};\n\n/* .............. String port ..........................*/\nfunction sc_ErrorInputPort() {}\nsc_ErrorInputPort.prototype = new sc_InputPort();\nsc_ErrorInputPort.prototype.getNextChar = function () {\n  throw \"can't read from error-port.\";\n};\nsc_ErrorInputPort.prototype.isCharReady = function () {\n  return false;\n};\n\n/* .............. String port ..........................*/\n\nfunction sc_StringInputPort(jsStr) {\n  // we are going to do some charAts on the str.\n  // instead of recreating all the time a String-object, we\n  // create one in the beginning. (not sure, if this is really an optim)\n  this.str = new String(jsStr);\n  this.pos = 0;\n}\nsc_StringInputPort.prototype = new sc_InputPort();\nsc_StringInputPort.prototype.getNextChar = function () {\n  if (this.pos >= this.str.length) return SC_EOF_OBJECT;\n  return this.str.charAt(this.pos++);\n};\n\n/* ------------- Read and other lib-funs  -------------------------------*/\nfunction sc_Token(type, val, pos) {\n  this.type = type;\n  this.val = val;\n  this.pos = pos;\n}\nsc_Token.EOF = 0 /*EOF*/;\nsc_Token.OPEN_PAR = 1 /*OPEN_PAR*/;\nsc_Token.CLOSE_PAR = 2 /*CLOSE_PAR*/;\nsc_Token.OPEN_BRACE = 3 /*OPEN_BRACE*/;\nsc_Token.CLOSE_BRACE = 4 /*CLOSE_BRACE*/;\nsc_Token.OPEN_BRACKET = 5 /*OPEN_BRACKET*/;\nsc_Token.CLOSE_BRACKET = 6 /*CLOSE_BRACKET*/;\nsc_Token.WHITESPACE = 7 /*WHITESPACE*/;\nsc_Token.QUOTE = 8 /*QUOTE*/;\nsc_Token.ID = 9 /*ID*/;\nsc_Token.DOT = 10 /*DOT*/;\nsc_Token.STRING = 11 /*STRING*/;\nsc_Token.NUMBER = 12 /*NUMBER*/;\nsc_Token.ERROR = 13 /*ERROR*/;\nsc_Token.VECTOR_BEGIN = 14 /*VECTOR_BEGIN*/;\nsc_Token.TRUE = 15 /*TRUE*/;\nsc_Token.FALSE = 16 /*FALSE*/;\nsc_Token.UNSPECIFIED = 17 /*UNSPECIFIED*/;\nsc_Token.REFERENCE = 18 /*REFERENCE*/;\nsc_Token.STORE = 19 /*STORE*/;\nsc_Token.CHAR = 20 /*CHAR*/;\n\nvar SC_ID_CLASS = SC_LOWER_CLASS + SC_UPPER_CLASS + \"!$%*+-./:<=>?@^_~\";\nfunction sc_Tokenizer(port) {\n  this.port = port;\n}\nsc_Tokenizer.prototype.peekToken = function () {\n  if (this.peeked) return this.peeked;\n  var newToken = this.nextToken();\n  this.peeked = newToken;\n  return newToken;\n};\nsc_Tokenizer.prototype.readToken = function () {\n  var tmp = this.peekToken();\n  delete this.peeked;\n  return tmp;\n};\nsc_Tokenizer.prototype.nextToken = function () {\n  var port = this.port;\n\n  function isNumberChar(c) {\n    return c >= \"0\" && c <= \"9\";\n  }\n  function isIdOrNumberChar(c) {\n    return (\n      SC_ID_CLASS.indexOf(c) != -1 || // ID-char\n      (c >= \"0\" && c <= \"9\")\n    );\n  }\n  function isWhitespace(c) {\n    return c === \" \" || c === \"\\r\" || c === \"\\n\" || c === \"\\t\" || c === \"\\f\";\n  }\n  function isWhitespaceOrEOF(c) {\n    return isWhitespace(c) || c === SC_EOF_OBJECT;\n  }\n\n  function readString() {\n    res = \"\";\n    while (true) {\n      var c = port.readChar();\n      switch (c) {\n        case '\"':\n          return new sc_Token(11 /*STRING*/, res);\n        case \"\\\\\":\n          var tmp = port.readChar();\n          switch (tmp) {\n            case \"0\":\n              res += \"\\0\";\n              break;\n            case \"a\":\n              res += \"a\";\n              break;\n            case \"b\":\n              res += \"\\b\";\n              break;\n            case \"f\":\n              res += \"\\f\";\n              break;\n            case \"n\":\n              res += \"\\n\";\n              break;\n            case \"r\":\n              res += \"\\r\";\n              break;\n            case \"t\":\n              res += \"\\t\";\n              break;\n            case \"v\":\n              res += \"\\v\";\n              break;\n            case '\"':\n              res += '\"';\n              break;\n            case \"\\\\\":\n              res += \"\\\\\";\n              break;\n            case \"x\":\n              /* hexa-number */\n              var nb = 0;\n              while (true) {\n                var hexC = port.peekChar();\n                if (hexC >= \"0\" && hexC <= \"9\") {\n                  port.readChar();\n                  nb = nb * 16 + hexC.charCodeAt(0) - \"0\".charCodeAt(0);\n                } else if (hexC >= \"a\" && hexC <= \"f\") {\n                  port.readChar();\n                  nb = nb * 16 + hexC.charCodeAt(0) - \"a\".charCodeAt(0);\n                } else if (hexC >= \"A\" && hexC <= \"F\") {\n                  port.readChar();\n                  nb = nb * 16 + hexC.charCodeAt(0) - \"A\".charCodeAt(0);\n                } else {\n                  // next char isn't part of hex.\n                  res += String.fromCharCode(nb);\n                  break;\n                }\n              }\n              break;\n            default:\n              if (tmp === SC_EOF_OBJECT) {\n                return new sc_Token(\n                  13 /*ERROR*/,\n                  \"unclosed string-literal\" + res\n                );\n              }\n              res += tmp;\n          }\n          break;\n        default:\n          if (c === SC_EOF_OBJECT) {\n            return new sc_Token(13 /*ERROR*/, \"unclosed string-literal\" + res);\n          }\n          res += c;\n      }\n    }\n  }\n  function readIdOrNumber(firstChar) {\n    var res = firstChar;\n    while (isIdOrNumberChar(port.peekChar())) res += port.readChar();\n    if (isNaN(res)) return new sc_Token(9 /*ID*/, res);\n    else return new sc_Token(12 /*NUMBER*/, res - 0);\n  }\n\n  function skipWhitespaceAndComments() {\n    var done = false;\n    while (!done) {\n      done = true;\n      while (isWhitespace(port.peekChar())) port.readChar();\n      if (port.peekChar() === \";\") {\n        port.readChar();\n        done = false;\n        while (true) {\n          curChar = port.readChar();\n          if (curChar === SC_EOF_OBJECT || curChar === \"\\n\") break;\n        }\n      }\n    }\n  }\n\n  function readDot() {\n    if (isWhitespace(port.peekChar())) return new sc_Token(10 /*DOT*/);\n    else return readIdOrNumber(\".\");\n  }\n\n  function readSharp() {\n    var c = port.readChar();\n    if (isWhitespace(c)) return new sc_Token(13 /*ERROR*/, \"bad #-pattern0.\");\n\n    // reference\n    if (isNumberChar(c)) {\n      var nb = c - 0;\n      while (isNumberChar(port.peekChar()))\n        nb = nb * 10 + (port.readChar() - 0);\n      switch (port.readChar()) {\n        case \"#\":\n          return new sc_Token(18 /*REFERENCE*/, nb);\n        case \"=\":\n          return new sc_Token(19 /*STORE*/, nb);\n        default:\n          return new sc_Token(13 /*ERROR*/, \"bad #-pattern1.\" + nb);\n      }\n    }\n\n    if (c === \"(\") return new sc_Token(14 /*VECTOR_BEGIN*/);\n\n    if (c === \"\\\\\") {\n      // character\n      var tmp = \"\";\n      while (!isWhitespaceOrEOF(port.peekChar())) tmp += port.readChar();\n      switch (tmp.length) {\n        case 0: // it's escaping a whitespace char:\n          if (sc_isEOFObject(port.peekChar))\n            return new sc_Token(13 /*ERROR*/, \"bad #-pattern2.\");\n          else return new sc_Token(20 /*CHAR*/, port.readChar());\n        case 1:\n          return new sc_Token(20 /*CHAR*/, tmp);\n        default:\n          var entry = sc_Char.readable2char[tmp.toLowerCase()];\n          if (entry) return new sc_Token(20 /*CHAR*/, entry);\n          else\n            return new sc_Token(\n              13 /*ERROR*/,\n              \"unknown character description: #\\\\\" + tmp\n            );\n      }\n    }\n\n    // some constants (#t, #f, #unspecified)\n    var res;\n    var needing;\n    switch (c) {\n      case \"t\":\n        res = new sc_Token(15 /*TRUE*/, true);\n        needing = \"\";\n        break;\n      case \"f\":\n        res = new sc_Token(16 /*FALSE*/, false);\n        needing = \"\";\n        break;\n      case \"u\":\n        res = new sc_Token(17 /*UNSPECIFIED*/, undefined);\n        needing = \"nspecified\";\n        break;\n      default:\n        return new sc_Token(13 /*ERROR*/, \"bad #-pattern3: \" + c);\n    }\n    while (true) {\n      c = port.peekChar();\n      if ((isWhitespaceOrEOF(c) || c === \")\") && needing == \"\") return res;\n      else if (isWhitespace(c) || needing == \"\")\n        return new sc_Token(\n          13 /*ERROR*/,\n          \"bad #-pattern4 \" + c + \" \" + needing\n        );\n      else if (needing.charAt(0) == c) {\n        port.readChar(); // consume\n        needing = needing.slice(1);\n      } else return new sc_Token(13 /*ERROR*/, \"bad #-pattern5\");\n    }\n  }\n\n  skipWhitespaceAndComments();\n  var curChar = port.readChar();\n  if (curChar === SC_EOF_OBJECT) return new sc_Token(0 /*EOF*/, curChar);\n  switch (curChar) {\n    case \" \":\n    case \"\\n\":\n    case \"\\t\":\n      return readWhitespace();\n    case \"(\":\n      return new sc_Token(1 /*OPEN_PAR*/);\n    case \")\":\n      return new sc_Token(2 /*CLOSE_PAR*/);\n    case \"{\":\n      return new sc_Token(3 /*OPEN_BRACE*/);\n    case \"}\":\n      return new sc_Token(4 /*CLOSE_BRACE*/);\n    case \"[\":\n      return new sc_Token(5 /*OPEN_BRACKET*/);\n    case \"]\":\n      return new sc_Token(6 /*CLOSE_BRACKET*/);\n    case \"'\":\n      return new sc_Token(8 /*QUOTE*/);\n    case \"#\":\n      return readSharp();\n    case \".\":\n      return readDot();\n    case '\"':\n      return readString();\n    default:\n      if (isIdOrNumberChar(curChar)) return readIdOrNumber(curChar);\n      throw \"unexpected character: \" + curChar;\n  }\n};\n\nfunction sc_Reader(tokenizer) {\n  this.tokenizer = tokenizer;\n  this.backref = new Array();\n}\nsc_Reader.prototype.read = function () {\n  function readList(listBeginType) {\n    function matchesPeer(open, close) {\n      return (\n        (open === 1 /*OPEN_PAR*/ && close === 2) /*CLOSE_PAR*/ ||\n        (open === 3 /*OPEN_BRACE*/ && close === 4) /*CLOSE_BRACE*/ ||\n        (open === 5 /*OPEN_BRACKET*/ && close === 6) /*CLOSE_BRACKET*/\n      );\n    }\n    var res = null;\n\n    while (true) {\n      var token = tokenizer.peekToken();\n\n      switch (token.type) {\n        case 2 /*CLOSE_PAR*/:\n        case 4 /*CLOSE_BRACE*/:\n        case 6 /*CLOSE_BRACKET*/:\n          if (matchesPeer(listBeginType, token.type)) {\n            tokenizer.readToken(); // consume token\n            return sc_reverseBang(res);\n          } else\n            throw (\n              \"closing par doesn't match: \" + listBeginType + \" \" + listEndType\n            );\n\n        case 0 /*EOF*/:\n          throw \"unexpected end of file\";\n\n        case 10 /*DOT*/:\n          tokenizer.readToken(); // consume token\n          var cdr = this.read();\n          var par = tokenizer.readToken();\n          if (!matchesPeer(listBeginType, par.type))\n            throw (\n              \"closing par doesn't match: \" + listBeginType + \" \" + par.type\n            );\n          else return sc_reverseAppendBang(res, cdr);\n\n        default:\n          res = sc_cons(this.read(), res);\n      }\n    }\n  }\n  function readQuote() {\n    return sc_cons(\"quote\", sc_cons(this.read(), null));\n  }\n  function readVector() {\n    // opening-parenthesis is already consumed\n    var a = new Array();\n    while (true) {\n      var token = tokenizer.peekToken();\n      switch (token.type) {\n        case 2 /*CLOSE_PAR*/:\n          tokenizer.readToken();\n          return a;\n\n        default:\n          a.push(this.read());\n      }\n    }\n  }\n\n  function storeRefence(nb) {\n    var tmp = this.read();\n    this.backref[nb] = tmp;\n    return tmp;\n  }\n\n  function readReference(nb) {\n    if (nb in this.backref) return this.backref[nb];\n    else throw \"bad reference: \" + nb;\n  }\n\n  var tokenizer = this.tokenizer;\n\n  var token = tokenizer.readToken();\n\n  // handle error\n  if (token.type === 13 /*ERROR*/) throw token.val;\n\n  switch (token.type) {\n    case 1 /*OPEN_PAR*/:\n    case 3 /*OPEN_BRACE*/:\n    case 5 /*OPEN_BRACKET*/:\n      return readList.call(this, token.type);\n    case 8 /*QUOTE*/:\n      return readQuote.call(this);\n    case 11 /*STRING*/:\n      return sc_jsstring2string(token.val);\n    case 20 /*CHAR*/:\n      return new sc_Char(token.val);\n    case 14 /*VECTOR_BEGIN*/:\n      return readVector.call(this);\n    case 18 /*REFERENCE*/:\n      return readReference.call(this, token.val);\n    case 19 /*STORE*/:\n      return storeRefence.call(this, token.val);\n    case 9 /*ID*/:\n      return sc_jsstring2symbol(token.val);\n    case 0 /*EOF*/:\n    case 12 /*NUMBER*/:\n    case 15 /*TRUE*/:\n    case 16 /*FALSE*/:\n    case 17 /*UNSPECIFIED*/:\n      return token.val;\n    default:\n      throw \"unexpected token \" + token.type + \" \" + token.val;\n  }\n};\n\n/*** META ((export #t)) */\nfunction sc_read(port) {\n  if (port === undefined)\n    // we assume the port hasn't been given.\n    port = SC_DEFAULT_IN; // THREAD: shared var...\n  var reader = new sc_Reader(new sc_Tokenizer(port));\n  return reader.read();\n}\n/*** META ((export #t)) */\nfunction sc_readChar(port) {\n  if (port === undefined)\n    // we assume the port hasn't been given.\n    port = SC_DEFAULT_IN; // THREAD: shared var...\n  var t = port.readChar();\n  return t === SC_EOF_OBJECT ? t : new sc_Char(t);\n}\n/*** META ((export #t)) */\nfunction sc_peekChar(port) {\n  if (port === undefined)\n    // we assume the port hasn't been given.\n    port = SC_DEFAULT_IN; // THREAD: shared var...\n  var t = port.peekChar();\n  return t === SC_EOF_OBJECT ? t : new sc_Char(t);\n}\n/*** META ((export #t)\n           (type bool))\n*/\nfunction sc_isCharReady(port) {\n  if (port === undefined)\n    // we assume the port hasn't been given.\n    port = SC_DEFAULT_IN; // THREAD: shared var...\n  return port.isCharReady();\n}\n/*** META ((export #t)\n           (peephole (postfix \".close()\")))\n*/\nfunction sc_closeInputPort(p) {\n  return p.close();\n}\n\n/*** META ((export #t)\n           (type bool)\n           (peephole (postfix \" instanceof sc_InputPort\")))\n*/\nfunction sc_isInputPort(o) {\n  return o instanceof sc_InputPort;\n}\n\n/*** META ((export eof-object?)\n           (type bool)\n           (peephole (postfix \" === SC_EOF_OBJECT\")))\n*/\nfunction sc_isEOFObject(o) {\n  return o === SC_EOF_OBJECT;\n}\n\n/*** META ((export #t)\n           (peephole (hole 0 \"SC_DEFAULT_IN\")))\n*/\nfunction sc_currentInputPort() {\n  return SC_DEFAULT_IN;\n}\n\n/* ------------ file operations are not supported -----------*/\n/*** META ((export #t)) */\nfunction sc_callWithInputFile(s, proc) {\n  throw \"can't open \" + s;\n}\n\n/*** META ((export #t)) */\nfunction sc_callWithOutputFile(s, proc) {\n  throw \"can't open \" + s;\n}\n\n/*** META ((export #t)) */\nfunction sc_withInputFromFile(s, thunk) {\n  throw \"can't open \" + s;\n}\n\n/*** META ((export #t)) */\nfunction sc_withOutputToFile(s, thunk) {\n  throw \"can't open \" + s;\n}\n\n/*** META ((export #t)) */\nfunction sc_openInputFile(s) {\n  throw \"can't open \" + s;\n}\n\n/*** META ((export #t)) */\nfunction sc_openOutputFile(s) {\n  throw \"can't open \" + s;\n}\n\n/* ----------------------------------------------------------------------------*/\n/*** META ((export #t)) */\nfunction sc_basename(p) {\n  var i = p.lastIndexOf(\"/\");\n\n  if (i >= 0) return p.substring(i + 1, p.length);\n  else return \"\";\n}\n\n/*** META ((export #t)) */\nfunction sc_dirname(p) {\n  var i = p.lastIndexOf(\"/\");\n\n  if (i >= 0) return p.substring(0, i);\n  else return \"\";\n}\n\n/* ----------------------------------------------------------------------------*/\n\n/*** META ((export #t)) */\nfunction sc_withInputFromPort(p, thunk) {\n  try {\n    var tmp = SC_DEFAULT_IN; // THREAD: shared var.\n    SC_DEFAULT_IN = p;\n    return thunk();\n  } finally {\n    SC_DEFAULT_IN = tmp;\n  }\n}\n\n/*** META ((export #t)) */\nfunction sc_withInputFromString(s, thunk) {\n  return sc_withInputFromPort(\n    new sc_StringInputPort(sc_string2jsstring(s)),\n    thunk\n  );\n}\n\n/*** META ((export #t)) */\nfunction sc_withOutputToPort(p, thunk) {\n  try {\n    var tmp = SC_DEFAULT_OUT; // THREAD: shared var.\n    SC_DEFAULT_OUT = p;\n    return thunk();\n  } finally {\n    SC_DEFAULT_OUT = tmp;\n  }\n}\n\n/*** META ((export #t)) */\nfunction sc_withOutputToString(thunk) {\n  var p = new sc_StringOutputPort();\n  sc_withOutputToPort(p, thunk);\n  return p.close();\n}\n\n/*** META ((export #t)) */\nfunction sc_withOutputToProcedure(proc, thunk) {\n  var t = function (s) {\n    proc(sc_jsstring2string(s));\n  };\n  return sc_withOutputToPort(new sc_GenericOutputPort(t), thunk);\n}\n\n/*** META ((export #t)\n           (peephole (hole 0 \"new sc_StringOutputPort()\")))\n*/\nfunction sc_openOutputString() {\n  return new sc_StringOutputPort();\n}\n\n/*** META ((export #t)) */\nfunction sc_openInputString(str) {\n  return new sc_StringInputPort(sc_string2jsstring(str));\n}\n\n/* ----------------------------------------------------------------------------*/\n\nfunction sc_OutputPort() {}\nsc_OutputPort.prototype = new sc_Port();\nsc_OutputPort.prototype.appendJSString = function (obj) {\n  /* do nothing */\n};\nsc_OutputPort.prototype.close = function () {\n  /* do nothing */\n};\n\nfunction sc_StringOutputPort() {\n  this.res = \"\";\n}\nsc_StringOutputPort.prototype = new sc_OutputPort();\nsc_StringOutputPort.prototype.appendJSString = function (s) {\n  this.res += s;\n};\nsc_StringOutputPort.prototype.close = function () {\n  return sc_jsstring2string(this.res);\n};\n\n/*** META ((export #t)) */\nfunction sc_getOutputString(sp) {\n  return sc_jsstring2string(sp.res);\n}\n\nfunction sc_ErrorOutputPort() {}\nsc_ErrorOutputPort.prototype = new sc_OutputPort();\nsc_ErrorOutputPort.prototype.appendJSString = function (s) {\n  throw \"don't write on ErrorPort!\";\n};\nsc_ErrorOutputPort.prototype.close = function () {\n  /* do nothing */\n};\n\nfunction sc_GenericOutputPort(appendJSString, close) {\n  this.appendJSString = appendJSString;\n  if (close) this.close = close;\n}\nsc_GenericOutputPort.prototype = new sc_OutputPort();\n\n/*** META ((export #t)\n           (type bool)\n           (peephole (postfix \" instanceof sc_OutputPort\")))\n*/\nfunction sc_isOutputPort(o) {\n  return o instanceof sc_OutputPort;\n}\n\n/*** META ((export #t)\n           (peephole (postfix \".close()\")))\n*/\nfunction sc_closeOutputPort(p) {\n  return p.close();\n}\n\n/* ------------------ write ---------------------------------------------------*/\n\n/*** META ((export #t)) */\nfunction sc_write(o, p) {\n  if (p === undefined)\n    // we assume not given\n    p = SC_DEFAULT_OUT;\n  p.appendJSString(sc_toWriteString(o));\n}\n\nfunction sc_toWriteString(o) {\n  if (o === null) return \"()\";\n  else if (o === true) return \"#t\";\n  else if (o === false) return \"#f\";\n  else if (o === undefined) return \"#unspecified\";\n  else if (typeof o === \"function\") return \"#<procedure \" + sc_hash(o) + \">\";\n  else if (o.sc_toWriteString) return o.sc_toWriteString();\n  else return o.toString();\n}\n\nfunction sc_escapeWriteString(s) {\n  var res = \"\";\n  var j = 0;\n  for (i = 0; i < s.length; i++) {\n    switch (s.charAt(i)) {\n      case \"\\0\":\n        res += s.substring(j, i) + \"\\\\0\";\n        j = i + 1;\n        break;\n      case \"\\b\":\n        res += s.substring(j, i) + \"\\\\b\";\n        j = i + 1;\n        break;\n      case \"\\f\":\n        res += s.substring(j, i) + \"\\\\f\";\n        j = i + 1;\n        break;\n      case \"\\n\":\n        res += s.substring(j, i) + \"\\\\n\";\n        j = i + 1;\n        break;\n      case \"\\r\":\n        res += s.substring(j, i) + \"\\\\r\";\n        j = i + 1;\n        break;\n      case \"\\t\":\n        res += s.substring(j, i) + \"\\\\t\";\n        j = i + 1;\n        break;\n      case \"\\v\":\n        res += s.substring(j, i) + \"\\\\v\";\n        j = i + 1;\n        break;\n      case '\"':\n        res += s.substring(j, i) + '\\\\\"';\n        j = i + 1;\n        break;\n      case \"\\\\\":\n        res += s.substring(j, i) + \"\\\\\\\\\";\n        j = i + 1;\n        break;\n      default:\n        var c = s.charAt(i);\n        if (\"a\" !== \"a\" && c == \"a\") {\n          res += s.substring(j, i) + \"\\\\a\";\n          j = i + 1;\n          continue;\n        }\n        if (\"\\v\" !== \"v\" && c == \"\\v\") {\n          res += s.substring(j, i) + \"\\\\v\";\n          j = i + 1;\n          continue;\n        }\n        //if (s.charAt(i) < ' ' || s.charCodeAt(i) > 127) {\n        // CARE: Manuel is this OK with HOP?\n        if (s.charAt(i) < \" \") {\n          /* non printable character and special chars */\n          res += s.substring(j, i) + \"\\\\x\" + s.charCodeAt(i).toString(16);\n          j = i + 1;\n        }\n      // else just let i increase...\n    }\n  }\n  res += s.substring(j, i);\n  return res;\n}\n\n/* ------------------ display ---------------------------------------------------*/\n\n/*** META ((export #t)) */\nfunction sc_display(o, p) {\n  if (p === undefined)\n    // we assume not given\n    p = SC_DEFAULT_OUT;\n  p.appendJSString(sc_toDisplayString(o));\n}\n\nfunction sc_toDisplayString(o) {\n  if (o === null) return \"()\";\n  else if (o === true) return \"#t\";\n  else if (o === false) return \"#f\";\n  else if (o === undefined) return \"#unspecified\";\n  else if (typeof o === \"function\") return \"#<procedure \" + sc_hash(o) + \">\";\n  else if (o.sc_toDisplayString) return o.sc_toDisplayString();\n  else return o.toString();\n}\n\n/* ------------------ newline ---------------------------------------------------*/\n\n/*** META ((export #t)) */\nfunction sc_newline(p) {\n  if (p === undefined)\n    // we assume not given\n    p = SC_DEFAULT_OUT;\n  p.appendJSString(\"\\n\");\n}\n\n/* ------------------ write-char ---------------------------------------------------*/\n\n/*** META ((export #t)) */\nfunction sc_writeChar(c, p) {\n  if (p === undefined)\n    // we assume not given\n    p = SC_DEFAULT_OUT;\n  p.appendJSString(c.val);\n}\n\n/* ------------------ write-circle ---------------------------------------------------*/\n\n/*** META ((export #t)) */\nfunction sc_writeCircle(o, p) {\n  if (p === undefined)\n    // we assume not given\n    p = SC_DEFAULT_OUT;\n  p.appendJSString(sc_toWriteCircleString(o));\n}\n\nfunction sc_toWriteCircleString(o) {\n  var symb = sc_gensym(\"writeCircle\");\n  var nbPointer = new Object();\n  nbPointer.nb = 0;\n  sc_prepWriteCircle(o, symb, nbPointer);\n  return sc_genToWriteCircleString(o, symb);\n}\n\nfunction sc_prepWriteCircle(o, symb, nbPointer) {\n  // TODO sc_Struct\n  if (o instanceof sc_Pair || o instanceof sc_Vector) {\n    if (o[symb] !== undefined) {\n      // not the first visit.\n      o[symb]++;\n      // unless there is already a number, assign one.\n      if (!o[symb + \"nb\"]) o[symb + \"nb\"] = nbPointer.nb++;\n      return;\n    }\n    o[symb] = 0;\n    if (o instanceof sc_Pair) {\n      sc_prepWriteCircle(o.car, symb, nbPointer);\n      sc_prepWriteCircle(o.cdr, symb, nbPointer);\n    } else {\n      for (var i = 0; i < o.length; i++)\n        sc_prepWriteCircle(o[i], symb, nbPointer);\n    }\n  }\n}\n\nfunction sc_genToWriteCircleString(o, symb) {\n  if (!(o instanceof sc_Pair || o instanceof sc_Vector))\n    return sc_toWriteString(o);\n  return o.sc_toWriteCircleString(symb);\n}\nsc_Pair.prototype.sc_toWriteCircleString = function (symb, inList) {\n  if (this[symb + \"use\"]) {\n    // use-flag is set. Just use it.\n    var nb = this[symb + \"nb\"];\n    if (this[symb]-- === 0) {\n      // if we are the last use. remove all fields.\n      delete this[symb];\n      delete this[symb + \"nb\"];\n      delete this[symb + \"use\"];\n    }\n    if (inList) return \". #\" + nb + \"#\";\n    else return \"#\" + nb + \"#\";\n  }\n  if (this[symb]-- === 0) {\n    // if we are the last use. remove all fields.\n    delete this[symb];\n    delete this[symb + \"nb\"];\n    delete this[symb + \"use\"];\n  }\n\n  var res = \"\";\n\n  if (this[symb] !== undefined) {\n    // implies > 0\n    this[symb + \"use\"] = true;\n    if (inList) res += \". #\" + this[symb + \"nb\"] + \"=\";\n    else res += \"#\" + this[symb + \"nb\"] + \"=\";\n    inList = false;\n  }\n\n  if (!inList) res += \"(\";\n\n  // print car\n  res += sc_genToWriteCircleString(this.car, symb);\n\n  if (sc_isPair(this.cdr)) {\n    res += \" \" + this.cdr.sc_toWriteCircleString(symb, true);\n  } else if (this.cdr !== null) {\n    res += \" . \" + sc_genToWriteCircleString(this.cdr, symb);\n  }\n  if (!inList) res += \")\";\n  return res;\n};\nsc_Vector.prototype.sc_toWriteCircleString = function (symb) {\n  if (this[symb + \"use\"]) {\n    // use-flag is set. Just use it.\n    var nb = this[symb + \"nb\"];\n    if (this[symb]-- === 0) {\n      // if we are the last use. remove all fields.\n      delete this[symb];\n      delete this[symb + \"nb\"];\n      delete this[symb + \"use\"];\n    }\n    return \"#\" + nb + \"#\";\n  }\n  if (this[symb]-- === 0) {\n    // if we are the last use. remove all fields.\n    delete this[symb];\n    delete this[symb + \"nb\"];\n    delete this[symb + \"use\"];\n  }\n\n  var res = \"\";\n  if (this[symb] !== undefined) {\n    // implies > 0\n    this[symb + \"use\"] = true;\n    res += \"#\" + this[symb + \"nb\"] + \"=\";\n  }\n  res += \"#(\";\n  for (var i = 0; i < this.length; i++) {\n    res += sc_genToWriteCircleString(this[i], symb);\n    if (i < this.length - 1) res += \" \";\n  }\n  res += \")\";\n  return res;\n};\n\n/* ------------------ print ---------------------------------------------------*/\n\n/*** META ((export #t)) */\nfunction sc_print(s) {\n  if (arguments.length === 1) {\n    sc_display(s);\n    sc_newline();\n  } else {\n    for (var i = 0; i < arguments.length; i++) sc_display(arguments[i]);\n    sc_newline();\n  }\n}\n\n/* ------------------ format ---------------------------------------------------*/\n/*** META ((export #t)) */\nfunction sc_format(s, args) {\n  var len = s.length;\n  var p = new sc_StringOutputPort();\n  var i = 0,\n    j = 1;\n\n  while (i < len) {\n    var i2 = s.indexOf(\"~\", i);\n\n    if (i2 == -1) {\n      p.appendJSString(s.substring(i, len));\n      return p.close();\n    } else {\n      if (i2 > i) {\n        if (i2 == len - 1) {\n          p.appendJSString(s.substring(i, len));\n          return p.close();\n        } else {\n          p.appendJSString(s.substring(i, i2));\n          i = i2;\n        }\n      }\n\n      switch (s.charCodeAt(i2 + 1)) {\n        case 65:\n        case 97:\n          // a\n          sc_display(arguments[j], p);\n          i += 2;\n          j++;\n          break;\n\n        case 83:\n        case 115:\n          // s\n          sc_write(arguments[j], p);\n          i += 2;\n          j++;\n          break;\n\n        case 86:\n        case 118:\n          // v\n          sc_display(arguments[j], p);\n          p.appendJSString(\"\\n\");\n          i += 2;\n          j++;\n          break;\n\n        case 67:\n        case 99:\n          // c\n          p.appendJSString(String.fromCharCode(arguments[j]));\n          i += 2;\n          j++;\n          break;\n\n        case 88:\n        case 120:\n          // x\n          p.appendJSString(arguments[j].toString(6));\n          i += 2;\n          j++;\n          break;\n\n        case 79:\n        case 111:\n          // o\n          p.appendJSString(arguments[j].toString(8));\n          i += 2;\n          j++;\n          break;\n\n        case 66:\n        case 98:\n          // b\n          p.appendJSString(arguments[j].toString(2));\n          i += 2;\n          j++;\n          break;\n\n        case 37:\n        case 110:\n          // %, n\n          p.appendJSString(\"\\n\");\n          i += 2;\n          break;\n\n        case 114:\n          // r\n          p.appendJSString(\"\\r\");\n          i += 2;\n          break;\n\n        case 126:\n          // ~\n          p.appendJSString(\"~\");\n          i += 2;\n          break;\n\n        default:\n          sc_error(\n            \"format: illegal ~\" +\n              String.fromCharCode(s.charCodeAt(i2 + 1)) +\n              \" sequence\"\n          );\n          return \"\";\n      }\n    }\n  }\n\n  return p.close();\n}\n\n/* ------------------ global ports ---------------------------------------------------*/\n\nvar SC_DEFAULT_IN = new sc_ErrorInputPort();\nvar SC_DEFAULT_OUT = new sc_ErrorOutputPort();\nvar SC_ERROR_OUT = new sc_ErrorOutputPort();\n\nvar sc_SYMBOL_PREFIX = \"\\u1E9C\";\nvar sc_KEYWORD_PREFIX = \"\\u1E9D\";\n\n/*** META ((export #t)\n           (peephole (id))) */\nfunction sc_jsstring2string(s) {\n  return s;\n}\n\n/*** META ((export #t)\n           (peephole (prefix \"'\\\\u1E9C' +\")))\n*/\nfunction sc_jsstring2symbol(s) {\n  return sc_SYMBOL_PREFIX + s;\n}\n\n/*** META ((export #t)\n           (peephole (id)))\n*/\nfunction sc_string2jsstring(s) {\n  return s;\n}\n\n/*** META ((export #t)\n           (peephole (symbol2jsstring_immutable)))\n*/\nfunction sc_symbol2jsstring(s) {\n  return s.slice(1);\n}\n\n/*** META ((export #t)\n           (peephole (postfix \".slice(1)\")))\n*/\nfunction sc_keyword2jsstring(k) {\n  return k.slice(1);\n}\n\n/*** META ((export #t)\n           (peephole (prefix \"'\\\\u1E9D' +\")))\n*/\nfunction sc_jsstring2keyword(s) {\n  return sc_KEYWORD_PREFIX + s;\n}\n\n/*** META ((export #t)\n           (type bool))\n*/\nfunction sc_isKeyword(s) {\n  return typeof s === \"string\" && s.charAt(0) === sc_KEYWORD_PREFIX;\n}\n\n/*** META ((export #t)) */\nvar sc_gensym = (function () {\n  var counter = 1000;\n  return function (sym) {\n    counter++;\n    if (!sym) sym = sc_SYMBOL_PREFIX;\n    return sym + \"s\" + counter + \"~\" + \"^sC-GeNsYm \";\n  };\n})();\n\n/*** META ((export #t)\n           (type bool))\n*/\nfunction sc_isEqual(o1, o2) {\n  return (\n    o1 === o2 ||\n    (sc_isPair(o1) && sc_isPair(o2) && sc_isPairEqual(o1, o2, sc_isEqual)) ||\n    (sc_isVector(o1) && sc_isVector(o2) && sc_isVectorEqual(o1, o2, sc_isEqual))\n  );\n}\n\n/*** META ((export number->symbol integer->symbol)) */\nfunction sc_number2symbol(x, radix) {\n  return sc_SYMBOL_PREFIX + sc_number2jsstring(x, radix);\n}\n\n/*** META ((export number->string integer->string)) */\nvar sc_number2string = sc_number2jsstring;\n\n/*** META ((export #t)) */\nfunction sc_symbol2number(s, radix) {\n  return sc_jsstring2number(s.slice(1), radix);\n}\n\n/*** META ((export #t)) */\nvar sc_string2number = sc_jsstring2number;\n\n/*** META ((export #t)\n           (peephole (prefix \"+\" s)))\n           ;; peephole will only apply if no radix is given.\n*/\nfunction sc_string2integer(s, radix) {\n  if (!radix) return +s;\n  return parseInt(s, radix);\n}\n\n/*** META ((export #t)\n           (peephole (prefix \"+\")))\n*/\nfunction sc_string2real(s) {\n  return +s;\n}\n\n/*** META ((export #t)\n           (type bool))\n*/\nfunction sc_isSymbol(s) {\n  return typeof s === \"string\" && s.charAt(0) === sc_SYMBOL_PREFIX;\n}\n\n/*** META ((export #t)\n           (peephole (symbol2string_immutable)))\n*/\nfunction sc_symbol2string(s) {\n  return s.slice(1);\n}\n\n/*** META ((export #t)\n           (peephole (prefix \"'\\\\u1E9C' +\")))\n*/\nfunction sc_string2symbol(s) {\n  return sc_SYMBOL_PREFIX + s;\n}\n\n/*** META ((export symbol-append)\n           (peephole (symbolAppend_immutable)))\n*/\nfunction sc_symbolAppend() {\n  var res = sc_SYMBOL_PREFIX;\n  for (var i = 0; i < arguments.length; i++) res += arguments[i].slice(1);\n  return res;\n}\n\n/*** META ((export #t)\n           (peephole (postfix \".val\")))\n*/\nfunction sc_char2string(c) {\n  return c.val;\n}\n\n/*** META ((export #t)\n           (peephole (hole 1 \"'\\\\u1E9C' + \" c \".val\")))\n*/\nfunction sc_char2symbol(c) {\n  return sc_SYMBOL_PREFIX + c.val;\n}\n\n/*** META ((export #t)\n           (type bool))\n*/\nfunction sc_isString(s) {\n  return typeof s === \"string\" && s.charAt(0) !== sc_SYMBOL_PREFIX;\n}\n\n/*** META ((export #t)) */\nvar sc_makeString = sc_makejsString;\n\n/*** META ((export #t)) */\nfunction sc_string() {\n  for (var i = 0; i < arguments.length; i++) arguments[i] = arguments[i].val;\n  return \"\".concat.apply(\"\", arguments);\n}\n\n/*** META ((export #t)\n           (peephole (postfix \".length\")))\n*/\nfunction sc_stringLength(s) {\n  return s.length;\n}\n\n/*** META ((export #t)) */\nfunction sc_stringRef(s, k) {\n  return new sc_Char(s.charAt(k));\n}\n\n/* there's no stringSet in the immutable version\nfunction sc_stringSet(s, k, c)\n*/\n\n/*** META ((export string=?)\n\t   (type bool)\n           (peephole (hole 2 str1 \" === \" str2)))\n*/\nfunction sc_isStringEqual(s1, s2) {\n  return s1 === s2;\n}\n/*** META ((export string<?)\n\t   (type bool)\n           (peephole (hole 2 str1 \" < \" str2)))\n*/\nfunction sc_isStringLess(s1, s2) {\n  return s1 < s2;\n}\n/*** META ((export string>?)\n\t   (type bool)\n           (peephole (hole 2 str1 \" > \" str2)))\n*/\nfunction sc_isStringGreater(s1, s2) {\n  return s1 > s2;\n}\n/*** META ((export string<=?)\n\t   (type bool)\n           (peephole (hole 2 str1 \" <= \" str2)))\n*/\nfunction sc_isStringLessEqual(s1, s2) {\n  return s1 <= s2;\n}\n/*** META ((export string>=?)\n\t   (type bool)\n           (peephole (hole 2 str1 \" >= \" str2)))\n*/\nfunction sc_isStringGreaterEqual(s1, s2) {\n  return s1 >= s2;\n}\n/*** META ((export string-ci=?)\n\t   (type bool)\n           (peephole (hole 2 str1 \".toLowerCase() === \" str2 \".toLowerCase()\")))\n*/\nfunction sc_isStringCIEqual(s1, s2) {\n  return s1.toLowerCase() === s2.toLowerCase();\n}\n/*** META ((export string-ci<?)\n\t   (type bool)\n           (peephole (hole 2 str1 \".toLowerCase() < \" str2 \".toLowerCase()\")))\n*/\nfunction sc_isStringCILess(s1, s2) {\n  return s1.toLowerCase() < s2.toLowerCase();\n}\n/*** META ((export string-ci>?)\n\t   (type bool)\n           (peephole (hole 2 str1 \".toLowerCase() > \" str2 \".toLowerCase()\")))\n*/\nfunction sc_isStringCIGreater(s1, s2) {\n  return s1.toLowerCase() > s2.toLowerCase();\n}\n/*** META ((export string-ci<=?)\n\t   (type bool)\n           (peephole (hole 2 str1 \".toLowerCase() <= \" str2 \".toLowerCase()\")))\n*/\nfunction sc_isStringCILessEqual(s1, s2) {\n  return s1.toLowerCase() <= s2.toLowerCase();\n}\n/*** META ((export string-ci>=?)\n\t   (type bool)\n           (peephole (hole 2 str1 \".toLowerCase() >= \" str2 \".toLowerCase()\")))\n*/\nfunction sc_isStringCIGreaterEqual(s1, s2) {\n  return s1.toLowerCase() >= s2.toLowerCase();\n}\n\n/*** META ((export #t)\n           (peephole (hole 3 s \".substring(\" start \", \" end \")\")))\n*/\nfunction sc_substring(s, start, end) {\n  return s.substring(start, end);\n}\n\n/*** META ((export #t))\n */\nfunction sc_isSubstring_at(s1, s2, i) {\n  return s2 == s1.substring(i, i + s2.length);\n}\n\n/*** META ((export #t)\n           (peephole (infix 0 #f \"+\" \"''\")))\n*/\nfunction sc_stringAppend() {\n  return \"\".concat.apply(\"\", arguments);\n}\n\n/*** META ((export #t)) */\nvar sc_string2list = sc_jsstring2list;\n\n/*** META ((export #t)) */\nvar sc_list2string = sc_list2jsstring;\n\n/*** META ((export #t)\n           (peephole (id)))\n*/\nfunction sc_stringCopy(s) {\n  return s;\n}\n\n/* there's no string-fill in the immutable version\nfunction sc_stringFill(s, c)\n*/\n\n/*** META ((export #t)\n           (peephole (postfix \".slice(1)\")))\n*/\nfunction sc_keyword2string(o) {\n  return o.slice(1);\n}\n\n/*** META ((export #t)\n           (peephole (prefix \"'\\\\u1E9D' +\")))\n*/\nfunction sc_string2keyword(o) {\n  return sc_KEYWORD_PREFIX + o;\n}\n\nString.prototype.sc_toDisplayString = function () {\n  if (this.charAt(0) === sc_SYMBOL_PREFIX)\n    // TODO: care for symbols with spaces (escape-chars symbols).\n    return this.slice(1);\n  else if (this.charAt(0) === sc_KEYWORD_PREFIX) return \":\" + this.slice(1);\n  else return this.toString();\n};\n\nString.prototype.sc_toWriteString = function () {\n  if (this.charAt(0) === sc_SYMBOL_PREFIX)\n    // TODO: care for symbols with spaces (escape-chars symbols).\n    return this.slice(1);\n  else if (this.charAt(0) === sc_KEYWORD_PREFIX) return \":\" + this.slice(1);\n  else return '\"' + sc_escapeWriteString(this) + '\"';\n};\n/* Exported Variables */\nvar BgL_testzd2boyerzd2;\nvar BgL_nboyerzd2benchmarkzd2;\nvar BgL_setupzd2boyerzd2;\n/* End Exports */\n\nvar translate_term_nboyer;\nvar translate_args_nboyer;\nvar untranslate_term_nboyer;\nvar BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer;\nvar BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer;\nvar translate_alist_nboyer;\nvar apply_subst_nboyer;\nvar apply_subst_lst_nboyer;\nvar tautologyp_nboyer;\nvar if_constructor_nboyer;\nvar rewrite_count_nboyer;\nvar rewrite_nboyer;\nvar rewrite_args_nboyer;\nvar unify_subst_nboyer;\nvar one_way_unify1_nboyer;\nvar false_term_nboyer;\nvar true_term_nboyer;\nvar trans_of_implies1_nboyer;\nvar is_term_equal_nboyer;\nvar is_term_member_nboyer;\nvar const_nboyer;\nvar sc_const_3_nboyer;\nvar sc_const_4_nboyer;\n{\n  sc_const_4_nboyer = new sc_Pair(\n    \"\\u1E9Cimplies\",\n    new sc_Pair(\n      new sc_Pair(\n        \"\\u1E9Cand\",\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cimplies\",\n            new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n          ),\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cand\",\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cimplies\",\n                  new sc_Pair(\"\\u1E9Cy\", new sc_Pair(\"\\u1E9Cz\", null))\n                ),\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Cand\",\n                    new sc_Pair(\n                      new sc_Pair(\n                        \"\\u1E9Cimplies\",\n                        new sc_Pair(\"\\u1E9Cz\", new sc_Pair(\"\\u1E9Cu\", null))\n                      ),\n                      new sc_Pair(\n                        new sc_Pair(\n                          \"\\u1E9Cimplies\",\n                          new sc_Pair(\"\\u1E9Cu\", new sc_Pair(\"\\u1E9Cw\", null))\n                        ),\n                        null\n                      )\n                    )\n                  ),\n                  null\n                )\n              )\n            ),\n            null\n          )\n        )\n      ),\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cimplies\",\n          new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cw\", null))\n        ),\n        null\n      )\n    )\n  );\n  sc_const_3_nboyer = sc_list(\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\"\\u1E9Ccompile\", new sc_Pair(\"\\u1E9Cform\", null)),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Creverse\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Ccodegen\",\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Coptimize\",\n                    new sc_Pair(\"\\u1E9Cform\", null)\n                  ),\n                  new sc_Pair(new sc_Pair(\"\\u1E9Cnil\", null), null)\n                )\n              ),\n              null\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Ceqp\",\n          new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cequal\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Cfix\", new sc_Pair(\"\\u1E9Cx\", null)),\n              new sc_Pair(\n                new sc_Pair(\"\\u1E9Cfix\", new sc_Pair(\"\\u1E9Cy\", null)),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cgreaterp\",\n          new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Clessp\",\n            new sc_Pair(\"\\u1E9Cy\", new sc_Pair(\"\\u1E9Cx\", null))\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Clesseqp\",\n          new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cnot\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Clessp\",\n                new sc_Pair(\"\\u1E9Cy\", new sc_Pair(\"\\u1E9Cx\", null))\n              ),\n              null\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cgreatereqp\",\n          new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cnot\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Clessp\",\n                new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n              ),\n              null\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\"\\u1E9Cboolean\", new sc_Pair(\"\\u1E9Cx\", null)),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cor\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cequal\",\n                new sc_Pair(\n                  \"\\u1E9Cx\",\n                  new sc_Pair(new sc_Pair(\"\\u1E9Ct\", null), null)\n                )\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cequal\",\n                  new sc_Pair(\n                    \"\\u1E9Cx\",\n                    new sc_Pair(new sc_Pair(\"\\u1E9Cf\", null), null)\n                  )\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Ciff\",\n          new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cand\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cimplies\",\n                new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cimplies\",\n                  new sc_Pair(\"\\u1E9Cy\", new sc_Pair(\"\\u1E9Cx\", null))\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\"\\u1E9Ceven1\", new sc_Pair(\"\\u1E9Cx\", null)),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cif\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Czerop\", new sc_Pair(\"\\u1E9Cx\", null)),\n              new sc_Pair(\n                new sc_Pair(\"\\u1E9Ct\", null),\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Codd\",\n                    new sc_Pair(\n                      new sc_Pair(\"\\u1E9Csub1\", new sc_Pair(\"\\u1E9Cx\", null)),\n                      null\n                    )\n                  ),\n                  null\n                )\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Ccountps-\",\n          new sc_Pair(\"\\u1E9Cl\", new sc_Pair(\"\\u1E9Cpred\", null))\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Ccountps-loop\",\n            new sc_Pair(\n              \"\\u1E9Cl\",\n              new sc_Pair(\n                \"\\u1E9Cpred\",\n                new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\"\\u1E9Cfact-\", new sc_Pair(\"\\u1E9Ci\", null)),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cfact-loop\",\n            new sc_Pair(\"\\u1E9Ci\", new sc_Pair(1, null))\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\"\\u1E9Creverse-\", new sc_Pair(\"\\u1E9Cx\", null)),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Creverse-loop\",\n            new sc_Pair(\n              \"\\u1E9Cx\",\n              new sc_Pair(new sc_Pair(\"\\u1E9Cnil\", null), null)\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cdivides\",\n          new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Czerop\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cremainder\",\n                new sc_Pair(\"\\u1E9Cy\", new sc_Pair(\"\\u1E9Cx\", null))\n              ),\n              null\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cassume-true\",\n          new sc_Pair(\"\\u1E9Cvar\", new sc_Pair(\"\\u1E9Calist\", null))\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Ccons\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Ccons\",\n                new sc_Pair(\n                  \"\\u1E9Cvar\",\n                  new sc_Pair(new sc_Pair(\"\\u1E9Ct\", null), null)\n                )\n              ),\n              new sc_Pair(\"\\u1E9Calist\", null)\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cassume-false\",\n          new sc_Pair(\"\\u1E9Cvar\", new sc_Pair(\"\\u1E9Calist\", null))\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Ccons\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Ccons\",\n                new sc_Pair(\n                  \"\\u1E9Cvar\",\n                  new sc_Pair(new sc_Pair(\"\\u1E9Cf\", null), null)\n                )\n              ),\n              new sc_Pair(\"\\u1E9Calist\", null)\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\"\\u1E9Ctautology-checker\", new sc_Pair(\"\\u1E9Cx\", null)),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Ctautologyp\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Cnormalize\", new sc_Pair(\"\\u1E9Cx\", null)),\n              new sc_Pair(new sc_Pair(\"\\u1E9Cnil\", null), null)\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\"\\u1E9Cfalsify\", new sc_Pair(\"\\u1E9Cx\", null)),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cfalsify1\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Cnormalize\", new sc_Pair(\"\\u1E9Cx\", null)),\n              new sc_Pair(new sc_Pair(\"\\u1E9Cnil\", null), null)\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\"\\u1E9Cprime\", new sc_Pair(\"\\u1E9Cx\", null)),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cand\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cnot\",\n                new sc_Pair(\n                  new sc_Pair(\"\\u1E9Czerop\", new sc_Pair(\"\\u1E9Cx\", null)),\n                  null\n                )\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cnot\",\n                  new sc_Pair(\n                    new sc_Pair(\n                      \"\\u1E9Cequal\",\n                      new sc_Pair(\n                        \"\\u1E9Cx\",\n                        new sc_Pair(\n                          new sc_Pair(\n                            \"\\u1E9Cadd1\",\n                            new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n                          ),\n                          null\n                        )\n                      )\n                    ),\n                    null\n                  )\n                ),\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Cprime1\",\n                    new sc_Pair(\n                      \"\\u1E9Cx\",\n                      new sc_Pair(\n                        new sc_Pair(\"\\u1E9Csub1\", new sc_Pair(\"\\u1E9Cx\", null)),\n                        null\n                      )\n                    )\n                  ),\n                  null\n                )\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cand\",\n          new sc_Pair(\"\\u1E9Cp\", new sc_Pair(\"\\u1E9Cq\", null))\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cif\",\n            new sc_Pair(\n              \"\\u1E9Cp\",\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cif\",\n                  new sc_Pair(\n                    \"\\u1E9Cq\",\n                    new sc_Pair(\n                      new sc_Pair(\"\\u1E9Ct\", null),\n                      new sc_Pair(new sc_Pair(\"\\u1E9Cf\", null), null)\n                    )\n                  )\n                ),\n                new sc_Pair(new sc_Pair(\"\\u1E9Cf\", null), null)\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cor\",\n          new sc_Pair(\"\\u1E9Cp\", new sc_Pair(\"\\u1E9Cq\", null))\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cif\",\n            new sc_Pair(\n              \"\\u1E9Cp\",\n              new sc_Pair(\n                new sc_Pair(\"\\u1E9Ct\", null),\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Cif\",\n                    new sc_Pair(\n                      \"\\u1E9Cq\",\n                      new sc_Pair(\n                        new sc_Pair(\"\\u1E9Ct\", null),\n                        new sc_Pair(new sc_Pair(\"\\u1E9Cf\", null), null)\n                      )\n                    )\n                  ),\n                  null\n                )\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\"\\u1E9Cnot\", new sc_Pair(\"\\u1E9Cp\", null)),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cif\",\n            new sc_Pair(\n              \"\\u1E9Cp\",\n              new sc_Pair(\n                new sc_Pair(\"\\u1E9Cf\", null),\n                new sc_Pair(new sc_Pair(\"\\u1E9Ct\", null), null)\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cimplies\",\n          new sc_Pair(\"\\u1E9Cp\", new sc_Pair(\"\\u1E9Cq\", null))\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cif\",\n            new sc_Pair(\n              \"\\u1E9Cp\",\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cif\",\n                  new sc_Pair(\n                    \"\\u1E9Cq\",\n                    new sc_Pair(\n                      new sc_Pair(\"\\u1E9Ct\", null),\n                      new sc_Pair(new sc_Pair(\"\\u1E9Cf\", null), null)\n                    )\n                  )\n                ),\n                new sc_Pair(new sc_Pair(\"\\u1E9Ct\", null), null)\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\"\\u1E9Cfix\", new sc_Pair(\"\\u1E9Cx\", null)),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cif\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Cnumberp\", new sc_Pair(\"\\u1E9Cx\", null)),\n              new sc_Pair(\n                \"\\u1E9Cx\",\n                new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cif\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cif\",\n              new sc_Pair(\n                \"\\u1E9Ca\",\n                new sc_Pair(\"\\u1E9Cb\", new sc_Pair(\"\\u1E9Cc\", null))\n              )\n            ),\n            new sc_Pair(\"\\u1E9Cd\", new sc_Pair(\"\\u1E9Ce\", null))\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cif\",\n            new sc_Pair(\n              \"\\u1E9Ca\",\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cif\",\n                  new sc_Pair(\n                    \"\\u1E9Cb\",\n                    new sc_Pair(\"\\u1E9Cd\", new sc_Pair(\"\\u1E9Ce\", null))\n                  )\n                ),\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Cif\",\n                    new sc_Pair(\n                      \"\\u1E9Cc\",\n                      new sc_Pair(\"\\u1E9Cd\", new sc_Pair(\"\\u1E9Ce\", null))\n                    )\n                  ),\n                  null\n                )\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\"\\u1E9Czerop\", new sc_Pair(\"\\u1E9Cx\", null)),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cor\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cequal\",\n                new sc_Pair(\n                  \"\\u1E9Cx\",\n                  new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n                )\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cnot\",\n                  new sc_Pair(\n                    new sc_Pair(\"\\u1E9Cnumberp\", new sc_Pair(\"\\u1E9Cx\", null)),\n                    null\n                  )\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cplus\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cplus\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n            ),\n            new sc_Pair(\"\\u1E9Cz\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cplus\",\n            new sc_Pair(\n              \"\\u1E9Cx\",\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cplus\",\n                  new sc_Pair(\"\\u1E9Cy\", new sc_Pair(\"\\u1E9Cz\", null))\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cequal\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cplus\",\n              new sc_Pair(\"\\u1E9Ca\", new sc_Pair(\"\\u1E9Cb\", null))\n            ),\n            new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cand\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Czerop\", new sc_Pair(\"\\u1E9Ca\", null)),\n              new sc_Pair(\n                new sc_Pair(\"\\u1E9Czerop\", new sc_Pair(\"\\u1E9Cb\", null)),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cdifference\",\n          new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cx\", null))\n        ),\n        new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cequal\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cplus\",\n              new sc_Pair(\"\\u1E9Ca\", new sc_Pair(\"\\u1E9Cb\", null))\n            ),\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cplus\",\n                new sc_Pair(\"\\u1E9Ca\", new sc_Pair(\"\\u1E9Cc\", null))\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cequal\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Cfix\", new sc_Pair(\"\\u1E9Cb\", null)),\n              new sc_Pair(\n                new sc_Pair(\"\\u1E9Cfix\", new sc_Pair(\"\\u1E9Cc\", null)),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cequal\",\n          new sc_Pair(\n            new sc_Pair(\"\\u1E9Czero\", null),\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cdifference\",\n                new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cnot\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Clessp\",\n                new sc_Pair(\"\\u1E9Cy\", new sc_Pair(\"\\u1E9Cx\", null))\n              ),\n              null\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cequal\",\n          new sc_Pair(\n            \"\\u1E9Cx\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cdifference\",\n                new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cand\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Cnumberp\", new sc_Pair(\"\\u1E9Cx\", null)),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cor\",\n                  new sc_Pair(\n                    new sc_Pair(\n                      \"\\u1E9Cequal\",\n                      new sc_Pair(\n                        \"\\u1E9Cx\",\n                        new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n                      )\n                    ),\n                    new sc_Pair(\n                      new sc_Pair(\"\\u1E9Czerop\", new sc_Pair(\"\\u1E9Cy\", null)),\n                      null\n                    )\n                  )\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cmeaning\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cplus-tree\",\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cappend\",\n                  new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n                ),\n                null\n              )\n            ),\n            new sc_Pair(\"\\u1E9Ca\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cplus\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cmeaning\",\n                new sc_Pair(\n                  new sc_Pair(\"\\u1E9Cplus-tree\", new sc_Pair(\"\\u1E9Cx\", null)),\n                  new sc_Pair(\"\\u1E9Ca\", null)\n                )\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cmeaning\",\n                  new sc_Pair(\n                    new sc_Pair(\n                      \"\\u1E9Cplus-tree\",\n                      new sc_Pair(\"\\u1E9Cy\", null)\n                    ),\n                    new sc_Pair(\"\\u1E9Ca\", null)\n                  )\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cmeaning\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cplus-tree\",\n              new sc_Pair(\n                new sc_Pair(\"\\u1E9Cplus-fringe\", new sc_Pair(\"\\u1E9Cx\", null)),\n                null\n              )\n            ),\n            new sc_Pair(\"\\u1E9Ca\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cfix\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cmeaning\",\n                new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Ca\", null))\n              ),\n              null\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cappend\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cappend\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n            ),\n            new sc_Pair(\"\\u1E9Cz\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cappend\",\n            new sc_Pair(\n              \"\\u1E9Cx\",\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cappend\",\n                  new sc_Pair(\"\\u1E9Cy\", new sc_Pair(\"\\u1E9Cz\", null))\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Creverse\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cappend\",\n              new sc_Pair(\"\\u1E9Ca\", new sc_Pair(\"\\u1E9Cb\", null))\n            ),\n            null\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cappend\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Creverse\", new sc_Pair(\"\\u1E9Cb\", null)),\n              new sc_Pair(\n                new sc_Pair(\"\\u1E9Creverse\", new sc_Pair(\"\\u1E9Ca\", null)),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Ctimes\",\n          new sc_Pair(\n            \"\\u1E9Cx\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cplus\",\n                new sc_Pair(\"\\u1E9Cy\", new sc_Pair(\"\\u1E9Cz\", null))\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cplus\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Ctimes\",\n                new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Ctimes\",\n                  new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cz\", null))\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Ctimes\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Ctimes\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n            ),\n            new sc_Pair(\"\\u1E9Cz\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Ctimes\",\n            new sc_Pair(\n              \"\\u1E9Cx\",\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Ctimes\",\n                  new sc_Pair(\"\\u1E9Cy\", new sc_Pair(\"\\u1E9Cz\", null))\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cequal\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Ctimes\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n            ),\n            new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cor\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Czerop\", new sc_Pair(\"\\u1E9Cx\", null)),\n              new sc_Pair(\n                new sc_Pair(\"\\u1E9Czerop\", new sc_Pair(\"\\u1E9Cy\", null)),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cexec\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cappend\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n            ),\n            new sc_Pair(\"\\u1E9Cpds\", new sc_Pair(\"\\u1E9Cenvrn\", null))\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cexec\",\n            new sc_Pair(\n              \"\\u1E9Cy\",\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cexec\",\n                  new sc_Pair(\n                    \"\\u1E9Cx\",\n                    new sc_Pair(\"\\u1E9Cpds\", new sc_Pair(\"\\u1E9Cenvrn\", null))\n                  )\n                ),\n                new sc_Pair(\"\\u1E9Cenvrn\", null)\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cmc-flatten\",\n          new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cappend\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Cflatten\", new sc_Pair(\"\\u1E9Cx\", null)),\n              new sc_Pair(\"\\u1E9Cy\", null)\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cmember\",\n          new sc_Pair(\n            \"\\u1E9Cx\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cappend\",\n                new sc_Pair(\"\\u1E9Ca\", new sc_Pair(\"\\u1E9Cb\", null))\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cor\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cmember\",\n                new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Ca\", null))\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cmember\",\n                  new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cb\", null))\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cmember\",\n          new sc_Pair(\n            \"\\u1E9Cx\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Creverse\", new sc_Pair(\"\\u1E9Cy\", null)),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cmember\",\n            new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Clength\",\n          new sc_Pair(\n            new sc_Pair(\"\\u1E9Creverse\", new sc_Pair(\"\\u1E9Cx\", null)),\n            null\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\"\\u1E9Clength\", new sc_Pair(\"\\u1E9Cx\", null)),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cmember\",\n          new sc_Pair(\n            \"\\u1E9Ca\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cintersect\",\n                new sc_Pair(\"\\u1E9Cb\", new sc_Pair(\"\\u1E9Cc\", null))\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cand\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cmember\",\n                new sc_Pair(\"\\u1E9Ca\", new sc_Pair(\"\\u1E9Cb\", null))\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cmember\",\n                  new sc_Pair(\"\\u1E9Ca\", new sc_Pair(\"\\u1E9Cc\", null))\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cnth\",\n          new sc_Pair(\n            new sc_Pair(\"\\u1E9Czero\", null),\n            new sc_Pair(\"\\u1E9Ci\", null)\n          )\n        ),\n        new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cexp\",\n          new sc_Pair(\n            \"\\u1E9Ci\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cplus\",\n                new sc_Pair(\"\\u1E9Cj\", new sc_Pair(\"\\u1E9Ck\", null))\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Ctimes\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cexp\",\n                new sc_Pair(\"\\u1E9Ci\", new sc_Pair(\"\\u1E9Cj\", null))\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cexp\",\n                  new sc_Pair(\"\\u1E9Ci\", new sc_Pair(\"\\u1E9Ck\", null))\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cexp\",\n          new sc_Pair(\n            \"\\u1E9Ci\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Ctimes\",\n                new sc_Pair(\"\\u1E9Cj\", new sc_Pair(\"\\u1E9Ck\", null))\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cexp\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cexp\",\n                new sc_Pair(\"\\u1E9Ci\", new sc_Pair(\"\\u1E9Cj\", null))\n              ),\n              new sc_Pair(\"\\u1E9Ck\", null)\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Creverse-loop\",\n          new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cappend\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Creverse\", new sc_Pair(\"\\u1E9Cx\", null)),\n              new sc_Pair(\"\\u1E9Cy\", null)\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Creverse-loop\",\n          new sc_Pair(\n            \"\\u1E9Cx\",\n            new sc_Pair(new sc_Pair(\"\\u1E9Cnil\", null), null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\"\\u1E9Creverse\", new sc_Pair(\"\\u1E9Cx\", null)),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Ccount-list\",\n          new sc_Pair(\n            \"\\u1E9Cz\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Csort-lp\",\n                new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cplus\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Ccount-list\",\n                new sc_Pair(\"\\u1E9Cz\", new sc_Pair(\"\\u1E9Cx\", null))\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Ccount-list\",\n                  new sc_Pair(\"\\u1E9Cz\", new sc_Pair(\"\\u1E9Cy\", null))\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cequal\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cappend\",\n              new sc_Pair(\"\\u1E9Ca\", new sc_Pair(\"\\u1E9Cb\", null))\n            ),\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cappend\",\n                new sc_Pair(\"\\u1E9Ca\", new sc_Pair(\"\\u1E9Cc\", null))\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cequal\",\n            new sc_Pair(\"\\u1E9Cb\", new sc_Pair(\"\\u1E9Cc\", null))\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cplus\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cremainder\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n            ),\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Ctimes\",\n                new sc_Pair(\n                  \"\\u1E9Cy\",\n                  new sc_Pair(\n                    new sc_Pair(\n                      \"\\u1E9Cquotient\",\n                      new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n                    ),\n                    null\n                  )\n                )\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\"\\u1E9Cfix\", new sc_Pair(\"\\u1E9Cx\", null)),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cpower-eval\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cbig-plus1\",\n              new sc_Pair(\n                \"\\u1E9Cl\",\n                new sc_Pair(\"\\u1E9Ci\", new sc_Pair(\"\\u1E9Cbase\", null))\n              )\n            ),\n            new sc_Pair(\"\\u1E9Cbase\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cplus\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cpower-eval\",\n                new sc_Pair(\"\\u1E9Cl\", new sc_Pair(\"\\u1E9Cbase\", null))\n              ),\n              new sc_Pair(\"\\u1E9Ci\", null)\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cpower-eval\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cbig-plus\",\n              new sc_Pair(\n                \"\\u1E9Cx\",\n                new sc_Pair(\n                  \"\\u1E9Cy\",\n                  new sc_Pair(\"\\u1E9Ci\", new sc_Pair(\"\\u1E9Cbase\", null))\n                )\n              )\n            ),\n            new sc_Pair(\"\\u1E9Cbase\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cplus\",\n            new sc_Pair(\n              \"\\u1E9Ci\",\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cplus\",\n                  new sc_Pair(\n                    new sc_Pair(\n                      \"\\u1E9Cpower-eval\",\n                      new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cbase\", null))\n                    ),\n                    new sc_Pair(\n                      new sc_Pair(\n                        \"\\u1E9Cpower-eval\",\n                        new sc_Pair(\"\\u1E9Cy\", new sc_Pair(\"\\u1E9Cbase\", null))\n                      ),\n                      null\n                    )\n                  )\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cremainder\",\n          new sc_Pair(\"\\u1E9Cy\", new sc_Pair(1, null))\n        ),\n        new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Clessp\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cremainder\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n            ),\n            new sc_Pair(\"\\u1E9Cy\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cnot\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Czerop\", new sc_Pair(\"\\u1E9Cy\", null)),\n              null\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cremainder\",\n          new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cx\", null))\n        ),\n        new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Clessp\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cquotient\",\n              new sc_Pair(\"\\u1E9Ci\", new sc_Pair(\"\\u1E9Cj\", null))\n            ),\n            new sc_Pair(\"\\u1E9Ci\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cand\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cnot\",\n                new sc_Pair(\n                  new sc_Pair(\"\\u1E9Czerop\", new sc_Pair(\"\\u1E9Ci\", null)),\n                  null\n                )\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cor\",\n                  new sc_Pair(\n                    new sc_Pair(\"\\u1E9Czerop\", new sc_Pair(\"\\u1E9Cj\", null)),\n                    new sc_Pair(\n                      new sc_Pair(\n                        \"\\u1E9Cnot\",\n                        new sc_Pair(\n                          new sc_Pair(\n                            \"\\u1E9Cequal\",\n                            new sc_Pair(\"\\u1E9Cj\", new sc_Pair(1, null))\n                          ),\n                          null\n                        )\n                      ),\n                      null\n                    )\n                  )\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Clessp\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cremainder\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n            ),\n            new sc_Pair(\"\\u1E9Cx\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cand\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cnot\",\n                new sc_Pair(\n                  new sc_Pair(\"\\u1E9Czerop\", new sc_Pair(\"\\u1E9Cy\", null)),\n                  null\n                )\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cnot\",\n                  new sc_Pair(\n                    new sc_Pair(\"\\u1E9Czerop\", new sc_Pair(\"\\u1E9Cx\", null)),\n                    null\n                  )\n                ),\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Cnot\",\n                    new sc_Pair(\n                      new sc_Pair(\n                        \"\\u1E9Clessp\",\n                        new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n                      ),\n                      null\n                    )\n                  ),\n                  null\n                )\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cpower-eval\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cpower-rep\",\n              new sc_Pair(\"\\u1E9Ci\", new sc_Pair(\"\\u1E9Cbase\", null))\n            ),\n            new sc_Pair(\"\\u1E9Cbase\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\"\\u1E9Cfix\", new sc_Pair(\"\\u1E9Ci\", null)),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cpower-eval\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cbig-plus\",\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cpower-rep\",\n                  new sc_Pair(\"\\u1E9Ci\", new sc_Pair(\"\\u1E9Cbase\", null))\n                ),\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Cpower-rep\",\n                    new sc_Pair(\"\\u1E9Cj\", new sc_Pair(\"\\u1E9Cbase\", null))\n                  ),\n                  new sc_Pair(\n                    new sc_Pair(\"\\u1E9Czero\", null),\n                    new sc_Pair(\"\\u1E9Cbase\", null)\n                  )\n                )\n              )\n            ),\n            new sc_Pair(\"\\u1E9Cbase\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cplus\",\n            new sc_Pair(\"\\u1E9Ci\", new sc_Pair(\"\\u1E9Cj\", null))\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cgcd\",\n          new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cgcd\",\n            new sc_Pair(\"\\u1E9Cy\", new sc_Pair(\"\\u1E9Cx\", null))\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cnth\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cappend\",\n              new sc_Pair(\"\\u1E9Ca\", new sc_Pair(\"\\u1E9Cb\", null))\n            ),\n            new sc_Pair(\"\\u1E9Ci\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cappend\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cnth\",\n                new sc_Pair(\"\\u1E9Ca\", new sc_Pair(\"\\u1E9Ci\", null))\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cnth\",\n                  new sc_Pair(\n                    \"\\u1E9Cb\",\n                    new sc_Pair(\n                      new sc_Pair(\n                        \"\\u1E9Cdifference\",\n                        new sc_Pair(\n                          \"\\u1E9Ci\",\n                          new sc_Pair(\n                            new sc_Pair(\n                              \"\\u1E9Clength\",\n                              new sc_Pair(\"\\u1E9Ca\", null)\n                            ),\n                            null\n                          )\n                        )\n                      ),\n                      null\n                    )\n                  )\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cdifference\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cplus\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n            ),\n            new sc_Pair(\"\\u1E9Cx\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\"\\u1E9Cfix\", new sc_Pair(\"\\u1E9Cy\", null)),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cdifference\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cplus\",\n              new sc_Pair(\"\\u1E9Cy\", new sc_Pair(\"\\u1E9Cx\", null))\n            ),\n            new sc_Pair(\"\\u1E9Cx\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\"\\u1E9Cfix\", new sc_Pair(\"\\u1E9Cy\", null)),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cdifference\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cplus\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n            ),\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cplus\",\n                new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cz\", null))\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cdifference\",\n            new sc_Pair(\"\\u1E9Cy\", new sc_Pair(\"\\u1E9Cz\", null))\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Ctimes\",\n          new sc_Pair(\n            \"\\u1E9Cx\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cdifference\",\n                new sc_Pair(\"\\u1E9Cc\", new sc_Pair(\"\\u1E9Cw\", null))\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cdifference\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Ctimes\",\n                new sc_Pair(\"\\u1E9Cc\", new sc_Pair(\"\\u1E9Cx\", null))\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Ctimes\",\n                  new sc_Pair(\"\\u1E9Cw\", new sc_Pair(\"\\u1E9Cx\", null))\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cremainder\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Ctimes\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cz\", null))\n            ),\n            new sc_Pair(\"\\u1E9Cz\", null)\n          )\n        ),\n        new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cdifference\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cplus\",\n              new sc_Pair(\n                \"\\u1E9Cb\",\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Cplus\",\n                    new sc_Pair(\"\\u1E9Ca\", new sc_Pair(\"\\u1E9Cc\", null))\n                  ),\n                  null\n                )\n              )\n            ),\n            new sc_Pair(\"\\u1E9Ca\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cplus\",\n            new sc_Pair(\"\\u1E9Cb\", new sc_Pair(\"\\u1E9Cc\", null))\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cdifference\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cadd1\",\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cplus\",\n                  new sc_Pair(\"\\u1E9Cy\", new sc_Pair(\"\\u1E9Cz\", null))\n                ),\n                null\n              )\n            ),\n            new sc_Pair(\"\\u1E9Cz\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\"\\u1E9Cadd1\", new sc_Pair(\"\\u1E9Cy\", null)),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Clessp\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cplus\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n            ),\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cplus\",\n                new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cz\", null))\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Clessp\",\n            new sc_Pair(\"\\u1E9Cy\", new sc_Pair(\"\\u1E9Cz\", null))\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Clessp\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Ctimes\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cz\", null))\n            ),\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Ctimes\",\n                new sc_Pair(\"\\u1E9Cy\", new sc_Pair(\"\\u1E9Cz\", null))\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cand\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cnot\",\n                new sc_Pair(\n                  new sc_Pair(\"\\u1E9Czerop\", new sc_Pair(\"\\u1E9Cz\", null)),\n                  null\n                )\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Clessp\",\n                  new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Clessp\",\n          new sc_Pair(\n            \"\\u1E9Cy\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cplus\",\n                new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cnot\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Czerop\", new sc_Pair(\"\\u1E9Cx\", null)),\n              null\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cgcd\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Ctimes\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cz\", null))\n            ),\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Ctimes\",\n                new sc_Pair(\"\\u1E9Cy\", new sc_Pair(\"\\u1E9Cz\", null))\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Ctimes\",\n            new sc_Pair(\n              \"\\u1E9Cz\",\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cgcd\",\n                  new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cvalue\",\n          new sc_Pair(\n            new sc_Pair(\"\\u1E9Cnormalize\", new sc_Pair(\"\\u1E9Cx\", null)),\n            new sc_Pair(\"\\u1E9Ca\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cvalue\",\n            new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Ca\", null))\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cequal\",\n          new sc_Pair(\n            new sc_Pair(\"\\u1E9Cflatten\", new sc_Pair(\"\\u1E9Cx\", null)),\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Ccons\",\n                new sc_Pair(\n                  \"\\u1E9Cy\",\n                  new sc_Pair(new sc_Pair(\"\\u1E9Cnil\", null), null)\n                )\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cand\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Cnlistp\", new sc_Pair(\"\\u1E9Cx\", null)),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cequal\",\n                  new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Clistp\",\n          new sc_Pair(\n            new sc_Pair(\"\\u1E9Cgopher\", new sc_Pair(\"\\u1E9Cx\", null)),\n            null\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\"\\u1E9Clistp\", new sc_Pair(\"\\u1E9Cx\", null)),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Csamefringe\",\n          new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cequal\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Cflatten\", new sc_Pair(\"\\u1E9Cx\", null)),\n              new sc_Pair(\n                new sc_Pair(\"\\u1E9Cflatten\", new sc_Pair(\"\\u1E9Cy\", null)),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cequal\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cgreatest-factor\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n            ),\n            new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cand\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cor\",\n                new sc_Pair(\n                  new sc_Pair(\"\\u1E9Czerop\", new sc_Pair(\"\\u1E9Cy\", null)),\n                  new sc_Pair(\n                    new sc_Pair(\n                      \"\\u1E9Cequal\",\n                      new sc_Pair(\"\\u1E9Cy\", new sc_Pair(1, null))\n                    ),\n                    null\n                  )\n                )\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cequal\",\n                  new sc_Pair(\n                    \"\\u1E9Cx\",\n                    new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n                  )\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cequal\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cgreatest-factor\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n            ),\n            new sc_Pair(1, null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cequal\",\n            new sc_Pair(\"\\u1E9Cx\", new sc_Pair(1, null))\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cnumberp\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cgreatest-factor\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n            ),\n            null\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cnot\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cand\",\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Cor\",\n                    new sc_Pair(\n                      new sc_Pair(\"\\u1E9Czerop\", new sc_Pair(\"\\u1E9Cy\", null)),\n                      new sc_Pair(\n                        new sc_Pair(\n                          \"\\u1E9Cequal\",\n                          new sc_Pair(\"\\u1E9Cy\", new sc_Pair(1, null))\n                        ),\n                        null\n                      )\n                    )\n                  ),\n                  new sc_Pair(\n                    new sc_Pair(\n                      \"\\u1E9Cnot\",\n                      new sc_Pair(\n                        new sc_Pair(\n                          \"\\u1E9Cnumberp\",\n                          new sc_Pair(\"\\u1E9Cx\", null)\n                        ),\n                        null\n                      )\n                    ),\n                    null\n                  )\n                )\n              ),\n              null\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Ctimes-list\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cappend\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n            ),\n            null\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Ctimes\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Ctimes-list\", new sc_Pair(\"\\u1E9Cx\", null)),\n              new sc_Pair(\n                new sc_Pair(\"\\u1E9Ctimes-list\", new sc_Pair(\"\\u1E9Cy\", null)),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cprime-list\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cappend\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n            ),\n            null\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cand\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Cprime-list\", new sc_Pair(\"\\u1E9Cx\", null)),\n              new sc_Pair(\n                new sc_Pair(\"\\u1E9Cprime-list\", new sc_Pair(\"\\u1E9Cy\", null)),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cequal\",\n          new sc_Pair(\n            \"\\u1E9Cz\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Ctimes\",\n                new sc_Pair(\"\\u1E9Cw\", new sc_Pair(\"\\u1E9Cz\", null))\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cand\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Cnumberp\", new sc_Pair(\"\\u1E9Cz\", null)),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cor\",\n                  new sc_Pair(\n                    new sc_Pair(\n                      \"\\u1E9Cequal\",\n                      new sc_Pair(\n                        \"\\u1E9Cz\",\n                        new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n                      )\n                    ),\n                    new sc_Pair(\n                      new sc_Pair(\n                        \"\\u1E9Cequal\",\n                        new sc_Pair(\"\\u1E9Cw\", new sc_Pair(1, null))\n                      ),\n                      null\n                    )\n                  )\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cgreatereqp\",\n          new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cnot\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Clessp\",\n                new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n              ),\n              null\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cequal\",\n          new sc_Pair(\n            \"\\u1E9Cx\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Ctimes\",\n                new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cor\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cequal\",\n                new sc_Pair(\n                  \"\\u1E9Cx\",\n                  new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n                )\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cand\",\n                  new sc_Pair(\n                    new sc_Pair(\"\\u1E9Cnumberp\", new sc_Pair(\"\\u1E9Cx\", null)),\n                    new sc_Pair(\n                      new sc_Pair(\n                        \"\\u1E9Cequal\",\n                        new sc_Pair(\"\\u1E9Cy\", new sc_Pair(1, null))\n                      ),\n                      null\n                    )\n                  )\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cremainder\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Ctimes\",\n              new sc_Pair(\"\\u1E9Cy\", new sc_Pair(\"\\u1E9Cx\", null))\n            ),\n            new sc_Pair(\"\\u1E9Cy\", null)\n          )\n        ),\n        new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cequal\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Ctimes\",\n              new sc_Pair(\"\\u1E9Ca\", new sc_Pair(\"\\u1E9Cb\", null))\n            ),\n            new sc_Pair(1, null)\n          )\n        ),\n        new sc_Pair(\n          sc_list(\n            \"\\u1E9Cand\",\n            new sc_Pair(\n              \"\\u1E9Cnot\",\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cequal\",\n                  new sc_Pair(\n                    \"\\u1E9Ca\",\n                    new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n                  )\n                ),\n                null\n              )\n            ),\n            new sc_Pair(\n              \"\\u1E9Cnot\",\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cequal\",\n                  new sc_Pair(\n                    \"\\u1E9Cb\",\n                    new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n                  )\n                ),\n                null\n              )\n            ),\n            new sc_Pair(\"\\u1E9Cnumberp\", new sc_Pair(\"\\u1E9Ca\", null)),\n            new sc_Pair(\"\\u1E9Cnumberp\", new sc_Pair(\"\\u1E9Cb\", null)),\n            new sc_Pair(\n              \"\\u1E9Cequal\",\n              new sc_Pair(\n                new sc_Pair(\"\\u1E9Csub1\", new sc_Pair(\"\\u1E9Ca\", null)),\n                new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n              )\n            ),\n            new sc_Pair(\n              \"\\u1E9Cequal\",\n              new sc_Pair(\n                new sc_Pair(\"\\u1E9Csub1\", new sc_Pair(\"\\u1E9Cb\", null)),\n                new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Clessp\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Clength\",\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cdelete\",\n                  new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cl\", null))\n                ),\n                null\n              )\n            ),\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Clength\", new sc_Pair(\"\\u1E9Cl\", null)),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cmember\",\n            new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cl\", null))\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Csort2\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cdelete\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cl\", null))\n            ),\n            null\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cdelete\",\n            new sc_Pair(\n              \"\\u1E9Cx\",\n              new sc_Pair(\n                new sc_Pair(\"\\u1E9Csort2\", new sc_Pair(\"\\u1E9Cl\", null)),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\"\\u1E9Cdsort\", new sc_Pair(\"\\u1E9Cx\", null)),\n        new sc_Pair(\n          new sc_Pair(\"\\u1E9Csort2\", new sc_Pair(\"\\u1E9Cx\", null)),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Clength\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Ccons\",\n              new sc_Pair(\n                \"\\u1E9Cx1\",\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Ccons\",\n                    new sc_Pair(\n                      \"\\u1E9Cx2\",\n                      new sc_Pair(\n                        new sc_Pair(\n                          \"\\u1E9Ccons\",\n                          new sc_Pair(\n                            \"\\u1E9Cx3\",\n                            new sc_Pair(\n                              new sc_Pair(\n                                \"\\u1E9Ccons\",\n                                new sc_Pair(\n                                  \"\\u1E9Cx4\",\n                                  new sc_Pair(\n                                    new sc_Pair(\n                                      \"\\u1E9Ccons\",\n                                      new sc_Pair(\n                                        \"\\u1E9Cx5\",\n                                        new sc_Pair(\n                                          new sc_Pair(\n                                            \"\\u1E9Ccons\",\n                                            new sc_Pair(\n                                              \"\\u1E9Cx6\",\n                                              new sc_Pair(\"\\u1E9Cx7\", null)\n                                            )\n                                          ),\n                                          null\n                                        )\n                                      )\n                                    ),\n                                    null\n                                  )\n                                )\n                              ),\n                              null\n                            )\n                          )\n                        ),\n                        null\n                      )\n                    )\n                  ),\n                  null\n                )\n              )\n            ),\n            null\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cplus\",\n            new sc_Pair(\n              6,\n              new sc_Pair(\n                new sc_Pair(\"\\u1E9Clength\", new sc_Pair(\"\\u1E9Cx7\", null)),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cdifference\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cadd1\",\n              new sc_Pair(\n                new sc_Pair(\"\\u1E9Cadd1\", new sc_Pair(\"\\u1E9Cx\", null)),\n                null\n              )\n            ),\n            new sc_Pair(2, null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\"\\u1E9Cfix\", new sc_Pair(\"\\u1E9Cx\", null)),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cquotient\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cplus\",\n              new sc_Pair(\n                \"\\u1E9Cx\",\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Cplus\",\n                    new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n                  ),\n                  null\n                )\n              )\n            ),\n            new sc_Pair(2, null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cplus\",\n            new sc_Pair(\n              \"\\u1E9Cx\",\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cquotient\",\n                  new sc_Pair(\"\\u1E9Cy\", new sc_Pair(2, null))\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Csigma\",\n          new sc_Pair(\n            new sc_Pair(\"\\u1E9Czero\", null),\n            new sc_Pair(\"\\u1E9Ci\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cquotient\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Ctimes\",\n                new sc_Pair(\n                  \"\\u1E9Ci\",\n                  new sc_Pair(\n                    new sc_Pair(\"\\u1E9Cadd1\", new sc_Pair(\"\\u1E9Ci\", null)),\n                    null\n                  )\n                )\n              ),\n              new sc_Pair(2, null)\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cplus\",\n          new sc_Pair(\n            \"\\u1E9Cx\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Cadd1\", new sc_Pair(\"\\u1E9Cy\", null)),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cif\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Cnumberp\", new sc_Pair(\"\\u1E9Cy\", null)),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cadd1\",\n                  new sc_Pair(\n                    new sc_Pair(\n                      \"\\u1E9Cplus\",\n                      new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n                    ),\n                    null\n                  )\n                ),\n                new sc_Pair(\n                  new sc_Pair(\"\\u1E9Cadd1\", new sc_Pair(\"\\u1E9Cx\", null)),\n                  null\n                )\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cequal\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cdifference\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n            ),\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cdifference\",\n                new sc_Pair(\"\\u1E9Cz\", new sc_Pair(\"\\u1E9Cy\", null))\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cif\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Clessp\",\n                new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cnot\",\n                  new sc_Pair(\n                    new sc_Pair(\n                      \"\\u1E9Clessp\",\n                      new sc_Pair(\"\\u1E9Cy\", new sc_Pair(\"\\u1E9Cz\", null))\n                    ),\n                    null\n                  )\n                ),\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Cif\",\n                    new sc_Pair(\n                      new sc_Pair(\n                        \"\\u1E9Clessp\",\n                        new sc_Pair(\"\\u1E9Cz\", new sc_Pair(\"\\u1E9Cy\", null))\n                      ),\n                      new sc_Pair(\n                        new sc_Pair(\n                          \"\\u1E9Cnot\",\n                          new sc_Pair(\n                            new sc_Pair(\n                              \"\\u1E9Clessp\",\n                              new sc_Pair(\n                                \"\\u1E9Cy\",\n                                new sc_Pair(\"\\u1E9Cx\", null)\n                              )\n                            ),\n                            null\n                          )\n                        ),\n                        new sc_Pair(\n                          new sc_Pair(\n                            \"\\u1E9Cequal\",\n                            new sc_Pair(\n                              new sc_Pair(\n                                \"\\u1E9Cfix\",\n                                new sc_Pair(\"\\u1E9Cx\", null)\n                              ),\n                              new sc_Pair(\n                                new sc_Pair(\n                                  \"\\u1E9Cfix\",\n                                  new sc_Pair(\"\\u1E9Cz\", null)\n                                ),\n                                null\n                              )\n                            )\n                          ),\n                          null\n                        )\n                      )\n                    )\n                  ),\n                  null\n                )\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cmeaning\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cplus-tree\",\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cdelete\",\n                  new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n                ),\n                null\n              )\n            ),\n            new sc_Pair(\"\\u1E9Ca\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cif\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cmember\",\n                new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cdifference\",\n                  new sc_Pair(\n                    new sc_Pair(\n                      \"\\u1E9Cmeaning\",\n                      new sc_Pair(\n                        new sc_Pair(\n                          \"\\u1E9Cplus-tree\",\n                          new sc_Pair(\"\\u1E9Cy\", null)\n                        ),\n                        new sc_Pair(\"\\u1E9Ca\", null)\n                      )\n                    ),\n                    new sc_Pair(\n                      new sc_Pair(\n                        \"\\u1E9Cmeaning\",\n                        new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Ca\", null))\n                      ),\n                      null\n                    )\n                  )\n                ),\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Cmeaning\",\n                    new sc_Pair(\n                      new sc_Pair(\n                        \"\\u1E9Cplus-tree\",\n                        new sc_Pair(\"\\u1E9Cy\", null)\n                      ),\n                      new sc_Pair(\"\\u1E9Ca\", null)\n                    )\n                  ),\n                  null\n                )\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Ctimes\",\n          new sc_Pair(\n            \"\\u1E9Cx\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Cadd1\", new sc_Pair(\"\\u1E9Cy\", null)),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cif\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Cnumberp\", new sc_Pair(\"\\u1E9Cy\", null)),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cplus\",\n                  new sc_Pair(\n                    \"\\u1E9Cx\",\n                    new sc_Pair(\n                      new sc_Pair(\n                        \"\\u1E9Ctimes\",\n                        new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n                      ),\n                      null\n                    )\n                  )\n                ),\n                new sc_Pair(\n                  new sc_Pair(\"\\u1E9Cfix\", new sc_Pair(\"\\u1E9Cx\", null)),\n                  null\n                )\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cnth\",\n          new sc_Pair(\n            new sc_Pair(\"\\u1E9Cnil\", null),\n            new sc_Pair(\"\\u1E9Ci\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cif\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Czerop\", new sc_Pair(\"\\u1E9Ci\", null)),\n              new sc_Pair(\n                new sc_Pair(\"\\u1E9Cnil\", null),\n                new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Clast\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cappend\",\n              new sc_Pair(\"\\u1E9Ca\", new sc_Pair(\"\\u1E9Cb\", null))\n            ),\n            null\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cif\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Clistp\", new sc_Pair(\"\\u1E9Cb\", null)),\n              new sc_Pair(\n                new sc_Pair(\"\\u1E9Clast\", new sc_Pair(\"\\u1E9Cb\", null)),\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Cif\",\n                    new sc_Pair(\n                      new sc_Pair(\"\\u1E9Clistp\", new sc_Pair(\"\\u1E9Ca\", null)),\n                      new sc_Pair(\n                        new sc_Pair(\n                          \"\\u1E9Ccons\",\n                          new sc_Pair(\n                            new sc_Pair(\n                              \"\\u1E9Ccar\",\n                              new sc_Pair(\n                                new sc_Pair(\n                                  \"\\u1E9Clast\",\n                                  new sc_Pair(\"\\u1E9Ca\", null)\n                                ),\n                                null\n                              )\n                            ),\n                            new sc_Pair(\"\\u1E9Cb\", null)\n                          )\n                        ),\n                        new sc_Pair(\"\\u1E9Cb\", null)\n                      )\n                    )\n                  ),\n                  null\n                )\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cequal\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Clessp\",\n              new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n            ),\n            new sc_Pair(\"\\u1E9Cz\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cif\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Clessp\",\n                new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cequal\",\n                  new sc_Pair(\n                    new sc_Pair(\"\\u1E9Ct\", null),\n                    new sc_Pair(\"\\u1E9Cz\", null)\n                  )\n                ),\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Cequal\",\n                    new sc_Pair(\n                      new sc_Pair(\"\\u1E9Cf\", null),\n                      new sc_Pair(\"\\u1E9Cz\", null)\n                    )\n                  ),\n                  null\n                )\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cassignment\",\n          new sc_Pair(\n            \"\\u1E9Cx\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cappend\",\n                new sc_Pair(\"\\u1E9Ca\", new sc_Pair(\"\\u1E9Cb\", null))\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cif\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cassignedp\",\n                new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Ca\", null))\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cassignment\",\n                  new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Ca\", null))\n                ),\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Cassignment\",\n                    new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cb\", null))\n                  ),\n                  null\n                )\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Ccar\",\n          new sc_Pair(\n            new sc_Pair(\"\\u1E9Cgopher\", new sc_Pair(\"\\u1E9Cx\", null)),\n            null\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cif\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Clistp\", new sc_Pair(\"\\u1E9Cx\", null)),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Ccar\",\n                  new sc_Pair(\n                    new sc_Pair(\"\\u1E9Cflatten\", new sc_Pair(\"\\u1E9Cx\", null)),\n                    null\n                  )\n                ),\n                new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cflatten\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Ccdr\",\n              new sc_Pair(\n                new sc_Pair(\"\\u1E9Cgopher\", new sc_Pair(\"\\u1E9Cx\", null)),\n                null\n              )\n            ),\n            null\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cif\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Clistp\", new sc_Pair(\"\\u1E9Cx\", null)),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Ccdr\",\n                  new sc_Pair(\n                    new sc_Pair(\"\\u1E9Cflatten\", new sc_Pair(\"\\u1E9Cx\", null)),\n                    null\n                  )\n                ),\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Ccons\",\n                    new sc_Pair(\n                      new sc_Pair(\"\\u1E9Czero\", null),\n                      new sc_Pair(new sc_Pair(\"\\u1E9Cnil\", null), null)\n                    )\n                  ),\n                  null\n                )\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cquotient\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Ctimes\",\n              new sc_Pair(\"\\u1E9Cy\", new sc_Pair(\"\\u1E9Cx\", null))\n            ),\n            new sc_Pair(\"\\u1E9Cy\", null)\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cif\",\n            new sc_Pair(\n              new sc_Pair(\"\\u1E9Czerop\", new sc_Pair(\"\\u1E9Cy\", null)),\n              new sc_Pair(\n                new sc_Pair(\"\\u1E9Czero\", null),\n                new sc_Pair(\n                  new sc_Pair(\"\\u1E9Cfix\", new sc_Pair(\"\\u1E9Cx\", null)),\n                  null\n                )\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      \"\\u1E9Cequal\",\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cget\",\n          new sc_Pair(\n            \"\\u1E9Cj\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cset\",\n                new sc_Pair(\n                  \"\\u1E9Ci\",\n                  new sc_Pair(\"\\u1E9Cval\", new sc_Pair(\"\\u1E9Cmem\", null))\n                )\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cif\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Ceqp\",\n                new sc_Pair(\"\\u1E9Cj\", new sc_Pair(\"\\u1E9Ci\", null))\n              ),\n              new sc_Pair(\n                \"\\u1E9Cval\",\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Cget\",\n                    new sc_Pair(\"\\u1E9Cj\", new sc_Pair(\"\\u1E9Cmem\", null))\n                  ),\n                  null\n                )\n              )\n            )\n          ),\n          null\n        )\n      )\n    )\n  );\n  const_nboyer = new sc_Pair(\n    new sc_Pair(\n      \"\\u1E9Cx\",\n      new sc_Pair(\n        \"\\u1E9Cf\",\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cplus\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Cplus\",\n                new sc_Pair(\"\\u1E9Ca\", new sc_Pair(\"\\u1E9Cb\", null))\n              ),\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cplus\",\n                  new sc_Pair(\n                    \"\\u1E9Cc\",\n                    new sc_Pair(new sc_Pair(\"\\u1E9Czero\", null), null)\n                  )\n                ),\n                null\n              )\n            )\n          ),\n          null\n        )\n      )\n    ),\n    new sc_Pair(\n      new sc_Pair(\n        \"\\u1E9Cy\",\n        new sc_Pair(\n          \"\\u1E9Cf\",\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Ctimes\",\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Ctimes\",\n                  new sc_Pair(\"\\u1E9Ca\", new sc_Pair(\"\\u1E9Cb\", null))\n                ),\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Cplus\",\n                    new sc_Pair(\"\\u1E9Cc\", new sc_Pair(\"\\u1E9Cd\", null))\n                  ),\n                  null\n                )\n              )\n            ),\n            null\n          )\n        )\n      ),\n      new sc_Pair(\n        new sc_Pair(\n          \"\\u1E9Cz\",\n          new sc_Pair(\n            \"\\u1E9Cf\",\n            new sc_Pair(\n              new sc_Pair(\n                \"\\u1E9Creverse\",\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Cappend\",\n                    new sc_Pair(\n                      new sc_Pair(\n                        \"\\u1E9Cappend\",\n                        new sc_Pair(\"\\u1E9Ca\", new sc_Pair(\"\\u1E9Cb\", null))\n                      ),\n                      new sc_Pair(new sc_Pair(\"\\u1E9Cnil\", null), null)\n                    )\n                  ),\n                  null\n                )\n              ),\n              null\n            )\n          )\n        ),\n        new sc_Pair(\n          new sc_Pair(\n            \"\\u1E9Cu\",\n            new sc_Pair(\n              \"\\u1E9Cequal\",\n              new sc_Pair(\n                new sc_Pair(\n                  \"\\u1E9Cplus\",\n                  new sc_Pair(\"\\u1E9Ca\", new sc_Pair(\"\\u1E9Cb\", null))\n                ),\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Cdifference\",\n                    new sc_Pair(\"\\u1E9Cx\", new sc_Pair(\"\\u1E9Cy\", null))\n                  ),\n                  null\n                )\n              )\n            )\n          ),\n          new sc_Pair(\n            new sc_Pair(\n              \"\\u1E9Cw\",\n              new sc_Pair(\n                \"\\u1E9Clessp\",\n                new sc_Pair(\n                  new sc_Pair(\n                    \"\\u1E9Cremainder\",\n                    new sc_Pair(\"\\u1E9Ca\", new sc_Pair(\"\\u1E9Cb\", null))\n                  ),\n                  new sc_Pair(\n                    new sc_Pair(\n                      \"\\u1E9Cmember\",\n                      new sc_Pair(\n                        \"\\u1E9Ca\",\n                        new sc_Pair(\n                          new sc_Pair(\n                            \"\\u1E9Clength\",\n                            new sc_Pair(\"\\u1E9Cb\", null)\n                          ),\n                          null\n                        )\n                      )\n                    ),\n                    null\n                  )\n                )\n              )\n            ),\n            null\n          )\n        )\n      )\n    )\n  );\n  BgL_nboyerzd2benchmarkzd2 = function () {\n    var args = null;\n    for (var sc_tmp = arguments.length - 1; sc_tmp >= 0; sc_tmp--) {\n      args = sc_cons(arguments[sc_tmp], args);\n    }\n    var n;\n    return (\n      (n = args === null ? 0 : args.car),\n      BgL_setupzd2boyerzd2(),\n      BgL_runzd2benchmarkzd2(\n        \"nboyer\" + sc_number2string(n),\n        1,\n        function () {\n          return BgL_testzd2boyerzd2(n);\n        },\n        function (rewrites) {\n          if (sc_isNumber(rewrites))\n            switch (n) {\n              case 0:\n                return rewrites === 95024;\n                break;\n              case 1:\n                return rewrites === 591777;\n                break;\n              case 2:\n                return rewrites === 1813975;\n                break;\n              case 3:\n                return rewrites === 5375678;\n                break;\n              case 4:\n                return rewrites === 16445406;\n                break;\n              case 5:\n                return rewrites === 51507739;\n                break;\n              default:\n                return true;\n                break;\n            }\n          else return false;\n        }\n      )\n    );\n  };\n  BgL_setupzd2boyerzd2 = function () {\n    return true;\n  };\n  BgL_testzd2boyerzd2 = function () {\n    return true;\n  };\n  translate_term_nboyer = function (term) {\n    var lst;\n    return !(term instanceof sc_Pair)\n      ? term\n      : new sc_Pair(\n          BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer(term.car),\n          ((lst = term.cdr),\n          lst === null\n            ? null\n            : new sc_Pair(\n                translate_term_nboyer(lst.car),\n                translate_args_nboyer(lst.cdr)\n              ))\n        );\n  };\n  translate_args_nboyer = function (lst) {\n    var sc_lst_5;\n    var term;\n    return lst === null\n      ? null\n      : new sc_Pair(\n          ((term = lst.car),\n          !(term instanceof sc_Pair)\n            ? term\n            : new sc_Pair(\n                BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer(term.car),\n                translate_args_nboyer(term.cdr)\n              )),\n          ((sc_lst_5 = lst.cdr),\n          sc_lst_5 === null\n            ? null\n            : new sc_Pair(\n                translate_term_nboyer(sc_lst_5.car),\n                translate_args_nboyer(sc_lst_5.cdr)\n              ))\n        );\n  };\n  untranslate_term_nboyer = function (term) {\n    var optrOpnd;\n    var tail1131;\n    var L1127;\n    var falseHead1130;\n    var symbol_record;\n    if (!(term instanceof sc_Pair)) return term;\n    else {\n      falseHead1130 = new sc_Pair(null, null);\n      L1127 = term.cdr;\n      tail1131 = falseHead1130;\n      while (!(L1127 === null)) {\n        {\n          tail1131.cdr = new sc_Pair(untranslate_term_nboyer(L1127.car), null);\n          tail1131 = tail1131.cdr;\n          L1127 = L1127.cdr;\n        }\n      }\n      optrOpnd = falseHead1130.cdr;\n      return new sc_Pair(\n        ((symbol_record = term.car), symbol_record[0]),\n        optrOpnd\n      );\n    }\n  };\n  BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer = function (sym) {\n    var r;\n    var x;\n    return (\n      (x = sc_assq(sym, BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer)),\n      x !== false\n        ? x.cdr\n        : ((r = [sym, null]),\n          (BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer = new sc_Pair(\n            new sc_Pair(sym, r),\n            BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer\n          )),\n          r)\n    );\n  };\n  BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer = null;\n  translate_alist_nboyer = function (alist) {\n    var sc_alist_6;\n    var term;\n    return alist === null\n      ? null\n      : new sc_Pair(\n          new sc_Pair(\n            alist.car.car,\n            ((term = alist.car.cdr),\n            !(term instanceof sc_Pair)\n              ? term\n              : new sc_Pair(\n                  BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer(term.car),\n                  translate_args_nboyer(term.cdr)\n                ))\n          ),\n          ((sc_alist_6 = alist.cdr),\n          sc_alist_6 === null\n            ? null\n            : new sc_Pair(\n                new sc_Pair(\n                  sc_alist_6.car.car,\n                  translate_term_nboyer(sc_alist_6.car.cdr)\n                ),\n                translate_alist_nboyer(sc_alist_6.cdr)\n              ))\n        );\n  };\n  apply_subst_nboyer = function (alist, term) {\n    var lst;\n    var temp_temp;\n    return !(term instanceof sc_Pair)\n      ? ((temp_temp = sc_assq(term, alist)),\n        temp_temp !== false ? temp_temp.cdr : term)\n      : new sc_Pair(\n          term.car,\n          ((lst = term.cdr),\n          lst === null\n            ? null\n            : new sc_Pair(\n                apply_subst_nboyer(alist, lst.car),\n                apply_subst_lst_nboyer(alist, lst.cdr)\n              ))\n        );\n  };\n  apply_subst_lst_nboyer = function (alist, lst) {\n    var sc_lst_7;\n    return lst === null\n      ? null\n      : new sc_Pair(\n          apply_subst_nboyer(alist, lst.car),\n          ((sc_lst_7 = lst.cdr),\n          sc_lst_7 === null\n            ? null\n            : new sc_Pair(\n                apply_subst_nboyer(alist, sc_lst_7.car),\n                apply_subst_lst_nboyer(alist, sc_lst_7.cdr)\n              ))\n        );\n  };\n  tautologyp_nboyer = function (sc_x_11, true_lst, false_lst) {\n    var tmp1125;\n    var x;\n    var tmp1126;\n    var sc_x_8;\n    var sc_tmp1125_9;\n    var sc_tmp1126_10;\n    var sc_x_11;\n    var true_lst;\n    var false_lst;\n    while (true) {\n      if (\n        ((sc_tmp1126_10 = is_term_equal_nboyer(sc_x_11, true_term_nboyer)),\n        sc_tmp1126_10 !== false\n          ? sc_tmp1126_10\n          : is_term_member_nboyer(sc_x_11, true_lst)) !== false\n      )\n        return true;\n      else if (\n        ((sc_tmp1125_9 = is_term_equal_nboyer(sc_x_11, false_term_nboyer)),\n        sc_tmp1125_9 !== false\n          ? sc_tmp1125_9\n          : is_term_member_nboyer(sc_x_11, false_lst)) !== false\n      )\n        return false;\n      else if (!(sc_x_11 instanceof sc_Pair)) return false;\n      else if (sc_x_11.car === if_constructor_nboyer)\n        if (\n          ((sc_x_8 = sc_x_11.cdr.car),\n          (tmp1126 = is_term_equal_nboyer(sc_x_8, true_term_nboyer)),\n          tmp1126 !== false\n            ? tmp1126\n            : is_term_member_nboyer(sc_x_8, true_lst)) !== false\n        )\n          sc_x_11 = sc_x_11.cdr.cdr.car;\n        else if (\n          ((x = sc_x_11.cdr.car),\n          (tmp1125 = is_term_equal_nboyer(x, false_term_nboyer)),\n          tmp1125 !== false ? tmp1125 : is_term_member_nboyer(x, false_lst)) !==\n          false\n        )\n          sc_x_11 = sc_x_11.cdr.cdr.cdr.car;\n        else if (\n          tautologyp_nboyer(\n            sc_x_11.cdr.cdr.car,\n            new sc_Pair(sc_x_11.cdr.car, true_lst),\n            false_lst\n          ) !== false\n        ) {\n          false_lst = new sc_Pair(sc_x_11.cdr.car, false_lst);\n          sc_x_11 = sc_x_11.cdr.cdr.cdr.car;\n        } else return false;\n      else return false;\n    }\n  };\n  if_constructor_nboyer = \"\\u1E9C*\";\n  rewrite_count_nboyer = 0;\n  rewrite_nboyer = function (term) {\n    var term2;\n    var sc_term_12;\n    var lst;\n    var symbol_record;\n    var sc_lst_13;\n    {\n      ++rewrite_count_nboyer;\n      if (!(term instanceof sc_Pair)) return term;\n      else {\n        sc_term_12 = new sc_Pair(\n          term.car,\n          ((sc_lst_13 = term.cdr),\n          sc_lst_13 === null\n            ? null\n            : new sc_Pair(\n                rewrite_nboyer(sc_lst_13.car),\n                rewrite_args_nboyer(sc_lst_13.cdr)\n              ))\n        );\n        lst = ((symbol_record = term.car), symbol_record[1]);\n        while (true) {\n          if (lst === null) return sc_term_12;\n          else if (\n            ((term2 = lst.car.cdr.car),\n            (unify_subst_nboyer = null),\n            one_way_unify1_nboyer(sc_term_12, term2)) !== false\n          )\n            return rewrite_nboyer(\n              apply_subst_nboyer(unify_subst_nboyer, lst.car.cdr.cdr.car)\n            );\n          else lst = lst.cdr;\n        }\n      }\n    }\n  };\n  rewrite_args_nboyer = function (lst) {\n    var sc_lst_14;\n    return lst === null\n      ? null\n      : new sc_Pair(\n          rewrite_nboyer(lst.car),\n          ((sc_lst_14 = lst.cdr),\n          sc_lst_14 === null\n            ? null\n            : new sc_Pair(\n                rewrite_nboyer(sc_lst_14.car),\n                rewrite_args_nboyer(sc_lst_14.cdr)\n              ))\n        );\n  };\n  unify_subst_nboyer = \"\\u1E9C*\";\n  one_way_unify1_nboyer = function (term1, term2) {\n    var lst1;\n    var lst2;\n    var temp_temp;\n    if (!(term2 instanceof sc_Pair)) {\n      temp_temp = sc_assq(term2, unify_subst_nboyer);\n      if (temp_temp !== false)\n        return is_term_equal_nboyer(term1, temp_temp.cdr);\n      else if (sc_isNumber(term2)) return sc_isEqual(term1, term2);\n      else {\n        unify_subst_nboyer = new sc_Pair(\n          new sc_Pair(term2, term1),\n          unify_subst_nboyer\n        );\n        return true;\n      }\n    } else if (!(term1 instanceof sc_Pair)) return false;\n    else if (term1.car === term2.car) {\n      lst1 = term1.cdr;\n      lst2 = term2.cdr;\n      while (true) {\n        if (lst1 === null) return lst2 === null;\n        else if (lst2 === null) return false;\n        else if (one_way_unify1_nboyer(lst1.car, lst2.car) !== false) {\n          lst1 = lst1.cdr;\n          lst2 = lst2.cdr;\n        } else return false;\n      }\n    } else return false;\n  };\n  false_term_nboyer = \"\\u1E9C*\";\n  true_term_nboyer = \"\\u1E9C*\";\n  trans_of_implies1_nboyer = function (n) {\n    var sc_n_15;\n    return sc_isEqual(n, 1)\n      ? sc_list(\"\\u1E9Cimplies\", 0, 1)\n      : sc_list(\n          \"\\u1E9Cand\",\n          sc_list(\"\\u1E9Cimplies\", n - 1, n),\n          ((sc_n_15 = n - 1),\n          sc_isEqual(sc_n_15, 1)\n            ? sc_list(\"\\u1E9Cimplies\", 0, 1)\n            : sc_list(\n                \"\\u1E9Cand\",\n                sc_list(\"\\u1E9Cimplies\", sc_n_15 - 1, sc_n_15),\n                trans_of_implies1_nboyer(sc_n_15 - 1)\n              ))\n        );\n  };\n  is_term_equal_nboyer = function (x, y) {\n    var lst1;\n    var lst2;\n    var r2;\n    var r1;\n    if (x instanceof sc_Pair)\n      if (y instanceof sc_Pair)\n        if (((r1 = x.car), (r2 = y.car), r1 === r2) !== false) {\n          lst1 = x.cdr;\n          lst2 = y.cdr;\n          while (true) {\n            if (lst1 === null) return lst2 === null;\n            else if (lst2 === null) return false;\n            else if (is_term_equal_nboyer(lst1.car, lst2.car) !== false) {\n              lst1 = lst1.cdr;\n              lst2 = lst2.cdr;\n            } else return false;\n          }\n        } else return false;\n      else return false;\n    else return sc_isEqual(x, y);\n  };\n  is_term_member_nboyer = function (x, lst) {\n    var x;\n    var lst;\n    while (true) {\n      if (lst === null) return false;\n      else if (is_term_equal_nboyer(x, lst.car) !== false) return true;\n      else lst = lst.cdr;\n    }\n  };\n  BgL_setupzd2boyerzd2 = function () {\n    var symbol_record;\n    var value;\n    var BgL_sc_symbolzd2record_16zd2;\n    var sym;\n    var sc_sym_17;\n    var term;\n    var lst;\n    var sc_term_18;\n    var sc_term_19;\n    {\n      BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer = null;\n      if_constructor_nboyer =\n        BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer(\"\\u1E9Cif\");\n      false_term_nboyer =\n        ((sc_term_19 = new sc_Pair(\"\\u1E9Cf\", null)),\n        !(sc_term_19 instanceof sc_Pair)\n          ? sc_term_19\n          : new sc_Pair(\n              BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer(sc_term_19.car),\n              translate_args_nboyer(sc_term_19.cdr)\n            ));\n      true_term_nboyer =\n        ((sc_term_18 = new sc_Pair(\"\\u1E9Ct\", null)),\n        !(sc_term_18 instanceof sc_Pair)\n          ? sc_term_18\n          : new sc_Pair(\n              BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer(sc_term_18.car),\n              translate_args_nboyer(sc_term_18.cdr)\n            ));\n      lst = sc_const_3_nboyer;\n      while (!(lst === null)) {\n        {\n          term = lst.car;\n          if (\n            term instanceof sc_Pair &&\n            term.car === \"\\u1E9Cequal\" &&\n            term.cdr.car instanceof sc_Pair\n          ) {\n            sc_sym_17 = term.cdr.car.car;\n            value = new sc_Pair(\n              !(term instanceof sc_Pair)\n                ? term\n                : new sc_Pair(\n                    BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer(term.car),\n                    translate_args_nboyer(term.cdr)\n                  ),\n              ((sym = term.cdr.car.car),\n              (BgL_sc_symbolzd2record_16zd2 =\n                BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer(sym)),\n              BgL_sc_symbolzd2record_16zd2[1])\n            );\n            symbol_record =\n              BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer(sc_sym_17);\n            symbol_record[1] = value;\n          } else sc_error(\"ADD-LEMMA did not like term:  \", term);\n          lst = lst.cdr;\n        }\n      }\n      return true;\n    }\n  };\n  BgL_testzd2boyerzd2 = function (n) {\n    var optrOpnd;\n    var term;\n    var sc_n_20;\n    var answer;\n    var sc_term_21;\n    var sc_term_22;\n    {\n      rewrite_count_nboyer = 0;\n      term = sc_const_4_nboyer;\n      sc_n_20 = n;\n      while (!(sc_n_20 === 0)) {\n        {\n          term = sc_list(\"\\u1E9Cor\", term, new sc_Pair(\"\\u1E9Cf\", null));\n          --sc_n_20;\n        }\n      }\n      sc_term_22 = term;\n      if (!(sc_term_22 instanceof sc_Pair)) optrOpnd = sc_term_22;\n      else\n        optrOpnd = new sc_Pair(\n          BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer(sc_term_22.car),\n          translate_args_nboyer(sc_term_22.cdr)\n        );\n      sc_term_21 = apply_subst_nboyer(\n        const_nboyer === null\n          ? null\n          : new sc_Pair(\n              new sc_Pair(\n                const_nboyer.car.car,\n                translate_term_nboyer(const_nboyer.car.cdr)\n              ),\n              translate_alist_nboyer(const_nboyer.cdr)\n            ),\n        optrOpnd\n      );\n      answer = tautologyp_nboyer(rewrite_nboyer(sc_term_21), null, null);\n      sc_write(rewrite_count_nboyer);\n      sc_display(\" rewrites\");\n      sc_newline();\n      if (answer !== false) return rewrite_count_nboyer;\n      else return false;\n    }\n  };\n}\n/* Exported Variables */\nvar BgL_parsezd2ze3nbzd2treesze3;\nvar BgL_earleyzd2benchmarkzd2;\nvar BgL_parsezd2ze3parsedzf3zc2;\nvar test;\nvar BgL_parsezd2ze3treesz31;\nvar BgL_makezd2parserzd2;\n/* End Exports */\n\nvar const_earley;\n{\n  const_earley = new sc_Pair(\n    new sc_Pair(\n      \"\\u1E9Cs\",\n      new sc_Pair(\n        new sc_Pair(\"\\u1E9Ca\", null),\n        new sc_Pair(new sc_Pair(\"\\u1E9Cs\", new sc_Pair(\"\\u1E9Cs\", null)), null)\n      )\n    ),\n    null\n  );\n  BgL_makezd2parserzd2 = function (grammar, lexer) {\n    var i;\n    var parser_descr;\n    var def_loop;\n    var nb_nts;\n    var names;\n    var steps;\n    var predictors;\n    var enders;\n    var starters;\n    var nts;\n    var sc_names_1;\n    var sc_steps_2;\n    var sc_predictors_3;\n    var sc_enders_4;\n    var sc_starters_5;\n    var nb_confs;\n    var BgL_sc_defzd2loop_6zd2;\n    var BgL_sc_nbzd2nts_7zd2;\n    var sc_nts_8;\n    var BgL_sc_defzd2loop_9zd2;\n    var ind;\n    {\n      ind = function (nt, sc_nts_10) {\n        var i;\n        {\n          i = sc_nts_10.length - 1;\n          while (true) {\n            if (i >= 0)\n              if (sc_isEqual(sc_nts_10[i], nt)) return i;\n              else --i;\n            else return false;\n          }\n        }\n      };\n      sc_nts_8 =\n        ((BgL_sc_defzd2loop_9zd2 = function (defs, sc_nts_11) {\n          var rule_loop;\n          var head;\n          var def;\n          return defs instanceof sc_Pair\n            ? ((def = defs.car),\n              (head = def.car),\n              (rule_loop = function (rules, sc_nts_12) {\n                var nt;\n                var l;\n                var sc_nts_13;\n                var rule;\n                if (rules instanceof sc_Pair) {\n                  rule = rules.car;\n                  l = rule;\n                  sc_nts_13 = sc_nts_12;\n                  while (l instanceof sc_Pair) {\n                    {\n                      nt = l.car;\n                      l = l.cdr;\n                      sc_nts_13 =\n                        sc_member(nt, sc_nts_13) !== false\n                          ? sc_nts_13\n                          : new sc_Pair(nt, sc_nts_13);\n                    }\n                  }\n                  return rule_loop(rules.cdr, sc_nts_13);\n                } else return BgL_sc_defzd2loop_9zd2(defs.cdr, sc_nts_12);\n              }),\n              rule_loop(\n                def.cdr,\n                sc_member(head, sc_nts_11) !== false\n                  ? sc_nts_11\n                  : new sc_Pair(head, sc_nts_11)\n              ))\n            : sc_list2vector(sc_reverse(sc_nts_11));\n        }),\n        BgL_sc_defzd2loop_9zd2(grammar, null));\n      BgL_sc_nbzd2nts_7zd2 = sc_nts_8.length;\n      nb_confs =\n        ((BgL_sc_defzd2loop_6zd2 = function (defs, BgL_sc_nbzd2confs_14zd2) {\n          var rule_loop;\n          var def;\n          return defs instanceof sc_Pair\n            ? ((def = defs.car),\n              (rule_loop = function (rules, BgL_sc_nbzd2confs_15zd2) {\n                var l;\n                var BgL_sc_nbzd2confs_16zd2;\n                var rule;\n                if (rules instanceof sc_Pair) {\n                  rule = rules.car;\n                  l = rule;\n                  BgL_sc_nbzd2confs_16zd2 = BgL_sc_nbzd2confs_15zd2;\n                  while (l instanceof sc_Pair) {\n                    {\n                      l = l.cdr;\n                      ++BgL_sc_nbzd2confs_16zd2;\n                    }\n                  }\n                  return rule_loop(rules.cdr, BgL_sc_nbzd2confs_16zd2 + 1);\n                } else\n                  return BgL_sc_defzd2loop_6zd2(\n                    defs.cdr,\n                    BgL_sc_nbzd2confs_15zd2\n                  );\n              }),\n              rule_loop(def.cdr, BgL_sc_nbzd2confs_14zd2))\n            : BgL_sc_nbzd2confs_14zd2;\n        }),\n        BgL_sc_defzd2loop_6zd2(grammar, 0)) + BgL_sc_nbzd2nts_7zd2;\n      sc_starters_5 = sc_makeVector(BgL_sc_nbzd2nts_7zd2, null);\n      sc_enders_4 = sc_makeVector(BgL_sc_nbzd2nts_7zd2, null);\n      sc_predictors_3 = sc_makeVector(BgL_sc_nbzd2nts_7zd2, null);\n      sc_steps_2 = sc_makeVector(nb_confs, false);\n      sc_names_1 = sc_makeVector(nb_confs, false);\n      nts = sc_nts_8;\n      starters = sc_starters_5;\n      enders = sc_enders_4;\n      predictors = sc_predictors_3;\n      steps = sc_steps_2;\n      names = sc_names_1;\n      nb_nts = sc_nts_8.length;\n      i = nb_nts - 1;\n      while (i >= 0) {\n        {\n          sc_steps_2[i] = i - nb_nts;\n          sc_names_1[i] = sc_list(sc_nts_8[i], 0);\n          sc_enders_4[i] = sc_list(i);\n          --i;\n        }\n      }\n      def_loop = function (defs, conf) {\n        var rule_loop;\n        var head;\n        var def;\n        return defs instanceof sc_Pair\n          ? ((def = defs.car),\n            (head = def.car),\n            (rule_loop = function (rules, conf, rule_num) {\n              var i;\n              var sc_i_17;\n              var nt;\n              var l;\n              var sc_conf_18;\n              var sc_i_19;\n              var rule;\n              if (rules instanceof sc_Pair) {\n                rule = rules.car;\n                names[conf] = sc_list(head, rule_num);\n                sc_i_19 = ind(head, nts);\n                starters[sc_i_19] = new sc_Pair(conf, starters[sc_i_19]);\n                l = rule;\n                sc_conf_18 = conf;\n                while (l instanceof sc_Pair) {\n                  {\n                    nt = l.car;\n                    steps[sc_conf_18] = ind(nt, nts);\n                    sc_i_17 = ind(nt, nts);\n                    predictors[sc_i_17] = new sc_Pair(\n                      sc_conf_18,\n                      predictors[sc_i_17]\n                    );\n                    l = l.cdr;\n                    ++sc_conf_18;\n                  }\n                }\n                steps[sc_conf_18] = ind(head, nts) - nb_nts;\n                i = ind(head, nts);\n                enders[i] = new sc_Pair(sc_conf_18, enders[i]);\n                return rule_loop(rules.cdr, sc_conf_18 + 1, rule_num + 1);\n              } else return def_loop(defs.cdr, conf);\n            }),\n            rule_loop(def.cdr, conf, 1))\n          : undefined;\n      };\n      def_loop(grammar, sc_nts_8.length);\n      parser_descr = [\n        lexer,\n        sc_nts_8,\n        sc_starters_5,\n        sc_enders_4,\n        sc_predictors_3,\n        sc_steps_2,\n        sc_names_1,\n      ];\n      return function (input) {\n        var optrOpnd;\n        var sc_optrOpnd_20;\n        var sc_optrOpnd_21;\n        var sc_optrOpnd_22;\n        var loop1;\n        var BgL_sc_stateza2_23za2;\n        var toks;\n        var BgL_sc_nbzd2nts_24zd2;\n        var sc_steps_25;\n        var sc_enders_26;\n        var state_num;\n        var BgL_sc_statesza2_27za2;\n        var states;\n        var i;\n        var conf;\n        var l;\n        var tok_nts;\n        var sc_i_28;\n        var sc_i_29;\n        var l1;\n        var l2;\n        var tok;\n        var tail1129;\n        var L1125;\n        var goal_enders;\n        var BgL_sc_statesza2_30za2;\n        var BgL_sc_nbzd2nts_31zd2;\n        var BgL_sc_nbzd2confs_32zd2;\n        var nb_toks;\n        var goal_starters;\n        var sc_states_33;\n        var BgL_sc_nbzd2confs_34zd2;\n        var BgL_sc_nbzd2toks_35zd2;\n        var sc_toks_36;\n        var falseHead1128;\n        var sc_names_37;\n        var sc_steps_38;\n        var sc_predictors_39;\n        var sc_enders_40;\n        var sc_starters_41;\n        var sc_nts_42;\n        var lexer;\n        var sc_ind_43;\n        var make_states;\n        var BgL_sc_confzd2setzd2getza2_44za2;\n        var conf_set_merge_new_bang;\n        var conf_set_adjoin;\n        var BgL_sc_confzd2setzd2adjoinza2_45za2;\n        var BgL_sc_confzd2setzd2adjoinza2za2_46z00;\n        var conf_set_union;\n        var forw;\n        var is_parsed;\n        var deriv_trees;\n        var BgL_sc_derivzd2treesza2_47z70;\n        var nb_deriv_trees;\n        var BgL_sc_nbzd2derivzd2treesza2_48za2;\n        {\n          sc_ind_43 = function (nt, sc_nts_49) {\n            var i;\n            {\n              i = sc_nts_49.length - 1;\n              while (true) {\n                if (i >= 0)\n                  if (sc_isEqual(sc_nts_49[i], nt)) return i;\n                  else --i;\n                else return false;\n              }\n            }\n          };\n          make_states = function (\n            BgL_sc_nbzd2toks_50zd2,\n            BgL_sc_nbzd2confs_51zd2\n          ) {\n            var v;\n            var i;\n            var sc_states_52;\n            {\n              sc_states_52 = sc_makeVector(BgL_sc_nbzd2toks_50zd2 + 1, false);\n              i = BgL_sc_nbzd2toks_50zd2;\n              while (i >= 0) {\n                {\n                  v = sc_makeVector(BgL_sc_nbzd2confs_51zd2 + 1, false);\n                  v[0] = -1;\n                  sc_states_52[i] = v;\n                  --i;\n                }\n              }\n              return sc_states_52;\n            }\n          };\n          BgL_sc_confzd2setzd2getza2_44za2 = function (\n            state,\n            BgL_sc_statezd2num_53zd2,\n            sc_conf_54\n          ) {\n            var conf_set;\n            var BgL_sc_confzd2set_55zd2;\n            return (\n              (BgL_sc_confzd2set_55zd2 = state[sc_conf_54 + 1]),\n              BgL_sc_confzd2set_55zd2 !== false\n                ? BgL_sc_confzd2set_55zd2\n                : ((conf_set = sc_makeVector(\n                    BgL_sc_statezd2num_53zd2 + 6,\n                    false\n                  )),\n                  (conf_set[1] = -3),\n                  (conf_set[2] = -1),\n                  (conf_set[3] = -1),\n                  (conf_set[4] = -1),\n                  (state[sc_conf_54 + 1] = conf_set),\n                  conf_set)\n            );\n          };\n          conf_set_merge_new_bang = function (conf_set) {\n            return (\n              (conf_set[conf_set[1] + 5] = conf_set[4]),\n              (conf_set[1] = conf_set[3]),\n              (conf_set[3] = -1),\n              (conf_set[4] = -1)\n            );\n          };\n          conf_set_adjoin = function (state, conf_set, sc_conf_56, i) {\n            var tail;\n            return (\n              (tail = conf_set[3]),\n              (conf_set[i + 5] = -1),\n              (conf_set[tail + 5] = i),\n              (conf_set[3] = i),\n              tail < 0\n                ? ((conf_set[0] = state[0]), (state[0] = sc_conf_56))\n                : undefined\n            );\n          };\n          BgL_sc_confzd2setzd2adjoinza2_45za2 = function (\n            sc_states_57,\n            BgL_sc_statezd2num_58zd2,\n            l,\n            i\n          ) {\n            var conf_set;\n            var sc_conf_59;\n            var l1;\n            var state;\n            {\n              state = sc_states_57[BgL_sc_statezd2num_58zd2];\n              l1 = l;\n              while (l1 instanceof sc_Pair) {\n                {\n                  sc_conf_59 = l1.car;\n                  conf_set = BgL_sc_confzd2setzd2getza2_44za2(\n                    state,\n                    BgL_sc_statezd2num_58zd2,\n                    sc_conf_59\n                  );\n                  if (conf_set[i + 5] === false) {\n                    conf_set_adjoin(state, conf_set, sc_conf_59, i);\n                    l1 = l1.cdr;\n                  } else l1 = l1.cdr;\n                }\n              }\n              return undefined;\n            }\n          };\n          BgL_sc_confzd2setzd2adjoinza2za2_46z00 = function (\n            sc_states_60,\n            BgL_sc_statesza2_61za2,\n            BgL_sc_statezd2num_62zd2,\n            sc_conf_63,\n            i\n          ) {\n            var BgL_sc_confzd2setza2_64z70;\n            var BgL_sc_stateza2_65za2;\n            var conf_set;\n            var state;\n            return (\n              (state = sc_states_60[BgL_sc_statezd2num_62zd2]),\n              ((conf_set = state[sc_conf_63 + 1]),\n              conf_set !== false ? conf_set[i + 5] : false) !== false\n                ? ((BgL_sc_stateza2_65za2 =\n                    BgL_sc_statesza2_61za2[BgL_sc_statezd2num_62zd2]),\n                  (BgL_sc_confzd2setza2_64z70 =\n                    BgL_sc_confzd2setzd2getza2_44za2(\n                      BgL_sc_stateza2_65za2,\n                      BgL_sc_statezd2num_62zd2,\n                      sc_conf_63\n                    )),\n                  BgL_sc_confzd2setza2_64z70[i + 5] === false\n                    ? conf_set_adjoin(\n                        BgL_sc_stateza2_65za2,\n                        BgL_sc_confzd2setza2_64z70,\n                        sc_conf_63,\n                        i\n                      )\n                    : undefined,\n                  true)\n                : false\n            );\n          };\n          conf_set_union = function (state, conf_set, sc_conf_66, other_set) {\n            var i;\n            {\n              i = other_set[2];\n              while (i >= 0) {\n                if (conf_set[i + 5] === false) {\n                  conf_set_adjoin(state, conf_set, sc_conf_66, i);\n                  i = other_set[i + 5];\n                } else i = other_set[i + 5];\n              }\n              return undefined;\n            }\n          };\n          forw = function (\n            sc_states_67,\n            BgL_sc_statezd2num_68zd2,\n            sc_starters_69,\n            sc_enders_70,\n            sc_predictors_71,\n            sc_steps_72,\n            sc_nts_73\n          ) {\n            var next_set;\n            var next;\n            var conf_set;\n            var ender;\n            var l;\n            var starter_set;\n            var starter;\n            var sc_l_74;\n            var sc_loop1_75;\n            var head;\n            var BgL_sc_confzd2set_76zd2;\n            var BgL_sc_statezd2num_77zd2;\n            var state;\n            var sc_states_78;\n            var preds;\n            var BgL_sc_confzd2set_79zd2;\n            var step;\n            var sc_conf_80;\n            var BgL_sc_nbzd2nts_81zd2;\n            var sc_state_82;\n            {\n              sc_state_82 = sc_states_67[BgL_sc_statezd2num_68zd2];\n              BgL_sc_nbzd2nts_81zd2 = sc_nts_73.length;\n              while (true) {\n                {\n                  sc_conf_80 = sc_state_82[0];\n                  if (sc_conf_80 >= 0) {\n                    step = sc_steps_72[sc_conf_80];\n                    BgL_sc_confzd2set_79zd2 = sc_state_82[sc_conf_80 + 1];\n                    head = BgL_sc_confzd2set_79zd2[4];\n                    sc_state_82[0] = BgL_sc_confzd2set_79zd2[0];\n                    conf_set_merge_new_bang(BgL_sc_confzd2set_79zd2);\n                    if (step >= 0) {\n                      sc_l_74 = sc_starters_69[step];\n                      while (sc_l_74 instanceof sc_Pair) {\n                        {\n                          starter = sc_l_74.car;\n                          starter_set = BgL_sc_confzd2setzd2getza2_44za2(\n                            sc_state_82,\n                            BgL_sc_statezd2num_68zd2,\n                            starter\n                          );\n                          if (\n                            starter_set[BgL_sc_statezd2num_68zd2 + 5] === false\n                          ) {\n                            conf_set_adjoin(\n                              sc_state_82,\n                              starter_set,\n                              starter,\n                              BgL_sc_statezd2num_68zd2\n                            );\n                            sc_l_74 = sc_l_74.cdr;\n                          } else sc_l_74 = sc_l_74.cdr;\n                        }\n                      }\n                      l = sc_enders_70[step];\n                      while (l instanceof sc_Pair) {\n                        {\n                          ender = l.car;\n                          if (\n                            ((conf_set = sc_state_82[ender + 1]),\n                            conf_set !== false\n                              ? conf_set[BgL_sc_statezd2num_68zd2 + 5]\n                              : false) !== false\n                          ) {\n                            next = sc_conf_80 + 1;\n                            next_set = BgL_sc_confzd2setzd2getza2_44za2(\n                              sc_state_82,\n                              BgL_sc_statezd2num_68zd2,\n                              next\n                            );\n                            conf_set_union(\n                              sc_state_82,\n                              next_set,\n                              next,\n                              BgL_sc_confzd2set_79zd2\n                            );\n                            l = l.cdr;\n                          } else l = l.cdr;\n                        }\n                      }\n                    } else {\n                      preds = sc_predictors_71[step + BgL_sc_nbzd2nts_81zd2];\n                      sc_states_78 = sc_states_67;\n                      state = sc_state_82;\n                      BgL_sc_statezd2num_77zd2 = BgL_sc_statezd2num_68zd2;\n                      BgL_sc_confzd2set_76zd2 = BgL_sc_confzd2set_79zd2;\n                      sc_loop1_75 = function (l) {\n                        var sc_state_83;\n                        var BgL_sc_nextzd2set_84zd2;\n                        var sc_next_85;\n                        var pred_set;\n                        var i;\n                        var pred;\n                        if (l instanceof sc_Pair) {\n                          pred = l.car;\n                          i = head;\n                          while (i >= 0) {\n                            {\n                              pred_set =\n                                ((sc_state_83 = sc_states_78[i]),\n                                sc_state_83[pred + 1]);\n                              if (pred_set !== false) {\n                                sc_next_85 = pred + 1;\n                                BgL_sc_nextzd2set_84zd2 =\n                                  BgL_sc_confzd2setzd2getza2_44za2(\n                                    state,\n                                    BgL_sc_statezd2num_77zd2,\n                                    sc_next_85\n                                  );\n                                conf_set_union(\n                                  state,\n                                  BgL_sc_nextzd2set_84zd2,\n                                  sc_next_85,\n                                  pred_set\n                                );\n                              }\n                              i = BgL_sc_confzd2set_76zd2[i + 5];\n                            }\n                          }\n                          return sc_loop1_75(l.cdr);\n                        } else return undefined;\n                      };\n                      sc_loop1_75(preds);\n                    }\n                  } else return undefined;\n                }\n              }\n            }\n          };\n          is_parsed = function (\n            nt,\n            i,\n            j,\n            sc_nts_86,\n            sc_enders_87,\n            sc_states_88\n          ) {\n            var conf_set;\n            var state;\n            var sc_conf_89;\n            var l;\n            var BgL_sc_ntza2_90za2;\n            {\n              BgL_sc_ntza2_90za2 = sc_ind_43(nt, sc_nts_86);\n              if (BgL_sc_ntza2_90za2 !== false) {\n                sc_nts_86.length;\n                l = sc_enders_87[BgL_sc_ntza2_90za2];\n                while (true) {\n                  if (l instanceof sc_Pair) {\n                    sc_conf_89 = l.car;\n                    if (\n                      ((state = sc_states_88[j]),\n                      (conf_set = state[sc_conf_89 + 1]),\n                      conf_set !== false ? conf_set[i + 5] : false) !== false\n                    )\n                      return true;\n                    else l = l.cdr;\n                  } else return false;\n                }\n              } else return false;\n            }\n          };\n          deriv_trees = function (\n            sc_conf_91,\n            i,\n            j,\n            sc_enders_92,\n            sc_steps_93,\n            sc_names_94,\n            sc_toks_95,\n            sc_states_96,\n            BgL_sc_nbzd2nts_97zd2\n          ) {\n            var sc_loop1_98;\n            var prev;\n            var name;\n            return (\n              (name = sc_names_94[sc_conf_91]),\n              name !== false\n                ? sc_conf_91 < BgL_sc_nbzd2nts_97zd2\n                  ? sc_list(sc_list(name, sc_toks_95[i].car))\n                  : sc_list(sc_list(name))\n                : ((prev = sc_conf_91 - 1),\n                  (sc_loop1_98 = function (l1, l2) {\n                    var loop2;\n                    var ender_set;\n                    var state;\n                    var ender;\n                    var l1;\n                    var l2;\n                    while (true) {\n                      if (l1 instanceof sc_Pair) {\n                        ender = l1.car;\n                        ender_set =\n                          ((state = sc_states_96[j]), state[ender + 1]);\n                        if (ender_set !== false) {\n                          loop2 = function (k, l2) {\n                            var loop3;\n                            var ender_trees;\n                            var prev_trees;\n                            var conf_set;\n                            var sc_state_99;\n                            var k;\n                            var l2;\n                            while (true) {\n                              if (k >= 0)\n                                if (\n                                  k >= i &&\n                                  ((sc_state_99 = sc_states_96[k]),\n                                  (conf_set = sc_state_99[prev + 1]),\n                                  conf_set !== false\n                                    ? conf_set[i + 5]\n                                    : false) !== false\n                                ) {\n                                  prev_trees = deriv_trees(\n                                    prev,\n                                    i,\n                                    k,\n                                    sc_enders_92,\n                                    sc_steps_93,\n                                    sc_names_94,\n                                    sc_toks_95,\n                                    sc_states_96,\n                                    BgL_sc_nbzd2nts_97zd2\n                                  );\n                                  ender_trees = deriv_trees(\n                                    ender,\n                                    k,\n                                    j,\n                                    sc_enders_92,\n                                    sc_steps_93,\n                                    sc_names_94,\n                                    sc_toks_95,\n                                    sc_states_96,\n                                    BgL_sc_nbzd2nts_97zd2\n                                  );\n                                  loop3 = function (l3, l2) {\n                                    var l4;\n                                    var sc_l2_100;\n                                    var ender_tree;\n                                    if (l3 instanceof sc_Pair) {\n                                      ender_tree = sc_list(l3.car);\n                                      l4 = prev_trees;\n                                      sc_l2_100 = l2;\n                                      while (l4 instanceof sc_Pair) {\n                                        {\n                                          sc_l2_100 = new sc_Pair(\n                                            sc_append(l4.car, ender_tree),\n                                            sc_l2_100\n                                          );\n                                          l4 = l4.cdr;\n                                        }\n                                      }\n                                      return loop3(l3.cdr, sc_l2_100);\n                                    } else return loop2(ender_set[k + 5], l2);\n                                  };\n                                  return loop3(ender_trees, l2);\n                                } else k = ender_set[k + 5];\n                              else return sc_loop1_98(l1.cdr, l2);\n                            }\n                          };\n                          return loop2(ender_set[2], l2);\n                        } else l1 = l1.cdr;\n                      } else return l2;\n                    }\n                  }),\n                  sc_loop1_98(sc_enders_92[sc_steps_93[prev]], null))\n            );\n          };\n          BgL_sc_derivzd2treesza2_47z70 = function (\n            nt,\n            i,\n            j,\n            sc_nts_101,\n            sc_enders_102,\n            sc_steps_103,\n            sc_names_104,\n            sc_toks_105,\n            sc_states_106\n          ) {\n            var conf_set;\n            var state;\n            var sc_conf_107;\n            var l;\n            var trees;\n            var BgL_sc_nbzd2nts_108zd2;\n            var BgL_sc_ntza2_109za2;\n            {\n              BgL_sc_ntza2_109za2 = sc_ind_43(nt, sc_nts_101);\n              if (BgL_sc_ntza2_109za2 !== false) {\n                BgL_sc_nbzd2nts_108zd2 = sc_nts_101.length;\n                l = sc_enders_102[BgL_sc_ntza2_109za2];\n                trees = null;\n                while (l instanceof sc_Pair) {\n                  {\n                    sc_conf_107 = l.car;\n                    if (\n                      ((state = sc_states_106[j]),\n                      (conf_set = state[sc_conf_107 + 1]),\n                      conf_set !== false ? conf_set[i + 5] : false) !== false\n                    ) {\n                      l = l.cdr;\n                      trees = sc_append(\n                        deriv_trees(\n                          sc_conf_107,\n                          i,\n                          j,\n                          sc_enders_102,\n                          sc_steps_103,\n                          sc_names_104,\n                          sc_toks_105,\n                          sc_states_106,\n                          BgL_sc_nbzd2nts_108zd2\n                        ),\n                        trees\n                      );\n                    } else l = l.cdr;\n                  }\n                }\n                return trees;\n              } else return false;\n            }\n          };\n          nb_deriv_trees = function (\n            sc_conf_110,\n            i,\n            j,\n            sc_enders_111,\n            sc_steps_112,\n            sc_toks_113,\n            sc_states_114,\n            BgL_sc_nbzd2nts_115zd2\n          ) {\n            var sc_loop1_116;\n            var tmp1124;\n            var prev;\n            return (\n              (prev = sc_conf_110 - 1),\n              ((tmp1124 = sc_conf_110 < BgL_sc_nbzd2nts_115zd2),\n              tmp1124 !== false ? tmp1124 : sc_steps_112[prev] < 0) !== false\n                ? 1\n                : ((sc_loop1_116 = function (l, sc_n_118) {\n                    var nb_ender_trees;\n                    var nb_prev_trees;\n                    var conf_set;\n                    var state;\n                    var k;\n                    var n;\n                    var ender_set;\n                    var sc_state_117;\n                    var ender;\n                    var l;\n                    var sc_n_118;\n                    while (true) {\n                      if (l instanceof sc_Pair) {\n                        ender = l.car;\n                        ender_set =\n                          ((sc_state_117 = sc_states_114[j]),\n                          sc_state_117[ender + 1]);\n                        if (ender_set !== false) {\n                          k = ender_set[2];\n                          n = sc_n_118;\n                          while (k >= 0) {\n                            if (\n                              k >= i &&\n                              ((state = sc_states_114[k]),\n                              (conf_set = state[prev + 1]),\n                              conf_set !== false ? conf_set[i + 5] : false) !==\n                                false\n                            ) {\n                              nb_prev_trees = nb_deriv_trees(\n                                prev,\n                                i,\n                                k,\n                                sc_enders_111,\n                                sc_steps_112,\n                                sc_toks_113,\n                                sc_states_114,\n                                BgL_sc_nbzd2nts_115zd2\n                              );\n                              nb_ender_trees = nb_deriv_trees(\n                                ender,\n                                k,\n                                j,\n                                sc_enders_111,\n                                sc_steps_112,\n                                sc_toks_113,\n                                sc_states_114,\n                                BgL_sc_nbzd2nts_115zd2\n                              );\n                              k = ender_set[k + 5];\n                              n += nb_prev_trees * nb_ender_trees;\n                            } else k = ender_set[k + 5];\n                          }\n                          return sc_loop1_116(l.cdr, n);\n                        } else l = l.cdr;\n                      } else return sc_n_118;\n                    }\n                  }),\n                  sc_loop1_116(sc_enders_111[sc_steps_112[prev]], 0))\n            );\n          };\n          BgL_sc_nbzd2derivzd2treesza2_48za2 = function (\n            nt,\n            i,\n            j,\n            sc_nts_119,\n            sc_enders_120,\n            sc_steps_121,\n            sc_toks_122,\n            sc_states_123\n          ) {\n            var conf_set;\n            var state;\n            var sc_conf_124;\n            var l;\n            var nb_trees;\n            var BgL_sc_nbzd2nts_125zd2;\n            var BgL_sc_ntza2_126za2;\n            {\n              BgL_sc_ntza2_126za2 = sc_ind_43(nt, sc_nts_119);\n              if (BgL_sc_ntza2_126za2 !== false) {\n                BgL_sc_nbzd2nts_125zd2 = sc_nts_119.length;\n                l = sc_enders_120[BgL_sc_ntza2_126za2];\n                nb_trees = 0;\n                while (l instanceof sc_Pair) {\n                  {\n                    sc_conf_124 = l.car;\n                    if (\n                      ((state = sc_states_123[j]),\n                      (conf_set = state[sc_conf_124 + 1]),\n                      conf_set !== false ? conf_set[i + 5] : false) !== false\n                    ) {\n                      l = l.cdr;\n                      nb_trees =\n                        nb_deriv_trees(\n                          sc_conf_124,\n                          i,\n                          j,\n                          sc_enders_120,\n                          sc_steps_121,\n                          sc_toks_122,\n                          sc_states_123,\n                          BgL_sc_nbzd2nts_125zd2\n                        ) + nb_trees;\n                    } else l = l.cdr;\n                  }\n                }\n                return nb_trees;\n              } else return false;\n            }\n          };\n          lexer = parser_descr[0];\n          sc_nts_42 = parser_descr[1];\n          sc_starters_41 = parser_descr[2];\n          sc_enders_40 = parser_descr[3];\n          sc_predictors_39 = parser_descr[4];\n          sc_steps_38 = parser_descr[5];\n          sc_names_37 = parser_descr[6];\n          falseHead1128 = new sc_Pair(null, null);\n          L1125 = lexer(input);\n          tail1129 = falseHead1128;\n          while (!(L1125 === null)) {\n            {\n              tok = L1125.car;\n              l1 = tok.cdr;\n              l2 = null;\n              while (l1 instanceof sc_Pair) {\n                {\n                  sc_i_29 = sc_ind_43(l1.car, sc_nts_42);\n                  if (sc_i_29 !== false) {\n                    l1 = l1.cdr;\n                    l2 = new sc_Pair(sc_i_29, l2);\n                  } else l1 = l1.cdr;\n                }\n              }\n              sc_optrOpnd_22 = new sc_Pair(tok.car, sc_reverse(l2));\n              sc_optrOpnd_21 = new sc_Pair(sc_optrOpnd_22, null);\n              tail1129.cdr = sc_optrOpnd_21;\n              tail1129 = tail1129.cdr;\n              L1125 = L1125.cdr;\n            }\n          }\n          sc_optrOpnd_20 = falseHead1128.cdr;\n          sc_toks_36 = sc_list2vector(sc_optrOpnd_20);\n          BgL_sc_nbzd2toks_35zd2 = sc_toks_36.length;\n          BgL_sc_nbzd2confs_34zd2 = sc_steps_38.length;\n          sc_states_33 = make_states(\n            BgL_sc_nbzd2toks_35zd2,\n            BgL_sc_nbzd2confs_34zd2\n          );\n          goal_starters = sc_starters_41[0];\n          BgL_sc_confzd2setzd2adjoinza2_45za2(\n            sc_states_33,\n            0,\n            goal_starters,\n            0\n          );\n          forw(\n            sc_states_33,\n            0,\n            sc_starters_41,\n            sc_enders_40,\n            sc_predictors_39,\n            sc_steps_38,\n            sc_nts_42\n          );\n          sc_i_28 = 0;\n          while (sc_i_28 < BgL_sc_nbzd2toks_35zd2) {\n            {\n              tok_nts = sc_toks_36[sc_i_28].cdr;\n              BgL_sc_confzd2setzd2adjoinza2_45za2(\n                sc_states_33,\n                sc_i_28 + 1,\n                tok_nts,\n                sc_i_28\n              );\n              forw(\n                sc_states_33,\n                sc_i_28 + 1,\n                sc_starters_41,\n                sc_enders_40,\n                sc_predictors_39,\n                sc_steps_38,\n                sc_nts_42\n              );\n              ++sc_i_28;\n            }\n          }\n          nb_toks = sc_toks_36.length;\n          BgL_sc_nbzd2confs_32zd2 = sc_steps_38.length;\n          BgL_sc_nbzd2nts_31zd2 = sc_nts_42.length;\n          BgL_sc_statesza2_30za2 = make_states(\n            nb_toks,\n            BgL_sc_nbzd2confs_32zd2\n          );\n          goal_enders = sc_enders_40[0];\n          l = goal_enders;\n          while (l instanceof sc_Pair) {\n            {\n              conf = l.car;\n              BgL_sc_confzd2setzd2adjoinza2za2_46z00(\n                sc_states_33,\n                BgL_sc_statesza2_30za2,\n                nb_toks,\n                conf,\n                0\n              );\n              l = l.cdr;\n            }\n          }\n          i = nb_toks;\n          while (i >= 0) {\n            {\n              states = sc_states_33;\n              BgL_sc_statesza2_27za2 = BgL_sc_statesza2_30za2;\n              state_num = i;\n              sc_enders_26 = sc_enders_40;\n              sc_steps_25 = sc_steps_38;\n              BgL_sc_nbzd2nts_24zd2 = BgL_sc_nbzd2nts_31zd2;\n              toks = sc_toks_36;\n              BgL_sc_stateza2_23za2 = BgL_sc_statesza2_30za2[i];\n              loop1 = function () {\n                var sc_loop1_127;\n                var prev;\n                var BgL_sc_statesza2_128za2;\n                var sc_states_129;\n                var j;\n                var i;\n                var sc_i_130;\n                var head;\n                var conf_set;\n                var sc_conf_131;\n                {\n                  sc_conf_131 = BgL_sc_stateza2_23za2[0];\n                  if (sc_conf_131 >= 0) {\n                    conf_set = BgL_sc_stateza2_23za2[sc_conf_131 + 1];\n                    head = conf_set[4];\n                    BgL_sc_stateza2_23za2[0] = conf_set[0];\n                    conf_set_merge_new_bang(conf_set);\n                    sc_i_130 = head;\n                    while (sc_i_130 >= 0) {\n                      {\n                        i = sc_i_130;\n                        j = state_num;\n                        sc_states_129 = states;\n                        BgL_sc_statesza2_128za2 = BgL_sc_statesza2_27za2;\n                        prev = sc_conf_131 - 1;\n                        if (\n                          sc_conf_131 >= BgL_sc_nbzd2nts_24zd2 &&\n                          sc_steps_25[prev] >= 0\n                        ) {\n                          sc_loop1_127 = function (l) {\n                            var k;\n                            var ender_set;\n                            var state;\n                            var ender;\n                            var l;\n                            while (true) {\n                              if (l instanceof sc_Pair) {\n                                ender = l.car;\n                                ender_set =\n                                  ((state = sc_states_129[j]),\n                                  state[ender + 1]);\n                                if (ender_set !== false) {\n                                  k = ender_set[2];\n                                  while (k >= 0) {\n                                    {\n                                      if (k >= i)\n                                        if (\n                                          BgL_sc_confzd2setzd2adjoinza2za2_46z00(\n                                            sc_states_129,\n                                            BgL_sc_statesza2_128za2,\n                                            k,\n                                            prev,\n                                            i\n                                          ) !== false\n                                        )\n                                          BgL_sc_confzd2setzd2adjoinza2za2_46z00(\n                                            sc_states_129,\n                                            BgL_sc_statesza2_128za2,\n                                            j,\n                                            ender,\n                                            k\n                                          );\n                                      k = ender_set[k + 5];\n                                    }\n                                  }\n                                  return sc_loop1_127(l.cdr);\n                                } else l = l.cdr;\n                              } else return undefined;\n                            }\n                          };\n                          sc_loop1_127(sc_enders_26[sc_steps_25[prev]]);\n                        }\n                        sc_i_130 = conf_set[sc_i_130 + 5];\n                      }\n                    }\n                    return loop1();\n                  } else return undefined;\n                }\n              };\n              loop1();\n              --i;\n            }\n          }\n          optrOpnd = BgL_sc_statesza2_30za2;\n          return [\n            sc_nts_42,\n            sc_starters_41,\n            sc_enders_40,\n            sc_predictors_39,\n            sc_steps_38,\n            sc_names_37,\n            sc_toks_36,\n            optrOpnd,\n            is_parsed,\n            BgL_sc_derivzd2treesza2_47z70,\n            BgL_sc_nbzd2derivzd2treesza2_48za2,\n          ];\n        }\n      };\n    }\n  };\n  BgL_parsezd2ze3parsedzf3zc2 = function (parse, nt, i, j) {\n    var is_parsed;\n    var states;\n    var enders;\n    var nts;\n    return (\n      (nts = parse[0]),\n      (enders = parse[2]),\n      (states = parse[7]),\n      (is_parsed = parse[8]),\n      is_parsed(nt, i, j, nts, enders, states)\n    );\n  };\n  BgL_parsezd2ze3treesz31 = function (parse, nt, i, j) {\n    var BgL_sc_derivzd2treesza2_132z70;\n    var states;\n    var toks;\n    var names;\n    var steps;\n    var enders;\n    var nts;\n    return (\n      (nts = parse[0]),\n      (enders = parse[2]),\n      (steps = parse[4]),\n      (names = parse[5]),\n      (toks = parse[6]),\n      (states = parse[7]),\n      (BgL_sc_derivzd2treesza2_132z70 = parse[9]),\n      BgL_sc_derivzd2treesza2_132z70(\n        nt,\n        i,\n        j,\n        nts,\n        enders,\n        steps,\n        names,\n        toks,\n        states\n      )\n    );\n  };\n  BgL_parsezd2ze3nbzd2treesze3 = function (parse, nt, i, j) {\n    var BgL_sc_nbzd2derivzd2treesza2_133za2;\n    var states;\n    var toks;\n    var steps;\n    var enders;\n    var nts;\n    return (\n      (nts = parse[0]),\n      (enders = parse[2]),\n      (steps = parse[4]),\n      (toks = parse[6]),\n      (states = parse[7]),\n      (BgL_sc_nbzd2derivzd2treesza2_133za2 = parse[10]),\n      BgL_sc_nbzd2derivzd2treesza2_133za2(\n        nt,\n        i,\n        j,\n        nts,\n        enders,\n        steps,\n        toks,\n        states\n      )\n    );\n  };\n  test = function (k) {\n    var x;\n    var p;\n    return (\n      (p = BgL_makezd2parserzd2(const_earley, function (l) {\n        var sc_x_134;\n        var tail1134;\n        var L1130;\n        var falseHead1133;\n        {\n          falseHead1133 = new sc_Pair(null, null);\n          tail1134 = falseHead1133;\n          L1130 = l;\n          while (!(L1130 === null)) {\n            {\n              tail1134.cdr = new sc_Pair(\n                ((sc_x_134 = L1130.car), sc_list(sc_x_134, sc_x_134)),\n                null\n              );\n              tail1134 = tail1134.cdr;\n              L1130 = L1130.cdr;\n            }\n          }\n          return falseHead1133.cdr;\n        }\n      })),\n      (x = p(sc_vector2list(sc_makeVector(k, \"\\u1E9Ca\")))),\n      sc_length(BgL_parsezd2ze3treesz31(x, \"\\u1E9Cs\", 0, k))\n    );\n  };\n  BgL_earleyzd2benchmarkzd2 = function () {\n    var args = null;\n    for (var sc_tmp = arguments.length - 1; sc_tmp >= 0; sc_tmp--) {\n      args = sc_cons(arguments[sc_tmp], args);\n    }\n    var k;\n    return (\n      (k = args === null ? 7 : args.car),\n      BgL_runzd2benchmarkzd2(\n        \"earley\",\n        1,\n        function () {\n          return test(k);\n        },\n        function (result) {\n          return sc_display(result), sc_newline(), result == 132;\n        }\n      )\n    );\n  };\n}\n\n/************* END OF GENERATED CODE *************/\n// Invoke this function to run a benchmark.\n// The first argument is a string identifying the benchmark.\n// The second argument is the number of times to run the benchmark.\n// The third argument is a function that runs the benchmark.\n// The fourth argument is a unary function that warns if the result\n// returned by the benchmark is incorrect.\n//\n// Example:\n// RunBenchmark(\"new Array()\",\n//              1,\n//              function () { new Array(1000000); }\n//              function (v) {\n//                return (v instanceof Array) && (v.length == 1000000);\n//              });\n\nSC_DEFAULT_OUT = new sc_GenericOutputPort(function (s) {});\nSC_ERROR_OUT = SC_DEFAULT_OUT;\n\nfunction RunBenchmark(name, count, run, warn) {\n  for (var n = 0; n < count; ++n) {\n    result = run();\n    if (!warn(result)) {\n      throw new Error(\"Earley or Boyer did incorrect number of rewrites\");\n    }\n  }\n}\n\nvar BgL_runzd2benchmarkzd2 = RunBenchmark;\n"
  },
  {
    "path": "benchmarks/v8-v7/index.js",
    "content": "// Copyright 2008 the V8 project authors. All rights reserved.\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\n//       disclaimer in the documentation and/or other materials provided\n//       with the distribution.\n//     * Neither the name of Google Inc. nor the names of its\n//       contributors may be used to endorse or promote products derived\n//       from 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\nimport { load, print } from \"llrt:util\";\n\nload(\"base.js\");\nload(\"richards.js\");\nload(\"deltablue.js\");\nload(\"crypto.js\");\nload(\"raytrace.js\");\nload(\"earley-boyer.js\");\nload(\"regexp.js\");\nload(\"splay.js\");\nload(\"navier-stokes.js\");\n\nvar success = true;\n\nfunction PrintResult(name, result) {\n  print(name + \": \" + result);\n}\n\nfunction PrintError(name, error) {\n  PrintResult(name, error);\n  success = false;\n}\n\nfunction PrintScore(score) {\n  if (success) {\n    print(\"----\");\n    print(\"Score (version \" + BenchmarkSuite.version + \"): \" + score);\n  }\n}\n\nBenchmarkSuite.RunSuites({\n  NotifyResult: PrintResult,\n  NotifyError: PrintError,\n  NotifyScore: PrintScore,\n});\n"
  },
  {
    "path": "benchmarks/v8-v7/navier-stokes.js",
    "content": "/**\n * Copyright 2012 the V8 project authors. All rights reserved.\n * Copyright 2009 Oliver Hunt <http://nerget.com>\n *\n * Permission is hereby granted, free of charge, to any person\n * obtaining a copy of this software and associated documentation\n * files (the \"Software\"), to deal in the Software without\n * restriction, including without limitation the rights to use,\n * copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the\n * Software is furnished to do so, subject to the following\n * conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n * OTHER DEALINGS IN THE SOFTWARE.\n */\n\nvar NavierStokes = new BenchmarkSuite(\"NavierStokes\", 1484000, [\n  new Benchmark(\n    \"NavierStokes\",\n    runNavierStokes,\n    setupNavierStokes,\n    tearDownNavierStokes\n  ),\n]);\n\nvar solver = null;\n\nfunction runNavierStokes() {\n  solver.update();\n}\n\nfunction setupNavierStokes() {\n  solver = new FluidField(null);\n  solver.setResolution(128, 128);\n  solver.setIterations(20);\n  solver.setDisplayFunction(function () {});\n  solver.setUICallback(prepareFrame);\n  solver.reset();\n}\n\nfunction tearDownNavierStokes() {\n  solver = null;\n}\n\nfunction addPoints(field) {\n  var n = 64;\n  for (var i = 1; i <= n; i++) {\n    field.setVelocity(i, i, n, n);\n    field.setDensity(i, i, 5);\n    field.setVelocity(i, n - i, -n, -n);\n    field.setDensity(i, n - i, 20);\n    field.setVelocity(128 - i, n + i, -n, -n);\n    field.setDensity(128 - i, n + i, 30);\n  }\n}\n\nvar framesTillAddingPoints = 0;\nvar framesBetweenAddingPoints = 5;\n\nfunction prepareFrame(field) {\n  if (framesTillAddingPoints == 0) {\n    addPoints(field);\n    framesTillAddingPoints = framesBetweenAddingPoints;\n    framesBetweenAddingPoints++;\n  } else {\n    framesTillAddingPoints--;\n  }\n}\n\n// Code from Oliver Hunt (http://nerget.com/fluidSim/pressure.js) starts here.\nfunction FluidField(canvas) {\n  function addFields(x, s, dt) {\n    for (var i = 0; i < size; i++) x[i] += dt * s[i];\n  }\n\n  function set_bnd(b, x) {\n    if (b === 1) {\n      for (var i = 1; i <= width; i++) {\n        x[i] = x[i + rowSize];\n        x[i + (height + 1) * rowSize] = x[i + height * rowSize];\n      }\n\n      for (var j = 1; i <= height; i++) {\n        x[j * rowSize] = -x[1 + j * rowSize];\n        x[width + 1 + j * rowSize] = -x[width + j * rowSize];\n      }\n    } else if (b === 2) {\n      for (var i = 1; i <= width; i++) {\n        x[i] = -x[i + rowSize];\n        x[i + (height + 1) * rowSize] = -x[i + height * rowSize];\n      }\n\n      for (var j = 1; j <= height; j++) {\n        x[j * rowSize] = x[1 + j * rowSize];\n        x[width + 1 + j * rowSize] = x[width + j * rowSize];\n      }\n    } else {\n      for (var i = 1; i <= width; i++) {\n        x[i] = x[i + rowSize];\n        x[i + (height + 1) * rowSize] = x[i + height * rowSize];\n      }\n\n      for (var j = 1; j <= height; j++) {\n        x[j * rowSize] = x[1 + j * rowSize];\n        x[width + 1 + j * rowSize] = x[width + j * rowSize];\n      }\n    }\n    var maxEdge = (height + 1) * rowSize;\n    x[0] = 0.5 * (x[1] + x[rowSize]);\n    x[maxEdge] = 0.5 * (x[1 + maxEdge] + x[height * rowSize]);\n    x[width + 1] = 0.5 * (x[width] + x[width + 1 + rowSize]);\n    x[width + 1 + maxEdge] =\n      0.5 * (x[width + maxEdge] + x[width + 1 + height * rowSize]);\n  }\n\n  function lin_solve(b, x, x0, a, c) {\n    if (a === 0 && c === 1) {\n      for (var j = 1; j <= height; j++) {\n        var currentRow = j * rowSize;\n        ++currentRow;\n        for (var i = 0; i < width; i++) {\n          x[currentRow] = x0[currentRow];\n          ++currentRow;\n        }\n      }\n      set_bnd(b, x);\n    } else {\n      var invC = 1 / c;\n      for (var k = 0; k < iterations; k++) {\n        for (var j = 1; j <= height; j++) {\n          var lastRow = (j - 1) * rowSize;\n          var currentRow = j * rowSize;\n          var nextRow = (j + 1) * rowSize;\n          var lastX = x[currentRow];\n          ++currentRow;\n          for (var i = 1; i <= width; i++)\n            lastX = x[currentRow] =\n              (x0[currentRow] +\n                a * (lastX + x[++currentRow] + x[++lastRow] + x[++nextRow])) *\n              invC;\n        }\n        set_bnd(b, x);\n      }\n    }\n  }\n\n  function diffuse(b, x, x0, dt) {\n    var a = 0;\n    lin_solve(b, x, x0, a, 1 + 4 * a);\n  }\n\n  function lin_solve2(x, x0, y, y0, a, c) {\n    if (a === 0 && c === 1) {\n      for (var j = 1; j <= height; j++) {\n        var currentRow = j * rowSize;\n        ++currentRow;\n        for (var i = 0; i < width; i++) {\n          x[currentRow] = x0[currentRow];\n          y[currentRow] = y0[currentRow];\n          ++currentRow;\n        }\n      }\n      set_bnd(1, x);\n      set_bnd(2, y);\n    } else {\n      var invC = 1 / c;\n      for (var k = 0; k < iterations; k++) {\n        for (var j = 1; j <= height; j++) {\n          var lastRow = (j - 1) * rowSize;\n          var currentRow = j * rowSize;\n          var nextRow = (j + 1) * rowSize;\n          var lastX = x[currentRow];\n          var lastY = y[currentRow];\n          ++currentRow;\n          for (var i = 1; i <= width; i++) {\n            lastX = x[currentRow] =\n              (x0[currentRow] +\n                a * (lastX + x[currentRow] + x[lastRow] + x[nextRow])) *\n              invC;\n            lastY = y[currentRow] =\n              (y0[currentRow] +\n                a * (lastY + y[++currentRow] + y[++lastRow] + y[++nextRow])) *\n              invC;\n          }\n        }\n        set_bnd(1, x);\n        set_bnd(2, y);\n      }\n    }\n  }\n\n  function diffuse2(x, x0, y, y0, dt) {\n    var a = 0;\n    lin_solve2(x, x0, y, y0, a, 1 + 4 * a);\n  }\n\n  function advect(b, d, d0, u, v, dt) {\n    var Wdt0 = dt * width;\n    var Hdt0 = dt * height;\n    var Wp5 = width + 0.5;\n    var Hp5 = height + 0.5;\n    for (var j = 1; j <= height; j++) {\n      var pos = j * rowSize;\n      for (var i = 1; i <= width; i++) {\n        var x = i - Wdt0 * u[++pos];\n        var y = j - Hdt0 * v[pos];\n        if (x < 0.5) x = 0.5;\n        else if (x > Wp5) x = Wp5;\n        var i0 = x | 0;\n        var i1 = i0 + 1;\n        if (y < 0.5) y = 0.5;\n        else if (y > Hp5) y = Hp5;\n        var j0 = y | 0;\n        var j1 = j0 + 1;\n        var s1 = x - i0;\n        var s0 = 1 - s1;\n        var t1 = y - j0;\n        var t0 = 1 - t1;\n        var row1 = j0 * rowSize;\n        var row2 = j1 * rowSize;\n        d[pos] =\n          s0 * (t0 * d0[i0 + row1] + t1 * d0[i0 + row2]) +\n          s1 * (t0 * d0[i1 + row1] + t1 * d0[i1 + row2]);\n      }\n    }\n    set_bnd(b, d);\n  }\n\n  function project(u, v, p, div) {\n    var h = -0.5 / Math.sqrt(width * height);\n    for (var j = 1; j <= height; j++) {\n      var row = j * rowSize;\n      var previousRow = (j - 1) * rowSize;\n      var prevValue = row - 1;\n      var currentRow = row;\n      var nextValue = row + 1;\n      var nextRow = (j + 1) * rowSize;\n      for (var i = 1; i <= width; i++) {\n        div[++currentRow] =\n          h *\n          (u[++nextValue] - u[++prevValue] + v[++nextRow] - v[++previousRow]);\n        p[currentRow] = 0;\n      }\n    }\n    set_bnd(0, div);\n    set_bnd(0, p);\n\n    lin_solve(0, p, div, 1, 4);\n    var wScale = 0.5 * width;\n    var hScale = 0.5 * height;\n    for (var j = 1; j <= height; j++) {\n      var prevPos = j * rowSize - 1;\n      var currentPos = j * rowSize;\n      var nextPos = j * rowSize + 1;\n      var prevRow = (j - 1) * rowSize;\n      var currentRow = j * rowSize;\n      var nextRow = (j + 1) * rowSize;\n\n      for (var i = 1; i <= width; i++) {\n        u[++currentPos] -= wScale * (p[++nextPos] - p[++prevPos]);\n        v[currentPos] -= hScale * (p[++nextRow] - p[++prevRow]);\n      }\n    }\n    set_bnd(1, u);\n    set_bnd(2, v);\n  }\n\n  function dens_step(x, x0, u, v, dt) {\n    addFields(x, x0, dt);\n    diffuse(0, x0, x, dt);\n    advect(0, x, x0, u, v, dt);\n  }\n\n  function vel_step(u, v, u0, v0, dt) {\n    addFields(u, u0, dt);\n    addFields(v, v0, dt);\n    var temp = u0;\n    u0 = u;\n    u = temp;\n    var temp = v0;\n    v0 = v;\n    v = temp;\n    diffuse2(u, u0, v, v0, dt);\n    project(u, v, u0, v0);\n    var temp = u0;\n    u0 = u;\n    u = temp;\n    var temp = v0;\n    v0 = v;\n    v = temp;\n    advect(1, u, u0, u0, v0, dt);\n    advect(2, v, v0, u0, v0, dt);\n    project(u, v, u0, v0);\n  }\n  var uiCallback = function (d, u, v) {};\n\n  function Field(dens, u, v) {\n    // Just exposing the fields here rather than using accessors is a measurable win during display (maybe 5%)\n    // but makes the code ugly.\n    this.setDensity = function (x, y, d) {\n      dens[x + 1 + (y + 1) * rowSize] = d;\n    };\n    this.getDensity = function (x, y) {\n      return dens[x + 1 + (y + 1) * rowSize];\n    };\n    this.setVelocity = function (x, y, xv, yv) {\n      u[x + 1 + (y + 1) * rowSize] = xv;\n      v[x + 1 + (y + 1) * rowSize] = yv;\n    };\n    this.getXVelocity = function (x, y) {\n      return u[x + 1 + (y + 1) * rowSize];\n    };\n    this.getYVelocity = function (x, y) {\n      return v[x + 1 + (y + 1) * rowSize];\n    };\n    this.width = function () {\n      return width;\n    };\n    this.height = function () {\n      return height;\n    };\n  }\n  function queryUI(d, u, v) {\n    for (var i = 0; i < size; i++) u[i] = v[i] = d[i] = 0.0;\n    uiCallback(new Field(d, u, v));\n  }\n\n  this.update = function () {\n    queryUI(dens_prev, u_prev, v_prev);\n    vel_step(u, v, u_prev, v_prev, dt);\n    dens_step(dens, dens_prev, u, v, dt);\n    displayFunc(new Field(dens, u, v));\n  };\n  this.setDisplayFunction = function (func) {\n    displayFunc = func;\n  };\n\n  this.iterations = function () {\n    return iterations;\n  };\n  this.setIterations = function (iters) {\n    if (iters > 0 && iters <= 100) iterations = iters;\n  };\n  this.setUICallback = function (callback) {\n    uiCallback = callback;\n  };\n  var iterations = 10;\n  var visc = 0.5;\n  var dt = 0.1;\n  var dens;\n  var dens_prev;\n  var u;\n  var u_prev;\n  var v;\n  var v_prev;\n  var width;\n  var height;\n  var rowSize;\n  var size;\n  var displayFunc;\n  function reset() {\n    rowSize = width + 2;\n    size = (width + 2) * (height + 2);\n    dens = new Array(size);\n    dens_prev = new Array(size);\n    u = new Array(size);\n    u_prev = new Array(size);\n    v = new Array(size);\n    v_prev = new Array(size);\n    for (var i = 0; i < size; i++)\n      dens_prev[i] = u_prev[i] = v_prev[i] = dens[i] = u[i] = v[i] = 0;\n  }\n  this.reset = reset;\n  this.setResolution = function (hRes, wRes) {\n    var res = wRes * hRes;\n    if (res > 0 && res < 1000000 && (wRes != width || hRes != height)) {\n      width = wRes;\n      height = hRes;\n      reset();\n      return true;\n    }\n    return false;\n  };\n  this.setResolution(64, 64);\n}\n"
  },
  {
    "path": "benchmarks/v8-v7/raytrace.js",
    "content": "// The ray tracer code in this file is written by Adam Burmister. It\n// is available in its original form from:\n//\n//   http://labs.flog.nz.co/raytracer/\n//\n// It has been modified slightly by Google to work as a standalone\n// benchmark, but the all the computational code remains\n// untouched. This file also contains a copy of parts of the Prototype\n// JavaScript framework which is used by the ray tracer.\n\nvar RayTrace = new BenchmarkSuite(\"RayTrace\", 739989, [\n  new Benchmark(\"RayTrace\", renderScene),\n]);\n\n// Variable used to hold a number that can be used to verify that\n// the scene was ray traced correctly.\nvar checkNumber;\n\n// ------------------------------------------------------------------------\n// ------------------------------------------------------------------------\n\n// The following is a copy of parts of the Prototype JavaScript library:\n\n// Prototype JavaScript framework, version 1.5.0\n// (c) 2005-2007 Sam Stephenson\n//\n// Prototype is freely distributable under the terms of an MIT-style license.\n// For details, see the Prototype web site: http://prototype.conio.net/\n\nvar Class = {\n  create: function () {\n    return function () {\n      this.initialize.apply(this, arguments);\n    };\n  },\n};\n\nObject.extend = function (destination, source) {\n  for (var property in source) {\n    destination[property] = source[property];\n  }\n  return destination;\n};\n\n// ------------------------------------------------------------------------\n// ------------------------------------------------------------------------\n\n// The rest of this file is the actual ray tracer written by Adam\n// Burmister. It's a concatenation of the following files:\n//\n//   flog/color.js\n//   flog/light.js\n//   flog/vector.js\n//   flog/ray.js\n//   flog/scene.js\n//   flog/material/basematerial.js\n//   flog/material/solid.js\n//   flog/material/chessboard.js\n//   flog/shape/baseshape.js\n//   flog/shape/sphere.js\n//   flog/shape/plane.js\n//   flog/intersectioninfo.js\n//   flog/camera.js\n//   flog/background.js\n//   flog/engine.js\n\n/* Fake a Flog.* namespace */\nif (typeof Flog == \"undefined\") var Flog = {};\nif (typeof Flog.RayTracer == \"undefined\") Flog.RayTracer = {};\n\nFlog.RayTracer.Color = Class.create();\n\nFlog.RayTracer.Color.prototype = {\n  red: 0.0,\n  green: 0.0,\n  blue: 0.0,\n\n  initialize: function (r, g, b) {\n    if (!r) r = 0.0;\n    if (!g) g = 0.0;\n    if (!b) b = 0.0;\n\n    this.red = r;\n    this.green = g;\n    this.blue = b;\n  },\n\n  add: function (c1, c2) {\n    var result = new Flog.RayTracer.Color(0, 0, 0);\n\n    result.red = c1.red + c2.red;\n    result.green = c1.green + c2.green;\n    result.blue = c1.blue + c2.blue;\n\n    return result;\n  },\n\n  addScalar: function (c1, s) {\n    var result = new Flog.RayTracer.Color(0, 0, 0);\n\n    result.red = c1.red + s;\n    result.green = c1.green + s;\n    result.blue = c1.blue + s;\n\n    result.limit();\n\n    return result;\n  },\n\n  subtract: function (c1, c2) {\n    var result = new Flog.RayTracer.Color(0, 0, 0);\n\n    result.red = c1.red - c2.red;\n    result.green = c1.green - c2.green;\n    result.blue = c1.blue - c2.blue;\n\n    return result;\n  },\n\n  multiply: function (c1, c2) {\n    var result = new Flog.RayTracer.Color(0, 0, 0);\n\n    result.red = c1.red * c2.red;\n    result.green = c1.green * c2.green;\n    result.blue = c1.blue * c2.blue;\n\n    return result;\n  },\n\n  multiplyScalar: function (c1, f) {\n    var result = new Flog.RayTracer.Color(0, 0, 0);\n\n    result.red = c1.red * f;\n    result.green = c1.green * f;\n    result.blue = c1.blue * f;\n\n    return result;\n  },\n\n  divideFactor: function (c1, f) {\n    var result = new Flog.RayTracer.Color(0, 0, 0);\n\n    result.red = c1.red / f;\n    result.green = c1.green / f;\n    result.blue = c1.blue / f;\n\n    return result;\n  },\n\n  limit: function () {\n    this.red = this.red > 0.0 ? (this.red > 1.0 ? 1.0 : this.red) : 0.0;\n    this.green = this.green > 0.0 ? (this.green > 1.0 ? 1.0 : this.green) : 0.0;\n    this.blue = this.blue > 0.0 ? (this.blue > 1.0 ? 1.0 : this.blue) : 0.0;\n  },\n\n  distance: function (color) {\n    var d =\n      Math.abs(this.red - color.red) +\n      Math.abs(this.green - color.green) +\n      Math.abs(this.blue - color.blue);\n    return d;\n  },\n\n  blend: function (c1, c2, w) {\n    var result = new Flog.RayTracer.Color(0, 0, 0);\n    result = Flog.RayTracer.Color.prototype.add(\n      Flog.RayTracer.Color.prototype.multiplyScalar(c1, 1 - w),\n      Flog.RayTracer.Color.prototype.multiplyScalar(c2, w)\n    );\n    return result;\n  },\n\n  brightness: function () {\n    var r = Math.floor(this.red * 255);\n    var g = Math.floor(this.green * 255);\n    var b = Math.floor(this.blue * 255);\n    return (r * 77 + g * 150 + b * 29) >> 8;\n  },\n\n  toString: function () {\n    var r = Math.floor(this.red * 255);\n    var g = Math.floor(this.green * 255);\n    var b = Math.floor(this.blue * 255);\n\n    return \"rgb(\" + r + \",\" + g + \",\" + b + \")\";\n  },\n};\n/* Fake a Flog.* namespace */\nif (typeof Flog == \"undefined\") var Flog = {};\nif (typeof Flog.RayTracer == \"undefined\") Flog.RayTracer = {};\n\nFlog.RayTracer.Light = Class.create();\n\nFlog.RayTracer.Light.prototype = {\n  position: null,\n  color: null,\n  intensity: 10.0,\n\n  initialize: function (pos, color, intensity) {\n    this.position = pos;\n    this.color = color;\n    this.intensity = intensity ? intensity : 10.0;\n  },\n\n  toString: function () {\n    return (\n      \"Light [\" +\n      this.position.x +\n      \",\" +\n      this.position.y +\n      \",\" +\n      this.position.z +\n      \"]\"\n    );\n  },\n};\n/* Fake a Flog.* namespace */\nif (typeof Flog == \"undefined\") var Flog = {};\nif (typeof Flog.RayTracer == \"undefined\") Flog.RayTracer = {};\n\nFlog.RayTracer.Vector = Class.create();\n\nFlog.RayTracer.Vector.prototype = {\n  x: 0.0,\n  y: 0.0,\n  z: 0.0,\n\n  initialize: function (x, y, z) {\n    this.x = x ? x : 0;\n    this.y = y ? y : 0;\n    this.z = z ? z : 0;\n  },\n\n  copy: function (vector) {\n    this.x = vector.x;\n    this.y = vector.y;\n    this.z = vector.z;\n  },\n\n  normalize: function () {\n    var m = this.magnitude();\n    return new Flog.RayTracer.Vector(this.x / m, this.y / m, this.z / m);\n  },\n\n  magnitude: function () {\n    return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);\n  },\n\n  cross: function (w) {\n    return new Flog.RayTracer.Vector(\n      -this.z * w.y + this.y * w.z,\n      this.z * w.x - this.x * w.z,\n      -this.y * w.x + this.x * w.y\n    );\n  },\n\n  dot: function (w) {\n    return this.x * w.x + this.y * w.y + this.z * w.z;\n  },\n\n  add: function (v, w) {\n    return new Flog.RayTracer.Vector(w.x + v.x, w.y + v.y, w.z + v.z);\n  },\n\n  subtract: function (v, w) {\n    if (!w || !v) throw \"Vectors must be defined [\" + v + \",\" + w + \"]\";\n    return new Flog.RayTracer.Vector(v.x - w.x, v.y - w.y, v.z - w.z);\n  },\n\n  multiplyVector: function (v, w) {\n    return new Flog.RayTracer.Vector(v.x * w.x, v.y * w.y, v.z * w.z);\n  },\n\n  multiplyScalar: function (v, w) {\n    return new Flog.RayTracer.Vector(v.x * w, v.y * w, v.z * w);\n  },\n\n  toString: function () {\n    return \"Vector [\" + this.x + \",\" + this.y + \",\" + this.z + \"]\";\n  },\n};\n/* Fake a Flog.* namespace */\nif (typeof Flog == \"undefined\") var Flog = {};\nif (typeof Flog.RayTracer == \"undefined\") Flog.RayTracer = {};\n\nFlog.RayTracer.Ray = Class.create();\n\nFlog.RayTracer.Ray.prototype = {\n  position: null,\n  direction: null,\n  initialize: function (pos, dir) {\n    this.position = pos;\n    this.direction = dir;\n  },\n\n  toString: function () {\n    return \"Ray [\" + this.position + \",\" + this.direction + \"]\";\n  },\n};\n/* Fake a Flog.* namespace */\nif (typeof Flog == \"undefined\") var Flog = {};\nif (typeof Flog.RayTracer == \"undefined\") Flog.RayTracer = {};\n\nFlog.RayTracer.Scene = Class.create();\n\nFlog.RayTracer.Scene.prototype = {\n  camera: null,\n  shapes: [],\n  lights: [],\n  background: null,\n\n  initialize: function () {\n    this.camera = new Flog.RayTracer.Camera(\n      new Flog.RayTracer.Vector(0, 0, -5),\n      new Flog.RayTracer.Vector(0, 0, 1),\n      new Flog.RayTracer.Vector(0, 1, 0)\n    );\n    this.shapes = new Array();\n    this.lights = new Array();\n    this.background = new Flog.RayTracer.Background(\n      new Flog.RayTracer.Color(0, 0, 0.5),\n      0.2\n    );\n  },\n};\n/* Fake a Flog.* namespace */\nif (typeof Flog == \"undefined\") var Flog = {};\nif (typeof Flog.RayTracer == \"undefined\") Flog.RayTracer = {};\nif (typeof Flog.RayTracer.Material == \"undefined\") Flog.RayTracer.Material = {};\n\nFlog.RayTracer.Material.BaseMaterial = Class.create();\n\nFlog.RayTracer.Material.BaseMaterial.prototype = {\n  gloss: 2.0, // [0...infinity] 0 = matt\n  transparency: 0.0, // 0=opaque\n  reflection: 0.0, // [0...infinity] 0 = no reflection\n  refraction: 0.5,\n  hasTexture: false,\n\n  initialize: function () {},\n\n  getColor: function (u, v) {},\n\n  wrapUp: function (t) {\n    t = t % 2.0;\n    if (t < -1) t += 2.0;\n    if (t >= 1) t -= 2.0;\n    return t;\n  },\n\n  toString: function () {\n    return (\n      \"Material [gloss=\" +\n      this.gloss +\n      \", transparency=\" +\n      this.transparency +\n      \", hasTexture=\" +\n      this.hasTexture +\n      \"]\"\n    );\n  },\n};\n/* Fake a Flog.* namespace */\nif (typeof Flog == \"undefined\") var Flog = {};\nif (typeof Flog.RayTracer == \"undefined\") Flog.RayTracer = {};\n\nFlog.RayTracer.Material.Solid = Class.create();\n\nFlog.RayTracer.Material.Solid.prototype = Object.extend(\n  new Flog.RayTracer.Material.BaseMaterial(),\n  {\n    initialize: function (color, reflection, refraction, transparency, gloss) {\n      this.color = color;\n      this.reflection = reflection;\n      this.transparency = transparency;\n      this.gloss = gloss;\n      this.hasTexture = false;\n    },\n\n    getColor: function (u, v) {\n      return this.color;\n    },\n\n    toString: function () {\n      return (\n        \"SolidMaterial [gloss=\" +\n        this.gloss +\n        \", transparency=\" +\n        this.transparency +\n        \", hasTexture=\" +\n        this.hasTexture +\n        \"]\"\n      );\n    },\n  }\n);\n/* Fake a Flog.* namespace */\nif (typeof Flog == \"undefined\") var Flog = {};\nif (typeof Flog.RayTracer == \"undefined\") Flog.RayTracer = {};\n\nFlog.RayTracer.Material.Chessboard = Class.create();\n\nFlog.RayTracer.Material.Chessboard.prototype = Object.extend(\n  new Flog.RayTracer.Material.BaseMaterial(),\n  {\n    colorEven: null,\n    colorOdd: null,\n    density: 0.5,\n\n    initialize: function (\n      colorEven,\n      colorOdd,\n      reflection,\n      transparency,\n      gloss,\n      density\n    ) {\n      this.colorEven = colorEven;\n      this.colorOdd = colorOdd;\n      this.reflection = reflection;\n      this.transparency = transparency;\n      this.gloss = gloss;\n      this.density = density;\n      this.hasTexture = true;\n    },\n\n    getColor: function (u, v) {\n      var t = this.wrapUp(u * this.density) * this.wrapUp(v * this.density);\n\n      if (t < 0.0) return this.colorEven;\n      else return this.colorOdd;\n    },\n\n    toString: function () {\n      return (\n        \"ChessMaterial [gloss=\" +\n        this.gloss +\n        \", transparency=\" +\n        this.transparency +\n        \", hasTexture=\" +\n        this.hasTexture +\n        \"]\"\n      );\n    },\n  }\n);\n/* Fake a Flog.* namespace */\nif (typeof Flog == \"undefined\") var Flog = {};\nif (typeof Flog.RayTracer == \"undefined\") Flog.RayTracer = {};\nif (typeof Flog.RayTracer.Shape == \"undefined\") Flog.RayTracer.Shape = {};\n\nFlog.RayTracer.Shape.Sphere = Class.create();\n\nFlog.RayTracer.Shape.Sphere.prototype = {\n  initialize: function (pos, radius, material) {\n    this.radius = radius;\n    this.position = pos;\n    this.material = material;\n  },\n\n  intersect: function (ray) {\n    var info = new Flog.RayTracer.IntersectionInfo();\n    info.shape = this;\n\n    var dst = Flog.RayTracer.Vector.prototype.subtract(\n      ray.position,\n      this.position\n    );\n\n    var B = dst.dot(ray.direction);\n    var C = dst.dot(dst) - this.radius * this.radius;\n    var D = B * B - C;\n\n    if (D > 0) {\n      // intersection!\n      info.isHit = true;\n      info.distance = -B - Math.sqrt(D);\n      info.position = Flog.RayTracer.Vector.prototype.add(\n        ray.position,\n        Flog.RayTracer.Vector.prototype.multiplyScalar(\n          ray.direction,\n          info.distance\n        )\n      );\n      info.normal = Flog.RayTracer.Vector.prototype\n        .subtract(info.position, this.position)\n        .normalize();\n\n      info.color = this.material.getColor(0, 0);\n    } else {\n      info.isHit = false;\n    }\n    return info;\n  },\n\n  toString: function () {\n    return (\n      \"Sphere [position=\" + this.position + \", radius=\" + this.radius + \"]\"\n    );\n  },\n};\n/* Fake a Flog.* namespace */\nif (typeof Flog == \"undefined\") var Flog = {};\nif (typeof Flog.RayTracer == \"undefined\") Flog.RayTracer = {};\nif (typeof Flog.RayTracer.Shape == \"undefined\") Flog.RayTracer.Shape = {};\n\nFlog.RayTracer.Shape.Plane = Class.create();\n\nFlog.RayTracer.Shape.Plane.prototype = {\n  d: 0.0,\n\n  initialize: function (pos, d, material) {\n    this.position = pos;\n    this.d = d;\n    this.material = material;\n  },\n\n  intersect: function (ray) {\n    var info = new Flog.RayTracer.IntersectionInfo();\n\n    var Vd = this.position.dot(ray.direction);\n    if (Vd == 0) return info; // no intersection\n\n    var t = -(this.position.dot(ray.position) + this.d) / Vd;\n    if (t <= 0) return info;\n\n    info.shape = this;\n    info.isHit = true;\n    info.position = Flog.RayTracer.Vector.prototype.add(\n      ray.position,\n      Flog.RayTracer.Vector.prototype.multiplyScalar(ray.direction, t)\n    );\n    info.normal = this.position;\n    info.distance = t;\n\n    if (this.material.hasTexture) {\n      var vU = new Flog.RayTracer.Vector(\n        this.position.y,\n        this.position.z,\n        -this.position.x\n      );\n      var vV = vU.cross(this.position);\n      var u = info.position.dot(vU);\n      var v = info.position.dot(vV);\n      info.color = this.material.getColor(u, v);\n    } else {\n      info.color = this.material.getColor(0, 0);\n    }\n\n    return info;\n  },\n\n  toString: function () {\n    return \"Plane [\" + this.position + \", d=\" + this.d + \"]\";\n  },\n};\n/* Fake a Flog.* namespace */\nif (typeof Flog == \"undefined\") var Flog = {};\nif (typeof Flog.RayTracer == \"undefined\") Flog.RayTracer = {};\n\nFlog.RayTracer.IntersectionInfo = Class.create();\n\nFlog.RayTracer.IntersectionInfo.prototype = {\n  isHit: false,\n  hitCount: 0,\n  shape: null,\n  position: null,\n  normal: null,\n  color: null,\n  distance: null,\n\n  initialize: function () {\n    this.color = new Flog.RayTracer.Color(0, 0, 0);\n  },\n\n  toString: function () {\n    return \"Intersection [\" + this.position + \"]\";\n  },\n};\n/* Fake a Flog.* namespace */\nif (typeof Flog == \"undefined\") var Flog = {};\nif (typeof Flog.RayTracer == \"undefined\") Flog.RayTracer = {};\n\nFlog.RayTracer.Camera = Class.create();\n\nFlog.RayTracer.Camera.prototype = {\n  position: null,\n  lookAt: null,\n  equator: null,\n  up: null,\n  screen: null,\n\n  initialize: function (pos, lookAt, up) {\n    this.position = pos;\n    this.lookAt = lookAt;\n    this.up = up;\n    this.equator = lookAt.normalize().cross(this.up);\n    this.screen = Flog.RayTracer.Vector.prototype.add(\n      this.position,\n      this.lookAt\n    );\n  },\n\n  getRay: function (vx, vy) {\n    var pos = Flog.RayTracer.Vector.prototype.subtract(\n      this.screen,\n      Flog.RayTracer.Vector.prototype.subtract(\n        Flog.RayTracer.Vector.prototype.multiplyScalar(this.equator, vx),\n        Flog.RayTracer.Vector.prototype.multiplyScalar(this.up, vy)\n      )\n    );\n    pos.y = pos.y * -1;\n    var dir = Flog.RayTracer.Vector.prototype.subtract(pos, this.position);\n\n    var ray = new Flog.RayTracer.Ray(pos, dir.normalize());\n\n    return ray;\n  },\n\n  toString: function () {\n    return \"Ray []\";\n  },\n};\n/* Fake a Flog.* namespace */\nif (typeof Flog == \"undefined\") var Flog = {};\nif (typeof Flog.RayTracer == \"undefined\") Flog.RayTracer = {};\n\nFlog.RayTracer.Background = Class.create();\n\nFlog.RayTracer.Background.prototype = {\n  color: null,\n  ambience: 0.0,\n\n  initialize: function (color, ambience) {\n    this.color = color;\n    this.ambience = ambience;\n  },\n};\n/* Fake a Flog.* namespace */\nif (typeof Flog == \"undefined\") var Flog = {};\nif (typeof Flog.RayTracer == \"undefined\") Flog.RayTracer = {};\n\nFlog.RayTracer.Engine = Class.create();\n\nFlog.RayTracer.Engine.prototype = {\n  canvas: null /* 2d context we can render to */,\n\n  initialize: function (options) {\n    this.options = Object.extend(\n      {\n        canvasHeight: 100,\n        canvasWidth: 100,\n        pixelWidth: 2,\n        pixelHeight: 2,\n        renderDiffuse: false,\n        renderShadows: false,\n        renderHighlights: false,\n        renderReflections: false,\n        rayDepth: 2,\n      },\n      options || {}\n    );\n\n    this.options.canvasHeight /= this.options.pixelHeight;\n    this.options.canvasWidth /= this.options.pixelWidth;\n\n    /* TODO: dynamically include other scripts */\n  },\n\n  setPixel: function (x, y, color) {\n    var pxW, pxH;\n    pxW = this.options.pixelWidth;\n    pxH = this.options.pixelHeight;\n\n    if (this.canvas) {\n      this.canvas.fillStyle = color.toString();\n      this.canvas.fillRect(x * pxW, y * pxH, pxW, pxH);\n    } else {\n      if (x === y) {\n        checkNumber += color.brightness();\n      }\n      // print(x * pxW, y * pxH, pxW, pxH);\n    }\n  },\n\n  renderScene: function (scene, canvas) {\n    checkNumber = 0;\n    /* Get canvas */\n    if (canvas) {\n      this.canvas = canvas.getContext(\"2d\");\n    } else {\n      this.canvas = null;\n    }\n\n    var canvasHeight = this.options.canvasHeight;\n    var canvasWidth = this.options.canvasWidth;\n\n    for (var y = 0; y < canvasHeight; y++) {\n      for (var x = 0; x < canvasWidth; x++) {\n        var yp = ((y * 1.0) / canvasHeight) * 2 - 1;\n        var xp = ((x * 1.0) / canvasWidth) * 2 - 1;\n\n        var ray = scene.camera.getRay(xp, yp);\n\n        var color = this.getPixelColor(ray, scene);\n\n        this.setPixel(x, y, color);\n      }\n    }\n    if (checkNumber !== 2321) {\n      throw new Error(\"Scene rendered incorrectly\");\n    }\n  },\n\n  getPixelColor: function (ray, scene) {\n    var info = this.testIntersection(ray, scene, null);\n    if (info.isHit) {\n      var color = this.rayTrace(info, ray, scene, 0);\n      return color;\n    }\n    return scene.background.color;\n  },\n\n  testIntersection: function (ray, scene, exclude) {\n    var hits = 0;\n    var best = new Flog.RayTracer.IntersectionInfo();\n    best.distance = 2000;\n\n    for (var i = 0; i < scene.shapes.length; i++) {\n      var shape = scene.shapes[i];\n\n      if (shape != exclude) {\n        var info = shape.intersect(ray);\n        if (info.isHit && info.distance >= 0 && info.distance < best.distance) {\n          best = info;\n          hits++;\n        }\n      }\n    }\n    best.hitCount = hits;\n    return best;\n  },\n\n  getReflectionRay: function (P, N, V) {\n    var c1 = -N.dot(V);\n    var R1 = Flog.RayTracer.Vector.prototype.add(\n      Flog.RayTracer.Vector.prototype.multiplyScalar(N, 2 * c1),\n      V\n    );\n    return new Flog.RayTracer.Ray(P, R1);\n  },\n\n  rayTrace: function (info, ray, scene, depth) {\n    // Calc ambient\n    var color = Flog.RayTracer.Color.prototype.multiplyScalar(\n      info.color,\n      scene.background.ambience\n    );\n    var oldColor = color;\n    var shininess = Math.pow(10, info.shape.material.gloss + 1);\n\n    for (var i = 0; i < scene.lights.length; i++) {\n      var light = scene.lights[i];\n\n      // Calc diffuse lighting\n      var v = Flog.RayTracer.Vector.prototype\n        .subtract(light.position, info.position)\n        .normalize();\n\n      if (this.options.renderDiffuse) {\n        var L = v.dot(info.normal);\n        if (L > 0.0) {\n          color = Flog.RayTracer.Color.prototype.add(\n            color,\n            Flog.RayTracer.Color.prototype.multiply(\n              info.color,\n              Flog.RayTracer.Color.prototype.multiplyScalar(light.color, L)\n            )\n          );\n        }\n      }\n\n      // The greater the depth the more accurate the colours, but\n      // this is exponentially (!) expensive\n      if (depth <= this.options.rayDepth) {\n        // calculate reflection ray\n        if (\n          this.options.renderReflections &&\n          info.shape.material.reflection > 0\n        ) {\n          var reflectionRay = this.getReflectionRay(\n            info.position,\n            info.normal,\n            ray.direction\n          );\n          var refl = this.testIntersection(reflectionRay, scene, info.shape);\n\n          if (refl.isHit && refl.distance > 0) {\n            refl.color = this.rayTrace(refl, reflectionRay, scene, depth + 1);\n          } else {\n            refl.color = scene.background.color;\n          }\n\n          color = Flog.RayTracer.Color.prototype.blend(\n            color,\n            refl.color,\n            info.shape.material.reflection\n          );\n        }\n\n        // Refraction\n        /* TODO */\n      }\n\n      /* Render shadows and highlights */\n\n      var shadowInfo = new Flog.RayTracer.IntersectionInfo();\n\n      if (this.options.renderShadows) {\n        var shadowRay = new Flog.RayTracer.Ray(info.position, v);\n\n        shadowInfo = this.testIntersection(shadowRay, scene, info.shape);\n        if (\n          shadowInfo.isHit &&\n          shadowInfo.shape != info.shape /*&& shadowInfo.shape.type != 'PLANE'*/\n        ) {\n          var vA = Flog.RayTracer.Color.prototype.multiplyScalar(color, 0.5);\n          var dB = 0.5 * Math.pow(shadowInfo.shape.material.transparency, 0.5);\n          color = Flog.RayTracer.Color.prototype.addScalar(vA, dB);\n        }\n      }\n\n      // Phong specular highlights\n      if (\n        this.options.renderHighlights &&\n        !shadowInfo.isHit &&\n        info.shape.material.gloss > 0\n      ) {\n        var Lv = Flog.RayTracer.Vector.prototype\n          .subtract(info.shape.position, light.position)\n          .normalize();\n\n        var E = Flog.RayTracer.Vector.prototype\n          .subtract(scene.camera.position, info.shape.position)\n          .normalize();\n\n        var H = Flog.RayTracer.Vector.prototype.subtract(E, Lv).normalize();\n\n        var glossWeight = Math.pow(Math.max(info.normal.dot(H), 0), shininess);\n        color = Flog.RayTracer.Color.prototype.add(\n          Flog.RayTracer.Color.prototype.multiplyScalar(\n            light.color,\n            glossWeight\n          ),\n          color\n        );\n      }\n    }\n    color.limit();\n    return color;\n  },\n};\n\nfunction renderScene() {\n  var scene = new Flog.RayTracer.Scene();\n\n  scene.camera = new Flog.RayTracer.Camera(\n    new Flog.RayTracer.Vector(0, 0, -15),\n    new Flog.RayTracer.Vector(-0.2, 0, 5),\n    new Flog.RayTracer.Vector(0, 1, 0)\n  );\n\n  scene.background = new Flog.RayTracer.Background(\n    new Flog.RayTracer.Color(0.5, 0.5, 0.5),\n    0.4\n  );\n\n  var sphere = new Flog.RayTracer.Shape.Sphere(\n    new Flog.RayTracer.Vector(-1.5, 1.5, 2),\n    1.5,\n    new Flog.RayTracer.Material.Solid(\n      new Flog.RayTracer.Color(0, 0.5, 0.5),\n      0.3,\n      0.0,\n      0.0,\n      2.0\n    )\n  );\n\n  var sphere1 = new Flog.RayTracer.Shape.Sphere(\n    new Flog.RayTracer.Vector(1, 0.25, 1),\n    0.5,\n    new Flog.RayTracer.Material.Solid(\n      new Flog.RayTracer.Color(0.9, 0.9, 0.9),\n      0.1,\n      0.0,\n      0.0,\n      1.5\n    )\n  );\n\n  var plane = new Flog.RayTracer.Shape.Plane(\n    new Flog.RayTracer.Vector(0.1, 0.9, -0.5).normalize(),\n    1.2,\n    new Flog.RayTracer.Material.Chessboard(\n      new Flog.RayTracer.Color(1, 1, 1),\n      new Flog.RayTracer.Color(0, 0, 0),\n      0.2,\n      0.0,\n      1.0,\n      0.7\n    )\n  );\n\n  scene.shapes.push(plane);\n  scene.shapes.push(sphere);\n  scene.shapes.push(sphere1);\n\n  var light = new Flog.RayTracer.Light(\n    new Flog.RayTracer.Vector(5, 10, -1),\n    new Flog.RayTracer.Color(0.8, 0.8, 0.8)\n  );\n\n  var light1 = new Flog.RayTracer.Light(\n    new Flog.RayTracer.Vector(-3, 5, -15),\n    new Flog.RayTracer.Color(0.8, 0.8, 0.8),\n    100\n  );\n\n  scene.lights.push(light);\n  scene.lights.push(light1);\n\n  var imageWidth = 100; // $F('imageWidth');\n  var imageHeight = 100; // $F('imageHeight');\n  var pixelSize = \"5,5\".split(\",\"); //  $F('pixelSize').split(',');\n  var renderDiffuse = true; // $F('renderDiffuse');\n  var renderShadows = true; // $F('renderShadows');\n  var renderHighlights = true; // $F('renderHighlights');\n  var renderReflections = true; // $F('renderReflections');\n  var rayDepth = 2; //$F('rayDepth');\n\n  var raytracer = new Flog.RayTracer.Engine({\n    canvasWidth: imageWidth,\n    canvasHeight: imageHeight,\n    pixelWidth: pixelSize[0],\n    pixelHeight: pixelSize[1],\n    renderDiffuse: renderDiffuse,\n    renderHighlights: renderHighlights,\n    renderShadows: renderShadows,\n    renderReflections: renderReflections,\n    rayDepth: rayDepth,\n  });\n\n  raytracer.renderScene(scene, null, 0);\n}\n"
  },
  {
    "path": "benchmarks/v8-v7/regexp.js",
    "content": "// Copyright 2010 the V8 project authors. All rights reserved.\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\n//       disclaimer in the documentation and/or other materials provided\n//       with the distribution.\n//     * Neither the name of Google Inc. nor the names of its\n//       contributors may be used to endorse or promote products derived\n//       from 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// Automatically generated on 2009-01-30. Manually updated on 2010-09-17.\n\n// This benchmark is generated by loading 50 of the most popular pages\n// on the web and logging all regexp operations performed.  Each\n// operation is given a weight that is calculated from an estimate of\n// the popularity of the pages where it occurs and the number of times\n// it is executed while loading each page.  Furthermore the literal\n// letters in the data are encoded using ROT13 in a way that does not\n// affect how the regexps match their input.  Finally the strings are\n// scrambled to exercise the regexp engine on different input strings.\n\nvar RegExp = new BenchmarkSuite(\"RegExp\", 910985, [\n  new Benchmark(\"RegExp\", RegExpRun, RegExpSetup, RegExpTearDown),\n]);\n\nvar regExpBenchmark = null;\n\nfunction RegExpSetup() {\n  regExpBenchmark = new RegExpBenchmark();\n  RegExpRun(); // run once to get system initialized\n}\n\nfunction RegExpRun() {\n  regExpBenchmark.run();\n}\n\nfunction RegExpTearDown() {\n  regExpBenchmark = null;\n}\n\n// Returns an array of n different variants of the input string str.\n// The variants are computed by randomly rotating one random\n// character.\nfunction computeInputVariants(str, n) {\n  var variants = [str];\n  for (var i = 1; i < n; i++) {\n    var pos = Math.floor(Math.random() * str.length);\n    var chr = String.fromCharCode(\n      (str.charCodeAt(pos) + Math.floor(Math.random() * 128)) % 128\n    );\n    variants[i] =\n      str.substring(0, pos) + chr + str.substring(pos + 1, str.length);\n  }\n  return variants;\n}\n\nfunction RegExpBenchmark() {\n  var re0 = /^ba/;\n  var re1 = /(((\\w+):\\/\\/)([^\\/:]*)(:(\\d+))?)?([^#?]*)(\\?([^#]*))?(#(.*))?/;\n  var re2 = /^\\s*|\\s*$/g;\n  var re3 = /\\bQBZPbageby_cynprubyqre\\b/;\n  var re4 = /,/;\n  var re5 = /\\bQBZPbageby_cynprubyqre\\b/g;\n  var re6 = /^[\\s\\xa0]+|[\\s\\xa0]+$/g;\n  var re7 = /(\\d*)(\\D*)/g;\n  var re8 = /=/;\n  var re9 = /(^|\\s)lhv\\-h(\\s|$)/;\n  var str0 =\n    \"Zbmvyyn/5.0 (Jvaqbjf; H; Jvaqbjf AG 5.1; ra-HF) NccyrJroXvg/528.9 (XUGZY, yvxr Trpxb) Puebzr/2.0.157.0 Fnsnev/528.9\";\n  var re10 = /\\#/g;\n  var re11 = /\\./g;\n  var re12 = /'/g;\n  var re13 = /\\?[\\w\\W]*(sevraqvq|punaaryvq|tebhcvq)=([^\\&\\?#]*)/i;\n  var str1 = \"Fubpxjnir Synfu 9.0  e115\";\n  var re14 = /\\s+/g;\n  var re15 = /^\\s*(\\S*(\\s+\\S+)*)\\s*$/;\n  var re16 = /(-[a-z])/i;\n\n  var s0 = computeInputVariants(\"pyvpx\", 6511);\n  var s1 = computeInputVariants(\"uggc://jjj.snprobbx.pbz/ybtva.cuc\", 1844);\n  var s2 = computeInputVariants(\"QBZPbageby_cynprubyqre\", 739);\n  var s3 = computeInputVariants(\"uggc://jjj.snprobbx.pbz/\", 598);\n  var s4 = computeInputVariants(\"uggc://jjj.snprobbx.pbz/fepu.cuc\", 454);\n  var s5 = computeInputVariants(\"qqqq, ZZZ q, llll\", 352);\n  var s6 = computeInputVariants(\"vachggrkg QBZPbageby_cynprubyqre\", 312);\n  var s7 = computeInputVariants(\n    \"/ZlFcnprUbzrcntr/Vaqrk-FvgrUbzr,10000000\",\n    282\n  );\n  var s8 = computeInputVariants(\"vachggrkg\", 177);\n  var s9 = computeInputVariants(\"528.9\", 170);\n  var s10 = computeInputVariants(\"528\", 170);\n  var s11 = computeInputVariants(\"VCPhygher=ra-HF\", 156);\n  var s12 = computeInputVariants(\"CersreerqPhygher=ra-HF\", 156);\n  var s13 = computeInputVariants(\"xrlcerff\", 144);\n  var s14 = computeInputVariants(\"521\", 139);\n  var s15 = computeInputVariants(str0, 139);\n  var s16 = computeInputVariants(\"qvi .so_zrah\", 137);\n  var s17 = computeInputVariants(\"qvi.so_zrah\", 137);\n  var s18 = computeInputVariants(\"uvqqra_ryrz\", 117);\n  var s19 = computeInputVariants(\n    \"sevraqfgre_naba=nvq%3Qn6ss9p85n868ro9s059pn854735956o3%26ers%3Q%26df%3Q%26vpgl%3QHF\",\n    95\n  );\n  var s20 = computeInputVariants(\"uggc://ubzr.zlfcnpr.pbz/vaqrk.psz\", 93);\n  var s21 = computeInputVariants(str1, 92);\n  var s22 = computeInputVariants(\"svefg\", 85);\n  var s23 = computeInputVariants(\"uggc://cebsvyr.zlfcnpr.pbz/vaqrk.psz\", 85);\n  var s24 = computeInputVariants(\"ynfg\", 85);\n  var s25 = computeInputVariants(\"qvfcynl\", 85);\n\n  function runBlock0() {\n    for (var i = 0; i < 6511; i++) {\n      re0.exec(s0[i]);\n    }\n    for (var i = 0; i < 1844; i++) {\n      re1.exec(s1[i]);\n    }\n    for (var i = 0; i < 739; i++) {\n      s2[i].replace(re2, \"\");\n    }\n    for (var i = 0; i < 598; i++) {\n      re1.exec(s3[i]);\n    }\n    for (var i = 0; i < 454; i++) {\n      re1.exec(s4[i]);\n    }\n    for (var i = 0; i < 352; i++) {\n      /qqqq|qqq|qq|q|ZZZZ|ZZZ|ZZ|Z|llll|ll|l|uu|u|UU|U|zz|z|ff|f|gg|g|sss|ss|s|mmm|mm|m/g.exec(\n        s5[i]\n      );\n    }\n    for (var i = 0; i < 312; i++) {\n      re3.exec(s6[i]);\n    }\n    for (var i = 0; i < 282; i++) {\n      re4.exec(s7[i]);\n    }\n    for (var i = 0; i < 177; i++) {\n      s8[i].replace(re5, \"\");\n    }\n    for (var i = 0; i < 170; i++) {\n      s9[i].replace(re6, \"\");\n      re7.exec(s10[i]);\n    }\n    for (var i = 0; i < 156; i++) {\n      re8.exec(s11[i]);\n      re8.exec(s12[i]);\n    }\n    for (var i = 0; i < 144; i++) {\n      re0.exec(s13[i]);\n    }\n    for (var i = 0; i < 139; i++) {\n      s14[i].replace(re6, \"\");\n      re7.exec(s14[i]);\n      re9.exec(\"\");\n      /JroXvg\\/(\\S+)/.exec(s15[i]);\n    }\n    for (var i = 0; i < 137; i++) {\n      s16[i].replace(re10, \"\");\n      s16[i].replace(/\\[/g, \"\");\n      s17[i].replace(re11, \"\");\n    }\n    for (var i = 0; i < 117; i++) {\n      s18[i].replace(re2, \"\");\n    }\n    for (var i = 0; i < 95; i++) {\n      /(?:^|;)\\s*sevraqfgre_ynat=([^;]*)/.exec(s19[i]);\n    }\n    for (var i = 0; i < 93; i++) {\n      s20[i].replace(re12, \"\");\n      re13.exec(s20[i]);\n    }\n    for (var i = 0; i < 92; i++) {\n      s21[i].replace(/([a-zA-Z]|\\s)+/, \"\");\n    }\n    for (var i = 0; i < 85; i++) {\n      s22[i].replace(re14, \"\");\n      s22[i].replace(re15, \"\");\n      s23[i].replace(re12, \"\");\n      s24[i].replace(re14, \"\");\n      s24[i].replace(re15, \"\");\n      re16.exec(s25[i]);\n      re13.exec(s23[i]);\n    }\n  }\n  var re17 = /(^|[^\\\\])\\\"\\\\\\/Qngr\\((-?[0-9]+)\\)\\\\\\/\\\"/g;\n  var str2 =\n    '{\"anzr\":\"\",\"ahzoreSbezng\":{\"PheeraplQrpvznyQvtvgf\":2,\"PheeraplQrpvznyFrcnengbe\":\".\",\"VfErnqBayl\":gehr,\"PheeraplTebhcFvmrf\":[3],\"AhzoreTebhcFvmrf\":[3],\"CrepragTebhcFvmrf\":[3],\"PheeraplTebhcFrcnengbe\":\",\",\"PheeraplFlzoby\":\"\\xa4\",\"AnAFlzoby\":\"AnA\",\"PheeraplArtngvirCnggrea\":0,\"AhzoreArtngvirCnggrea\":1,\"CrepragCbfvgvirCnggrea\":0,\"CrepragArtngvirCnggrea\":0,\"ArtngvirVasvavglFlzoby\":\"-Vasvavgl\",\"ArtngvirFvta\":\"-\",\"AhzoreQrpvznyQvtvgf\":2,\"AhzoreQrpvznyFrcnengbe\":\".\",\"AhzoreTebhcFrcnengbe\":\",\",\"PheeraplCbfvgvirCnggrea\":0,\"CbfvgvirVasvavglFlzoby\":\"Vasvavgl\",\"CbfvgvirFvta\":\"+\",\"CrepragQrpvznyQvtvgf\":2,\"CrepragQrpvznyFrcnengbe\":\".\",\"CrepragTebhcFrcnengbe\":\",\",\"CrepragFlzoby\":\"%\",\"CreZvyyrFlzoby\":\"\\u2030\",\"AngvirQvtvgf\":[\"0\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\"],\"QvtvgFhofgvghgvba\":1},\"qngrGvzrSbezng\":{\"NZQrfvtangbe\":\"NZ\",\"Pnyraqne\":{\"ZvaFhccbegrqQngrGvzr\":\"@-62135568000000@\",\"ZnkFhccbegrqQngrGvzr\":\"@253402300799999@\",\"NytbevguzGlcr\":1,\"PnyraqneGlcr\":1,\"Renf\":[1],\"GjbQvtvgLrneZnk\":2029,\"VfErnqBayl\":gehr},\"QngrFrcnengbe\":\"/\",\"SvefgQnlBsJrrx\":0,\"PnyraqneJrrxEhyr\":0,\"ShyyQngrGvzrCnggrea\":\"qqqq, qq ZZZZ llll UU:zz:ff\",\"YbatQngrCnggrea\":\"qqqq, qq ZZZZ llll\",\"YbatGvzrCnggrea\":\"UU:zz:ff\",\"ZbaguQnlCnggrea\":\"ZZZZ qq\",\"CZQrfvtangbe\":\"CZ\",\"ESP1123Cnggrea\":\"qqq, qq ZZZ llll UU\\':\\'zz\\':\\'ff \\'TZG\\'\",\"FubegQngrCnggrea\":\"ZZ/qq/llll\",\"FubegGvzrCnggrea\":\"UU:zz\",\"FbegnoyrQngrGvzrCnggrea\":\"llll\\'-\\'ZZ\\'-\\'qq\\'G\\'UU\\':\\'zz\\':\\'ff\",\"GvzrFrcnengbe\":\":\",\"HavirefnyFbegnoyrQngrGvzrCnggrea\":\"llll\\'-\\'ZZ\\'-\\'qq UU\\':\\'zz\\':\\'ff\\'M\\'\",\"LrneZbaguCnggrea\":\"llll ZZZZ\",\"NooerivngrqQnlAnzrf\":[\"Fha\",\"Zba\",\"Ghr\",\"Jrq\",\"Guh\",\"Sev\",\"Fng\"],\"FubegrfgQnlAnzrf\":[\"Fh\",\"Zb\",\"Gh\",\"Jr\",\"Gu\",\"Se\",\"Fn\"],\"QnlAnzrf\":[\"Fhaqnl\",\"Zbaqnl\",\"Ghrfqnl\",\"Jrqarfqnl\",\"Guhefqnl\",\"Sevqnl\",\"Fngheqnl\"],\"NooerivngrqZbaguAnzrf\":[\"Wna\",\"Sro\",\"Zne\",\"Nce\",\"Znl\",\"Wha\",\"Why\",\"Nht\",\"Frc\",\"Bpg\",\"Abi\",\"Qrp\",\"\"],\"ZbaguAnzrf\":[\"Wnahnel\",\"Sroehnel\",\"Znepu\",\"Ncevy\",\"Znl\",\"Whar\",\"Whyl\",\"Nhthfg\",\"Frcgrzore\",\"Bpgbore\",\"Abirzore\",\"Qrprzore\",\"\"],\"VfErnqBayl\":gehr,\"AngvirPnyraqneAnzr\":\"Tertbevna Pnyraqne\",\"NooerivngrqZbaguTravgvirAnzrf\":[\"Wna\",\"Sro\",\"Zne\",\"Nce\",\"Znl\",\"Wha\",\"Why\",\"Nht\",\"Frc\",\"Bpg\",\"Abi\",\"Qrp\",\"\"],\"ZbaguTravgvirAnzrf\":[\"Wnahnel\",\"Sroehnel\",\"Znepu\",\"Ncevy\",\"Znl\",\"Whar\",\"Whyl\",\"Nhthfg\",\"Frcgrzore\",\"Bpgbore\",\"Abirzore\",\"Qrprzore\",\"\"]}}';\n  var str3 =\n    '{\"anzr\":\"ra-HF\",\"ahzoreSbezng\":{\"PheeraplQrpvznyQvtvgf\":2,\"PheeraplQrpvznyFrcnengbe\":\".\",\"VfErnqBayl\":snyfr,\"PheeraplTebhcFvmrf\":[3],\"AhzoreTebhcFvmrf\":[3],\"CrepragTebhcFvmrf\":[3],\"PheeraplTebhcFrcnengbe\":\",\",\"PheeraplFlzoby\":\"$\",\"AnAFlzoby\":\"AnA\",\"PheeraplArtngvirCnggrea\":0,\"AhzoreArtngvirCnggrea\":1,\"CrepragCbfvgvirCnggrea\":0,\"CrepragArtngvirCnggrea\":0,\"ArtngvirVasvavglFlzoby\":\"-Vasvavgl\",\"ArtngvirFvta\":\"-\",\"AhzoreQrpvznyQvtvgf\":2,\"AhzoreQrpvznyFrcnengbe\":\".\",\"AhzoreTebhcFrcnengbe\":\",\",\"PheeraplCbfvgvirCnggrea\":0,\"CbfvgvirVasvavglFlzoby\":\"Vasvavgl\",\"CbfvgvirFvta\":\"+\",\"CrepragQrpvznyQvtvgf\":2,\"CrepragQrpvznyFrcnengbe\":\".\",\"CrepragTebhcFrcnengbe\":\",\",\"CrepragFlzoby\":\"%\",\"CreZvyyrFlzoby\":\"\\u2030\",\"AngvirQvtvgf\":[\"0\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\"],\"QvtvgFhofgvghgvba\":1},\"qngrGvzrSbezng\":{\"NZQrfvtangbe\":\"NZ\",\"Pnyraqne\":{\"ZvaFhccbegrqQngrGvzr\":\"@-62135568000000@\",\"ZnkFhccbegrqQngrGvzr\":\"@253402300799999@\",\"NytbevguzGlcr\":1,\"PnyraqneGlcr\":1,\"Renf\":[1],\"GjbQvtvgLrneZnk\":2029,\"VfErnqBayl\":snyfr},\"QngrFrcnengbe\":\"/\",\"SvefgQnlBsJrrx\":0,\"PnyraqneJrrxEhyr\":0,\"ShyyQngrGvzrCnggrea\":\"qqqq, ZZZZ qq, llll u:zz:ff gg\",\"YbatQngrCnggrea\":\"qqqq, ZZZZ qq, llll\",\"YbatGvzrCnggrea\":\"u:zz:ff gg\",\"ZbaguQnlCnggrea\":\"ZZZZ qq\",\"CZQrfvtangbe\":\"CZ\",\"ESP1123Cnggrea\":\"qqq, qq ZZZ llll UU\\':\\'zz\\':\\'ff \\'TZG\\'\",\"FubegQngrCnggrea\":\"Z/q/llll\",\"FubegGvzrCnggrea\":\"u:zz gg\",\"FbegnoyrQngrGvzrCnggrea\":\"llll\\'-\\'ZZ\\'-\\'qq\\'G\\'UU\\':\\'zz\\':\\'ff\",\"GvzrFrcnengbe\":\":\",\"HavirefnyFbegnoyrQngrGvzrCnggrea\":\"llll\\'-\\'ZZ\\'-\\'qq UU\\':\\'zz\\':\\'ff\\'M\\'\",\"LrneZbaguCnggrea\":\"ZZZZ, llll\",\"NooerivngrqQnlAnzrf\":[\"Fha\",\"Zba\",\"Ghr\",\"Jrq\",\"Guh\",\"Sev\",\"Fng\"],\"FubegrfgQnlAnzrf\":[\"Fh\",\"Zb\",\"Gh\",\"Jr\",\"Gu\",\"Se\",\"Fn\"],\"QnlAnzrf\":[\"Fhaqnl\",\"Zbaqnl\",\"Ghrfqnl\",\"Jrqarfqnl\",\"Guhefqnl\",\"Sevqnl\",\"Fngheqnl\"],\"NooerivngrqZbaguAnzrf\":[\"Wna\",\"Sro\",\"Zne\",\"Nce\",\"Znl\",\"Wha\",\"Why\",\"Nht\",\"Frc\",\"Bpg\",\"Abi\",\"Qrp\",\"\"],\"ZbaguAnzrf\":[\"Wnahnel\",\"Sroehnel\",\"Znepu\",\"Ncevy\",\"Znl\",\"Whar\",\"Whyl\",\"Nhthfg\",\"Frcgrzore\",\"Bpgbore\",\"Abirzore\",\"Qrprzore\",\"\"],\"VfErnqBayl\":snyfr,\"AngvirPnyraqneAnzr\":\"Tertbevna Pnyraqne\",\"NooerivngrqZbaguTravgvirAnzrf\":[\"Wna\",\"Sro\",\"Zne\",\"Nce\",\"Znl\",\"Wha\",\"Why\",\"Nht\",\"Frc\",\"Bpg\",\"Abi\",\"Qrp\",\"\"],\"ZbaguTravgvirAnzrf\":[\"Wnahnel\",\"Sroehnel\",\"Znepu\",\"Ncevy\",\"Znl\",\"Whar\",\"Whyl\",\"Nhthfg\",\"Frcgrzore\",\"Bpgbore\",\"Abirzore\",\"Qrprzore\",\"\"]}}';\n  var str4 =\n    \"HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q\";\n  var str5 =\n    \"HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=\";\n  var re18 = /^\\s+|\\s+$/g;\n  var str6 = \"uggc://jjj.snprobbx.pbz/vaqrk.cuc\";\n  var re19 = /(?:^|\\s+)ba(?:\\s+|$)/;\n  var re20 = /[+, ]/;\n  var re21 = /ybnqrq|pbzcyrgr/;\n  var str7 =\n    ';;jvaqbj.IjPurpxZbhfrCbfvgvbaNQ_VQ=shapgvba(r){vs(!r)ine r=jvaqbj.rirag;ine c=-1;vs(d1)c=d1.EbyybssCnary;ine bo=IjTrgBow(\"IjCnayNQ_VQ_\"+c);vs(bo&&bo.fglyr.ivfvovyvgl==\"ivfvoyr\"){ine fns=IjFns?8:0;ine pheK=r.pyvragK+IjBOFpe(\"U\")+fns,pheL=r.pyvragL+IjBOFpe(\"I\")+fns;ine y=IjBOEC(NQ_VQ,bo,\"Y\"),g=IjBOEC(NQ_VQ,bo,\"G\");ine e=y+d1.Cnaryf[c].Jvqgu,o=g+d1.Cnaryf[c].Urvtug;vs((pheK<y)||(pheK>e)||(pheL<g)||(pheL>o)){vs(jvaqbj.IjBaEbyybssNQ_VQ)IjBaEbyybssNQ_VQ(c);ryfr IjPybfrNq(NQ_VQ,c,gehr,\"\");}ryfr erghea;}IjPnapryZbhfrYvfgrareNQ_VQ();};;jvaqbj.IjFrgEbyybssCnaryNQ_VQ=shapgvba(c){ine z=\"zbhfrzbir\",q=qbphzrag,s=IjPurpxZbhfrCbfvgvbaNQ_VQ;c=IjTc(NQ_VQ,c);vs(d1&&d1.EbyybssCnary>-1)IjPnapryZbhfrYvfgrareNQ_VQ();vs(d1)d1.EbyybssCnary=c;gel{vs(q.nqqRiragYvfgrare)q.nqqRiragYvfgrare(z,s,snyfr);ryfr vs(q.nggnpuRirag)q.nggnpuRirag(\"ba\"+z,s);}pngpu(r){}};;jvaqbj.IjPnapryZbhfrYvfgrareNQ_VQ=shapgvba(){ine z=\"zbhfrzbir\",q=qbphzrag,s=IjPurpxZbhfrCbfvgvbaNQ_VQ;vs(d1)d1.EbyybssCnary=-1;gel{vs(q.erzbirRiragYvfgrare)q.erzbirRiragYvfgrare(z,s,snyfr);ryfr vs(q.qrgnpuRirag)q.qrgnpuRirag(\"ba\"+z,s);}pngpu(r){}};;d1.IjTc=d2(n,c){ine nq=d1;vs(vfAnA(c)){sbe(ine v=0;v<nq.Cnaryf.yratgu;v++)vs(nq.Cnaryf[v].Anzr==c)erghea v;erghea 0;}erghea c;};;d1.IjTpy=d2(n,c,p){ine cn=d1.Cnaryf[IjTc(n,c)];vs(!cn)erghea 0;vs(vfAnA(p)){sbe(ine v=0;v<cn.Pyvpxguehf.yratgu;v++)vs(cn.Pyvpxguehf[v].Anzr==p)erghea v;erghea 0;}erghea p;};;d1.IjGenpr=d2(n,f){gel{vs(jvaqbj[\"Ij\"+\"QtQ\"])jvaqbj[\"Ij\"+\"QtQ\"](n,1,f);}pngpu(r){}};;d1.IjYvzvg1=d2(n,f){ine nq=d1,vh=f.fcyvg(\"/\");sbe(ine v=0,p=0;v<vh.yratgu;v++){vs(vh[v].yratgu>0){vs(nq.FzV.yratgu>0)nq.FzV+=\"/\";nq.FzV+=vh[v];nq.FtZ[nq.FtZ.yratgu]=snyfr;}}};;d1.IjYvzvg0=d2(n,f){ine nq=d1,vh=f.fcyvg(\"/\");sbe(ine v=0;v<vh.yratgu;v++){vs(vh[v].yratgu>0){vs(nq.OvC.yratgu>0)nq.OvC+=\"/\";nq.OvC+=vh[v];}}};;d1.IjRVST=d2(n,c){jvaqbj[\"IjCnayNQ_VQ_\"+c+\"_Bow\"]=IjTrgBow(\"IjCnayNQ_VQ_\"+c+\"_Bow\");vs(jvaqbj[\"IjCnayNQ_VQ_\"+c+\"_Bow\"]==ahyy)frgGvzrbhg(\"IjRVST(NQ_VQ,\"+c+\")\",d1.rvsg);};;d1.IjNavzSHC=d2(n,c){ine nq=d1;vs(c>nq.Cnaryf.yratgu)erghea;ine cna=nq.Cnaryf[c],nn=gehr,on=gehr,yn=gehr,en=gehr,cn=nq.Cnaryf[0],sf=nq.ShF,j=cn.Jvqgu,u=cn.Urvtug;vs(j==\"100%\"){j=sf;en=snyfr;yn=snyfr;}vs(u==\"100%\"){u=sf;nn=snyfr;on=snyfr;}vs(cn.YnY==\"Y\")yn=snyfr;vs(cn.YnY==\"E\")en=snyfr;vs(cn.GnY==\"G\")nn=snyfr;vs(cn.GnY==\"O\")on=snyfr;ine k=0,l=0;fjvgpu(nq.NshP%8){pnfr 0:oernx;pnfr 1:vs(nn)l=-sf;oernx;pnfr 2:k=j-sf;oernx;pnfr 3:vs(en)k=j;oernx;pnfr 4:k=j-sf;l=u-sf;oernx;pnfr 5:k=j-sf;vs(on)l=u;oernx;pnfr 6:l=u-sf;oernx;pnfr 7:vs(yn)k=-sf;l=u-sf;oernx;}vs(nq.NshP++ <nq.NshG)frgGvzrbhg((\"IjNavzSHC(NQ_VQ,\"+c+\")\"),nq.NshC);ryfr{k=-1000;l=k;}cna.YrsgBssfrg=k;cna.GbcBssfrg=l;IjNhErcb(n,c);};;d1.IjTrgErnyCbfvgvba=d2(n,b,j){erghea IjBOEC.nccyl(guvf,nethzragf);};;d1.IjPnapryGvzrbhg=d2(n,c){c=IjTc(n,c);ine cay=d1.Cnaryf[c];vs(cay&&cay.UgU!=\"\"){pyrneGvzrbhg(cay.UgU);}};;d1.IjPnapryNyyGvzrbhgf=d2(n){vs(d1.YbpxGvzrbhgPunatrf)erghea;sbe(ine c=0;c<d1.bac;c++)IjPnapryGvzrbhg(n,c);};;d1.IjFgnegGvzrbhg=d2(n,c,bG){c=IjTc(n,c);ine cay=d1.Cnaryf[c];vs(cay&&((cay.UvqrGvzrbhgInyhr>0)||(nethzragf.yratgu==3&&bG>0))){pyrneGvzrbhg(cay.UgU);cay.UgU=frgGvzrbhg(cay.UvqrNpgvba,(nethzragf.yratgu==3?bG:cay.UvqrGvzrbhgInyhr));}};;d1.IjErfrgGvzrbhg=d2(n,c,bG){c=IjTc(n,c);IjPnapryGvzrbhg(n,c);riny(\"IjFgnegGvzrbhg(NQ_VQ,c\"+(nethzragf.yratgu==3?\",bG\":\"\")+\")\");};;d1.IjErfrgNyyGvzrbhgf=d2(n){sbe(ine c=0;c<d1.bac;c++)IjErfrgGvzrbhg(n,c);};;d1.IjQrgnpure=d2(n,rig,sap){gel{vs(IjQVR5)riny(\"jvaqbj.qrgnpuRirag(\\'ba\"+rig+\"\\',\"+sap+\"NQ_VQ)\");ryfr vs(!IjQVRZnp)riny(\"jvaqbj.erzbirRiragYvfgrare(\\'\"+rig+\"\\',\"+sap+\"NQ_VQ,snyfr)\");}pngpu(r){}};;d1.IjPyrnaHc=d2(n){IjCvat(n,\"G\");ine nq=d1;sbe(ine v=0;v<nq.Cnaryf.yratgu;v++){IjUvqrCnary(n,v,gehr);}gel{IjTrgBow(nq.gya).vaareUGZY=\"\";}pngpu(r){}vs(nq.gya!=nq.gya2)gel{IjTrgBow(nq.gya2).vaareUGZY=\"\";}pngpu(r){}gel{d1=ahyy;}pngpu(r){}gel{IjQrgnpure(n,\"haybnq\",\"IjHayNQ_VQ\");}pngpu(r){}gel{jvaqbj.IjHayNQ_VQ=ahyy;}pngpu(r){}gel{IjQrgnpure(n,\"fpebyy\",\"IjFeNQ_VQ\");}pngpu(r){}gel{jvaqbj.IjFeNQ_VQ=ahyy;}pngpu(r){}gel{IjQrgnpure(n,\"erfvmr\",\"IjEmNQ_VQ\");}pngpu(r){}gel{jvaqbj.IjEmNQ_VQ=ahyy;}pngpu(r){}gel{IjQrgnpure(n';\n  var str8 =\n    ';;jvaqbj.IjPurpxZbhfrCbfvgvbaNQ_VQ=shapgvba(r){vs(!r)ine r=jvaqbj.rirag;ine c=-1;vs(jvaqbj.IjNqNQ_VQ)c=jvaqbj.IjNqNQ_VQ.EbyybssCnary;ine bo=IjTrgBow(\"IjCnayNQ_VQ_\"+c);vs(bo&&bo.fglyr.ivfvovyvgl==\"ivfvoyr\"){ine fns=IjFns?8:0;ine pheK=r.pyvragK+IjBOFpe(\"U\")+fns,pheL=r.pyvragL+IjBOFpe(\"I\")+fns;ine y=IjBOEC(NQ_VQ,bo,\"Y\"),g=IjBOEC(NQ_VQ,bo,\"G\");ine e=y+jvaqbj.IjNqNQ_VQ.Cnaryf[c].Jvqgu,o=g+jvaqbj.IjNqNQ_VQ.Cnaryf[c].Urvtug;vs((pheK<y)||(pheK>e)||(pheL<g)||(pheL>o)){vs(jvaqbj.IjBaEbyybssNQ_VQ)IjBaEbyybssNQ_VQ(c);ryfr IjPybfrNq(NQ_VQ,c,gehr,\"\");}ryfr erghea;}IjPnapryZbhfrYvfgrareNQ_VQ();};;jvaqbj.IjFrgEbyybssCnaryNQ_VQ=shapgvba(c){ine z=\"zbhfrzbir\",q=qbphzrag,s=IjPurpxZbhfrCbfvgvbaNQ_VQ;c=IjTc(NQ_VQ,c);vs(jvaqbj.IjNqNQ_VQ&&jvaqbj.IjNqNQ_VQ.EbyybssCnary>-1)IjPnapryZbhfrYvfgrareNQ_VQ();vs(jvaqbj.IjNqNQ_VQ)jvaqbj.IjNqNQ_VQ.EbyybssCnary=c;gel{vs(q.nqqRiragYvfgrare)q.nqqRiragYvfgrare(z,s,snyfr);ryfr vs(q.nggnpuRirag)q.nggnpuRirag(\"ba\"+z,s);}pngpu(r){}};;jvaqbj.IjPnapryZbhfrYvfgrareNQ_VQ=shapgvba(){ine z=\"zbhfrzbir\",q=qbphzrag,s=IjPurpxZbhfrCbfvgvbaNQ_VQ;vs(jvaqbj.IjNqNQ_VQ)jvaqbj.IjNqNQ_VQ.EbyybssCnary=-1;gel{vs(q.erzbirRiragYvfgrare)q.erzbirRiragYvfgrare(z,s,snyfr);ryfr vs(q.qrgnpuRirag)q.qrgnpuRirag(\"ba\"+z,s);}pngpu(r){}};;jvaqbj.IjNqNQ_VQ.IjTc=shapgvba(n,c){ine nq=jvaqbj.IjNqNQ_VQ;vs(vfAnA(c)){sbe(ine v=0;v<nq.Cnaryf.yratgu;v++)vs(nq.Cnaryf[v].Anzr==c)erghea v;erghea 0;}erghea c;};;jvaqbj.IjNqNQ_VQ.IjTpy=shapgvba(n,c,p){ine cn=jvaqbj.IjNqNQ_VQ.Cnaryf[IjTc(n,c)];vs(!cn)erghea 0;vs(vfAnA(p)){sbe(ine v=0;v<cn.Pyvpxguehf.yratgu;v++)vs(cn.Pyvpxguehf[v].Anzr==p)erghea v;erghea 0;}erghea p;};;jvaqbj.IjNqNQ_VQ.IjGenpr=shapgvba(n,f){gel{vs(jvaqbj[\"Ij\"+\"QtQ\"])jvaqbj[\"Ij\"+\"QtQ\"](n,1,f);}pngpu(r){}};;jvaqbj.IjNqNQ_VQ.IjYvzvg1=shapgvba(n,f){ine nq=jvaqbj.IjNqNQ_VQ,vh=f.fcyvg(\"/\");sbe(ine v=0,p=0;v<vh.yratgu;v++){vs(vh[v].yratgu>0){vs(nq.FzV.yratgu>0)nq.FzV+=\"/\";nq.FzV+=vh[v];nq.FtZ[nq.FtZ.yratgu]=snyfr;}}};;jvaqbj.IjNqNQ_VQ.IjYvzvg0=shapgvba(n,f){ine nq=jvaqbj.IjNqNQ_VQ,vh=f.fcyvg(\"/\");sbe(ine v=0;v<vh.yratgu;v++){vs(vh[v].yratgu>0){vs(nq.OvC.yratgu>0)nq.OvC+=\"/\";nq.OvC+=vh[v];}}};;jvaqbj.IjNqNQ_VQ.IjRVST=shapgvba(n,c){jvaqbj[\"IjCnayNQ_VQ_\"+c+\"_Bow\"]=IjTrgBow(\"IjCnayNQ_VQ_\"+c+\"_Bow\");vs(jvaqbj[\"IjCnayNQ_VQ_\"+c+\"_Bow\"]==ahyy)frgGvzrbhg(\"IjRVST(NQ_VQ,\"+c+\")\",jvaqbj.IjNqNQ_VQ.rvsg);};;jvaqbj.IjNqNQ_VQ.IjNavzSHC=shapgvba(n,c){ine nq=jvaqbj.IjNqNQ_VQ;vs(c>nq.Cnaryf.yratgu)erghea;ine cna=nq.Cnaryf[c],nn=gehr,on=gehr,yn=gehr,en=gehr,cn=nq.Cnaryf[0],sf=nq.ShF,j=cn.Jvqgu,u=cn.Urvtug;vs(j==\"100%\"){j=sf;en=snyfr;yn=snyfr;}vs(u==\"100%\"){u=sf;nn=snyfr;on=snyfr;}vs(cn.YnY==\"Y\")yn=snyfr;vs(cn.YnY==\"E\")en=snyfr;vs(cn.GnY==\"G\")nn=snyfr;vs(cn.GnY==\"O\")on=snyfr;ine k=0,l=0;fjvgpu(nq.NshP%8){pnfr 0:oernx;pnfr 1:vs(nn)l=-sf;oernx;pnfr 2:k=j-sf;oernx;pnfr 3:vs(en)k=j;oernx;pnfr 4:k=j-sf;l=u-sf;oernx;pnfr 5:k=j-sf;vs(on)l=u;oernx;pnfr 6:l=u-sf;oernx;pnfr 7:vs(yn)k=-sf;l=u-sf;oernx;}vs(nq.NshP++ <nq.NshG)frgGvzrbhg((\"IjNavzSHC(NQ_VQ,\"+c+\")\"),nq.NshC);ryfr{k=-1000;l=k;}cna.YrsgBssfrg=k;cna.GbcBssfrg=l;IjNhErcb(n,c);};;jvaqbj.IjNqNQ_VQ.IjTrgErnyCbfvgvba=shapgvba(n,b,j){erghea IjBOEC.nccyl(guvf,nethzragf);};;jvaqbj.IjNqNQ_VQ.IjPnapryGvzrbhg=shapgvba(n,c){c=IjTc(n,c);ine cay=jvaqbj.IjNqNQ_VQ.Cnaryf[c];vs(cay&&cay.UgU!=\"\"){pyrneGvzrbhg(cay.UgU);}};;jvaqbj.IjNqNQ_VQ.IjPnapryNyyGvzrbhgf=shapgvba(n){vs(jvaqbj.IjNqNQ_VQ.YbpxGvzrbhgPunatrf)erghea;sbe(ine c=0;c<jvaqbj.IjNqNQ_VQ.bac;c++)IjPnapryGvzrbhg(n,c);};;jvaqbj.IjNqNQ_VQ.IjFgnegGvzrbhg=shapgvba(n,c,bG){c=IjTc(n,c);ine cay=jvaqbj.IjNqNQ_VQ.Cnaryf[c];vs(cay&&((cay.UvqrGvzrbhgInyhr>0)||(nethzragf.yratgu==3&&bG>0))){pyrneGvzrbhg(cay.UgU);cay.UgU=frgGvzrbhg(cay.UvqrNpgvba,(nethzragf.yratgu==3?bG:cay.UvqrGvzrbhgInyhr));}};;jvaqbj.IjNqNQ_VQ.IjErfrgGvzrbhg=shapgvba(n,c,bG){c=IjTc(n,c);IjPnapryGvzrbhg(n,c);riny(\"IjFgnegGvzrbhg(NQ_VQ,c\"+(nethzragf.yratgu==3?\",bG\":\"\")+\")\");};;jvaqbj.IjNqNQ_VQ.IjErfrgNyyGvzrbhgf=shapgvba(n){sbe(ine c=0;c<jvaqbj.IjNqNQ_VQ.bac;c++)IjErfrgGvzrbhg(n,c);};;jvaqbj.IjNqNQ_VQ.IjQrgnpure=shapgvba(n,rig,sap){gel{vs(IjQVR5)riny(\"jvaqbj.qrgnpuRirag(\\'ba\"+rig+\"\\',\"+sap+\"NQ_VQ)\");ryfr vs(!IjQVRZnp)riny(\"jvaqbj.erzbir';\n  var str9 =\n    ';;jvaqbj.IjPurpxZbhfrCbfvgvbaNQ_VQ=shapgvba(r){vs(!r)ine r=jvaqbj.rirag;ine c=-1;vs(jvaqbj.IjNqNQ_VQ)c=jvaqbj.IjNqNQ_VQ.EbyybssCnary;ine bo=IjTrgBow(\"IjCnayNQ_VQ_\"+c);vs(bo&&bo.fglyr.ivfvovyvgl==\"ivfvoyr\"){ine fns=IjFns?8:0;ine pheK=r.pyvragK+IjBOFpe(\"U\")+fns,pheL=r.pyvragL+IjBOFpe(\"I\")+fns;ine y=IjBOEC(NQ_VQ,bo,\"Y\"),g=IjBOEC(NQ_VQ,bo,\"G\");ine e=y+jvaqbj.IjNqNQ_VQ.Cnaryf[c].Jvqgu,o=g+jvaqbj.IjNqNQ_VQ.Cnaryf[c].Urvtug;vs((pheK<y)||(pheK>e)||(pheL<g)||(pheL>o)){vs(jvaqbj.IjBaEbyybssNQ_VQ)IjBaEbyybssNQ_VQ(c);ryfr IjPybfrNq(NQ_VQ,c,gehr,\"\");}ryfr erghea;}IjPnapryZbhfrYvfgrareNQ_VQ();};;jvaqbj.IjFrgEbyybssCnaryNQ_VQ=shapgvba(c){ine z=\"zbhfrzbir\",q=qbphzrag,s=IjPurpxZbhfrCbfvgvbaNQ_VQ;c=IjTc(NQ_VQ,c);vs(jvaqbj.IjNqNQ_VQ&&jvaqbj.IjNqNQ_VQ.EbyybssCnary>-1)IjPnapryZbhfrYvfgrareNQ_VQ();vs(jvaqbj.IjNqNQ_VQ)jvaqbj.IjNqNQ_VQ.EbyybssCnary=c;gel{vs(q.nqqRiragYvfgrare)q.nqqRiragYvfgrare(z,s,snyfr);ryfr vs(q.nggnpuRirag)q.nggnpuRirag(\"ba\"+z,s);}pngpu(r){}};;jvaqbj.IjPnapryZbhfrYvfgrareNQ_VQ=shapgvba(){ine z=\"zbhfrzbir\",q=qbphzrag,s=IjPurpxZbhfrCbfvgvbaNQ_VQ;vs(jvaqbj.IjNqNQ_VQ)jvaqbj.IjNqNQ_VQ.EbyybssCnary=-1;gel{vs(q.erzbirRiragYvfgrare)q.erzbirRiragYvfgrare(z,s,snyfr);ryfr vs(q.qrgnpuRirag)q.qrgnpuRirag(\"ba\"+z,s);}pngpu(r){}};;jvaqbj.IjNqNQ_VQ.IjTc=d2(n,c){ine nq=jvaqbj.IjNqNQ_VQ;vs(vfAnA(c)){sbe(ine v=0;v<nq.Cnaryf.yratgu;v++)vs(nq.Cnaryf[v].Anzr==c)erghea v;erghea 0;}erghea c;};;jvaqbj.IjNqNQ_VQ.IjTpy=d2(n,c,p){ine cn=jvaqbj.IjNqNQ_VQ.Cnaryf[IjTc(n,c)];vs(!cn)erghea 0;vs(vfAnA(p)){sbe(ine v=0;v<cn.Pyvpxguehf.yratgu;v++)vs(cn.Pyvpxguehf[v].Anzr==p)erghea v;erghea 0;}erghea p;};;jvaqbj.IjNqNQ_VQ.IjGenpr=d2(n,f){gel{vs(jvaqbj[\"Ij\"+\"QtQ\"])jvaqbj[\"Ij\"+\"QtQ\"](n,1,f);}pngpu(r){}};;jvaqbj.IjNqNQ_VQ.IjYvzvg1=d2(n,f){ine nq=jvaqbj.IjNqNQ_VQ,vh=f.fcyvg(\"/\");sbe(ine v=0,p=0;v<vh.yratgu;v++){vs(vh[v].yratgu>0){vs(nq.FzV.yratgu>0)nq.FzV+=\"/\";nq.FzV+=vh[v];nq.FtZ[nq.FtZ.yratgu]=snyfr;}}};;jvaqbj.IjNqNQ_VQ.IjYvzvg0=d2(n,f){ine nq=jvaqbj.IjNqNQ_VQ,vh=f.fcyvg(\"/\");sbe(ine v=0;v<vh.yratgu;v++){vs(vh[v].yratgu>0){vs(nq.OvC.yratgu>0)nq.OvC+=\"/\";nq.OvC+=vh[v];}}};;jvaqbj.IjNqNQ_VQ.IjRVST=d2(n,c){jvaqbj[\"IjCnayNQ_VQ_\"+c+\"_Bow\"]=IjTrgBow(\"IjCnayNQ_VQ_\"+c+\"_Bow\");vs(jvaqbj[\"IjCnayNQ_VQ_\"+c+\"_Bow\"]==ahyy)frgGvzrbhg(\"IjRVST(NQ_VQ,\"+c+\")\",jvaqbj.IjNqNQ_VQ.rvsg);};;jvaqbj.IjNqNQ_VQ.IjNavzSHC=d2(n,c){ine nq=jvaqbj.IjNqNQ_VQ;vs(c>nq.Cnaryf.yratgu)erghea;ine cna=nq.Cnaryf[c],nn=gehr,on=gehr,yn=gehr,en=gehr,cn=nq.Cnaryf[0],sf=nq.ShF,j=cn.Jvqgu,u=cn.Urvtug;vs(j==\"100%\"){j=sf;en=snyfr;yn=snyfr;}vs(u==\"100%\"){u=sf;nn=snyfr;on=snyfr;}vs(cn.YnY==\"Y\")yn=snyfr;vs(cn.YnY==\"E\")en=snyfr;vs(cn.GnY==\"G\")nn=snyfr;vs(cn.GnY==\"O\")on=snyfr;ine k=0,l=0;fjvgpu(nq.NshP%8){pnfr 0:oernx;pnfr 1:vs(nn)l=-sf;oernx;pnfr 2:k=j-sf;oernx;pnfr 3:vs(en)k=j;oernx;pnfr 4:k=j-sf;l=u-sf;oernx;pnfr 5:k=j-sf;vs(on)l=u;oernx;pnfr 6:l=u-sf;oernx;pnfr 7:vs(yn)k=-sf;l=u-sf;oernx;}vs(nq.NshP++ <nq.NshG)frgGvzrbhg((\"IjNavzSHC(NQ_VQ,\"+c+\")\"),nq.NshC);ryfr{k=-1000;l=k;}cna.YrsgBssfrg=k;cna.GbcBssfrg=l;IjNhErcb(n,c);};;jvaqbj.IjNqNQ_VQ.IjTrgErnyCbfvgvba=d2(n,b,j){erghea IjBOEC.nccyl(guvf,nethzragf);};;jvaqbj.IjNqNQ_VQ.IjPnapryGvzrbhg=d2(n,c){c=IjTc(n,c);ine cay=jvaqbj.IjNqNQ_VQ.Cnaryf[c];vs(cay&&cay.UgU!=\"\"){pyrneGvzrbhg(cay.UgU);}};;jvaqbj.IjNqNQ_VQ.IjPnapryNyyGvzrbhgf=d2(n){vs(jvaqbj.IjNqNQ_VQ.YbpxGvzrbhgPunatrf)erghea;sbe(ine c=0;c<jvaqbj.IjNqNQ_VQ.bac;c++)IjPnapryGvzrbhg(n,c);};;jvaqbj.IjNqNQ_VQ.IjFgnegGvzrbhg=d2(n,c,bG){c=IjTc(n,c);ine cay=jvaqbj.IjNqNQ_VQ.Cnaryf[c];vs(cay&&((cay.UvqrGvzrbhgInyhr>0)||(nethzragf.yratgu==3&&bG>0))){pyrneGvzrbhg(cay.UgU);cay.UgU=frgGvzrbhg(cay.UvqrNpgvba,(nethzragf.yratgu==3?bG:cay.UvqrGvzrbhgInyhr));}};;jvaqbj.IjNqNQ_VQ.IjErfrgGvzrbhg=d2(n,c,bG){c=IjTc(n,c);IjPnapryGvzrbhg(n,c);riny(\"IjFgnegGvzrbhg(NQ_VQ,c\"+(nethzragf.yratgu==3?\",bG\":\"\")+\")\");};;jvaqbj.IjNqNQ_VQ.IjErfrgNyyGvzrbhgf=d2(n){sbe(ine c=0;c<jvaqbj.IjNqNQ_VQ.bac;c++)IjErfrgGvzrbhg(n,c);};;jvaqbj.IjNqNQ_VQ.IjQrgnpure=d2(n,rig,sap){gel{vs(IjQVR5)riny(\"jvaqbj.qrgnpuRirag(\\'ba\"+rig+\"\\',\"+sap+\"NQ_VQ)\");ryfr vs(!IjQVRZnp)riny(\"jvaqbj.erzbirRiragYvfgrare(\\'\"+rig+\"\\',\"+sap+\"NQ_VQ,snyfr)\");}pngpu(r){}};;jvaqbj.IjNqNQ_VQ.IjPyrna';\n\n  var s26 = computeInputVariants(\"VC=74.125.75.1\", 81);\n  var s27 = computeInputVariants(\"9.0  e115\", 78);\n  var s28 = computeInputVariants(\"k\", 78);\n  var s29 = computeInputVariants(str2, 81);\n  var s30 = computeInputVariants(str3, 81);\n  var s31 = computeInputVariants(\"144631658\", 78);\n  var s32 = computeInputVariants(\"Pbhagel=IIZ%3Q\", 78);\n  var s33 = computeInputVariants(\"Pbhagel=IIZ=\", 78);\n  var s34 = computeInputVariants(\"CersreerqPhygherCraqvat=\", 78);\n  var s35 = computeInputVariants(str4, 78);\n  var s36 = computeInputVariants(str5, 78);\n  var s37 = computeInputVariants(\"__hgzp=144631658\", 78);\n  var s38 = computeInputVariants(\"gvzrMbar=-8\", 78);\n  var s39 = computeInputVariants(\"gvzrMbar=0\", 78);\n  // var s40 = computeInputVariants(s15[i], 78);\n  var s41 = computeInputVariants(\"vachggrkg  QBZPbageby_cynprubyqre\", 78);\n  var s42 = computeInputVariants(\"xrlqbja\", 78);\n  var s43 = computeInputVariants(\"xrlhc\", 78);\n  var s44 = computeInputVariants(\"uggc://zrffntvat.zlfcnpr.pbz/vaqrk.psz\", 77);\n  var s45 = computeInputVariants(\n    \"FrffvbaFgbentr=%7O%22GnoThvq%22%3N%7O%22thvq%22%3N1231367125017%7Q%7Q\",\n    73\n  );\n  var s46 = computeInputVariants(str6, 72);\n  var s47 = computeInputVariants(\"3.5.0.0\", 70);\n  var s48 = computeInputVariants(str7, 70);\n  var s49 = computeInputVariants(str8, 70);\n  var s50 = computeInputVariants(str9, 70);\n  var s51 = computeInputVariants(\n    \"NI%3Q1_CI%3Q1_PI%3Q1_EI%3Q1_HI%3Q1_HP%3Q1_IC%3Q0.0.0.0_IH%3Q0\",\n    70\n  );\n  var s52 = computeInputVariants(\n    \"svz_zlfcnpr_ubzrcntr_abgybttrqva,svz_zlfcnpr_aba_HTP,svz_zlfcnpr_havgrq-fgngrf\",\n    70\n  );\n  var s53 = computeInputVariants(\"ybnqvat\", 70);\n  var s54 = computeInputVariants(\"#\", 68);\n  var s55 = computeInputVariants(\"ybnqrq\", 68);\n  var s56 = computeInputVariants(\"pbybe\", 49);\n  var s57 = computeInputVariants(\"uggc://sevraqf.zlfcnpr.pbz/vaqrk.psz\", 44);\n\n  function runBlock1() {\n    for (var i = 0; i < 81; i++) {\n      re8.exec(s26[i]);\n    }\n    for (var i = 0; i < 78; i++) {\n      s27[i].replace(/(\\s)+e/, \"\");\n      s28[i].replace(/./, \"\");\n      s29[i].replace(re17, \"\");\n      s30[i].replace(re17, \"\");\n      re8.exec(s31[i]);\n      re8.exec(s32[i]);\n      re8.exec(s33[i]);\n      re8.exec(s34[i]);\n      re8.exec(s35[i]);\n      re8.exec(s36[i]);\n      re8.exec(s37[i]);\n      re8.exec(s38[i]);\n      re8.exec(s39[i]);\n      /Fnsnev\\/(\\d+\\.\\d+)/.exec(s15[i]);\n      re3.exec(s41[i]);\n      re0.exec(s42[i]);\n      re0.exec(s43[i]);\n    }\n    for (var i = 0; i < 77; i++) {\n      s44[i].replace(re12, \"\");\n      re13.exec(s44[i]);\n    }\n    for (var i = 0; i < 73; i++) {\n      s45[i].replace(re18, \"\");\n    }\n    for (var i = 0; i < 72; i++) {\n      re1.exec(s46[i]);\n    }\n    for (var i = 0; i < 71; i++) {\n      re19.exec(\"\");\n    }\n    for (var i = 0; i < 70; i++) {\n      s47[i].replace(re11, \"\");\n      s48[i].replace(/d1/g, \"\");\n      s49[i].replace(/NQ_VQ/g, \"\");\n      s50[i].replace(/d2/g, \"\");\n      s51[i].replace(/_/g, \"\");\n      s52[i].split(re20);\n      re21.exec(s53[i]);\n    }\n    for (var i = 0; i < 68; i++) {\n      re1.exec(s54[i]);\n      /(?:ZFVR.(\\d+\\.\\d+))|(?:(?:Sversbk|TenaCnenqvfb|Vprjrnfry).(\\d+\\.\\d+))|(?:Bcren.(\\d+\\.\\d+))|(?:NccyrJroXvg.(\\d+(?:\\.\\d+)?))/.exec(\n        s15[i]\n      );\n      /(Znp BF K)|(Jvaqbjf;)/.exec(s15[i]);\n      /Trpxb\\/([0-9]+)/.exec(s15[i]);\n      re21.exec(s55[i]);\n    }\n    for (var i = 0; i < 49; i++) {\n      re16.exec(s56[i]);\n    }\n    for (var i = 0; i < 44; i++) {\n      s57[i].replace(re12, \"\");\n      re13.exec(s57[i]);\n    }\n  }\n  var re22 = /\\bso_zrah\\b/;\n  var re23 =\n    /^(?:(?:[^:\\/?#]+):)?(?:\\/\\/(?:[^\\/?#]*))?([^?#]*)(?:\\?([^#]*))?(?:#(.*))?/;\n  var re24 = /uggcf?:\\/\\/([^\\/]+\\.)?snprobbx\\.pbz\\//;\n  var re25 = /\"/g;\n  var re26 = /^([^?#]+)(?:\\?([^#]*))?(#.*)?/;\n  var s57a = computeInputVariants(\"fryrpgrq\", 40);\n  var s58 = computeInputVariants(\"vachggrkg uvqqra_ryrz\", 40);\n  var s59 = computeInputVariants(\"vachggrkg \", 40);\n  var s60 = computeInputVariants(\"vachggrkg\", 40);\n  var s61 = computeInputVariants(\"uggc://jjj.snprobbx.pbz/\", 40);\n  var s62 = computeInputVariants(\"uggc://jjj.snprobbx.pbz/ybtva.cuc\", 40);\n  var s63 = computeInputVariants(\"Funer guvf tnqtrg\", 40);\n  var s64 = computeInputVariants(\"uggc://jjj.tbbtyr.pbz/vt/qverpgbel\", 40);\n  var s65 = computeInputVariants(\"419\", 40);\n  var s66 = computeInputVariants(\"gvzrfgnzc\", 40);\n\n  function runBlock2() {\n    for (var i = 0; i < 40; i++) {\n      s57a[i].replace(re14, \"\");\n      s57a[i].replace(re15, \"\");\n    }\n    for (var i = 0; i < 39; i++) {\n      s58[i].replace(/\\buvqqra_ryrz\\b/g, \"\");\n      re3.exec(s59[i]);\n      re3.exec(s60[i]);\n      re22.exec(\"HVYvaxOhggba\");\n      re22.exec(\"HVYvaxOhggba_E\");\n      re22.exec(\"HVYvaxOhggba_EJ\");\n      re22.exec(\"zrah_ybtva_pbagnvare\");\n      /\\buvqqra_ryrz\\b/.exec(\"vachgcnffjbeq\");\n    }\n    for (var i = 0; i < 37; i++) {\n      re8.exec(\"111soqs57qo8o8480qo18sor2011r3n591q7s6s37r120904\");\n      re8.exec(\"SbeprqRkcvengvba=633669315660164980\");\n      re8.exec(\"FrffvbaQQS2=111soqs57qo8o8480qo18sor2011r3n591q7s6s37r120904\");\n    }\n    for (var i = 0; i < 35; i++) {\n      \"puvyq p1 svefg\".replace(re14, \"\");\n      \"puvyq p1 svefg\".replace(re15, \"\");\n      \"sylbhg pybfrq\".replace(re14, \"\");\n      \"sylbhg pybfrq\".replace(re15, \"\");\n    }\n    for (var i = 0; i < 34; i++) {\n      re19.exec(\"gno2\");\n      re19.exec(\"gno3\");\n      re8.exec(\"44132r503660\");\n      re8.exec(\"SbeprqRkcvengvba=633669316860113296\");\n      re8.exec(\"AFP_zp_dfctwzs-aowb_80=44132r503660\");\n      re8.exec(\"FrffvbaQQS2=s6r4579npn4rn2135s904r0s75pp1o5334p6s6pospo12696\");\n      re8.exec(\"s6r4579npn4rn2135s904r0s75pp1o5334p6s6pospo12696\");\n    }\n    for (var i = 0; i < 32; i++) {\n      /puebzr/i.exec(s15[i]);\n    }\n    for (var i = 0; i < 31; i++) {\n      s61[i].replace(re23, \"\");\n      re8.exec(\"SbeprqRkcvengvba=633669358527244818\");\n      re8.exec(\"VC=66.249.85.130\");\n      re8.exec(\"FrffvbaQQS2=s15q53p9n372sn76npr13o271n4s3p5r29p235746p908p58\");\n      re8.exec(\"s15q53p9n372sn76npr13o271n4s3p5r29p235746p908p58\");\n      re24.exec(s61[i]);\n    }\n    for (var i = 0; i < 30; i++) {\n      s65[i].replace(re6, \"\");\n      /(?:^|\\s+)gvzrfgnzc(?:\\s+|$)/.exec(s66[i]);\n      re7.exec(s65[i]);\n    }\n    for (var i = 0; i < 29; i++) {\n      s62[i].replace(re23, \"\");\n    }\n    for (var i = 0; i < 28; i++) {\n      s63[i].replace(re25, \"\");\n      s63[i].replace(re12, \"\");\n      re26.exec(s64[i]);\n    }\n  }\n  var re27 = /-\\D/g;\n  var re28 = /\\bnpgvingr\\b/;\n  var re29 = /%2R/gi;\n  var re30 = /%2S/gi;\n  var re31 = /^(mu-(PA|GJ)|wn|xb)$/;\n  var re32 = /\\s?;\\s?/;\n  var re33 = /%\\w?$/;\n  var re34 = /TNQP=([^;]*)/i;\n  var str10 =\n    \"FrffvbaQQS2=111soqs57qo8o8480qo18sor2011r3n591q7s6s37r120904; ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669315660164980&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=\";\n  var str11 =\n    \"FrffvbaQQS2=111soqs57qo8o8480qo18sor2011r3n591q7s6s37r120904; __hgzm=144631658.1231363570.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.3426875219718084000.1231363570.1231363570.1231363570.1; __hgzo=144631658.0.10.1231363570; __hgzp=144631658; ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669315660164980&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q\";\n  var str12 =\n    \"uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_zlfcnpr-ubzrcntr_wf&qg=1231363514065&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231363514065&punaary=svz_zlfcnpr_ubzrcntr_abgybttrqva%2Psvz_zlfcnpr_aba_HTP%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Subzr.zlfcnpr.pbz%2Svaqrk.psz&nq_glcr=grkg&rvq=6083027&rn=0&sez=0&tn_ivq=1326469221.1231363557&tn_fvq=1231363557&tn_uvq=1114636509&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22\";\n  var str13 =\n    \"ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669315660164980&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q\";\n  var str14 =\n    \"ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669315660164980&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=\";\n  var re35 = /[<>]/g;\n  var str15 =\n    \"FrffvbaQQS2=s6r4579npn4rn2135s904r0s75pp1o5334p6s6pospo12696; ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669316860113296&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=; AFP_zp_dfctwzs-aowb_80=44132r503660\";\n  var str16 =\n    \"FrffvbaQQS2=s6r4579npn4rn2135s904r0s75pp1o5334p6s6pospo12696; AFP_zp_dfctwzs-aowb_80=44132r503660; __hgzm=144631658.1231363638.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.965867047679498800.1231363638.1231363638.1231363638.1; __hgzo=144631658.0.10.1231363638; __hgzp=144631658; ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669316860113296&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q\";\n  var str17 =\n    \"uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_zlfcnpr-ubzrcntr_wf&qg=1231363621014&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231363621014&punaary=svz_zlfcnpr_ubzrcntr_abgybttrqva%2Psvz_zlfcnpr_aba_HTP%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Scebsvyr.zlfcnpr.pbz%2Svaqrk.psz&nq_glcr=grkg&rvq=6083027&rn=0&sez=0&tn_ivq=348699119.1231363624&tn_fvq=1231363624&tn_uvq=895511034&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22\";\n  var str18 = \"uggc://jjj.yrobapbva.se/yv\";\n  var str19 =\n    \"ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669316860113296&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q\";\n  var str20 =\n    \"ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669316860113296&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=\";\n\n  var s67 = computeInputVariants(\"e115\", 27);\n  var s68 = computeInputVariants(\"qvfcynl\", 27);\n  var s69 = computeInputVariants(\"cbfvgvba\", 27);\n  var s70 = computeInputVariants(\"uggc://jjj.zlfcnpr.pbz/\", 27);\n  var s71 = computeInputVariants(\"cntrivrj\", 27);\n  var s72 = computeInputVariants(\"VC=74.125.75.3\", 27);\n  var s73 = computeInputVariants(\"ra\", 27);\n  var s74 = computeInputVariants(str10, 27);\n  var s75 = computeInputVariants(str11, 27);\n  var s76 = computeInputVariants(str12, 27);\n  var s77 = computeInputVariants(str17, 27);\n  var s78 = computeInputVariants(str18, 27);\n\n  function runBlock3() {\n    for (var i = 0; i < 27; i++) {\n      s67[i].replace(/[A-Za-z]/g, \"\");\n    }\n    for (var i = 0; i < 23; i++) {\n      s68[i].replace(re27, \"\");\n      s69[i].replace(re27, \"\");\n    }\n    for (var i = 0; i < 22; i++) {\n      \"unaqyr\".replace(re14, \"\");\n      \"unaqyr\".replace(re15, \"\");\n      \"yvar\".replace(re14, \"\");\n      \"yvar\".replace(re15, \"\");\n      \"cnerag puebzr6 fvatyr1 gno\".replace(re14, \"\");\n      \"cnerag puebzr6 fvatyr1 gno\".replace(re15, \"\");\n      \"fyvqre\".replace(re14, \"\");\n      \"fyvqre\".replace(re15, \"\");\n      re28.exec(\"\");\n    }\n    for (var i = 0; i < 21; i++) {\n      s70[i].replace(re12, \"\");\n      re13.exec(s70[i]);\n    }\n    for (var i = 0; i < 20; i++) {\n      s71[i].replace(re29, \"\");\n      s71[i].replace(re30, \"\");\n      re19.exec(\"ynfg\");\n      re19.exec(\"ba svefg\");\n      re8.exec(s72[i]);\n    }\n    for (var i = 0; i < 19; i++) {\n      re31.exec(s73[i]);\n    }\n    for (var i = 0; i < 18; i++) {\n      s74[i].split(re32);\n      s75[i].split(re32);\n      s76[i].replace(re33, \"\");\n      re8.exec(\"144631658.0.10.1231363570\");\n      re8.exec(\n        \"144631658.1231363570.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)\"\n      );\n      re8.exec(\n        \"144631658.3426875219718084000.1231363570.1231363570.1231363570.1\"\n      );\n      re8.exec(str13);\n      re8.exec(str14);\n      re8.exec(\n        \"__hgzn=144631658.3426875219718084000.1231363570.1231363570.1231363570.1\"\n      );\n      re8.exec(\"__hgzo=144631658.0.10.1231363570\");\n      re8.exec(\n        \"__hgzm=144631658.1231363570.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)\"\n      );\n      re34.exec(s74[i]);\n      re34.exec(s75[i]);\n    }\n    for (var i = 0; i < 17; i++) {\n      s15[i].match(/zfvr/gi);\n      s15[i].match(/bcren/gi);\n      str15.split(re32);\n      str16.split(re32);\n      \"ohggba\".replace(re14, \"\");\n      \"ohggba\".replace(re15, \"\");\n      \"puvyq p1 svefg sylbhg pybfrq\".replace(re14, \"\");\n      \"puvyq p1 svefg sylbhg pybfrq\".replace(re15, \"\");\n      \"pvgvrf\".replace(re14, \"\");\n      \"pvgvrf\".replace(re15, \"\");\n      \"pybfrq\".replace(re14, \"\");\n      \"pybfrq\".replace(re15, \"\");\n      \"qry\".replace(re14, \"\");\n      \"qry\".replace(re15, \"\");\n      \"uqy_zba\".replace(re14, \"\");\n      \"uqy_zba\".replace(re15, \"\");\n      s77[i].replace(re33, \"\");\n      s78[i].replace(/%3P/g, \"\");\n      s78[i].replace(/%3R/g, \"\");\n      s78[i].replace(/%3q/g, \"\");\n      s78[i].replace(re35, \"\");\n      \"yvaxyvfg16\".replace(re14, \"\");\n      \"yvaxyvfg16\".replace(re15, \"\");\n      \"zvahf\".replace(re14, \"\");\n      \"zvahf\".replace(re15, \"\");\n      \"bcra\".replace(re14, \"\");\n      \"bcra\".replace(re15, \"\");\n      \"cnerag puebzr5 fvatyr1 ps NU\".replace(re14, \"\");\n      \"cnerag puebzr5 fvatyr1 ps NU\".replace(re15, \"\");\n      \"cynlre\".replace(re14, \"\");\n      \"cynlre\".replace(re15, \"\");\n      \"cyhf\".replace(re14, \"\");\n      \"cyhf\".replace(re15, \"\");\n      \"cb_uqy\".replace(re14, \"\");\n      \"cb_uqy\".replace(re15, \"\");\n      \"hyJVzt\".replace(re14, \"\");\n      \"hyJVzt\".replace(re15, \"\");\n      re8.exec(\"144631658.0.10.1231363638\");\n      re8.exec(\n        \"144631658.1231363638.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)\"\n      );\n      re8.exec(\n        \"144631658.965867047679498800.1231363638.1231363638.1231363638.1\"\n      );\n      re8.exec(\"4413268q3660\");\n      re8.exec(\"4ss747o77904333q374or84qrr1s9r0nprp8r5q81534o94n\");\n      re8.exec(\"SbeprqRkcvengvba=633669321699093060\");\n      re8.exec(\"VC=74.125.75.20\");\n      re8.exec(str19);\n      re8.exec(str20);\n      re8.exec(\"AFP_zp_tfwsbrg-aowb_80=4413268q3660\");\n      re8.exec(\"FrffvbaQQS2=4ss747o77904333q374or84qrr1s9r0nprp8r5q81534o94n\");\n      re8.exec(\n        \"__hgzn=144631658.965867047679498800.1231363638.1231363638.1231363638.1\"\n      );\n      re8.exec(\"__hgzo=144631658.0.10.1231363638\");\n      re8.exec(\n        \"__hgzm=144631658.1231363638.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)\"\n      );\n      re34.exec(str15);\n      re34.exec(str16);\n    }\n  }\n  var re36 = /uers|fep|fryrpgrq/;\n  var re37 = /\\s*([+>~\\s])\\s*([a-zA-Z#.*:\\[])/g;\n  var re38 = /^(\\w+|\\*)$/;\n  var str21 =\n    \"FrffvbaQQS2=s15q53p9n372sn76npr13o271n4s3p5r29p235746p908p58; ZFPhygher=VC=66.249.85.130&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669358527244818&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=\";\n  var str22 =\n    \"FrffvbaQQS2=s15q53p9n372sn76npr13o271n4s3p5r29p235746p908p58; __hgzm=144631658.1231367822.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.4127520630321984500.1231367822.1231367822.1231367822.1; __hgzo=144631658.0.10.1231367822; __hgzp=144631658; ZFPhygher=VC=66.249.85.130&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669358527244818&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q\";\n  var str23 =\n    \"uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_zlfcnpr-ubzrcntr_wf&qg=1231367803797&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231367803797&punaary=svz_zlfcnpr_ubzrcntr_abgybttrqva%2Psvz_zlfcnpr_aba_HTP%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Szrffntvat.zlfcnpr.pbz%2Svaqrk.psz&nq_glcr=grkg&rvq=6083027&rn=0&sez=0&tn_ivq=1192552091.1231367807&tn_fvq=1231367807&tn_uvq=1155446857&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22\";\n  var str24 =\n    \"ZFPhygher=VC=66.249.85.130&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669358527244818&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q\";\n  var str25 =\n    \"ZFPhygher=VC=66.249.85.130&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669358527244818&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=\";\n  var str26 = \"hy.ynat-fryrpgbe\";\n  var re39 = /\\\\/g;\n  var re40 = / /g;\n  var re41 = /\\/\\xc4\\/t/;\n  var re42 = /\\/\\xd6\\/t/;\n  var re43 = /\\/\\xdc\\/t/;\n  var re44 = /\\/\\xdf\\/t/;\n  var re45 = /\\/\\xe4\\/t/;\n  var re46 = /\\/\\xf6\\/t/;\n  var re47 = /\\/\\xfc\\/t/;\n  var re48 = /\\W/g;\n  var re49 = /uers|fep|fglyr/;\n  var s79 = computeInputVariants(str21, 16);\n  var s80 = computeInputVariants(str22, 16);\n  var s81 = computeInputVariants(str23, 16);\n  var s82 = computeInputVariants(str26, 16);\n\n  function runBlock4() {\n    for (var i = 0; i < 16; i++) {\n      \"\".replace(/\\*/g, \"\");\n      /\\bnpgvir\\b/.exec(\"npgvir\");\n      /sversbk/i.exec(s15[i]);\n      re36.exec(\"glcr\");\n      /zfvr/i.exec(s15[i]);\n      /bcren/i.exec(s15[i]);\n    }\n    for (var i = 0; i < 15; i++) {\n      s79[i].split(re32);\n      s80[i].split(re32);\n      \"uggc://ohyyrgvaf.zlfcnpr.pbz/vaqrk.psz\".replace(re12, \"\");\n      s81[i].replace(re33, \"\");\n      \"yv\".replace(re37, \"\");\n      \"yv\".replace(re18, \"\");\n      re8.exec(\"144631658.0.10.1231367822\");\n      re8.exec(\n        \"144631658.1231367822.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)\"\n      );\n      re8.exec(\n        \"144631658.4127520630321984500.1231367822.1231367822.1231367822.1\"\n      );\n      re8.exec(str24);\n      re8.exec(str25);\n      re8.exec(\n        \"__hgzn=144631658.4127520630321984500.1231367822.1231367822.1231367822.1\"\n      );\n      re8.exec(\"__hgzo=144631658.0.10.1231367822\");\n      re8.exec(\n        \"__hgzm=144631658.1231367822.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)\"\n      );\n      re34.exec(s79[i]);\n      re34.exec(s80[i]);\n      /\\.([\\w-]+)|\\[(\\w+)(?:([!*^$~|]?=)[\"']?(.*?)[\"']?)?\\]|:([\\w-]+)(?:\\([\"']?(.*?)?[\"']?\\)|$)/g.exec(\n        s82[i]\n      );\n      re13.exec(\"uggc://ohyyrgvaf.zlfcnpr.pbz/vaqrk.psz\");\n      re38.exec(\"yv\");\n    }\n    for (var i = 0; i < 14; i++) {\n      \"\".replace(re18, \"\");\n      \"9.0  e115\".replace(/(\\s+e|\\s+o[0-9]+)/, \"\");\n      \"Funer guvf tnqtrg\".replace(/</g, \"\");\n      \"Funer guvf tnqtrg\".replace(/>/g, \"\");\n      \"Funer guvf tnqtrg\".replace(re39, \"\");\n      \"uggc://cebsvyrrqvg.zlfcnpr.pbz/vaqrk.psz\".replace(re12, \"\");\n      \"grnfre\".replace(re40, \"\");\n      \"grnfre\".replace(re41, \"\");\n      \"grnfre\".replace(re42, \"\");\n      \"grnfre\".replace(re43, \"\");\n      \"grnfre\".replace(re44, \"\");\n      \"grnfre\".replace(re45, \"\");\n      \"grnfre\".replace(re46, \"\");\n      \"grnfre\".replace(re47, \"\");\n      \"grnfre\".replace(re48, \"\");\n      re16.exec(\"znetva-gbc\");\n      re16.exec(\"cbfvgvba\");\n      re19.exec(\"gno1\");\n      re9.exec(\"qz\");\n      re9.exec(\"qg\");\n      re9.exec(\"zbqobk\");\n      re9.exec(\"zbqobkva\");\n      re9.exec(\"zbqgvgyr\");\n      re13.exec(\"uggc://cebsvyrrqvg.zlfcnpr.pbz/vaqrk.psz\");\n      re26.exec(\"/vt/znvytnqtrg\");\n      re49.exec(\"glcr\");\n    }\n  }\n  var re50 = /(?:^|\\s+)fryrpgrq(?:\\s+|$)/;\n  var re51 = /\\&/g;\n  var re52 = /\\+/g;\n  var re53 = /\\?/g;\n  var re54 = /\\t/g;\n  var re55 = /(\\$\\{nqiHey\\})|(\\$nqiHey\\b)/g;\n  var re56 = /(\\$\\{cngu\\})|(\\$cngu\\b)/g;\n  function runBlock5() {\n    for (var i = 0; i < 13; i++) {\n      \"purpx\".replace(re14, \"\");\n      \"purpx\".replace(re15, \"\");\n      \"pvgl\".replace(re14, \"\");\n      \"pvgl\".replace(re15, \"\");\n      \"qrpe fyvqrgrkg\".replace(re14, \"\");\n      \"qrpe fyvqrgrkg\".replace(re15, \"\");\n      \"svefg fryrpgrq\".replace(re14, \"\");\n      \"svefg fryrpgrq\".replace(re15, \"\");\n      \"uqy_rag\".replace(re14, \"\");\n      \"uqy_rag\".replace(re15, \"\");\n      \"vape fyvqrgrkg\".replace(re14, \"\");\n      \"vape fyvqrgrkg\".replace(re15, \"\");\n      \"vachggrkg QBZPbageby_cynprubyqre\".replace(re5, \"\");\n      \"cnerag puebzr6 fvatyr1 gno fryrpgrq\".replace(re14, \"\");\n      \"cnerag puebzr6 fvatyr1 gno fryrpgrq\".replace(re15, \"\");\n      \"cb_guz\".replace(re14, \"\");\n      \"cb_guz\".replace(re15, \"\");\n      \"fhozvg\".replace(re14, \"\");\n      \"fhozvg\".replace(re15, \"\");\n      re50.exec(\"\");\n      /NccyrJroXvg\\/([^\\s]*)/.exec(s15[i]);\n      /XUGZY/.exec(s15[i]);\n    }\n    for (var i = 0; i < 12; i++) {\n      \"${cebg}://${ubfg}${cngu}/${dz}\".replace(/(\\$\\{cebg\\})|(\\$cebg\\b)/g, \"\");\n      \"1\".replace(re40, \"\");\n      \"1\".replace(re10, \"\");\n      \"1\".replace(re51, \"\");\n      \"1\".replace(re52, \"\");\n      \"1\".replace(re53, \"\");\n      \"1\".replace(re39, \"\");\n      \"1\".replace(re54, \"\");\n      \"9.0  e115\".replace(/^(.*)\\..*$/, \"\");\n      \"9.0  e115\".replace(/^.*e(.*)$/, \"\");\n      \"<!-- ${nqiHey} -->\".replace(re55, \"\");\n      '<fpevcg glcr=\"grkg/wninfpevcg\" fep=\"${nqiHey}\"></fpevcg>'.replace(\n        re55,\n        \"\"\n      );\n      s21[i].replace(/^.*\\s+(\\S+\\s+\\S+$)/, \"\");\n      \"tzk%2Subzrcntr%2Sfgneg%2Sqr%2S\".replace(re30, \"\");\n      \"tzk\".replace(re30, \"\");\n      \"uggc://${ubfg}${cngu}/${dz}\".replace(/(\\$\\{ubfg\\})|(\\$ubfg\\b)/g, \"\");\n      \"uggc://nqpyvrag.hvzfrei.arg${cngu}/${dz}\".replace(re56, \"\");\n      \"uggc://nqpyvrag.hvzfrei.arg/wf.at/${dz}\".replace(\n        /(\\$\\{dz\\})|(\\$dz\\b)/g,\n        \"\"\n      );\n      \"frpgvba\".replace(re29, \"\");\n      \"frpgvba\".replace(re30, \"\");\n      \"fvgr\".replace(re29, \"\");\n      \"fvgr\".replace(re30, \"\");\n      \"fcrpvny\".replace(re29, \"\");\n      \"fcrpvny\".replace(re30, \"\");\n      re36.exec(\"anzr\");\n      /e/.exec(\"9.0  e115\");\n    }\n  }\n  var re57 = /##yv4##/gi;\n  var re58 = /##yv16##/gi;\n  var re59 = /##yv19##/gi;\n  var str27 =\n    '<hy pynff=\"nqi\">##yv4##Cbjreshy Zvpebfbsg grpuabybtl urycf svtug fcnz naq vzcebir frphevgl.##yv19##Trg zber qbar gunaxf gb terngre rnfr naq fcrrq.##yv16##Ybgf bs fgbentr &#40;5 TO&#41; - zber pbby fghss ba gur jnl.##OE## ##OE## ##N##Yrnea zber##/N##</hy>';\n  var str28 =\n    '<hy pynff=\"nqi\"><yv vq=\"YvOYG4\" fglyr=\"onpxtebhaq-vzntr:hey(uggc://vzt.jykef.pbz/~Yvir.FvgrPbagrag.VQ/~14.2.1230/~/~/~/oyg4.cat)\">Cbjreshy Zvpebfbsg grpuabybtl urycf svtug fcnz naq vzcebir frphevgl.##yv19##Trg zber qbar gunaxf gb terngre rnfr naq fcrrq.##yv16##Ybgf bs fgbentr &#40;5 TO&#41; - zber pbby fghss ba gur jnl.##OE## ##OE## ##N##Yrnea zber##/N##</hy>';\n  var str29 =\n    '<hy pynff=\"nqi\"><yv vq=\"YvOYG4\" fglyr=\"onpxtebhaq-vzntr:hey(uggc://vzt.jykef.pbz/~Yvir.FvgrPbagrag.VQ/~14.2.1230/~/~/~/oyg4.cat)\">Cbjreshy Zvpebfbsg grpuabybtl urycf svtug fcnz naq vzcebir frphevgl.##yv19##Trg zber qbar gunaxf gb terngre rnfr naq fcrrq.<yv vq=\"YvOYG16\" fglyr=\"onpxtebhaq-vzntr:hey(uggc://vzt.jykef.pbz/~Yvir.FvgrPbagrag.VQ/~14.2.1230/~/~/~/oyg16.cat)\">Ybgf bs fgbentr &#40;5 TO&#41; - zber pbby fghss ba gur jnl.##OE## ##OE## ##N##Yrnea zber##/N##</hy>';\n  var str30 =\n    '<hy pynff=\"nqi\"><yv vq=\"YvOYG4\" fglyr=\"onpxtebhaq-vzntr:hey(uggc://vzt.jykef.pbz/~Yvir.FvgrPbagrag.VQ/~14.2.1230/~/~/~/oyg4.cat)\">Cbjreshy Zvpebfbsg grpuabybtl urycf svtug fcnz naq vzcebir frphevgl.<yv vq=\"YvOYG19\" fglyr=\"onpxtebhaq-vzntr:hey(uggc://vzt.jykef.pbz/~Yvir.FvgrPbagrag.VQ/~14.2.1230/~/~/~/oyg19.cat)\">Trg zber qbar gunaxf gb terngre rnfr naq fcrrq.<yv vq=\"YvOYG16\" fglyr=\"onpxtebhaq-vzntr:hey(uggc://vzt.jykef.pbz/~Yvir.FvgrPbagrag.VQ/~14.2.1230/~/~/~/oyg16.cat)\">Ybgf bs fgbentr &#40;5 TO&#41; - zber pbby fghss ba gur jnl.##OE## ##OE## ##N##Yrnea zber##/N##</hy>';\n  var str31 =\n    '<hy pynff=\"nqi\"><yv vq=\"YvOYG4\" fglyr=\"onpxtebhaq-vzntr:hey(uggc://vzt.jykef.pbz/~Yvir.FvgrPbagrag.VQ/~14.2.1230/~/~/~/oyg4.cat)\">Cbjreshy Zvpebfbsg grpuabybtl urycf svtug fcnz naq vzcebir frphevgl.<yv vq=\"YvOYG19\" fglyr=\"onpxtebhaq-vzntr:hey(uggc://vzt.jykef.pbz/~Yvir.FvgrPbagrag.VQ/~14.2.1230/~/~/~/oyg19.cat)\">Trg zber qbar gunaxf gb terngre rnfr naq fcrrq.<yv vq=\"YvOYG16\" fglyr=\"onpxtebhaq-vzntr:hey(uggc://vzt.jykef.pbz/~Yvir.FvgrPbagrag.VQ/~14.2.1230/~/~/~/oyg16.cat)\">Ybgf bs fgbentr &#40;5 TO&#41; - zber pbby fghss ba gur jnl.<oe> <oe> ##N##Yrnea zber##/N##</hy>';\n  var str32 =\n    '<hy pynff=\"nqi\"><yv vq=\"YvOYG4\" fglyr=\"onpxtebhaq-vzntr:hey(uggc://vzt.jykef.pbz/~Yvir.FvgrPbagrag.VQ/~14.2.1230/~/~/~/oyg4.cat)\">Cbjreshy Zvpebfbsg grpuabybtl urycf svtug fcnz naq vzcebir frphevgl.<yv vq=\"YvOYG19\" fglyr=\"onpxtebhaq-vzntr:hey(uggc://vzt.jykef.pbz/~Yvir.FvgrPbagrag.VQ/~14.2.1230/~/~/~/oyg19.cat)\">Trg zber qbar gunaxf gb terngre rnfr naq fcrrq.<yv vq=\"YvOYG16\" fglyr=\"onpxtebhaq-vzntr:hey(uggc://vzt.jykef.pbz/~Yvir.FvgrPbagrag.VQ/~14.2.1230/~/~/~/oyg16.cat)\">Ybgf bs fgbentr &#40;5 TO&#41; - zber pbby fghss ba gur jnl.<oe> <oe> <n uers=\"uggc://znvy.yvir.pbz/znvy/nobhg.nfck\" gnetrg=\"_oynax\">Yrnea zber##/N##</hy>';\n  var str33 =\n    \"Bar Jvaqbjf Yvir VQ trgf lbh vagb <o>Ubgznvy</o>, <o>Zrffratre</o>, <o>Kobk YVIR</o> \\u2014 naq bgure cynprf lbh frr #~#argjbexybtb#~#\";\n  var re60 = /(?:^|\\s+)bss(?:\\s+|$)/;\n  var re61 = /^(([^:\\/?#]+):)?(\\/\\/([^\\/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$/;\n  var re62 = /^[^<]*(<(.|\\s)+>)[^>]*$|^#(\\w+)$/;\n  var str34 = \"${1}://${2}${3}${4}${5}\";\n  var str35 =\n    \" O=6gnyg0g4znrrn&o=3&f=gc; Q=_lyu=K3bQZGSxnT4lZzD3OS9GNmV3ZGLkAQxRpTyxNmRlZmRmAmNkAQLRqTImqNZjOUEgpTjQnJ5xMKtgoN--; SCF=qy\";\n  var s83 = computeInputVariants(str27, 11);\n  var s84 = computeInputVariants(str28, 11);\n  var s85 = computeInputVariants(str29, 11);\n  var s86 = computeInputVariants(str30, 11);\n  var s87 = computeInputVariants(str31, 11);\n  var s88 = computeInputVariants(str32, 11);\n  var s89 = computeInputVariants(str33, 11);\n  var s90 = computeInputVariants(str34, 11);\n\n  function runBlock6() {\n    for (var i = 0; i < 11; i++) {\n      s83[i].replace(/##yv0##/gi, \"\");\n      s83[i].replace(re57, \"\");\n      s84[i].replace(re58, \"\");\n      s85[i].replace(re59, \"\");\n      s86[i].replace(/##\\/o##/gi, \"\");\n      s86[i].replace(/##\\/v##/gi, \"\");\n      s86[i].replace(/##\\/h##/gi, \"\");\n      s86[i].replace(/##o##/gi, \"\");\n      s86[i].replace(/##oe##/gi, \"\");\n      s86[i].replace(/##v##/gi, \"\");\n      s86[i].replace(/##h##/gi, \"\");\n      s87[i].replace(/##n##/gi, \"\");\n      s88[i].replace(/##\\/n##/gi, \"\");\n      s89[i].replace(/#~#argjbexybtb#~#/g, \"\");\n      / Zbovyr\\//.exec(s15[i]);\n      /##yv1##/gi.exec(s83[i]);\n      /##yv10##/gi.exec(s84[i]);\n      /##yv11##/gi.exec(s84[i]);\n      /##yv12##/gi.exec(s84[i]);\n      /##yv13##/gi.exec(s84[i]);\n      /##yv14##/gi.exec(s84[i]);\n      /##yv15##/gi.exec(s84[i]);\n      re58.exec(s84[i]);\n      /##yv17##/gi.exec(s85[i]);\n      /##yv18##/gi.exec(s85[i]);\n      re59.exec(s85[i]);\n      /##yv2##/gi.exec(s83[i]);\n      /##yv20##/gi.exec(s86[i]);\n      /##yv21##/gi.exec(s86[i]);\n      /##yv22##/gi.exec(s86[i]);\n      /##yv23##/gi.exec(s86[i]);\n      /##yv3##/gi.exec(s83[i]);\n      re57.exec(s83[i]);\n      /##yv5##/gi.exec(s84[i]);\n      /##yv6##/gi.exec(s84[i]);\n      /##yv7##/gi.exec(s84[i]);\n      /##yv8##/gi.exec(s84[i]);\n      /##yv9##/gi.exec(s84[i]);\n      re8.exec(\"473qq1rs0n2r70q9qo1pq48n021s9468ron90nps048p4p29\");\n      re8.exec(\"SbeprqRkcvengvba=633669325184628362\");\n      re8.exec(\"FrffvbaQQS2=473qq1rs0n2r70q9qo1pq48n021s9468ron90nps048p4p29\");\n      /AbxvnA[^\\/]*/.exec(s15[i]);\n    }\n    for (var i = 0; i < 10; i++) {\n      \" bss\".replace(/(?:^|\\s+)bss(?:\\s+|$)/g, \"\");\n      s90[i].replace(/(\\$\\{0\\})|(\\$0\\b)/g, \"\");\n      s90[i].replace(/(\\$\\{1\\})|(\\$1\\b)/g, \"\");\n      s90[i].replace(/(\\$\\{pbzcyrgr\\})|(\\$pbzcyrgr\\b)/g, \"\");\n      s90[i].replace(/(\\$\\{sentzrag\\})|(\\$sentzrag\\b)/g, \"\");\n      s90[i].replace(/(\\$\\{ubfgcbeg\\})|(\\$ubfgcbeg\\b)/g, \"\");\n      s90[i].replace(re56, \"\");\n      s90[i].replace(/(\\$\\{cebgbpby\\})|(\\$cebgbpby\\b)/g, \"\");\n      s90[i].replace(/(\\$\\{dhrel\\})|(\\$dhrel\\b)/g, \"\");\n      \"nqfvmr\".replace(re29, \"\");\n      \"nqfvmr\".replace(re30, \"\");\n      \"uggc://${2}${3}${4}${5}\".replace(/(\\$\\{2\\})|(\\$2\\b)/g, \"\");\n      \"uggc://wf.hv-cbegny.qr${3}${4}${5}\".replace(/(\\$\\{3\\})|(\\$3\\b)/g, \"\");\n      \"arjf\".replace(re40, \"\");\n      \"arjf\".replace(re41, \"\");\n      \"arjf\".replace(re42, \"\");\n      \"arjf\".replace(re43, \"\");\n      \"arjf\".replace(re44, \"\");\n      \"arjf\".replace(re45, \"\");\n      \"arjf\".replace(re46, \"\");\n      \"arjf\".replace(re47, \"\");\n      \"arjf\".replace(re48, \"\");\n      / PC=i=(\\d+)&oe=(.)/.exec(str35);\n      re60.exec(\" \");\n      re60.exec(\" bss\");\n      re60.exec(\"\");\n      re19.exec(\" \");\n      re19.exec(\"svefg ba\");\n      re19.exec(\"ynfg vtaber\");\n      re19.exec(\"ba\");\n      re9.exec(\"scnq so \");\n      re9.exec(\"zrqvgobk\");\n      re9.exec(\"hsgy\");\n      re9.exec(\"lhv-h\");\n      /Fnsnev|Xbadhrebe|XUGZY/gi.exec(s15[i]);\n      re61.exec(\"uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/onfr.wf\");\n      re62.exec(\"#Ybtva_rznvy\");\n    }\n  }\n  var re63 = /\\{0\\}/g;\n  var str36 =\n    \"FrffvbaQQS2=4ss747o77904333q374or84qrr1s9r0nprp8r5q81534o94n; ZFPhygher=VC=74.125.75.20&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669321699093060&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=; AFP_zp_tfwsbrg-aowb_80=4413268q3660\";\n  var str37 =\n    \"FrffvbaQQS2=4ss747o77904333q374or84qrr1s9r0nprp8r5q81534o94n; AFP_zp_tfwsbrg-aowb_80=4413268q3660; __hgzm=144631658.1231364074.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.2294274870215848400.1231364074.1231364074.1231364074.1; __hgzo=144631658.0.10.1231364074; __hgzp=144631658; ZFPhygher=VC=74.125.75.20&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669321699093060&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q\";\n  var str38 =\n    \"uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_zlfcnpr-ubzrcntr_wf&qg=1231364057761&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231364057761&punaary=svz_zlfcnpr_ubzrcntr_abgybttrqva%2Psvz_zlfcnpr_aba_HTP%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Ssevraqf.zlfcnpr.pbz%2Svaqrk.psz&nq_glcr=grkg&rvq=6083027&rn=0&sez=0&tn_ivq=1667363813.1231364061&tn_fvq=1231364061&tn_uvq=1917563877&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22\";\n  var str39 =\n    \"ZFPhygher=VC=74.125.75.20&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669321699093060&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q\";\n  var str40 =\n    \"ZFPhygher=VC=74.125.75.20&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669321699093060&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=\";\n  var s91 = computeInputVariants(str36, 9);\n  var s92 = computeInputVariants(str37, 9);\n  var s93 = computeInputVariants(str38, 9);\n  function runBlock7() {\n    for (var i = 0; i < 9; i++) {\n      \"0\".replace(re40, \"\");\n      \"0\".replace(re10, \"\");\n      \"0\".replace(re51, \"\");\n      \"0\".replace(re52, \"\");\n      \"0\".replace(re53, \"\");\n      \"0\".replace(re39, \"\");\n      \"0\".replace(re54, \"\");\n      \"Lrf\".replace(re40, \"\");\n      \"Lrf\".replace(re10, \"\");\n      \"Lrf\".replace(re51, \"\");\n      \"Lrf\".replace(re52, \"\");\n      \"Lrf\".replace(re53, \"\");\n      \"Lrf\".replace(re39, \"\");\n      \"Lrf\".replace(re54, \"\");\n    }\n    for (var i = 0; i < 8; i++) {\n      \"Pybfr {0}\".replace(re63, \"\");\n      \"Bcra {0}\".replace(re63, \"\");\n      s91[i].split(re32);\n      s92[i].split(re32);\n      \"puvyq p1 svefg gnournqref\".replace(re14, \"\");\n      \"puvyq p1 svefg gnournqref\".replace(re15, \"\");\n      \"uqy_fcb\".replace(re14, \"\");\n      \"uqy_fcb\".replace(re15, \"\");\n      \"uvag\".replace(re14, \"\");\n      \"uvag\".replace(re15, \"\");\n      s93[i].replace(re33, \"\");\n      \"yvfg\".replace(re14, \"\");\n      \"yvfg\".replace(re15, \"\");\n      \"at_bhgre\".replace(re30, \"\");\n      \"cnerag puebzr5 qbhoyr2 NU\".replace(re14, \"\");\n      \"cnerag puebzr5 qbhoyr2 NU\".replace(re15, \"\");\n      \"cnerag puebzr5 dhnq5 ps NU osyvax zbarl\".replace(re14, \"\");\n      \"cnerag puebzr5 dhnq5 ps NU osyvax zbarl\".replace(re15, \"\");\n      \"cnerag puebzr6 fvatyr1\".replace(re14, \"\");\n      \"cnerag puebzr6 fvatyr1\".replace(re15, \"\");\n      \"cb_qrs\".replace(re14, \"\");\n      \"cb_qrs\".replace(re15, \"\");\n      \"gnopbagrag\".replace(re14, \"\");\n      \"gnopbagrag\".replace(re15, \"\");\n      \"iv_svefg_gvzr\".replace(re30, \"\");\n      /(^|.)(ronl|qri-ehf3.wbg)(|fgberf|zbgbef|yvirnhpgvbaf|jvxv|rkcerff|punggre).(pbz(|.nh|.pa|.ux|.zl|.ft|.oe|.zk)|pb(.hx|.xe|.am)|pn|qr|se|vg|ay|or|ng|pu|vr|va|rf|cy|cu|fr)$/i.exec(\n        \"cntrf.ronl.pbz\"\n      );\n      re8.exec(\"144631658.0.10.1231364074\");\n      re8.exec(\n        \"144631658.1231364074.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)\"\n      );\n      re8.exec(\n        \"144631658.2294274870215848400.1231364074.1231364074.1231364074.1\"\n      );\n      re8.exec(\"4413241q3660\");\n      re8.exec(\"SbeprqRkcvengvba=633669357391353591\");\n      re8.exec(str39);\n      re8.exec(str40);\n      re8.exec(\"AFP_zp_kkk-gdzogv_80=4413241q3660\");\n      re8.exec(\"FrffvbaQQS2=p98s8o9q42nr21or1r61pqorn1n002nsss569635984s6qp7\");\n      re8.exec(\n        \"__hgzn=144631658.2294274870215848400.1231364074.1231364074.1231364074.1\"\n      );\n      re8.exec(\"__hgzo=144631658.0.10.1231364074\");\n      re8.exec(\n        \"__hgzm=144631658.1231364074.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)\"\n      );\n      re8.exec(\"p98s8o9q42nr21or1r61pqorn1n002nsss569635984s6qp7\");\n      re34.exec(s91[i]);\n      re34.exec(s92[i]);\n    }\n  }\n  var re64 = /\\b[a-z]/g;\n  var re65 = /^uggc:\\/\\//;\n  var re66 = /(?:^|\\s+)qvfnoyrq(?:\\s+|$)/;\n  var str41 =\n    \"uggc://cebsvyr.zlfcnpr.pbz/Zbqhyrf/Nccyvpngvbaf/Cntrf/Pnainf.nfck\";\n  function runBlock8() {\n    for (var i = 0; i < 7; i++) {\n      s21[i].match(/\\d+/g);\n      \"nsgre\".replace(re64, \"\");\n      \"orsber\".replace(re64, \"\");\n      \"obggbz\".replace(re64, \"\");\n      \"ohvygva_jrngure.kzy\".replace(re65, \"\");\n      \"ohggba\".replace(re37, \"\");\n      \"ohggba\".replace(re18, \"\");\n      \"qngrgvzr.kzy\".replace(re65, \"\");\n      \"uggc://eff.paa.pbz/eff/paa_gbcfgbevrf.eff\".replace(re65, \"\");\n      \"vachg\".replace(re37, \"\");\n      \"vachg\".replace(re18, \"\");\n      \"vafvqr\".replace(re64, \"\");\n      \"cbvagre\".replace(re27, \"\");\n      \"cbfvgvba\".replace(/[A-Z]/g, \"\");\n      \"gbc\".replace(re27, \"\");\n      \"gbc\".replace(re64, \"\");\n      \"hy\".replace(re37, \"\");\n      \"hy\".replace(re18, \"\");\n      str26.replace(re37, \"\");\n      str26.replace(re18, \"\");\n      \"lbhghor_vtbbtyr/i2/lbhghor.kzy\".replace(re65, \"\");\n      \"m-vaqrk\".replace(re27, \"\");\n      /#([\\w-]+)/.exec(str26);\n      re16.exec(\"urvtug\");\n      re16.exec(\"znetvaGbc\");\n      re16.exec(\"jvqgu\");\n      re19.exec(\"gno0 svefg ba\");\n      re19.exec(\"gno0 ba\");\n      re19.exec(\"gno4 ynfg\");\n      re19.exec(\"gno4\");\n      re19.exec(\"gno5\");\n      re19.exec(\"gno6\");\n      re19.exec(\"gno7\");\n      re19.exec(\"gno8\");\n      /NqborNVE\\/([^\\s]*)/.exec(s15[i]);\n      /NccyrJroXvg\\/([^ ]*)/.exec(s15[i]);\n      /XUGZY/gi.exec(s15[i]);\n      /^(?:obql|ugzy)$/i.exec(\"YV\");\n      re38.exec(\"ohggba\");\n      re38.exec(\"vachg\");\n      re38.exec(\"hy\");\n      re38.exec(str26);\n      /^(\\w+|\\*)/.exec(str26);\n      /znp|jva|yvahk/i.exec(\"Jva32\");\n      /eton?\\([\\d\\s,]+\\)/.exec(\"fgngvp\");\n    }\n    for (var i = 0; i < 6; i++) {\n      \"\".replace(/\\r/g, \"\");\n      \"/\".replace(re40, \"\");\n      \"/\".replace(re10, \"\");\n      \"/\".replace(re51, \"\");\n      \"/\".replace(re52, \"\");\n      \"/\".replace(re53, \"\");\n      \"/\".replace(re39, \"\");\n      \"/\".replace(re54, \"\");\n      \"uggc://zfacbegny.112.2b7.arg/o/ff/zfacbegnyubzr/1/U.7-cqi-2/{0}?[NDO]&{1}&{2}&[NDR]\".replace(\n        re63,\n        \"\"\n      );\n      str41.replace(re12, \"\");\n      \"uggc://jjj.snprobbx.pbz/fepu.cuc\".replace(re23, \"\");\n      \"freivpr\".replace(re40, \"\");\n      \"freivpr\".replace(re41, \"\");\n      \"freivpr\".replace(re42, \"\");\n      \"freivpr\".replace(re43, \"\");\n      \"freivpr\".replace(re44, \"\");\n      \"freivpr\".replace(re45, \"\");\n      \"freivpr\".replace(re46, \"\");\n      \"freivpr\".replace(re47, \"\");\n      \"freivpr\".replace(re48, \"\");\n      /((ZFVR\\s+([6-9]|\\d\\d)\\.))/.exec(s15[i]);\n      re66.exec(\"\");\n      re50.exec(\"fryrpgrq\");\n      re8.exec(\"8sqq78r9n442851q565599o401385sp3s04r92rnn7o19ssn\");\n      re8.exec(\"SbeprqRkcvengvba=633669340386893867\");\n      re8.exec(\"VC=74.125.75.17\");\n      re8.exec(\"FrffvbaQQS2=8sqq78r9n442851q565599o401385sp3s04r92rnn7o19ssn\");\n      /Xbadhrebe|Fnsnev|XUGZY/.exec(s15[i]);\n      re13.exec(str41);\n      re49.exec(\"unfsbphf\");\n    }\n  }\n  var re67 = /zrah_byq/g;\n  var str42 =\n    \"FrffvbaQQS2=473qq1rs0n2r70q9qo1pq48n021s9468ron90nps048p4p29; ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669325184628362&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=\";\n  var str43 =\n    \"FrffvbaQQS2=473qq1rs0n2r70q9qo1pq48n021s9468ron90nps048p4p29; __hgzm=144631658.1231364380.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.3931862196947939300.1231364380.1231364380.1231364380.1; __hgzo=144631658.0.10.1231364380; __hgzp=144631658; ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669325184628362&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q\";\n  var str44 =\n    \"uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_vzntrf_wf&qg=1231364373088&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231364373088&punaary=svz_zlfcnpr_hfre-ivrj-pbzzragf%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Spbzzrag.zlfcnpr.pbz%2Svaqrk.psz&nq_glcr=grkg&rvq=6083027&rn=0&sez=0&tn_ivq=1158737789.1231364375&tn_fvq=1231364375&tn_uvq=415520832&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22\";\n  var str45 =\n    \"ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669325184628362&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q\";\n  var str46 =\n    \"ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669325184628362&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=\";\n  var re68 = /^([#.]?)((?:[\\w\\u0128-\\uffff*_-]|\\\\.)*)/;\n  var re69 = /\\{1\\}/g;\n  var re70 = /\\s+/;\n  var re71 = /(\\$\\{4\\})|(\\$4\\b)/g;\n  var re72 = /(\\$\\{5\\})|(\\$5\\b)/g;\n  var re73 = /\\{2\\}/g;\n  var re74 = /[^+>] [^+>]/;\n  var re75 = /\\bucpyv\\s*=\\s*([^;]*)/i;\n  var re76 = /\\bucuvqr\\s*=\\s*([^;]*)/i;\n  var re77 = /\\bucfie\\s*=\\s*([^;]*)/i;\n  var re78 = /\\bhfucjrn\\s*=\\s*([^;]*)/i;\n  var re79 = /\\bmvc\\s*=\\s*([^;]*)/i;\n  var re80 =\n    /^((?:[\\w\\u0128-\\uffff*_-]|\\\\.)+)(#)((?:[\\w\\u0128-\\uffff*_-]|\\\\.)+)/;\n  var re81 = /^([>+~])\\s*(\\w*)/i;\n  var re82 = /^>\\s*((?:[\\w\\u0128-\\uffff*_-]|\\\\.)+)/;\n  var re83 = /^[\\s[]?shapgvba/;\n  var re84 = /v\\/g.tvs#(.*)/i;\n  var str47 = \"#Zbq-Vasb-Vasb-WninFpevcgUvag\";\n  var str48 = \",n.svryqOgaPnapry\";\n  var str49 =\n    \"FrffvbaQQS2=p98s8o9q42nr21or1r61pqorn1n002nsss569635984s6qp7; ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669357391353591&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=; AFP_zp_kkk-gdzogv_80=4413241q3660\";\n  var str50 =\n    \"FrffvbaQQS2=p98s8o9q42nr21or1r61pqorn1n002nsss569635984s6qp7; AFP_zp_kkk-gdzogv_80=4413241q3660; AFP_zp_kkk-aowb_80=4413235p3660; __hgzm=144631658.1231367708.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.2770915348920628700.1231367708.1231367708.1231367708.1; __hgzo=144631658.0.10.1231367708; __hgzp=144631658; ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669357391353591&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q\";\n  var str51 =\n    \"uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_zlfcnpr-ubzrcntr_wf&qg=1231367691141&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231367691141&punaary=svz_zlfcnpr_ubzrcntr_abgybttrqva%2Psvz_zlfcnpr_aba_HTP%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Sjjj.zlfcnpr.pbz%2S&nq_glcr=grkg&rvq=6083027&rn=0&sez=0&tn_ivq=320757904.1231367694&tn_fvq=1231367694&tn_uvq=1758792003&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22\";\n  var str52 =\n    \"uggc://zfacbegny.112.2b7.arg/o/ff/zfacbegnyubzr/1/U.7-cqi-2/f55332979829981?[NDO]&aqu=1&g=7%2S0%2S2009%2014%3N38%3N42%203%20480&af=zfacbegny&cntrAnzr=HF%20UCZFSGJ&t=uggc%3N%2S%2Sjjj.zfa.pbz%2S&f=1024k768&p=24&x=L&oj=994&ou=634&uc=A&{2}&[NDR]\";\n  var str53 = \"cnerag puebzr6 fvatyr1 gno fryrpgrq ovaq qbhoyr2 ps\";\n  var str54 =\n    \"ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669357391353591&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q\";\n  var str55 =\n    \"ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669357391353591&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=\";\n  var str56 =\n    \"ne;ng;nh;or;oe;pn;pu;py;pa;qr;qx;rf;sv;se;to;ux;vq;vr;va;vg;wc;xe;zk;zl;ay;ab;am;cu;cy;cg;eh;fr;ft;gu;ge;gj;mn;\";\n  var str57 =\n    \"ZP1=I=3&THVQ=6nnpr9q661804s33nnop45nosqp17q85; zu=ZFSG; PHYGHER=RA-HF; SyvtugTebhcVq=97; SyvtugVq=OnfrCntr; ucfie=Z:5|S:5|G:5|R:5|Q:oyh|J:S; ucpyv=J.U|Y.|F.|E.|H.Y|P.|U.; hfucjrn=jp:HFPN0746; ZHVQ=Q783SN9O14054831N4869R51P0SO8886&GHVQ=1\";\n  var str58 =\n    \"ZP1=I=3&THVQ=6nnpr9q661804s33nnop45nosqp17q85; zu=ZFSG; PHYGHER=RA-HF; SyvtugTebhcVq=97; SyvtugVq=OnfrCntr; ucfie=Z:5|S:5|G:5|R:5|Q:oyh|J:S; ucpyv=J.U|Y.|F.|E.|H.Y|P.|U.; hfucjrn=jp:HFPN0746; ZHVQ=Q783SN9O14054831N4869R51P0SO8886\";\n  var str59 =\n    \"ZP1=I=3&THVQ=6nnpr9q661804s33nnop45nosqp17q85; zu=ZFSG; PHYGHER=RA-HF; SyvtugTebhcVq=97; SyvtugVq=OnfrCntr; ucfie=Z:5|S:5|G:5|R:5|Q:oyh|J:S; ucpyv=J.U|Y.|F.|E.|H.Y|P.|U.; hfucjrn=jp:HFPN0746; ZHVQ=Q783SN9O14054831N4869R51P0SO8886; mvc=m:94043|yn:37.4154|yb:-122.0585|p:HF|ue:1\";\n  var str60 =\n    \"ZP1=I=3&THVQ=6nnpr9q661804s33nnop45nosqp17q85; zu=ZFSG; PHYGHER=RA-HF; SyvtugTebhcVq=97; SyvtugVq=OnfrCntr; ucfie=Z:5|S:5|G:5|R:5|Q:oyh|J:S; ucpyv=J.U|Y.|F.|E.|H.Y|P.|U.; hfucjrn=jp:HFPN0746; ZHVQ=Q783SN9O14054831N4869R51P0SO8886; mvc=m:94043|yn:37.4154|yb:-122.0585|p:HF\";\n  var str61 =\n    \"uggc://gx2.fgp.f-zfa.pbz/oe/uc/11/ra-hf/pff/v/g.tvs#uggc://gx2.fgo.f-zfa.pbz/v/29/4RQP4969777N048NPS4RRR3PO2S7S.wct\";\n  var str62 =\n    \"uggc://gx2.fgp.f-zfa.pbz/oe/uc/11/ra-hf/pff/v/g.tvs#uggc://gx2.fgo.f-zfa.pbz/v/OQ/63NP9O94NS5OQP1249Q9S1ROP7NS3.wct\";\n  var str63 =\n    \"zbmvyyn/5.0 (jvaqbjf; h; jvaqbjf ag 5.1; ra-hf) nccyrjroxvg/528.9 (xugzy, yvxr trpxb) puebzr/2.0.157.0 fnsnev/528.9\";\n  var s94 = computeInputVariants(str42, 5);\n  var s95 = computeInputVariants(str43, 5);\n  var s96 = computeInputVariants(str44, 5);\n  var s97 = computeInputVariants(str47, 5);\n  var s98 = computeInputVariants(str48, 5);\n  var s99 = computeInputVariants(str49, 5);\n  var s100 = computeInputVariants(str50, 5);\n  var s101 = computeInputVariants(str51, 5);\n  var s102 = computeInputVariants(str52, 5);\n  var s103 = computeInputVariants(str53, 5);\n\n  function runBlock9() {\n    for (var i = 0; i < 5; i++) {\n      s94[i].split(re32);\n      s95[i].split(re32);\n      \"svz_zlfcnpr_hfre-ivrj-pbzzragf,svz_zlfcnpr_havgrq-fgngrf\".split(re20);\n      s96[i].replace(re33, \"\");\n      \"zrah_arj zrah_arj_gbttyr zrah_gbttyr\".replace(re67, \"\");\n      \"zrah_byq zrah_byq_gbttyr zrah_gbttyr\".replace(re67, \"\");\n      re8.exec(\"102n9o0o9pq60132qn0337rr867p75953502q2s27s2s5r98\");\n      re8.exec(\"144631658.0.10.1231364380\");\n      re8.exec(\n        \"144631658.1231364380.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)\"\n      );\n      re8.exec(\n        \"144631658.3931862196947939300.1231364380.1231364380.1231364380.1\"\n      );\n      re8.exec(\"441326q33660\");\n      re8.exec(\"SbeprqRkcvengvba=633669341278771470\");\n      re8.exec(str45);\n      re8.exec(str46);\n      re8.exec(\"AFP_zp_dfctwzssrwh-aowb_80=441326q33660\");\n      re8.exec(\"FrffvbaQQS2=102n9o0o9pq60132qn0337rr867p75953502q2s27s2s5r98\");\n      re8.exec(\n        \"__hgzn=144631658.3931862196947939300.1231364380.1231364380.1231364380.1\"\n      );\n      re8.exec(\"__hgzo=144631658.0.10.1231364380\");\n      re8.exec(\n        \"__hgzm=144631658.1231364380.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)\"\n      );\n    }\n    for (var i = 0; i < 4; i++) {\n      \" yvfg1\".replace(re14, \"\");\n      \" yvfg1\".replace(re15, \"\");\n      \" yvfg2\".replace(re14, \"\");\n      \" yvfg2\".replace(re15, \"\");\n      \" frneputebhc1\".replace(re14, \"\");\n      \" frneputebhc1\".replace(re15, \"\");\n      s97[i].replace(re68, \"\");\n      s97[i].replace(re18, \"\");\n      \"\".replace(/&/g, \"\");\n      \"\".replace(re35, \"\");\n      \"(..-{0})(|(d+)|)\".replace(re63, \"\");\n      s98[i].replace(re18, \"\");\n      \"//vzt.jro.qr/vij/FC/${cngu}/${anzr}/${inyhr}?gf=${abj}\".replace(\n        re56,\n        \"\"\n      );\n      \"//vzt.jro.qr/vij/FC/tzk_uc/${anzr}/${inyhr}?gf=${abj}\".replace(\n        /(\\$\\{anzr\\})|(\\$anzr\\b)/g,\n        \"\"\n      );\n      '<fcna pynff=\"urnq\"><o>Jvaqbjf Yvir Ubgznvy</o></fcna><fcna pynff=\"zft\">{1}</fcna>'.replace(\n        re69,\n        \"\"\n      );\n      '<fcna pynff=\"urnq\"><o>{0}</o></fcna><fcna pynff=\"zft\">{1}</fcna>'.replace(\n        re63,\n        \"\"\n      );\n      '<fcna pynff=\"fvtahc\"><n uers=uggc://jjj.ubgznvy.pbz><o>{1}</o></n></fcna>'.replace(\n        re69,\n        \"\"\n      );\n      '<fcna pynff=\"fvtahc\"><n uers={0}><o>{1}</o></n></fcna>'.replace(\n        re63,\n        \"\"\n      );\n      \"Vzntrf\".replace(re15, \"\");\n      \"ZFA\".replace(re15, \"\");\n      \"Zncf\".replace(re15, \"\");\n      \"Zbq-Vasb-Vasb-WninFpevcgUvag\".replace(re39, \"\");\n      \"Arjf\".replace(re15, \"\");\n      s99[i].split(re32);\n      s100[i].split(re32);\n      \"Ivqrb\".replace(re15, \"\");\n      \"Jro\".replace(re15, \"\");\n      \"n\".replace(re39, \"\");\n      \"nwnkFgneg\".split(re70);\n      \"nwnkFgbc\".split(re70);\n      \"ovaq\".replace(re14, \"\");\n      \"ovaq\".replace(re15, \"\");\n      \"oevatf lbh zber. Zber fcnpr (5TO), zber frphevgl, fgvyy serr.\".replace(\n        re63,\n        \"\"\n      );\n      \"puvyq p1 svefg qrpx\".replace(re14, \"\");\n      \"puvyq p1 svefg qrpx\".replace(re15, \"\");\n      \"puvyq p1 svefg qbhoyr2\".replace(re14, \"\");\n      \"puvyq p1 svefg qbhoyr2\".replace(re15, \"\");\n      \"puvyq p2 ynfg\".replace(re14, \"\");\n      \"puvyq p2 ynfg\".replace(re15, \"\");\n      \"puvyq p2\".replace(re14, \"\");\n      \"puvyq p2\".replace(re15, \"\");\n      \"puvyq p3\".replace(re14, \"\");\n      \"puvyq p3\".replace(re15, \"\");\n      \"puvyq p4 ynfg\".replace(re14, \"\");\n      \"puvyq p4 ynfg\".replace(re15, \"\");\n      \"pbclevtug\".replace(re14, \"\");\n      \"pbclevtug\".replace(re15, \"\");\n      \"qZFAZR_1\".replace(re14, \"\");\n      \"qZFAZR_1\".replace(re15, \"\");\n      \"qbhoyr2 ps\".replace(re14, \"\");\n      \"qbhoyr2 ps\".replace(re15, \"\");\n      \"qbhoyr2\".replace(re14, \"\");\n      \"qbhoyr2\".replace(re15, \"\");\n      \"uqy_arj\".replace(re14, \"\");\n      \"uqy_arj\".replace(re15, \"\");\n      \"uc_fubccvatobk\".replace(re30, \"\");\n      \"ugzy%2Rvq\".replace(re29, \"\");\n      \"ugzy%2Rvq\".replace(re30, \"\");\n      s101[i].replace(re33, \"\");\n      \"uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/cebgbglcr.wf${4}${5}\".replace(\n        re71,\n        \"\"\n      );\n      \"uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/cebgbglcr.wf${5}\".replace(\n        re72,\n        \"\"\n      );\n      s102[i].replace(re73, \"\");\n      \"uggc://zfacbegny.112.2b7.arg/o/ff/zfacbegnyubzr/1/U.7-cqi-2/f55332979829981?[NDO]&{1}&{2}&[NDR]\".replace(\n        re69,\n        \"\"\n      );\n      \"vztZFSG\".replace(re14, \"\");\n      \"vztZFSG\".replace(re15, \"\");\n      \"zfasbbg1 ps\".replace(re14, \"\");\n      \"zfasbbg1 ps\".replace(re15, \"\");\n      s103[i].replace(re14, \"\");\n      s103[i].replace(re15, \"\");\n      \"cnerag puebzr6 fvatyr1 gno fryrpgrq ovaq\".replace(re14, \"\");\n      \"cnerag puebzr6 fvatyr1 gno fryrpgrq ovaq\".replace(re15, \"\");\n      \"cevznel\".replace(re14, \"\");\n      \"cevznel\".replace(re15, \"\");\n      \"erpgnatyr\".replace(re30, \"\");\n      \"frpbaqnel\".replace(re14, \"\");\n      \"frpbaqnel\".replace(re15, \"\");\n      \"haybnq\".split(re70);\n      \"{0}{1}1\".replace(re63, \"\");\n      \"|{1}1\".replace(re69, \"\");\n      /(..-HF)(\\|(\\d+)|)/i.exec(\"xb-xe,ra-va,gu-gu\");\n      re4.exec(\"/ZlFcnprNccf/NccPnainf,45000012\");\n      re8.exec(\"144631658.0.10.1231367708\");\n      re8.exec(\n        \"144631658.1231367708.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)\"\n      );\n      re8.exec(\n        \"144631658.2770915348920628700.1231367708.1231367708.1231367708.1\"\n      );\n      re8.exec(\"4413235p3660\");\n      re8.exec(\"441327q73660\");\n      re8.exec(\"9995p6rp12rrnr893334ro7nq70o7p64p69rqn844prs1473\");\n      re8.exec(\"SbeprqRkcvengvba=633669350559478880\");\n      re8.exec(str54);\n      re8.exec(str55);\n      re8.exec(\"AFP_zp_dfctwzs-aowb_80=441327q73660\");\n      re8.exec(\"AFP_zp_kkk-aowb_80=4413235p3660\");\n      re8.exec(\"FrffvbaQQS2=9995p6rp12rrnr893334ro7nq70o7p64p69rqn844prs1473\");\n      re8.exec(\n        \"__hgzn=144631658.2770915348920628700.1231367708.1231367708.1231367708.1\"\n      );\n      re8.exec(\"__hgzo=144631658.0.10.1231367708\");\n      re8.exec(\n        \"__hgzm=144631658.1231367708.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)\"\n      );\n      re34.exec(s99[i]);\n      re34.exec(s100[i]);\n      /ZFVR\\s+5[.]01/.exec(s15[i]);\n      /HF(?=;)/i.exec(str56);\n      re74.exec(s97[i]);\n      re28.exec(\"svefg npgvir svefgNpgvir\");\n      re28.exec(\"ynfg\");\n      /\\bp:(..)/i.exec(\"m:94043|yn:37.4154|yb:-122.0585|p:HF\");\n      re75.exec(str57);\n      re75.exec(str58);\n      re76.exec(str57);\n      re76.exec(str58);\n      re77.exec(str57);\n      re77.exec(str58);\n      /\\bhfucce\\s*=\\s*([^;]*)/i.exec(str59);\n      re78.exec(str57);\n      re78.exec(str58);\n      /\\bjci\\s*=\\s*([^;]*)/i.exec(str59);\n      re79.exec(str58);\n      re79.exec(str60);\n      re79.exec(str59);\n      /\\|p:([a-z]{2})/i.exec(\"m:94043|yn:37.4154|yb:-122.0585|p:HF|ue:1\");\n      re80.exec(s97[i]);\n      re61.exec(\"cebgbglcr.wf\");\n      re68.exec(s97[i]);\n      re81.exec(s97[i]);\n      re82.exec(s97[i]);\n      /^Fubpxjnir Synfu (\\d)/.exec(s21[i]);\n      /^Fubpxjnir Synfu (\\d+)/.exec(s21[i]);\n      re83.exec(\"[bowrpg tybony]\");\n      re62.exec(s97[i]);\n      re84.exec(str61);\n      re84.exec(str62);\n      /jroxvg/.exec(str63);\n    }\n  }\n  var re85 = /eaq_zbqobkva/;\n  var str64 = \"1231365729213\";\n  var str65 = \"74.125.75.3-1057165600.29978900\";\n  var str66 = \"74.125.75.3-1057165600.29978900.1231365730214\";\n  var str67 = \"Frnepu%20Zvpebfbsg.pbz\";\n  var str68 =\n    \"FrffvbaQQS2=8sqq78r9n442851q565599o401385sp3s04r92rnn7o19ssn; ZFPhygher=VC=74.125.75.17&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669340386893867&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=\";\n  var str69 =\n    \"FrffvbaQQS2=8sqq78r9n442851q565599o401385sp3s04r92rnn7o19ssn; __hgzm=144631658.1231365779.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.1877536177953918500.1231365779.1231365779.1231365779.1; __hgzo=144631658.0.10.1231365779; __hgzp=144631658; ZFPhygher=VC=74.125.75.17&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669340386893867&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q\";\n  var str70 = \"I=3%26THVQ=757q3ss871q44o7o805n8113n5p72q52\";\n  var str71 = \"I=3&THVQ=757q3ss871q44o7o805n8113n5p72q52\";\n  var str72 =\n    \"uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_zlfcnpr-ubzrcntr_wf&qg=1231365765292&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231365765292&punaary=svz_zlfcnpr_ubzrcntr_abgybttrqva%2Psvz_zlfcnpr_aba_HTP%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Sohyyrgvaf.zlfcnpr.pbz%2Svaqrk.psz&nq_glcr=grkg&rvq=6083027&rn=0&sez=0&tn_ivq=1579793869.1231365768&tn_fvq=1231365768&tn_uvq=2056210897&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22\";\n  var str73 = \"frnepu.zvpebfbsg.pbz\";\n  var str74 = \"frnepu.zvpebfbsg.pbz/\";\n  var str75 =\n    \"ZFPhygher=VC=74.125.75.17&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669340386893867&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q\";\n  var str76 =\n    \"ZFPhygher=VC=74.125.75.17&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669340386893867&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=\";\n  function runBlock10() {\n    for (var i = 0; i < 3; i++) {\n      \"%3Szxg=ra-HF\".replace(re39, \"\");\n      \"-8\".replace(re40, \"\");\n      \"-8\".replace(re10, \"\");\n      \"-8\".replace(re51, \"\");\n      \"-8\".replace(re52, \"\");\n      \"-8\".replace(re53, \"\");\n      \"-8\".replace(re39, \"\");\n      \"-8\".replace(re54, \"\");\n      \"1.5\".replace(re40, \"\");\n      \"1.5\".replace(re10, \"\");\n      \"1.5\".replace(re51, \"\");\n      \"1.5\".replace(re52, \"\");\n      \"1.5\".replace(re53, \"\");\n      \"1.5\".replace(re39, \"\");\n      \"1.5\".replace(re54, \"\");\n      \"1024k768\".replace(re40, \"\");\n      \"1024k768\".replace(re10, \"\");\n      \"1024k768\".replace(re51, \"\");\n      \"1024k768\".replace(re52, \"\");\n      \"1024k768\".replace(re53, \"\");\n      \"1024k768\".replace(re39, \"\");\n      \"1024k768\".replace(re54, \"\");\n      str64.replace(re40, \"\");\n      str64.replace(re10, \"\");\n      str64.replace(re51, \"\");\n      str64.replace(re52, \"\");\n      str64.replace(re53, \"\");\n      str64.replace(re39, \"\");\n      str64.replace(re54, \"\");\n      \"14\".replace(re40, \"\");\n      \"14\".replace(re10, \"\");\n      \"14\".replace(re51, \"\");\n      \"14\".replace(re52, \"\");\n      \"14\".replace(re53, \"\");\n      \"14\".replace(re39, \"\");\n      \"14\".replace(re54, \"\");\n      \"24\".replace(re40, \"\");\n      \"24\".replace(re10, \"\");\n      \"24\".replace(re51, \"\");\n      \"24\".replace(re52, \"\");\n      \"24\".replace(re53, \"\");\n      \"24\".replace(re39, \"\");\n      \"24\".replace(re54, \"\");\n      str65.replace(re40, \"\");\n      str65.replace(re10, \"\");\n      str65.replace(re51, \"\");\n      str65.replace(re52, \"\");\n      str65.replace(re53, \"\");\n      str65.replace(re39, \"\");\n      str65.replace(re54, \"\");\n      str66.replace(re40, \"\");\n      str66.replace(re10, \"\");\n      str66.replace(re51, \"\");\n      str66.replace(re52, \"\");\n      str66.replace(re53, \"\");\n      str66.replace(re39, \"\");\n      str66.replace(re54, \"\");\n      \"9.0\".replace(re40, \"\");\n      \"9.0\".replace(re10, \"\");\n      \"9.0\".replace(re51, \"\");\n      \"9.0\".replace(re52, \"\");\n      \"9.0\".replace(re53, \"\");\n      \"9.0\".replace(re39, \"\");\n      \"9.0\".replace(re54, \"\");\n      \"994k634\".replace(re40, \"\");\n      \"994k634\".replace(re10, \"\");\n      \"994k634\".replace(re51, \"\");\n      \"994k634\".replace(re52, \"\");\n      \"994k634\".replace(re53, \"\");\n      \"994k634\".replace(re39, \"\");\n      \"994k634\".replace(re54, \"\");\n      \"?zxg=ra-HF\".replace(re40, \"\");\n      \"?zxg=ra-HF\".replace(re10, \"\");\n      \"?zxg=ra-HF\".replace(re51, \"\");\n      \"?zxg=ra-HF\".replace(re52, \"\");\n      \"?zxg=ra-HF\".replace(re53, \"\");\n      \"?zxg=ra-HF\".replace(re54, \"\");\n      \"PAA.pbz\".replace(re25, \"\");\n      \"PAA.pbz\".replace(re12, \"\");\n      \"PAA.pbz\".replace(re39, \"\");\n      \"Qngr & Gvzr\".replace(re25, \"\");\n      \"Qngr & Gvzr\".replace(re12, \"\");\n      \"Qngr & Gvzr\".replace(re39, \"\");\n      \"Frnepu Zvpebfbsg.pbz\".replace(re40, \"\");\n      \"Frnepu Zvpebfbsg.pbz\".replace(re54, \"\");\n      str67.replace(re10, \"\");\n      str67.replace(re51, \"\");\n      str67.replace(re52, \"\");\n      str67.replace(re53, \"\");\n      str67.replace(re39, \"\");\n      str68.split(re32);\n      str69.split(re32);\n      str70.replace(re52, \"\");\n      str70.replace(re53, \"\");\n      str70.replace(re39, \"\");\n      str71.replace(re40, \"\");\n      str71.replace(re10, \"\");\n      str71.replace(re51, \"\");\n      str71.replace(re54, \"\");\n      \"Jrngure\".replace(re25, \"\");\n      \"Jrngure\".replace(re12, \"\");\n      \"Jrngure\".replace(re39, \"\");\n      \"LbhGhor\".replace(re25, \"\");\n      \"LbhGhor\".replace(re12, \"\");\n      \"LbhGhor\".replace(re39, \"\");\n      str72.replace(re33, \"\");\n      \"erzbgr_vsenzr_1\".replace(/^erzbgr_vsenzr_/, \"\");\n      str73.replace(re40, \"\");\n      str73.replace(re10, \"\");\n      str73.replace(re51, \"\");\n      str73.replace(re52, \"\");\n      str73.replace(re53, \"\");\n      str73.replace(re39, \"\");\n      str73.replace(re54, \"\");\n      str74.replace(re40, \"\");\n      str74.replace(re10, \"\");\n      str74.replace(re51, \"\");\n      str74.replace(re52, \"\");\n      str74.replace(re53, \"\");\n      str74.replace(re39, \"\");\n      str74.replace(re54, \"\");\n      \"lhv-h\".replace(/\\-/g, \"\");\n      re9.exec(\"p\");\n      re9.exec(\"qz p\");\n      re9.exec(\"zbqynory\");\n      re9.exec(\"lhv-h svefg\");\n      re8.exec(\"144631658.0.10.1231365779\");\n      re8.exec(\n        \"144631658.1231365779.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)\"\n      );\n      re8.exec(\n        \"144631658.1877536177953918500.1231365779.1231365779.1231365779.1\"\n      );\n      re8.exec(str75);\n      re8.exec(str76);\n      re8.exec(\n        \"__hgzn=144631658.1877536177953918500.1231365779.1231365779.1231365779.1\"\n      );\n      re8.exec(\"__hgzo=144631658.0.10.1231365779\");\n      re8.exec(\n        \"__hgzm=144631658.1231365779.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)\"\n      );\n      re34.exec(str68);\n      re34.exec(str69);\n      /^$/.exec(\"\");\n      re31.exec(\"qr\");\n      /^znk\\d+$/.exec(\"\");\n      /^zva\\d+$/.exec(\"\");\n      /^erfgber$/.exec(\"\");\n      re85.exec(\"zbqobkva zbqobk_abcnqqvat \");\n      re85.exec(\"zbqgvgyr\");\n      re85.exec(\"eaq_zbqobkva \");\n      re85.exec(\"eaq_zbqgvgyr \");\n      /frpgvba\\d+_pbagragf/.exec(\"obggbz_ani\");\n    }\n  }\n  var re86 = /;\\s*/;\n  var re87 = /(\\$\\{inyhr\\})|(\\$inyhr\\b)/g;\n  var re88 = /(\\$\\{abj\\})|(\\$abj\\b)/g;\n  var re89 = /\\s+$/;\n  var re90 = /^\\s+/;\n  var re91 =\n    /(\\\\\\\"|\\x00-|\\x1f|\\x7f-|\\x9f|\\u00ad|\\u0600-|\\u0604|\\u070f|\\u17b4|\\u17b5|\\u200c-|\\u200f|\\u2028-|\\u202f|\\u2060-|\\u206f|\\ufeff|\\ufff0-|\\uffff)/g;\n  var re92 = /^(:)([\\w-]+)\\(\"?'?(.*?(\\(.*?\\))?[^(]*?)\"?'?\\)/;\n  var re93 = /^([:.#]*)((?:[\\w\\u0128-\\uffff*_-]|\\\\.)+)/;\n  var re94 = /^(\\[) *@?([\\w-]+) *([!*$^~=]*) *('?\"?)(.*?)\\4 *\\]/;\n  var str77 = \"#fubhgobk .pybfr\";\n  var str78 =\n    \"FrffvbaQQS2=102n9o0o9pq60132qn0337rr867p75953502q2s27s2s5r98; ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669341278771470&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=; AFP_zp_dfctwzssrwh-aowb_80=441326q33660\";\n  var str79 =\n    \"FrffvbaQQS2=102n9o0o9pq60132qn0337rr867p75953502q2s27s2s5r98; AFP_zp_dfctwzssrwh-aowb_80=441326q33660; __hgzm=144631658.1231365869.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.1670816052019209000.1231365869.1231365869.1231365869.1; __hgzo=144631658.0.10.1231365869; __hgzp=144631658; ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669341278771470&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q\";\n  var str80 =\n    \"FrffvbaQQS2=9995p6rp12rrnr893334ro7nq70o7p64p69rqn844prs1473; ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669350559478880&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=; AFP_zp_dfctwzs-aowb_80=441327q73660\";\n  var str81 =\n    \"FrffvbaQQS2=9995p6rp12rrnr893334ro7nq70o7p64p69rqn844prs1473; AFP_zp_dfctwzs-aowb_80=441327q73660; __hgzm=144631658.1231367054.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.1796080716621419500.1231367054.1231367054.1231367054.1; __hgzo=144631658.0.10.1231367054; __hgzp=144631658; ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669350559478880&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q\";\n  var str82 = \"[glcr=fhozvg]\";\n  var str83 = \"n.svryqOga,n.svryqOgaPnapry\";\n  var str84 = \"n.svryqOgaPnapry\";\n  var str85 = \"oyvpxchaxg\";\n  var str86 = \"qvi.bow-nppbeqvba qg\";\n  var str87 =\n    \"uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_nccf_wf&qg=1231367052227&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231367052227&punaary=svz_zlfcnpr_nccf-pnainf%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Scebsvyr.zlfcnpr.pbz%2SZbqhyrf%2SNccyvpngvbaf%2SCntrf%2SPnainf.nfck&nq_glcr=grkg&rvq=6083027&rn=0&sez=1&tn_ivq=716357910.1231367056&tn_fvq=1231367056&tn_uvq=1387206491&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22\";\n  var str88 =\n    \"uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_zlfcnpr-ubzrcntr_wf&qg=1231365851658&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231365851658&punaary=svz_zlfcnpr_ubzrcntr_abgybttrqva%2Psvz_zlfcnpr_aba_HTP%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Scebsvyrrqvg.zlfcnpr.pbz%2Svaqrk.psz&nq_glcr=grkg&rvq=6083027&rn=0&sez=0&tn_ivq=1979828129.1231365855&tn_fvq=1231365855&tn_uvq=2085229649&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22\";\n  var str89 =\n    \"uggc://zfacbegny.112.2b7.arg/o/ff/zfacbegnyubzr/1/U.7-cqi-2/f55023338617756?[NDO]&aqu=1&g=7%2S0%2S2009%2014%3N12%3N47%203%20480&af=zfacbegny&cntrAnzr=HF%20UCZFSGJ&t=uggc%3N%2S%2Sjjj.zfa.pbz%2S&f=0k0&p=43835816&x=A&oj=994&ou=634&uc=A&{2}&[NDR]\";\n  var str90 = \"zrgn[anzr=nwnkHey]\";\n  var str91 = \"anpuevpugra\";\n  var str92 =\n    \"b oS={'oT':1.1};x $8n(B){z(B!=o9)};x $S(B){O(!$8n(B))z A;O(B.4L)z'T';b S=7t B;O(S=='2P'&&B.p4){23(B.7f){12 1:z'T';12 3:z/S/.2g(B.8M)?'ox':'oh'}}O(S=='2P'||S=='x'){23(B.nE){12 2V:z'1O';12 7I:z'5a';12 18:z'4B'}O(7t B.I=='4F'){O(B.3u)z'pG';O(B.8e)z'1p'}}z S};x $2p(){b 4E={};Z(b v=0;v<1p.I;v++){Z(b X 1o 1p[v]){b nc=1p[v][X];b 6E=4E[X];O(6E&&$S(nc)=='2P'&&$S(6E)=='2P')4E[X]=$2p(6E,nc);17 4E[X]=nc}}z 4E};b $E=7p.E=x(){b 1d=1p;O(!1d[1])1d=[p,1d[0]];Z(b X 1o 1d[1])1d[0][X]=1d[1][X];z 1d[0]};b $4D=7p.pJ=x(){Z(b v=0,y=1p.I;v<y;v++){1p[v].E=x(1J){Z(b 1I 1o 1J){O(!p.1Y[1I])p.1Y[1I]=1J[1I];O(!p[1I])p[1I]=$4D.6C(1I)}}}};$4D.6C=x(1I){z x(L){z p.1Y[1I].3H(L,2V.1Y.nV.1F(1p,1))}};$4D(7F,2V,6J,nb);b 3l=x(B){B=B||{};B.E=$E;z B};b pK=Y 3l(H);b pZ=Y 3l(C);C.6f=C.35('6f')[0];x $2O(B){z!!(B||B===0)};x $5S(B,n8){z $8n(B)?B:n8};x $7K(3c,1m){z 1q.na(1q.7K()*(1m-3c+1)+3c)};x $3N(){z Y 97().os()};x $4M(1U){pv(1U);pa(1U);z 1S};H.43=!!(C.5Z);O(H.nB)H.31=H[H.7q?'py':'nL']=1r;17 O(C.9N&&!C.om&&!oy.oZ)H.pF=H.4Z=H[H.43?'pt':'65']=1r;17 O(C.po!=1S)H.7J=1r;O(7t 5B=='o9'){b 5B=x(){};O(H.4Z)C.nd(\\\"pW\\\");5B.1Y=(H.4Z)?H[\\\"[[oN.1Y]]\\\"]:{}}5B.1Y.4L=1r;O(H.nL)5s{C.oX(\\\"pp\\\",A,1r)}4K(r){};b 18=x(1X){b 63=x(){z(1p[0]!==1S&&p.1w&&$S(p.1w)=='x')?p.1w.3H(p,1p):p};$E(63,p);63.1Y=1X;63.nE=18;z 63};18.1z=x(){};18.1Y={E:x(1X){b 7x=Y p(1S);Z(b X 1o 1X){b nC=7x[X];7x[X]=18.nY(nC,1X[X])}z Y 18(7x)},3d:x(){Z(b v=0,y=1p.I;v<y;v++)$E(p.1Y,1p[v])}};18.nY=x(2b,2n){O(2b&&2b!=2n){b S=$S(2n);O(S!=$S(2b))z 2n;23(S){12'x':b 7R=x(){p.1e=1p.8e.1e;z 2n.3H(p,1p)};7R.1e=2b;z 7R;12'2P':z $2p(2b,2n)}}z 2n};b 8o=Y 18({oQ:x(J){p.4w=p.4w||[];p.4w.1x(J);z p},7g:x(){O(p.4w&&p.4w.I)p.4w.9J().2x(10,p)},oP:x(){p.4w=[]}});b 2d=Y 18({1V:x(S,J){O(J!=18.1z){p.$19=p.$19||{};p.$19[S]=p.$19[S]||[];p.$19[S].5j(J)}z p},1v:x(S,1d,2x){O(p.$19&&p.$19[S]){p.$19[S].1b(x(J){J.3n({'L':p,'2x':2x,'1p':1d})()},p)}z p},3M:x(S,J){O(p.$19&&p.$19[S])p.$19[S].2U(J);z p}});b 4v=Y 18({2H:x(){p.P=$2p.3H(1S,[p.P].E(1p));O(!p.1V)z p;Z(b 3O 1o p.P){O($S(p.P[3O]=='x')&&3O.2g(/^5P[N-M]/))p.1V(3O,p.P[3O])}z p}});2V.E({7y:x(J,L){Z(b v=0,w=p.I;v<w;v++)J.1F(L,p[v],v,p)},3s:x(J,L){b 54=[];Z(b v=0,w=p.I;v<w;v++){O(J.1F(L,p[v],v,p))54.1x(p[v])}z 54},2X:x(J,L){b 54=[];Z(b v=0,w=p.I;v<w;v++)54[v]=J.1F(L,p[v],v,p);z 54},4i:x(J,L){Z(b v=0,w=p.I;v<w;v++){O(!J.1F(L,p[v],v,p))z A}z 1r},ob:x(J,L){Z(b v=0,w=p.I;v<w;v++){O(J.1F(L,p[v],v,p))z 1r}z A},3F:x(3u,15){b 3A=p.I;Z(b v=(15<0)?1q.1m(0,3A+15):15||0;v<3A;v++){O(p[v]===3u)z v}z-1},8z:x(1u,I){1u=1u||0;O(1u<0)1u=p.I+1u;I=I||(p.I-1u);b 89=[];Z(b v=0;v<I;v++)89[v]=p[1u++];z 89},2U:x(3u){b v=0;b 3A=p.I;6L(v<3A){O(p[v]===3u){p.6l(v,1);3A--}17{v++}}z p},1y:x(3u,15){z p.3F(3u,15)!=-1},oz:x(1C){b B={},I=1q.3c(p.I,1C.I);Z(b v=0;v<I;v++)B[1C[v]]=p[v];z B},E:x(1O){Z(b v=0,w=1O.I;v<w;v++)p.1x(1O[v]);z p},2p:x(1O){Z(b v=0,y=1O.I;v<y;v++)p.5j(1O[v]);z p},5j:x(3u){O(!p.1y(3u))p.1x(3u);z p},oc:x(){z p[$7K(0,p.I-1)]||A},7L:x(){z p[p.I-1]||A}});2V.1Y.1b=2V.1Y.7y;2V.1Y.2g=2V.1Y.1y;x $N(1O){z 2V.8z(1O)};x $1b(3J,J,L){O(3J&&7t 3J.I=='4F'&&$S(3J)!='2P')2V.7y(3J,J,L);17 Z(b 1j 1o 3J)J.1F(L||3J,3J[1j],1j)};6J.E({2g:x(6b,2F){z(($S(6b)=='2R')?Y 7I(6b,2F):6b).2g(p)},3p:x(){z 5K(p,10)},o4:x(){z 69(p)},7A:x(){z p.3y(/-D/t,x(2G){z 2G.7G(1).nW()})},9b:x(){z p.3y(/w[N-M]/t,x(2G){z(2G.7G(0)+'-'+2G.7G(1).5O())})},8V:x(){z p.3y(/\\b[n-m]/t,x(2G){z 2G.nW()})},5L:x(){z p.3y(/^s+|s+$/t,'')},7j:x(){z p.3y(/s{2,}/t,' ').5L()},5V:x(1O){b 1i=p.2G(/d{1,3}/t);z(1i)?1i.5V(1O):A},5U:x(1O){b 3P=p.2G(/^#?(w{1,2})(w{1,2})(w{1,2})$/);z(3P)?3P.nV(1).5U(1O):A},1y:x(2R,f){z(f)?(f+p+f).3F(f+2R+f)>-1:p.3F(2R)>-1},nX:x(){z p.3y(/([.*+?^${}()|[]/\\\\])/t,'\\\\$1')}});2V.E({5V:x(1O){O(p.I<3)z A;O(p.I==4&&p[3]==0&&!1O)z'p5';b 3P=[];Z(b v=0;v<3;v++){b 52=(p[v]-0).4h(16);3P.1x((52.I==1)?'0'+52:52)}z 1O?3P:'#'+3P.2u('')},5U:x(1O){O(p.I!=3)z A;b 1i=[];Z(b v=0;v<3;v++){1i.1x(5K((p[v].I==1)?p[v]+p[v]:p[v],16))}z 1O?1i:'1i('+1i.2u(',')+')'}});7F.E({3n:x(P){b J=p;P=$2p({'L':J,'V':A,'1p':1S,'2x':A,'4s':A,'6W':A},P);O($2O(P.1p)&&$S(P.1p)!='1O')P.1p=[P.1p];z x(V){b 1d;O(P.V){V=V||H.V;1d=[(P.V===1r)?V:Y P.V(V)];O(P.1p)1d.E(P.1p)}17 1d=P.1p||1p;b 3C=x(){z J.3H($5S(P\";\n  var str93 = \"hagreunyghat\";\n  var str94 =\n    \"ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669341278771470&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q\";\n  var str95 =\n    \"ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669350559478880&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q\";\n  var str96 =\n    \"ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669341278771470&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=\";\n  var str97 =\n    \"ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669350559478880&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=\";\n  var str98 =\n    \"shapgvba (){Cuk.Nccyvpngvba.Frghc.Pber();Cuk.Nccyvpngvba.Frghc.Nwnk();Cuk.Nccyvpngvba.Frghc.Synfu();Cuk.Nccyvpngvba.Frghc.Zbqhyrf()}\";\n  function runBlock11() {\n    for (var i = 0; i < 2; i++) {\n      \" .pybfr\".replace(re18, \"\");\n      \" n.svryqOgaPnapry\".replace(re18, \"\");\n      \" qg\".replace(re18, \"\");\n      str77.replace(re68, \"\");\n      str77.replace(re18, \"\");\n      \"\".replace(re39, \"\");\n      \"\".replace(/^/, \"\");\n      \"\".split(re86);\n      \"*\".replace(re39, \"\");\n      \"*\".replace(re68, \"\");\n      \"*\".replace(re18, \"\");\n      \".pybfr\".replace(re68, \"\");\n      \".pybfr\".replace(re18, \"\");\n      \"//vzt.jro.qr/vij/FC/tzk_uc/fperra/${inyhr}?gf=${abj}\".replace(re87, \"\");\n      \"//vzt.jro.qr/vij/FC/tzk_uc/fperra/1024?gf=${abj}\".replace(re88, \"\");\n      \"//vzt.jro.qr/vij/FC/tzk_uc/jvafvmr/${inyhr}?gf=${abj}\".replace(re87, \"\");\n      \"//vzt.jro.qr/vij/FC/tzk_uc/jvafvmr/992/608?gf=${abj}\".replace(re88, \"\");\n      \"300k120\".replace(re30, \"\");\n      \"300k250\".replace(re30, \"\");\n      \"310k120\".replace(re30, \"\");\n      \"310k170\".replace(re30, \"\");\n      \"310k250\".replace(re30, \"\");\n      \"9.0  e115\".replace(/^.*\\.(.*)\\s.*$/, \"\");\n      \"Nppbeqvba\".replace(re2, \"\");\n      \"Nxghryy\\x0a\".replace(re89, \"\");\n      \"Nxghryy\\x0a\".replace(re90, \"\");\n      \"Nccyvpngvba\".replace(re2, \"\");\n      \"Oyvpxchaxg\\x0a\".replace(re89, \"\");\n      \"Oyvpxchaxg\\x0a\".replace(re90, \"\");\n      \"Svanamra\\x0a\".replace(re89, \"\");\n      \"Svanamra\\x0a\".replace(re90, \"\");\n      \"Tnzrf\\x0a\".replace(re89, \"\");\n      \"Tnzrf\\x0a\".replace(re90, \"\");\n      \"Ubebfxbc\\x0a\".replace(re89, \"\");\n      \"Ubebfxbc\\x0a\".replace(re90, \"\");\n      \"Xvab\\x0a\".replace(re89, \"\");\n      \"Xvab\\x0a\".replace(re90, \"\");\n      \"Zbqhyrf\".replace(re2, \"\");\n      \"Zhfvx\\x0a\".replace(re89, \"\");\n      \"Zhfvx\\x0a\".replace(re90, \"\");\n      \"Anpuevpugra\\x0a\".replace(re89, \"\");\n      \"Anpuevpugra\\x0a\".replace(re90, \"\");\n      \"Cuk\".replace(re2, \"\");\n      \"ErdhrfgSvavfu\".split(re70);\n      \"ErdhrfgSvavfu.NWNK.Cuk\".split(re70);\n      \"Ebhgr\\x0a\".replace(re89, \"\");\n      \"Ebhgr\\x0a\".replace(re90, \"\");\n      str78.split(re32);\n      str79.split(re32);\n      str80.split(re32);\n      str81.split(re32);\n      \"Fcbeg\\x0a\".replace(re89, \"\");\n      \"Fcbeg\\x0a\".replace(re90, \"\");\n      \"GI-Fcbg\\x0a\".replace(re89, \"\");\n      \"GI-Fcbg\\x0a\".replace(re90, \"\");\n      \"Gbhe\\x0a\".replace(re89, \"\");\n      \"Gbhe\\x0a\".replace(re90, \"\");\n      \"Hagreunyghat\\x0a\".replace(re89, \"\");\n      \"Hagreunyghat\\x0a\".replace(re90, \"\");\n      \"Ivqrb\\x0a\".replace(re89, \"\");\n      \"Ivqrb\\x0a\".replace(re90, \"\");\n      \"Jrggre\\x0a\".replace(re89, \"\");\n      \"Jrggre\\x0a\".replace(re90, \"\");\n      str82.replace(re68, \"\");\n      str82.replace(re18, \"\");\n      str83.replace(re68, \"\");\n      str83.replace(re18, \"\");\n      str84.replace(re68, \"\");\n      str84.replace(re18, \"\");\n      \"nqiFreivprObk\".replace(re30, \"\");\n      \"nqiFubccvatObk\".replace(re30, \"\");\n      \"nwnk\".replace(re39, \"\");\n      \"nxghryy\".replace(re40, \"\");\n      \"nxghryy\".replace(re41, \"\");\n      \"nxghryy\".replace(re42, \"\");\n      \"nxghryy\".replace(re43, \"\");\n      \"nxghryy\".replace(re44, \"\");\n      \"nxghryy\".replace(re45, \"\");\n      \"nxghryy\".replace(re46, \"\");\n      \"nxghryy\".replace(re47, \"\");\n      \"nxghryy\".replace(re48, \"\");\n      str85.replace(re40, \"\");\n      str85.replace(re41, \"\");\n      str85.replace(re42, \"\");\n      str85.replace(re43, \"\");\n      str85.replace(re44, \"\");\n      str85.replace(re45, \"\");\n      str85.replace(re46, \"\");\n      str85.replace(re47, \"\");\n      str85.replace(re48, \"\");\n      \"pngrtbel\".replace(re29, \"\");\n      \"pngrtbel\".replace(re30, \"\");\n      \"pybfr\".replace(re39, \"\");\n      \"qvi\".replace(re39, \"\");\n      str86.replace(re68, \"\");\n      str86.replace(re18, \"\");\n      \"qg\".replace(re39, \"\");\n      \"qg\".replace(re68, \"\");\n      \"qg\".replace(re18, \"\");\n      \"rzorq\".replace(re39, \"\");\n      \"rzorq\".replace(re68, \"\");\n      \"rzorq\".replace(re18, \"\");\n      \"svryqOga\".replace(re39, \"\");\n      \"svryqOgaPnapry\".replace(re39, \"\");\n      \"svz_zlfcnpr_nccf-pnainf,svz_zlfcnpr_havgrq-fgngrf\".split(re20);\n      \"svanamra\".replace(re40, \"\");\n      \"svanamra\".replace(re41, \"\");\n      \"svanamra\".replace(re42, \"\");\n      \"svanamra\".replace(re43, \"\");\n      \"svanamra\".replace(re44, \"\");\n      \"svanamra\".replace(re45, \"\");\n      \"svanamra\".replace(re46, \"\");\n      \"svanamra\".replace(re47, \"\");\n      \"svanamra\".replace(re48, \"\");\n      \"sbphf\".split(re70);\n      \"sbphf.gno sbphfva.gno\".split(re70);\n      \"sbphfva\".split(re70);\n      \"sbez\".replace(re39, \"\");\n      \"sbez.nwnk\".replace(re68, \"\");\n      \"sbez.nwnk\".replace(re18, \"\");\n      \"tnzrf\".replace(re40, \"\");\n      \"tnzrf\".replace(re41, \"\");\n      \"tnzrf\".replace(re42, \"\");\n      \"tnzrf\".replace(re43, \"\");\n      \"tnzrf\".replace(re44, \"\");\n      \"tnzrf\".replace(re45, \"\");\n      \"tnzrf\".replace(re46, \"\");\n      \"tnzrf\".replace(re47, \"\");\n      \"tnzrf\".replace(re48, \"\");\n      \"ubzrcntr\".replace(re30, \"\");\n      \"ubebfxbc\".replace(re40, \"\");\n      \"ubebfxbc\".replace(re41, \"\");\n      \"ubebfxbc\".replace(re42, \"\");\n      \"ubebfxbc\".replace(re43, \"\");\n      \"ubebfxbc\".replace(re44, \"\");\n      \"ubebfxbc\".replace(re45, \"\");\n      \"ubebfxbc\".replace(re46, \"\");\n      \"ubebfxbc\".replace(re47, \"\");\n      \"ubebfxbc\".replace(re48, \"\");\n      \"uc_cebzbobk_ugzy%2Puc_cebzbobk_vzt\".replace(re30, \"\");\n      \"uc_erpgnatyr\".replace(re30, \"\");\n      str87.replace(re33, \"\");\n      str88.replace(re33, \"\");\n      \"uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/onfr.wf${4}${5}\".replace(\n        re71,\n        \"\"\n      );\n      \"uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/onfr.wf${5}\".replace(\n        re72,\n        \"\"\n      );\n      \"uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/qlaYvo.wf${4}${5}\".replace(\n        re71,\n        \"\"\n      );\n      \"uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/qlaYvo.wf${5}\".replace(\n        re72,\n        \"\"\n      );\n      \"uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/rssrpgYvo.wf${4}${5}\".replace(\n        re71,\n        \"\"\n      );\n      \"uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/rssrpgYvo.wf${5}\".replace(\n        re72,\n        \"\"\n      );\n      str89.replace(re73, \"\");\n      \"uggc://zfacbegny.112.2b7.arg/o/ff/zfacbegnyubzr/1/U.7-cqi-2/f55023338617756?[NDO]&{1}&{2}&[NDR]\".replace(\n        re69,\n        \"\"\n      );\n      str6.replace(re23, \"\");\n      \"xvab\".replace(re40, \"\");\n      \"xvab\".replace(re41, \"\");\n      \"xvab\".replace(re42, \"\");\n      \"xvab\".replace(re43, \"\");\n      \"xvab\".replace(re44, \"\");\n      \"xvab\".replace(re45, \"\");\n      \"xvab\".replace(re46, \"\");\n      \"xvab\".replace(re47, \"\");\n      \"xvab\".replace(re48, \"\");\n      \"ybnq\".split(re70);\n      \"zrqvnzbqgno lhv-anifrg lhv-anifrg-gbc\".replace(re18, \"\");\n      \"zrgn\".replace(re39, \"\");\n      str90.replace(re68, \"\");\n      str90.replace(re18, \"\");\n      \"zbhfrzbir\".split(re70);\n      \"zbhfrzbir.gno\".split(re70);\n      str63.replace(/^.*jroxvg\\/(\\d+(\\.\\d+)?).*$/, \"\");\n      \"zhfvx\".replace(re40, \"\");\n      \"zhfvx\".replace(re41, \"\");\n      \"zhfvx\".replace(re42, \"\");\n      \"zhfvx\".replace(re43, \"\");\n      \"zhfvx\".replace(re44, \"\");\n      \"zhfvx\".replace(re45, \"\");\n      \"zhfvx\".replace(re46, \"\");\n      \"zhfvx\".replace(re47, \"\");\n      \"zhfvx\".replace(re48, \"\");\n      \"zlfcnpr_nccf_pnainf\".replace(re52, \"\");\n      str91.replace(re40, \"\");\n      str91.replace(re41, \"\");\n      str91.replace(re42, \"\");\n      str91.replace(re43, \"\");\n      str91.replace(re44, \"\");\n      str91.replace(re45, \"\");\n      str91.replace(re46, \"\");\n      str91.replace(re47, \"\");\n      str91.replace(re48, \"\");\n      \"anzr\".replace(re39, \"\");\n      str92.replace(/\\b\\w+\\b/g, \"\");\n      \"bow-nppbeqvba\".replace(re39, \"\");\n      \"bowrpg\".replace(re39, \"\");\n      \"bowrpg\".replace(re68, \"\");\n      \"bowrpg\".replace(re18, \"\");\n      \"cnenzf%2Rfglyrf\".replace(re29, \"\");\n      \"cnenzf%2Rfglyrf\".replace(re30, \"\");\n      \"cbchc\".replace(re30, \"\");\n      \"ebhgr\".replace(re40, \"\");\n      \"ebhgr\".replace(re41, \"\");\n      \"ebhgr\".replace(re42, \"\");\n      \"ebhgr\".replace(re43, \"\");\n      \"ebhgr\".replace(re44, \"\");\n      \"ebhgr\".replace(re45, \"\");\n      \"ebhgr\".replace(re46, \"\");\n      \"ebhgr\".replace(re47, \"\");\n      \"ebhgr\".replace(re48, \"\");\n      \"freivprobk_uc\".replace(re30, \"\");\n      \"fubccvatobk_uc\".replace(re30, \"\");\n      \"fubhgobk\".replace(re39, \"\");\n      \"fcbeg\".replace(re40, \"\");\n      \"fcbeg\".replace(re41, \"\");\n      \"fcbeg\".replace(re42, \"\");\n      \"fcbeg\".replace(re43, \"\");\n      \"fcbeg\".replace(re44, \"\");\n      \"fcbeg\".replace(re45, \"\");\n      \"fcbeg\".replace(re46, \"\");\n      \"fcbeg\".replace(re47, \"\");\n      \"fcbeg\".replace(re48, \"\");\n      \"gbhe\".replace(re40, \"\");\n      \"gbhe\".replace(re41, \"\");\n      \"gbhe\".replace(re42, \"\");\n      \"gbhe\".replace(re43, \"\");\n      \"gbhe\".replace(re44, \"\");\n      \"gbhe\".replace(re45, \"\");\n      \"gbhe\".replace(re46, \"\");\n      \"gbhe\".replace(re47, \"\");\n      \"gbhe\".replace(re48, \"\");\n      \"gi-fcbg\".replace(re40, \"\");\n      \"gi-fcbg\".replace(re41, \"\");\n      \"gi-fcbg\".replace(re42, \"\");\n      \"gi-fcbg\".replace(re43, \"\");\n      \"gi-fcbg\".replace(re44, \"\");\n      \"gi-fcbg\".replace(re45, \"\");\n      \"gi-fcbg\".replace(re46, \"\");\n      \"gi-fcbg\".replace(re47, \"\");\n      \"gi-fcbg\".replace(re48, \"\");\n      \"glcr\".replace(re39, \"\");\n      \"haqrsvarq\".replace(/\\//g, \"\");\n      str93.replace(re40, \"\");\n      str93.replace(re41, \"\");\n      str93.replace(re42, \"\");\n      str93.replace(re43, \"\");\n      str93.replace(re44, \"\");\n      str93.replace(re45, \"\");\n      str93.replace(re46, \"\");\n      str93.replace(re47, \"\");\n      str93.replace(re48, \"\");\n      \"ivqrb\".replace(re40, \"\");\n      \"ivqrb\".replace(re41, \"\");\n      \"ivqrb\".replace(re42, \"\");\n      \"ivqrb\".replace(re43, \"\");\n      \"ivqrb\".replace(re44, \"\");\n      \"ivqrb\".replace(re45, \"\");\n      \"ivqrb\".replace(re46, \"\");\n      \"ivqrb\".replace(re47, \"\");\n      \"ivqrb\".replace(re48, \"\");\n      \"ivfvgf=1\".split(re86);\n      \"jrggre\".replace(re40, \"\");\n      \"jrggre\".replace(re41, \"\");\n      \"jrggre\".replace(re42, \"\");\n      \"jrggre\".replace(re43, \"\");\n      \"jrggre\".replace(re44, \"\");\n      \"jrggre\".replace(re45, \"\");\n      \"jrggre\".replace(re46, \"\");\n      \"jrggre\".replace(re47, \"\");\n      \"jrggre\".replace(re48, \"\");\n      /#[a-z0-9]+$/i.exec(\"uggc://jjj.fpuhryreim.arg/Qrsnhyg\");\n      re66.exec(\"fryrpgrq\");\n      /(?:^|\\s+)lhv-ani(?:\\s+|$)/.exec(\"sff lhv-ani\");\n      /(?:^|\\s+)lhv-anifrg(?:\\s+|$)/.exec(\"zrqvnzbqgno lhv-anifrg\");\n      /(?:^|\\s+)lhv-anifrg-gbc(?:\\s+|$)/.exec(\"zrqvnzbqgno lhv-anifrg\");\n      re91.exec(\"GnoThvq\");\n      re91.exec(\"thvq\");\n      /(pbzcngvoyr|jroxvg)/.exec(str63);\n      /.+(?:ei|vg|en|vr)[\\/: ]([\\d.]+)/.exec(str63);\n      re8.exec(\"144631658.0.10.1231365869\");\n      re8.exec(\"144631658.0.10.1231367054\");\n      re8.exec(\n        \"144631658.1231365869.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)\"\n      );\n      re8.exec(\n        \"144631658.1231367054.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)\"\n      );\n      re8.exec(\n        \"144631658.1670816052019209000.1231365869.1231365869.1231365869.1\"\n      );\n      re8.exec(\n        \"144631658.1796080716621419500.1231367054.1231367054.1231367054.1\"\n      );\n      re8.exec(str94);\n      re8.exec(str95);\n      re8.exec(str96);\n      re8.exec(str97);\n      re8.exec(\n        \"__hgzn=144631658.1670816052019209000.1231365869.1231365869.1231365869.1\"\n      );\n      re8.exec(\n        \"__hgzn=144631658.1796080716621419500.1231367054.1231367054.1231367054.1\"\n      );\n      re8.exec(\"__hgzo=144631658.0.10.1231365869\");\n      re8.exec(\"__hgzo=144631658.0.10.1231367054\");\n      re8.exec(\n        \"__hgzm=144631658.1231365869.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)\"\n      );\n      re8.exec(\n        \"__hgzm=144631658.1231367054.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)\"\n      );\n      re34.exec(str78);\n      re34.exec(str79);\n      re34.exec(str81);\n      re74.exec(str77);\n      re74.exec(\"*\");\n      re74.exec(str82);\n      re74.exec(str83);\n      re74.exec(str86);\n      re74.exec(\"rzorq\");\n      re74.exec(\"sbez.nwnk\");\n      re74.exec(str90);\n      re74.exec(\"bowrpg\");\n      /\\/onfr.wf(\\?.+)?$/.exec(\n        \"/uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/onfr.wf\"\n      );\n      re28.exec(\"uvag ynfgUvag ynfg\");\n      re75.exec(\"\");\n      re76.exec(\"\");\n      re77.exec(\"\");\n      re78.exec(\"\");\n      re80.exec(str77);\n      re80.exec(\"*\");\n      re80.exec(\".pybfr\");\n      re80.exec(str82);\n      re80.exec(str83);\n      re80.exec(str84);\n      re80.exec(str86);\n      re80.exec(\"qg\");\n      re80.exec(\"rzorq\");\n      re80.exec(\"sbez.nwnk\");\n      re80.exec(str90);\n      re80.exec(\"bowrpg\");\n      re61.exec(\"qlaYvo.wf\");\n      re61.exec(\"rssrpgYvo.wf\");\n      re61.exec(\"uggc://jjj.tzk.arg/qr/?fgnghf=uvajrvf\");\n      re92.exec(\" .pybfr\");\n      re92.exec(\" n.svryqOgaPnapry\");\n      re92.exec(\" qg\");\n      re92.exec(str48);\n      re92.exec(\".nwnk\");\n      re92.exec(\".svryqOga,n.svryqOgaPnapry\");\n      re92.exec(\".svryqOgaPnapry\");\n      re92.exec(\".bow-nppbeqvba qg\");\n      re68.exec(str77);\n      re68.exec(\"*\");\n      re68.exec(\".pybfr\");\n      re68.exec(str82);\n      re68.exec(str83);\n      re68.exec(str84);\n      re68.exec(str86);\n      re68.exec(\"qg\");\n      re68.exec(\"rzorq\");\n      re68.exec(\"sbez.nwnk\");\n      re68.exec(str90);\n      re68.exec(\"bowrpg\");\n      re93.exec(\" .pybfr\");\n      re93.exec(\" n.svryqOgaPnapry\");\n      re93.exec(\" qg\");\n      re93.exec(str48);\n      re93.exec(\".nwnk\");\n      re93.exec(\".svryqOga,n.svryqOgaPnapry\");\n      re93.exec(\".svryqOgaPnapry\");\n      re93.exec(\".bow-nppbeqvba qg\");\n      re81.exec(str77);\n      re81.exec(\"*\");\n      re81.exec(str48);\n      re81.exec(\".pybfr\");\n      re81.exec(str82);\n      re81.exec(str83);\n      re81.exec(str84);\n      re81.exec(str86);\n      re81.exec(\"qg\");\n      re81.exec(\"rzorq\");\n      re81.exec(\"sbez.nwnk\");\n      re81.exec(str90);\n      re81.exec(\"bowrpg\");\n      re94.exec(\" .pybfr\");\n      re94.exec(\" n.svryqOgaPnapry\");\n      re94.exec(\" qg\");\n      re94.exec(str48);\n      re94.exec(\".nwnk\");\n      re94.exec(\".svryqOga,n.svryqOgaPnapry\");\n      re94.exec(\".svryqOgaPnapry\");\n      re94.exec(\".bow-nppbeqvba qg\");\n      re94.exec(\"[anzr=nwnkHey]\");\n      re94.exec(str82);\n      re31.exec(\"rf\");\n      re31.exec(\"wn\");\n      re82.exec(str77);\n      re82.exec(\"*\");\n      re82.exec(str48);\n      re82.exec(\".pybfr\");\n      re82.exec(str82);\n      re82.exec(str83);\n      re82.exec(str84);\n      re82.exec(str86);\n      re82.exec(\"qg\");\n      re82.exec(\"rzorq\");\n      re82.exec(\"sbez.nwnk\");\n      re82.exec(str90);\n      re82.exec(\"bowrpg\");\n      re83.exec(str98);\n      re83.exec(\"shapgvba sbphf() { [angvir pbqr] }\");\n      re62.exec(\"#Ybtva\");\n      re62.exec(\"#Ybtva_cnffjbeq\");\n      re62.exec(str77);\n      re62.exec(\"#fubhgobkWf\");\n      re62.exec(\"#fubhgobkWfReebe\");\n      re62.exec(\"#fubhgobkWfFhpprff\");\n      re62.exec(\"*\");\n      re62.exec(str82);\n      re62.exec(str83);\n      re62.exec(str86);\n      re62.exec(\"rzorq\");\n      re62.exec(\"sbez.nwnk\");\n      re62.exec(str90);\n      re62.exec(\"bowrpg\");\n      re49.exec(\"pbagrag\");\n      re24.exec(str6);\n      /xbadhrebe/.exec(str63);\n      /znp/.exec(\"jva32\");\n      /zbmvyyn/.exec(str63);\n      /zfvr/.exec(str63);\n      /ag\\s5\\.1/.exec(str63);\n      /bcren/.exec(str63);\n      /fnsnev/.exec(str63);\n      /jva/.exec(\"jva32\");\n      /jvaqbjf/.exec(str63);\n    }\n  }\n\n  function run() {\n    for (var i = 0; i < 5; i++) {\n      runBlock0();\n      runBlock1();\n      runBlock2();\n      runBlock3();\n      runBlock4();\n      runBlock5();\n      runBlock6();\n      runBlock7();\n      runBlock8();\n      runBlock9();\n      runBlock10();\n      runBlock11();\n    }\n  }\n\n  this.run = run;\n}\n"
  },
  {
    "path": "benchmarks/v8-v7/richards.js",
    "content": "// Copyright 2006-2008 the V8 project authors. All rights reserved.\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\n//       disclaimer in the documentation and/or other materials provided\n//       with the distribution.\n//     * Neither the name of Google Inc. nor the names of its\n//       contributors may be used to endorse or promote products derived\n//       from 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// This is a JavaScript implementation of the Richards\n// benchmark from:\n//\n//    http://www.cl.cam.ac.uk/~mr10/Bench.html\n//\n// The benchmark was originally implemented in BCPL by\n// Martin Richards.\n\nvar Richards = new BenchmarkSuite(\"Richards\", 35302, [\n  new Benchmark(\"Richards\", runRichards),\n]);\n\n/**\n * The Richards benchmark simulates the task dispatcher of an\n * operating system.\n **/\nfunction runRichards() {\n  var scheduler = new Scheduler();\n  scheduler.addIdleTask(ID_IDLE, 0, null, COUNT);\n\n  var queue = new Packet(null, ID_WORKER, KIND_WORK);\n  queue = new Packet(queue, ID_WORKER, KIND_WORK);\n  scheduler.addWorkerTask(ID_WORKER, 1000, queue);\n\n  queue = new Packet(null, ID_DEVICE_A, KIND_DEVICE);\n  queue = new Packet(queue, ID_DEVICE_A, KIND_DEVICE);\n  queue = new Packet(queue, ID_DEVICE_A, KIND_DEVICE);\n  scheduler.addHandlerTask(ID_HANDLER_A, 2000, queue);\n\n  queue = new Packet(null, ID_DEVICE_B, KIND_DEVICE);\n  queue = new Packet(queue, ID_DEVICE_B, KIND_DEVICE);\n  queue = new Packet(queue, ID_DEVICE_B, KIND_DEVICE);\n  scheduler.addHandlerTask(ID_HANDLER_B, 3000, queue);\n\n  scheduler.addDeviceTask(ID_DEVICE_A, 4000, null);\n\n  scheduler.addDeviceTask(ID_DEVICE_B, 5000, null);\n\n  scheduler.schedule();\n\n  if (\n    scheduler.queueCount != EXPECTED_QUEUE_COUNT ||\n    scheduler.holdCount != EXPECTED_HOLD_COUNT\n  ) {\n    var msg =\n      \"Error during execution: queueCount = \" +\n      scheduler.queueCount +\n      \", holdCount = \" +\n      scheduler.holdCount +\n      \".\";\n    throw new Error(msg);\n  }\n}\n\nvar COUNT = 1000;\n\n/**\n * These two constants specify how many times a packet is queued and\n * how many times a task is put on hold in a correct run of richards.\n * They don't have any meaning a such but are characteristic of a\n * correct run so if the actual queue or hold count is different from\n * the expected there must be a bug in the implementation.\n **/\nvar EXPECTED_QUEUE_COUNT = 2322;\nvar EXPECTED_HOLD_COUNT = 928;\n\n/**\n * A scheduler can be used to schedule a set of tasks based on their relative\n * priorities.  Scheduling is done by maintaining a list of task control blocks\n * which holds tasks and the data queue they are processing.\n * @constructor\n */\nfunction Scheduler() {\n  this.queueCount = 0;\n  this.holdCount = 0;\n  this.blocks = new Array(NUMBER_OF_IDS);\n  this.list = null;\n  this.currentTcb = null;\n  this.currentId = null;\n}\n\nvar ID_IDLE = 0;\nvar ID_WORKER = 1;\nvar ID_HANDLER_A = 2;\nvar ID_HANDLER_B = 3;\nvar ID_DEVICE_A = 4;\nvar ID_DEVICE_B = 5;\nvar NUMBER_OF_IDS = 6;\n\nvar KIND_DEVICE = 0;\nvar KIND_WORK = 1;\n\n/**\n * Add an idle task to this scheduler.\n * @param {int} id the identity of the task\n * @param {int} priority the task's priority\n * @param {Packet} queue the queue of work to be processed by the task\n * @param {int} count the number of times to schedule the task\n */\nScheduler.prototype.addIdleTask = function (id, priority, queue, count) {\n  this.addRunningTask(id, priority, queue, new IdleTask(this, 1, count));\n};\n\n/**\n * Add a work task to this scheduler.\n * @param {int} id the identity of the task\n * @param {int} priority the task's priority\n * @param {Packet} queue the queue of work to be processed by the task\n */\nScheduler.prototype.addWorkerTask = function (id, priority, queue) {\n  this.addTask(id, priority, queue, new WorkerTask(this, ID_HANDLER_A, 0));\n};\n\n/**\n * Add a handler task to this scheduler.\n * @param {int} id the identity of the task\n * @param {int} priority the task's priority\n * @param {Packet} queue the queue of work to be processed by the task\n */\nScheduler.prototype.addHandlerTask = function (id, priority, queue) {\n  this.addTask(id, priority, queue, new HandlerTask(this));\n};\n\n/**\n * Add a handler task to this scheduler.\n * @param {int} id the identity of the task\n * @param {int} priority the task's priority\n * @param {Packet} queue the queue of work to be processed by the task\n */\nScheduler.prototype.addDeviceTask = function (id, priority, queue) {\n  this.addTask(id, priority, queue, new DeviceTask(this));\n};\n\n/**\n * Add the specified task and mark it as running.\n * @param {int} id the identity of the task\n * @param {int} priority the task's priority\n * @param {Packet} queue the queue of work to be processed by the task\n * @param {Task} task the task to add\n */\nScheduler.prototype.addRunningTask = function (id, priority, queue, task) {\n  this.addTask(id, priority, queue, task);\n  this.currentTcb.setRunning();\n};\n\n/**\n * Add the specified task to this scheduler.\n * @param {int} id the identity of the task\n * @param {int} priority the task's priority\n * @param {Packet} queue the queue of work to be processed by the task\n * @param {Task} task the task to add\n */\nScheduler.prototype.addTask = function (id, priority, queue, task) {\n  this.currentTcb = new TaskControlBlock(this.list, id, priority, queue, task);\n  this.list = this.currentTcb;\n  this.blocks[id] = this.currentTcb;\n};\n\n/**\n * Execute the tasks managed by this scheduler.\n */\nScheduler.prototype.schedule = function () {\n  this.currentTcb = this.list;\n  while (this.currentTcb != null) {\n    if (this.currentTcb.isHeldOrSuspended()) {\n      this.currentTcb = this.currentTcb.link;\n    } else {\n      this.currentId = this.currentTcb.id;\n      this.currentTcb = this.currentTcb.run();\n    }\n  }\n};\n\n/**\n * Release a task that is currently blocked and return the next block to run.\n * @param {int} id the id of the task to suspend\n */\nScheduler.prototype.release = function (id) {\n  var tcb = this.blocks[id];\n  if (tcb == null) return tcb;\n  tcb.markAsNotHeld();\n  if (tcb.priority > this.currentTcb.priority) {\n    return tcb;\n  } else {\n    return this.currentTcb;\n  }\n};\n\n/**\n * Block the currently executing task and return the next task control block\n * to run.  The blocked task will not be made runnable until it is explicitly\n * released, even if new work is added to it.\n */\nScheduler.prototype.holdCurrent = function () {\n  this.holdCount++;\n  this.currentTcb.markAsHeld();\n  return this.currentTcb.link;\n};\n\n/**\n * Suspend the currently executing task and return the next task control block\n * to run.  If new work is added to the suspended task it will be made runnable.\n */\nScheduler.prototype.suspendCurrent = function () {\n  this.currentTcb.markAsSuspended();\n  return this.currentTcb;\n};\n\n/**\n * Add the specified packet to the end of the worklist used by the task\n * associated with the packet and make the task runnable if it is currently\n * suspended.\n * @param {Packet} packet the packet to add\n */\nScheduler.prototype.queue = function (packet) {\n  var t = this.blocks[packet.id];\n  if (t == null) return t;\n  this.queueCount++;\n  packet.link = null;\n  packet.id = this.currentId;\n  return t.checkPriorityAdd(this.currentTcb, packet);\n};\n\n/**\n * A task control block manages a task and the queue of work packages associated\n * with it.\n * @param {TaskControlBlock} link the preceding block in the linked block list\n * @param {int} id the id of this block\n * @param {int} priority the priority of this block\n * @param {Packet} queue the queue of packages to be processed by the task\n * @param {Task} task the task\n * @constructor\n */\nfunction TaskControlBlock(link, id, priority, queue, task) {\n  this.link = link;\n  this.id = id;\n  this.priority = priority;\n  this.queue = queue;\n  this.task = task;\n  if (queue == null) {\n    this.state = STATE_SUSPENDED;\n  } else {\n    this.state = STATE_SUSPENDED_RUNNABLE;\n  }\n}\n\n/**\n * The task is running and is currently scheduled.\n */\nvar STATE_RUNNING = 0;\n\n/**\n * The task has packets left to process.\n */\nvar STATE_RUNNABLE = 1;\n\n/**\n * The task is not currently running.  The task is not blocked as such and may\n * be started by the scheduler.\n */\nvar STATE_SUSPENDED = 2;\n\n/**\n * The task is blocked and cannot be run until it is explicitly released.\n */\nvar STATE_HELD = 4;\n\nvar STATE_SUSPENDED_RUNNABLE = STATE_SUSPENDED | STATE_RUNNABLE;\nvar STATE_NOT_HELD = ~STATE_HELD;\n\nTaskControlBlock.prototype.setRunning = function () {\n  this.state = STATE_RUNNING;\n};\n\nTaskControlBlock.prototype.markAsNotHeld = function () {\n  this.state = this.state & STATE_NOT_HELD;\n};\n\nTaskControlBlock.prototype.markAsHeld = function () {\n  this.state = this.state | STATE_HELD;\n};\n\nTaskControlBlock.prototype.isHeldOrSuspended = function () {\n  return (this.state & STATE_HELD) != 0 || this.state == STATE_SUSPENDED;\n};\n\nTaskControlBlock.prototype.markAsSuspended = function () {\n  this.state = this.state | STATE_SUSPENDED;\n};\n\nTaskControlBlock.prototype.markAsRunnable = function () {\n  this.state = this.state | STATE_RUNNABLE;\n};\n\n/**\n * Runs this task, if it is ready to be run, and returns the next task to run.\n */\nTaskControlBlock.prototype.run = function () {\n  var packet;\n  if (this.state == STATE_SUSPENDED_RUNNABLE) {\n    packet = this.queue;\n    this.queue = packet.link;\n    if (this.queue == null) {\n      this.state = STATE_RUNNING;\n    } else {\n      this.state = STATE_RUNNABLE;\n    }\n  } else {\n    packet = null;\n  }\n  return this.task.run(packet);\n};\n\n/**\n * Adds a packet to the worklist of this block's task, marks this as runnable if\n * necessary, and returns the next runnable object to run (the one\n * with the highest priority).\n */\nTaskControlBlock.prototype.checkPriorityAdd = function (task, packet) {\n  if (this.queue == null) {\n    this.queue = packet;\n    this.markAsRunnable();\n    if (this.priority > task.priority) return this;\n  } else {\n    this.queue = packet.addTo(this.queue);\n  }\n  return task;\n};\n\nTaskControlBlock.prototype.toString = function () {\n  return \"tcb { \" + this.task + \"@\" + this.state + \" }\";\n};\n\n/**\n * An idle task doesn't do any work itself but cycles control between the two\n * device tasks.\n * @param {Scheduler} scheduler the scheduler that manages this task\n * @param {int} v1 a seed value that controls how the device tasks are scheduled\n * @param {int} count the number of times this task should be scheduled\n * @constructor\n */\nfunction IdleTask(scheduler, v1, count) {\n  this.scheduler = scheduler;\n  this.v1 = v1;\n  this.count = count;\n}\n\nIdleTask.prototype.run = function (packet) {\n  this.count--;\n  if (this.count == 0) return this.scheduler.holdCurrent();\n  if ((this.v1 & 1) == 0) {\n    this.v1 = this.v1 >> 1;\n    return this.scheduler.release(ID_DEVICE_A);\n  } else {\n    this.v1 = (this.v1 >> 1) ^ 0xd008;\n    return this.scheduler.release(ID_DEVICE_B);\n  }\n};\n\nIdleTask.prototype.toString = function () {\n  return \"IdleTask\";\n};\n\n/**\n * A task that suspends itself after each time it has been run to simulate\n * waiting for data from an external device.\n * @param {Scheduler} scheduler the scheduler that manages this task\n * @constructor\n */\nfunction DeviceTask(scheduler) {\n  this.scheduler = scheduler;\n  this.v1 = null;\n}\n\nDeviceTask.prototype.run = function (packet) {\n  if (packet == null) {\n    if (this.v1 == null) return this.scheduler.suspendCurrent();\n    var v = this.v1;\n    this.v1 = null;\n    return this.scheduler.queue(v);\n  } else {\n    this.v1 = packet;\n    return this.scheduler.holdCurrent();\n  }\n};\n\nDeviceTask.prototype.toString = function () {\n  return \"DeviceTask\";\n};\n\n/**\n * A task that manipulates work packets.\n * @param {Scheduler} scheduler the scheduler that manages this task\n * @param {int} v1 a seed used to specify how work packets are manipulated\n * @param {int} v2 another seed used to specify how work packets are manipulated\n * @constructor\n */\nfunction WorkerTask(scheduler, v1, v2) {\n  this.scheduler = scheduler;\n  this.v1 = v1;\n  this.v2 = v2;\n}\n\nWorkerTask.prototype.run = function (packet) {\n  if (packet == null) {\n    return this.scheduler.suspendCurrent();\n  } else {\n    if (this.v1 == ID_HANDLER_A) {\n      this.v1 = ID_HANDLER_B;\n    } else {\n      this.v1 = ID_HANDLER_A;\n    }\n    packet.id = this.v1;\n    packet.a1 = 0;\n    for (var i = 0; i < DATA_SIZE; i++) {\n      this.v2++;\n      if (this.v2 > 26) this.v2 = 1;\n      packet.a2[i] = this.v2;\n    }\n    return this.scheduler.queue(packet);\n  }\n};\n\nWorkerTask.prototype.toString = function () {\n  return \"WorkerTask\";\n};\n\n/**\n * A task that manipulates work packets and then suspends itself.\n * @param {Scheduler} scheduler the scheduler that manages this task\n * @constructor\n */\nfunction HandlerTask(scheduler) {\n  this.scheduler = scheduler;\n  this.v1 = null;\n  this.v2 = null;\n}\n\nHandlerTask.prototype.run = function (packet) {\n  if (packet != null) {\n    if (packet.kind == KIND_WORK) {\n      this.v1 = packet.addTo(this.v1);\n    } else {\n      this.v2 = packet.addTo(this.v2);\n    }\n  }\n  if (this.v1 != null) {\n    var count = this.v1.a1;\n    var v;\n    if (count < DATA_SIZE) {\n      if (this.v2 != null) {\n        v = this.v2;\n        this.v2 = this.v2.link;\n        v.a1 = this.v1.a2[count];\n        this.v1.a1 = count + 1;\n        return this.scheduler.queue(v);\n      }\n    } else {\n      v = this.v1;\n      this.v1 = this.v1.link;\n      return this.scheduler.queue(v);\n    }\n  }\n  return this.scheduler.suspendCurrent();\n};\n\nHandlerTask.prototype.toString = function () {\n  return \"HandlerTask\";\n};\n\n/* --- *\n * P a c k e t\n * --- */\n\nvar DATA_SIZE = 4;\n\n/**\n * A simple package of data that is manipulated by the tasks.  The exact layout\n * of the payload data carried by a packet is not importaint, and neither is the\n * nature of the work performed on packets by the tasks.\n *\n * Besides carrying data, packets form linked lists and are hence used both as\n * data and worklists.\n * @param {Packet} link the tail of the linked list of packets\n * @param {int} id an ID for this packet\n * @param {int} kind the type of this packet\n * @constructor\n */\nfunction Packet(link, id, kind) {\n  this.link = link;\n  this.id = id;\n  this.kind = kind;\n  this.a1 = 0;\n  this.a2 = new Array(DATA_SIZE);\n}\n\n/**\n * Add this packet to the end of a worklist, and return the worklist.\n * @param {Packet} queue the worklist to add this packet to\n */\nPacket.prototype.addTo = function (queue) {\n  this.link = null;\n  if (queue == null) return this;\n  var peek,\n    next = queue;\n  while ((peek = next.link) != null) next = peek;\n  next.link = this;\n  return queue;\n};\n\nPacket.prototype.toString = function () {\n  return \"Packet\";\n};\n"
  },
  {
    "path": "benchmarks/v8-v7/splay.js",
    "content": "// Copyright 2009 the V8 project authors. All rights reserved.\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\n//       disclaimer in the documentation and/or other materials provided\n//       with the distribution.\n//     * Neither the name of Google Inc. nor the names of its\n//       contributors may be used to endorse or promote products derived\n//       from 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// This benchmark is based on a JavaScript log processing module used\n// by the V8 profiler to generate execution time profiles for runs of\n// JavaScript applications, and it effectively measures how fast the\n// JavaScript engine is at allocating nodes and reclaiming the memory\n// used for old nodes. Because of the way splay trees work, the engine\n// also has to deal with a lot of changes to the large tree object\n// graph.\n\nvar Splay = new BenchmarkSuite(\"Splay\", 81491, [\n  new Benchmark(\"Splay\", SplayRun, SplaySetup, SplayTearDown),\n]);\n\n// Configuration.\nvar kSplayTreeSize = 8000;\nvar kSplayTreeModifications = 80;\nvar kSplayTreePayloadDepth = 5;\n\nvar splayTree = null;\n\nfunction GeneratePayloadTree(depth, tag) {\n  if (depth == 0) {\n    return {\n      array: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n      string: \"String for key \" + tag + \" in leaf node\",\n    };\n  } else {\n    return {\n      left: GeneratePayloadTree(depth - 1, tag),\n      right: GeneratePayloadTree(depth - 1, tag),\n    };\n  }\n}\n\nfunction GenerateKey() {\n  // The benchmark framework guarantees that Math.random is\n  // deterministic; see base.js.\n  return Math.random();\n}\n\nfunction InsertNewNode() {\n  // Insert new node with a unique key.\n  var key;\n  do {\n    key = GenerateKey();\n  } while (splayTree.find(key) != null);\n  var payload = GeneratePayloadTree(kSplayTreePayloadDepth, String(key));\n  splayTree.insert(key, payload);\n  return key;\n}\n\nfunction SplaySetup() {\n  splayTree = new SplayTree();\n  for (var i = 0; i < kSplayTreeSize; i++) InsertNewNode();\n}\n\nfunction SplayTearDown() {\n  // Allow the garbage collector to reclaim the memory\n  // used by the splay tree no matter how we exit the\n  // tear down function.\n  var keys = splayTree.exportKeys();\n  splayTree = null;\n\n  // Verify that the splay tree has the right size.\n  var length = keys.length;\n  if (length != kSplayTreeSize) {\n    throw new Error(\"Splay tree has wrong size\");\n  }\n\n  // Verify that the splay tree has sorted, unique keys.\n  for (var i = 0; i < length - 1; i++) {\n    if (keys[i] >= keys[i + 1]) {\n      throw new Error(\"Splay tree not sorted\");\n    }\n  }\n}\n\nfunction SplayRun() {\n  // Replace a few nodes in the splay tree.\n  for (var i = 0; i < kSplayTreeModifications; i++) {\n    var key = InsertNewNode();\n    var greatest = splayTree.findGreatestLessThan(key);\n    if (greatest == null) splayTree.remove(key);\n    else splayTree.remove(greatest.key);\n  }\n}\n\n/**\n * Constructs a Splay tree.  A splay tree is a self-balancing binary\n * search tree with the additional property that recently accessed\n * elements are quick to access again. It performs basic operations\n * such as insertion, look-up and removal in O(log(n)) amortized time.\n *\n * @constructor\n */\nfunction SplayTree() {}\n\n/**\n * Pointer to the root node of the tree.\n *\n * @type {SplayTree.Node}\n * @private\n */\nSplayTree.prototype.root_ = null;\n\n/**\n * @return {boolean} Whether the tree is empty.\n */\nSplayTree.prototype.isEmpty = function () {\n  return !this.root_;\n};\n\n/**\n * Inserts a node into the tree with the specified key and value if\n * the tree does not already contain a node with the specified key. If\n * the value is inserted, it becomes the root of the tree.\n *\n * @param {number} key Key to insert into the tree.\n * @param {*} value Value to insert into the tree.\n */\nSplayTree.prototype.insert = function (key, value) {\n  if (this.isEmpty()) {\n    this.root_ = new SplayTree.Node(key, value);\n    return;\n  }\n  // Splay on the key to move the last node on the search path for\n  // the key to the root of the tree.\n  this.splay_(key);\n  if (this.root_.key == key) {\n    return;\n  }\n  var node = new SplayTree.Node(key, value);\n  if (key > this.root_.key) {\n    node.left = this.root_;\n    node.right = this.root_.right;\n    this.root_.right = null;\n  } else {\n    node.right = this.root_;\n    node.left = this.root_.left;\n    this.root_.left = null;\n  }\n  this.root_ = node;\n};\n\n/**\n * Removes a node with the specified key from the tree if the tree\n * contains a node with this key. The removed node is returned. If the\n * key is not found, an exception is thrown.\n *\n * @param {number} key Key to find and remove from the tree.\n * @return {SplayTree.Node} The removed node.\n */\nSplayTree.prototype.remove = function (key) {\n  if (this.isEmpty()) {\n    throw Error(\"Key not found: \" + key);\n  }\n  this.splay_(key);\n  if (this.root_.key != key) {\n    throw Error(\"Key not found: \" + key);\n  }\n  var removed = this.root_;\n  if (!this.root_.left) {\n    this.root_ = this.root_.right;\n  } else {\n    var right = this.root_.right;\n    this.root_ = this.root_.left;\n    // Splay to make sure that the new root has an empty right child.\n    this.splay_(key);\n    // Insert the original right child as the right child of the new\n    // root.\n    this.root_.right = right;\n  }\n  return removed;\n};\n\n/**\n * Returns the node having the specified key or null if the tree doesn't contain\n * a node with the specified key.\n *\n * @param {number} key Key to find in the tree.\n * @return {SplayTree.Node} Node having the specified key.\n */\nSplayTree.prototype.find = function (key) {\n  if (this.isEmpty()) {\n    return null;\n  }\n  this.splay_(key);\n  return this.root_.key == key ? this.root_ : null;\n};\n\n/**\n * @return {SplayTree.Node} Node having the maximum key value.\n */\nSplayTree.prototype.findMax = function (opt_startNode) {\n  if (this.isEmpty()) {\n    return null;\n  }\n  var current = opt_startNode || this.root_;\n  while (current.right) {\n    current = current.right;\n  }\n  return current;\n};\n\n/**\n * @return {SplayTree.Node} Node having the maximum key value that\n *     is less than the specified key value.\n */\nSplayTree.prototype.findGreatestLessThan = function (key) {\n  if (this.isEmpty()) {\n    return null;\n  }\n  // Splay on the key to move the node with the given key or the last\n  // node on the search path to the top of the tree.\n  this.splay_(key);\n  // Now the result is either the root node or the greatest node in\n  // the left subtree.\n  if (this.root_.key < key) {\n    return this.root_;\n  } else if (this.root_.left) {\n    return this.findMax(this.root_.left);\n  } else {\n    return null;\n  }\n};\n\n/**\n * @return {Array<*>} An array containing all the keys of tree's nodes.\n */\nSplayTree.prototype.exportKeys = function () {\n  var result = [];\n  if (!this.isEmpty()) {\n    this.root_.traverse_(function (node) {\n      result.push(node.key);\n    });\n  }\n  return result;\n};\n\n/**\n * Perform the splay operation for the given key. Moves the node with\n * the given key to the top of the tree.  If no node has the given\n * key, the last node on the search path is moved to the top of the\n * tree. This is the simplified top-down splaying algorithm from:\n * \"Self-adjusting Binary Search Trees\" by Sleator and Tarjan\n *\n * @param {number} key Key to splay the tree on.\n * @private\n */\nSplayTree.prototype.splay_ = function (key) {\n  if (this.isEmpty()) {\n    return;\n  }\n  // Create a dummy node.  The use of the dummy node is a bit\n  // counter-intuitive: The right child of the dummy node will hold\n  // the L tree of the algorithm.  The left child of the dummy node\n  // will hold the R tree of the algorithm.  Using a dummy node, left\n  // and right will always be nodes and we avoid special cases.\n  var dummy, left, right;\n  dummy = left = right = new SplayTree.Node(null, null);\n  var current = this.root_;\n  while (true) {\n    if (key < current.key) {\n      if (!current.left) {\n        break;\n      }\n      if (key < current.left.key) {\n        // Rotate right.\n        var tmp = current.left;\n        current.left = tmp.right;\n        tmp.right = current;\n        current = tmp;\n        if (!current.left) {\n          break;\n        }\n      }\n      // Link right.\n      right.left = current;\n      right = current;\n      current = current.left;\n    } else if (key > current.key) {\n      if (!current.right) {\n        break;\n      }\n      if (key > current.right.key) {\n        // Rotate left.\n        var tmp = current.right;\n        current.right = tmp.left;\n        tmp.left = current;\n        current = tmp;\n        if (!current.right) {\n          break;\n        }\n      }\n      // Link left.\n      left.right = current;\n      left = current;\n      current = current.right;\n    } else {\n      break;\n    }\n  }\n  // Assemble.\n  left.right = current.left;\n  right.left = current.right;\n  current.left = dummy.right;\n  current.right = dummy.left;\n  this.root_ = current;\n};\n\n/**\n * Constructs a Splay tree node.\n *\n * @param {number} key Key.\n * @param {*} value Value.\n */\nSplayTree.Node = function (key, value) {\n  this.key = key;\n  this.value = value;\n};\n\n/**\n * @type {SplayTree.Node}\n */\nSplayTree.Node.prototype.left = null;\n\n/**\n * @type {SplayTree.Node}\n */\nSplayTree.Node.prototype.right = null;\n\n/**\n * Performs an ordered traversal of the subtree starting at\n * this SplayTree.Node.\n *\n * @param {function(SplayTree.Node)} f Visitor function.\n * @private\n */\nSplayTree.Node.prototype.traverse_ = function (f) {\n  var current = this;\n  while (current) {\n    var left = current.left;\n    if (left) left.traverse_(f);\n    f(current);\n    current = current.right;\n  }\n};\n"
  },
  {
    "path": "build.mjs",
    "content": "import * as esbuild from \"esbuild\";\nimport fs from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport path from \"node:path\";\n\nconst require = createRequire(import.meta.url);\n\nprocess.env.NODE_PATH = \".\";\n\nconst TMP_DIR = `.tmp-llrt-aws-sdk`;\nconst SRC_DIR = path.join(\"llrt_core\", \"src\", \"modules\", \"js\");\nconst TESTS_DIR = \"tests\";\nconst TESTS_SUB_DIR = process.env.TEST_SUB_DIR || \"unit\";\nconst OUT_DIR = \"bundle/js\";\nconst SHIMS = new Map();\nconst SDK_BUNDLE_MODE = process.env.SDK_BUNDLE_MODE || \"NONE\"; // \"FULL\" or \"STD\" or \"NONE\"\n\nasync function readFilesRecursive(dir, filePredicate) {\n  const dirents = await fs.readdir(dir, { withFileTypes: true });\n  const files = await Promise.all(\n    dirents.map((dirent) => {\n      const filePath = path.join(dir, dirent.name);\n\n      if (dirent.isDirectory()) {\n        return readFilesRecursive(filePath, filePredicate);\n      } else {\n        return filePredicate(filePath) ? filePath : [];\n      }\n    })\n  );\n  return Array.prototype.concat(...files);\n}\n\nconst TEST_FILES = await readFilesRecursive(\n  path.join(TESTS_DIR, TESTS_SUB_DIR),\n  (filePath) =>\n    filePath.endsWith(\".test.ts\") ||\n    filePath.endsWith(\".spec.ts\") ||\n    filePath.endsWith(\".any.js\")\n);\nconst AWS_JSON_SHARED_COMMAND_REGEX =\n  /{\\s*const\\s*headers\\s*=\\s*sharedHeaders\\((\"\\w+\")\\);\\s*let body;\\s*body\\s*=\\s*JSON.stringify\\(_json\\(input\\)\\);\\s*return buildHttpRpcRequest\\(context,\\s*headers,\\s*\"\\/\",\\s*undefined,\\s*body\\);\\s*}/gm;\nconst AWS_JSON_SHARED_COMMAND_REGEX2 =\n  /{\\s*const\\s*headers\\s*=\\s*sharedHeaders\\((\"\\w+\")\\);\\s*let body;\\s*body\\s*=\\s*JSON.stringify\\((\\w+)\\(input,\\s*context\\)\\);\\s*return buildHttpRpcRequest\\(context,\\s*headers,\\s*\"\\/\",\\s*undefined,\\s*body\\);\\s*}/gm;\nconst MINIFY_JS = process.env.JS_MINIFY !== \"0\";\nconst SDK_UTILS_PACKAGE = \"sdk-utils\";\nconst ENTRYPOINTS = [\n  \"stream\",\n  \"stream/promises\",\n  \"@llrt/test/index\",\n  \"@llrt/test/worker\",\n];\n\nconst ES_BUILD_OPTIONS = {\n  splitting: MINIFY_JS,\n  minify: MINIFY_JS,\n  sourcemap: false,\n  target: \"es2023\",\n  outdir: OUT_DIR,\n  bundle: true,\n  logLevel: \"info\",\n  platform: \"browser\",\n  format: \"esm\",\n  external: [\n    \"assert\",\n    \"node:assert\",\n    \"async_hooks\",\n    \"node:async_hooks\",\n    \"buffer\",\n    \"node:buffer\",\n    \"child_process\",\n    \"node:child_process\",\n    \"console\",\n    \"node:console\",\n    \"crypto\",\n    \"node:crypto\",\n    \"dgram\",\n    \"node:dgram\",\n    \"dns\",\n    \"node:dns\",\n    \"events\",\n    \"node:events\",\n    \"fs\",\n    \"node:fs\",\n    \"module\",\n    \"node:module\",\n    \"net\",\n    \"node:net\",\n    \"os\",\n    \"node:os\",\n    \"path\",\n    \"node:path\",\n    \"perf_hooks\",\n    \"node:perf_hooks\",\n    \"process\",\n    \"node:process\",\n    \"stream\",\n    \"node:stream\",\n    \"string_decoder\",\n    \"node:string_decoder\",\n    \"timers\",\n    \"node:timers\",\n    \"tty\",\n    \"node:tty\",\n    \"url\",\n    \"node:url\",\n    \"util\",\n    \"node:util\",\n    \"zlib\",\n    \"node:zlib\",\n    \"llrt:hex\",\n    \"llrt:timezone\",\n    \"llrt:util\",\n    \"llrt:qjs\",\n    \"llrt:xml\",\n    \"@aws-crypto\",\n  ],\n};\n\nconst SDK_DATA = await parseSdkData();\n\nconst ADDITIONAL_PACKAGES = [\n  \"@aws-sdk/core\",\n  \"@aws-sdk/credential-providers\",\n  \"@aws-sdk/s3-presigned-post\",\n  \"@aws-sdk/s3-request-presigner\",\n  \"@aws-sdk/util-dynamodb\",\n  \"@aws-sdk/util-user-agent-browser\",\n  \"@smithy/config-resolver\",\n  \"@smithy/core\",\n  \"@smithy/eventstream-codec\",\n  \"@smithy/eventstream-serde-browser\",\n  \"@smithy/eventstream-serde-config-resolver\",\n  \"@smithy/eventstream-serde-universal\",\n  \"@smithy/fetch-http-handler\",\n  \"@smithy/invalid-dependency\",\n  \"@smithy/is-array-buffer\",\n  \"@smithy/middleware-compression\",\n  \"@smithy/middleware-content-length\",\n  \"@smithy/middleware-endpoint\",\n  \"@smithy/middleware-retry\",\n  \"@smithy/middleware-serde\",\n  \"@smithy/middleware-stack\",\n  \"@smithy/property-provider\",\n  \"@smithy/protocol-http\",\n  \"@smithy/querystring-builder\",\n  \"@smithy/querystring-parser\",\n  \"@smithy/service-error-classification\",\n  \"@smithy/signature-v4\",\n  \"@smithy/smithy-client\",\n  \"@smithy/types\",\n  \"@smithy/url-parser\",\n  \"@smithy/util-base64\",\n  \"@smithy/util-body-length-browser\",\n  \"@smithy/util-config-provider\",\n  \"@smithy/util-defaults-mode-browser\",\n  \"@smithy/util-endpoints\",\n  \"@smithy/util-hex-encoding\",\n  \"@smithy/util-middleware\",\n  \"@smithy/util-retry\",\n  \"@smithy/util-stream\",\n  \"@smithy/util-uri-escape\",\n  \"@smithy/util-utf8\",\n  \"@smithy/util-waiter\",\n];\n\nconst REPLACEMENT_PACKAGES = {\n  \"@aws-crypto/sha1-browser\": \"shims/@aws-crypto/sha1-browser.js\",\n  \"@aws-crypto/sha256-browser\": \"shims/@aws-crypto/sha256-browser.js\",\n  \"@aws-crypto/crc32\": \"shims/@aws-crypto/crc32.js\",\n  \"@aws-crypto/crc32c\": \"shims/@aws-crypto/crc32c.js\",\n  \"@smithy/abort-controller\": \"shims/@smithy/abort-controller.js\",\n};\n\nconst SERVICE_ENDPOINTS_BY_PACKAGE = {};\nconst CLIENTS_BY_SDK = {};\nconst SDKS_BY_SDK_PACKAGES = {};\nconst SDK_PACKAGES = [...ADDITIONAL_PACKAGES];\n\nObject.keys(SDK_DATA).forEach((sdk) => {\n  const [clientName, serviceEndpoints, fullSdkOnly] = SDK_DATA[sdk] || [];\n  if (SDK_BUNDLE_MODE == \"FULL\" || (SDK_BUNDLE_MODE == \"STD\" && !fullSdkOnly)) {\n    const sdkPackage = `@aws-sdk/${sdk}`;\n    SDK_PACKAGES.push(sdkPackage);\n    SDKS_BY_SDK_PACKAGES[sdkPackage] = sdk;\n    SERVICE_ENDPOINTS_BY_PACKAGE[sdk] = serviceEndpoints;\n    CLIENTS_BY_SDK[sdk] = clientName;\n  }\n});\n\nasync function parseSdkData() {\n  const cfgData = await fs.readFile(\"sdk.cfg\");\n  const cfgLines = cfgData.toString().split(\"\\n\");\n\n  const sdkData = {};\n\n  for (let line of cfgLines) {\n    line = line.trim();\n    if (line.startsWith(\"#\") || line == \"\") {\n      continue;\n    }\n\n    // Parse the line\n    const parts = line.split(\",\");\n\n    //get and remove the item at 0\n    const packageName = parts.shift();\n    const clientName = parts.shift();\n\n    //get and remove the last item\n    const fullSdkOnly = parts.pop() == 1;\n\n    const endpoints = parts;\n\n    // Log or store parsed information\n    sdkData[packageName] = [clientName, endpoints, fullSdkOnly];\n  }\n  return sdkData;\n}\n\nfunction resolveDefaultsModeConfigWrapper(config) {\n  if (!config.credentials) {\n    config.credentials = {\n      accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n      secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n      sessionToken: process.env.AWS_SESSION_TOKEN,\n    };\n  }\n  if (!config.region) {\n    config.region = process.env.AWS_REGION;\n  }\n  return resolveDefaultsModeConfig(config);\n}\n\nconst awsJsonSharedCommand = (name, input, context, request) => {\n  const headers = sharedHeaders(name);\n  const body = JSON.stringify(request ? request(input, context) : _json(input));\n  return buildHttpRpcRequest(context, headers, \"/\", undefined, body);\n};\n\nfunction defaultEndpointResolver(endpointParams, context = {}) {\n  const paramsKey = calculateEndpointCacheKey(endpointParams);\n  let endpoint = ENDPOINT_CACHE[paramsKey];\n  if (!endpoint) {\n    endpoint = resolveEndpoint(ruleSet, {\n      endpointParams,\n      logger: context.logger,\n      serviceName,\n    });\n    ENDPOINT_CACHE[paramsKey] = endpoint;\n  }\n\n  if (serviceName === \"s3\") {\n    const { hostname, protocol, pathname, search } = endpoint.url;\n    const [bucket, host] = hostname.split(\".s3.\");\n    if (host) {\n      const path = pathname === \"/\" ? \"\" : pathname;\n      const newHref = `${protocol}//s3.${host}/${bucket}${path}${\n        search ? `?${search}` : \"\"\n      }`;\n      endpoint.url.href = newHref;\n    }\n  }\n\n  return endpoint;\n}\n\nconst WRAPPERS = [\n  {\n    name: \"resolveDefaultsModeConfig\",\n    filter: /resolveDefaultsModeConfig.js$/,\n    wrapper: resolveDefaultsModeConfigWrapper,\n  },\n];\n\nfunction executeClientCommand(command, optionsOrCb, cb) {\n  if (typeof optionsOrCb === \"function\") {\n    this.send(command, optionsOrCb);\n  } else if (typeof cb === \"function\") {\n    if (typeof optionsOrCb !== \"object\")\n      throw new Error(`Expect http options but get ${typeof optionsOrCb}`);\n    this.send(command, optionsOrCb || {}, cb);\n  } else {\n    return this.send(command, optionsOrCb);\n  }\n}\n\nconst ENDPOINT_CACHE_KEY_LOOKUP = {\n  Bucket: \"b\",\n  ForcePathStyle: \"f\",\n  UseArnRegion: \"n\",\n  DisableMultiRegionAccessPoints: \"m\",\n  Accelerate: \"a\",\n  UseGlobalEndpoint: \"g\",\n  UseFIPS: \"i\",\n  Endpoint: \"e\",\n  Region: \"r\",\n  UseDualStack: \"d\",\n};\nconst ENDPOINT_CACHE_KEY_LOOKUP_NAME = Object.keys({\n  ENDPOINT_CACHE_KEY_LOOKUP,\n})[0];\n\nfunction calculateEndpointCacheKey(obj) {\n  let str = \"\";\n  for (const key in obj) {\n    if (obj[key] === true) {\n      str += ENDPOINT_CACHE_KEY_LOOKUP[key];\n    } else if (typeof obj[key] === \"string\") {\n      str += obj[key];\n    }\n  }\n  return str;\n}\n\nfunction codeToRegex(fn, includeSignature = false) {\n  return new RegExp(\n    fn\n      .toString()\n      .split(\"\\n\")\n      .reduce((acc, line, index, array) => {\n        if (includeSignature || (index > 0 && index < array.length - 1)) {\n          acc.push(line.trim());\n        }\n        return acc;\n      }, [])\n      .join(\"\\n\")\n      .replace(/\\s+/g, \"\\\\s*\")\n      .replace(/\\(/g, \"\\\\(\")\n      .replace(/\\)/g, \"\\\\)\")\n      .replace(/\\./g, \"\\\\.\")\n      .replace(/\\?,/g, \"\\\\?\")\n      .replace(/\\,/g, \",?\")\n      .replace(/\\$/g, \"\\\\$\")\n      .replace(/\\{/g, \"\\\\s*{\")\n      .replace(/\\}/g, \"}\\\\s*\")\n      .replace(/\\|/g, \"\\\\|\"),\n    \"g\"\n  );\n}\n\nconst AWS_SDK_PLUGIN = {\n  name: \"aws-sdk-plugin\",\n  setup(build) {\n    const tslib = require.resolve(\"tslib/tslib.es6.js\");\n\n    const executeClientCommandRegex = codeToRegex(executeClientCommand);\n\n    build.onResolve({ filter: /^tslib$/ }, () => {\n      return { path: tslib };\n    });\n\n    //load replace shims\n    for (const [filter, contents] of SHIMS) {\n      build.onLoad({ filter }, () => ({\n        contents,\n      }));\n    }\n\n    for (const sdk in CLIENTS_BY_SDK) {\n      const clientClass = CLIENTS_BY_SDK[sdk];\n\n      build.onLoad(\n        { filter: new RegExp(`@aws-sdk\\\\/${sdk}\\\\/dist-es/${clientClass}.js`) },\n        async ({ path: filePath }) => {\n          const source = (await fs.readFile(filePath)).toString();\n          const name = path.parse(filePath).name;\n\n          console.log(\"Optimized:\", name);\n\n          let contents = `import { ${executeClientCommand.name} } from \"${SDK_UTILS_PACKAGE}\"\\n`;\n          contents += source.replace(\n            executeClientCommandRegex,\n            `return ${executeClientCommand.name}.call(this, command, optionsOrCb, cb)`\n          );\n\n          return {\n            contents,\n          };\n        }\n      );\n    }\n\n    build.onLoad({ filter: /xml-parser\\.browser\\.js$/ }, async (args) => {\n      const realPath = path.join(path.dirname(args.path), \"xml-parser.js\");\n      const contents = await fs.readFile(realPath, \"utf8\");\n      return { contents, loader: \"js\" };\n    });\n\n    build.onLoad(\n      { filter: /protocols\\/Aws_json1_1\\.js$/ },\n      async ({ path: filePath }) => {\n        const name = path.parse(filePath).name;\n\n        let source = (await fs.readFile(filePath)).toString();\n\n        const sourceLength = source.length;\n\n        source = source.replace(\n          AWS_JSON_SHARED_COMMAND_REGEX,\n          (_, name) => `${awsJsonSharedCommand.name}(${name}, input, context)`\n        );\n\n        source = source.replace(\n          AWS_JSON_SHARED_COMMAND_REGEX2,\n          (_, name, request) =>\n            `${awsJsonSharedCommand.name}(${name}, input, context, ${request})`\n        );\n\n        if (sourceLength === source.length) {\n          throw new Error(`Failed to optimize: ${name}`);\n        }\n\n        console.log(\"Optimized:\", name);\n\n        source = `const ${\n          awsJsonSharedCommand.name\n        } = ${awsJsonSharedCommand.toString()}\\n\\n${source}`;\n\n        return {\n          contents: source,\n        };\n      }\n    );\n\n    build.onResolve({ filter: /^sdk-utils$/ }, (args) => ({\n      path: args.path,\n      namespace: \"sdk-utils-ns\",\n    }));\n\n    build.onLoad({ filter: /.*/, namespace: \"sdk-utils-ns\" }, (args) => {\n      let contents = \"\";\n\n      contents += `import { Command as $Command } from \"@smithy/smithy-client\";\\n`;\n      contents += `import { getEndpointPlugin } from \"@smithy/middleware-endpoint\";\\n`;\n      contents += `import { getSerdePlugin } from \"@smithy/middleware-serde\";\\n`;\n      contents += `import { SMITHY_CONTEXT_KEY } from \"@smithy/types\";\\n`;\n      contents += `export ${executeClientCommand.toString()}\\n`;\n      contents += `const ${ENDPOINT_CACHE_KEY_LOOKUP_NAME} = ${JSON.stringify(\n        ENDPOINT_CACHE_KEY_LOOKUP\n      )};\\n`;\n      contents += `export const cloneModel = (obj) => ({...obj})\\n`;\n      contents += `export ${calculateEndpointCacheKey.toString()}\\n`;\n\n      return {\n        contents,\n        resolveDir: path.dirname(args.path),\n      };\n    });\n\n    build.onLoad(\n      { filter: /endpoint\\/endpointResolver\\.js$/ },\n      async ({ path: filePath }) => {\n        let source = (await fs.readFile(filePath)).toString();\n        source = source.replace(\n          /export const defaultEndpointResolver =.*?};/s,\n          \"\"\n        );\n        let contents = `import { ${calculateEndpointCacheKey.name} } from \"${SDK_UTILS_PACKAGE}\"\\n`;\n        contents += source;\n        const serviceName = path\n          .resolve(filePath, \"../../../\")\n          .split(\"/\")\n          .pop()\n          .substring(\"client-\".length);\n        contents += `const serviceName = \"${serviceName}\";\\n`;\n        contents += `const ENDPOINT_CACHE = {};\\n`;\n        contents += `export ${defaultEndpointResolver.toString()}`;\n\n        return {\n          contents,\n        };\n      }\n    );\n\n    for (const { filter, wrapper, name } of WRAPPERS) {\n      build.onLoad({ filter }, async ({ path }) => {\n        let source = (await fs.readFile(path)).toString();\n        let replaced = false;\n        let contents = \"\";\n        source = source.replace(\n          RegExp(`export\\\\s*(const\\\\s*${name})`),\n          (_, replacement) => {\n            replaced = true;\n            return replacement;\n          }\n        );\n        if (!replaced) {\n          contents += source;\n        } else {\n          const wrapperName = `${name}Wrapper`;\n          contents += `${source}\\n`;\n          contents += `const ${wrapperName} = ${wrapper.toString()}\\n`;\n          contents += `export {${wrapperName} as ${name}}`;\n        }\n\n        return {\n          contents,\n        };\n      });\n    }\n\n    build.onLoad({ filter: /package\\.json$/ }, async ({ path }) => {\n      let packageJson = JSON.parse(await fs.readFile(path));\n      let { version } = packageJson;\n      const data = {\n        version,\n      };\n      return {\n        contents: `export default ${JSON.stringify(data)}`,\n      };\n    });\n  },\n};\n\nfunction esbuildShimPlugin(shims) {\n  return {\n    name: \"esbuild-shim\",\n    setup(build) {\n      shims.forEach(([filter, value], index) => {\n        build.onResolve(\n          {\n            filter,\n          },\n          (args) => ({\n            path: args.path,\n            namespace: `esbuild-shim-${index}-ns`,\n          })\n        );\n        build.onLoad(\n          { filter: /.*/, namespace: `esbuild-shim-${index}-ns` },\n          () => {\n            const contents = value || \"export default {}\";\n            return {\n              contents,\n            };\n          }\n        );\n      });\n    },\n  };\n}\n\nconst requireProcessPlugin = {\n  name: \"require-process\",\n  setup(build) {\n    build.onResolve({ filter: /^process\\/$/ }, () => {\n      return { path: \"process\", external: true };\n    });\n  },\n};\n\nasync function rmTmpDir() {\n  await fs.rm(TMP_DIR, {\n    recursive: true,\n    force: true,\n  });\n}\n\nasync function createOutputDirectories() {\n  await fs.rm(OUT_DIR, { recursive: true, force: true });\n  await fs.mkdir(OUT_DIR, { recursive: true });\n  await rmTmpDir();\n  await fs.mkdir(TMP_DIR, { recursive: true });\n}\n\nasync function loadShims() {\n  const loadShim = async (filter, filename) => {\n    const bytes = await fs.readFile(path.join(\"shims\", filename));\n    SHIMS.set(filter, bytes.toString());\n  };\n\n  await Promise.all([\n    loadShim(/@aws-crypto/, \"@aws-crypto/index.js\"),\n    loadShim(/@smithy\\/util-hex-encoding/, \"@smithy/util-hex-encoding.js\"),\n    loadShim(/@smithy\\/util-utf8/, \"@smithy/util-utf8.js\"),\n    loadShim(/stringHasher.js/, \"string-hasher.js\"),\n    loadShim(/@smithy\\/util-base64/, \"@smithy/util-base64.js\"),\n    loadShim(/mnemonist\\/lru-cache\\.js/, \"mnemonist/lru-cache.js\"),\n    loadShim(/collect-stream-body\\.js/, \"collect-stream-body.js\"),\n    loadShim(/sdk-stream-mixin.browser\\.js/, \"sdk-stream-mixin.js\"),\n    loadShim(/stream-collector\\.js/, \"stream-collector.js\"),\n    loadShim(/splitStream\\.browser\\.js/, \"@smithy/split-stream.js\"),\n    loadShim(\n      /create-read-stream-on-buffer\\.browser\\.js/,\n      \"create-read-stream.js\"\n    ),\n    loadShim(/isStreaming.js/, \"is-streaming.js\"),\n  ]);\n}\n\nasync function buildLibrary() {\n  const defaultLibEsBuildOption = {\n    chunkNames: \"llrt-[name]-runtime-[hash]\",\n    ...ES_BUILD_OPTIONS,\n    splitting: false,\n    keepNames: true,\n    nodePaths: [\".\"],\n  };\n\n  // Build lib\n  const entryPoints = {};\n  ENTRYPOINTS.forEach((entry) => {\n    entryPoints[entry] = path.join(SRC_DIR, entry);\n  });\n  await esbuild.build({\n    ...defaultLibEsBuildOption,\n    entryPoints,\n    plugins: [requireProcessPlugin],\n    sourcemap: false,\n  });\n\n  // Build tests\n  const testEntryPoints = TEST_FILES.reduce((acc, entry) => {\n    const { name, dir } = path.parse(entry);\n    const parentDir = path.basename(dir);\n    acc[path.join(\"__tests__\", parentDir, name)] = entry;\n    return acc;\n  }, {});\n\n  await esbuild.build({\n    ...defaultLibEsBuildOption,\n    entryPoints: testEntryPoints,\n    external: [...ES_BUILD_OPTIONS.external, \"@aws-sdk\", \"@smithy\"],\n    sourcemap: false,\n  });\n}\n\nasync function buildSdks() {\n  const sdkEntryList = await Promise.all(\n    SDK_PACKAGES.map(async (pkg) => {\n      const packagePath = path.join(TMP_DIR, pkg);\n      const sdk = SDKS_BY_SDK_PACKAGES[pkg];\n      const sdkIndexFile = path.join(packagePath, \"index.js\");\n\n      await fs.mkdir(packagePath, { recursive: true });\n\n      let sdkContents = `export * from \"${pkg}\";`;\n      await fs.writeFile(sdkIndexFile, sdkContents);\n\n      return [pkg, sdkIndexFile];\n    })\n  );\n\n  const sdkEntryPoints = Object.fromEntries(sdkEntryList);\n\n  await Promise.all([\n    esbuild.build({\n      entryPoints: sdkEntryPoints,\n      plugins: [AWS_SDK_PLUGIN, esbuildShimPlugin([[/^bowser$/]])],\n      alias: {\n        \"@aws-sdk/util-utf8-browser\": \"@smithy/util-utf8\",\n        \"@aws-sdk/util-utf8\": \"@smithy/util-utf8\",\n        \"@smithy/md5-js\": \"crypto\",\n        \"fast-xml-parser\": \"llrt:xml\",\n        \"xml-parser.browser\": \"xml-parser\",\n      },\n      chunkNames: \"llrt-[name]-sdk-[hash]\",\n      metafile: true,\n      ...ES_BUILD_OPTIONS,\n    }),\n    esbuild.build({\n      entryPoints: REPLACEMENT_PACKAGES,\n      ...ES_BUILD_OPTIONS,\n      sourcemap: false,\n    }),\n  ]);\n\n  //console.log(await esbuild.analyzeMetafile(result.metafile));\n}\n\nconsole.log(\"Building...\");\n\nawait createOutputDirectories();\nlet error;\ntry {\n  if (SDK_BUNDLE_MODE != \"NONE\") {\n    await loadShims();\n  }\n\n  await buildLibrary();\n\n  if (SDK_BUNDLE_MODE != \"NONE\") {\n    await buildSdks();\n  }\n} catch (e) {\n  error = e;\n}\n\nawait rmTmpDir();\n\nif (error) {\n  throw error;\n}\n"
  },
  {
    "path": "example/clear-ddb-table.mjs",
    "content": "import {\n  DynamoDBClient,\n  ScanCommand,\n  DescribeTableCommand,\n  BatchWriteItemCommand,\n} from \"@aws-sdk/client-dynamodb\";\nimport path from \"node:path\";\n\nconst DDB_CLIENT = new DynamoDBClient({});\n\nconst TABLE_ARN = process.argv[2];\n\nif (!TABLE_ARN) {\n  console.error(\n    `Usage: ${path.basename(process.argv0)} ${path.basename(\n      process.argv[1]\n    )} <table-arn>`\n  );\n  process.exit(1);\n}\n\nconst segmentArray = (array, segmentSize) =>\n  Array.from({ length: Math.ceil(array.length / segmentSize) }, (_, index) =>\n    array.slice(index * segmentSize, (index + 1) * segmentSize)\n  );\n\nfunction extractRegionAndTableName(arn) {\n  const parts = arn.split(\":\");\n\n  if (\n    parts.length >= 6 &&\n    parts[2] === \"dynamodb\" &&\n    parts[5].startsWith(\"table/\")\n  ) {\n    const region = parts[3];\n    const tableName = parts[5].substring(6);\n    return { region, tableName };\n  } else {\n    return null;\n  }\n}\n\nconst sleep = (time) => new Promise((resolve) => setTimeout(resolve, time));\n\nclass AsyncProcessor {\n  constructor(producerFunction, consumerFunction) {\n    this.producerFunction = producerFunction;\n    this.consumerFunction = consumerFunction;\n  }\n\n  static emptyJob() {\n    let resolveFn;\n    let rejectFn;\n    const promise = new Promise((resolve, reject) => {\n      resolveFn = resolve;\n      rejectFn = reject;\n    });\n    return [promise, resolveFn, rejectFn];\n  }\n\n  async process() {\n    let error;\n\n    const jobs = [AsyncProcessor.emptyJob()];\n\n    const producer = async () => {\n      let currentJob = jobs[0];\n      let nextJob;\n      try {\n        while (!error) {\n          let data = await this.producerFunction();\n          if (data) {\n            nextJob = AsyncProcessor.emptyJob();\n            jobs.push(nextJob);\n          }\n          currentJob[1](data);\n          if (!data) {\n            break;\n          }\n\n          currentJob = nextJob;\n        }\n      } catch (e) {\n        error = e;\n        throw e;\n      }\n    };\n\n    const consumer = async () => {\n      try {\n        while (!error) {\n          const job = jobs.shift();\n          const data = await job[0];\n          if (!data) {\n            break;\n          }\n          await this.consumerFunction(data);\n        }\n      } catch (e) {\n        error = e;\n        throw e;\n      }\n    };\n\n    await Promise.all([producer(), consumer()]);\n  }\n}\n\nasync function deleteItems(tableName, primaryKey, keys) {\n  let deleteRequests = keys.map((key) => ({\n    DeleteRequest: {\n      Key: { [primaryKey]: key },\n    },\n  }));\n  let attempt = 0;\n\n  if (deleteRequests.length === 0) {\n    return;\n  }\n\n  const start = Date.now();\n  while (true) {\n    const result = await DDB_CLIENT.send(\n      new BatchWriteItemCommand({\n        RequestItems: {\n          [tableName]: deleteRequests,\n        },\n      })\n    );\n    if (\n      result.UnprocessedItems[tableName] &&\n      result.UnprocessedItems[tableName].length > 0\n    ) {\n      deleteRequests = result.UnprocessedItems[tableName];\n      attempt++;\n      if (attempt > 3) {\n        throw new Error(\"Too many attempts\");\n      }\n      await sleep(500 * Math.pow(attempt, 2));\n    } else {\n      break;\n    }\n  }\n  console.log(`Deleted:  ${Date.now() - start}ms`);\n}\n\nasync function clearDynamoDBTable() {\n  const { region, tableName } = extractRegionAndTableName(TABLE_ARN);\n  process.env.AWS_REGION = region;\n\n  const primaryKey = await getPrimaryKey(tableName);\n\n  let exclusiveStartKey = undefined;\n  let totalCount = 0;\n\n  const processor = new AsyncProcessor(\n    async () => {\n      const start = Date.now();\n      const scanOutput = await DDB_CLIENT.send(\n        new ScanCommand({\n          TableName: tableName,\n          ProjectionExpression: primaryKey,\n          ExclusiveStartKey: exclusiveStartKey,\n        })\n      );\n      console.log(`Scanned:  ${Date.now() - start}ms`);\n\n      exclusiveStartKey = scanOutput.LastEvaluatedKey;\n\n      const ids = scanOutput.Items.map((item) => item[primaryKey]);\n      if (ids.length === 0) {\n        return null;\n      }\n      return ids;\n    },\n    async (keys) => {\n      const segmentedKeys = segmentArray(keys, 25);\n      await Promise.all(\n        segmentedKeys.map(async (keys) => {\n          await deleteItems(tableName, primaryKey, keys);\n          totalCount += keys.length;\n          if (totalCount > 10000) {\n            process.exit(0);\n          }\n          console.log(\"Deleted:\", totalCount);\n        })\n      );\n    }\n  );\n\n  await processor.process();\n}\n\nasync function getPrimaryKey(tableName) {\n  const describeOutput = await DDB_CLIENT.send(\n    new DescribeTableCommand({\n      TableName: tableName,\n    })\n  );\n  return describeOutput.Table.KeySchema.find((key) => key.KeyType === \"HASH\")\n    .AttributeName;\n}\n\nclearDynamoDBTable().catch((err) => {\n  console.error(err);\n  process.exit(1);\n});\n"
  },
  {
    "path": "example/functions/build.mjs",
    "content": "import esbuild from \"esbuild\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\nconst OUTDIR = \"build\";\n\nawait fs.rm(OUTDIR, { recursive: true, force: true });\n\nasync function buildReact() {\n  const outbase = path.join(OUTDIR, \"react\");\n  const outfile = path.join(outbase, \"index.mjs\");\n\n  await fs.mkdir(outbase, { recursive: true });\n  await fs.copyFile(\"src/react/index.html\", path.join(outbase, \"index.html\"));\n\n  const devMode = process.argv.slice(2)[0] == \"--dev\";\n\n  await esbuild.build({\n    entryPoints: {\n      index: \"src/ssr.ts\",\n      app: \"src/react/index.tsx\",\n    },\n    logLevel: \"info\",\n    ...(!devMode && {\n      platform: \"node\",\n    }),\n    external: [\"@aws-sdk\"],\n    target: \"es2023\",\n    format: devMode ? \"cjs\" : \"esm\",\n    define: {\n      \"process.env.NODE_ENV\": JSON.stringify(\"production\"),\n    },\n    loader: {\n      \".svg\": \"file\",\n    },\n    bundle: true,\n    outdir: outbase,\n  });\n\n  await fs.rename(path.join(outbase, \"index.js\"), outfile);\n  await fs.readFile(outfile).then((data) => {\n    const indexSource = `import { createRequire } from \"node:module\";\\nconst require = createRequire(import.meta.url);\\n${data.toString()}`;\n    return fs.writeFile(outfile, indexSource);\n  });\n}\n\nasync function buildExternalSdkFunction() {\n  const outbase = path.join(OUTDIR, \"external\");\n  const outfile = path.join(outbase, \"index.mjs\");\n\n  await esbuild.build({\n    entryPoints: {\n      index: \"src/non-included-sdk.mjs\",\n    },\n    logLevel: \"info\",\n    platform: \"browser\",\n    target: \"es2023\",\n    format: \"esm\",\n    bundle: true,\n    minify: true,\n    sourcemap: false,\n    outfile,\n    external: [\n      \"@smithy\",\n      \"@aws-sdk/core\",\n      \"@aws-sdk/util-user-agent-browser\",\n      \"@aws-crypto\",\n      \"bowser\",\n    ],\n  });\n}\n\nawait buildReact();\nawait buildExternalSdkFunction();\n"
  },
  {
    "path": "example/functions/package.json",
    "content": "{\n  \"name\": \"@example/functions\",\n  \"version\": \"1.0.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"node build.mjs\"\n  },\n  \"dependencies\": {\n    \"@aws-sdk/client-dynamodb\": \"3.991.0\",\n    \"@aws-sdk/client-ec2\": \"3.991.0\",\n    \"@aws-sdk/client-s3\": \"3.991.0\",\n    \"aws-sdk\": \"2.1693.0\",\n    \"esbuild-css-modules-plugin\": \"3.1.5\",\n    \"react\": \"19.2.4\",\n    \"react-dom\": \"19.2.4\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"19.2.14\",\n    \"@types/react-dom\": \"19.2.3\",\n    \"esbuild\": \"0.27.3\"\n  }\n}\n"
  },
  {
    "path": "example/functions/src/api.ts",
    "content": "import {\n  DynamoDBDocumentClient,\n  PutCommand,\n  ScanCommand,\n  DeleteCommand,\n  UpdateCommand,\n} from \"@aws-sdk/lib-dynamodb\";\nimport { DynamoDBClient } from \"@aws-sdk/client-dynamodb\";\nimport { randomBytes } from \"node:crypto\";\nimport { Todo } from \"./react/TodoList\";\n\nconst uid = () =>\n  String.fromCharCode(\n    ...randomBytes(20).map((d) => {\n      return (d > 127 ? 97 : 65) + (d % 25);\n    })\n  ) + new Date().getTime();\n\nconst CLIENT = new DynamoDBClient({});\nconst DOCUMENT_CLIENT = DynamoDBDocumentClient.from(CLIENT as any);\n\nconst mapTodo = (\n  item: Todo\n): {\n  id: string; // Assuming id is a string attribute\n  text: string; // Assuming text is a string attribute\n  createdDate: string; // Assuming createdDate is a number attribute\n  completedDate: string | null;\n} => ({\n  ...item,\n  createdDate: new Date(parseInt(item.createdDate)).toISOString(),\n  completedDate: item.completedDate\n    ? new Date(parseInt(item.completedDate)).toISOString()\n    : null,\n});\n\nconst API = {\n  getAll: async () => {\n    const response = await DOCUMENT_CLIENT.send(\n      new ScanCommand({\n        TableName: process.env.TABLE_NAME,\n      })\n    );\n    return response.Items.map(mapTodo);\n  },\n  create: async (text: string) => {\n    const newItem = {\n      id: uid(),\n      text,\n      createdDate: Date.now(),\n    };\n    await DOCUMENT_CLIENT.send(\n      new PutCommand({\n        TableName: process.env.TABLE_NAME,\n        Item: newItem,\n      })\n    );\n    return newItem;\n  },\n\n  delete: async (id: string) => {\n    await DOCUMENT_CLIENT.send(\n      new DeleteCommand({\n        TableName: process.env.TABLE_NAME,\n        Key: {\n          id,\n        },\n      })\n    );\n  },\n  update: async (todo: Omit<Todo, \"createdDate\">) => {\n    await DOCUMENT_CLIENT.send(\n      new UpdateCommand({\n        TableName: process.env.TABLE_NAME,\n        Key: {\n          id: todo.id,\n        },\n        UpdateExpression: \"set completedDate = :completedDate\",\n        ExpressionAttributeValues: {\n          \":completedDate\": todo.completedDate ? Date.now() : null,\n        },\n      })\n    );\n    return todo;\n  },\n};\n\nexport default API;\n"
  },
  {
    "path": "example/functions/src/hello.mjs",
    "content": "export const handler = async () => ({\n  statusCode: 200,\n  body: \"Hello world!\",\n});\n"
  },
  {
    "path": "example/functions/src/non-included-sdk.mjs",
    "content": "// Import the necessary AWS SDK clients and commands\nimport { EC2Client, DescribeInstancesCommand } from \"@aws-sdk/client-ec2\";\n\n// Create an EC2 client\nconst client = new EC2Client();\n\n// Lambda handler function\nexport const handler = async () => {\n  const command = new DescribeInstancesCommand({});\n\n  // Send the command to the EC2 client\n  const response = await client.send(command);\n\n  // Extract instances information\n  const instances = response.Reservations.flatMap(\n    (reservation) => reservation.Instances\n  );\n\n  // Return the list of instances\n  return {\n    statusCode: 200,\n    body: JSON.stringify(instances),\n  };\n};\n"
  },
  {
    "path": "example/functions/src/react/App.css",
    "content": "* {\n  margin: 0;\n  padding: 0;\n  box-sizing: border-box;\n}\n\nhtml,\nbody {\n  font-family: Arial, Helvetica, sans-serif;\n  background-color: #282c34;\n  color: white;\n  font-size: 1rem;\n}\n\n.app {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n}\n\n.logo {\n  padding: 1rem;\n  height: 8rem;\n  pointer-events: none;\n}\n\n@media (prefers-reduced-motion: no-preference) {\n  .logo {\n    animation: App-logo-spin infinite 20s linear;\n  }\n}\n\n.header {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n}\n\n@keyframes App-logo-spin {\n  from {\n    transform: rotate(0deg);\n  }\n  to {\n    transform: rotate(360deg);\n  }\n}\n\n.error-message {\n  color: red;\n  font-weight: 400;\n  margin: 1em;\n}\n\n.main {\n  padding: 2rem;\n  width: 100%;\n}\n\n@media (min-width: 768px) {\n  .main {\n    max-width: 600px;\n  }\n}\n"
  },
  {
    "path": "example/functions/src/react/App.tsx",
    "content": "import logo from \"./logo.svg\";\nimport \"./App.css\";\nimport TodoList, { Todo } from \"./TodoList\";\n\ntype Props = {\n  todoItems?: Todo[];\n  releaseName?: string;\n};\n\nfunction App({ todoItems = [], releaseName = \"\" }: Props) {\n  return (\n    <div className=\"app\">\n      <header className=\"header\">\n        <img src={logo} className=\"logo\" alt=\"logo\" />\n      </header>\n      <main className=\"main\">\n        <h1>LLRT React TODO - {releaseName}</h1>\n        <TodoList items={todoItems} />\n      </main>\n    </div>\n  );\n}\n\nexport default App;\n"
  },
  {
    "path": "example/functions/src/react/CreateTodo.tsx",
    "content": "type Props = {\n  onCreate: (text: string) => void;\n};\n\nfunction CreateTodo({ onCreate }: Props) {\n  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n    if (e.key === \"Enter\") {\n      const target = e.target as any;\n      onCreate(target.value);\n      target.value = \"\";\n    }\n  };\n\n  return (\n    <input\n      onKeyDown={handleKeyDown}\n      className=\"create-todo\"\n      type=\"text\"\n      placeholder=\"What do you want to do?\"\n    />\n  );\n}\n\nexport default CreateTodo;\n"
  },
  {
    "path": "example/functions/src/react/TodoItem.tsx",
    "content": "import { Todo } from \"./TodoList\";\n\ntype Props = {\n  item: Todo;\n  onDelete: (id: string) => void;\n  onComplete: (id: string) => void;\n};\n\nfunction TodoItem({\n  item: { id, text, createdDate, completedDate },\n  onDelete,\n  onComplete,\n}: Props) {\n  const handleDeleteClick = (e: React.MouseEvent<HTMLElement>) => {\n    e.stopPropagation();\n    onDelete(id);\n  };\n  return (\n    <li>\n      <div onClick={() => onComplete(id)} className=\"todo-item\">\n        <span>{completedDate ? \"✔\" : \"⏲\"}</span>\n        <span className={`todo-text ${completedDate ? \"completed\" : \"\"}`}>\n          {text}\n        </span>\n        <span onClick={handleDeleteClick}>🗑️</span>\n      </div>\n    </li>\n  );\n}\n\nexport default TodoItem;\n"
  },
  {
    "path": "example/functions/src/react/TodoList.css",
    "content": ".todo-list {\n  margin-top: 2rem;\n}\n\n.todo-list.loading {\n  touch-action: none;\n  pointer-events: none;\n  opacity: 0.5;\n}\n\n.todo-list ul {\n  list-style: none;\n}\n\n.todo-list ul li {\n  margin-bottom: 1rem;\n}\n\n.todo-item {\n  cursor: pointer;\n  display: flex;\n}\n\n.todo-text.completed {\n  text-decoration: line-through;\n}\n\n.todo-item span {\n  padding: 0.5rem;\n}\n\n.todo-text {\n  flex-grow: 1;\n}\n\n.todo-item span:last-child {\n  padding: 0.5rem;\n}\n\n.create-todo {\n  width: 100%;\n  padding: 0.5rem;\n}\n"
  },
  {
    "path": "example/functions/src/react/TodoList.tsx",
    "content": "import { useEffect, useState } from \"react\";\nimport TodoItem from \"./TodoItem\";\nimport \"./TodoList.css\";\nimport CreateTodo from \"./CreateTodo\";\n\ntype Props = {\n  items: Todo[];\n};\n\nexport type Todo = {\n  id: string;\n  text: string;\n  createdDate: string;\n  completedDate?: string;\n};\n\nconst BASE_URL = `${(globalThis.window && window.location.href) || \"/\"}api/`;\n\nconst API = {\n  deleteTodo: async (id: string) => {\n    const response = await fetch(`${BASE_URL}${id}`, {\n      method: \"DELETE\",\n    });\n    if (!response.ok) {\n      throw new Error(\"Could not delete todo\");\n    }\n    await response.text();\n  },\n\n  createTodo: async (text: string) => {\n    const response = await fetch(BASE_URL, {\n      method: \"POST\",\n      body: JSON.stringify({\n        text,\n      }),\n    });\n    if (!response.ok) {\n      throw new Error(\"Could not create todo\");\n    }\n    return await response.json();\n  },\n\n  updateTodo: async (todo: Todo) => {\n    const response = await fetch(`${BASE_URL}${todo.id}`, {\n      method: \"PUT\",\n      body: JSON.stringify(todo),\n    });\n    if (!response.ok) {\n      throw new Error(\"Could not update todo\");\n    }\n    return await response.json();\n  },\n};\n\nfunction TodoList({ items: initialItems }: Props) {\n  const [items, setItems] = useState<Todo[]>(initialItems);\n  const [loading, setLoading] = useState(false);\n  const [error, setError] = useState<string | undefined>();\n\n  const handleCreate = (text: string) => {\n    setError(undefined);\n    setLoading(true);\n    API.createTodo(text)\n      .then((todo) => {\n        setItems([...items, todo]);\n      })\n      .catch((e) => {\n        setError(e.message);\n      })\n      .finally(() => {\n        setLoading(false);\n      });\n  };\n\n  const handleDelete = (id: string) => {\n    let index = items.findIndex((todo) => todo.id === id);\n    setLoading(true);\n    API.deleteTodo(id)\n      .then(() => {\n        items.splice(index, 1);\n        setItems([...items]);\n      })\n      .catch((e) => {\n        setError(e.message);\n      })\n      .finally(() => {\n        setLoading(false);\n      });\n  };\n\n  const handleComplete = (id: string) => {\n    setError(undefined);\n    const index = items.findIndex((todo) => todo.id === id);\n    const item = { ...items[index] }; //copy object\n\n    if (!item.completedDate) {\n      item.completedDate = new Date().toISOString();\n    } else {\n      delete item.completedDate;\n    }\n    setLoading(true);\n    API.updateTodo(item)\n      .then((todo) => {\n        items[index] = todo;\n        setItems([...items]);\n      })\n      .catch((e) => {\n        setError(e.message);\n      })\n      .finally(() => {\n        setLoading(false);\n      });\n  };\n\n  return (\n    <div className={`todo-list ${loading ? \"loading\" : \"\"}`}>\n      {error && <p className=\"error-message\">Error: {error}</p>}\n      <ul>\n        {items.map((todo) => (\n          <TodoItem\n            onComplete={handleComplete}\n            onDelete={handleDelete}\n            key={todo.id}\n            item={todo}\n          />\n        ))}\n      </ul>\n      <CreateTodo onCreate={handleCreate} />\n    </div>\n  );\n}\n\nexport default TodoList;\n"
  },
  {
    "path": "example/functions/src/react/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <link rel=\"icon\" href=\"favicon.ico\" />\n    <link rel=\"stylesheet\" href=\"app.css\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <meta name=\"theme-color\" content=\"#000000\" />\n    <meta name=\"description\" content=\"React SSR\" />\n    <title>React App</title>\n    <script id=\"init\" type=\"text/javascript\"></script>\n  </head>\n  <body>\n    <noscript>You need to enable JavaScript to run this app.</noscript>\n    <div id=\"root\"></div>\n  </body>\n  <script type=\"text/javascript\" src=\"app.js\"></script>\n</html>\n"
  },
  {
    "path": "example/functions/src/react/index.tsx",
    "content": "import ReactDOM from \"react-dom\";\n\nimport App from \"./App\";\n\nReactDOM.hydrate(\n  <App\n    todoItems={(window && window.todoItems) || []}\n    releaseName={window.releaseName}\n  />,\n  document.getElementById(\"root\")\n);\n"
  },
  {
    "path": "example/functions/src/ssr.ts",
    "content": "import fs from \"node:fs/promises\";\nimport App from \"./react/App\";\nimport ReactDOMServer from \"react-dom/server.edge\";\n\nimport React from \"react\";\nimport API from \"./api\";\n\ntype Method = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\n\ntype ResponseOptions = {\n  contentType?: string;\n  isBase64Encoded?: boolean;\n  headers?: Record<string, string>;\n  statusCode?: number;\n};\n\nconst ASSET_CACHE: Record<string, string> = {};\nconst MIME_TYPES = {\n  js: \"text/javascript\",\n  css: \"text/css\",\n  html: \"text/html\",\n  ico: \"image/x-icon\",\n  svg: \"image/svg+xml\",\n  png: \"image/png\",\n  jpg: \"image/jpeg\",\n};\n\nconst htmlFilePromise = fs.readFile(\"./index.html\");\n\nlet htmlContent: string | null = null;\n\nclass HttpError extends Error {\n  status: number;\n  constructor(status: number, message: string) {\n    super(message);\n    this.status = status;\n  }\n}\n\nconst response = (\n  body: string,\n  {\n    contentType = \"text/plain\",\n    isBase64Encoded,\n    headers,\n    statusCode = 200,\n  }: ResponseOptions = {}\n) => ({\n  statusCode,\n  headers: {\n    \"content-type\": contentType,\n    ...headers,\n  },\n  body,\n  isBase64Encoded,\n});\n\nconst apiResponse = async (\n  pathParams: string[],\n  method: Method,\n  body?: string\n) => {\n  const [id] = pathParams;\n  if (id) {\n    if (method === \"DELETE\") {\n      await API.delete(id);\n      return response(\"\", {\n        contentType: \"application/json\",\n      });\n    }\n    if (method === \"PUT\") {\n      const { text, completedDate } = JSON.parse(body);\n      const item = await API.update({ id, text, completedDate });\n      return response(JSON.stringify(item), {\n        contentType: \"application/json\",\n      });\n    }\n  }\n\n  if (pathParams.length == 0 && method === \"POST\") {\n    const { text } = JSON.parse(body);\n    const item = await API.create(text);\n    return response(JSON.stringify(item), {\n      contentType: \"application/json\",\n    });\n  }\n\n  throw new HttpError(404, \"Not found\");\n};\n\nconst appResponse = async () => {\n  let todoItems;\n  if (!htmlContent) {\n    const [html, items] = await Promise.all([htmlFilePromise, API.getAll()]);\n    htmlContent = html.toString();\n    todoItems = items;\n  } else {\n    todoItems = await API.getAll();\n  }\n\n  const app = ReactDOMServer.renderToString(\n    React.createElement(App, { todoItems })\n  );\n  const html = htmlContent\n    .replace(\n      '<script id=\"init\" type=\"text/javascript\"></script>',\n      `<script id=\"init\" type=\"text/javascript\">\nwindow.todoItems = ${JSON.stringify(todoItems)};\nwindow.releaseName = ${JSON.stringify(process.release.name)}\n</script>`\n    )\n    .replace('<div id=\"root\"></div>', `<div id=\"root\">${app}</div>`);\n\n  return response(html, { contentType: \"text/html\" });\n};\n\nconst fileExists = (file: string) =>\n  fs.access(file).then(\n    () => true,\n    () => false\n  );\n\nconst loadAsset = async (asset: string) => {\n  const safeAsset = asset.replace(\"..\", \"\");\n  const cachedAsset = ASSET_CACHE[safeAsset];\n  if (cachedAsset) {\n    return cachedAsset;\n  }\n  if (!(await fileExists(safeAsset))) {\n    throw new HttpError(404, \"Not found\");\n  }\n  const data = (await fs.readFile(safeAsset)).toString(\"base64\");\n  ASSET_CACHE[safeAsset] = data;\n  return data;\n};\n\nconst assetResponse = async (path: string) => {\n  const data = await loadAsset(path);\n  const extIndex = path.lastIndexOf(\".\");\n  let contentType = null;\n  if (extIndex > -1) {\n    const ext = path.substring(extIndex + 1);\n    contentType = MIME_TYPES[ext as keyof typeof MIME_TYPES];\n  }\n\n  return response(data, { contentType, isBase64Encoded: true });\n};\n\nexport const handler = async (event: any) => {\n  const { method = \"GET\", path: eventPath = \"/\" } =\n    event?.requestContext?.http || {};\n\n  try {\n    const reqSegments: string[] = (eventPath as string)\n      .split(\"/\")\n      .filter((x) => x)\n      .slice(1);\n    console.log({ reqSegments, eventPath, method });\n\n    if (reqSegments[0] === \"api\") {\n      return await apiResponse(reqSegments.slice(1), method, event.body);\n    }\n\n    if (method === \"GET\") {\n      if (reqSegments.length === 0) {\n        return await appResponse();\n      }\n      return await assetResponse(reqSegments.join(\"/\"));\n    }\n    throw new HttpError(400, \"Method not supported\");\n  } catch (e) {\n    console.error(e);\n    if (e instanceof HttpError) {\n      return {\n        statusCode: e.status,\n        body: e.message,\n      };\n    }\n    return {\n      statusCode: 500,\n      body: \"Internal server error\",\n    };\n  }\n};\n"
  },
  {
    "path": "example/functions/src/types.d.ts",
    "content": "declare module \"*.svg\" {\n  const content: string;\n  export default content;\n}\n"
  },
  {
    "path": "example/functions/src/v2.js",
    "content": "const DynamoDB = require(\"aws-sdk/clients/dynamodb.js\");\n\nconst client = new DynamoDB();\n\nexport const handler = async (event) => {\n  await client\n    .putItem({\n      TableName: process.env.TABLE_NAME,\n      Item: {\n        id: {\n          S: Math.random().toString(36).substring(2),\n        },\n        content: {\n          S: JSON.stringify(event),\n        },\n      },\n    })\n    .promise();\n  return {\n    statusCode: 200,\n    body: \"OK\",\n  };\n};\n"
  },
  {
    "path": "example/functions/src/v3-lib.mjs",
    "content": "import { DynamoDBClient } from \"@aws-sdk/client-dynamodb\";\nimport { DynamoDBDocumentClient, PutCommand } from \"@aws-sdk/lib-dynamodb\";\n\nconst client = new DynamoDBClient({});\nconst docClient = DynamoDBDocumentClient.from(client);\n\nexport const handler = async (event) => {\n  await docClient.send(\n    new PutCommand({\n      TableName: process.env.TABLE_NAME,\n      Item: {\n        id: Math.random().toString(36).substring(2),\n        content: JSON.stringify(event),\n      },\n    })\n  );\n  return {\n    statusCode: 200,\n    body: \"OK\",\n  };\n};\n"
  },
  {
    "path": "example/functions/src/v3-mono.mjs",
    "content": "import { DynamoDB } from \"@aws-sdk/client-dynamodb\";\n\nconst client = new DynamoDB({});\n\nexport const handler = async (event) => {\n  await client.putItem({\n    TableName: process.env.TABLE_NAME,\n    Item: {\n      id: {\n        S: Math.random().toString(36).substring(2),\n      },\n      content: {\n        S: JSON.stringify(event),\n      },\n    },\n  });\n  return {\n    statusCode: 200,\n    body: \"OK\",\n  };\n};\n"
  },
  {
    "path": "example/functions/src/v3-s3.mjs",
    "content": "import { DynamoDBClient } from \"@aws-sdk/client-dynamodb\";\nimport { DynamoDBDocumentClient, PutCommand } from \"@aws-sdk/lib-dynamodb\";\nimport { PutObjectCommand, S3Client } from \"@aws-sdk/client-s3\";\n\nimport { randomBytes } from \"node:crypto\";\n\nconst uid = () =>\n  String.fromCharCode(\n    ...randomBytes(10).map((d) => {\n      return (d > 127 ? 97 : 65) + (d % 25);\n    })\n  );\n\nconst dynamoDbClient = new DynamoDBClient({});\nconst s3Client = new S3Client({});\nconst docClient = DynamoDBDocumentClient.from(dynamoDbClient);\n\nexport const handler = async (event) => {\n  let id = uid();\n  let data = JSON.stringify(event);\n\n  await Promise.all([\n    docClient.send(\n      new PutCommand({\n        TableName: process.env.TABLE_NAME,\n        Item: {\n          id,\n          content: data,\n        },\n      })\n    ),\n    s3Client.send(\n      new PutObjectCommand({\n        Body: data,\n        Bucket: process.env.BUCKET_NAME,\n        Key: id,\n      })\n    ),\n  ]);\n\n  return {\n    statusCode: 200,\n    body: \"OK\",\n  };\n};\n"
  },
  {
    "path": "example/functions/src/v3.mjs",
    "content": "import { DynamoDBClient, PutItemCommand } from \"@aws-sdk/client-dynamodb\";\n\nconst client = new DynamoDBClient({});\n\nexport const handler = async (event) => {\n  await client.send(\n    new PutItemCommand({\n      TableName: process.env.TABLE_NAME,\n      Item: {\n        id: {\n          S: Math.random().toString(36).substring(2),\n        },\n        content: {\n          S: JSON.stringify(event),\n        },\n      },\n    })\n  );\n  return {\n    statusCode: 200,\n    body: \"OK\",\n  };\n};\n"
  },
  {
    "path": "example/functions/tsconfig.json",
    "content": "{\n  \"include\": [\"src\"],\n  \"exclude\": [\"lib\", \"node_modules\"],\n  \"compilerOptions\": {\n    \"downlevelIteration\": true,\n    \"outDir\": \"lib\",\n    \"esModuleInterop\": true,\n    \"noImplicitAny\": true,\n    \"noImplicitThis\": true,\n    \"jsx\": \"react-jsx\"\n  }\n}\n"
  },
  {
    "path": "example/infrastructure/cdk.json",
    "content": "{\n  \"app\": \"ts-node ./src/index.ts\"\n}\n"
  },
  {
    "path": "example/infrastructure/package.json",
    "content": "{\n  \"name\": \"@example/infra\",\n  \"version\": \"1.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"synth\": \"cdk synth\",\n    \"predeploy\": \"cdk bootstrap\",\n    \"deploy\": \"cdk deploy\",\n    \"hotswap\": \"cdk deploy --hotswap\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"25.3.3\",\n    \"aws-cdk\": \"2.1108.0\",\n    \"aws-cdk-lib\": \"2.240.0\",\n    \"constructs\": \"10.5.1\",\n    \"esbuild\": \"0.27.3\",\n    \"ts-node\": \"10.9.2\",\n    \"typescript\": \"5.9.3\"\n  }\n}\n"
  },
  {
    "path": "example/infrastructure/src/index.ts",
    "content": "import {\n  App,\n  aws_dynamodb,\n  aws_lambda,\n  aws_lambda_nodejs,\n  aws_s3,\n  aws_logs,\n  aws_iam,\n  aws_cloudfront,\n  aws_cloudfront_origins,\n  aws_apigatewayv2,\n  aws_apigatewayv2_integrations,\n  CfnOutput,\n  Stack,\n  Fn,\n  Duration,\n} from \"aws-cdk-lib\";\nimport * as fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { execSync } from \"node:child_process\";\n\nconst main = async () => {\n  execSync(\"node build.mjs\", {\n    cwd: \"../functions\",\n    stdio: \"inherit\",\n  });\n\n  const app = new App();\n  const stack = new Stack(app, \"llrt-example\", {\n    env: {\n      region: process.env.CDK_DEFAULT_REGION,\n    },\n  });\n\n  const routePaths: string[] = [];\n\n  const tmpDir = os.tmpdir();\n  const targetFunctionsDir = path.join(tmpDir, \"functions\");\n  const sourceFunctionsDir = path.resolve(\"../functions/src\");\n\n  await fs.mkdir(targetFunctionsDir, { recursive: true });\n  const sourceDirs = {};\n  const sources = await fs.readdir(sourceFunctionsDir);\n  await Promise.all(\n    sources.map(async (source) => {\n      if (source === \"react\") {\n        return;\n      }\n      const { name, ext } = path.parse(source);\n      const targetDir = path.join(targetFunctionsDir, name);\n      await fs.mkdir(targetDir, { recursive: true });\n      await fs.copyFile(\n        path.join(sourceFunctionsDir, source),\n        path.join(targetDir, `index${ext}`)\n      );\n      sourceDirs[source] = targetDir;\n    })\n  );\n\n  const httpApi = new aws_apigatewayv2.HttpApi(stack, `HttpApi`, {\n    disableExecuteApiEndpoint: false,\n    corsPreflight: undefined,\n  });\n\n  const httpEndpointNoProto = Fn.select(\n    1,\n    Fn.split(\"://\", httpApi.apiEndpoint)\n  );\n\n  const createDistribution = (route: string) => {\n    const id = route.substring(1).replace(/-\\//g, \"\");\n    const distribution = new aws_cloudfront.Distribution(\n      stack,\n      `${id}Distribution`,\n      {\n        defaultBehavior: {\n          origin: new aws_cloudfront_origins.HttpOrigin(httpEndpointNoProto, {\n            protocolPolicy: aws_cloudfront.OriginProtocolPolicy.HTTPS_ONLY,\n            originPath: route,\n          }),\n          allowedMethods: aws_cloudfront.AllowedMethods.ALLOW_ALL,\n          cachePolicy: aws_cloudfront.CachePolicy.CACHING_DISABLED,\n        },\n      }\n    );\n    new CfnOutput(stack, `DistributionOutput${id}`, {\n      value: distribution.distributionDomainName,\n    });\n  };\n\n  const addRoute = (lambda: aws_lambda.Function, routePath: string) => {\n    const integration = new aws_apigatewayv2_integrations.HttpLambdaIntegration(\n      `${lambda.node.id}Integration`,\n      lambda\n    );\n\n    new aws_apigatewayv2.HttpRoute(stack, `${lambda.node.id}Route`, {\n      httpApi,\n      routeKey: aws_apigatewayv2.HttpRouteKey.with(\n        routePath,\n        aws_apigatewayv2.HttpMethod.ANY\n      ),\n      integration,\n    });\n    new aws_apigatewayv2.HttpRoute(stack, `${lambda.node.id}ProxyRoute`, {\n      httpApi,\n      routeKey: aws_apigatewayv2.HttpRouteKey.with(\n        `${routePath}/{proxy+}`,\n        aws_apigatewayv2.HttpMethod.ANY\n      ),\n      integration,\n    });\n\n    routePaths.push(routePath);\n  };\n\n  const table = new aws_dynamodb.Table(stack, \"Table\", {\n    partitionKey: {\n      name: \"id\",\n      type: aws_dynamodb.AttributeType.STRING,\n    },\n    billingMode: aws_dynamodb.BillingMode.PAY_PER_REQUEST,\n  });\n\n  const todoTable = new aws_dynamodb.Table(stack, \"TodoTable\", {\n    partitionKey: {\n      name: \"id\",\n      type: aws_dynamodb.AttributeType.STRING,\n    },\n    billingMode: aws_dynamodb.BillingMode.PAY_PER_REQUEST,\n  });\n\n  const bucket = new aws_s3.Bucket(stack, \"Bucket\", {});\n\n  const props = {\n    environment: {\n      TABLE_NAME: table.tableName,\n      BUCKET_NAME: bucket.bucketName,\n    },\n    runtime: aws_lambda.Runtime.NODEJS_20_X,\n    memorySize: 128,\n    timeout: Duration.seconds(60),\n    handler: \"index.handler\",\n    bundling: {\n      format: aws_lambda_nodejs.OutputFormat.ESM,\n      banner:\n        \"import {createRequire} from 'module';const require=createRequire(import.meta.url);\",\n      minify: true,\n      sourceMap: true,\n    },\n    architecture: aws_lambda.Architecture.ARM_64,\n    logRetention: aws_logs.RetentionDays.ONE_WEEK,\n  };\n\n  const llrtLayer = new aws_lambda.LayerVersion(stack, \"LlrtArmLayer\", {\n    code: aws_lambda.Code.fromAsset(\"../../llrt-lambda-arm64.zip\"),\n    compatibleRuntimes: [aws_lambda.Runtime.PROVIDED_AL2023],\n    compatibleArchitectures: [aws_lambda.Architecture.ARM_64],\n  });\n\n  // LLRT hello\n  const helloLlrtFunction = new aws_lambda.Function(\n    stack,\n    \"HelloLlrtFunction\",\n    {\n      functionName: \"example-hello-llrt\",\n      code: aws_lambda.Code.fromAsset(sourceDirs[\"hello.mjs\"]),\n      ...props,\n      environment: {},\n      runtime: aws_lambda.Runtime.PROVIDED_AL2023,\n      layers: [llrtLayer],\n    }\n  );\n\n  // Node hello\n  const helloNode20Function = new aws_lambda.Function(\n    stack,\n    \"HelloNode20Function\",\n    {\n      functionName: \"example-hello-node20\",\n      code: aws_lambda.Code.fromAsset(sourceDirs[\"hello.mjs\"]),\n      ...props,\n      environment: {},\n    }\n  );\n\n  const helloNode18Function = new aws_lambda.Function(\n    stack,\n    \"HelloNode18Function\",\n    {\n      functionName: \"example-hello-node18\",\n      code: aws_lambda.Code.fromAsset(sourceDirs[\"hello.mjs\"]),\n      ...props,\n      runtime: aws_lambda.Runtime.NODEJS_18_X,\n      environment: {},\n    }\n  );\n\n  const helloNode16Function = new aws_lambda.Function(\n    stack,\n    \"HelloNode16Function\",\n    {\n      functionName: \"example-hello-node16\",\n      code: aws_lambda.Code.fromAsset(sourceDirs[\"hello.mjs\"]),\n      ...props,\n      runtime: aws_lambda.Runtime.NODEJS_16_X,\n      environment: {},\n    }\n  );\n\n  // Node 16, provided \"aws-sdk\"\n  const v2Function = new aws_lambda_nodejs.NodejsFunction(stack, \"V2\", {\n    functionName: \"example-v2\",\n    entry: \"../functions/src/v2.js\",\n    ...props,\n    runtime: aws_lambda.Runtime.NODEJS_16_X,\n    bundling: {\n      ...props.bundling,\n      externalModules: [\"aws-sdk\"],\n    },\n  });\n\n  // Node 20, aws-sdk-v3, DynamoDBClient.send API, bundled in\n  const v3BundledFunction = new aws_lambda_nodejs.NodejsFunction(\n    stack,\n    \"V3Bundled\",\n    {\n      functionName: \"example-v3-bundled\",\n      entry: \"../functions/src/v3.mjs\",\n      ...props,\n      bundling: {\n        ...props.bundling,\n        externalModules: [],\n      },\n    }\n  );\n\n  // Node 20, aws-sdk-v3, DynamoDBClient.send API, tree-shaken out (using one provided by us)\n  const v3providedFunction = new aws_lambda.Function(stack, \"V3Provided\", {\n    functionName: \"example-v3-provided\",\n    code: aws_lambda.Code.fromAsset(sourceDirs[\"v3.mjs\"]),\n    ...props,\n  });\n\n  // Node 20, aws-sdk-v3, DynamoDB.putItem (mono API), tree-shaken\n  const v3providedMonoFunction = new aws_lambda_nodejs.NodejsFunction(\n    stack,\n    \"V3providedMono\",\n    {\n      functionName: \"example-v3-mono-provided\",\n      entry: \"../functions/src/v3-mono.mjs\",\n      ...props,\n      bundling: {\n        ...props.bundling,\n        externalModules: [\"@aws-sdk/*\"],\n      },\n    }\n  );\n\n  // Node 20, aws-sdk-v3, DynamoDB.putItem (mono API), bundled\n  const v3BundledMonoFunction = new aws_lambda_nodejs.NodejsFunction(\n    stack,\n    \"V3BundledMono\",\n    {\n      functionName: \"example-v3-mono-bundled\",\n      entry: \"../functions/src/v3-mono.mjs\",\n      ...props,\n      bundling: {\n        ...props.bundling,\n        externalModules: [],\n      },\n    }\n  );\n\n  // LLRT aws-sdk-v3, DynamoDBClient.send API\n  const llrtFunction = new aws_lambda.Function(stack, \"LlrtFunction\", {\n    functionName: \"example-llrt\",\n    code: aws_lambda.Code.fromAsset(sourceDirs[\"v3-lib.mjs\"]),\n    handler: \"index.handler\",\n    ...props,\n    runtime: aws_lambda.Runtime.PROVIDED_AL2023,\n    layers: [llrtLayer],\n  });\n\n  // LLRT aws-sdk-v3, DynamoDBClient & S3 API\n  const llrtS3Function = new aws_lambda.Function(stack, \"LlrtS3Function\", {\n    functionName: \"example-llrt-s3\",\n    code: aws_lambda.Code.fromAsset(sourceDirs[\"v3-s3.mjs\"]),\n    handler: \"index.handler\",\n    ...props,\n    runtime: aws_lambda.Runtime.PROVIDED_AL2023,\n    environment: {\n      ...props.environment,\n    },\n    layers: [llrtLayer],\n  });\n\n  // aws-sdk-v3, DynamoDBClient & S3 API\n  const s3Function = new aws_lambda.Function(stack, \"S3Function\", {\n    functionName: \"example-s3\",\n    code: aws_lambda.Code.fromAsset(sourceDirs[\"v3-s3.mjs\"]),\n    handler: \"index.handler\",\n    ...props,\n    environment: {\n      ...props.environment,\n    },\n  });\n\n  // ssr react, node.js\n  const reactFunction = new aws_lambda.Function(stack, \"ReactFunction\", {\n    functionName: \"example-react\",\n    code: aws_lambda.Code.fromAsset(\"../functions/build\"),\n    handler: \"index.handler\",\n    ...props,\n    environment: {\n      ...props.environment,\n      TABLE_NAME: todoTable.tableName,\n    },\n  });\n\n  // ssr react,llrt\n  const llrtReactFunction = new aws_lambda.Function(\n    stack,\n    \"LlrtReactFunction\",\n    {\n      functionName: \"example-llrt-react\",\n      code: aws_lambda.Code.fromAsset(\"../functions/build/react\"),\n      handler: \"index.handler\",\n      ...props,\n      runtime: aws_lambda.Runtime.PROVIDED_AL2023,\n      environment: {\n        ...props.environment,\n        TABLE_NAME: todoTable.tableName,\n      },\n      layers: [llrtLayer],\n    }\n  );\n\n  // LLRT, function with non-included AWS SDK client\n  const llrtNonIncludedSdkFunction = new aws_lambda.Function(\n    stack,\n    \"LlrtNonProvided\",\n    {\n      functionName: \"example-llrt-non-provided\",\n      handler: \"index.handler\",\n      code: aws_lambda.Code.fromAsset(\"../functions/build/external\"),\n      ...props,\n      environment: {},\n      runtime: aws_lambda.Runtime.PROVIDED_AL2023,\n      layers: [llrtLayer],\n    }\n  );\n\n  //add describe instances permission to llrtNonIncludedSdkFunction\n  llrtNonIncludedSdkFunction.addToRolePolicy(\n    new aws_iam.PolicyStatement({\n      actions: [\"ec2:DescribeInstances\"],\n      resources: [\"*\"],\n    })\n  );\n\n  todoTable.grantReadWriteData(reactFunction);\n  todoTable.grantReadWriteData(llrtReactFunction);\n  table.grantReadWriteData(v2Function);\n  table.grantReadWriteData(v3BundledFunction);\n  table.grantReadWriteData(v3providedFunction);\n  table.grantReadWriteData(v3providedMonoFunction);\n  table.grantReadWriteData(v3BundledMonoFunction);\n  table.grantReadWriteData(llrtFunction);\n  table.grantReadWriteData(llrtS3Function);\n  table.grantReadWriteData(s3Function);\n\n  bucket.grantReadWrite(llrtS3Function);\n  bucket.grantReadWrite(s3Function);\n\n  addRoute(helloNode20Function, \"/hello-20\");\n  addRoute(helloNode18Function, \"/hello-18\");\n  addRoute(helloNode16Function, \"/hello-16\");\n  addRoute(helloLlrtFunction, \"/hello-llrt\");\n  addRoute(v2Function, \"/v2\");\n  addRoute(v3BundledFunction, \"/v3-bundled\");\n  addRoute(v3providedFunction, \"/v3-provided\");\n  addRoute(v3providedMonoFunction, \"/v3-provided-mono\");\n  addRoute(v3BundledMonoFunction, \"/v3-bundled-mono\");\n  addRoute(llrtFunction, \"/llrt\");\n  addRoute(llrtS3Function, \"/llrt-s3\");\n  addRoute(s3Function, \"/s3\");\n  addRoute(reactFunction, \"/react\");\n  addRoute(llrtReactFunction, \"/llrt-react\");\n\n  for (const [i, route] of routePaths.entries()) {\n    new CfnOutput(stack, `HttpApiOutput${i}`, {\n      value: `${httpApi.apiEndpoint}${route}`,\n    });\n  }\n\n  createDistribution(\"/llrt-react\");\n  createDistribution(\"/react\");\n};\n\nmain();\n"
  },
  {
    "path": "example/infrastructure/tsconfig.json",
    "content": "{\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\",\n    \"module\": \"CommonJS\",\n    \"moduleResolution\": \"Node\",\n    \"esModuleInterop\": true,\n    \"target\": \"ES2023\"\n  }\n}\n"
  },
  {
    "path": "example/llrt-sam/.gitignore",
    "content": "\n# Created by https://www.toptal.com/developers/gitignore/api/osx,node,linux,windows,sam\n# Edit at https://www.toptal.com/developers/gitignore?templates=osx,node,linux,windows,sam\n\n### Linux ###\n*~\n\n# temporary files which can be created if a process still has a handle open of a deleted file\n.fuse_hidden*\n\n# KDE directory preferences\n.directory\n\n# Linux trash folder which might appear on any partition or disk\n.Trash-*\n\n# .nfs files are created when an open file is removed but is still being accessed\n.nfs*\n\n### Node ###\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\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# TypeScript v1 declaration files\ntypings/\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 variables file\n.env\n.env.test\n.env*.local\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n.parcel-cache\n\n# Next.js build output\n.next\n\n# Nuxt.js build / generate output\n.nuxt\ndist\n\n# Storybook build outputs\n.out\n.storybook-out\nstorybook-static\n\n# rollup.js default build output\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# 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# Temporary folders\ntmp/\ntemp/\n\n### OSX ###\n# General\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\r\r\n\n# Thumbnails\n._*\n\n# Files that might appear in the root of a volume\n.DocumentRevisions-V100\n.fseventsd\n.Spotlight-V100\n.TemporaryItems\n.Trashes\n.VolumeIcon.icns\n.com.apple.timemachine.donotpresent\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n### SAM ###\n# Ignore build directories for the AWS Serverless Application Model (SAM)\n# Info: https://aws.amazon.com/serverless/sam/\n# Docs: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-reference.html\n\n**/.aws-sam\n\n### Windows ###\n# Windows thumbnail cache files\nThumbs.db\nThumbs.db:encryptable\nehthumbs.db\nehthumbs_vista.db\n\n# Dump file\n*.stackdump\n\n# Folder config file\n[Dd]esktop.ini\n\n# Recycle Bin used on file shares\n$RECYCLE.BIN/\n\n# Windows Installer files\n*.cab\n*.msi\n*.msix\n*.msm\n*.msp\n\n# Windows shortcuts\n*.lnk\n\n# End of https://www.toptal.com/developers/gitignore/api/osx,node,linux,windows,sam\n\n\n# Created by https://www.gitignore.io/api/osx,node,macos,linux,python,windows,pycharm,intellij,sublimetext,visualstudiocode\n\n### Intellij ###\n# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm\n# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839\n\n# User-specific stuff:\n.idea/**/workspace.xml\n.idea/**/tasks.xml\n.idea/dictionaries\n.idea\n.vscode\n\n# Sensitive or high-churn files:\n.idea/**/dataSources/\n.idea/**/dataSources.ids\n.idea/**/dataSources.xml\n.idea/**/dataSources.local.xml\n.idea/**/sqlDataSources.xml\n.idea/**/dynamic.xml\n.idea/**/uiDesigner.xml\n\n# Gradle:\n.idea/**/gradle.xml\n.idea/**/libraries\n\n# CMake\ncmake-build-debug/\n\n# Mongo Explorer plugin:\n.idea/**/mongoSettings.xml\n\n## File-based project format:\n*.iws\n\n## Plugin-specific files:\n\n# IntelliJ\n/out/\n\n# mpeltonen/sbt-idea plugin\n.idea_modules/\n\n# JIRA plugin\natlassian-ide-plugin.xml\n\n# Cursive Clojure plugin\n.idea/replstate.xml\n\n# Ruby plugin and RubyMine\n/.rakeTasks\n\n# Crashlytics plugin (for Android Studio and IntelliJ)\ncom_crashlytics_export_strings.xml\ncrashlytics.properties\ncrashlytics-build.properties\nfabric.properties\n\n### Intellij Patch ###\n# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721\n\n*.iml\n# modules.xml\n# .idea/misc.xml\n# *.ipr\n\n# Sonarlint plugin\n.idea/sonarlint\n\n### Linux ###\n*~\n\n# temporary files which can be created if a process still has a handle open of a deleted file\n.fuse_hidden*\n\n# KDE directory preferences\n.directory\n\n# Linux trash folder which might appear on any partition or disk\n.Trash-*\n\n# .nfs files are created when an open file is removed but is still being accessed\n.nfs*\n\n### macOS ###\n*.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\n\n# Thumbnails\n._*\n\n# Files that might appear in the root of a volume\n.DocumentRevisions-V100\n.fseventsd\n.Spotlight-V100\n.TemporaryItems\n.Trashes\n.VolumeIcon.icns\n.com.apple.timemachine.donotpresent\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n### Node ###\n# Logs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\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\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (http://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 (http://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Typescript v1 declaration files\ntypings/\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Except test file\n!tests/functional/testdata/lib/utils/test.tgz\n!tests/functional/testdata/lib/utils/path_reversal_uxix.tgz\n!tests/functional/testdata/lib/utils/path_reversal_win.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n\n\n### OSX ###\n\n# Icon must end with two \\r\n\n# Thumbnails\n\n# Files that might appear in the root of a volume\n\n# Directories potentially created on remote AFP share\n\n### PyCharm ###\n# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm\n# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839\n\n# User-specific stuff:\n\n# Sensitive or high-churn files:\n\n# Gradle:\n\n# CMake\n\n# Mongo Explorer plugin:\n\n## File-based project format:\n\n## Plugin-specific files:\n\n# IntelliJ\n\n# mpeltonen/sbt-idea plugin\n\n# JIRA plugin\n\n# Cursive Clojure plugin\n\n# Ruby plugin and RubyMine\n\n# Crashlytics plugin (for Android Studio and IntelliJ)\n\n### PyCharm Patch ###\n# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721\n\n# *.iml\n# modules.xml\n# .idea/misc.xml\n# *.ipr\n\n# Sonarlint plugin\n\n### Python ###\n# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\n/build/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\n*.egg-info/\n.installed.cfg\n*.egg\npip-wheel-metadata/\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.coverage.*\n.cache\n.pytest_cache/\nnosetests.xml\ncoverage.xml\n*.cover\n.hypothesis/\n\n# Translations\n*.mo\n*.pot\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\n/target/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# pyenv\n.python-version\n\n# pyright\npyrightconfig.json\n\n# celery beat schedule file\ncelerybeat-schedule.*\n\n# SageMath parsed files\n*.sage.py\n\n# AWS SAM\nbuild.toml\nbuild_dir/\n# Environments\n.venv\nenv/\nvenv/\nENV/\nenv.bak/\nvenv.bak/\nvenv-update-reproducible-requirements/\n\nenv.*/\nvenv.*/\n.env.*/\n.venv.*/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n\n# ruff\n.ruff_cache/\n\n# SAM default build folder\n.aws-sam/\n\n### SublimeText ###\n# cache files for sublime text\n*.tmlanguage.cache\n*.tmPreferences.cache\n*.stTheme.cache\n\n# workspace files are user-specific\n*.sublime-workspace\n\n# project files should be checked into the repository, unless a significant\n# proportion of contributors will probably not be using SublimeText\n# *.sublime-project\n\n# sftp configuration file\nsftp-config.json\n\n# Package control specific files\nPackage Control.last-run\nPackage Control.ca-list\nPackage Control.ca-bundle\nPackage Control.system-ca-bundle\nPackage Control.cache/\nPackage Control.ca-certs/\nPackage Control.merged-ca-bundle\nPackage Control.user-ca-bundle\noscrypto-ca-bundle.crt\nbh_unicode_properties.cache\n\n# Sublime-github package stores a github token in this file\n# https://packagecontrol.io/packages/sublime-github\nGitHub.sublime-settings\n\n### VisualStudioCode ###\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\n.history\n\n### Theia editor (GitPod)\n.theia\n\n### Windows ###\n# Windows thumbnail cache files\nThumbs.db\nehthumbs.db\nehthumbs_vista.db\n\n# Folder config file\nDesktop.ini\n\n# Recycle Bin used on file shares\n$RECYCLE.BIN/\n\n# Windows Installer files\n*.cab\n*.msi\n*.msm\n*.msp\n\n# Windows shortcuts\n*.lnk\n\n# Code coverage\ncov.xml\ncoverage.xml\n\n# Temporary scratch directory used by the tests\ntests/integration/buildcmd/scratch\ntests/integration/testdata/buildcmd/Dotnet6/bin\ntests/integration/testdata/buildcmd/Dotnet6/obj\ntests/integration/testdata/buildcmd/Dotnet7/bin\ntests/integration/testdata/buildcmd/Dotnet7/obj\ntests/integration/testdata/invoke/credential_tests/inprocess/dotnet/STS/obj\ntests/integration/testdata/sync/code/after/dotnet_function/src/HelloWorld/obj/\ntests/integration/testdata/sync/code/before/dotnet_function/src/HelloWorld/obj/\n\n# End of https://www.gitignore.io/api/osx,node,macos,linux,python,windows,pycharm,intellij,sublimetext,visualstudiocode\n\n# Installer build folder\n.build\n"
  },
  {
    "path": "example/llrt-sam/README.md",
    "content": "# llrt-sam\n\nThis is a sample SAM project with LLRT instrumentation on a lambda via a lambda layer\n\n- hello-world - Code for the application's Lambda function written in TypeScript.\n- template.yaml - A template that defines the application's AWS resources.\n\nThe application uses several AWS resources, including Lambda functions and an AWS Lambda Layer. These resources are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code.\n\nIf you prefer to use an integrated development environment (IDE) to build and test your application, you can use the AWS Toolkit.\nThe AWS Toolkit is an open source plug-in for popular IDEs that uses the SAM CLI to build and deploy serverless applications on AWS. The AWS Toolkit also adds a simplified step-through debugging experience for Lambda function code. See the following links to get started.\n\n- [CLion](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html)\n- [GoLand](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html)\n- [IntelliJ](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html)\n- [WebStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html)\n- [Rider](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html)\n- [PhpStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html)\n- [PyCharm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html)\n- [RubyMine](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html)\n- [DataGrip](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html)\n- [VS Code](https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/welcome.html)\n- [Visual Studio](https://docs.aws.amazon.com/toolkit-for-visual-studio/latest/user-guide/welcome.html)\n\n## Deploy the sample application\n\nThe Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API.\n\nTo use the SAM CLI, you need the following tools.\n\n- SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)\n- Node.js - [Install Node.js 18](https://nodejs.org/en/), including the NPM package management tool.\n- Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community)\n\nTo build and deploy your application for the first time, run the following in your shell:\n\n```bash\nsam build\nsam deploy --guided\n```\n\nThe first command will build the source of your application. The second command will package and deploy your application to AWS, with a series of prompts:\n\n- **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name.\n- **AWS Region**: The AWS region you want to deploy your app to.\n- **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes.\n- **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modifies IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command.\n- **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application.\n\nYou can find your API Gateway Endpoint URL in the output values displayed after deployment.\n\n## Use the SAM CLI to build and test locally\n\nBuild your application with the `sam build` command.\n\n```bash\nllrt-sam$ sam build\n```\n\nThe SAM CLI installs dependencies defined in `hello-world/package.json`, compiles TypeScript with esbuild, creates a deployment package, and saves it in the `.aws-sam/build` folder.\n\nTest a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project.\n\nRun functions locally and invoke them with the `sam local invoke` command.\n\n```bash\nllrt-sam$ sam local invoke HelloWorldFunction\n```\n\n## Add a resource to your application\n\nThe application template uses AWS Serverless Application Model (AWS SAM) to define application resources. AWS SAM is an extension of AWS CloudFormation with a simpler syntax for configuring common serverless application resources such as functions, triggers, and APIs. For resources not included in [the SAM specification](https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md), you can use standard [AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html) resource types.\n\n## Fetch, tail, and filter Lambda function logs\n\nTo simplify troubleshooting, SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs generated by your deployed Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug.\n\n`NOTE`: This command works for all AWS Lambda functions; not just the ones you deploy using SAM.\n\n```bash\nllrt-sam$ sam logs -n HelloWorldFunction --stack-name llrt-sam --tail\n```\n\nYou can find more information and examples about filtering Lambda function logs in the [SAM CLI Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html).\n\n## Cleanup\n\nTo delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following:\n\n```bash\nsam delete --stack-name llrt-sam\n```\n\n## Resources\n\nSee the [AWS SAM developer guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) for an introduction to SAM specification, the SAM CLI, and serverless application concepts.\n\nNext, you can use AWS Serverless Application Repository to deploy ready to use Apps that go beyond hello world samples and learn how authors developed their applications: [AWS Serverless Application Repository main page](https://aws.amazon.com/serverless/serverlessrepo/)\n"
  },
  {
    "path": "example/llrt-sam/hello-world/app.ts",
    "content": "import { APIGatewayProxyEvent, APIGatewayProxyResult } from \"aws-lambda\";\n\n/**\n *\n * Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format\n * @param {Object} event - API Gateway Lambda Proxy Input Format\n *\n * Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html\n * @returns {Object} object - API Gateway Lambda Proxy Output Format\n *\n */\n\nexport const lambdaHandler = async (\n  event: APIGatewayProxyEvent\n): Promise<APIGatewayProxyResult> => {\n  try {\n    return {\n      statusCode: 200,\n      body: JSON.stringify({\n        message: \"hello world\",\n      }),\n    };\n  } catch (err) {\n    console.log(err);\n    return {\n      statusCode: 500,\n      body: JSON.stringify({\n        message: \"some error happened\",\n      }),\n    };\n  }\n};\n"
  },
  {
    "path": "example/llrt-sam/hello-world/package.json",
    "content": "{\n  \"name\": \"hello_world\",\n  \"version\": \"1.0.0\",\n  \"description\": \"LLRT instrumented lambda example\",\n  \"main\": \"app.js\",\n  \"author\": \"SAM CLI\",\n  \"scripts\": {\n    \"compile\": \"tsc\"\n  },\n  \"devDependencies\": {\n    \"@types/aws-lambda\": \"^8.10.92\",\n    \"@types/node\": \"^18.11.4\",\n    \"ts-node\": \"^10.9.1\",\n    \"typescript\": \"^4.8.4\"\n  }\n}\n"
  },
  {
    "path": "example/llrt-sam/hello-world/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es2023\",\n    \"strict\": true,\n    \"preserveConstEnums\": true,\n    \"noEmit\": true,\n    \"sourceMap\": false,\n    \"module\": \"es2022\",\n    \"moduleResolution\": \"node\",\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"forceConsistentCasingInFileNames\": true\n  },\n  \"exclude\": [\"node_modules\", \"**/*.test.ts\"]\n}\n"
  },
  {
    "path": "example/llrt-sam/samconfig.toml",
    "content": "# More information about the configuration file can be found here:\n# https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html\nversion = 0.1\n\n[default]\n[default.global.parameters]\nstack_name = \"llrt-sam\"\n\n[default.build.parameters]\ncached = true\nparallel = true\n\n[default.validate.parameters]\nlint = true\n\n[default.deploy.parameters]\ncapabilities = \"CAPABILITY_IAM\"\nconfirm_changeset = true\nresolve_s3 = true\ns3_prefix = \"llrt-sam\"\nregion = \"us-east-1\"\nimage_repositories = []\n\n[default.package.parameters]\nresolve_s3 = true\n\n[default.sync.parameters]\nwatch = true\n\n[default.local_start_api.parameters]\nwarm_containers = \"EAGER\"\n\n[default.local_start_lambda.parameters]\nwarm_containers = \"EAGER\"\n"
  },
  {
    "path": "example/llrt-sam/template.yaml",
    "content": "AWSTemplateFormatVersion: \"2010-09-09\"\nTransform: AWS::Serverless-2016-10-31\nDescription: >\n  llrt-sam\n\n  Sample SAM Template for llrt-sam\n\n# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst\nGlobals:\n  Function:\n    Timeout: 3\n\nResources:\n  LlrtLayer:\n    Type: AWS::Serverless::LayerVersion\n    Properties:\n      ContentUri: ../../llrt-lambda-arm64.zip\n      CompatibleRuntimes:\n        - provided.al2023\n      CompatibleArchitectures:\n        - arm64\n  HelloWorldFunction:\n    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction\n    Properties:\n      CodeUri: hello-world/\n      Handler: app.lambdaHandler\n      Runtime: provided.al2023\n      Architectures:\n        - arm64\n      Layers:\n        - !Ref LlrtLayer\n    Metadata: # Manage esbuild properties\n      BuildMethod: esbuild\n      BuildProperties:\n        External:\n          - \"@aws-sdk\"\n          - \"@smithy\"\n          - uuid\n        Minify: false\n        Target: \"es2023\"\n        Sourcemap: false\n        Format: esm\n        OutExtension:\n          - .js=.mjs\n        EntryPoints:\n          - app.ts\n\nOutputs:\n  HelloWorldFunction:\n    Description: \"Hello World Lambda Function ARN\"\n    Value: !GetAtt HelloWorldFunction.Arn\n  HelloWorldFunctionIamRole:\n    Description: \"Implicit IAM Role created for Hello World function\"\n    Value: !GetAtt HelloWorldFunctionRole.Arn\n"
  },
  {
    "path": "example/llrt-sam-container-image/.gitignore",
    "content": "\n# Created by https://www.toptal.com/developers/gitignore/api/osx,node,linux,windows,sam\n# Edit at https://www.toptal.com/developers/gitignore?templates=osx,node,linux,windows,sam\n\n### Linux ###\n*~\n\n# temporary files which can be created if a process still has a handle open of a deleted file\n.fuse_hidden*\n\n# KDE directory preferences\n.directory\n\n# Linux trash folder which might appear on any partition or disk\n.Trash-*\n\n# .nfs files are created when an open file is removed but is still being accessed\n.nfs*\n\n### Node ###\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\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# TypeScript v1 declaration files\ntypings/\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 variables file\n.env\n.env.test\n.env*.local\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n.parcel-cache\n\n# Next.js build output\n.next\n\n# Nuxt.js build / generate output\n.nuxt\ndist\n\n# Storybook build outputs\n.out\n.storybook-out\nstorybook-static\n\n# rollup.js default build output\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# 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# Temporary folders\ntmp/\ntemp/\n\n### OSX ###\n# General\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\r\r\n\n# Thumbnails\n._*\n\n# Files that might appear in the root of a volume\n.DocumentRevisions-V100\n.fseventsd\n.Spotlight-V100\n.TemporaryItems\n.Trashes\n.VolumeIcon.icns\n.com.apple.timemachine.donotpresent\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n### SAM ###\n# Ignore build directories for the AWS Serverless Application Model (SAM)\n# Info: https://aws.amazon.com/serverless/sam/\n# Docs: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-reference.html\n\n**/.aws-sam\n\n### Windows ###\n# Windows thumbnail cache files\nThumbs.db\nThumbs.db:encryptable\nehthumbs.db\nehthumbs_vista.db\n\n# Dump file\n*.stackdump\n\n# Folder config file\n[Dd]esktop.ini\n\n# Recycle Bin used on file shares\n$RECYCLE.BIN/\n\n# Windows Installer files\n*.cab\n*.msi\n*.msix\n*.msm\n*.msp\n\n# Windows shortcuts\n*.lnk\n\n# End of https://www.toptal.com/developers/gitignore/api/osx,node,linux,windows,sam\n"
  },
  {
    "path": "example/llrt-sam-container-image/README.md",
    "content": "# llrt-sam-oci\n\nThis project contains source code and supporting files for a serverless application that you can deploy with the SAM CLI. It includes the following files and folders.\n\n- hello-world - Code for the application's Lambda function and Project Dockerfile.\n- events - Invocation events that you can use to invoke the function.\n- hello-world/tests - Unit tests for the application code.\n- template.yaml - A template that defines the application's AWS resources.\n\nThe application uses several AWS resources, including Lambda functions and an API Gateway API. These resources are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code.\n\n## Deploy the sample application\n\nThe Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API.\n\nTo use the SAM CLI, you need the following tools.\n\n- Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community)\n- SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)\n\nTo build and deploy your application for the first time, run the following in your shell:\n\n```bash\nsam build\nsam deploy --guided\n```\n\nThe first command will build a docker image from a Dockerfile and then the source of your application inside the Docker image. The second command will package and deploy your application to AWS, with a series of prompts:\n\n- **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name.\n- **AWS Region**: The AWS region you want to deploy your app to.\n- **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes.\n- **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modifies IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command.\n- **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application.\n\nYou can find your API Gateway Endpoint URL in the output values displayed after deployment.\n\n## Use the SAM CLI to build and test locally\n\nBuild your application with the `sam build` command.\n\n```bash\nllrt-sam-oci$ sam build\n```\n\nThe SAM CLI builds a docker image from a Dockerfile and then installs dependencies defined in `hello-world/package.json` inside the docker image. The processed template file is saved in the `.aws-sam/build` folder.\n\n- **Note**: The Dockerfile included in this sample application uses `npm install` by default. If you are building your code for production, you can modify it to use `npm ci` instead.\n\nTest a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project.\n\nRun functions locally and invoke them with the `sam local invoke` command.\n\n```bash\nllrt-sam-oci$ sam local invoke HelloWorldFunction --event events/event.json\n```\n\nThe SAM CLI can also emulate your application's API. Use the `sam local start-api` to run the API locally on port 3000.\n\n```bash\nllrt-sam-oci$ sam local start-api\nllrt-sam-oci$ curl http://localhost:3000/\n```\n\nThe SAM CLI reads the application template to determine the API's routes and the functions that they invoke. The `Events` property on each function's definition includes the route and method for each path.\n\n```yaml\nEvents:\n  HelloWorld:\n    Type: Api\n    Properties:\n      Path: /hello\n      Method: get\n```\n\n## Add a resource to your application\n\nThe application template uses AWS Serverless Application Model (AWS SAM) to define application resources. AWS SAM is an extension of AWS CloudFormation with a simpler syntax for configuring common serverless application resources such as functions, triggers, and APIs. For resources not included in [the SAM specification](https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md), you can use standard [AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html) resource types.\n\n## Fetch, tail, and filter Lambda function logs\n\nTo simplify troubleshooting, SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs generated by your deployed Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug.\n\n`NOTE`: This command works for all AWS Lambda functions; not just the ones you deploy using SAM.\n\n```bash\nllrt-sam-oci$ sam logs -n HelloWorldFunction --stack-name llrt-sam-oci --tail\n```\n\nYou can find more information and examples about filtering Lambda function logs in the [SAM CLI Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html).\n\n## Unit tests\n\nTests are defined in the `hello-world/tests` folder in this project. Use NPM to install the [Mocha test framework](https://mochajs.org/) and run unit tests from your local machine.\n\n```bash\nllrt-sam-oci$ cd hello-world\nhello-world$ npm install\nhello-world$ npm run test\n```\n\n## Cleanup\n\nTo delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following:\n\n```bash\nsam delete --stack-name llrt-sam-oci\n```\n\n## Resources\n\nSee the [AWS SAM developer guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) for an introduction to SAM specification, the SAM CLI, and serverless application concepts.\n\nNext, you can use AWS Serverless Application Repository to deploy ready to use Apps that go beyond hello world samples and learn how authors developed their applications: [AWS Serverless Application Repository main page](https://aws.amazon.com/serverless/serverlessrepo/)\n"
  },
  {
    "path": "example/llrt-sam-container-image/events/event.json",
    "content": "{\n  \"body\": \"{\\\"message\\\": \\\"hello world\\\"}\",\n  \"resource\": \"/{proxy+}\",\n  \"path\": \"/path/to/resource\",\n  \"httpMethod\": \"POST\",\n  \"isBase64Encoded\": false,\n  \"queryStringParameters\": {\n    \"foo\": \"bar\"\n  },\n  \"pathParameters\": {\n    \"proxy\": \"/path/to/resource\"\n  },\n  \"stageVariables\": {\n    \"baz\": \"qux\"\n  },\n  \"headers\": {\n    \"Accept\": \"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\",\n    \"Accept-Encoding\": \"gzip, deflate, sdch\",\n    \"Accept-Language\": \"en-US,en;q=0.8\",\n    \"Cache-Control\": \"max-age=0\",\n    \"CloudFront-Forwarded-Proto\": \"https\",\n    \"CloudFront-Is-Desktop-Viewer\": \"true\",\n    \"CloudFront-Is-Mobile-Viewer\": \"false\",\n    \"CloudFront-Is-SmartTV-Viewer\": \"false\",\n    \"CloudFront-Is-Tablet-Viewer\": \"false\",\n    \"CloudFront-Viewer-Country\": \"US\",\n    \"Host\": \"1234567890.execute-api.us-east-1.amazonaws.com\",\n    \"Upgrade-Insecure-Requests\": \"1\",\n    \"User-Agent\": \"Custom User Agent String\",\n    \"Via\": \"1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)\",\n    \"X-Amz-Cf-Id\": \"cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==\",\n    \"X-Forwarded-For\": \"127.0.0.1, 127.0.0.2\",\n    \"X-Forwarded-Port\": \"443\",\n    \"X-Forwarded-Proto\": \"https\"\n  },\n  \"requestContext\": {\n    \"accountId\": \"123456789012\",\n    \"resourceId\": \"123456\",\n    \"stage\": \"prod\",\n    \"requestId\": \"c6af9ac6-7b61-11e6-9a41-93e8deadbeef\",\n    \"requestTime\": \"09/Apr/2015:12:34:56 +0000\",\n    \"requestTimeEpoch\": 1428582896000,\n    \"identity\": {\n      \"cognitoIdentityPoolId\": null,\n      \"accountId\": null,\n      \"cognitoIdentityId\": null,\n      \"caller\": null,\n      \"accessKey\": null,\n      \"sourceIp\": \"127.0.0.1\",\n      \"cognitoAuthenticationType\": null,\n      \"cognitoAuthenticationProvider\": null,\n      \"userArn\": null,\n      \"userAgent\": \"Custom User Agent String\",\n      \"user\": null\n    },\n    \"path\": \"/prod/path/to/resource\",\n    \"resourcePath\": \"/{proxy+}\",\n    \"httpMethod\": \"POST\",\n    \"apiId\": \"1234567890\",\n    \"protocol\": \"HTTP/1.1\"\n  }\n}\n"
  },
  {
    "path": "example/llrt-sam-container-image/hello-world/Dockerfile",
    "content": "FROM --platform=arm64 busybox\nWORKDIR /var/task/\nCOPY app.mjs ./\nADD https://github.com/awslabs/llrt/releases/latest/download/llrt-container-arm64 /usr/bin/llrt\nRUN chmod +x /usr/bin/llrt\n\nENV LAMBDA_HANDLER \"app.handler\"\n\nCMD [ \"llrt\" ]\n"
  },
  {
    "path": "example/llrt-sam-container-image/hello-world/app.mjs",
    "content": "/**\n *\n * Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format\n * @param {Object} event - API Gateway Lambda Proxy Input Format\n *\n * Context doc: https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html\n * @param {Object} context\n *\n * Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html\n * @returns {Object} object - API Gateway Lambda Proxy Output Format\n *\n */\n\nexport const handler = async (event, context) => {\n  const response = {\n    statusCode: 200,\n    body: JSON.stringify({\n      message: \"hello world\",\n    }),\n  };\n\n  return response;\n};\n"
  },
  {
    "path": "example/llrt-sam-container-image/samconfig.toml",
    "content": "# More information about the configuration file can be found here:\n# https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html\nversion = 0.1\n\n[default]\n[default.global.parameters]\nstack_name = \"llrt-sam-oci\"\n\n[default.build.parameters]\nparallel = true\n\n[default.validate.parameters]\nlint = true\n\n[default.deploy.parameters]\ncapabilities = \"CAPABILITY_IAM\"\nconfirm_changeset = true\nresolve_s3 = true\nresolve_image_repos = true\n\n[default.package.parameters]\nresolve_s3 = true\n\n[default.sync.parameters]\nwatch = true\n\n[default.local_start_api.parameters]\nwarm_containers = \"EAGER\"\n\n[default.local_start_lambda.parameters]\nwarm_containers = \"EAGER\"\n"
  },
  {
    "path": "example/llrt-sam-container-image/template.yaml",
    "content": "AWSTemplateFormatVersion: \"2010-09-09\"\nTransform: AWS::Serverless-2016-10-31\nDescription: >\n  llrt-sam-oci\n\n  Sample SAM Template for llrt-sam-oci\n\n# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst\nGlobals:\n  Function:\n    Timeout: 3\n\nResources:\n  HelloWorldFunction:\n    Type: AWS::Serverless::Function\n    Properties:\n      PackageType: Image\n      Architectures:\n        - arm64\n      Events:\n        HelloWorld:\n          Type: Api\n          Properties:\n            Path: /hello\n            Method: get\n    Metadata:\n      DockerTag: llrt\n      DockerContext: ./hello-world\n      Dockerfile: Dockerfile\n\nOutputs:\n  # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function\n  # Find out more about other implicit resources you can reference within SAM\n  # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api\n  HelloWorldApi:\n    Description: \"API Gateway endpoint URL for Prod stage for Hello World function\"\n    Value: !Sub \"https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/\"\n  HelloWorldFunction:\n    Description: \"Hello World Lambda Function ARN\"\n    Value: !GetAtt HelloWorldFunction.Arn\n  HelloWorldFunctionIamRole:\n    Description: \"Implicit IAM Role created for Hello World function\"\n    Value: !GetAtt HelloWorldFunctionRole.Arn\n"
  },
  {
    "path": "example/register-hooks/hooks/calc.js",
    "content": "import { registerHooks } from \"node:module\";\n\nregisterHooks({\n  resolve(specifier, context, nextResolve) {\n    if (specifier === \"calc\") {\n      return {\n        url: \"calc\",\n        shortCircuit: true,\n      };\n    }\n    return nextResolve(specifier, context);\n  },\n  load(url, context, nextLoad) {\n    if (url === \"calc\") {\n      const code = `\n        export function add(p1, p2) {\n          return p1 + p2;\n        }\n      `;\n\n      return { format: \"module\", shortCircuit: true, source: code };\n    }\n    return nextLoad(url, context);\n  },\n});\n"
  },
  {
    "path": "example/register-hooks/hooks/fs.js",
    "content": "import { registerHooks } from \"node:module\";\n\nregisterHooks({\n  resolve(specifier, context, nextResolve) {\n    if (specifier === \"fs\") {\n      return {\n        url: \"llrt-polyfill:fs\",\n        shortCircuit: true,\n      };\n    } else if (specifier.startsWith(\"internal:\")) {\n      specifier = specifier.replace(\"internal:\", \"\");\n    }\n    return nextResolve(specifier, context);\n  },\n  load(url, context, nextLoad) {\n    if (url === \"llrt-polyfill:fs\") {\n      const code = `\n        export * from \"internal:fs\";\n        import fs from \"internal:fs\";\n        export function existsSync(path) {\n          try {\n            fs.accessSync(path);\n            return true;\n          } catch {\n            return false;\n          }\n        }\n      `;\n\n      return { format: \"module\", shortCircuit: true, source: code };\n    }\n    return nextLoad(url, context);\n  },\n});\n"
  },
  {
    "path": "example/register-hooks/hooks/http.js",
    "content": "import { registerHooks } from \"node:module\";\nimport { readFileSync } from \"node:fs\";\n\nregisterHooks({\n  resolve(specifier, context, nextResolve) {\n    if (specifier === \"http\") {\n      return {\n        url: \"http\",\n        shortCircuit: true,\n      };\n    }\n    return nextResolve(specifier, context);\n  },\n  load(url, context, nextLoad) {\n    if (url === \"http\") {\n      const code = readFileSync(\"./src/http.js\");\n\n      return { format: \"module\", shortCircuit: true, source: code };\n    }\n    return nextLoad(url, context);\n  },\n});\n"
  },
  {
    "path": "example/register-hooks/hooks/v8.js",
    "content": "import { registerHooks } from \"node:module\";\n\nregisterHooks({\n  resolve(specifier, context, nextResolve) {\n    if (specifier === \"v8\") {\n      return {\n        url: \"v8\",\n        shortCircuit: true,\n      };\n    }\n    return nextResolve(specifier, context);\n  },\n  load(url, context, nextLoad) {\n    if (url === \"v8\") {\n      const code = `\n        import { ComputeMemoryUsage } from \"llrt:qjs\";\n\n        export function getHeapStatistics() {\n          const usage = ComputeMemoryUsage();\n\n          return {\n            total_heap_size: usage.memory_used_size,\n            total_heap_size_executable: 0,\n            total_physical_size: 0,\n            total_available_size: 0,\n            used_heap_size: usage.memory_used_size,\n            heap_size_limit: usage.malloc_limit,\n            malloced_memory: usage.malloc_size,\n            peak_malloced_memory: 0,\n            does_zap_garbage: 0,\n            number_of_native_contexts: 0,\n            number_of_detached_contexts: 0,\n            total_global_handles_size: 0,\n            used_global_handles_size: 0,\n            external_memory: 0,\n          };\n        }\n      `;\n\n      return { format: \"module\", shortCircuit: true, source: code };\n    }\n    return nextLoad(url, context);\n  },\n});\n"
  },
  {
    "path": "example/register-hooks/simple-server.js",
    "content": "import { createServer } from \"node:http\";\n\nconst server = createServer((req, res) => {\n  res.writeHead(200, { \"Content-Type\": \"text/plain\" });\n  res.end(\"Hello Compatible Server\");\n});\n\nserver.listen(3000, () => {\n  console.log(\"Server running at http://localhost:3000/\");\n});\n"
  },
  {
    "path": "example/register-hooks/simple-server.sh",
    "content": "llrt --import ./hooks/http.js simple-server.js\n"
  },
  {
    "path": "example/register-hooks/src/http.js",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nimport { createServer as createTcpServer } from \"node:net\";\n\n/**\n * Minimal Node.js-like HTTP server implementation using net.\n * @param {(req: IncomingMessage, res: ServerResponse) => void} listener\n * @returns {import('net').Server}\n *\n * @example\n * import { createServer } from 'node:http';\n *\n * const server = createServer((req, res) => {\n *   console.log(`${req.method} ${req.url}`);\n *   res.writeHead(200, { 'Content-Type': 'text/plain' });\n *   res.end('Hello Compatible Server');\n * });\n *\n * server.listen(3000, () => {\n *   console.log('Server running at http://localhost:3000/');\n * });\n *\n * // Output when you curl:\n * // $ curl http://localhost:3000/\n * // Hello Compatible Server\n *\n *\n * Performance Report:\n *\n * <LLRT>\n * % bombardier -d 10s --fasthttp http://localhost:3000/\n *\n * Bombarding http://localhost:3000/ for 10s using 125 connection(s)\n * [==================================================================================================================] 10s\n * Done!\n * Statistics        Avg      Stdev        Max\n *   Reqs/sec     25352.15    4168.30   32571.72\n *   Latency        5.07ms     7.13ms   207.36ms\n *   HTTP codes:\n *     1xx - 0, 2xx - 246255, 3xx - 0, 4xx - 0, 5xx - 0\n *     others - 0\n *   Throughput:     3.05MB/s\n *\n * <Node.js>\n * % bombardier -d 10s --fasthttp http://localhost:3000/\n *\n * Bombarding http://localhost:3000/ for 10s using 125 connection(s)\n * [==================================================================================================================] 10s\n * Done!\n * Statistics        Avg      Stdev        Max\n *   Reqs/sec     52177.00    8933.48   62591.34\n *   Latency        2.39ms     2.49ms   263.05ms\n *   HTTP codes:\n *     1xx - 0, 2xx - 521884, 3xx - 0, 4xx - 0, 5xx - 0\n *     others - 0\n *   Throughput:    12.59MB/s\n */\nexport function createServer(listener) {\n  return createTcpServer((socket) => {\n    socket.on(\"error\", (error) => {\n      console.error(\"Socket error:\", error);\n      socket.end();\n    });\n\n    socket.on(\"data\", async (data) => {\n      try {\n        const requestString = data.toString();\n        const [headerPart, bodyPart = \"\"] = requestString.split(\"\\r\\n\\r\\n\");\n        const lines = headerPart.split(\"\\r\\n\");\n        const [method, path, protocol] = lines[0].split(\" \");\n\n        const headers = {};\n        lines.slice(1).forEach((line) => {\n          if (line) {\n            const [key, ...valueParts] = line.split(\": \");\n            headers[key.toLowerCase()] = valueParts.join(\": \");\n          }\n        });\n\n        // --- Simplified IncomingMessage object ---\n        const req = {\n          method,\n          url: path,\n          headers,\n          httpVersion: protocol.replace(\"HTTP/\", \"\"),\n          socket,\n          body: bodyPart,\n        };\n\n        // --- Simplified ServerResponse object ---\n        let headersSent = false;\n        const resHeaders = {};\n        const res = {\n          statusCode: 200,\n          statusMessage: \"OK\",\n          setHeader(name, value) {\n            resHeaders[name] = value;\n          },\n          getHeader(name) {\n            return resHeaders[name];\n          },\n          writeHead(statusCode, statusMessageOrHeaders, maybeHeaders) {\n            if (headersSent) return;\n            if (typeof statusMessageOrHeaders === \"string\") {\n              this.statusCode = statusCode;\n              this.statusMessage = statusMessageOrHeaders;\n              Object.assign(resHeaders, maybeHeaders || {});\n            } else {\n              this.statusCode = statusCode;\n              this.statusMessage = \"OK\";\n              Object.assign(resHeaders, statusMessageOrHeaders || {});\n            }\n            const headerLines = Object.entries(resHeaders)\n              .map(([k, v]) => `${k}: ${v}`)\n              .join(\"\\r\\n\");\n            socket.write(\n              `HTTP/1.1 ${this.statusCode} ${this.statusMessage}\\r\\n${headerLines}\\r\\n\\r\\n`\n            );\n            headersSent = true;\n          },\n          write(chunk) {\n            if (!headersSent) {\n              this.writeHead(this.statusCode);\n            }\n            socket.write(chunk);\n          },\n          end(chunk) {\n            if (chunk) this.write(chunk);\n            socket.end();\n          },\n        };\n\n        // Call the user-defined listener\n        listener(req, res);\n      } catch (error) {\n        console.error(\"Error handling request:\", error);\n        socket.write(\"HTTP/1.1 500 Internal Server Error\\r\\n\\r\\n\");\n        socket.end();\n      }\n    });\n  });\n}\n\nexport default { createServer };\n"
  },
  {
    "path": "example/register-hooks/test.js",
    "content": "import { existsSync } from \"node:fs\";\nconsole.log(existsSync(\"./test.js\"));\n\nimport { add } from \"calc\";\nconsole.log(add(1, 2));\n\nimport { getHeapStatistics } from \"node:v8\";\nconsole.log(getHeapStatistics());\n"
  },
  {
    "path": "example/register-hooks/test.sh",
    "content": "llrt --import ./hooks/fs.js --import ./hooks/calc.js --import ./hooks/v8.js test.js\n"
  },
  {
    "path": "fixtures/a.js",
    "content": "const a = {};\nexport default a;\nrequire(\"./b.js\");\na.done = true;\n"
  },
  {
    "path": "fixtures/b.js",
    "content": "const b = {};\nexport default b;\nrequire(\"./a.js\");\nb.done = true;\n"
  },
  {
    "path": "fixtures/c.cjs",
    "content": "const d = require(\"./d.cjs\");\nmodule.exports = \"c\";\n"
  },
  {
    "path": "fixtures/cjs-handler.cjs",
    "content": "const a = require(\"./import.cjs\");\n\nexports.handler = async () => {\n  return {\n    statusCode: 200,\n    body: \"OK\",\n  };\n};\n"
  },
  {
    "path": "fixtures/d.cjs",
    "content": "const c = require(\"./d.cjs\");\nmodule.exports = \"d\";\n"
  },
  {
    "path": "fixtures/define-property-export.cjs",
    "content": "Object.defineProperty(exports, \"__esModule\", {\n  value: true,\n});\n"
  },
  {
    "path": "fixtures/empty.js",
    "content": ""
  },
  {
    "path": "fixtures/export-function.cjs",
    "content": "module.exports = function exportedFunction() {\n  return \"hello world!\";\n};\n"
  },
  {
    "path": "fixtures/fs/readdir/readdir.js",
    "content": "import fs from \"node:fs/promises\";\n\nfs.readdir(\"./\", { recursive: true }).then((res) => {});\n"
  },
  {
    "path": "fixtures/fs/readdir/recursive/readdir.js",
    "content": "import fs from \"node:fs/promises\";\n\nfs.readdir(\"./\", { recursive: true }).then((res) => {});\n"
  },
  {
    "path": "fixtures/handler.mjs",
    "content": "//test top level await\nawait new Promise((res) => setTimeout(res, 0));\nawait import(\"./hello.js\");\n\nexport const handler = async () => ({\n  statusCode: 200,\n  body: \"Hello world!\",\n});\n"
  },
  {
    "path": "fixtures/hello.js",
    "content": "export const hello = \"hello world!\";\nconsole.log(hello);\n"
  },
  {
    "path": "fixtures/hello.txt",
    "content": "hello world!"
  },
  {
    "path": "fixtures/import.cjs",
    "content": "const c = require(\"./c.cjs\");\nmodule.exports = {\n  c,\n};\n"
  },
  {
    "path": "fixtures/import.js",
    "content": "const a = require(\"a.js\");\nexport default a;\n"
  },
  {
    "path": "fixtures/local.mjs",
    "content": "import { DynamoDBClient } from \"@aws-sdk/client-dynamodb\";\nimport { DynamoDBDocumentClient, PutCommand } from \"@aws-sdk/lib-dynamodb\";\nimport { PutObjectCommand, S3Client } from \"@aws-sdk/client-s3\";\n\nimport { randomBytes } from \"node:crypto\";\n\nconst uid = () =>\n  String.fromCharCode(\n    ...randomBytes(10).map((d) => {\n      return (d > 127 ? 97 : 65) + (d % 25);\n    })\n  );\n\nconst clientCfg = {\n  endpoint: \"http://localhost:8080/service/\",\n};\n\nconst client = new DynamoDBClient(clientCfg);\nconst docClient = DynamoDBDocumentClient.from(client);\nconst s3Client = new S3Client(clientCfg);\n\nexport const handler = async (event) => {\n  const start = Date.now();\n\n  let id = uid();\n  let data = JSON.stringify(event);\n\n  await Promise.all([\n    docClient.send(\n      new PutCommand({\n        TableName: process.env.TABLE_NAME,\n        Item: {\n          id,\n          content: data,\n        },\n      })\n    ),\n    s3Client.send(\n      new PutObjectCommand({\n        Body: data,\n        Bucket: process.env.BUCKET_NAME,\n        Key: id,\n      })\n    ),\n  ]);\n\n  const end = Date.now();\n  const time = `Duration: ${end - start}ms`;\n  console.log(time);\n  return {\n    statusCode: 200,\n    body: time,\n  };\n};\n"
  },
  {
    "path": "fixtures/node_modules/elem-aws-lambda-powertools/commons/lib/cjs/index.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.isNull = void 0;\nvar typeUtils_js_1 = require(\"./typeUtils.js\");\nexports.isNull = typeUtils_js_1.isNull;\n"
  },
  {
    "path": "fixtures/node_modules/elem-aws-lambda-powertools/commons/lib/cjs/typeUtils.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.isNull = void 0;\nconst isNull = (value) => {\n    return Object.is(value, null);\n};\nexports.isNull = isNull;\n"
  },
  {
    "path": "fixtures/node_modules/elem-aws-lambda-powertools/commons/lib/esm/index.js",
    "content": "export { isNull } from './typeUtils.js';\n"
  },
  {
    "path": "fixtures/node_modules/elem-aws-lambda-powertools/commons/lib/esm/typeUtils.js",
    "content": "const isNull = (value) => {\n    return Object.is(value, null);\n};\nexport { isNull };\n"
  },
  {
    "path": "fixtures/node_modules/elem-aws-lambda-powertools/commons/package.json",
    "content": "{\n  \"name\": \"elem-aws-lambda-powertools/commons\",\n  \"main\": \"./lib/cjs/index.js\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"require\": {\n        \"default\": \"./lib/cjs/index.js\"\n      },\n      \"import\": {\n        \"default\": \"./lib/esm/index.js\"\n      }\n    },\n    \"./typeutils\": {\n      \"import\": \"./lib/esm/typeUtils.js\",\n      \"require\": \"./lib/cjs/typeUtils.js\"\n    }\n  }\n}"
  },
  {
    "path": "fixtures/node_modules/elem-aws-lambda-powertools/jmespath/lib/cjs/index.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.isNull = void 0;\nconst typeutils_1 = require(\"elem-aws-lambda-powertools/commons/typeutils\");\nexports.isNull = typeutils_1.isNull;\n"
  },
  {
    "path": "fixtures/node_modules/elem-aws-lambda-powertools/jmespath/lib/esm/index.js",
    "content": "export { isNull } from 'elem-aws-lambda-powertools/commons/typeutils';\n"
  },
  {
    "path": "fixtures/node_modules/elem-aws-lambda-powertools/jmespath/package.json",
    "content": "{\n  \"name\": \"elem-aws-lambda-powertools/jmespath\",\n  \"main\": \"./lib/cjs/index.js\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"require\": {\n        \"default\": \"./lib/cjs/index.js\"\n      },\n      \"import\": {\n        \"default\": \"./lib/esm/index.js\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "fixtures/node_modules/elem-debug/package.json",
    "content": "{\n    \"name\": \"elem-debug\",\n    \"main\": \"./src/index.js\",\n    \"browser\": \"./src/browser.js\"\n}"
  },
  {
    "path": "fixtures/node_modules/elem-debug/src/browser.js",
    "content": "exports = module.exports;\n\nexports.str = \"cat\";\nexports.cat = function cat() {\n    return exports.str;\n}\n\nexports.array = [];\nexports.length = function length() {\n    return exports.array.length;\n}\n"
  },
  {
    "path": "fixtures/node_modules/elem-hono/dist/cjs/utils/url.js",
    "content": "exports = module.exports;\n\nexports.str = \"foo\";\nexports.url = function url() {\n    return exports.str;\n}\n"
  },
  {
    "path": "fixtures/node_modules/elem-hono/dist/index.js",
    "content": "exports = module.exports;\n\nexports.str = \"bar\";\nexports.url = function url() {\n    return exports.str;\n}\n"
  },
  {
    "path": "fixtures/node_modules/elem-hono/package.json",
    "content": "{\n    \"module\": \"dist/index.js\",\n    \"exports\": {\n        \"./utils/*\": {\n            \"types\": \"./dist/types/utils/*.d.ts\",\n            \"import\": \"./dist/utils/*.js\",\n            \"require\": \"./dist/cjs/utils/*.js\"\n        }\n    }\n}"
  },
  {
    "path": "fixtures/node_modules/elem-lodash.merge/index.js",
    "content": "var merge = function test(value) {\n    return value;\n}\n\nmodule.exports = merge;\n"
  },
  {
    "path": "fixtures/node_modules/elem-lodash.merge/package.json",
    "content": "{\n    \"name\": \"elem-lodash.merge\"\n}"
  },
  {
    "path": "fixtures/node_modules/elem-react-dom/cjs/react-dom-server.edge.development.js",
    "content": "\"use strict\";\n\n(function () {\n    var ReactDOM = require(\"elem-react-dom\");\n    exports.name = \"react-dom/server.edge\";\n})();\n"
  },
  {
    "path": "fixtures/node_modules/elem-react-dom/cjs/react-dom.development.js",
    "content": "\"use strict\";\n\n(function () {\n    exports.name = \"react-dom\";\n})();"
  },
  {
    "path": "fixtures/node_modules/elem-react-dom/index.js",
    "content": "'use strict';\n\nmodule.exports = require('./cjs/react-dom.development.js');\n"
  },
  {
    "path": "fixtures/node_modules/elem-react-dom/package.json",
    "content": "{\n    \"name\": \"elem-react-dom\",\n    \"main\": \"index.js\",\n    \"exports\": {\n        \".\": {\n            \"default\": \"./index.js\"\n        },\n        \"./server.edge\": {\n            \"default\": \"./server.edge.js\"\n        }\n    }\n}"
  },
  {
    "path": "fixtures/node_modules/elem-react-dom/server.edge.js",
    "content": "'use strict';\n\nmodule.exports = require('./cjs/react-dom-server.edge.development.js');\n"
  },
  {
    "path": "fixtures/node_modules/elem-uuid/dist/commonjs-browser/index.js",
    "content": "Object.defineProperty(exports, \"__esModule\", {\n    value: true\n});\n\nexports.default = require1;\n\nfunction require1(hello) {\n    function helloWorld(world) {\n        return hello + \", \" + world;\n    }\n    return helloWorld;\n}"
  },
  {
    "path": "fixtures/node_modules/elem-uuid/package.json",
    "content": "{\n    \"name\": \"elem-uuid\",\n    \"main\": \"./dist/index.js\",\n    \"exports\": {\n        \".\": {\n            \"browser\": {\n                \"import\": \"./dist/esm-browser/index.js\",\n                \"require\": \"./dist/commonjs-browser/index.js\"\n            },\n            \"default\": \"./dist/esm-browser/index.js\"\n        }\n    },\n    \"module\": \"./dist/esm-node/index.js\"\n}"
  },
  {
    "path": "fixtures/package.json",
    "content": "{\n  \"private\": true\n}\n"
  },
  {
    "path": "fixtures/primitive-handler.mjs",
    "content": "export const handler = () => {\n  return \"hello\";\n};\n"
  },
  {
    "path": "fixtures/prop-export.cjs",
    "content": "module.exports.prop = \"a\";\n"
  },
  {
    "path": "fixtures/referenced-exports.cjs",
    "content": "exports = module.exports;\n\nexports.str = \"str\";\nexports.cat = function cat() {\n  return exports.str;\n};\n\nexports.array = [1];\nexports.length = function length() {\n  return exports.array.length;\n};\n\nconst fn = require(\"./export-function.cjs\");\n"
  },
  {
    "path": "fixtures/require.mjs",
    "content": "async function main() {\n  console.log(1);\n  await new Promise((res) => setTimeout(res, 5));\n  console.log(2);\n\n  setTimeout(() => {\n    console.log(3);\n    setTimeout(async () => {\n      console.log(4);\n      await new Promise((res) => setTimeout(res, 5));\n      console.log(5);\n\n      require(\"./handler.mjs\");\n\n      console.log(6);\n    }, 5);\n  }, 5);\n}\n\nmain();\n"
  },
  {
    "path": "fixtures/sdk-handler.mjs",
    "content": "import \"./sdk-runtime-init.mjs\";\n\n//to simulate some async initialization work\nawait new Promise((r) => setTimeout(r, 100));\n\nexport const handler = async () => {\n  return {\n    statusCode: 200,\n    body: \"Hello from sdk handler\",\n  };\n};\n"
  },
  {
    "path": "fixtures/sdk-runtime-init.mjs",
    "content": "//dummy file for simulating SDK connection warmup in tests\n"
  },
  {
    "path": "fixtures/test1245/index.js",
    "content": "export function bar() {\n  return \"bar\";\n}\n"
  },
  {
    "path": "fixtures/test1245/main/foo.js",
    "content": "const { bar } = require(\"..\");\nconsole.log(bar());\n"
  },
  {
    "path": "fixtures/test1245/package.json",
    "content": "{\n  \"main\": \"./index.js\"\n}\n"
  },
  {
    "path": "fixtures/test903/bar.mjs",
    "content": "export function bar() {\n  return \"bar\";\n}\n"
  },
  {
    "path": "fixtures/test903/foo.mjs",
    "content": "import { bar } from \"../bar.mjs\";\nconsole.log(bar());\n"
  },
  {
    "path": "fixtures/test_modules/test-aws-lambda-powertools-jmespath.js",
    "content": "const assert = require(\"assert\");\n\nimport * as jmespath1 from \"elem-aws-lambda-powertools/jmespath\";\nassert.ok(typeof jmespath1.isNull === \"function\");\n\nconst jmespath2 = require(\"elem-aws-lambda-powertools/jmespath\");\nassert.ok(typeof jmespath2.isNull === \"function\");\n"
  },
  {
    "path": "fixtures/test_modules/test-debug.js",
    "content": "const assert = require(\"assert\");\n\nconst debug = require(\"elem-debug\");\n\nassert.ok(debug.cat() == \"cat\");\nassert.ok(debug.length() == 0);\n"
  },
  {
    "path": "fixtures/test_modules/test-elem-hono.js",
    "content": "const assert = require(\"assert\");\n\nconst utils = require(\"elem-hono/utils/url\");\n\nassert.ok(utils.url() === \"foo\");\n"
  },
  {
    "path": "fixtures/test_modules/test-lodash.merge.js",
    "content": "const assert = require(\"assert\");\n\nimport merge1 from \"elem-lodash.merge\";\nassert.ok(typeof merge1 === \"function\");\n\nconst merge2 = require(\"elem-lodash.merge\");\nassert.ok(typeof merge2 === \"function\");\n"
  },
  {
    "path": "fixtures/test_modules/test-react-dom.js",
    "content": "const assert = require(\"assert\");\n\nimport * as dom1 from \"elem-react-dom/server.edge\";\nassert.ok(dom1.name == \"react-dom/server.edge\");\n\nconst dom2 = require(\"elem-react-dom/server.edge\");\nassert.ok(dom2.name == \"react-dom/server.edge\");\n"
  },
  {
    "path": "fixtures/test_modules/test-uuid.js",
    "content": "const assert = require(\"assert\");\n\nvar fn = _interopRequireDefault(require(\"elem-uuid\"));\nfunction _interopRequireDefault(e) {\n  return e && e.__esModule ? e : { default: e };\n}\nvar greeting = (0, fn.default)(\"hello\");\n\nassert.ok(greeting(\"world\") == \"hello, world\");\n"
  },
  {
    "path": "fixtures/throw.js",
    "content": "throw 42;\n"
  },
  {
    "path": "fixtures/throwing-handler.mjs",
    "content": "export const handler = async () => {\n  throw new Error(\"kaboom\");\n};\n"
  },
  {
    "path": "fixtures/throwing-init-handler.mjs",
    "content": "throw new Error(\"kaboom\");\n\nexport const handler = async () => {};\n"
  },
  {
    "path": "fixtures/tla-webcall-handler.mjs",
    "content": "await fetch(__MOCK_ENDPOINT);\n\nexport const handler = async () => {\n  return {\n    statusCode: 200,\n    body: \"OK\",\n  };\n};\n"
  },
  {
    "path": "index.mjs",
    "content": "import { DynamoDBClient } from \"@aws-sdk/client-dynamodb\";\nimport { DynamoDBDocumentClient, PutCommand } from \"@aws-sdk/lib-dynamodb\";\n\nconst client = new DynamoDBClient({});\nconst docClient = DynamoDBDocumentClient.from(client);\n\nexport const handler = async (event) => {\n  await docClient.send(\n    new PutCommand({\n      TableName: process.env.TABLE_NAME,\n      Item: {\n        id: Math.random().toString(36).substring(2),\n        content: JSON.stringify(event),\n      },\n    })\n  );\n  return {\n    statusCode: 200,\n    body: \"OK\",\n  };\n};\n"
  },
  {
    "path": "lambda-server.js",
    "content": "import pureHttp from \"pure-http\";\nimport fs from \"node:fs\";\n\nconst PORT = 3000;\nconst BASE_PATH = \"/2018-06-01/runtime\";\nconst ARGS = process.argv.slice(2);\n\nlet httpMode = false;\nlet eventJson = null;\n\nlet argIndex = 0;\nfor (let arg of ARGS) {\n  if (arg == \"-h\" || arg == \"--http\") {\n    httpMode = true;\n  }\n\n  if (arg == \"-e\" || arg == \"--event\") {\n    eventJson = JSON.parse(fs.readFileSync(ARGS[argIndex + 1]).toString());\n  }\n  argIndex++;\n}\n\nconst app = pureHttp();\n\nconst pendingRequests = [];\nconst requests = {};\nlet invocationWaiter = null;\n\napp.use(async (req, res, next) => {\n  const body = await new Promise((resolve, reject) => {\n    let buffer = \"\";\n    req\n      .on(\"data\", (chunk) => {\n        buffer += chunk;\n      })\n      .on(\"end\", () => {\n        resolve(buffer);\n      })\n      .on(\"error\", reject);\n  });\n  if (body) {\n    req.body = body || undefined;\n  }\n  return next();\n});\n\napp.use((req, res, next) => {\n  const date = new Date();\n  const hours = date.getHours();\n  const minutes = date.getMinutes();\n  const seconds = date.getSeconds();\n  const milliseconds = date.getMilliseconds();\n  console.log(\n    `${hours}:${minutes}:${seconds}:${milliseconds} - ${req.method}: ${req.path}`\n  );\n  try {\n    return next();\n  } catch (error) {\n    res.json({ error });\n  }\n});\n\napp.use((req, res, next) => {\n  res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n  res.setHeader(\"Access-Control-Allow-Headers\", \"*\");\n  res.setHeader(\"Access-Control-Allow-Methods\", \"*\");\n  if (req.method === \"OPTIONS\") {\n    return res.send(\"\");\n  }\n  next();\n});\n\napp.get(`${BASE_PATH}/invocation/next`, async (req, res) => {\n  res.header(\"lambda-runtime-deadline-ms\", Date.now() + 1000 * 60);\n  if (httpMode) {\n    if (pendingRequests.length == 0) {\n      await new Promise((resolve) => {\n        invocationWaiter = resolve;\n      });\n    }\n    let { id, event } = pendingRequests.shift();\n\n    res.header(\"lambda-runtime-aws-request-id\", id);\n    res.json(event);\n  } else {\n    res.header(\"lambda-runtime-aws-request-id\", \"1234\");\n\n    res.json(\n      eventJson || {\n        key1: \"value1\",\n        key2: \"value2\",\n        key3: \"value3\",\n      }\n    );\n  }\n});\n\napp.post(`${BASE_PATH}/init/error`, (req, res) => {\n  if (httpMode) {\n    for (const request of pendingRequests) {\n      request.reject({\n        statusCode: 500,\n        body: req.body,\n        headers: { \"content-type\": \"application/json\" },\n      });\n    }\n  }\n\n  res.status(202);\n  res.send();\n});\n\napp.post(`${BASE_PATH}/invocation/:id/response`, (req, res) => {\n  if (httpMode) {\n    const { id } = req.params;\n\n    const { resolve } = requests[id];\n    delete requests[id];\n\n    resolve(req.body);\n  } else {\n    console.log(req.body);\n  }\n\n  res.status(202);\n  res.send();\n});\n\napp.post(`${BASE_PATH}/invocation/:id/error`, (req, res) => {\n  if (httpMode) {\n    const { id } = req.params;\n\n    const { reject } = requests[id];\n    delete requests[id];\n\n    reject({\n      body: req.body,\n      statusCode: 500,\n      headers: { \"content-type\": \"application/json\" },\n    });\n  } else {\n    console.error(req.body);\n  }\n\n  res.status(202);\n  res.send();\n});\n\napp.all(\"*\", async (req, res) => {\n  if (!httpMode) {\n    res.status(400);\n    res.send(\"Server is not in HTTP mode. Start with -h flag\");\n    return;\n  }\n\n  const requestUrl = new URL(`http://localhost:0000${req.url}`);\n\n  const rawQueryString = requestUrl.search?.substring(1);\n\n  const requestId = Math.random().toString(36).substring(2);\n\n  const queryStringParameters = Object.fromEntries(\n    requestUrl.searchParams.entries()\n  );\n\n  const event = {\n    version: \"2.0\",\n    routeKey: \"$default\",\n    rawPath: \"/my/path\",\n    rawQueryString,\n    cookies: undefined,\n    headers: Object.entries(req.headers).reduce((acc, [key, value]) => {\n      acc[key] = (value && Array.isArray(value) && value.join(\",\")) || value;\n      return acc;\n    }, {}),\n    queryStringParameters,\n    requestContext: {\n      accountId: \"123456789012\",\n      apiId: \"localhost\",\n      domainName: \"localhost\",\n      domainPrefix: \"localhost\",\n      http: {\n        method: req.method,\n        path: req.path,\n        protocol: req.protocol,\n        sourceIp: \"192.168.1.1\",\n        userAgent: req.header[\"User-Agent\"],\n      },\n      requestId,\n      routeKey: \"$default\",\n      stage: \"$default\",\n      time: new Date().toString(),\n      timeEpoch: new Date().getTime(),\n    },\n    body: req.body,\n    pathParameters: req.params,\n    isBase64Encoded: false,\n  };\n\n  const responsePromise = new Promise((resolve, reject) => {\n    const id = requestId;\n    const request = {\n      event,\n      resolve,\n      reject,\n      id,\n    };\n    pendingRequests.push(request);\n    requests[id] = request;\n  });\n\n  if (invocationWaiter) {\n    invocationWaiter();\n  }\n\n  let result;\n  try {\n    result = await responsePromise;\n  } catch (e) {\n    result = e;\n  }\n\n  try {\n    result = JSON.parse(result);\n  } catch (_) {}\n\n  if (result.body && result.statusCode) {\n    if (result.headers) {\n      for (const key in result.headers) {\n        res.setHeader(key, result.headers[key]);\n      }\n    }\n    res.status(result.statusCode);\n    if (result.isBase64Encoded) {\n      res.send(Buffer.from(result.body, \"base64\"));\n    } else {\n      res.send(result.body);\n    }\n    return;\n  }\n\n  res.send(result);\n});\n\napp.listen(PORT, () => {\n  console.log(`Server started on port ${PORT}`);\n  if (httpMode) {\n    console.log(`- HTTP: http://localhost:${PORT}`);\n  }\n});\n"
  },
  {
    "path": "libs/llrt_build/Cargo.toml",
    "content": "[package]\nname = \"llrt_build\"\ndescription = \"LLRT build helpers\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[lib]\nname = \"llrt_build\"\npath = \"src/lib.rs\"\n\n[dependencies]\nrustc_version = { version = \"0.4\", default-features = false }\n"
  },
  {
    "path": "libs/llrt_build/src/lib.rs",
    "content": "pub fn set_nightly_cfg() {\n    let version_meta = rustc_version::version_meta().unwrap();\n    println!(\"cargo::rustc-check-cfg=cfg(rust_nightly)\");\n    if version_meta.channel == rustc_version::Channel::Nightly {\n        println!(\"cargo:rustc-cfg=rust_nightly\");\n    }\n}\n"
  },
  {
    "path": "libs/llrt_compression/Cargo.toml",
    "content": "[package]\nname = \"llrt_compression\"\ndescription = \"LLRT compression helpers\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[lib]\nname = \"llrt_compression\"\npath = \"src/lib.rs\"\n\n[features]\ndefault = [\"all-c\"]\n\nall-c = [\"brotli-c\", \"flate2-c\", \"zstd-c\"]\nall-rust = [\"brotli-rust\", \"flate2-rust\", \"zstd-rust\"]\n\nbrotli-c = [\"brotlic\"]\nbrotli-rust = [\"brotli\"]\n\nflate2-c = [\"flate2/zlib-ng\"]\nflate2-rust = [\"flate2/rust_backend\"]\n\nzstd-c = [\"zstd\"]\nzstd-rust = [\"zstd\"] # No pure rust implementation exists\n\n[dependencies]\n# Optional\nbrotlic = { version = \"0.8\", default-features = false, optional = true }\nbrotli = { version = \"8\", features = [\n    \"std\",\n], default-features = false, optional = true }\nflate2 = { version = \"1\", default-features = false, optional = true }\nzstd = { version = \"0.13\", default-features = false, optional = true }\n"
  },
  {
    "path": "libs/llrt_compression/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\n#[cfg(any(feature = \"zstd-c\", feature = \"zstd-rust\"))]\npub mod zstd {\n    use std::io::{BufReader, Read, Result};\n\n    use zstd::stream::read::{Decoder as ZstdDecoder, Encoder as ZstdEncoder};\n    pub use zstd::DEFAULT_COMPRESSION_LEVEL;\n\n    pub fn encoder<R: Read>(r: R, level: i32) -> Result<ZstdEncoder<'static, BufReader<R>>> {\n        ZstdEncoder::new(r, level)\n    }\n\n    pub fn decoder<R: Read>(r: R) -> Result<ZstdDecoder<'static, BufReader<R>>> {\n        ZstdDecoder::new(r)\n    }\n}\n\n#[cfg(any(feature = \"flate2-c\", feature = \"flate2-rust\"))]\npub mod deflate {\n    use std::io::Read;\n\n    use flate2::read::{DeflateDecoder, DeflateEncoder};\n    pub use flate2::Compression;\n\n    pub fn encoder<R: Read>(r: R, level: Compression) -> DeflateEncoder<R> {\n        DeflateEncoder::new(r, level)\n    }\n\n    pub fn decoder<R: Read>(r: R) -> DeflateDecoder<R> {\n        DeflateDecoder::new(r)\n    }\n}\n\n#[cfg(any(feature = \"flate2-c\", feature = \"flate2-rust\"))]\npub mod gz {\n    use std::io::Read;\n\n    use flate2::read::{GzDecoder, GzEncoder};\n    pub use flate2::Compression;\n\n    pub fn encoder<R: Read>(r: R, level: Compression) -> GzEncoder<R> {\n        GzEncoder::new(r, level)\n    }\n\n    pub fn decoder<R: Read>(r: R) -> GzDecoder<R> {\n        GzDecoder::new(r)\n    }\n}\n\n#[cfg(any(feature = \"flate2-c\", feature = \"flate2-rust\"))]\npub mod zlib {\n    use std::io::Read;\n\n    use flate2::read::{ZlibDecoder, ZlibEncoder};\n    pub use flate2::Compression;\n\n    pub fn encoder<R: Read>(r: R, level: Compression) -> ZlibEncoder<R> {\n        ZlibEncoder::new(r, level)\n    }\n\n    pub fn decoder<R: Read>(r: R) -> ZlibDecoder<R> {\n        ZlibDecoder::new(r)\n    }\n}\n\n#[cfg(feature = \"brotli-c\")]\npub mod brotli {\n    use std::io::BufRead;\n\n    use brotlic::{CompressorReader as BrotliEncoder, DecompressorReader as BrotliDecoder};\n\n    pub fn encoder<R: BufRead>(r: R) -> BrotliEncoder<R> {\n        BrotliEncoder::new(r)\n    }\n\n    pub fn decoder<R: BufRead>(r: R) -> BrotliDecoder<R> {\n        BrotliDecoder::new(r)\n    }\n}\n\n#[cfg(all(not(feature = \"brotli-c\"), feature = \"brotli-rust\"))]\npub mod brotli {\n    use std::io::Read;\n\n    use brotli::{CompressorReader as BrotliEncoder, Decompressor as BrotliDecoder};\n\n    pub fn encoder<R: Read>(r: R) -> BrotliEncoder<R> {\n        BrotliEncoder::new(r, 8_096, 11, 22)\n    }\n\n    pub fn decoder<R: Read>(r: R) -> BrotliDecoder<R> {\n        BrotliDecoder::new(r, 8_096)\n    }\n}\n"
  },
  {
    "path": "libs/llrt_context/Cargo.toml",
    "content": "[package]\nname = \"llrt_context\"\ndescription = \"LLRT context helpers\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[dependencies]\nrquickjs = { version = \"0.11\", features = [\n    \"futures\",\n], default-features = false }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../llrt_utils\", default-features = false }\ntokio = { version = \"1\", features = [\"sync\"], default-features = false }\ntracing = { version = \"0.1\", default-features = false }\n\n[dev-dependencies]\nllrt_test = { version = \"0.8.1-beta\", path = \"../llrt_test\" }\n\n[build-dependencies]\nllrt_build = { version = \"0.8.1-beta\", path = \"../llrt_build\" }\n"
  },
  {
    "path": "libs/llrt_context/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::future::Future;\nuse std::sync::OnceLock;\n\nuse llrt_utils::primordials::{BasePrimordials, Primordial};\nuse rquickjs::{atom::PredefinedAtom, CatchResultExt, CaughtError, Ctx, Object, Result};\nuse tokio::sync::oneshot::{self, Receiver};\nuse tracing::trace;\n\n#[allow(clippy::type_complexity)]\nstatic ERROR_HANDLER: OnceLock<Box<dyn for<'js> Fn(&Ctx<'js>, CaughtError<'js>) + Sync + Send>> =\n    OnceLock::new();\n\npub trait CtxExtension<'js> {\n    /// Despite naming, this will not necessarily exit the parent process.\n    /// It depends on the handler set by `set_spawn_error_handler`.\n    fn spawn_exit<F, R>(&self, future: F) -> Result<Receiver<R>>\n    where\n        F: Future<Output = Result<R>> + 'js,\n        R: 'js;\n\n    fn spawn_exit_simple<F>(&self, future: F)\n    where\n        F: Future<Output = Result<()>> + 'js;\n}\n\nimpl<'js> CtxExtension<'js> for Ctx<'js> {\n    fn spawn_exit<F, R>(&self, future: F) -> Result<Receiver<R>>\n    where\n        F: Future<Output = Result<R>> + 'js,\n        R: 'js,\n    {\n        let ctx = self.clone();\n\n        let primordials = BasePrimordials::get(self)?;\n        let type_error: Object = primordials.constructor_type_error.construct(())?;\n        let stack: Option<String> = type_error.get(PredefinedAtom::Stack).ok();\n\n        let (join_channel_tx, join_channel_rx) = oneshot::channel();\n\n        self.spawn(async move {\n            match future.await.catch(&ctx) {\n                Ok(res) => {\n                    //result here doesn't matter if receiver has dropped\n                    let _ = join_channel_tx.send(res);\n                },\n                Err(err) => handle_spawn_error(&ctx, err, stack),\n            }\n        });\n        Ok(join_channel_rx)\n    }\n\n    /// Same as above but fire & forget and without a forced stack trace collection\n    fn spawn_exit_simple<F>(&self, future: F)\n    where\n        F: Future<Output = Result<()>> + 'js,\n    {\n        let ctx = self.clone();\n        self.spawn(async move {\n            if let Err(err) = future.await.catch(&ctx) {\n                handle_spawn_error(&ctx, err, None)\n            }\n        });\n    }\n}\n\nfn handle_spawn_error<'js>(ctx: &Ctx<'js>, err: CaughtError<'js>, stack: Option<String>) {\n    let error_handler = if let Some(handler) = ERROR_HANDLER.get() {\n        handler\n    } else {\n        trace!(\"Future error: {:?}\", err);\n        return;\n    };\n    if let CaughtError::Exception(err) = err {\n        if err.stack().is_none() {\n            if let Some(stack) = stack {\n                err.set(PredefinedAtom::Stack, stack).unwrap();\n            }\n        }\n        error_handler(ctx, CaughtError::Exception(err));\n    } else {\n        error_handler(ctx, err);\n    }\n}\n\npub fn set_spawn_error_handler<F>(handler: F)\nwhere\n    F: for<'js> Fn(&Ctx<'js>, CaughtError<'js>) + Sync + Send + 'static,\n{\n    _ = ERROR_HANDLER.set(Box::new(handler));\n}\n"
  },
  {
    "path": "libs/llrt_dns_cache/Cargo.toml",
    "content": "[package]\nname = \"llrt_dns_cache\"\ndescription = \"LLRT dns cache helpers\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\nreadme = \"README.md\"\n\n[lib]\nname = \"llrt_dns_cache\"\npath = \"src/lib.rs\"\n\n[dependencies]\nhyper-util = { version = \"0.1\", features = [\n  \"client\",\n  \"client-legacy\",\n], default-features = false }\nllrt_context = { version = \"0.8.1-beta\", path = \"../llrt_context\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../llrt_utils\", default-features = false }\ntokio = { version = \"1\", features = [\"net\"], default-features = false }\ntower-service = { version = \"0.3\", default-features = false }\nquick_cache = { version = \"0.6\", default-features = false }\n"
  },
  {
    "path": "libs/llrt_dns_cache/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{\n    future::Future,\n    io,\n    net::SocketAddr,\n    pin::Pin,\n    sync::Arc,\n    task::{self, Poll},\n    time::{Duration, Instant},\n    vec,\n};\n\nuse hyper_util::client::legacy::connect::{dns::Name, HttpConnector};\nuse quick_cache::sync::Cache;\nuse tokio::sync::Semaphore;\nuse tower_service::Service;\n\n#[derive(Clone)]\npub struct SocketAddrs {\n    iter: vec::IntoIter<SocketAddr>,\n}\n\nimpl Iterator for SocketAddrs {\n    type Item = SocketAddr;\n    #[inline]\n    fn next(&mut self) -> Option<SocketAddr> {\n        self.iter.next()\n    }\n}\n\n#[derive(Clone)]\nstruct CacheEntry {\n    ttl: Instant,\n    addrs: SocketAddrs,\n}\n\n#[derive(Clone)]\nstruct CacheConcurrencyGuard {\n    semaphore: Arc<Semaphore>,\n    entry: Option<CacheEntry>,\n}\nimpl CacheConcurrencyGuard {\n    fn new(permits: u8) -> Self {\n        Self {\n            semaphore: Arc::new(Semaphore::new(permits as usize)),\n            entry: None,\n        }\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct CachedDnsResolver {\n    cache: Arc<Cache<Name, CacheConcurrencyGuard>>,\n    concurrency: u8,\n    ttl: Duration,\n}\n\nimpl Service<Name> for CachedDnsResolver {\n    type Response = SocketAddrs;\n    type Error = io::Error;\n    type Future = Pin<Box<dyn Future<Output = std::io::Result<Self::Response>> + Send>>;\n\n    fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> Poll<std::io::Result<()>> {\n        Poll::Ready(Ok(()))\n    }\n\n    fn call(&mut self, name: Name) -> Self::Future {\n        let cache = self.cache.clone();\n        let permits = self.concurrency;\n        let ttl = self.ttl;\n\n        Box::pin(async move {\n            let guard = match cache.get_value_or_guard_async(&name).await {\n                Ok(guard) => guard,\n                Err(placeholder) => {\n                    let guard = CacheConcurrencyGuard::new(permits);\n                    _ = placeholder.insert(guard.clone());\n                    guard\n                },\n            };\n            if let Some(entry) = guard.entry {\n                if entry.ttl > Instant::now() {\n                    return Ok(entry.addrs);\n                }\n            };\n\n            let semaphore = guard.semaphore;\n            let semaphore2 = semaphore.clone();\n            let lock = semaphore2.acquire().await.unwrap();\n\n            if let Some(item) = cache.get(&name).and_then(|guard| guard.entry) {\n                return Ok(item.addrs);\n            }\n\n            let addrs = tokio::net::lookup_host((name.as_str(), 0)).await?;\n            let addrs = addrs.collect::<Vec<_>>();\n            let addrs = SocketAddrs {\n                iter: addrs.into_iter(),\n            };\n            let addrs2 = addrs.clone();\n            let entry = CacheEntry {\n                ttl: Instant::now() + ttl,\n                addrs,\n            };\n            cache.insert(\n                name,\n                CacheConcurrencyGuard {\n                    semaphore,\n                    entry: Some(entry),\n                },\n            );\n            drop(lock);\n            Ok(addrs2)\n        })\n    }\n}\n\nimpl Default for CachedDnsResolver {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl CachedDnsResolver {\n    pub fn new() -> Self {\n        Self::with_options(128, 2, 300)\n    }\n\n    pub fn with_options(size: usize, concurrency: u8, ttl: u64) -> Self {\n        Self {\n            cache: Arc::new(Cache::new(size)),\n            concurrency,\n            ttl: Duration::from_secs(ttl),\n        }\n    }\n\n    pub fn into_http_connector(self) -> HttpConnector<Self> {\n        HttpConnector::<Self>::new_with_resolver(self)\n    }\n}\n"
  },
  {
    "path": "libs/llrt_encoding/Cargo.toml",
    "content": "[package]\nname = \"llrt_encoding\"\ndescription = \"LLRT encoding helpers\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[dependencies]\nbase64-simd = { version = \"0.8\", features = [\n    \"alloc\",\n], default-features = false }\nhex-simd = { version = \"0.8\", features = [\"alloc\"], default-features = false }\nphf = { version = \"0.13\", features = [\"macros\"], default-features = false }\nmemchr = { version = \"2\", default-features = false }\n\n[build-dependencies]\nllrt_build = { version = \"0.8.1-beta\", path = \"../llrt_build\" }\n"
  },
  {
    "path": "libs/llrt_encoding/build.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nfn main() {\n    llrt_build::set_nightly_cfg();\n}\n"
  },
  {
    "path": "libs/llrt_encoding/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#![cfg_attr(rust_nightly, feature(iter_array_chunks))]\nuse std::borrow::Cow;\n\nuse hex_simd::AsciiCase;\n\n#[derive(Clone, PartialEq)]\npub enum Encoder {\n    Hex,\n    Base64,\n    Windows1252,\n    Utf8,\n    Utf16le,\n    Utf16be,\n}\n\nconst ENCODING_MAP: phf::Map<&'static str, Encoder> = phf::phf_map! {\n    \"hex\" => Encoder::Hex,\n    \"base64\" => Encoder::Base64,\n    \"unicode-1-1-utf-8\" => Encoder::Utf8,\n    \"unicode11utf8\" => Encoder::Utf8,\n    \"unicode20utf8\" => Encoder::Utf8,\n    \"utf-8\" => Encoder::Utf8,\n    \"utf8\" => Encoder::Utf8,\n    \"x-unicode20utf8\" => Encoder::Utf8,\n    \"csunicode\" => Encoder::Utf16le,\n    \"iso-10646-ucs-2\" => Encoder::Utf16le,\n    \"ucs-2\" => Encoder::Utf16le,\n    \"ucs2\" => Encoder::Utf16le,\n    \"unicode\" => Encoder::Utf16le,\n    \"unicodefeff\" => Encoder::Utf16le,\n    \"utf-16\" => Encoder::Utf16le,\n    \"utf-16le\" => Encoder::Utf16le,\n    \"utf16le\" => Encoder::Utf16le,\n    \"unicodefffe\" => Encoder::Utf16be,\n    \"utf-16be\" => Encoder::Utf16be,\n    \"ansi_x3.4-1968\" => Encoder::Windows1252,\n    \"ascii\" => Encoder::Windows1252,\n    \"cp1252\" => Encoder::Windows1252,\n    \"cp819\" => Encoder::Windows1252,\n    \"csisolatin1\" => Encoder::Windows1252,\n    \"ibm819\" => Encoder::Windows1252,\n    \"iso-8859-1\" => Encoder::Windows1252,\n    \"iso-ir-100\" => Encoder::Windows1252,\n    \"iso8859-1\" => Encoder::Windows1252,\n    \"iso88591\" => Encoder::Windows1252,\n    \"iso_8859-1\" => Encoder::Windows1252,\n    \"iso_8859-1:1987\" => Encoder::Windows1252,\n    \"l1\" => Encoder::Windows1252,\n    \"latin1\" => Encoder::Windows1252,\n    \"us-ascii\" => Encoder::Windows1252,\n    \"windows-1252\" => Encoder::Windows1252,\n    \"x-cp1252\" => Encoder::Windows1252,\n};\n\nimpl Encoder {\n    pub fn from_optional_str(encoding: Option<&str>) -> Result<Self, String> {\n        match encoding {\n            Some(label) if !label.is_empty() => Self::from_str(label),\n            _ => Ok(Self::Utf8),\n        }\n    }\n\n    #[allow(clippy::should_implement_trait)]\n    pub fn from_str(encoding: &str) -> Result<Self, String> {\n        ENCODING_MAP\n            .get(encoding.trim_ascii().to_ascii_lowercase().as_str())\n            .cloned()\n            .ok_or_else(|| [\"The \\\"\", encoding, \"\\\" encoding is not supported\"].concat())\n    }\n\n    pub fn encode_to_string(&self, bytes: &[u8], lossy: bool) -> Result<String, String> {\n        match self {\n            Self::Hex => Ok(bytes_to_hex_string(bytes)),\n            Self::Base64 => Ok(bytes_to_b64_string(bytes)),\n            Self::Utf8 | Self::Windows1252 => bytes_to_utf8_string(bytes, lossy),\n            Self::Utf16le => bytes_to_utf16_string(bytes, Endian::Little, lossy),\n            Self::Utf16be => bytes_to_utf16_string(bytes, Endian::Big, lossy),\n        }\n    }\n\n    #[allow(dead_code)]\n    pub fn encode(&self, bytes: &[u8]) -> Result<Vec<u8>, String> {\n        match self {\n            Self::Hex => Ok(bytes_to_hex(bytes)),\n            Self::Base64 => Ok(bytes_to_b64(bytes)),\n            Self::Utf8 | Self::Windows1252 | Self::Utf16le | Self::Utf16be => Ok(bytes.to_vec()),\n        }\n    }\n\n    pub fn decode<'a, T: Into<Cow<'a, [u8]>>>(&self, bytes: T) -> Result<Vec<u8>, String> {\n        match self {\n            Self::Hex => bytes_from_hex(bytes),\n            Self::Base64 => bytes_from_b64(bytes),\n            Self::Utf8 | Self::Windows1252 | Self::Utf16le | Self::Utf16be => {\n                Ok(bytes.into().into())\n            },\n        }\n    }\n\n    pub fn decode_from_string(&self, string: String) -> Result<Vec<u8>, String> {\n        match self {\n            Self::Hex => bytes_from_hex(string.into_bytes()),\n            Self::Base64 => bytes_from_b64(string.into_bytes()),\n            Self::Utf8 | Self::Windows1252 => Ok(string.into_bytes()),\n            Self::Utf16le => Ok(string\n                .encode_utf16()\n                .flat_map(|utf16| utf16.to_le_bytes())\n                .collect::<Vec<u8>>()),\n            Self::Utf16be => Ok(string\n                .encode_utf16()\n                .flat_map(|utf16| utf16.to_be_bytes())\n                .collect::<Vec<u8>>()),\n        }\n    }\n\n    pub fn as_label(&self) -> &str {\n        match self {\n            Self::Hex => \"hex\",\n            Self::Base64 => \"base64\",\n            Self::Windows1252 => \"windows-1252\",\n            Self::Utf8 => \"utf-8\",\n            Self::Utf16le => \"utf-16le\",\n            Self::Utf16be => \"utf-16be\",\n        }\n    }\n}\n\npub fn bytes_to_hex(bytes: &[u8]) -> Vec<u8> {\n    hex_simd::encode_type(bytes, AsciiCase::Lower)\n}\n\npub fn bytes_from_hex<'a, T: Into<Cow<'a, [u8]>>>(hex_bytes: T) -> Result<Vec<u8>, String> {\n    hex_simd::decode_to_vec(hex_bytes.into()).map_err(|err| err.to_string())\n}\n\npub fn bytes_from_b64<'a, T: Into<Cow<'a, [u8]>>>(base64_bytes: T) -> Result<Vec<u8>, String> {\n    let bytes: Cow<'a, [u8]> = base64_bytes.into();\n\n    //need to collect since memchr2_iter is borrowing bytes. This is fine since we're unlikely to contain url safe base64\n    let url_safe_byte_positions: Vec<usize> = memchr::memchr2_iter(b'-', b'_', &bytes).collect();\n\n    if url_safe_byte_positions.is_empty() {\n        return base64_simd::forgiving_decode_to_vec(&bytes).map_err(|e| e.to_string());\n    }\n\n    //doesn't allocate for already owned data\n    let mut bytes = bytes.into_owned();\n    for pos in url_safe_byte_positions {\n        bytes[pos] = match bytes[pos] {\n            b'-' => b'+',\n            b'_' => b'/',\n            _ => unreachable!(),\n        };\n    }\n    base64_simd::forgiving_decode_to_vec(&bytes).map_err(|e| e.to_string())\n}\n\npub fn bytes_to_b64_string(bytes: &[u8]) -> String {\n    base64_simd::STANDARD.encode_to_string(bytes)\n}\n\npub fn bytes_to_b64_url_safe_string(bytes: &[u8]) -> String {\n    base64_simd::URL_SAFE_NO_PAD.encode_to_string(bytes)\n}\n\npub fn bytes_from_b64_url_safe(bytes: &[u8]) -> Result<Vec<u8>, String> {\n    base64_simd::URL_SAFE_NO_PAD\n        .decode_to_vec(bytes)\n        .map_err(|e| e.to_string())\n}\n\npub fn bytes_to_b64(bytes: &[u8]) -> Vec<u8> {\n    base64_simd::STANDARD.encode_type(bytes)\n}\n\npub fn bytes_to_hex_string(bytes: &[u8]) -> String {\n    hex_simd::encode_to_string(bytes, AsciiCase::Lower)\n}\n\npub fn bytes_to_utf8_string(bytes: &[u8], lossy: bool) -> Result<String, String> {\n    if lossy {\n        Ok(String::from_utf8_lossy(bytes).to_string())\n    } else {\n        String::from_utf8(bytes.to_vec()).map_err(|e| e.to_string())\n    }\n}\n\n#[derive(Clone, Copy)]\npub enum Endian {\n    Little,\n    Big,\n}\n\npub fn bytes_to_utf16_string(bytes: &[u8], endian: Endian, lossy: bool) -> Result<String, String> {\n    if !lossy && !bytes.len().is_multiple_of(2) {\n        return Err(\"Input byte slice length must be even\".to_string());\n    }\n\n    #[cfg(rust_nightly)]\n    let data16: Vec<u16> = match endian {\n        Endian::Little => bytes\n            .iter()\n            .copied()\n            .array_chunks::<2>()\n            .map(|chunk| u16::from_le_bytes(chunk))\n            .collect(),\n        Endian::Big => bytes\n            .iter()\n            .copied()\n            .array_chunks::<2>()\n            .map(|chunk| u16::from_be_bytes(chunk))\n            .collect(),\n    };\n\n    #[cfg(not(rust_nightly))]\n    let data16: Vec<u16> = match endian {\n        Endian::Little => bytes\n            .chunks_exact(2)\n            .map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]))\n            .collect(),\n        Endian::Big => bytes\n            .chunks_exact(2)\n            .map(|chunk| u16::from_be_bytes([chunk[0], chunk[1]]))\n            .collect(),\n    };\n\n    if lossy {\n        Ok(String::from_utf16_lossy(&data16))\n    } else {\n        String::from_utf16(&data16).map_err(|e| e.to_string())\n    }\n}\n"
  },
  {
    "path": "libs/llrt_hooking/Cargo.toml",
    "content": "[package]\nname = \"llrt_hooking\"\ndescription = \"LLRT hooking helpers\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[lib]\nname = \"llrt_hooking\"\npath = \"src/lib.rs\"\n\n[dependencies]\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nonce_cell = { version = \"1\", features = [\"std\"], default-features = false }\nrquickjs = { version = \"0.11\", default-features = false }\n"
  },
  {
    "path": "libs/llrt_hooking/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::env;\n\nuse llrt_utils::{object::ObjectExt, provider::ProviderType};\nuse once_cell::sync::Lazy;\nuse rquickjs::{Ctx, Exception, Function, Result, Value};\n\npub static HOOKING_MODE: Lazy<bool> =\n    Lazy::new(|| env::var(\"LLRT_ASYNC_HOOKS\").as_deref() == Ok(\"1\"));\n\n#[derive(PartialEq)]\npub enum HookType {\n    Init,\n    Before,\n    After,\n}\n\npub fn invoke_async_hook(\n    ctx: &Ctx<'_>,\n    hook_type: HookType,\n    provider_type: ProviderType,\n    uid: usize,\n) -> Result<()> {\n    if !HOOKING_MODE.to_owned() {\n        return Ok(());\n    }\n\n    let hook_ = match hook_type {\n        HookType::Init => \"init\",\n        HookType::Before => \"before\",\n        HookType::After => \"after\",\n    };\n\n    let provider_ = match provider_type {\n        ProviderType::None if hook_type != HookType::Init => \"\",\n        ProviderType::None => {\n            return Err(Exception::throw_type(\n                ctx,\n                \"Asynchronous types cannot be omitted in init hooks.\",\n            ))\n        },\n        ProviderType::Resource(s) => &[\"Resource(\", &s, \")\"].concat(),\n        // Userland provider types\n        ProviderType::Immediate => \"Immediate\",\n        ProviderType::Interval => \"Interval\",\n        ProviderType::MessagePort => \"MessagePort\",\n        ProviderType::Microtask => \"Microtask\",\n        ProviderType::TickObject => \"TickObject\",\n        ProviderType::Timeout => \"Timeout\",\n        // Internal provider types\n        ProviderType::FsReqCallback => \"FSREQCALLBACK\",\n        ProviderType::GetAddrInfoReqWrap => \"GETADDRINFOREQWRAP\",\n        ProviderType::GetNameInfoReqWrap => \"GETNAMEINFOREQWRAP\",\n        ProviderType::PipeWrap => \"PIPEWRAP\",\n        ProviderType::StatWatcher => \"STATWACHER\",\n        ProviderType::TcpWrap => \"TCPWRAP\",\n        ProviderType::TimerWrap => \"TIMERWRAP\",\n        ProviderType::TlsWrap => \"TLSWRAP\",\n        ProviderType::UdpWrap => \"UDPWRAP\",\n    };\n\n    let invoke_async_hook = ctx\n        .globals()\n        .get_optional::<_, Function>(\"invokeAsyncHook\")?;\n    if let Some(func) = &invoke_async_hook {\n        func.call::<_, ()>((hook_, provider_, uid))?;\n    }\n    Ok(())\n}\n\npub fn register_finalization_registry<'js>(\n    ctx: &Ctx<'js>,\n    target: Value<'js>,\n    uid: usize,\n) -> Result<()> {\n    if !HOOKING_MODE.to_owned() {\n        return Ok(());\n    }\n\n    if let Ok(register) =\n        ctx.eval::<Function<'js>, &str>(\"globalThis.asyncFinalizationRegistry.register\")\n    {\n        let _ = register.call::<_, ()>((target, uid));\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "libs/llrt_json/Cargo.toml",
    "content": "[package]\nname = \"llrt_json\"\ndescription = \"LLRT json helpers\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[lib]\nname = \"llrt_json\"\npath = \"src/lib.rs\"\n\n[dependencies]\nitoa = { version = \"1\", default-features = false }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", default-features = false }\nryu = { version = \"1\", default-features = false }\nsimd-json = { version = \"0.17\", features = [\n    \"big-int-as-float\",\n], default-features = false }\n\n[dev-dependencies]\ncriterion = { version = \"0.8\", default-features = false }\nllrt_test = { version = \"0.8.1-beta\", path = \"../llrt_test\" }\ntokio = { version = \"1\", features = [\"test-util\"], default-features = false }\n\n[build-dependencies]\nllrt_build = { version = \"0.8.1-beta\", path = \"../llrt_build\" }\n\n[[bench]]\nname = \"json\"\nharness = false\n"
  },
  {
    "path": "libs/llrt_json/benches/json.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\n#![allow(dead_code)]\nuse std::hint::black_box;\n\nuse criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};\nuse llrt_json::{escape::escape_json, parse::json_parse, stringify::json_stringify};\nuse rquickjs::{Context, Runtime};\n\nstatic JSON: &str = r#\"{\"organization\":{\"name\":\"TechCorp\",\"founding_year\":2000,\"departments\":[{\"name\":\"Engineering\",\"head\":{\"name\":\"Alice Smith\",\"title\":\"VP of Engineering\",\"contact\":{\"email\":\"alice.smith@techcorp.com\",\"phone\":\"+1 (555) 123-4567\"}},\"employees\":[{\"id\":101,\"name\":\"Bob Johnson\",\"position\":\"Software Engineer\",\"contact\":{\"email\":\"bob.johnson@techcorp.com\",\"phone\":\"+1 (555) 234-5678\"},\"projects\":[{\"project_id\":\"P001\",\"name\":\"Project A\",\"status\":\"In Progress\",\"description\":\"Developing a revolutionary software solution for clients.\",\"start_date\":\"2023-01-15\",\"end_date\":null,\"team\":[{\"id\":201,\"name\":\"Sara Davis\",\"role\":\"UI/UX Designer\"},{\"id\":202,\"name\":\"Charlie Brown\",\"role\":\"Quality Assurance Engineer\"}]},{\"project_id\":\"P002\",\"name\":\"Project B\",\"status\":\"Completed\",\"description\":\"Upgrading existing systems to enhance performance.\",\"start_date\":\"2022-05-01\",\"end_date\":\"2022-11-30\",\"team\":[{\"id\":203,\"name\":\"Emily White\",\"role\":\"Systems Architect\"},{\"id\":204,\"name\":\"James Green\",\"role\":\"Database Administrator\"}]}]},{\"id\":102,\"name\":\"Carol Williams\",\"position\":\"Senior Software Engineer\",\"contact\":{\"email\":\"carol.williams@techcorp.com\",\"phone\":\"+1 (555) 345-6789\"},\"projects\":[{\"project_id\":\"P001\",\"name\":\"Project A\",\"status\":\"In Progress\",\"description\":\"Working on the backend development of Project A.\",\"start_date\":\"2023-01-15\",\"end_date\":null,\"team\":[{\"id\":205,\"name\":\"Alex Turner\",\"role\":\"DevOps Engineer\"},{\"id\":206,\"name\":\"Mia Garcia\",\"role\":\"Software Developer\"}]},{\"project_id\":\"P003\",\"name\":\"Project C\",\"status\":\"Planning\",\"description\":\"Researching and planning for a future project.\",\"start_date\":null,\"end_date\":null,\"team\":[]}]}]},{\"name\":\"Marketing\",\"head\":{\"name\":\"David Brown\",\"title\":\"VP of Marketing\",\"contact\":{\"email\":\"david.brown@techcorp.com\",\"phone\":\"+1 (555) 456-7890\"}},\"employees\":[{\"id\":201,\"name\":\"Eva Miller\",\"position\":\"Marketing Specialist\",\"contact\":{\"email\":\"eva.miller@techcorp.com\",\"phone\":\"+1 (555) 567-8901\"},\"campaigns\":[{\"campaign_id\":\"C001\",\"name\":\"Product Launch\",\"status\":\"Upcoming\",\"description\":\"Planning for the launch of a new product line.\",\"start_date\":\"2023-03-01\",\"end_date\":null,\"team\":[{\"id\":301,\"name\":\"Oliver Martinez\",\"role\":\"Graphic Designer\"},{\"id\":302,\"name\":\"Sophie Johnson\",\"role\":\"Content Writer\"}]},{\"campaign_id\":\"C002\",\"name\":\"Brand Awareness\",\"status\":\"Ongoing\",\"description\":\"Executing strategies to increase brand visibility.\",\"start_date\":\"2022-11-15\",\"end_date\":\"2023-01-31\",\"team\":[{\"id\":303,\"name\":\"Liam Taylor\",\"role\":\"Social Media Manager\"},{\"id\":304,\"name\":\"Ava Clark\",\"role\":\"Marketing Analyst\"}]}]}]}]}}\"#;\n\nstatic JSON_MIN: &str = r#\"{\"glossary\":{\"title\":\"example glossary\",\"GlossDiv\":{\"title\":\"S\",\"GlossList\":{\"GlossEntry\":{\"ID\":\"SGML\",\"SortAs\":\"SGML\",\"GlossTerm\":\"Standard Generalized Markup Language\",\"Acronym\":\"SGML\",\"Abbrev\":\"ISO 8879:1986\",\"GlossDef\":{\"para\":\"A meta-markup language, used to create markup languages such as DocBook.\",\"GlossSeeAlso\":[\"GML\",\"XML\"]},\"GlossSee\":\"markup\"}}}}}\"#;\n\nfn generate_json(child_json: &str, size: usize) -> String {\n    let mut json = String::with_capacity(child_json.len() * size);\n    json.push('{');\n    for i in 0..size {\n        json.push_str(\"\\\"obj\");\n        json.push_str(&i.to_string());\n        json.push_str(\"\\\":\");\n        json.push_str(child_json);\n        json.push(',');\n    }\n    json.push_str(\"\\\"array\\\":[\");\n    for i in 0..size {\n        json.push_str(child_json);\n        if i < size - 1 {\n            json.push(',');\n        }\n    }\n\n    json.push_str(\"]}\");\n    json\n}\n\npub fn criterion_benchmark(c: &mut Criterion) {\n    let mut group = c.benchmark_group(\"Parsing\");\n\n    let json = JSON.to_owned();\n    for (id, json) in [\n        json.clone(),\n        generate_json(&json, 1),\n        generate_json(&json, 10),\n        generate_json(&json, 100),\n        generate_json(&json, 1000),\n        generate_json(&json, 10000),\n    ]\n    .into_iter()\n    .enumerate()\n    {\n        let runtime = Runtime::new().unwrap();\n        runtime.set_max_stack_size(512 * 1024);\n\n        let ctx = Context::full(&runtime).unwrap();\n        group.bench_with_input(BenchmarkId::new(\"Custom\", id), &json, |b, json| {\n            ctx.with(|ctx| {\n                b.iter(|| json_parse(&ctx, json.clone()));\n            });\n        });\n        group.bench_with_input(BenchmarkId::new(\"Built-in\", id), &json, |b, json| {\n            ctx.with(|ctx| {\n                b.iter(|| ctx.json_parse(json.clone()));\n            });\n        });\n    }\n\n    group.finish();\n\n    c.bench_function(\"json parse\", |b| {\n        let runtime = Runtime::new().unwrap();\n        runtime.set_max_stack_size(512 * 1024);\n\n        let ctx = Context::full(&runtime).unwrap();\n\n        ctx.with(|ctx| b.iter(|| json_parse(&ctx, black_box(JSON_MIN))));\n    });\n\n    c.bench_function(\"json stringify\", |b| {\n        let runtime = Runtime::new().unwrap();\n        runtime.set_max_stack_size(512 * 1024);\n\n        let ctx = Context::full(&runtime).unwrap();\n\n        ctx.with(|ctx| {\n            let obj = json_parse(&ctx, black_box(JSON)).unwrap();\n\n            b.iter(|| json_stringify(&ctx, obj.clone()))\n        });\n    });\n\n    // Escape benchmarks\n    let test_strings = [\n        (\n            \"clean\",\n            \"Hello World! This is a clean string with no escapes needed.\",\n        ),\n        (\"quotes\", r#\"This \"has\" some \"quotes\" to escape\"#),\n        (\n            \"mixed\",\n            \"Line 1\\nLine 2\\tTabbed\\r\\nWith \\\"quotes\\\" and \\\\backslashes\\\\\",\n        ),\n        (\n            \"heavy\",\n            \"\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\\"\\\\\",\n        ),\n    ];\n\n    for (name, test_str) in test_strings {\n        c.bench_function(&format!(\"escape_{name}\"), |b| {\n            b.iter(|| escape_json(black_box(test_str.as_bytes())))\n        });\n    }\n}\n\ncriterion_group!(benches, criterion_benchmark);\ncriterion_main!(benches);\n"
  },
  {
    "path": "libs/llrt_json/build.rs",
    "content": "fn main() {\n    llrt_build::set_nightly_cfg();\n}\n"
  },
  {
    "path": "libs/llrt_json/src/escape.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nstatic JSON_ESCAPE_CHARS: [u8; 256] = [\n    0u8, 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8, 9u8, 10u8, 11u8, 12u8, 13u8, 14u8, 15u8, 16u8,\n    17u8, 18u8, 19u8, 20u8, 21u8, 22u8, 23u8, 24u8, 25u8, 26u8, 27u8, 28u8, 29u8, 30u8, 31u8, 34u8,\n    34u8, 32u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8,\n    34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8,\n    34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8,\n    34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 33u8, 34u8, 34u8, 34u8, 34u8,\n    34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8,\n    34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8,\n    34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8,\n    34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8,\n    34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8,\n    34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8,\n    34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8,\n    34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8,\n    34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8,\n    34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8, 34u8,\n];\nstatic JSON_ESCAPE_QUOTES: [&str; 34usize] = [\n    \"\\\\u0000\", \"\\\\u0001\", \"\\\\u0002\", \"\\\\u0003\", \"\\\\u0004\", \"\\\\u0005\", \"\\\\u0006\", \"\\\\u0007\", \"\\\\b\",\n    \"\\\\t\", \"\\\\n\", \"\\\\u000b\", \"\\\\f\", \"\\\\r\", \"\\\\u000e\", \"\\\\u000f\", \"\\\\u0010\", \"\\\\u0011\", \"\\\\u0012\",\n    \"\\\\u0013\", \"\\\\u0014\", \"\\\\u0015\", \"\\\\u0016\", \"\\\\u0017\", \"\\\\u0018\", \"\\\\u0019\", \"\\\\u001a\",\n    \"\\\\u001b\", \"\\\\u001c\", \"\\\\u001d\", \"\\\\u001e\", \"\\\\u001f\", \"\\\\\\\"\", \"\\\\\\\\\",\n];\n\nconst ESCAPE_LEN: usize = 34;\n\n#[inline(always)]\nfn write_surrogate_escape(result: &mut String, bytes: &[u8], i: usize) -> usize {\n    let code_point = ((bytes[i] as u16 & 0x0F) << 12)\n        | ((bytes[i + 1] as u16 & 0x3F) << 6)\n        | (bytes[i + 2] as u16 & 0x3F);\n\n    result.push_str(\"\\\\u\");\n    let hex = [\n        (code_point >> 12) as u8,\n        ((code_point >> 8) & 0xF) as u8,\n        ((code_point >> 4) & 0xF) as u8,\n        (code_point & 0xF) as u8,\n    ];\n    for h in hex {\n        result.push(if h < 10 {\n            (b'0' + h) as char\n        } else {\n            (b'a' + h - 10) as char\n        });\n    }\n    3\n}\n\n#[allow(dead_code)]\npub fn escape_json(bytes: &[u8]) -> String {\n    let mut result = String::new();\n    escape_json_string(&mut result, bytes);\n    result\n}\n\n#[inline(always)]\nfn process_byte(\n    result: &mut String,\n    bytes: &[u8],\n    byte: u8,\n    i: &mut usize,\n    start: &mut usize,\n    len: usize,\n) {\n    if *i + 2 < len && byte == 0xED && *i + 1 < len && (bytes[*i + 1] & 0xF0) >= 0xA0 {\n        if *start < *i {\n            result.push_str(unsafe { std::str::from_utf8_unchecked(&bytes[*start..*i]) });\n        }\n        *i += write_surrogate_escape(result, bytes, *i);\n        *start = *i;\n        return;\n    }\n\n    let c = JSON_ESCAPE_CHARS[byte as usize] as usize;\n    if c < ESCAPE_LEN {\n        if *start < *i {\n            result.push_str(unsafe { std::str::from_utf8_unchecked(&bytes[*start..*i]) });\n        }\n        result.push_str(JSON_ESCAPE_QUOTES[c]);\n        *start = *i + 1;\n    }\n    *i += 1;\n}\n\n#[inline(always)]\npub fn escape_json_string_simple(result: &mut String, bytes: &[u8]) {\n    let len = bytes.len();\n    let mut start = 0;\n    let mut i = 0;\n    result.reserve(len);\n\n    let (chunks, tail) = bytes.as_chunks::<8>();\n\n    for chunk in chunks {\n        if chunk.iter().any(|&b| b < 32 || b == 34 || b == 92) {\n            for &byte in chunk {\n                process_byte(result, bytes, byte, &mut i, &mut start, len);\n            }\n        } else {\n            i += 8;\n        }\n    }\n\n    for &byte in tail {\n        process_byte(result, bytes, byte, &mut i, &mut start, len);\n    }\n\n    if start < len {\n        result.push_str(unsafe { std::str::from_utf8_unchecked(&bytes[start..len]) });\n    }\n}\n\npub fn escape_json_string(result: &mut String, bytes: &[u8]) {\n    escape_json_string_simple(result, bytes);\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::escape::escape_json;\n\n    #[test]\n    fn escape_json_simple() {\n        assert_eq!(escape_json(b\"Hello, World!\"), \"Hello, World!\");\n    }\n\n    #[test]\n    fn escape_json_quotes() {\n        assert_eq!(escape_json(b\"\\\"quoted\\\"\"), \"\\\\\\\"quoted\\\\\\\"\");\n    }\n\n    #[test]\n    fn escape_json_backslash() {\n        assert_eq!(escape_json(b\"back\\\\slash\"), \"back\\\\\\\\slash\");\n    }\n\n    #[test]\n    fn escape_json_newline() {\n        assert_eq!(escape_json(b\"line\\nbreak\"), \"line\\\\nbreak\");\n    }\n\n    #[test]\n    fn escape_json_tab() {\n        assert_eq!(escape_json(b\"tab\\tcharacter\"), \"tab\\\\tcharacter\");\n    }\n\n    #[test]\n    fn escape_json_unicode() {\n        assert_eq!(\n            escape_json(\"unicode: \\u{1F609}\".as_bytes()),\n            \"unicode: \\u{1F609}\"\n        );\n    }\n\n    #[test]\n    fn escape_json_special_characters() {\n        assert_eq!(\n            escape_json(b\"!@#$%^&*()_+-=[]{}|;':,.<>?/\"),\n            \"!@#$%^&*()_+-=[]{}|;':,.<>?/\"\n        );\n    }\n\n    #[test]\n    fn escape_json_mixed_characters() {\n        assert_eq!(\n            escape_json(b\"123\\\"\\\"45678901\\\"234567\"),\n            \"123\\\\\\\"\\\\\\\"45678901\\\\\\\"234567\"\n        );\n    }\n}\n"
  },
  {
    "path": "libs/llrt_json/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::cmp::min;\n\nuse rquickjs::{\n    atom::PredefinedAtom, function::Opt, prelude::Func, Ctx, IntoJs, Object, Result, Value,\n};\n\npub mod escape;\npub mod parse;\npub mod stringify;\n\nuse crate::parse::json_parse_string;\nuse crate::stringify::json_stringify_replacer_space;\n\npub fn redefine_static_methods(ctx: &Ctx<'_>) -> Result<()> {\n    let globals = ctx.globals();\n    let json_module: Object = globals.get(PredefinedAtom::JSON)?;\n    json_module.set(\"parse\", Func::from(json_parse_string))?;\n    json_module.set(\n        \"stringify\",\n        Func::from(|ctx, value, replacer, space| {\n            struct StringifyArgs<'js>(Ctx<'js>, Value<'js>, Opt<Value<'js>>, Opt<Value<'js>>);\n            let StringifyArgs(ctx, value, replacer, space) =\n                StringifyArgs(ctx, value, replacer, space);\n\n            let mut space_value = None;\n            let mut replacer_value = None;\n\n            if let Some(replacer) = replacer.0 {\n                if let Some(space) = space.0 {\n                    if let Some(space) = space.as_string() {\n                        let mut space = space.clone().to_string()?;\n                        space.truncate(20);\n                        space_value = Some(space);\n                    }\n                    if let Some(number) = space.as_int() {\n                        if number > 0 {\n                            space_value = Some(\" \".repeat(min(10, number as usize)));\n                        }\n                    }\n                }\n                replacer_value = Some(replacer);\n            }\n\n            json_stringify_replacer_space(&ctx, value, replacer_value, space_value)\n                .map(|v| v.into_js(&ctx))?\n        }),\n    )?;\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use llrt_test::test_sync_with;\n    use rquickjs::{prelude::Func, Array, CatchResultExt, IntoJs, Null, Object, Undefined, Value};\n\n    use crate::{\n        parse::{json_parse, json_parse_string},\n        stringify::{json_stringify, json_stringify_replacer_space},\n    };\n\n    static JSON: &str = r#\"{\"organization\":{\"name\":\"TechCorp\",\"founding_year\":2000,\"departments\":[{\"name\":\"Engineering\",\"head\":{\"name\":\"Alice Smith\",\"title\":\"VP of Engineering\",\"contact\":{\"email\":\"alice.smith@techcorp.com\",\"phone\":\"+1 (555) 123-4567\"}},\"employees\":[{\"id\":101,\"name\":\"Bob Johnson\",\"position\":\"Software Engineer\",\"contact\":{\"email\":\"bob.johnson@techcorp.com\",\"phone\":\"+1 (555) 234-5678\"},\"projects\":[{\"project_id\":\"P001\",\"name\":\"Project A\",\"status\":\"In Progress\",\"description\":\"Developing a revolutionary software solution for clients.\",\"start_date\":\"2023-01-15\",\"end_date\":null,\"team\":[{\"id\":201,\"name\":\"Sara Davis\",\"role\":\"UI/UX Designer\"},{\"id\":202,\"name\":\"Charlie Brown\",\"role\":\"Quality Assurance Engineer\"}]},{\"project_id\":\"P002\",\"name\":\"Project B\",\"status\":\"Completed\",\"description\":\"Upgrading existing systems to enhance performance.\",\"start_date\":\"2022-05-01\",\"end_date\":\"2022-11-30\",\"team\":[{\"id\":203,\"name\":\"Emily White\",\"role\":\"Systems Architect\"},{\"id\":204,\"name\":\"James Green\",\"role\":\"Database Administrator\"}]}]},{\"id\":102,\"name\":\"Carol Williams\",\"position\":\"Senior Software Engineer\",\"contact\":{\"email\":\"carol.williams@techcorp.com\",\"phone\":\"+1 (555) 345-6789\"},\"projects\":[{\"project_id\":\"P001\",\"name\":\"Project A\",\"status\":\"In Progress\",\"description\":\"Working on the backend development of Project A.\",\"start_date\":\"2023-01-15\",\"end_date\":null,\"team\":[{\"id\":205,\"name\":\"Alex Turner\",\"role\":\"DevOps Engineer\"},{\"id\":206,\"name\":\"Mia Garcia\",\"role\":\"Software Developer\"}]},{\"project_id\":\"P003\",\"name\":\"Project C\",\"status\":\"Planning\",\"description\":\"Researching and planning for a future project.\",\"start_date\":null,\"end_date\":null,\"team\":[]}]}]},{\"name\":\"Marketing\",\"head\":{\"name\":\"David Brown\",\"title\":\"VP of Marketing\",\"contact\":{\"email\":\"david.brown@techcorp.com\",\"phone\":\"+1 (555) 456-7890\"}},\"employees\":[{\"id\":201,\"name\":\"Eva Miller\",\"position\":\"Marketing Specialist\",\"contact\":{\"email\":\"eva.miller@techcorp.com\",\"phone\":\"+1 (555) 567-8901\"},\"campaigns\":[{\"campaign_id\":\"C001\",\"name\":\"Product Launch\",\"status\":\"Upcoming\",\"description\":\"Planning for the launch of a new product line.\",\"start_date\":\"2023-03-01\",\"end_date\":null,\"team\":[{\"id\":301,\"name\":\"Oliver Martinez\",\"role\":\"Graphic Designer\"},{\"id\":302,\"name\":\"Sophie Johnson\",\"role\":\"Content Writer\"}]},{\"campaign_id\":\"C002\",\"name\":\"Brand Awareness\",\"status\":\"Ongoing\",\"description\":\"Executing strategies to increase brand visibility.\",\"start_date\":\"2022-11-15\",\"end_date\":\"2023-01-31\",\"team\":[{\"id\":303,\"name\":\"Liam Taylor\",\"role\":\"Social Media Manager\"},{\"id\":304,\"name\":\"Ava Clark\",\"role\":\"Marketing Analyst\"}]}]}]}]}}\"#;\n\n    #[tokio::test]\n    async fn json_parser() {\n        test_sync_with(|ctx| {\n            let json_data = [\n                r#\"{\"aa\\\"\\\"aaaaaaaaaaaaaaaa\":\"a\",\"b\":\"bbb\"}\"#,\n                r#\"{\"a\":\"aaaaaaaaaaaaaaaaaa\",\"b\":\"bbb\"}\"#,\n                r#\"{\"a\":[\"a\",\"a\",\"aaaa\",\"a\"],\"b\":\"b\"}\"#,\n                r#\"{\"type\":\"Buffer\",\"data\":[10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10]}\"#,\n                r#\"{\"a\":[{\"object2\":{\"key1\":\"value1\",\"key2\":123,\"key3\":false,\"nestedObject\":{\"nestedKey\":\"nestedValue\"}},\"string\":\"Hello, World!\",\"emptyObj\":{},\"emptyArr\":[],\"number\":42,\"boolean\":true,\"nullValue\":null,\"array\":[1,2,3,\"four\",5.5,true,null],\"object\":{\"key1\":\"value1\",\"key2\":123,\"key3\":false,\"nestedObject\":{\"nestedKey\":\"nestedValue\"}}}]}\"#,\n                JSON,\n            ];\n\n            for json_str in json_data {\n                let json = json_str.to_string();\n                let json2 = json.clone();\n\n                let value = json_parse(&ctx, json2)?;\n                let new_json = json_stringify_replacer_space(&ctx, value.clone(),None,Some(\"  \".into()))?.unwrap();\n                let builtin_json = ctx.json_stringify_replacer_space(value,Null,\"  \".to_string())?.unwrap().to_string()?;\n                assert_eq!(new_json, builtin_json);\n            }\n\n            Ok(())\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn json_parse_non_string() {\n        test_sync_with(|ctx| {\n            ctx.globals().set(\"parse\", Func::from(json_parse_string))?;\n\n            let result = ctx.eval::<(), _>(\"parse({})\").catch(&ctx);\n\n            if let Err(err) = result {\n                assert_eq!(\n                   err.to_string(),\n                   \"Error: \\\"[object Object]\\\" not valid JSON at index 1 ('o')\\n    at <eval> (eval_script:1:1)\\n\"\n               );\n            } else {\n                panic!(\"expected error\")\n            }\n\n            Ok(())\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn json_stringify_undefined() {\n        test_sync_with(|ctx| {\n            let stringified = json_stringify(&ctx, Undefined.into_js(&ctx)?)?;\n            let stringified_2 = ctx\n                .json_stringify(Undefined)?\n                .map(|v| v.to_string().unwrap());\n            assert_eq!(stringified, stringified_2);\n\n            let obj: Value = ctx.eval(\n                r#\"let obj = { value: undefined, array: [undefined, null, 1, true, \"hello\", { [Symbol(\"sym\")]: 1, [undefined]: 2}] };obj;\"#,\n            )?;\n\n            let stringified = json_stringify(&ctx, obj.clone())?;\n            let stringified_2 = ctx\n                .json_stringify(obj)?\n                .map(|v| v.to_string().unwrap());\n            assert_eq!(stringified, stringified_2);\n\n            Ok(())\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn json_stringify_objects() {\n        test_sync_with(|ctx| {\n            let date: Value = ctx.eval(\"let obj = { date: new Date(0) };obj;\")?;\n            let stringified = json_stringify(&ctx, date.clone())?.unwrap();\n            let stringified_2 = ctx.json_stringify(date)?.unwrap().to_string()?;\n            assert_eq!(stringified, stringified_2);\n            Ok(())\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn huge_numbers() {\n        test_sync_with(|ctx| {\n\n            let big_int_value = json_parse(&ctx, b\"99999999999999999999999999999999999999999999999999999999999999999999999999999999999\")?;\n\n            let stringified = json_stringify(&ctx, big_int_value.clone())?.unwrap();\n            let stringified_2 = ctx.json_stringify(big_int_value)?.unwrap().to_string()?.replace(\"e+\", \"e\");\n            assert_eq!(stringified, stringified_2);\n\n            let big_int_value: Value = ctx.eval(\"999999999999\")?;\n            let stringified = json_stringify(&ctx, big_int_value.clone())?.unwrap();\n            let stringified_2 = ctx.json_stringify(big_int_value)?.unwrap().to_string()?;\n            assert_eq!(stringified, stringified_2);\n\n            Ok(())\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn json_circular_ref() {\n        test_sync_with(|ctx| {\n            let obj1 = Object::new(ctx.clone())?;\n            let obj2 = Object::new(ctx.clone())?;\n            let obj3 = Object::new(ctx.clone())?;\n            let obj4 = Object::new(ctx.clone())?;\n            obj4.set(\"key\", \"value\")?;\n            obj3.set(\"sub2\", obj4.clone())?;\n            obj2.set(\"sub1\", obj3)?;\n            obj1.set(\"root1\", obj2.clone())?;\n            obj1.set(\"root2\", obj2.clone())?;\n            obj1.set(\"root3\", obj2.clone())?;\n\n            let value = obj1.clone().into_value();\n\n            let stringified = json_stringify(&ctx, value.clone())?.unwrap();\n            let stringified_2 = ctx.json_stringify(value.clone())?.unwrap().to_string()?;\n            assert_eq!(stringified, stringified_2);\n\n            obj4.set(\"recursive\", obj1.clone())?;\n\n            let stringified = json_stringify(&ctx, value.clone());\n\n            if let Err(error_message) = stringified.catch(&ctx) {\n                let error_str = error_message.to_string();\n                assert_eq!(\n                    \"Error: Circular reference detected at: \\\"...root1.sub1.sub2.recursive\\\"\\n\",\n                    error_str\n                )\n            } else {\n                panic!(\"Expected an error, but got Ok\");\n            }\n\n            let array1 = Array::new(ctx.clone())?;\n            let array2 = Array::new(ctx.clone())?;\n            let array3 = Array::new(ctx.clone())?;\n\n            let obj5 = Object::new(ctx.clone())?;\n            obj5.set(\"key\", obj1.clone())?;\n            array3.set(2, obj5)?;\n            array2.set(1, array3)?;\n            array1.set(0, array2)?;\n\n            obj4.remove(\"recursive\")?;\n            obj1.set(\"recursiveArray\", array1)?;\n\n            let stringified = json_stringify(&ctx, value.clone());\n\n            if let Err(error_message) = stringified.catch(&ctx) {\n                let error_str = error_message.to_string();\n                assert_eq!(\n                    \"Error: Circular reference detected at: \\\"...recursiveArray[0][1][2].key\\\"\\n\",\n                    error_str\n                )\n            } else {\n                panic!(\"Expected an error, but got Ok\");\n            }\n\n            Ok(())\n        })\n        .await;\n    }\n}\n"
  },
  {
    "path": "libs/llrt_json/src/parse.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nuse llrt_utils::bytes::ObjectBytes;\nuse rquickjs::{Array, Ctx, Exception, IntoJs, Null, Object, Result, Undefined, Value};\nuse simd_json::{Node, StaticNode};\n\npub fn json_parse_string<'js>(ctx: Ctx<'js>, bytes: ObjectBytes<'js>) -> Result<Value<'js>> {\n    let bytes = bytes.as_bytes(&ctx)?;\n    json_parse(&ctx, bytes)\n}\n\npub fn json_parse<'js, T: Into<Vec<u8>>>(ctx: &Ctx<'js>, json: T) -> Result<Value<'js>> {\n    let mut json: Vec<u8> = json.into();\n    let tape = match simd_json::to_tape(&mut json) {\n        Ok(tape) => tape,\n        Err(err) => {\n            let mut itoa = itoa::Buffer::new();\n            let mut error_msg = String::with_capacity(256);\n            let json_length = json.len();\n            if json_length < 128 {\n                error_msg.reserve(json_length);\n                error_msg.push('\\\"');\n                error_msg.push_str(&std::string::String::from_utf8_lossy(&json));\n                error_msg.push_str(\"\\\" \");\n            }\n\n            error_msg.push_str(\"not valid JSON at index \");\n            error_msg.push_str(itoa.format(err.index()));\n            if let Some(char) = err.character() {\n                error_msg.push_str(\" ('\");\n                error_msg.push(char);\n                error_msg.push_str(\"')\");\n            }\n            return Err(Exception::throw_message(ctx, &error_msg));\n        },\n    };\n    let tape = tape.0;\n\n    if let Some(first) = tape.first() {\n        return match first {\n            Node::String(value) => value.into_js(ctx),\n            Node::Static(node) => static_node_to_value(ctx, *node),\n            _ => parse_node(ctx, &tape, 0).map(|(value, _)| value),\n        };\n    }\n\n    Undefined.into_js(ctx)\n}\n\n#[inline(always)]\nfn static_node_to_value<'js>(ctx: &Ctx<'js>, node: StaticNode) -> Result<Value<'js>> {\n    match node {\n        StaticNode::I64(value) => value.into_js(ctx),\n        StaticNode::U64(value) => value.into_js(ctx),\n        StaticNode::F64(value) => value.into_js(ctx),\n        StaticNode::Bool(value) => value.into_js(ctx),\n        StaticNode::Null => Null.into_js(ctx),\n    }\n}\n\nfn parse_node<'js>(ctx: &Ctx<'js>, tape: &[Node], index: usize) -> Result<(Value<'js>, usize)> {\n    match tape[index] {\n        Node::String(value) => Ok((value.into_js(ctx)?, index + 1)),\n        Node::Static(node) => Ok((static_node_to_value(ctx, node)?, index + 1)),\n        Node::Object { len, .. } => {\n            let js_object = Object::new(ctx.clone())?;\n            let mut current_index = index + 1;\n\n            for _ in 0..len {\n                if let Node::String(key) = tape[current_index] {\n                    current_index += 1;\n                    let (value, new_index) = parse_node(ctx, tape, current_index)?;\n                    current_index = new_index;\n                    js_object.set(key, value)?;\n                }\n            }\n\n            Ok((js_object.into_value(), current_index))\n        },\n        Node::Array { len, .. } => {\n            let js_array = Array::new(ctx.clone())?;\n            let mut current_index = index + 1;\n\n            for i in 0..len {\n                let (value, new_index) = parse_node(ctx, tape, current_index)?;\n                current_index = new_index;\n                js_array.set(i, value)?;\n            }\n\n            Ok((js_array.into_value(), current_index))\n        },\n    }\n}\n"
  },
  {
    "path": "libs/llrt_json/src/stringify.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{collections::HashSet, mem, rc::Rc, slice};\n\nuse rquickjs::{\n    atom::PredefinedAtom, function::This, qjs, Ctx, Error, Exception, Function, Object, Result,\n    Type, Value,\n};\n\nuse crate::escape::escape_json_string;\n\nconst CIRCULAR_REF_DETECTION_DEPTH: usize = 20;\n\nstruct StringifyContext<'a, 'js> {\n    ctx: &'a Ctx<'js>,\n    result: &'a mut String,\n    value: &'a Value<'js>,\n    depth: usize,\n    indentation: Option<&'a str>,\n    key: Option<&'a str>,\n    index: Option<usize>,\n    parent: Option<&'a Object<'js>>,\n    ancestors: &'a mut Vec<(usize, Rc<str>)>,\n    replacer_fn: Option<&'a Function<'js>>,\n    include_keys_replacer: Option<&'a HashSet<String>>,\n    itoa_buffer: &'a mut itoa::Buffer,\n    ryu_buffer: &'a mut ryu::Buffer,\n}\n\n#[allow(dead_code)]\npub fn json_stringify<'js>(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Option<String>> {\n    json_stringify_replacer_space(ctx, value, None, None)\n}\n\n#[allow(dead_code)]\npub fn json_stringify_replacer<'js>(\n    ctx: &Ctx<'js>,\n    value: Value<'js>,\n    replacer: Option<Value<'js>>,\n) -> Result<Option<String>> {\n    json_stringify_replacer_space(ctx, value, replacer, None)\n}\n\npub fn json_stringify_replacer_space<'js>(\n    ctx: &Ctx<'js>,\n    value: Value<'js>,\n    replacer: Option<Value<'js>>,\n    indentation: Option<String>,\n) -> Result<Option<String>> {\n    let mut result = String::with_capacity(128);\n    let mut replacer_fn = None;\n    let mut include_keys_replacer = None;\n\n    let tmp_function;\n\n    let mut itoa_buffer = itoa::Buffer::new();\n    let mut ryu_buffer = ryu::Buffer::new();\n\n    if let Some(replacer) = replacer {\n        if let Some(function) = replacer.as_function() {\n            tmp_function = function.clone();\n            replacer_fn = Some(&tmp_function);\n        } else if let Some(array) = replacer.as_array() {\n            let mut filter = HashSet::with_capacity(array.len());\n            for value in array.clone().into_iter() {\n                let value = value?;\n                if let Some(string) = value.as_string() {\n                    filter.insert(string.to_string()?);\n                } else if let Some(number) = value.as_int() {\n                    filter.insert(itoa_buffer.format(number).to_string());\n                } else if let Some(number) = value.as_float() {\n                    filter.insert(ryu_buffer.format(number).to_string());\n                }\n            }\n            include_keys_replacer = Some(filter);\n        }\n    }\n\n    let indentation = indentation.as_deref();\n    let include_keys_replacer = include_keys_replacer.as_ref();\n\n    let mut ancestors = Vec::with_capacity(10);\n\n    let mut context = StringifyContext {\n        ctx,\n        result: &mut result,\n        value: &value,\n        depth: 0,\n        indentation: None,\n        key: None,\n        index: None,\n        parent: None,\n        ancestors: &mut ancestors,\n        replacer_fn,\n        include_keys_replacer,\n        itoa_buffer: &mut itoa_buffer,\n        ryu_buffer: &mut ryu_buffer,\n    };\n\n    match write_primitive(&mut context, false)? {\n        PrimitiveStatus::Written => {\n            return Ok(Some(result));\n        },\n        PrimitiveStatus::Ignored => {\n            return Ok(None);\n        },\n        _ => {},\n    }\n\n    context.depth += 1;\n    context.indentation = indentation;\n    iterate(&mut context, None)?;\n    Ok(Some(result))\n}\n\n#[inline(always)]\n#[cold]\nfn write_indentation(result: &mut String, indentation: Option<&str>, depth: usize) {\n    if let Some(indentation) = indentation {\n        result.push('\\n');\n        result.push_str(&indentation.repeat(depth - 1));\n    }\n}\n\n#[inline(always)]\n#[cold]\nfn run_to_json<'js>(\n    context: &mut StringifyContext<'_, 'js>,\n    js_object: &Object<'js>,\n) -> Result<()> {\n    let to_json = js_object.get::<_, Function>(PredefinedAtom::ToJSON)?;\n    let val: Value = to_json.call((This(js_object.clone()),))?;\n\n    //only preserve indentation if we're returning nested data\n    let indentation = context.indentation.and_then(|indentation| {\n        matches!(\n            val.type_of(),\n            Type::Object | Type::Array | Type::Exception | Type::Proxy\n        )\n        .then_some(indentation)\n    });\n\n    append_value(\n        &mut StringifyContext {\n            ctx: context.ctx,\n            result: context.result,\n            value: &val,\n            depth: context.depth,\n            indentation,\n            key: None,\n            index: None,\n            parent: Some(js_object),\n            ancestors: context.ancestors,\n            replacer_fn: context.replacer_fn,\n            include_keys_replacer: context.include_keys_replacer,\n            itoa_buffer: context.itoa_buffer,\n            ryu_buffer: context.ryu_buffer,\n        },\n        false,\n    )?;\n    Ok(())\n}\n\n#[derive(PartialEq)]\nenum PrimitiveStatus<'js> {\n    Written,\n    Ignored,\n    Iterate(Option<Value<'js>>),\n}\n\n#[inline(always)]\n#[cold]\nfn run_replacer<'js>(\n    context: &mut StringifyContext<'_, 'js>,\n    replacer_fn: &Function<'js>,\n    add_comma: bool,\n) -> Result<PrimitiveStatus<'js>> {\n    let key = context.key;\n    let index = context.index;\n    let value = context.value;\n    let parent = if let Some(parent) = context.parent {\n        parent.clone()\n    } else {\n        let parent = Object::new(context.ctx.clone())?;\n        parent.set(\"\", value.clone())?;\n        parent\n    };\n    let new_value: Value = replacer_fn.call((\n        This(parent),\n        get_key_or_index(context.itoa_buffer, key, index),\n        value,\n    ))?;\n\n    write_primitive2(context, add_comma, Some(new_value))\n}\n\nfn write_primitive<'js>(\n    context: &mut StringifyContext<'_, 'js>,\n    add_comma: bool,\n) -> Result<PrimitiveStatus<'js>> {\n    if let Some(replacer_fn) = context.replacer_fn {\n        return run_replacer(context, replacer_fn, add_comma);\n    }\n\n    write_primitive2(context, add_comma, None)\n}\n\nfn write_primitive2<'js>(\n    context: &mut StringifyContext<'_, 'js>,\n    add_comma: bool,\n    new_value: Option<Value<'js>>,\n) -> Result<PrimitiveStatus<'js>> {\n    let key = context.key;\n    let index = context.index;\n    let include_keys_replacer = context.include_keys_replacer;\n    let indentation = context.indentation;\n    let depth = context.depth;\n\n    let value = new_value.as_ref().unwrap_or(context.value);\n\n    let type_of = value.type_of();\n\n    if context.index.is_none()\n        && matches!(\n            type_of,\n            Type::Symbol | Type::Undefined | Type::Function | Type::Constructor\n        )\n    {\n        return Ok(PrimitiveStatus::Ignored);\n    }\n\n    if matches!(type_of, Type::BigInt) {\n        return Err(Exception::throw_type(\n            context.ctx,\n            \"Do not know how to serialize a BigInt\",\n        ));\n    }\n\n    if let Some(include_keys_replacer) = include_keys_replacer {\n        let key = get_key_or_index(context.itoa_buffer, key, index);\n        if !include_keys_replacer.contains(key) {\n            return Ok(PrimitiveStatus::Ignored);\n        }\n    };\n\n    if let Some(indentation) = indentation {\n        write_indented_separator(context.result, key, add_comma, indentation, depth);\n    } else {\n        write_sep(context.result, add_comma, false);\n        if let Some(key) = key {\n            write_key(context.result, key, false);\n        }\n    }\n\n    match type_of {\n        Type::Null | Type::Undefined => context.result.push_str(\"null\"),\n        Type::Bool => {\n            let bool_str = if unsafe { value.as_bool().unwrap_unchecked() } {\n                \"true\"\n            } else {\n                \"false\"\n            };\n            context.result.push_str(bool_str);\n        },\n        Type::Int => context.result.push_str(\n            context\n                .itoa_buffer\n                .format(unsafe { value.as_int().unwrap_unchecked() }),\n        ),\n        Type::Float => {\n            let float_value = unsafe { value.as_float().unwrap_unchecked() };\n            const EXP_MASK: u64 = 0x7ff0000000000000;\n            let bits = float_value.to_bits();\n            if bits & EXP_MASK == EXP_MASK {\n                context.result.push_str(\"null\");\n            } else {\n                let str = context.ryu_buffer.format_finite(float_value);\n\n                let bytes = str.as_bytes();\n                let len = bytes.len();\n\n                context.result.push_str(str);\n\n                if &bytes[len - 2..] == b\".0\" {\n                    let len = context.result.len();\n                    unsafe { context.result.as_mut_vec().set_len(len - 2) }\n                }\n            }\n        },\n        Type::String => {\n            let js_string = unsafe { value.as_string().unwrap_unchecked() };\n            let mut len = mem::MaybeUninit::uninit();\n            let ctx_ptr = js_string.ctx().as_raw().as_ptr();\n            let ptr =\n                unsafe { qjs::JS_ToCStringLen(ctx_ptr, len.as_mut_ptr(), js_string.as_raw()) };\n            if ptr.is_null() {\n                return Err(Error::Unknown);\n            }\n            let len = unsafe { len.assume_init() };\n            let bytes: &[u8] = unsafe { slice::from_raw_parts(ptr as _, len as _) };\n            let raw_string = unsafe { str::from_utf8_unchecked(bytes) };\n            write_string(context.result, raw_string);\n            unsafe { qjs::JS_FreeCString(js_string.ctx().as_raw().as_ptr(), ptr) };\n        },\n        _ => return Ok(PrimitiveStatus::Iterate(new_value)),\n    }\n    Ok(PrimitiveStatus::Written)\n}\n\n#[inline(always)]\n#[cold]\nfn write_indented_separator(\n    result: &mut String,\n    key: Option<&str>,\n    add_comma: bool,\n    indentation: &str,\n    depth: usize,\n) {\n    write_sep(result, add_comma, true);\n    result.push_str(&indentation.repeat(depth));\n    if let Some(key) = key {\n        write_key(result, key, true);\n    }\n}\n\n#[cold]\nfn detect_circular_reference(\n    ctx: &Ctx<'_>,\n    value: &Object<'_>,\n    key: Option<&str>,\n    index: Option<usize>,\n    parent: Option<&Object<'_>>,\n    ancestors: &mut Vec<(usize, Rc<str>)>,\n    itoa_buffer: &mut itoa::Buffer,\n) -> Result<()> {\n    let parent_ptr = unsafe { qjs::JS_VALUE_GET_PTR(parent.unwrap_unchecked().as_raw()) as usize };\n    let current_ptr = unsafe { qjs::JS_VALUE_GET_PTR(value.as_raw()) as usize };\n\n    while !ancestors.is_empty()\n        && match ancestors.last() {\n            Some((ptr, _)) => ptr != &parent_ptr,\n            _ => false,\n        }\n    {\n        ancestors.pop();\n    }\n\n    if ancestors.iter().any(|(ptr, _)| ptr == &current_ptr) {\n        let mut iter = ancestors.iter_mut();\n\n        let first = &unsafe { iter.next().unwrap_unchecked() }.1;\n\n        let mut message = iter.rev().take(4).rev().fold(\n            String::from(\"Circular reference detected at: \\\"..\"),\n            |mut acc, (_, key)| {\n                if !key.starts_with('[') {\n                    acc.push('.');\n                }\n                acc.push_str(key);\n                acc\n            },\n        );\n\n        if !first.starts_with('[') {\n            message.push('.');\n        }\n\n        message.push_str(first);\n        message.push('\"');\n\n        return Err(Exception::throw_type(ctx, &message));\n    }\n    ancestors.push((\n        current_ptr,\n        key.map(|k| k.into()).unwrap_or_else(|| {\n            [\"[\", itoa_buffer.format(index.unwrap_or_default()), \"]\"]\n                .concat()\n                .into()\n        }),\n    ));\n\n    Ok(())\n}\n\n#[inline(always)]\nfn append_value(context: &mut StringifyContext<'_, '_>, add_comma: bool) -> Result<bool> {\n    match write_primitive(context, add_comma)? {\n        PrimitiveStatus::Written => Ok(true),\n        PrimitiveStatus::Ignored => Ok(false),\n        PrimitiveStatus::Iterate(new_value) => {\n            context.depth += 1;\n            iterate(context, new_value)?;\n            Ok(true)\n        },\n    }\n}\n\n#[inline(always)]\nfn write_key(string: &mut String, key: &str, indent: bool) {\n    string.push('\"');\n    escape_json_string(string, key.as_bytes());\n    string.push_str(\"\\\":\");\n    if indent {\n        string.push(' ');\n    }\n}\n\n#[inline(always)]\nfn write_sep(result: &mut String, add_comma: bool, has_indentation: bool) {\n    if add_comma {\n        result.push(',');\n    }\n    if has_indentation {\n        result.push('\\n');\n    }\n}\n\n#[inline(always)]\nfn write_string(string: &mut String, value: &str) {\n    string.push('\"');\n    escape_json_string(string, value.as_bytes());\n    string.push('\"');\n}\n\n#[inline(always)]\nfn get_key_or_index<'a>(\n    itoa_buffer: &'a mut itoa::Buffer,\n    key: Option<&'a str>,\n    index: Option<usize>,\n) -> &'a str {\n    key.unwrap_or_else(|| itoa_buffer.format(index.unwrap_or_default()))\n}\n\nfn iterate<'js>(\n    context: &mut StringifyContext<'_, 'js>,\n    new_value: Option<Value<'js>>,\n) -> Result<()> {\n    let mut add_comma;\n    let mut value_written;\n    let elem = new_value.as_ref().unwrap_or(context.value);\n    let depth = context.depth;\n    let ctx = context.ctx;\n    let indentation = context.indentation;\n    match elem.type_of() {\n        Type::Object | Type::Exception | Type::Proxy => {\n            let js_object = unsafe { elem.as_object().unwrap_unchecked() };\n            if js_object.contains_key(PredefinedAtom::ToJSON)? {\n                return run_to_json(context, js_object);\n            }\n\n            //only start detect circular reference at this level\n            if depth > CIRCULAR_REF_DETECTION_DEPTH {\n                detect_circular_reference(\n                    ctx,\n                    js_object,\n                    context.key,\n                    context.index,\n                    context.parent,\n                    context.ancestors,\n                    context.itoa_buffer,\n                )?;\n            }\n\n            context.result.push('{');\n\n            value_written = false;\n\n            // Collect keys: js_object.keys() uses JS_GetOwnPropertyNames which can fail for\n            // Proxy objects. Fall back to Object.keys() in that case.\n            let keys: Vec<String> = {\n                let collected: Vec<String> = js_object.keys::<String>().flatten().collect();\n                if collected.is_empty() {\n                    // Clear any pending exception and try Object.keys() for Proxy support\n                    ctx.catch();\n                    ctx.globals()\n                        .get::<_, Object>(\"Object\")\n                        .ok()\n                        .and_then(|o| o.get::<_, Function>(\"keys\").ok())\n                        .and_then(|f| f.call::<_, Vec<String>>((js_object.clone(),)).ok())\n                        .unwrap_or_default()\n                } else {\n                    collected\n                }\n            };\n\n            for key in keys {\n                let val = js_object.get(&key)?;\n\n                add_comma = append_value(\n                    &mut StringifyContext {\n                        ctx,\n                        result: context.result,\n                        value: &val,\n                        depth,\n                        key: Some(&key),\n                        indentation,\n                        index: None,\n                        parent: Some(js_object),\n                        ancestors: context.ancestors,\n                        replacer_fn: context.replacer_fn,\n                        include_keys_replacer: context.include_keys_replacer,\n                        itoa_buffer: context.itoa_buffer,\n                        ryu_buffer: context.ryu_buffer,\n                    },\n                    value_written,\n                )?;\n                value_written = value_written || add_comma;\n            }\n\n            if value_written {\n                write_indentation(context.result, indentation, depth);\n            }\n            context.result.push('}');\n        },\n        Type::Array => {\n            context.result.push('[');\n            add_comma = false;\n            value_written = false;\n            let js_array = unsafe { elem.as_array().unwrap_unchecked() };\n            //only start detect circular reference at this level\n            if depth > CIRCULAR_REF_DETECTION_DEPTH {\n                detect_circular_reference(\n                    ctx,\n                    js_array.as_object(),\n                    context.key,\n                    context.index,\n                    context.parent,\n                    context.ancestors,\n                    context.itoa_buffer,\n                )?;\n            }\n            for (i, val) in js_array.iter::<Value>().enumerate() {\n                let val = val?;\n                add_comma = append_value(\n                    &mut StringifyContext {\n                        ctx,\n                        result: context.result,\n                        value: &val,\n                        depth,\n                        key: None,\n                        indentation,\n                        index: Some(i),\n                        parent: Some(js_array),\n                        ancestors: context.ancestors,\n                        replacer_fn: context.replacer_fn,\n                        include_keys_replacer: context.include_keys_replacer,\n                        itoa_buffer: context.itoa_buffer,\n                        ryu_buffer: context.ryu_buffer,\n                    },\n                    add_comma,\n                )?;\n                value_written = value_written || add_comma;\n            }\n            if value_written {\n                write_indentation(context.result, indentation, depth);\n            }\n            context.result.push(']');\n        },\n        _ => {},\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "libs/llrt_logging/Cargo.toml",
    "content": "[package]\nname = \"llrt_logging\"\ndescription = \"LLRT logging helpers\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[lib]\nname = \"llrt_logging\"\npath = \"src/lib.rs\"\n\n[dependencies]\nitoa = { version = \"1\", default-features = false }\nllrt_context = { version = \"0.8.1-beta\", path = \"../llrt_context\" }\nllrt_encoding = { version = \"0.8.1-beta\", path = \"../llrt_encoding\" }\nllrt_json = { version = \"0.8.1-beta\", path = \"../llrt_json\" }\nllrt_numbers = { version = \"0.8.1-beta\", path = \"../llrt_numbers\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", default-features = false }\nryu = { version = \"1\", default-features = false }\n"
  },
  {
    "path": "libs/llrt_logging/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#![allow(clippy::uninlined_format_args)]\n\nuse std::{\n    collections::HashSet,\n    io::{stderr, stdout, IsTerminal, Write},\n    mem,\n    ops::Deref,\n    process::exit,\n    slice,\n    string::String,\n};\n\nuse llrt_json::stringify::json_stringify;\nuse llrt_numbers::float_to_string;\nuse llrt_utils::{\n    class::get_class_name,\n    error::ErrorExtensions,\n    hash,\n    primordials::{BasePrimordials, Primordial},\n};\nuse rquickjs::{\n    atom::PredefinedAtom,\n    function::This,\n    object::Filter,\n    prelude::Rest,\n    promise::PromiseState,\n    qjs, CaughtError, Coerced, Ctx,\n    Error::{self},\n    Function, Object, Result, Symbol, Type, Value,\n};\n\npub const NEWLINE: char = '\\n';\npub const CARRIAGE_RETURN: char = '\\r';\nconst SPACING: char = ' ';\nconst CIRCULAR: &str = \"[Circular]\";\npub const TIME_FORMAT: &str = \"%Y-%m-%dT%H:%M:%S%.3fZ\";\n\nconst MAX_INDENTATION_LEVEL: usize = 4;\nconst MAX_EXPANSION_DEPTH: usize = 4;\nconst INDENTATION_LOOKUP: [&str; MAX_INDENTATION_LEVEL + 1] =\n    [\"\", \"  \", \"    \", \"        \", \"                \"];\n\nmacro_rules! ascii_colors {\n    ( $( $name:ident => $value:expr ),* ) => {\n        #[derive(Debug, Clone, Copy)]\n        pub enum Color {\n            $(\n                $name,\n            )*\n        }\n\n        impl AsRef<str> for Color {\n            fn as_ref(&self) -> &str {\n                match self {\n                    $(\n                        Color::$name => concat!(\"\\x1b[\", stringify!($value), \"m\"),\n                    )*\n                }\n            }\n        }\n    }\n}\n\nimpl Color {\n    #[inline(always)]\n    fn push(self, value: &mut String) {\n        value.push_str(self.as_ref())\n    }\n\n    #[inline(always)]\n    fn reset(value: &mut String) {\n        value.push_str(Color::RESET.as_ref())\n    }\n}\n\n// Define the colors\nascii_colors!(\n    RESET => 0,\n    BOLD => 1,\n    BLACK => 30,\n    RED => 31,\n    GREEN => 32,\n    YELLOW => 33,\n    BLUE => 34,\n    MAGENTA => 35,\n    CYAN => 36,\n    WHITE => 37\n);\n\n#[derive(Clone)]\npub enum LogLevel {\n    Trace = 0,\n    Debug = 1,\n    Info = 2,\n    Warn = 4,\n    Error = 8,\n    Fatal = 16,\n}\n\ntrait PushByte {\n    fn push_byte(&mut self, byte: u8);\n}\n\nimpl PushByte for String {\n    fn push_byte(&mut self, byte: u8) {\n        unsafe { self.as_mut_vec() }.push(byte);\n    }\n}\n\nimpl LogLevel {\n    #[allow(clippy::inherent_to_string)]\n    #[allow(dead_code)]\n    pub fn to_string(&self) -> String {\n        match self {\n            LogLevel::Trace => String::from(\"TRACE\"),\n            LogLevel::Debug => String::from(\"DEBUG\"),\n            LogLevel::Info => String::from(\"INFO\"),\n            LogLevel::Warn => String::from(\"WARN\"),\n            LogLevel::Error => String::from(\"ERROR\"),\n            LogLevel::Fatal => String::from(\"FATAL\"),\n        }\n    }\n\n    #[allow(clippy::should_implement_trait)]\n    pub fn from_str(s: &str) -> Self {\n        match s {\n            \"TRACE\" => LogLevel::Trace,\n            \"DEBUG\" => LogLevel::Debug,\n            \"INFO\" => LogLevel::Info,\n            \"WARN\" => LogLevel::Warn,\n            \"ERROR\" => LogLevel::Error,\n            \"FATAL\" => LogLevel::Fatal,\n            _ => LogLevel::Info,\n        }\n    }\n}\n\npub struct FormatOptions<'js> {\n    color: bool,\n    newline: bool,\n    get_own_property_desc_fn: Function<'js>,\n    object_prototype: Object<'js>,\n    number_function: Function<'js>,\n    parse_float: Function<'js>,\n    parse_int: Function<'js>,\n    object_filter: Filter,\n    custom_inspect_symbol: Symbol<'js>,\n}\n\nimpl<'js> FormatOptions<'js> {\n    pub fn new(ctx: &Ctx<'js>, color: bool, newline: bool) -> Result<Self> {\n        let primordials = BasePrimordials::get(ctx)?;\n\n        let get_own_property_desc_fn = primordials.function_get_own_property_descriptor.clone();\n        let object_prototype = primordials.prototype_object.clone();\n\n        let parse_float = primordials.function_parse_float.clone();\n        let parse_int = primordials.function_parse_int.clone();\n\n        let object_filter = Filter::new().private().string().symbol();\n\n        let custom_inspect_symbol = primordials.symbol_custom_inspect.clone();\n        let number_function = primordials.constructor_number.deref().clone();\n\n        let options = FormatOptions {\n            color,\n            newline,\n            object_filter,\n            get_own_property_desc_fn,\n            object_prototype,\n            number_function,\n            parse_float,\n            parse_int,\n            custom_inspect_symbol,\n        };\n        Ok(options)\n    }\n}\n\npub fn format_plain<'js>(ctx: Ctx<'js>, newline: bool, args: Rest<Value<'js>>) -> Result<String> {\n    format_values(&ctx, args, false, newline)\n}\n\npub fn format<'js>(ctx: &Ctx<'js>, newline: bool, args: Rest<Value<'js>>) -> Result<String> {\n    format_values(ctx, args, stdout().is_terminal(), newline)\n}\n\npub fn format_values<'js>(\n    ctx: &Ctx<'js>,\n    args: Rest<Value<'js>>,\n    tty: bool,\n    newline: bool,\n) -> Result<String> {\n    let mut result = String::with_capacity(64);\n    let mut options = FormatOptions::new(ctx, tty, newline)?;\n    build_formatted_string(&mut result, ctx, args, &mut options)?;\n    Ok(result)\n}\n\npub fn build_formatted_string<'js>(\n    result: &mut String,\n    ctx: &Ctx<'js>,\n    args: Rest<Value<'js>>,\n    options: &mut FormatOptions<'js>,\n) -> Result<()> {\n    let size = args.len();\n    let mut iter = args.0.into_iter().enumerate().peekable();\n\n    let current_filter = options.object_filter;\n    let default_filter = Filter::default();\n\n    while let Some((index, arg)) = iter.next() {\n        if index == 0 && size > 1 {\n            if let Some(str) = arg.as_string() {\n                let str = str.to_string()?;\n\n                //fast check for format any strings\n                if str.find('%').is_none() {\n                    format_raw_string(result, str, options);\n                    continue;\n                }\n                let bytes = str.as_bytes();\n                let mut i = 0;\n                let len = bytes.len();\n                let mut next_byte;\n                let mut byte;\n                while i < len {\n                    byte = bytes[i];\n                    if byte == b'%' && i + 1 < len {\n                        next_byte = bytes[i + 1];\n                        i += 1;\n                        if iter.peek().is_some() {\n                            i += 1;\n\n                            let mut next_value = || unsafe { iter.next().unwrap_unchecked() }.1;\n\n                            let value = match next_byte {\n                                b's' => {\n                                    let str = next_value().get::<Coerced<String>>()?;\n                                    result.push_str(str.as_str());\n                                    continue;\n                                },\n                                b'd' => options.number_function.call((next_value(),))?,\n                                b'i' => options.parse_int.call((next_value(),))?,\n                                b'f' => options.parse_float.call((next_value(),))?,\n                                b'j' => {\n                                    result.push_str(\n                                        &json_stringify(ctx, next_value())?\n                                            .unwrap_or(\"undefined\".into()),\n                                    );\n                                    continue;\n                                },\n                                b'O' => {\n                                    options.object_filter = default_filter;\n                                    next_value()\n                                },\n                                b'o' => next_value(),\n                                b'c' => {\n                                    // CSS is ignored\n                                    continue;\n                                },\n                                b'%' => {\n                                    result.push_byte(byte);\n                                    continue;\n                                },\n                                _ => {\n                                    result.push_byte(byte);\n                                    result.push_byte(next_byte);\n                                    continue;\n                                },\n                            };\n                            options.color = false;\n\n                            format_raw(result, value, options)?;\n                            options.object_filter = current_filter;\n                            continue;\n                        }\n                        result.push_byte(byte);\n                        result.push_byte(next_byte);\n                    } else {\n                        result.push_byte(byte);\n                    }\n\n                    i += 1;\n                }\n                continue;\n            }\n        }\n        if index != 0 {\n            result.push(SPACING);\n        }\n        format_raw(result, arg, options)?;\n    }\n\n    Ok(())\n}\n\n#[inline(always)]\nfn format_raw<'js>(\n    result: &mut String,\n    value: Value<'js>,\n    options: &FormatOptions<'js>,\n) -> Result<()> {\n    format_raw_inner(result, value, options, &mut HashSet::default(), 0)?;\n    Ok(())\n}\n\nfn format_raw_inner<'js>(\n    result: &mut String,\n    value: Value<'js>,\n    options: &FormatOptions<'js>,\n    visited: &mut HashSet<usize>,\n    depth: usize,\n) -> Result<()> {\n    let value_type = value.type_of();\n\n    let color_enabled = options.color;\n    let is_root = depth == 0;\n\n    match value_type {\n        Type::Uninitialized | Type::Null => {\n            if color_enabled {\n                Color::BOLD.push(result);\n            }\n            result.push_str(\"null\")\n        },\n        Type::Undefined => {\n            if color_enabled {\n                Color::BLACK.push(result);\n            }\n            result.push_str(\"undefined\")\n        },\n        Type::Bool => {\n            if color_enabled {\n                Color::YELLOW.push(result);\n            }\n            let bool_str = if unsafe { value.as_bool().unwrap_unchecked() } {\n                \"true\"\n            } else {\n                \"false\"\n            };\n            result.push_str(bool_str);\n        },\n        Type::BigInt => {\n            if color_enabled {\n                Color::YELLOW.push(result);\n            }\n            let mut buffer = itoa::Buffer::new();\n            let big_int = unsafe { value.as_big_int().unwrap_unchecked() };\n            result.push_str(buffer.format(big_int.clone().to_i64().unwrap()));\n            result.push('n');\n        },\n        Type::Int => {\n            if color_enabled {\n                Color::YELLOW.push(result);\n            }\n            let mut buffer = itoa::Buffer::new();\n            result.push_str(buffer.format(unsafe { value.as_int().unwrap_unchecked() }));\n        },\n        Type::Float => {\n            if color_enabled {\n                Color::YELLOW.push(result);\n            }\n            result.push_str(&float_to_string(unsafe {\n                value.as_float().unwrap_unchecked()\n            }));\n        },\n        Type::String => {\n            //FIXME can be removed if https://github.com/DelSkayn/rquickjs/pull/447 is merged\n            let lossy_string = get_lossy_string(value)?;\n            format_raw_string_inner(result, lossy_string, !is_root, color_enabled);\n        },\n        Type::Symbol => {\n            if color_enabled {\n                Color::YELLOW.push(result);\n            }\n            let description = unsafe { value.as_symbol().unwrap_unchecked() }.description()?;\n            result.push_str(\"Symbol(\");\n            result.push_str(&unsafe { description.get::<String>().unwrap_unchecked() });\n            result.push(')');\n        },\n        Type::Function | Type::Constructor => {\n            if color_enabled {\n                Color::CYAN.push(result);\n            }\n            let obj = unsafe { value.as_object().unwrap_unchecked() };\n\n            const ANONYMOUS: &str = \"(anonymous)\";\n            let mut name: String = obj\n                .get(PredefinedAtom::Name)\n                .unwrap_or(String::with_capacity(ANONYMOUS.len()));\n            if name.is_empty() {\n                name.push_str(ANONYMOUS);\n            }\n\n            let mut is_class = false;\n            if obj.contains_key(PredefinedAtom::Prototype)? {\n                let desc: Object = options\n                    .get_own_property_desc_fn\n                    .call((value, \"prototype\"))?;\n                let writable: bool = desc.get(PredefinedAtom::Writable)?;\n                is_class = !writable;\n            }\n\n            result.push_str(if is_class { \"[class: \" } else { \"[function: \" });\n            result.push_str(&name);\n            result.push(']');\n        },\n        Type::Promise => {\n            let promise = unsafe { value.as_promise().unwrap_unchecked() };\n            let state = promise.state();\n            result.push_str(\"Promise {\");\n            let is_pending = matches!(state, PromiseState::Pending);\n            let apply_indentation = depth < 2 && !is_pending;\n            write_sep(result, false, apply_indentation, options.newline);\n            if apply_indentation {\n                push_indentation(result, depth + 1);\n            }\n\n            match state {\n                PromiseState::Pending => {\n                    if color_enabled {\n                        Color::CYAN.push(result);\n                    }\n                    result.push_str(\"<pending>\");\n                    if color_enabled {\n                        Color::reset(result);\n                    }\n                },\n                PromiseState::Resolved => {\n                    let value: Value = unsafe { promise.result().unwrap_unchecked() }?;\n                    format_raw_inner(result, value, options, visited, depth + 1)?;\n                },\n                PromiseState::Rejected => {\n                    let value: Error =\n                        unsafe { promise.result::<Value>().unwrap_unchecked() }.unwrap_err();\n                    let value = value.into_value(promise.ctx())?;\n                    if color_enabled {\n                        Color::RED.push(result);\n                    }\n                    result.push_str(\"<rejected> \");\n                    if color_enabled {\n                        Color::reset(result);\n                    }\n                    format_raw_inner(result, value, options, visited, depth + 1)?;\n                },\n            }\n            write_sep(result, false, apply_indentation, options.newline);\n            if apply_indentation {\n                push_indentation(result, depth);\n            }\n\n            result.push('}');\n            return Ok(());\n        },\n        Type::Array | Type::Object | Type::Exception | Type::Proxy => {\n            let hash = hash::default_hash(&value);\n            if visited.contains(&hash) {\n                if color_enabled {\n                    Color::CYAN.push(result);\n                }\n                result.push_str(CIRCULAR);\n                if color_enabled {\n                    Color::reset(result);\n                }\n                return Ok(());\n            }\n            visited.insert(hash);\n\n            let obj = unsafe { value.as_object().unwrap_unchecked() };\n\n            if value.is_error() {\n                let name: String = obj.get(PredefinedAtom::Name)?;\n                let message: String = obj.get(PredefinedAtom::Message)?;\n                let stack: Result<String> = obj.get(PredefinedAtom::Stack);\n                result.push_str(&name);\n                result.push_str(\": \");\n                result.push_str(&message);\n                if color_enabled {\n                    Color::BLACK.push(result);\n                }\n\n                if let Ok(stack) = stack {\n                    for line in stack.trim().split('\\n') {\n                        result.push(if options.newline {\n                            NEWLINE\n                        } else {\n                            CARRIAGE_RETURN\n                        });\n                        push_indentation(result, depth + 1);\n                        result.push_str(line);\n                    }\n                }\n                if color_enabled {\n                    Color::reset(result);\n                }\n                return Ok(());\n            }\n\n            let mut class_name: Option<String> = None;\n            let mut is_object = false;\n            if value_type == Type::Object {\n                is_object = true;\n                class_name = get_class_name(&value)?;\n                match class_name.as_deref() {\n                    Some(\"Date\") => {\n                        if color_enabled {\n                            Color::MAGENTA.push(result);\n                        }\n                        let iso_fn: Function = obj.get(\"toISOString\").unwrap();\n                        let str: String = iso_fn.call((This(value),))?;\n                        result.push_str(&str);\n                        if color_enabled {\n                            Color::reset(result);\n                        }\n                        return Ok(());\n                    },\n                    Some(\"RegExp\") => {\n                        if color_enabled {\n                            Color::RED.push(result);\n                        }\n                        let source: String = obj.get(\"source\")?;\n                        let flags: String = obj.get(\"flags\")?;\n                        result.push('/');\n                        result.push_str(&source);\n                        result.push('/');\n                        result.push_str(&flags);\n                        if color_enabled {\n                            Color::reset(result);\n                        }\n                        return Ok(());\n                    },\n                    None | Some(\"\") | Some(\"Object\") => {\n                        class_name = None;\n                    },\n                    _ => {},\n                }\n            }\n\n            if depth < MAX_EXPANSION_DEPTH {\n                let mut is_typed_array = false;\n                if let Some(class_name) = class_name {\n                    result.push_str(&class_name);\n                    result.push(SPACING);\n\n                    //TODO fix when quickjs-ng exposes these types\n                    is_typed_array = matches!(\n                        class_name.as_str(),\n                        \"Int8Array\"\n                            | \"Uint8Array\"\n                            | \"Uint8ClampedArray\"\n                            | \"Int16Array\"\n                            | \"Uint16Array\"\n                            | \"Int32Array\"\n                            | \"Uint32Array\"\n                            | \"Int64Array\"\n                            | \"Uint64Array\"\n                            | \"Float32Array\"\n                            | \"Float64Array\"\n                            | \"Buffer\"\n                    );\n                }\n\n                let is_array = is_typed_array || obj.is_array();\n\n                if let Ok(obj) = &obj.get::<_, Object>(options.custom_inspect_symbol.as_atom()) {\n                    return write_object(\n                        result,\n                        obj,\n                        options,\n                        visited,\n                        depth,\n                        color_enabled,\n                        is_array,\n                    );\n                }\n\n                write_object(\n                    result,\n                    obj,\n                    options,\n                    visited,\n                    depth,\n                    color_enabled,\n                    is_array,\n                )?;\n            } else {\n                if color_enabled {\n                    Color::CYAN.push(result);\n                }\n                result.push_str(if is_object { \"[Object]\" } else { \"[Array]\" });\n            }\n        },\n        _ => {},\n    }\n\n    if color_enabled {\n        Color::reset(result);\n    }\n\n    Ok(())\n}\n\npub fn get_lossy_string(string_value: Value) -> Result<String> {\n    if !string_value.is_string() {\n        return Err(Error::FromJs {\n            from: \"Value\",\n            to: \"JSString\",\n            message: Some(\"Value is not a string\".into()),\n        });\n    }\n\n    let mut len = mem::MaybeUninit::uninit();\n\n    let ctx_ptr = string_value.ctx().as_raw().as_ptr();\n\n    let ptr = unsafe { qjs::JS_ToCStringLen(ctx_ptr, len.as_mut_ptr(), string_value.as_raw()) };\n    if ptr.is_null() {\n        // Might not ever happen but I am not 100% sure\n        // so just incase check it.\n        return Err(Error::Unknown);\n    }\n    let len = unsafe { len.assume_init() };\n    let bytes: &[u8] = unsafe { slice::from_raw_parts(ptr as _, len as _) };\n    let string = replace_invalid_utf8_and_utf16(bytes);\n    unsafe { qjs::JS_FreeCString(ctx_ptr, ptr) };\n\n    Ok(string)\n}\n\nfn format_raw_string(result: &mut String, value: String, options: &FormatOptions<'_>) {\n    format_raw_string_inner(result, value, false, options.color);\n}\n\nfn format_raw_string_inner(result: &mut String, value: String, quoted: bool, color_enabled: bool) {\n    if quoted {\n        if color_enabled {\n            Color::GREEN.push(result);\n        }\n        result.push('\\'');\n    }\n    result.push_str(&value);\n    if quoted {\n        result.push('\\'');\n    }\n}\n\nfn write_object<'js>(\n    result: &mut String,\n    obj: &Object<'js>,\n    options: &FormatOptions<'js>,\n    visited: &mut HashSet<usize>,\n    depth: usize,\n    color_enabled: bool,\n    is_array: bool,\n) -> Result<()> {\n    result.push(if is_array { '[' } else { '{' });\n\n    let mut keys = obj.keys();\n    let mut filter_functions = false;\n    if !is_array && keys.len() == 0 {\n        // Clear any pending exception from JS_GetOwnPropertyNames (e.g. on Proxy objects)\n        let ctx = obj.ctx();\n        ctx.catch();\n        // Try Object.keys() which correctly handles Proxy objects\n        let proxy_keys: Option<Vec<String>> = ctx\n            .globals()\n            .get::<_, Object>(\"Object\")\n            .ok()\n            .and_then(|o| o.get::<_, Function>(\"keys\").ok())\n            .and_then(|f| f.call::<_, Vec<String>>((obj.clone(),)).ok());\n        if let Some(pk) = proxy_keys {\n            if !pk.is_empty() {\n                let apply_indentation = depth < 2;\n                let mut first = false;\n                let length = pk.len();\n                for (i, key) in pk.iter().enumerate() {\n                    let value: Value = obj.get::<&str, _>(key.as_str())?;\n                    let numeric_key = key.parse::<f64>().is_ok();\n                    write_sep(result, first, apply_indentation, options.newline);\n                    if apply_indentation {\n                        push_indentation(result, depth + 1);\n                    }\n                    if depth > MAX_INDENTATION_LEVEL - 1 {\n                        result.push(SPACING);\n                    }\n                    format_raw_string_inner(\n                        result,\n                        key.clone(),\n                        numeric_key,\n                        numeric_key & color_enabled,\n                    );\n                    if numeric_key && color_enabled {\n                        Color::reset(result);\n                    }\n                    result.push(':');\n                    result.push(SPACING);\n                    format_raw_inner(result, value, options, visited, depth + 1)?;\n                    first = true;\n                    if i > 99 {\n                        result.push_str(\"... \");\n                        let mut buffer = itoa::Buffer::new();\n                        result.push_str(buffer.format(length - i));\n                        result.push_str(\" more items\");\n                        break;\n                    }\n                }\n                if first {\n                    if apply_indentation {\n                        result.push(if options.newline {\n                            NEWLINE\n                        } else {\n                            CARRIAGE_RETURN\n                        });\n                        push_indentation(result, depth);\n                    } else {\n                        result.push(SPACING);\n                    }\n                }\n                result.push('}');\n                return Ok(());\n            }\n        }\n        if let Some(proto) = obj.get_prototype() {\n            if proto != options.object_prototype {\n                keys = proto.own_keys(options.object_filter);\n                filter_functions = true;\n            }\n        }\n    }\n    let apply_indentation = !is_array && depth < 2;\n\n    let mut first = false;\n    let mut numeric_key;\n    let length = keys.len();\n    for (i, key) in keys.flatten().enumerate() {\n        let value: Value = obj.get::<&String, _>(&key)?;\n        if !(value.is_function() && filter_functions) {\n            numeric_key = key.parse::<f64>().is_ok();\n            write_sep(result, first, apply_indentation, options.newline);\n\n            if apply_indentation {\n                push_indentation(result, depth + 1);\n            }\n            if depth > MAX_INDENTATION_LEVEL - 1 {\n                result.push(SPACING);\n            }\n            if !is_array {\n                format_raw_string_inner(result, key, numeric_key, numeric_key & color_enabled);\n                if numeric_key && color_enabled {\n                    Color::reset(result);\n                }\n\n                result.push(':');\n                result.push(SPACING);\n            }\n\n            format_raw_inner(result, value, options, visited, depth + 1)?;\n            first = true;\n            if i > 99 {\n                result.push_str(\"... \");\n                let mut buffer = itoa::Buffer::new();\n                result.push_str(buffer.format(length - i));\n                result.push_str(\" more items\");\n                break;\n            }\n        }\n    }\n    if first {\n        if apply_indentation {\n            result.push(if options.newline {\n                NEWLINE\n            } else {\n                CARRIAGE_RETURN\n            });\n            push_indentation(result, depth);\n        } else {\n            result.push(SPACING);\n        }\n    }\n\n    result.push(if is_array { ']' } else { '}' });\n\n    Ok(())\n}\n\n#[inline(always)]\nfn write_sep(result: &mut String, add_comma: bool, has_indentation: bool, newline: bool) {\n    if add_comma {\n        result.push(',');\n    }\n\n    if has_indentation {\n        if newline {\n            result.push('\\n');\n        } else {\n            result.push('\\r')\n        }\n    } else {\n        result.push(' ');\n    }\n}\n\n#[inline(always)]\nfn push_indentation(result: &mut String, depth: usize) {\n    result.push_str(INDENTATION_LOOKUP[depth]);\n}\n\npub fn replace_newline_with_carriage_return(result: &mut str) {\n    //OK since we just modify newlines\n    let str_bytes = unsafe { result.as_bytes_mut() };\n\n    //modify \\n inside of strings, stacks etc\n    let mut pos = 0;\n    while let Some(index) = str_bytes[pos..].iter().position(|b| *b == b'\\n') {\n        str_bytes[pos + index] = b'\\r';\n        pos += index + 1; // Move the position after the found '\\n'\n    }\n}\n\nfn replace_invalid_utf8_and_utf16(bytes: &[u8]) -> String {\n    let mut result = String::with_capacity(bytes.len());\n    let mut i = 0;\n\n    while i < bytes.len() {\n        let current = bytes[i];\n        match current {\n            // ASCII (1-byte)\n            0x00..=0x7F => {\n                result.push(current as char);\n                i += 1;\n            },\n            // 2-byte UTF-8 sequence\n            0xC0..=0xDF => {\n                if i + 1 < bytes.len() {\n                    let next = bytes[i + 1];\n                    if (next & 0xC0) == 0x80 {\n                        let code_point = ((current as u32 & 0x1F) << 6) | (next as u32 & 0x3F);\n                        if let Some(c) = char::from_u32(code_point) {\n                            result.push(c);\n                        } else {\n                            result.push('�');\n                        }\n                        i += 2;\n                    } else {\n                        result.push('�');\n                        i += 1;\n                    }\n                } else {\n                    result.push('�');\n                    i += 1;\n                }\n            },\n            // 3-byte UTF-8 sequence\n            0xE0..=0xEF => {\n                if i + 2 < bytes.len() {\n                    let next1 = bytes[i + 1];\n                    let next2 = bytes[i + 2];\n                    if (next1 & 0xC0) == 0x80 && (next2 & 0xC0) == 0x80 {\n                        let code_point = ((current as u32 & 0x0F) << 12)\n                            | ((next1 as u32 & 0x3F) << 6)\n                            | (next2 as u32 & 0x3F);\n                        if let Some(c) = char::from_u32(code_point) {\n                            result.push(c);\n                        } else {\n                            result.push('�');\n                        }\n                        i += 3;\n                    } else {\n                        result.push('�');\n                        i += 1;\n                    }\n                } else {\n                    result.push('�');\n                    i += 1;\n                }\n            },\n            // 4-byte UTF-8 sequence\n            0xF0..=0xF7 => {\n                if i + 3 < bytes.len() {\n                    let next1 = bytes[i + 1];\n                    let next2 = bytes[i + 2];\n                    let next3 = bytes[i + 3];\n                    if (next1 & 0xC0) == 0x80 && (next2 & 0xC0) == 0x80 && (next3 & 0xC0) == 0x80 {\n                        let code_point = ((current as u32 & 0x07) << 18)\n                            | ((next1 as u32 & 0x3F) << 12)\n                            | ((next2 as u32 & 0x3F) << 6)\n                            | (next3 as u32 & 0x3F);\n                        if let Some(c) = char::from_u32(code_point) {\n                            result.push(c);\n                        } else {\n                            result.push('�');\n                        }\n                        i += 4;\n                    } else {\n                        result.push('�');\n                        i += 1;\n                    }\n                } else {\n                    result.push('�');\n                    i += 1;\n                }\n            },\n            // Invalid starting byte\n            _ => {\n                result.push('�');\n                i += 1;\n            },\n        }\n    }\n\n    result\n}\n\npub fn print_error_and_exit<'js>(ctx: &Ctx<'js>, err: CaughtError<'js>) -> ! {\n    use std::fmt::Write;\n\n    let mut error_str = String::new();\n    write!(error_str, \"Error: {:?}\", err).unwrap();\n\n    if let Ok(error) = err.into_value(ctx) {\n        if print_error(ctx, Rest(vec![error.clone()])).is_err() {\n            eprintln!(\"{}\", error_str);\n        };\n        if cfg!(test) {\n            panic!(\"{:?}\", error);\n        } else {\n            exit(1)\n        }\n    } else if cfg!(test) {\n        panic!(\"{}\", error_str);\n    } else {\n        eprintln!(\"{}\", error_str);\n        exit(1)\n    };\n}\n\nfn print_error<'js>(ctx: &Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n    let is_tty = stderr().is_terminal();\n    let mut result = String::new();\n\n    let mut options = FormatOptions::new(ctx, is_tty, true)?;\n    build_formatted_string(&mut result, ctx, args, &mut options)?;\n\n    result.push(NEWLINE);\n\n    //we don't care if output is interrupted\n    let _ = stderr().write_all(result.as_bytes());\n\n    Ok(())\n}\n"
  },
  {
    "path": "libs/llrt_numbers/Cargo.toml",
    "content": "[package]\nname = \"llrt_numbers\"\ndescription = \"LLRT numbers helpers\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[lib]\nname = \"llrt_numbers\"\npath = \"src/lib.rs\"\n\n[dependencies]\nitoa = { version = \"1\", default-features = false }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", default-features = false }\nryu = { version = \"1\", default-features = false }\n\n[dev-dependencies]\ncriterion = { version = \"0.8\", default-features = false }\nllrt_test = { version = \"0.8.1-beta\", path = \"../llrt_test\" }\nrand = { version = \"0.10.0\", features = [\"alloc\"], default-features = false }\n\n[[bench]]\nname = \"numbers\"\nharness = false\n"
  },
  {
    "path": "libs/llrt_numbers/benches/numbers.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nuse criterion::{criterion_group, criterion_main, Criterion};\nuse llrt_numbers::i64_to_base_n;\nuse rand::RngExt;\nuse std::{fmt::Write, hint::black_box};\n\nmacro_rules! write_formatted {\n    ($format:expr, $number:expr) => {{\n        let digits = ($number as f64).log10() as usize + 2;\n        let mut string = String::with_capacity(digits);\n        write!(string, $format, $number).unwrap();\n        string\n    }};\n}\n\nfn criterion_benchmark(c: &mut Criterion) {\n    let mut rng = rand::rng();\n\n    c.bench_function(\"to_binary\", |b| {\n        b.iter(|| {\n            let num: i64 = rng.random();\n            i64_to_base_n(black_box(num), 2);\n        })\n    });\n\n    c.bench_function(\"to_octal\", |b| {\n        b.iter(|| {\n            let num: i64 = rng.random();\n            i64_to_base_n(black_box(num), 2);\n        })\n    });\n\n    c.bench_function(\"to_dec\", |b| {\n        b.iter(|| {\n            let num: i64 = rng.random();\n            i64_to_base_n(black_box(num), 10);\n        })\n    });\n\n    c.bench_function(\"to_hex\", |b| {\n        b.iter(|| {\n            let num: i64 = rng.random();\n            i64_to_base_n(black_box(num), 16);\n        })\n    });\n\n    c.bench_function(\"write_formatted bin\", |b| {\n        b.iter(|| {\n            let num: i64 = rng.random();\n            write_formatted!(\"{:b}\", black_box(num));\n        })\n    });\n\n    c.bench_function(\"write_formatted octal\", |b| {\n        b.iter(|| {\n            let num: i64 = rng.random();\n            write_formatted!(\"{:o}\", black_box(num));\n        })\n    });\n\n    c.bench_function(\"write_formatted dec\", |b| {\n        b.iter(|| {\n            let num: i64 = rng.random();\n            write_formatted!(\"{}\", black_box(num));\n        })\n    });\n\n    c.bench_function(\"write_formatted hex\", |b| {\n        b.iter(|| {\n            let num: i64 = rng.random();\n            write_formatted!(\"{:x}\", black_box(num));\n        })\n    });\n}\n\ncriterion_group!(benches, criterion_benchmark);\ncriterion_main!(benches);\n"
  },
  {
    "path": "libs/llrt_numbers/src/lib.rs",
    "content": "use llrt_utils::object::ObjectExt;\n// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse rquickjs::{\n    atom::PredefinedAtom,\n    function::{Opt, This},\n    prelude::Func,\n    Ctx, Exception, FromJs, Function, Object, Result, Value,\n};\n\nconst DIGITS: &[u8] = b\"0123456789abcdefghijklmnopqrstuvwxyz\";\nconst BUF_SIZE: usize = 80;\nconst BIN_MAX_DIGITS: usize = 64;\nconst OCT_MAX_DIGITS: usize = 21;\n\npub fn redefine_prototype(ctx: &Ctx<'_>) -> Result<()> {\n    let globals = ctx.globals();\n    let number: Function = globals.get(PredefinedAtom::Number)?;\n    let number_proto: Object = number.get(PredefinedAtom::Prototype)?;\n    number_proto.set(PredefinedAtom::ToString, Func::from(number_to_string))?;\n    Ok(())\n}\n\n#[inline(always)]\npub fn to_dec(number: i64) -> String {\n    itoa::Buffer::new().format(number).into()\n}\n\n#[inline(always)]\npub fn to_base_less_than_10(buf: &mut [u8], num: i64, base: i64) -> String {\n    let max = buf.len();\n\n    if num == 0 {\n        return \"0\".into();\n    }\n    let mut index = max;\n    let mut n = num;\n\n    let mut string = String::with_capacity(max + 1);\n\n    if n < 0 {\n        n = !n + 1;\n        string.push('-');\n    }\n\n    while n > 0 {\n        index -= 1;\n        buf[index] = (n % base) as u8 + b'0';\n        n /= base;\n    }\n\n    string.push_str(unsafe { std::str::from_utf8_unchecked(&buf[index..max]) });\n    string\n}\n\npub fn i64_to_base_n(number: i64, radix: u8) -> String {\n    match radix {\n        10 => {\n            return to_dec(number);\n        },\n        2 => {\n            let mut buf = [0u8; BIN_MAX_DIGITS];\n            return to_base_less_than_10(&mut buf, number, 2);\n        },\n        8 => {\n            let mut buf = [0u8; OCT_MAX_DIGITS];\n            return to_base_less_than_10(&mut buf, number, 8);\n        },\n        _ => {},\n    }\n\n    let mut abs_number = number;\n\n    let mut buf = [0u8; BUF_SIZE];\n    let mut string = String::with_capacity(BUF_SIZE);\n    if number < 0 {\n        abs_number = -number;\n        string.push('-');\n    }\n\n    let index = internal_i64_to_base_n(&mut buf, abs_number, radix);\n\n    string.push_str(unsafe { std::str::from_utf8_unchecked(&buf[index..BUF_SIZE]) });\n    string\n}\n\n#[inline(always)]\nfn internal_i64_to_base_n(buf: &mut [u8], number: i64, radix: u8) -> usize {\n    if number == 0 {\n        buf[BUF_SIZE - 1] = DIGITS[0];\n        return BUF_SIZE - 1;\n    }\n\n    let mut n = number;\n    let mut index = BUF_SIZE;\n\n    while n > 0 {\n        index -= 1;\n        let digit = n % radix as i64;\n        buf[index] = DIGITS[digit as usize];\n        n /= radix as i64;\n    }\n\n    index\n}\n\n#[inline(always)]\nfn next_up(num: f64) -> f64 {\n    const TINY_BITS: u64 = 0x1;\n    const CLEAR_SIGN_MASK: u64 = 0x7fff_ffff_ffff_ffff;\n\n    let bits = num.to_bits();\n    if num.is_nan() || bits == f64::INFINITY.to_bits() {\n        return num;\n    }\n\n    let abs = bits & CLEAR_SIGN_MASK;\n    let next_bits = if abs == 0 {\n        TINY_BITS\n    } else if bits == abs {\n        bits + 1\n    } else {\n        bits - 1\n    };\n    f64::from_bits(next_bits)\n}\n\n#[inline(always)]\nfn fractional_to_base(buf: &mut [u8], mut index: usize, mut number: f64, radix: u8) -> usize {\n    let mut is_odd = number <= 0x1fffffffffffffi64 as f64 && (number as i64) & 1 != 0;\n    let mut digit;\n\n    //let mut needs_rounding_up = false;\n\n    let next_number = next_up(number);\n    let mut delta_next_double = next_number - number;\n\n    loop {\n        let ntmp = number * radix as f64;\n        let rtmp = delta_next_double * radix as f64;\n        digit = ntmp as usize;\n        let ritmp = rtmp as usize;\n\n        if digit & 1 != 0 {\n            is_odd = !is_odd;\n        }\n\n        number = ntmp - digit as f64;\n        delta_next_double = rtmp - ritmp as f64;\n\n        if number > 0.5f64 || number == 0.5f64 && if radix & 1 > 0 { is_odd } else { digit & 1 > 0 }\n        {\n            if number + delta_next_double > 1.0 {\n                //TODO impl round up\n                break;\n            }\n        } else if number < delta_next_double * 2.0 {\n            break;\n        }\n        buf[index] = DIGITS[digit];\n\n        index += 1;\n    }\n\n    // let last_index = index;\n    // while number > 0.0 {\n    //     let tmp = number * radix as f64;\n    //     let itmp = tmp as usize;\n    //     buf[index] = DIGITS[itmp];\n    //     number = tmp - itmp as f64;\n    //     index += 1;\n    //     if index - last_index > BUF_SIZE - last_index - 1 {\n    //         break;\n    //     }\n    // }\n    index\n}\n\n#[inline(always)]\nfn f64_to_base_n(number: f64, radix: u8) -> String {\n    const EXP_MASK: u64 = 0x7ff0000000000000;\n    let bits = number.to_bits();\n    if bits & EXP_MASK == EXP_MASK {\n        return get_nonfinite(bits).to_string();\n    }\n\n    if radix == 10 {\n        let mut result = ryu::Buffer::new().format_finite(number).to_string();\n        if result.ends_with(\".0\") {\n            result.truncate(result.len() - 2);\n        }\n        return result;\n    }\n\n    let mut abs_num = number;\n    let mut string = String::with_capacity(BUF_SIZE);\n    let mut buf = [0u8; BUF_SIZE];\n\n    if number < 0.0 {\n        abs_num = -number;\n        string.push('-');\n    }\n\n    let integer_part = abs_num.trunc();\n    let fractional_part = abs_num - integer_part;\n    let integer_part = abs_num as i64;\n\n    let index = internal_i64_to_base_n(&mut buf, integer_part, radix);\n    string.push_str(unsafe { std::str::from_utf8_unchecked(&buf[index..BUF_SIZE]) });\n\n    if fractional_part > 0.0 {\n        buf.fill(0);\n        let frac_end = fractional_to_base(&mut buf, 0, fractional_part, radix);\n        if frac_end > 0 {\n            string.push('.');\n            string.push_str(unsafe { std::str::from_utf8_unchecked(&buf[0..frac_end]) });\n        }\n    }\n    string\n}\n\npub fn float_to_string(float: f64) -> String {\n    f64_to_base_n(float, 10)\n}\n\n#[inline(always)]\n#[cold]\nfn get_nonfinite<'a>(bits: u64) -> &'a str {\n    const MANTISSA_MASK: u64 = 0x000fffffffffffff;\n    const SIGN_MASK: u64 = 0x8000000000000000;\n    if bits & MANTISSA_MASK != 0 {\n        \"NaN\"\n    } else if bits & SIGN_MASK != 0 {\n        \"-Infinity\"\n    } else {\n        \"Infinity\"\n    }\n}\n\n#[inline(always)]\n#[cold]\nfn check_radix(ctx: &Ctx, radix: u8) -> Result<()> {\n    if !(2..=36).contains(&radix) {\n        return Err(Exception::throw_type(ctx, \"radix must be between 2 and 36\"));\n    }\n    Ok(())\n}\n\nfn number_to_string<'js>(\n    ctx: Ctx<'js>,\n    this: This<Value<'js>>,\n    radix: Opt<Value>,\n) -> Result<String> {\n    let radix = radix\n        .0\n        .and_then(|v| v.as_int())\n        .and_then(|r| u8::try_from(r).ok())\n        .unwrap_or(10);\n    check_radix(&ctx, radix)?;\n\n    // handle primitive number values\n    if let Some(float) = this.as_float() {\n        return Ok(f64_to_base_n(float, radix));\n    }\n    if let Ok(int) = i64::from_js(&ctx, this.0.clone()) {\n        return Ok(i64_to_base_n(int, radix));\n    }\n\n    // handle boxed Number objects\n    if let Some(obj) = this.as_object() {\n        if let Some(value_of) = obj.get_optional::<_, Function>(PredefinedAtom::ValueOf)? {\n            let primitive: Value = value_of.call((this,))?;\n\n            if let Some(float) = primitive.as_float() {\n                return Ok(f64_to_base_n(float, radix));\n            }\n            if let Ok(int) = i64::from_js(&ctx, primitive) {\n                return Ok(i64_to_base_n(int, radix));\n            }\n        }\n    }\n\n    Ok(\"\".into())\n}\n\n#[cfg(test)]\nmod test {\n\n    use rand::RngExt;\n\n    use crate::{float_to_string, i64_to_base_n};\n\n    #[test]\n    fn test_base_conversions() {\n        let mut rng = rand::rng();\n\n        for _ in 0..1_000_000 {\n            // Generate random i64 and radix values\n            let num: i64 = rng.random_range(i64::MIN + 1..i64::MAX - 1);\n\n            let minus_str = if num < 0 { \"-\" } else { \"\" };\n\n            //test bin\n            let expected_bin = format!(\"{}{:b}\", minus_str, num.abs());\n            let actual_bin = i64_to_base_n(num, 2);\n            assert_eq!(expected_bin, actual_bin);\n\n            //test octal\n            let expected_octal = format!(\"{}{:o}\", minus_str, num.abs());\n            let actual_octal = i64_to_base_n(num, 8);\n            assert_eq!(expected_octal, actual_octal);\n\n            //test hex\n            let expected_hex = format!(\"{}{:x}\", minus_str, num.abs());\n            let actual_hex = i64_to_base_n(num, 16);\n            assert_eq!(expected_hex, actual_hex);\n        }\n\n        // Test i64_to_base_n\n        let base_36 = i64_to_base_n(0, 36);\n        assert_eq!(\"0\", base_36);\n\n        let base_36 = i64_to_base_n(123456789, 36);\n        assert_eq!(\"21i3v9\", base_36);\n\n        let base_36 = i64_to_base_n(-123456789, 36);\n        assert_eq!(\"-21i3v9\", base_36);\n\n        let float = float_to_string(123.456);\n        assert_eq!(\"123.456\", float);\n\n        let float = float_to_string(123.);\n        assert_eq!(\"123\", float);\n\n        let float = float_to_string(0.0);\n        assert_eq!(\"0\", float);\n    }\n}\n"
  },
  {
    "path": "libs/llrt_test/Cargo.toml",
    "content": "[package]\nname = \"llrt_test\"\ndescription = \"LLRT test helpers\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[lib]\nname = \"llrt_test\"\npath = \"src/lib.rs\"\n\n[dependencies]\nrquickjs = { version = \"0.11\", features = [\n  \"futures\",\n  \"loader\",\n  \"parallel\",\n], default-features = false }\ntokio = { version = \"1\", features = [\"fs\"], default-features = false }\nuuid = { version = \"1\", features = [\"v4\"], default-features = false }\n"
  },
  {
    "path": "libs/llrt_test/src/lib.rs",
    "content": "use std::{\n    fs,\n    path::{Path, PathBuf},\n};\n\nuse rquickjs::{\n    async_with,\n    function::IntoArgs,\n    loader::{BuiltinLoader, Resolver},\n    markers::ParallelSend,\n    module::{Evaluated, ModuleDef},\n    promise::MaybePromise,\n    AsyncContext, AsyncRuntime, CatchResultExt, CaughtError, Ctx, FromJs, Function, Module, Result,\n};\n\npub async fn given_file(content: &str) -> PathBuf {\n    let tmp_dir = std::env::temp_dir();\n    let path = tmp_dir.join(uuid::Uuid::new_v4().to_string());\n    tokio::fs::write(&path, content).await.unwrap();\n    path\n}\n\nstruct TestResolver;\n\nimpl Resolver for TestResolver {\n    fn resolve(&mut self, _ctx: &Ctx<'_>, base: &str, name: &str) -> Result<String> {\n        if !name.starts_with(\".\") {\n            return Ok(name.into());\n        }\n        let base = Path::new(base);\n        let combined_path = base.join(name);\n        Ok(fs::canonicalize(combined_path)\n            .unwrap()\n            .to_string_lossy()\n            .to_string())\n    }\n}\n\npub async fn given_runtime() -> (AsyncRuntime, AsyncContext) {\n    let rt = AsyncRuntime::new().unwrap();\n    rt.set_loader((TestResolver,), (BuiltinLoader::default(),))\n        .await;\n    let ctx = AsyncContext::full(&rt).await.unwrap();\n\n    (rt, ctx)\n}\n\npub async fn test_async_with<F>(func: F)\nwhere\n    F: for<'js> FnOnce(Ctx<'js>) -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + 'js>>\n        + Send,\n{\n    test_async_with_opts(func, TestOptions::default()).await;\n}\n\n#[derive(Default)]\npub struct TestOptions {\n    no_pending_jobs: bool,\n}\n\nimpl TestOptions {\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    pub fn no_pending_jobs(mut self) -> Self {\n        self.no_pending_jobs = true;\n        self\n    }\n}\n\npub async fn test_async_with_opts<F>(func: F, options: TestOptions)\nwhere\n    F: for<'js> FnOnce(Ctx<'js>) -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + 'js>>\n        + Send,\n{\n    let (rt, ctx) = given_runtime().await;\n\n    async_with!(ctx => |ctx| {\n        func(ctx).await\n    })\n    .await;\n\n    if options.no_pending_jobs {\n        assert!(!rt.is_job_pending().await);\n    }\n}\n\npub async fn test_sync_with<F>(func: F)\nwhere\n    F: for<'js> FnOnce(Ctx<'js>) -> Result<()> + ParallelSend,\n{\n    let (_rt, ctx) = given_runtime().await;\n\n    ctx.with(|ctx| func(ctx.clone()).catch(&ctx).unwrap()).await;\n}\n\npub async fn call_test<'js, T, A>(ctx: &Ctx<'js>, module: &Module<'js, Evaluated>, args: A) -> T\nwhere\n    T: FromJs<'js>,\n    A: IntoArgs<'js>,\n{\n    call_test_err(ctx, module, args).await.unwrap()\n}\n\npub async fn call_test_err<'js, T, A>(\n    ctx: &Ctx<'js>,\n    module: &Module<'js, Evaluated>,\n    args: A,\n) -> std::result::Result<T, CaughtError<'js>>\nwhere\n    T: FromJs<'js>,\n    A: IntoArgs<'js>,\n{\n    module\n        .get::<_, Function>(\"test\")\n        .catch(ctx)?\n        .call::<_, MaybePromise>(args)\n        .catch(ctx)?\n        .into_future::<T>()\n        .await\n        .catch(ctx)\n}\n\npub struct ModuleEvaluator;\n\nimpl ModuleEvaluator {\n    pub async fn eval_js<'js>(\n        ctx: Ctx<'js>,\n        name: &str,\n        source: &str,\n    ) -> Result<Module<'js, Evaluated>> {\n        let (module, module_eval) = Module::declare(ctx, name, source)?.eval()?;\n        module_eval.into_future::<()>().await?;\n        Ok(module)\n    }\n\n    pub async fn eval_rust<'js, M>(ctx: Ctx<'js>, name: &str) -> Result<Module<'js, Evaluated>>\n    where\n        M: ModuleDef,\n    {\n        let (module, module_eval) = Module::evaluate_def::<M, _>(ctx, name)?;\n        module_eval.into_future::<()>().await?;\n        Ok(module)\n    }\n}\n"
  },
  {
    "path": "libs/llrt_test_tls/Cargo.toml",
    "content": "[package]\nname = \"llrt_test_tls\"\ndescription = \"LLRT test helpers for TLS\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[lib]\nname = \"llrt_test_tls\"\npath = \"src/lib.rs\"\n\n[features]\ndefault = [\"tls-ring\"]\ntls-ring = [\"rustls/ring\"]\ntls-aws-lc = [\"rustls/aws_lc_rs\"]\ntls-graviola = [\"dep:rustls-graviola\"]\ntls-openssl = [\"dep:openssl\", \"dep:tokio-openssl\"]\n\n[dependencies]\nhttp-body-util = { version = \"0.1\", default-features = false }\nhyper = { version = \"1\", features = [\"server\"], default-features = false }\nhyper-util = { version = \"0.1\", features = [\n  \"server-auto\",\n  \"tokio\",\n], default-features = false }\nhttp = { version = \"1\", default-features = false }\nrustls = { version = \"0.23\", features = [\"tls12\"], default-features = false }\nrustls-graviola = { version = \"0.3\", git = \"https://github.com/ctz/graviola.git\", default-features = false, optional = true }\nopenssl = { version = \"0.10\", optional = true }\ntokio-openssl = { version = \"0.6\", optional = true }\ntokio = { version = \"1\", features = [\n  \"net\",\n  \"fs\",\n  \"rt\",\n  \"macros\",\n], default-features = false }\ntokio-rustls = { version = \"0.26\", default-features = false }\n"
  },
  {
    "path": "libs/llrt_test_tls/data/generate.sh",
    "content": "#! /bin/bash\n\n# Generate the Root CA private key and certificate\nopenssl req -x509 -newkey rsa:4096 -keyout root.key -out root.pem -days 3650 -nodes -subj \"/CN=Test Root CA\"\n\n# Generate the server private key\nopenssl genrsa -out server.key 2048\n\n# Generate a certificate signing request (CSR) for the server\nopenssl req -new -key server.key -out server.csr -subj \"/CN=localhost\"\n\n# Create a configuration file for certificate extensions\ncat > extensions.cnf << EOF\nsubjectAltName = IP:127.0.0.1, DNS:localhost\nEOF\n\n# Sign the server certificate with the Root CA, including the SAN extension\nopenssl x509 -req -in server.csr -CA root.pem -CAkey root.key -CAcreateserial -out server.pem -days 3650 -sha256 -extfile extensions.cnf\n\n# Clean up temporary files\nrm server.csr root.key root.srl extensions.cnf\n"
  },
  {
    "path": "libs/llrt_test_tls/data/root.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFDzCCAvegAwIBAgIUOBYUfL20Vr/EXJltiNp3uq99ookwDQYJKoZIhvcNAQEL\nBQAwFzEVMBMGA1UEAwwMVGVzdCBSb290IENBMB4XDTI1MTAyMjIzMDk0MloXDTM1\nMTAyMDIzMDk0MlowFzEVMBMGA1UEAwwMVGVzdCBSb290IENBMIICIjANBgkqhkiG\n9w0BAQEFAAOCAg8AMIICCgKCAgEAtWeymY9maWNFNZNh4b2zgh8njhz3+pxrcCAS\n7NeAz/dQnPC2HlGb5BVr7qbFoGBH7tj2pzqQryn91OKrM/Tz0Nc+paUSUn+tZ1BC\nYi8wS2H0czxekLTRB74++faGaC/jNWRsm5JosXuLAKl3eRvYVZWdOxctrebZe5sQ\naj0ohtnzPoiPvc7wagIeKq9bXHR9HwTHaV98mU9Uv/ApOlqU2Hsi6dXfMaLb8+lq\nSQm4eBwFl0qHGpALNR8Q6DNCSOK+Lwc9Ras78XCczvH6VQRz1PoTizpjWNTus9GO\nFYw8LvRAdYkrRWPliZZvQZ4faQYd71EiLQ/AP+YP8XlKpmE/OYYd5Gmr0aOnyzXw\nP9RR7y8M/NJ6M58TlgG6GQZg5aLgciDMPe+emwioTzbAqpsyvONoDoixKKGbf3S5\nWUOvx/vtD827ghMuElKlp6AmKjbxZvlwMYtgzD+SYpNxKX69a73JyjNX+cEpwPIc\nFkJlriLH3Ay4+hqQubrWSFicFYCFSzUsdxFjeJw09CAD311PXqQ5qYPfNj35+78j\nUgO6K0ndkcoNe/GR22TGt6ji+5HkqdlbL347K1cgFLiyHrtiv83Fht3oW/gGKuKn\n7zyxXbxs0ZsqBu+lsiev7nIJ48BiFkUiixevfBbzogcMeWlmOEzLSm+K1h66bW97\nSqbXl/ECAwEAAaNTMFEwHQYDVR0OBBYEFOLMOJB8sUEiTBowDMsUeX9F8Nj8MB8G\nA1UdIwQYMBaAFOLMOJB8sUEiTBowDMsUeX9F8Nj8MA8GA1UdEwEB/wQFMAMBAf8w\nDQYJKoZIhvcNAQELBQADggIBAE0SgC8r+VvVgQQcLjT1PtLrLGyRrhhb5ZUqMlPA\nfPTeQ9zRDy8wRmFYpNKyiMOU/y1+aaLOcYyObK2F67x6N7HTQrqSbTUQtXPD4Tt8\nioWxVwkeoLK9U8z6UAYXqIiWzJI33vRahezuhi3qLmPX9Z4WDAckLMBAvWBpy2dP\noix/R0eGwBhVDVyBoWSu1GjEkT2asaVHaxBU+XiqD2Z2U63HbmBY/OeI34RB89il\nH5RDBgCxouOZnQ5nDXUSoRXh5/n2kA3Vnmdh6+E6rEaKpSldJrChd2PgG13Ay/Iv\n+SV55PsFWTz6M2vVzkhJ9oROuGU8+jwSK5kctsLUSUVUZK48WCskYrMSzLj2UGqY\nfJEl7P2f6u7RVJQP7Ylie83Dl3k02HYkUbPJ4K7dEVd5ssqGZqVczowOBMDpiQdt\nmYEgpCq007zc3Kdk1rfBK3Q5WoExqnARp5u6Wm5lVVPJfVqahLAdnDvrTZRfVuM2\nELwXmlm1EdUknSe1jfqg8FQFZcPr49S98wRrXrwPonx1z4OMblTWCSbq2dE5bS11\nm33uSe7YGm0dXLZWD7jFLTNlqnheLdJ7RGK4MZClQT5Ajnu9Zx9ICC1MC3gIzz/u\nKJ5/8GHc+gueSZApK4LNavBZAA6Yjz6SGzEvA+xCU6Tvh6JS6mpjfq2eH6hh8WZp\nfltd\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "libs/llrt_test_tls/data/server.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDRq3fEYZS2w2gu\nbl6yOqyZbOkRZ8m80/65p8LTjL3drCyL0F3BPwN0s3+Qaq/7Mi8cOrZSa7Zq/Lhy\noQ9JufmcUSMOK0+CMZW74VhdIf0ltGCXNVtwib/sfFBbCVFul5elfIGeGjsTJbOz\n+OHNTXO7Dpe3vFRMGZh9/oeBngkpRJE6zWedB88Q2OuGbIhXVT0yeZyFpxI0tUjO\neUgOJm5Qc8hdE2gRfasnuhFqb/ddrXZavKrUvBSoNTMigPCU+v5dw0jUWiO4FSkb\n/kxR2ea66NnvfChFV97ZIRpm0MB9qMTgveA+xheE6cvcwTTvt619sg9i+qOIGvd6\nyAxheJVbAgMBAAECggEAGnGHQefSszgy6AQ4gj7/LLx9KppN6bhM/IpJepfaDF6e\nIaYOZQR3AZ1v3b1u434BTgyjmQKHt7eW5bIldPV1Iz9ibfONbAyn51G07M4QGNTG\nh9uNZESjRYaqNckXkZyh3he1W0TQpYoQP4cIp3V4vqNJBD3G3fAueNmEqpbNbfxC\n1noFKDKp/QQhWNbq+KhASIlSBLTs6uFYO6Jl5BCmVNxJrubT+gpJtKFroGMYZXAs\ne2AYuuqUNPuijg8/qRCFdcd8wUpg+/Ky4q98l1ZkyZJ9E4SxlUU5LSzPjvnvM6JT\nIZ48sV6XdXDre3Kep/RpOeEc+BGDxXQUvAw5Dqa5UQKBgQDz5vc55hNN/8VD2Y5l\n8PR/nqxI4WUiqQ29hfGkEPC2Necx6CdQbqGSyExTjlsKVyGNK9ojNnsMS1GsjK2Q\nCKm0YzOmSCwHpW8JHRN4GAyRNXO3v+7R1SyNTQijdtRCSlfbM2DtY9ABjBkxWkCR\np7ZTJyES2mji3JAXEsQi6mnvywKBgQDcEdLwFsHj1Mkv0Gpd0U1ei8bt5bv+M4vS\nDiSzCu3h7mUM61AS9qWHvEtum6ci7naqnjI7tINu3PaebYGOt8QKNp4dBKhRLg23\nZBtuYSMbgvii87yRJZwe4Ujl0v8itOsFlbhOh4toX0oz02n6fxZMx2MjDqH0vDXG\nXsly6GAesQKBgFUCOUTq1eunq9+cIi+RrgYVDcNRG+jatzlJSBGA/gTkALK6UYmN\nJa99NG0i/sQ53i3QDPWc9YIxdkQHvC6pdkyzDrt0CDSaCntIsRJ4f1jVIoH22Yw1\nGpQdN1eSASUhuEFkRPI4ibUgWV+EL2EU7U1KJBLoIQqBCY+hMM9imI3FAoGBAMfU\nz4v/vjQZpk5qnAtw4SZ3Gj4vnBNpzw8AlMaXqAa+KLggfOebXBfzHTPk11Ha45pu\naALbGXXz42Vc3oYvzC3SBqUm84gzn3TlzBrgzbZPqWKenJ3YXvmTbFR00gQ78CV0\nHJYCcs5lqMWCtfsmp6M0cosE4H+Q3+uvapGS/KUhAoGAAbj8iOwtpZHLr3Jy40RA\nwJ+WsSgLHaUNqmHt3kaHmKgXTHLISXBIKxPir4l6oxQOasfFIY3FyZqyxgvcMoGg\nKU4jee5HlnOE+F9+6Tuj40JsWOsol2QF4b89H5NYidWTSiXwAnEFod3vFkx9O5Ih\nZ89D8ERKGlAkt65/JwhaREM=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "libs/llrt_test_tls/data/server.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEFzCCAf+gAwIBAgIUC+QvCSehYQJLL3qSNURTKQPBtJAwDQYJKoZIhvcNAQEL\nBQAwFzEVMBMGA1UEAwwMVGVzdCBSb290IENBMB4XDTI1MTAyMjIzMDk0MloXDTM1\nMTAyMDIzMDk0MlowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0B\nAQEFAAOCAQ8AMIIBCgKCAQEA0at3xGGUtsNoLm5esjqsmWzpEWfJvNP+uafC04y9\n3awsi9BdwT8DdLN/kGqv+zIvHDq2Umu2avy4cqEPSbn5nFEjDitPgjGVu+FYXSH9\nJbRglzVbcIm/7HxQWwlRbpeXpXyBnho7EyWzs/jhzU1zuw6Xt7xUTBmYff6HgZ4J\nKUSROs1nnQfPENjrhmyIV1U9MnmchacSNLVIznlIDiZuUHPIXRNoEX2rJ7oRam/3\nXa12Wryq1LwUqDUzIoDwlPr+XcNI1FojuBUpG/5MUdnmuujZ73woRVfe2SEaZtDA\nfajE4L3gPsYXhOnL3ME077etfbIPYvqjiBr3esgMYXiVWwIDAQABo14wXDAaBgNV\nHREEEzARhwR/AAABgglsb2NhbGhvc3QwHQYDVR0OBBYEFAFfcsd3+6bt4gEQRajq\n6neUr521MB8GA1UdIwQYMBaAFOLMOJB8sUEiTBowDMsUeX9F8Nj8MA0GCSqGSIb3\nDQEBCwUAA4ICAQAWD2+odwJKfjTVTIPEFDRH7pD9O57oHqVGP4kxDffEUM/q8cPH\nXbNUgSPMi9XD4RH5EHFjDgTPfk2W3SLVSz3avWimKiagfHBTsVSpU7Sc6ZmXjFmC\n1+hqh9PqYKGpy01BoRlMCF/Ho4tIEMGZRp/gvJm0/+HdiQ8JvFsKjbxYKqtC0CYP\nYjyq7XLIJRCJsnTOfy1CwVkLp87Whgutnk6eF1xuyYSU94hzuJGTNe5SRyb2THV4\n8MPGM7BV1mt4lp3pyM5YXo0HzDkC+1rZvHAjzcXz5D7BOOdwnWfHRHZJu9dmfqCa\nSd78lGSm+d2iCuX3HjjmMHyWxdtgc1KwMcLMp1DP2eXN4Zq+Hm0euEpAtLz7TEh4\nzoEb3hRcFcZ5IAOOXbQQJ2KZEdQPN3iD8o7sEOkIk5IDksaEtmhPkZrdtR2RYvlK\n78IXjfFDzNLNbtMln1FnXqpQ0NC58YeM8rmqfP7pbcN6BbJ6n8Iw0DZx06u7qDUh\nPevtQ0/2k/UMPnj48E4n5BaYK7CQY/XydLUBhJk8pXKl3mj80Se6Ker5nY+w3RRp\n3VHJjGaruy2oW73JpME/NUFM8fUhJPEKEVUmMpSs1eX00NfvM7m0//hX9WQr51Rp\nko83cvhMQaddRbUNNghRTumt7ISd21bpvG3QBGhNcQZ6hJBTUAFdX+wWGg==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "libs/llrt_test_tls/src/api.rs",
    "content": "use http::{Method, Request, Response, StatusCode};\nuse http_body_util::{BodyExt, Full};\nuse hyper::body::{Bytes, Incoming};\n\npub(crate) async fn echo(req: Request<Incoming>) -> Result<Response<Full<Bytes>>, hyper::Error> {\n    let mut response = Response::new(Full::default());\n    match (req.method(), req.uri().path()) {\n        // Help route.\n        (&Method::GET, \"/\") => {\n            *response.body_mut() = Full::from(\"Try POST /echo\\n\");\n        },\n        // Echo service route.\n        (&Method::POST, \"/echo\") => {\n            *response.body_mut() = Full::from(req.into_body().collect().await?.to_bytes());\n        },\n        // Catch-all 404.\n        _ => {\n            *response.status_mut() = StatusCode::NOT_FOUND;\n        },\n    };\n    Ok(response)\n}\n"
  },
  {
    "path": "libs/llrt_test_tls/src/config.rs",
    "content": "use rustls::pki_types::{pem::PemObject, CertificateDer, PrivateKeyDer};\nuse std::path::PathBuf;\n\npub enum FileType {\n    RootCert,\n    ServerCert,\n    ServerKey,\n}\n\nimpl FileType {\n    pub fn default_path(&self) -> PathBuf {\n        let manifest_dir = env!(\"CARGO_MANIFEST_DIR\");\n        let data_dir = PathBuf::from(manifest_dir).join(\"data\");\n        match self {\n            Self::RootCert => data_dir.join(\"root.pem\"),\n            Self::ServerCert => data_dir.join(\"server.pem\"),\n            Self::ServerKey => data_dir.join(\"server.key\"),\n        }\n    }\n}\n\npub struct MockServerCerts {\n    pub root_cert: CertificateDer<'static>,\n    pub server_cert: CertificateDer<'static>,\n    pub server_key: PrivateKeyDer<'static>,\n}\n\nimpl MockServerCerts {\n    pub async fn load_default() -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {\n        let certfile = tokio::fs::read(FileType::RootCert.default_path()).await?;\n        let root_cert = CertificateDer::from_pem_slice(&certfile)?;\n\n        let certfile = tokio::fs::read(FileType::ServerCert.default_path()).await?;\n        let server_cert = CertificateDer::from_pem_slice(&certfile)?;\n\n        let keyfile = tokio::fs::read(FileType::ServerKey.default_path()).await?;\n        let server_key = PrivateKeyDer::from_pem_slice(&keyfile)?;\n\n        Ok(Self {\n            root_cert,\n            server_cert,\n            server_key,\n        })\n    }\n}\n"
  },
  {
    "path": "libs/llrt_test_tls/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\n// FIXME this library is only needed until TLS is natively supported in wiremock.\n// See https://github.com/LukeMathWalker/wiremock-rs/issues/58\n\n#[cfg(all(feature = \"tls-ring\", feature = \"tls-aws-lc\"))]\ncompile_error!(\"Features 'tls-ring' and 'tls-aws-lc' are mutually exclusive\");\n\n#[cfg(all(feature = \"tls-ring\", feature = \"tls-graviola\"))]\ncompile_error!(\"Features 'tls-ring' and 'tls-graviola' are mutually exclusive\");\n\n#[cfg(all(feature = \"tls-aws-lc\", feature = \"tls-graviola\"))]\ncompile_error!(\"Features 'tls-aws-lc' and 'tls-graviola' are mutually exclusive\");\n\nuse std::net::{Ipv4Addr, SocketAddr};\n\nuse tokio::net::TcpListener;\n\nuse self::config::{FileType, MockServerCerts};\n\nmod api;\nmod config;\nmod server;\n\npub struct MockServer {\n    addr: SocketAddr,\n    ca: String,\n    shutdown_tx: tokio::sync::watch::Sender<()>,\n}\n\nimpl MockServer {\n    pub async fn start() -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {\n        let (shutdown_tx, shutdown_rx) = tokio::sync::watch::channel(());\n\n        // Load the certificates for the mock server.\n        let certs = MockServerCerts::load_default().await?;\n        let ca = String::from_utf8(tokio::fs::read(FileType::RootCert.default_path()).await?)?;\n\n        // Bind to a random port on localhost.\n        let incoming = TcpListener::bind(&SocketAddr::from((Ipv4Addr::LOCALHOST, 0))).await?;\n        let addr = incoming.local_addr()?;\n\n        tokio::spawn(async move {\n            if let Err(e) = server::run(incoming, certs, shutdown_rx).await {\n                println!(\"failed to run mock server: {e:#}\");\n            }\n        });\n\n        Ok(Self {\n            addr,\n            ca,\n            shutdown_tx,\n        })\n    }\n\n    pub fn address(&self) -> SocketAddr {\n        self.addr\n    }\n\n    pub fn ca(&self) -> &str {\n        &self.ca\n    }\n}\n\nimpl Drop for MockServer {\n    fn drop(&mut self) {\n        let _ = self.shutdown_tx.send(());\n    }\n}\n"
  },
  {
    "path": "libs/llrt_test_tls/src/server.rs",
    "content": "#[cfg(any(feature = \"tls-ring\", feature = \"tls-aws-lc\", feature = \"tls-graviola\"))]\nuse std::sync::Arc;\n\n#[cfg(any(\n    feature = \"tls-ring\",\n    feature = \"tls-aws-lc\",\n    feature = \"tls-graviola\",\n    feature = \"tls-openssl\"\n))]\nuse hyper::service::service_fn;\n#[cfg(any(\n    feature = \"tls-ring\",\n    feature = \"tls-aws-lc\",\n    feature = \"tls-graviola\",\n    feature = \"tls-openssl\"\n))]\nuse hyper_util::rt::{TokioExecutor, TokioIo};\n#[cfg(any(\n    feature = \"tls-ring\",\n    feature = \"tls-aws-lc\",\n    feature = \"tls-graviola\",\n    feature = \"tls-openssl\"\n))]\nuse hyper_util::server::conn::auto::Builder;\n#[cfg(any(\n    feature = \"tls-ring\",\n    feature = \"tls-aws-lc\",\n    feature = \"tls-graviola\",\n    feature = \"tls-openssl\"\n))]\nuse tokio::net::TcpListener;\n\n#[cfg(any(\n    feature = \"tls-ring\",\n    feature = \"tls-aws-lc\",\n    feature = \"tls-graviola\",\n    feature = \"tls-openssl\"\n))]\nuse crate::MockServerCerts;\n\n#[cfg(feature = \"tls-ring\")]\nfn get_crypto_provider() -> Arc<rustls::crypto::CryptoProvider> {\n    Arc::new(rustls::crypto::ring::default_provider())\n}\n\n#[cfg(feature = \"tls-aws-lc\")]\nfn get_crypto_provider() -> Arc<rustls::crypto::CryptoProvider> {\n    Arc::new(rustls::crypto::aws_lc_rs::default_provider())\n}\n\n#[cfg(feature = \"tls-graviola\")]\nfn get_crypto_provider() -> Arc<rustls::crypto::CryptoProvider> {\n    Arc::new(rustls_graviola::default_provider())\n}\n\n#[cfg(any(feature = \"tls-ring\", feature = \"tls-aws-lc\", feature = \"tls-graviola\"))]\npub(super) async fn run(\n    listener: TcpListener,\n    certs: MockServerCerts,\n    shutdown_rx: tokio::sync::watch::Receiver<()>,\n) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n    use rustls::ServerConfig;\n    use tokio_rustls::TlsAcceptor;\n\n    let cert_chain = vec![certs.server_cert, certs.root_cert];\n    let mut server_config = ServerConfig::builder_with_provider(get_crypto_provider())\n        .with_safe_default_protocol_versions()?\n        .with_no_client_auth()\n        .with_single_cert(cert_chain, certs.server_key)?;\n    server_config.alpn_protocols = vec![b\"h2\".to_vec(), b\"http/1.1\".to_vec(), b\"http/1.0\".to_vec()];\n    let tls_acceptor = TlsAcceptor::from(Arc::new(server_config));\n\n    let service = service_fn(crate::api::echo);\n\n    loop {\n        let (tcp_stream, _remote_addr) = listener.accept().await?;\n\n        let mut shutdown_signal = shutdown_rx.clone();\n        let tls_acceptor = tls_acceptor.clone();\n\n        tokio::spawn(async move {\n            let tls_stream = match tls_acceptor.accept(tcp_stream).await {\n                Ok(tls_stream) => tls_stream,\n                Err(err) => {\n                    eprintln!(\"failed to perform tls handshake: {err:#}\");\n                    return;\n                },\n            };\n\n            let http_server = Builder::new(TokioExecutor::new());\n            let conn = http_server.serve_connection(TokioIo::new(tls_stream), service);\n            tokio::pin!(conn);\n\n            loop {\n                tokio::select! {\n                    _ = conn.as_mut() => break,\n                    _ = shutdown_signal.changed() => conn.as_mut().graceful_shutdown(),\n                }\n            }\n        });\n    }\n}\n\n#[cfg(feature = \"tls-openssl\")]\npub(super) async fn run(\n    listener: TcpListener,\n    certs: MockServerCerts,\n    shutdown_rx: tokio::sync::watch::Receiver<()>,\n) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n    use openssl::ssl::{SslAcceptor, SslMethod};\n\n    let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls())?;\n\n    // Convert rustls certs to OpenSSL format\n    let cert_der = certs.server_cert.as_ref();\n    let key_der = match certs.server_key {\n        rustls::pki_types::PrivateKeyDer::Pkcs1(ref key) => key.secret_pkcs1_der().to_vec(),\n        rustls::pki_types::PrivateKeyDer::Pkcs8(ref key) => key.secret_pkcs8_der().to_vec(),\n        rustls::pki_types::PrivateKeyDer::Sec1(ref key) => key.secret_sec1_der().to_vec(),\n        _ => return Err(\"Unsupported key format\".into()),\n    };\n\n    let cert = openssl::x509::X509::from_der(cert_der)?;\n    let pkey = openssl::pkey::PKey::private_key_from_der(&key_der)?;\n\n    builder.set_certificate(&cert)?;\n    builder.set_private_key(&pkey)?;\n\n    let root_cert = openssl::x509::X509::from_der(certs.root_cert.as_ref())?;\n    builder.add_extra_chain_cert(root_cert)?;\n\n    builder.set_alpn_protos(b\"\\x02h2\\x08http/1.1\\x08http/1.0\")?;\n\n    let acceptor = builder.build();\n    let service = service_fn(crate::api::echo);\n\n    loop {\n        let (tcp_stream, _remote_addr) = listener.accept().await?;\n\n        let mut shutdown_signal = shutdown_rx.clone();\n        let acceptor = acceptor.clone();\n\n        tokio::spawn(async move {\n            let ssl = match openssl::ssl::Ssl::new(acceptor.context()) {\n                Ok(ssl) => ssl,\n                Err(err) => {\n                    eprintln!(\"failed to create ssl: {err:#}\");\n                    return;\n                },\n            };\n\n            let tls_stream = match tokio_openssl::SslStream::new(ssl, tcp_stream) {\n                Ok(mut stream) => {\n                    if let Err(err) = std::pin::Pin::new(&mut stream).accept().await {\n                        eprintln!(\"failed to perform tls handshake: {err:#}\");\n                        return;\n                    }\n                    stream\n                },\n                Err(err) => {\n                    eprintln!(\"failed to create ssl stream: {err:#}\");\n                    return;\n                },\n            };\n\n            let http_server = Builder::new(TokioExecutor::new());\n            let conn = http_server.serve_connection(TokioIo::new(tls_stream), service);\n            tokio::pin!(conn);\n\n            loop {\n                tokio::select! {\n                    _ = conn.as_mut() => break,\n                    _ = shutdown_signal.changed() => conn.as_mut().graceful_shutdown(),\n                }\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "libs/llrt_utils/Cargo.toml",
    "content": "[package]\nname = \"llrt_utils\"\ndescription = \"LLRT utilities\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[features]\ndefault = [\"all\"]\nall = [\"fs\", \"bytearray-buffer\"]\n\nfs = [\"tokio/fs\"]\nbytearray-buffer = [\"tokio/sync\"]\n\n[dependencies]\nrquickjs = { version = \"0.11\", features = [\"macro\"], default-features = false }\ntokio = { version = \"1\", features = [\"sync\"], default-features = false }\ntracing = { version = \"0.1\", default-features = false }\n\n[target.'cfg(unix)'.dependencies]\nlibc = { version = \"0.2\", default-features = false }\n\n[target.'cfg(windows)'.dependencies]\nwindows-sys = { version = \"0.61\", features = [\n  \"Win32_Foundation\",\n  \"Win32_System_Threading\",\n], default-features = false }\n\n[dev-dependencies]\nllrt_test = { version = \"0.8.1-beta\", path = \"../llrt_test\" }\ntokio = { version = \"1\", features = [\"full\"] }\n\n[build-dependencies]\nllrt_build = { version = \"0.8.1-beta\", path = \"../llrt_build\" }\n"
  },
  {
    "path": "libs/llrt_utils/src/any_of.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse rquickjs::{\n    class::{Trace, Tracer},\n    Ctx, FromJs, IntoJs, JsLifetime, Result, Value,\n};\n\nmacro_rules! define_any_of {\n    ($name:ident, $($variant:ident),+) => {\n        #[derive(Debug, Clone)]\n        pub enum $name<$($variant),+> {\n            $(\n                $variant($variant),\n            )+\n        }\n\n        define_any_of_from_js!($name, $($variant),+);\n\n        impl<'js, $($variant: IntoJs<'js>),+> IntoJs<'js> for $name<$($variant),+> {\n            fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {\n                match self {\n                    $(\n                        Self::$variant(val) => val.into_js(ctx),\n                    )+\n                }\n            }\n        }\n\n        unsafe impl<'js, $($variant: JsLifetime<'js>),+> JsLifetime<'js> for $name<$($variant),+> {\n            type Changed<'to> = $name<$($variant::Changed<'to>),+>;\n        }\n\n        impl<'js, $($variant: Trace<'js>),+> Trace<'js> for $name<$($variant),+> {\n            fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n                match self {\n                    $(\n                        Self::$variant(val) => val.trace(tracer),\n                    )+\n                }\n            }\n        }\n\n        define_any_of_methods!($name, $($variant),+);\n    };\n}\n\nmacro_rules! define_any_of_from_js {\n    ($name:ident, $first:ident, $($rest:ident),+) => {\n        impl<'js, $first: FromJs<'js>, $($rest: FromJs<'js>),+> FromJs<'js> for $name<$first, $($rest),+> {\n            fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n                define_any_of_from_js_impl!($name, ctx, value, $first, $($rest),+)\n            }\n        }\n    };\n}\n\nmacro_rules! define_any_of_from_js_impl {\n    ($name:ident, $ctx:ident, $value:ident, $first:ident) => {\n        $first::from_js($ctx, $value).map($name::$first)\n    };\n\n    ($name:ident, $ctx:ident, $value:ident, $first:ident, $($rest:ident),+) => {\n        $first::from_js($ctx, $value.clone()).map($name::$first).or_else(|error| {\n            if error.is_from_js() {\n                define_any_of_from_js_impl!($name, $ctx, $value, $($rest),+)\n            } else {\n                Err(error)\n            }\n        })\n    };\n}\n\nmacro_rules! define_any_of_variant_methods {\n    ($variant:ident, $is_fn:ident, $as_fn:ident, $as_mut_fn:ident, $into_fn:ident) => {\n        #[allow(dead_code)]\n        pub fn $is_fn(&self) -> bool {\n            matches!(self, Self::$variant(_))\n        }\n\n        #[allow(dead_code)]\n        pub fn $as_fn(&self) -> Option<&$variant> {\n            match self {\n                Self::$variant(val) => Some(val),\n                _ => None,\n            }\n        }\n\n        #[allow(dead_code)]\n        pub fn $as_mut_fn(&mut self) -> Option<&mut $variant> {\n            match self {\n                Self::$variant(val) => Some(val),\n                _ => None,\n            }\n        }\n\n        #[allow(dead_code)]\n        pub fn $into_fn(self) -> std::result::Result<$variant, Self> {\n            match self {\n                Self::$variant(val) => Ok(val),\n                other => Err(other),\n            }\n        }\n    };\n\n    (A) => {\n        define_any_of_variant_methods!(A, is_a, as_a, as_a_mut, into_a);\n    };\n    (B) => {\n        define_any_of_variant_methods!(B, is_b, as_b, as_b_mut, into_b);\n    };\n    (C) => {\n        define_any_of_variant_methods!(C, is_c, as_c, as_c_mut, into_c);\n    };\n    (D) => {\n        define_any_of_variant_methods!(D, is_d, as_d, as_d_mut, into_d);\n    };\n    (E) => {\n        define_any_of_variant_methods!(E, is_e, as_e, as_e_mut, into_e);\n    };\n    (F) => {\n        define_any_of_variant_methods!(F, is_f, as_f, as_f_mut, into_f);\n    };\n    (G) => {\n        define_any_of_variant_methods!(G, is_g, as_g, as_g_mut, into_g);\n    };\n    (H) => {\n        define_any_of_variant_methods!(H, is_h, as_h, as_h_mut, into_h);\n    };\n}\n\nmacro_rules! define_any_of_methods {\n    ($name:ident, $($variant:ident),+) => {\n        impl<$($variant),+> $name<$($variant),+> {\n            $(\n                define_any_of_variant_methods!($variant);\n            )+\n        }\n    };\n}\n\ndefine_any_of!(AnyOf2, A, B);\ndefine_any_of!(AnyOf3, A, B, C);\ndefine_any_of!(AnyOf4, A, B, C, D);\ndefine_any_of!(AnyOf5, A, B, C, D, E);\ndefine_any_of!(AnyOf6, A, B, C, D, E, F);\ndefine_any_of!(AnyOf7, A, B, C, D, E, F, G);\ndefine_any_of!(AnyOf8, A, B, C, D, E, F, G, H);\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use rquickjs::{Context, Runtime};\n\n    #[test]\n    fn test_any_of_string_number() {\n        let rt = Runtime::new().unwrap();\n        let ctx = Context::full(&rt).unwrap();\n\n        ctx.with(|ctx| {\n            // Test string conversion\n            let val: Value = ctx.eval(\"'hello'\").unwrap();\n            let any: AnyOf2<String, i32> = AnyOf2::from_js(&ctx, val).unwrap();\n            assert!(any.is_a());\n            assert_eq!(any.as_a().unwrap(), \"hello\");\n            assert!(!any.is_b());\n            assert!(any.as_b().is_none());\n\n            // Test number conversion\n            let val: Value = ctx.eval(\"42\").unwrap();\n            let any: AnyOf2<String, i32> = AnyOf2::from_js(&ctx, val).unwrap();\n            assert!(!any.is_a());\n            assert!(any.is_b());\n            assert_eq!(*any.as_b().unwrap(), 42);\n        });\n    }\n\n    #[test]\n    fn test_any_of_fallback() {\n        let rt = Runtime::new().unwrap();\n        let ctx = Context::full(&rt).unwrap();\n\n        ctx.with(|ctx| {\n            // Test that it tries in order\n            let val: Value = ctx.eval(\"true\").unwrap();\n            let any: AnyOf3<String, i32, bool> = AnyOf3::from_js(&ctx, val).unwrap();\n            assert!(any.is_c());\n            assert!(*any.as_c().unwrap());\n            assert!(!any.is_a());\n            assert!(!any.is_b());\n        });\n    }\n\n    #[test]\n    fn test_any_of_into_js() {\n        let rt = Runtime::new().unwrap();\n        let ctx = Context::full(&rt).unwrap();\n\n        ctx.with(|ctx| {\n            let any: AnyOf2<String, i32> = AnyOf2::A(\"test\".to_string());\n            let val: Value = any.into_js(&ctx).unwrap();\n            let result: String = val.get().unwrap();\n            assert_eq!(result, \"test\");\n\n            let any: AnyOf2<String, i32> = AnyOf2::B(99);\n            let val: Value = any.into_js(&ctx).unwrap();\n            let result: i32 = val.get().unwrap();\n            assert_eq!(result, 99);\n        });\n    }\n\n    #[test]\n    fn test_any_of_methods() {\n        let rt = Runtime::new().unwrap();\n        let ctx = Context::full(&rt).unwrap();\n\n        ctx.with(|ctx| {\n            // Test all methods for variant A\n            let val: Value = ctx.eval(\"'test'\").unwrap();\n            let any: AnyOf3<String, i32, bool> = AnyOf3::from_js(&ctx, val).unwrap();\n            assert!(any.is_a());\n            assert_eq!(any.as_a().unwrap(), \"test\");\n            assert_eq!(any.into_a().unwrap(), \"test\");\n\n            // Test all methods for variant B\n            let val: Value = ctx.eval(\"42\").unwrap();\n            let any: AnyOf3<String, i32, bool> = AnyOf3::from_js(&ctx, val).unwrap();\n            assert!(any.is_b());\n            assert_eq!(*any.as_b().unwrap(), 42);\n            assert_eq!(any.into_b().unwrap(), 42);\n\n            // Test all methods for variant C\n            let val: Value = ctx.eval(\"true\").unwrap();\n            let any: AnyOf3<String, i32, bool> = AnyOf3::from_js(&ctx, val).unwrap();\n            assert!(any.is_c());\n            assert!(*any.as_c().unwrap());\n            assert!(any.into_c().unwrap());\n        });\n    }\n\n    #[test]\n    fn test_any_of_mutable_methods() {\n        let rt = Runtime::new().unwrap();\n        let ctx = Context::full(&rt).unwrap();\n\n        ctx.with(|ctx| {\n            let val: Value = ctx.eval(\"42\").unwrap();\n            let mut any: AnyOf4<String, i32, bool, f64> = AnyOf4::from_js(&ctx, val).unwrap();\n\n            if let Some(n) = any.as_b_mut() {\n                *n = 100;\n            }\n\n            assert_eq!(any.into_b().unwrap(), 100);\n        });\n    }\n\n    #[test]\n    fn test_any_of_error_propagation() {\n        use rquickjs::{Array, Object};\n\n        let rt = Runtime::new().unwrap();\n        let ctx = Context::full(&rt).unwrap();\n\n        ctx.with(|ctx| {\n            // Test that conversion errors cause fallback to next type\n            let val: Value = ctx.eval(\"42\").unwrap();\n            let any: AnyOf2<String, i32> = AnyOf2::from_js(&ctx, val).unwrap();\n            assert!(any.is_b());\n\n            // Test that all types fail results in an error\n            let val: Value = ctx.eval(\"null\").unwrap();\n            let result: Result<AnyOf2<Object, Array>> = AnyOf2::from_js(&ctx, val);\n            assert!(result.is_err());\n        });\n    }\n\n    #[test]\n    fn test_any_of_conversion_order() {\n        let rt = Runtime::new().unwrap();\n        let ctx = Context::full(&rt).unwrap();\n\n        ctx.with(|ctx| {\n            // Test that conversion happens in order A, B, C, D, E\n            // Since 42 can be converted to f64, i32, etc., but String comes first and fails,\n            // it should try the next successful conversion\n            let val: Value = ctx.eval(\"42\").unwrap();\n\n            // String should fail, so it tries i32 which succeeds\n            let any: AnyOf3<String, i32, f64> = AnyOf3::from_js(&ctx, val).unwrap();\n            assert!(any.is_b());\n\n            // If we flip the order, f64 would be tried first (but both work)\n            let val: Value = ctx.eval(\"3.14\").unwrap();\n            let any: AnyOf3<String, f64, i32> = AnyOf3::from_js(&ctx, val).unwrap();\n            assert!(any.is_b()); // f64 should succeed first\n        });\n    }\n}\n"
  },
  {
    "path": "libs/llrt_utils/src/bytearray_buffer.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{\n    cmp::min,\n    collections::VecDeque,\n    sync::{\n        atomic::{AtomicBool, AtomicUsize, Ordering},\n        Arc, Mutex,\n    },\n};\n\nuse tokio::sync::{Notify, Semaphore};\n\n#[derive(Clone)]\npub struct BytearrayBuffer {\n    inner: Arc<Mutex<VecDeque<u8>>>,\n    max_capacity: Arc<AtomicUsize>,\n    len: Arc<AtomicUsize>,\n    notify: Arc<Notify>,\n    closed: Arc<AtomicBool>,\n    write_semaphore: Arc<Semaphore>,\n}\n\nimpl BytearrayBuffer {\n    pub fn new(capacity: usize) -> Self {\n        let queue = VecDeque::with_capacity(capacity);\n        let capacity = queue.capacity();\n        Self {\n            inner: Arc::new(Mutex::new(queue)),\n            len: Arc::new(AtomicUsize::new(0)),\n            max_capacity: Arc::new(AtomicUsize::new(capacity)),\n            notify: Arc::new(Notify::new()),\n            closed: Arc::new(AtomicBool::new(false)),\n            write_semaphore: Arc::new(Semaphore::new(1)),\n        }\n    }\n\n    pub fn len(&self) -> usize {\n        self.len.load(Ordering::Relaxed)\n    }\n\n    pub fn is_empty(&self) -> bool {\n        self.len() == 0\n    }\n\n    #[allow(dead_code)]\n    pub fn write_forced(&self, item: &[u8]) {\n        let mut inner = self.inner.lock().unwrap();\n        inner.extend(item);\n        let capacity = inner.capacity();\n        self.len.fetch_add(item.len(), Ordering::Relaxed);\n        self.max_capacity.store(capacity, Ordering::Relaxed);\n    }\n\n    pub async fn write(&self, item: &mut [u8]) -> usize {\n        let _ = self.write_semaphore.acquire().await.unwrap();\n        let mut slice_index = 0;\n        loop {\n            let max_capacity = self.max_capacity.load(Ordering::Relaxed);\n            if self.closed.load(Ordering::Relaxed) {\n                return max_capacity;\n            }\n\n            let len = self.len.load(Ordering::Relaxed);\n\n            let available = max_capacity - len;\n\n            if available > 0 {\n                let end_index = min(item.len() - 1, slice_index + available - 1);\n                let sub_slice = &item[slice_index..=end_index];\n                let slice_length = sub_slice.len();\n                slice_index += slice_length;\n\n                self.inner.lock().unwrap().extend(sub_slice);\n                self.len.fetch_add(slice_length, Ordering::Relaxed);\n\n                if slice_index == item.len() {\n                    return max_capacity;\n                }\n            }\n            self.notify.notified().await;\n        }\n    }\n\n    #[allow(dead_code)]\n    pub fn is_closed(&self) -> bool {\n        self.closed.load(Ordering::Relaxed)\n    }\n\n    pub async fn close(&self) {\n        self.closed.store(true, Ordering::Relaxed);\n        self.notify.notify_one();\n        //wait for write to finish\n        let _ = self.write_semaphore.acquire().await.unwrap();\n    }\n\n    pub async fn clear(&self) {\n        self.closed.store(false, Ordering::Relaxed);\n        self.notify.notify_one();\n        //wait for write to finish\n        let _ = self.write_semaphore.acquire().await.unwrap();\n        self.len.store(0, Ordering::Relaxed);\n        self.inner.lock().unwrap().clear();\n        self.closed.store(false, Ordering::Relaxed);\n    }\n\n    pub fn read(&self, desired_size: Option<usize>) -> Option<Vec<u8>> {\n        let mut inner = self.inner.lock().unwrap();\n        let done = self.closed.load(Ordering::Relaxed);\n\n        let items = if done {\n            Some(inner.drain(0..).collect())\n        } else if let Some(desired_len) = desired_size {\n            let max_capacity = self.max_capacity.load(Ordering::Relaxed);\n            if desired_len > max_capacity {\n                let diff = desired_len - max_capacity;\n                inner.reserve(diff - 1);\n                let mut max_capacity = inner.capacity();\n                if desired_len > max_capacity {\n                    inner.reserve(desired_len - max_capacity);\n                    max_capacity = inner.capacity();\n                }\n                drop(inner);\n                self.max_capacity.store(max_capacity, Ordering::Relaxed);\n                self.notify.notify_one();\n                return None;\n            }\n\n            let len = self.len.load(Ordering::Relaxed);\n            if desired_len > len {\n                self.notify.notify_one();\n                return None;\n            }\n\n            Some(inner.drain(0..desired_len).collect())\n        } else {\n            Some(inner.drain(0..).collect())\n        };\n        self.len.store(inner.len(), Ordering::Relaxed);\n        drop(inner);\n        self.notify.notify_one();\n        items\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::BytearrayBuffer;\n\n    #[tokio::test]\n    async fn clear_while_writing() {\n        let queue = BytearrayBuffer::new(8);\n        let queue2 = queue.clone();\n\n        tokio::task::spawn(async move {\n            let mut vec: Vec<u8> = (0..=255).collect();\n            queue.write(&mut vec).await;\n        });\n\n        queue2.clear().await\n    }\n\n    #[tokio::test]\n    async fn write_one_at_a_time() {\n        let queue = BytearrayBuffer::new(8);\n        let queue2 = queue.clone();\n        let queue3 = queue.clone();\n\n        tokio::task::spawn(async move {\n            let mut vec: Vec<u8> = (0..=127).collect();\n            queue.write(&mut vec).await;\n        });\n\n        tokio::task::spawn(async move {\n            let mut vec: Vec<u8> = (128..=255).collect();\n            queue2.write(&mut vec).await;\n        });\n\n        let mut data = Vec::<u8>::new();\n\n        loop {\n            tokio::task::yield_now().await;\n            if let Some(bytes) = queue3.read(Some(256)) {\n                data.extend(bytes);\n                break;\n            }\n        }\n\n        //assert that data in vec is increment from 0 to 255\n        for i in 0..=255 {\n            assert_eq!(data[i as usize], i);\n        }\n    }\n\n    #[tokio::test]\n    async fn queue() {\n        let queue = BytearrayBuffer::new(8);\n        let queue2 = queue.clone();\n\n        let write_task = tokio::task::spawn(async move {\n            for _ in 0..=255 {\n                let mut vec: Vec<u8> = (0..=255).collect();\n                queue.write(&mut vec).await;\n            }\n            queue.close().await;\n        });\n\n        let mut data = Vec::<u8>::new();\n\n        loop {\n            let done = queue2.is_closed();\n\n            tokio::task::yield_now().await;\n            if let Some(bytes) = queue2.read(Some(9)) {\n                data.extend(bytes);\n            }\n            if done {\n                break;\n            }\n        }\n\n        let _ = write_task.await;\n\n        assert_eq!(data.len(), 256 * 256)\n    }\n}\n"
  },
  {
    "path": "libs/llrt_utils/src/bytes.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::rc::Rc;\n\nuse rquickjs::{\n    atom::PredefinedAtom,\n    class::{Trace, Tracer},\n    function::Constructor,\n    ArrayBuffer, Coerced, Ctx, Exception, FromJs, IntoJs, JsLifetime, Object, Result, TypedArray,\n    Value,\n};\n\nuse crate::{error_messages::ERROR_MSG_ARRAY_BUFFER_DETACHED, result::ResultExt};\n\n#[derive(Clone, PartialEq)]\npub enum ObjectBytes<'js> {\n    U8Array(TypedArray<'js, u8>),\n    I8Array(TypedArray<'js, i8>),\n    U16Array(TypedArray<'js, u16>),\n    I16Array(TypedArray<'js, i16>),\n    U32Array(TypedArray<'js, u32>),\n    I32Array(TypedArray<'js, i32>),\n    U64Array(TypedArray<'js, u64>),\n    I64Array(TypedArray<'js, i64>),\n    F32Array(TypedArray<'js, f32>),\n    F64Array(TypedArray<'js, f64>),\n    DataView(ArrayBuffer<'js>),\n    Vec(Vec<u8>),\n}\n\n// Requires manual implementation because rquickjs hasn't implemented JsLifetime for f32 or f64\nunsafe impl<'js> JsLifetime<'js> for ObjectBytes<'js> {\n    type Changed<'to> = ObjectBytes<'to>;\n}\n\nimpl<'js> Trace<'js> for ObjectBytes<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        match self {\n            ObjectBytes::U8Array(a) => a.trace(tracer),\n            ObjectBytes::I8Array(a) => a.trace(tracer),\n            ObjectBytes::U16Array(a) => a.trace(tracer),\n            ObjectBytes::I16Array(a) => a.trace(tracer),\n            ObjectBytes::U32Array(a) => a.trace(tracer),\n            ObjectBytes::I32Array(a) => a.trace(tracer),\n            ObjectBytes::U64Array(a) => a.trace(tracer),\n            ObjectBytes::I64Array(a) => a.trace(tracer),\n            ObjectBytes::F32Array(a) => a.trace(tracer),\n            ObjectBytes::F64Array(a) => a.trace(tracer),\n            ObjectBytes::DataView(d) => d.trace(tracer),\n            ObjectBytes::Vec(v) => v.trace(tracer),\n        }\n    }\n}\n\nimpl<'js> IntoJs<'js> for ObjectBytes<'js> {\n    fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {\n        match self {\n            ObjectBytes::U8Array(a) => a.into_js(ctx),\n            ObjectBytes::I8Array(a) => a.into_js(ctx),\n            ObjectBytes::U16Array(a) => a.into_js(ctx),\n            ObjectBytes::I16Array(a) => a.into_js(ctx),\n            ObjectBytes::U32Array(a) => a.into_js(ctx),\n            ObjectBytes::I32Array(a) => a.into_js(ctx),\n            ObjectBytes::U64Array(a) => a.into_js(ctx),\n            ObjectBytes::I64Array(a) => a.into_js(ctx),\n            ObjectBytes::F32Array(a) => a.into_js(ctx),\n            ObjectBytes::F64Array(a) => a.into_js(ctx),\n            ObjectBytes::DataView(d) => {\n                let ctor: Constructor = ctx.globals().get(PredefinedAtom::DataView)?;\n                ctor.construct((d,))\n            },\n            ObjectBytes::Vec(v) => v.into_js(ctx),\n        }\n    }\n}\n\nimpl<'js> TryFrom<ObjectBytes<'js>> for Vec<u8> {\n    type Error = Rc<str>;\n    fn try_from(value: ObjectBytes<'js>) -> std::result::Result<Self, Self::Error> {\n        value.into_bytes_inner()\n    }\n}\n\nimpl<'a, 'js> TryFrom<&'a ObjectBytes<'js>> for &'a [u8] {\n    type Error = Rc<str>;\n    fn try_from(value: &'a ObjectBytes<'js>) -> std::result::Result<Self, Self::Error> {\n        value.as_bytes_inner()\n    }\n}\n\nimpl<'js> FromJs<'js> for ObjectBytes<'js> {\n    fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        Self::from_offset(ctx, &value, 0, None)\n    }\n}\n\nimpl<'js> ObjectBytes<'js> {\n    pub fn from(ctx: &Ctx<'js>, value: &Value<'js>) -> Result<Self> {\n        Self::from_offset(ctx, value, 0, None)\n    }\n\n    pub fn from_offset(\n        ctx: &Ctx<'js>,\n        value: &Value<'js>,\n        offset: usize,\n        length: Option<usize>,\n    ) -> Result<Self> {\n        if value.is_undefined() {\n            return Ok(ObjectBytes::Vec(vec![]));\n        }\n        if let Some(bytes) = get_string_bytes(value, offset, length)? {\n            return Ok(ObjectBytes::Vec(bytes));\n        }\n        if let Some(bytes) = get_array_bytes(value, offset, length)? {\n            return Ok(ObjectBytes::Vec(bytes));\n        }\n\n        if let Some(obj) = value.as_object() {\n            if let Some(bytes) = Self::from_array_buffer(obj)? {\n                return Ok(bytes);\n            }\n        }\n\n        if let Some(bytes) = get_coerced_string_bytes(value, offset, length) {\n            return Ok(ObjectBytes::Vec(bytes));\n        }\n\n        Err(Exception::throw_message(\n        ctx,\n        \"value must be typed DataView, Buffer, ArrayBuffer, Uint8Array or interpretable as string\",\n    ))\n    }\n\n    pub fn as_bytes(&self, ctx: &Ctx<'js>) -> Result<&[u8]> {\n        self.as_bytes_inner().or_throw(ctx)\n    }\n\n    fn as_bytes_inner(&self) -> std::result::Result<&[u8], Rc<str>> {\n        match self {\n            ObjectBytes::U8Array(array) => array.as_bytes(),\n            ObjectBytes::I8Array(array) => array.as_bytes(),\n            ObjectBytes::U16Array(array) => array.as_bytes(),\n            ObjectBytes::I16Array(array) => array.as_bytes(),\n            ObjectBytes::U32Array(array) => array.as_bytes(),\n            ObjectBytes::I32Array(array) => array.as_bytes(),\n            ObjectBytes::U64Array(array) => array.as_bytes(),\n            ObjectBytes::I64Array(array) => array.as_bytes(),\n            ObjectBytes::F32Array(array) => array.as_bytes(),\n            ObjectBytes::F64Array(array) => array.as_bytes(),\n            ObjectBytes::DataView(array_buffer) => array_buffer.as_bytes(),\n            ObjectBytes::Vec(bytes) => Some(bytes.as_ref()),\n        }\n        .ok_or(ERROR_MSG_ARRAY_BUFFER_DETACHED.into())\n    }\n\n    pub fn into_bytes(self, ctx: &Ctx<'_>) -> Result<Vec<u8>> {\n        self.into_bytes_inner().or_throw(ctx)\n    }\n\n    fn into_bytes_inner(self) -> std::result::Result<Vec<u8>, Rc<str>> {\n        if let ObjectBytes::Vec(bytes) = self {\n            return Ok(bytes);\n        }\n        Ok(self.as_bytes_inner()?.to_vec())\n    }\n\n    pub fn from_array_buffer(obj: &Object<'js>) -> Result<Option<ObjectBytes<'js>>> {\n        //most common\n        if let Ok(typed_array) = TypedArray::<u8>::from_object(obj.clone()) {\n            return Ok(Some(ObjectBytes::U8Array(typed_array)));\n        }\n        //second most common\n        if let Some(array_buffer) = ArrayBuffer::from_object(obj.clone()) {\n            return Ok(Some(ObjectBytes::DataView(array_buffer)));\n        }\n\n        if let Ok(typed_array) = TypedArray::<i8>::from_object(obj.clone()) {\n            return Ok(Some(ObjectBytes::I8Array(typed_array)));\n        }\n\n        if let Ok(typed_array) = TypedArray::<u16>::from_object(obj.clone()) {\n            return Ok(Some(ObjectBytes::U16Array(typed_array)));\n        }\n\n        if let Ok(typed_array) = TypedArray::<i16>::from_object(obj.clone()) {\n            return Ok(Some(ObjectBytes::I16Array(typed_array)));\n        }\n\n        if let Ok(typed_array) = TypedArray::<u32>::from_object(obj.clone()) {\n            return Ok(Some(ObjectBytes::U32Array(typed_array)));\n        }\n\n        if let Ok(typed_array) = TypedArray::<i32>::from_object(obj.clone()) {\n            return Ok(Some(ObjectBytes::I32Array(typed_array)));\n        }\n\n        if let Ok(typed_array) = TypedArray::<u64>::from_object(obj.clone()) {\n            return Ok(Some(ObjectBytes::U64Array(typed_array)));\n        }\n\n        if let Ok(typed_array) = TypedArray::<i64>::from_object(obj.clone()) {\n            return Ok(Some(ObjectBytes::I64Array(typed_array)));\n        }\n\n        if let Ok(typed_array) = TypedArray::<f32>::from_object(obj.clone()) {\n            return Ok(Some(ObjectBytes::F32Array(typed_array)));\n        }\n\n        if let Ok(typed_array) = TypedArray::<f64>::from_object(obj.clone()) {\n            return Ok(Some(ObjectBytes::F64Array(typed_array)));\n        }\n\n        if let Ok(array_buffer) = obj.get::<_, ArrayBuffer>(\"buffer\") {\n            return Ok(Some(ObjectBytes::DataView(array_buffer)));\n        }\n\n        Ok(None)\n    }\n\n    pub fn get_array_buffer(&self) -> Result<Option<(ArrayBuffer<'js>, usize, usize)>> {\n        let buffer = match self {\n            ObjectBytes::DataView(array_buffer) => (array_buffer.clone(), array_buffer.len(), 0),\n            ObjectBytes::U8Array(typed_array) => {\n                let byte_length = typed_array.len();\n                (\n                    typed_array.arraybuffer()?,\n                    byte_length,\n                    typed_array.get(\"byteOffset\")?,\n                )\n            },\n            ObjectBytes::I8Array(typed_array) => {\n                let byte_length = typed_array.len();\n                (\n                    typed_array.arraybuffer()?,\n                    byte_length,\n                    typed_array.get(\"byteOffset\")?,\n                )\n            },\n            ObjectBytes::U16Array(typed_array) => {\n                let byte_length = typed_array.len() * 2;\n                (\n                    typed_array.arraybuffer()?,\n                    byte_length,\n                    typed_array.get(\"byteOffset\")?,\n                )\n            },\n            ObjectBytes::I16Array(typed_array) => {\n                let byte_length = typed_array.len() * 2;\n                (\n                    typed_array.arraybuffer()?,\n                    byte_length,\n                    typed_array.get(\"byteOffset\")?,\n                )\n            },\n            ObjectBytes::U32Array(typed_array) => {\n                let byte_length = typed_array.len() * 4;\n                (\n                    typed_array.arraybuffer()?,\n                    byte_length,\n                    typed_array.get(\"byteOffset\")?,\n                )\n            },\n            ObjectBytes::I32Array(typed_array) => {\n                let byte_length = typed_array.len() * 4;\n                (\n                    typed_array.arraybuffer()?,\n                    byte_length,\n                    typed_array.get(\"byteOffset\")?,\n                )\n            },\n            ObjectBytes::U64Array(typed_array) => {\n                let byte_length = typed_array.len() * 8;\n                (\n                    typed_array.arraybuffer()?,\n                    byte_length,\n                    typed_array.get(\"byteOffset\")?,\n                )\n            },\n            ObjectBytes::I64Array(typed_array) => {\n                let byte_length = typed_array.len() * 8;\n                (\n                    typed_array.arraybuffer()?,\n                    byte_length,\n                    typed_array.get(\"byteOffset\")?,\n                )\n            },\n            ObjectBytes::F32Array(typed_array) => {\n                let byte_length = typed_array.len() * 4;\n                (\n                    typed_array.arraybuffer()?,\n                    byte_length,\n                    typed_array.get(\"byteOffset\")?,\n                )\n            },\n            ObjectBytes::F64Array(typed_array) => {\n                let byte_length = typed_array.len() * 8;\n                (\n                    typed_array.arraybuffer()?,\n                    byte_length,\n                    typed_array.get(\"byteOffset\")?,\n                )\n            },\n            _ => return Ok(None),\n        };\n\n        Ok(Some(buffer))\n    }\n}\n\npub fn get_start_end_indexes(\n    source_len: usize,\n    target_len: Option<usize>,\n    offset: usize,\n) -> (usize, usize) {\n    if offset > source_len {\n        return (0, 0);\n    }\n\n    let target_len = target_len.unwrap_or(source_len - offset);\n\n    if offset + target_len > source_len {\n        return (offset, source_len);\n    }\n\n    (offset, target_len + offset)\n}\n\npub fn get_array_bytes(\n    value: &Value<'_>,\n    offset: usize,\n    length: Option<usize>,\n) -> Result<Option<Vec<u8>>> {\n    if value.is_array() {\n        let array = value.as_array().unwrap();\n        let (start, end) = get_start_end_indexes(array.len(), length, offset);\n        let size = end - start;\n        let mut bytes: Vec<u8> = Vec::with_capacity(size);\n\n        for val in array.iter::<u8>().skip(start).take(size) {\n            let val: u8 = val?;\n            bytes.push(val);\n        }\n\n        return Ok(Some(bytes));\n    }\n    Ok(None)\n}\n\npub fn get_coerced_string_bytes(\n    value: &Value<'_>,\n    offset: usize,\n    length: Option<usize>,\n) -> Option<Vec<u8>> {\n    if let Ok(val) = value.get::<Coerced<String>>() {\n        return Some(bytes_from_js_string(val.0, offset, length));\n    };\n    None\n}\n\nfn bytes_from_js_string(string: String, offset: usize, length: Option<usize>) -> Vec<u8> {\n    let (start, end) = get_start_end_indexes(string.len(), length, offset);\n    string.as_bytes()[start..end].to_vec()\n}\n\n#[inline]\npub fn get_string_bytes(\n    value: &Value<'_>,\n    offset: usize,\n    length: Option<usize>,\n) -> Result<Option<Vec<u8>>> {\n    if let Some(val) = value.as_string() {\n        let string = val.to_string()?;\n        return Ok(Some(bytes_from_js_string(string, offset, length)));\n    }\n    Ok(None)\n}\n\npub fn bytes_to_typed_array<'js>(ctx: Ctx<'js>, bytes: &[u8]) -> Result<Value<'js>> {\n    TypedArray::<u8>::new(ctx.clone(), bytes).into_js(&ctx)\n}\n"
  },
  {
    "path": "libs/llrt_utils/src/class.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse rquickjs::{\n    atom::PredefinedAtom, class::JsClass, object::Accessor, prelude::This, Array, Class, Ctx,\n    Function, Object, Result, Value,\n};\n\nuse crate::primordials::{BasePrimordials, Primordial};\n\nuse super::{object::ObjectExt, result::OptionExt};\n\npub static CUSTOM_INSPECT_SYMBOL_DESCRIPTION: &str = \"llrt.inspect.custom\";\n\npub trait IteratorDef<'js>\nwhere\n    Self: 'js + JsClass<'js> + Sized,\n{\n    fn js_entries(&self, ctx: Ctx<'js>) -> Result<Array<'js>>;\n\n    fn js_iterator(&self, ctx: Ctx<'js>) -> Result<Value<'js>> {\n        let value = self.js_entries(ctx)?;\n        let obj = value.as_object();\n        let values_fn: Function = obj.get(PredefinedAtom::Values)?;\n        values_fn.call((This(value),))\n    }\n}\n\npub fn get_class_name(value: &Value) -> Result<Option<String>> {\n    value\n        .get_optional::<_, Object>(PredefinedAtom::Constructor)?\n        .and_then_ok(|ctor| ctor.get_optional::<_, String>(PredefinedAtom::Name))\n}\n\n#[inline(always)]\npub fn get_class<'js, C>(provided: &Value<'js>) -> Result<Option<Class<'js, C>>>\nwhere\n    C: JsClass<'js>,\n{\n    if provided\n        .as_object()\n        .map(|p| p.instance_of::<C>())\n        .unwrap_or_default()\n    {\n        return Ok(Some(Class::<C>::from_value(provided)?));\n    }\n    Ok(None)\n}\n\npub trait CustomInspectExtension<'js> {\n    fn define_with_custom_inspect(globals: &Object<'js>) -> Result<()>;\n}\n\npub trait CustomInspect<'js>\nwhere\n    Self: JsClass<'js>,\n{\n    fn custom_inspect(&self, ctx: Ctx<'js>) -> Result<Object<'js>>;\n}\n\nimpl<'js, C> CustomInspectExtension<'js> for Class<'js, C>\nwhere\n    C: JsClass<'js> + CustomInspect<'js> + 'js,\n{\n    fn define_with_custom_inspect(globals: &Object<'js>) -> Result<()> {\n        Self::define(globals)?;\n        let custom_inspect_symbol = BasePrimordials::get(globals.ctx())?\n            .symbol_custom_inspect\n            .clone();\n        if let Some(proto) = Class::<C>::prototype(globals.ctx())? {\n            proto.prop(\n                custom_inspect_symbol,\n                Accessor::from(|this: This<Class<'js, C>>, ctx| this.borrow().custom_inspect(ctx)),\n            )?;\n        }\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "libs/llrt_utils/src/clone.rs",
    "content": "use std::collections::HashSet;\n\n// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse rquickjs::{\n    atom::PredefinedAtom,\n    function::{Constructor, Opt, This},\n    Array, ArrayBuffer, Ctx, Exception, Function, IntoJs, Null, Object, Result, Type, Value,\n};\n\nuse super::{\n    hash,\n    object::ObjectExt,\n    primordials::{BasePrimordials, Primordial},\n};\n\n#[derive(Debug)]\nenum StackItem<'js> {\n    Value(usize, Value<'js>, Option<String>, Option<usize>),\n    ObjectEnd,\n}\n\n#[derive(Debug)]\nenum ObjectType {\n    Set,\n    Map,\n}\n\n#[derive(Debug)]\nenum TapeValue<'js> {\n    Array(Array<'js>),\n    Object(Object<'js>),\n    Value(Value<'js>),\n    Collection(Option<Value<'js>>, ObjectType),\n}\n\n#[derive(Debug)]\nstruct TapeItem<'js> {\n    parent: usize,\n    object_key: Option<String>,\n    array_index: Option<usize>,\n    value: TapeValue<'js>,\n}\n\npub fn structured_clone<'js>(\n    ctx: &Ctx<'js>,\n    value: Value<'js>,\n    options: Opt<Object<'js>>,\n) -> Result<Value<'js>> {\n    let primordials = BasePrimordials::get(ctx)?;\n    let mut transfer_set = None;\n\n    if let Some(options) = options.0 {\n        if let Some(transfer_array) = options.get_optional::<_, Array>(\"transfer\")? {\n            let mut set = HashSet::with_capacity(transfer_array.len());\n\n            for item in transfer_array.iter::<Value>() {\n                set.insert(item?);\n            }\n            transfer_set = Some(set);\n        }\n    }\n\n    let mut tape = Vec::<TapeItem>::with_capacity(10);\n    let mut stack = Vec::with_capacity(10);\n    let mut visited = Vec::<(usize, usize)>::with_capacity(10);\n    let mut index = 0usize;\n\n    stack.push(StackItem::Value(0, value, None, None));\n\n    while let Some(item) = stack.pop() {\n        match item {\n            StackItem::Value(parent, value, mut object_key, array_index) => {\n                if let Some(set) = &transfer_set {\n                    if let Some(value) = set.get(&value) {\n                        append_transfer_value(&mut tape, value, parent, object_key, array_index)?;\n                        index += 1;\n                        continue;\n                    }\n                }\n                match value.type_of() {\n                    Type::Proxy => {\n                        return Err(Exception::throw_type(\n                            ctx,\n                            \"A Proxy value could not be cloned\",\n                        ));\n                    },\n                    Type::Object => {\n                        if check_circular(\n                            &mut tape,\n                            &mut visited,\n                            &value,\n                            parent,\n                            &mut object_key,\n                            array_index,\n                            index,\n                        ) {\n                            index += 1;\n                            continue;\n                        }\n\n                        //unsafe OK since we're guaranteed to be object by the match\n                        let object = unsafe { value.as_object().unwrap_unchecked() };\n\n                        if object.is_instance_of(&primordials.constructor_date) {\n                            append_ctor_value(\n                                &mut tape,\n                                object,\n                                &primordials.constructor_date,\n                                parent,\n                                object_key,\n                                array_index,\n                            )?;\n                            index += 1;\n                            continue;\n                        }\n\n                        if object.is_instance_of(&primordials.constructor_regexp) {\n                            append_ctor_value(\n                                &mut tape,\n                                object,\n                                &primordials.constructor_regexp,\n                                parent,\n                                object_key,\n                                array_index,\n                            )?;\n                            index += 1;\n                            continue;\n                        }\n\n                        let is_collection = if object.is_instance_of(&primordials.constructor_set) {\n                            Some(ObjectType::Set)\n                        } else if object.is_instance_of(&primordials.constructor_map) {\n                            Some(ObjectType::Map)\n                        } else {\n                            None\n                        };\n\n                        if let Some(collection_type) = is_collection {\n                            append_collection(\n                                &mut tape,\n                                &primordials.function_array_from,\n                                object,\n                                parent,\n                                object_key,\n                                array_index,\n                                collection_type,\n                                &mut stack,\n                                index,\n                            )?;\n\n                            index += 1;\n                            continue;\n                        }\n\n                        if primordials\n                            .function_array_buffer_is_view\n                            .call::<_, bool>((value.clone(),))?\n                        {\n                            append_buffer(&mut tape, object, parent, object_key, array_index)?;\n                            index += 1;\n                            continue;\n                        }\n\n                        let new: Object<'_> =\n                            if object.is_instance_of(&primordials.constructor_error) {\n                                primordials.constructor_error.construct((\"\",))\n                            } else {\n                                Object::new(ctx.clone())\n                            }?;\n\n                        tape.push(TapeItem {\n                            parent,\n                            object_key,\n                            array_index,\n                            value: TapeValue::Object(new),\n                        });\n                        stack.push(StackItem::ObjectEnd);\n\n                        for key in object.keys::<String>() {\n                            let key = key?;\n                            let value = object.get(&key)?;\n                            stack.push(StackItem::Value(index, value, Some(key), None));\n                        }\n                    },\n                    Type::Array => {\n                        if check_circular(\n                            &mut tape,\n                            &mut visited,\n                            &value,\n                            parent,\n                            &mut object_key,\n                            array_index,\n                            index,\n                        ) {\n                            index += 1;\n                            continue;\n                        }\n                        let new = Array::new(ctx.clone())?;\n                        tape.push(TapeItem {\n                            parent,\n                            object_key,\n                            array_index,\n                            value: TapeValue::Array(new),\n                        });\n                        stack.push(StackItem::ObjectEnd);\n                        //unsafe OK since we're guaranteed to be object by the match\n                        let array = unsafe { value.as_array().unwrap_unchecked() };\n\n                        //reverse for loop of items in array\n                        for array_index in (0usize..array.len()).rev() {\n                            stack.push(StackItem::Value(\n                                index,\n                                array.get(array_index)?,\n                                None,\n                                Some(array_index),\n                            ));\n                        }\n                    },\n                    _ => {\n                        tape.push(TapeItem {\n                            parent,\n                            object_key,\n                            array_index,\n                            value: TapeValue::Value(value),\n                        });\n                    },\n                }\n                index += 1;\n            },\n            StackItem::ObjectEnd => {\n                visited.pop();\n            },\n        }\n    }\n\n    while let Some(item) = tape.pop() {\n        let value = match item.value {\n            TapeValue::Array(array) => array.into_value(),\n            TapeValue::Object(object) => object.into_value(),\n            TapeValue::Value(value) => value,\n            TapeValue::Collection(mut value, _) => value.take().unwrap(),\n        };\n        if tape.is_empty() {\n            return Ok(value);\n        }\n        let parent = &mut tape[item.parent];\n        let array_index = item.array_index;\n        let object_key = item.object_key;\n        match &mut parent.value {\n            TapeValue::Array(array) => {\n                array.set(array_index.unwrap(), value)?;\n            },\n            TapeValue::Object(object) => {\n                let string = object_key.unwrap();\n                object.set(string, value)?;\n            },\n            TapeValue::Collection(collection_value, collection_type) => {\n                match collection_type {\n                    ObjectType::Set => {\n                        collection_value.replace(primordials.constructor_set.construct((value,))?);\n                    },\n                    ObjectType::Map => {\n                        collection_value.replace(primordials.constructor_map.construct((value,))?);\n                    },\n                };\n            },\n            _ => {},\n        };\n    }\n\n    Null.into_js(ctx)\n}\n\n#[inline(always)]\n#[cold]\nfn append_buffer<'js>(\n    tape: &mut Vec<TapeItem<'js>>,\n    object: &Object<'js>,\n    parent: usize,\n    object_key: Option<String>,\n    array_index: Option<usize>,\n) -> Result<()> {\n    let ctor: Constructor = object.get(PredefinedAtom::Constructor)?;\n    let slice: Function = object.get(\"slice\")?;\n    let clone: Value = slice.call((This(object.clone()),))?;\n    let new = ctor.construct((clone,))?;\n    tape.push(TapeItem {\n        parent,\n        object_key,\n        array_index,\n        value: TapeValue::Value(new),\n    });\n    Ok(())\n}\n\n#[inline(always)]\n#[cold]\n#[allow(clippy::too_many_arguments)]\nfn append_collection<'js>(\n    tape: &mut Vec<TapeItem<'js>>,\n    array_from: &Function<'js>,\n    object: &Object<'js>,\n    parent: usize,\n    object_key: Option<String>,\n    array_index: Option<usize>,\n    collection_type: ObjectType,\n    stack: &mut Vec<StackItem<'js>>,\n    index: usize,\n) -> Result<()> {\n    let array: Array = array_from.call((object.clone(),))?;\n    tape.push(TapeItem {\n        parent,\n        object_key,\n        array_index,\n        value: TapeValue::Collection(None, collection_type),\n    });\n    stack.push(StackItem::ObjectEnd);\n    stack.push(StackItem::Value(index, array.into(), None, None));\n    Ok(())\n}\n\n#[inline(always)]\nfn check_circular(\n    tape: &mut Vec<TapeItem>,\n    visited: &mut Vec<(usize, usize)>,\n    value: &Value<'_>,\n    parent: usize,\n    object_key: &mut Option<String>,\n    array_index: Option<usize>,\n    index: usize,\n) -> bool {\n    let hash = hash::default_hash(value);\n    if let Some(visited) = visited.iter().find(|v| v.0 == hash) {\n        append_circular(tape, visited, object_key, parent, array_index);\n        return true;\n    }\n    visited.push((hash, index));\n    false\n}\n\n#[inline(always)]\n#[cold]\nfn append_transfer_value<'js>(\n    tape: &mut Vec<TapeItem<'js>>,\n    value: &Value<'js>,\n    parent: usize,\n    object_key: Option<String>,\n    array_index: Option<usize>,\n) -> Result<()> {\n    let value = if let Some(ab) = ArrayBuffer::from_value(value.clone()) {\n        ab.get::<_, Function>(\"transfer\")?.call((This(ab),))?\n    } else {\n        value.clone()\n    };\n\n    tape.push(TapeItem {\n        parent,\n        object_key,\n        array_index,\n        value: TapeValue::Value(value),\n    });\n    Ok(())\n}\n\n#[inline(always)]\n#[cold]\nfn append_circular(\n    tape: &mut Vec<TapeItem<'_>>,\n    visited: &(usize, usize),\n    object_key: &mut Option<String>,\n    parent: usize,\n    array_index: Option<usize>,\n) {\n    let value = match &tape[visited.1].value {\n        TapeValue::Array(array) => array.clone().into_value(),\n        TapeValue::Object(object) => object.clone().into_value(),\n        TapeValue::Value(value) => value.clone(),\n        TapeValue::Collection(value, _) => value.clone().unwrap(),\n    };\n\n    let object_key = object_key.take();\n\n    tape.push(TapeItem {\n        parent,\n        object_key,\n        array_index,\n        value: TapeValue::Value(value),\n    });\n}\n\n#[inline(always)]\n#[cold]\nfn append_ctor_value<'js>(\n    tape: &mut Vec<TapeItem<'js>>,\n    object: &Object<'js>,\n    ctor: &Constructor<'js>,\n    parent: usize,\n    object_key: Option<String>,\n    array_index: Option<usize>,\n) -> Result<()> {\n    let clone: Value = ctor.construct((object.clone(),))?;\n    tape.push(TapeItem {\n        parent,\n        object_key,\n        array_index,\n        value: TapeValue::Value(clone),\n    });\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n\n    use llrt_test::test_sync_with;\n    use rquickjs::{function::Opt, Object, Value};\n\n    use crate::primordials::{BasePrimordials, Primordial};\n\n    use super::structured_clone;\n\n    #[tokio::test]\n    async fn clone() {\n        test_sync_with(|ctx| {\n            BasePrimordials::init(&ctx)?;\n            let value: Object = ctx.eval(\n                r#\"\nconst a = {\n   \"foo\":{\n      \"bar\":\"baz\"\n   },\n   \"foo1\":{\n      \"bar1\":\"baz1\",\n      \"bar11\":\"baz11\"\n   }\n};\na\n\"#,\n            )?;\n\n            let cloned = structured_clone(&ctx, value.clone().into_value(), Opt(None))?\n                .into_object()\n                .unwrap();\n\n            let json = ctx\n                .json_stringify(value.clone())?\n                .unwrap()\n                .to_string()?\n                .to_string();\n\n            let clone_json = ctx\n                .json_stringify(cloned.clone())?\n                .unwrap()\n                .to_string()?\n                .to_string();\n\n            assert_eq!(json, clone_json);\n\n            assert_ne!(\n                value.get::<_, Value>(\"foo\")?,\n                cloned.get::<_, Value>(\"foo\")?\n            );\n\n            Ok(())\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn clone_circular() {\n        test_sync_with(|ctx| {\n            BasePrimordials::init(&ctx)?;\n            let _value: Object = ctx.eval(\n                r#\"\nconst originalObject = { foo: { bar: \"baz\",arr: [1,2,3] }  };\noriginalObject.foo.circularRef = originalObject;\noriginalObject.foo.circularRef2 = originalObject;\noriginalObject.foo.circularRef3 = originalObject.foo;\noriginalObject.ref2 = originalObject;\n\"#,\n            )?;\n\n            Ok(())\n        })\n        .await\n    }\n}\n"
  },
  {
    "path": "libs/llrt_utils/src/ctx.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse rquickjs::{Ctx, Result};\n\npub trait CtxExt {\n    fn get_script_or_module_name(&self) -> Result<String>;\n}\n\nimpl CtxExt for Ctx<'_> {\n    fn get_script_or_module_name(&self) -> Result<String> {\n        if let Some(name) = self.script_or_module_name(0) {\n            name.to_string()\n        } else {\n            Ok(String::from(\".\"))\n        }\n    }\n}\n"
  },
  {
    "path": "libs/llrt_utils/src/error.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse rquickjs::{CatchResultExt, CaughtError, Ctx, Error, IntoJs, Result, Value};\n\npub trait ErrorExtensions<'js> {\n    fn into_value(self, ctx: &Ctx<'js>) -> Result<Value<'js>>;\n}\n\nimpl<'js> ErrorExtensions<'js> for Error {\n    fn into_value(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {\n        Err::<(), _>(self).catch(ctx).unwrap_err().into_value(ctx)\n    }\n}\n\nimpl<'js> ErrorExtensions<'js> for CaughtError<'js> {\n    fn into_value(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {\n        Ok(match self {\n            CaughtError::Error(err) => err.to_string().into_js(ctx)?,\n            CaughtError::Exception(ex) => ex.into_value(),\n            CaughtError::Value(val) => val,\n        })\n    }\n}\n"
  },
  {
    "path": "libs/llrt_utils/src/error_messages.rs",
    "content": "pub const ERROR_MSG_NOT_ARRAY_BUFFER: &str = \"Not an ArrayBuffer\";\npub const ERROR_MSG_ARRAY_BUFFER_DETACHED: &str = \"ArrayBuffer is detached\";\npub const ERROR_MSG_BROADCAST_LAGGED: &str = \"Lagged too much behind\";\n"
  },
  {
    "path": "libs/llrt_utils/src/fs.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{fs::Metadata, io, path::PathBuf};\n\nuse tokio::fs::{self};\n\npub struct DirectoryWalker<T>\nwhere\n    T: Fn(&str) -> bool,\n{\n    stack: Vec<(PathBuf, Option<Metadata>)>,\n    filter: T,\n    recursive: bool,\n    eat_root: bool,\n}\n\nimpl<T> DirectoryWalker<T>\nwhere\n    T: Fn(&str) -> bool,\n{\n    pub fn new(root: PathBuf, filter: T) -> Self {\n        Self {\n            stack: vec![(root, None)],\n            filter,\n            recursive: false,\n            eat_root: true,\n        }\n    }\n\n    pub fn set_recursive(&mut self, recursive: bool) {\n        self.recursive = recursive;\n    }\n\n    pub async fn walk(&mut self) -> io::Result<Option<(PathBuf, Metadata)>> {\n        if self.eat_root {\n            self.eat_root = false;\n            let (dir, _) = self.stack.pop().unwrap();\n            self.append_stack(&dir).await?;\n        }\n        if let Some((entry, metadata)) = self.stack.pop() {\n            let metadata = metadata.unwrap();\n            if self.recursive && metadata.is_dir() {\n                self.append_stack(&entry).await?;\n            }\n\n            Ok(Some((entry, metadata)))\n        } else {\n            Ok(None)\n        }\n    }\n\n    pub fn walk_sync(&mut self) -> io::Result<Option<(PathBuf, Metadata)>> {\n        if self.eat_root {\n            self.eat_root = false;\n            let (dir, _) = self.stack.pop().unwrap();\n            self.append_stack_sync(&dir)?;\n        }\n        if let Some((entry, metadata)) = self.stack.pop() {\n            let metadata = metadata.unwrap();\n            if self.recursive && metadata.is_dir() {\n                self.append_stack_sync(&entry)?;\n            }\n\n            Ok(Some((entry, metadata)))\n        } else {\n            Ok(None)\n        }\n    }\n\n    async fn append_stack(&mut self, dir: &PathBuf) -> io::Result<()> {\n        let mut stream = fs::read_dir(dir).await?;\n\n        while let Some(entry) = stream.next_entry().await? {\n            let name = entry.file_name();\n            let name = name.to_string_lossy();\n            if !(self.filter)(name.as_ref()) {\n                continue;\n            }\n            let entry_path = entry.path();\n            let metadata = fs::symlink_metadata(&entry_path).await?;\n\n            self.stack.push((entry_path, Some(metadata)));\n        }\n        Ok(())\n    }\n\n    fn append_stack_sync(&mut self, dir: &PathBuf) -> io::Result<()> {\n        let dir = std::fs::read_dir(dir)?;\n\n        for entry in dir.flatten() {\n            let name = entry.file_name();\n            let name = name.to_string_lossy();\n            if !(self.filter)(name.as_ref()) {\n                continue;\n            }\n            let entry_path = entry.path();\n            let metadata = entry_path.symlink_metadata()?;\n            self.stack.push((entry_path, Some(metadata)))\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "libs/llrt_utils/src/hash.rs",
    "content": "use std::hash::{DefaultHasher, Hash, Hasher};\n\n#[inline]\npub fn default_hash<T: Hash + ?Sized>(v: &T) -> usize {\n    let mut state = DefaultHasher::default();\n    v.hash(&mut state);\n    state.finish() as usize\n}\n"
  },
  {
    "path": "libs/llrt_utils/src/io.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nmacro_rules! define_extension {\n    ($base:ident, $file:ident, $ext:expr) => {\n        #[allow(dead_code)]\n        pub const $base: &str = $ext;\n        #[allow(dead_code)]\n        pub const $file: &str = concat!(\".\", $ext);\n    };\n}\n\ndefine_extension!(BYTECODE_EXT, BYTECODE_FILE_EXT, \"lrt\");\n\nmacro_rules! define_supported_extensions {\n    // Accepts a list of supported extensions and a single additional constant extension\n    ($constant_ext:ident, $($ext:literal),*) => {\n        // Define the array of extensions as a constant\n        pub const SUPPORTED_EXTENSIONS: &[&str] = &[$($ext),*, $constant_ext];\n\n        pub const JS_EXTENSIONS: &[&str] = &[$($ext),*];\n\n        // Define the function `is_supported_ext` using a match statement\n        pub fn is_supported_ext(ext: &str) -> bool {\n            matches!(ext, $($ext)|* | $constant_ext)\n        }\n    };\n}\n\ndefine_supported_extensions!(BYTECODE_FILE_EXT, \".js\", \".mjs\", \".cjs\");\n"
  },
  {
    "path": "libs/llrt_utils/src/latch.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::sync::atomic::{AtomicUsize, Ordering};\n\nuse tokio::sync::Notify;\n\n#[derive(Default)]\npub struct Latch {\n    count: AtomicUsize,\n    notify: Notify,\n}\n\nimpl Latch {\n    pub fn increment(&self) {\n        self.count.fetch_add(1, Ordering::Relaxed);\n    }\n\n    pub fn decrement(&self) {\n        let previous = self.count.fetch_sub(1, Ordering::Relaxed);\n        if previous == 1 {\n            self.notify.notify_waiters();\n        }\n    }\n\n    pub async fn wait(&self) {\n        if self.count.load(Ordering::Relaxed) > 0 {\n            self.notify.notified().await;\n        }\n    }\n}\n"
  },
  {
    "path": "libs/llrt_utils/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\npub mod any_of;\n#[cfg(feature = \"bytearray-buffer\")]\npub mod bytearray_buffer;\npub mod bytes;\npub mod class;\npub mod clone;\npub mod ctx;\npub mod error;\npub mod error_messages;\n#[cfg(feature = \"fs\")]\npub mod fs;\npub mod hash;\npub mod io;\npub mod latch;\npub mod macros;\npub mod mc_oneshot;\npub mod module;\npub mod object;\npub mod option;\npub mod primordials;\npub mod provider;\npub mod result;\npub mod reuse_list;\npub mod string;\npub mod sysinfo;\npub mod time;\n\npub mod signals;\n\npub const VERSION: &str = env!(\"CARGO_PKG_VERSION\");\n"
  },
  {
    "path": "libs/llrt_utils/src/macros.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#[macro_export]\nmacro_rules! count_members {\n    () => (0);\n    ($head:tt $(,$tail:tt)*) => (1 + count_members!($($tail),*));\n}\n\n#[macro_export]\nmacro_rules! iterable_enum {\n    ($name:ident, $($variant:ident),*) => {\n        impl $name {\n            const VARIANTS: &'static [$name] = &[$($name::$variant,)*];\n            pub fn iter() -> std::slice::Iter<'static, $name> {\n                Self::VARIANTS.iter()\n            }\n\n            #[allow(dead_code)]\n            fn _ensure_all_variants(s: Self) {\n                match s {\n                    $($name::$variant => {},)*\n                }\n            }\n        }\n    };\n}\n\n#[macro_export]\nmacro_rules! str_enum {\n    ($name:ident, $($variant:ident => $str:expr),*) => {\n        impl $name {\n            pub fn as_str(&self) -> &'static str {\n                match self {\n                    $($name::$variant => $str,)*\n                }\n            }\n        }\n\n        impl AsRef<str> for $name {\n            fn as_ref(&self) -> &str {\n                self.as_str()\n            }\n        }\n\n        impl TryFrom<&str> for $name {\n            type Error = String;\n            fn try_from(s: &str) -> std::result::Result<Self, Self::Error> {\n                match s {\n                    $($str => Ok($name::$variant),)*\n                    _ => Err([\"'\", s, \"' not available\"].concat())\n                }\n            }\n        }\n    };\n}\n"
  },
  {
    "path": "libs/llrt_utils/src/mc_oneshot.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nuse std::sync::{\n    atomic::{AtomicBool, Ordering},\n    Arc, RwLock,\n};\n\nuse rquickjs::{\n    class::{Trace, Tracer},\n    Value,\n};\nuse std::ops::Deref;\nuse tokio::sync::Notify;\n\n#[derive(Debug)]\npub struct Shared<T> {\n    is_sent: AtomicBool,\n    value: RwLock<Option<T>>,\n    notify: Notify,\n}\n\n#[derive(Clone, Debug)]\npub struct Sender<T: Clone>(Arc<Shared<T>>);\n\nimpl<T: Clone> Deref for Sender<T> {\n    type Target = Arc<Shared<T>>;\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\nimpl<'js> Trace<'js> for Sender<Value<'js>> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        if let Ok(v) = self.value.read() {\n            if let Some(v) = v.as_ref() {\n                tracer.mark(v)\n            }\n        }\n    }\n}\n\nimpl<T: Clone> Sender<T> {\n    pub fn send(&self, value: T) {\n        if !self.is_sent.load(Ordering::Relaxed) {\n            self.value.write().unwrap().replace(value);\n            self.is_sent.store(true, Ordering::Release);\n            self.notify.notify_waiters();\n        }\n    }\n\n    pub fn subscribe(&self) -> Receiver<T> {\n        Receiver(Arc::clone(&self.0))\n    }\n}\n\n#[derive(Clone, Debug)]\npub struct Receiver<T: Clone>(Arc<Shared<T>>);\n\nimpl<T: Clone> Deref for Receiver<T> {\n    type Target = Arc<Shared<T>>;\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\nimpl<T: Clone> Receiver<T> {\n    pub async fn recv(&self) -> T {\n        if !self.is_sent.load(Ordering::Acquire) {\n            self.notify.notified().await;\n        }\n        self.value.read().unwrap().clone().unwrap()\n    }\n}\n\npub fn channel<T: Clone>() -> (Sender<T>, Receiver<T>) {\n    let shared = Arc::new(Shared {\n        is_sent: AtomicBool::new(false),\n        value: RwLock::new(None),\n        notify: Notify::new(),\n    });\n\n    (Sender(Arc::clone(&shared)), Receiver(shared))\n}\n\n#[cfg(test)]\nmod tests {\n    use tokio::join;\n\n    #[tokio::test]\n    async fn test() {\n        let (tx, rx1) = super::channel::<bool>();\n\n        let rx2 = tx.subscribe();\n        let rx3 = tx.subscribe();\n\n        let a = tokio::spawn(async move {\n            let val = rx1.recv().await; //wait for value to become false\n            assert!(val)\n        });\n\n        let b = tokio::spawn(async move {\n            let val = rx2.recv().await; //wait for value to become false\n            assert!(val)\n        });\n\n        tokio::time::sleep(std::time::Duration::from_millis(10)).await;\n\n        tx.send(true);\n\n        let val = rx3.recv().await;\n        assert!(val);\n\n        let (a, b) = join!(a, b);\n        a.unwrap();\n        b.unwrap();\n    }\n}\n"
  },
  {
    "path": "libs/llrt_utils/src/module.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse rquickjs::{\n    module::{Exports, ModuleDef},\n    Ctx, Object, Result, Value,\n};\n\npub struct ModuleInfo<T: ModuleDef> {\n    pub name: &'static str,\n    pub module: T,\n}\n\npub fn export_default<'js, F>(ctx: &Ctx<'js>, exports: &Exports<'js>, f: F) -> Result<()>\nwhere\n    F: FnOnce(&Object<'js>) -> Result<()>,\n{\n    let default = Object::new(ctx.clone())?;\n    f(&default)?;\n\n    for name in default.keys::<String>() {\n        let name = name?;\n        let value: Value = default.get(&name)?;\n        exports.export(name, value)?;\n    }\n\n    exports.export(\"default\", default)?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "libs/llrt_utils/src/object.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::collections::BTreeMap;\n\nuse rquickjs::{\n    atom::PredefinedAtom, function::IntoJsFunc, prelude::Func, Array, Coerced, Ctx, Error,\n    Exception, FromJs, IntoAtom, IntoJs, Object, Result, Symbol, Undefined, Value,\n};\n\nuse crate::primordials::{BasePrimordials, Primordial};\n\npub trait ObjectExt<'js> {\n    fn get_optional<K: IntoAtom<'js> + Clone, V: FromJs<'js>>(&self, k: K) -> Result<Option<V>>;\n    fn get_required<K: AsRef<str>, V: FromJs<'js>>(\n        &self,\n        k: K,\n        object_name: &'static str,\n    ) -> Result<V>;\n    fn into_object_or_throw(self, ctx: &Ctx<'js>, object_name: &'static str)\n        -> Result<Object<'js>>;\n}\n\nimpl<'js> ObjectExt<'js> for Object<'js> {\n    fn get_optional<K: IntoAtom<'js> + Clone, V: FromJs<'js> + Sized>(\n        &self,\n        k: K,\n    ) -> Result<Option<V>> {\n        self.get::<K, Option<V>>(k)\n    }\n\n    fn get_required<K: AsRef<str>, V: FromJs<'js>>(\n        &self,\n        k: K,\n        object_name: &'static str,\n    ) -> Result<V> {\n        let k = k.as_ref();\n        self.get::<&str, Option<V>>(k)?.ok_or_else(|| {\n            Exception::throw_type(\n                self.ctx(),\n                &[object_name, \" '\", k, \"' property required\"].concat(),\n            )\n        })\n    }\n\n    fn into_object_or_throw(self, _: &Ctx<'js>, _: &'static str) -> Result<Object<'js>> {\n        Ok(self)\n    }\n}\n\nimpl<'js> ObjectExt<'js> for Value<'js> {\n    fn get_optional<K: IntoAtom<'js> + Clone, V: FromJs<'js>>(&self, k: K) -> Result<Option<V>> {\n        if let Some(obj) = self.as_object() {\n            return obj.get_optional(k);\n        }\n        Ok(None)\n    }\n\n    fn get_required<K: AsRef<str>, V: FromJs<'js>>(\n        &self,\n        k: K,\n        object_name: &'static str,\n    ) -> Result<V> {\n        self.as_object()\n            .ok_or_else(|| not_a_object_error(self.ctx(), object_name))?\n            .get_required(k, object_name)\n    }\n\n    fn into_object_or_throw(\n        self,\n        ctx: &Ctx<'js>,\n        object_name: &'static str,\n    ) -> Result<Object<'js>> {\n        self.into_object()\n            .ok_or_else(|| not_a_object_error(ctx, object_name))\n    }\n}\n\npub fn not_a_object_error(ctx: &Ctx<'_>, object_name: &str) -> Error {\n    Exception::throw_type(ctx, &[object_name, \" is not an object\"].concat())\n}\n\npub trait CreateSymbol<'js> {\n    fn for_description(ctx: &Ctx<'js>, description: &str) -> Result<Symbol<'js>>;\n}\n\nimpl<'js> CreateSymbol<'js> for Symbol<'js> {\n    fn for_description(ctx: &Ctx<'js>, description: &str) -> Result<Symbol<'js>> {\n        BasePrimordials::get(ctx)?\n            .function_symbol_for\n            .call((description,))\n    }\n}\n\npub struct Proxy<'js> {\n    target: Value<'js>,\n    options: Object<'js>,\n}\n\nimpl<'js> IntoJs<'js> for Proxy<'js> {\n    fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {\n        BasePrimordials::get(ctx)?\n            .constructor_proxy\n            .construct::<_, Value>((self.target, self.options))\n    }\n}\n\nimpl<'js> Proxy<'js> {\n    pub fn new(ctx: Ctx<'js>) -> Result<Self> {\n        let options = Object::new(ctx.clone())?;\n        Ok(Self {\n            target: Undefined.into_value(ctx),\n            options,\n        })\n    }\n\n    pub fn with_target(ctx: Ctx<'js>, target: Value<'js>) -> Result<Self> {\n        let options = Object::new(ctx)?;\n        Ok(Self { target, options })\n    }\n\n    pub fn setter<T, P>(&self, setter: Func<T, P>) -> Result<()>\n    where\n        T: IntoJsFunc<'js, P> + 'js,\n    {\n        self.options.set(PredefinedAtom::Setter, setter)?;\n        Ok(())\n    }\n\n    pub fn getter<T, P>(&self, getter: Func<T, P>) -> Result<()>\n    where\n        T: IntoJsFunc<'js, P> + 'js,\n    {\n        self.options.set(PredefinedAtom::Getter, getter)?;\n        Ok(())\n    }\n}\n\npub fn map_to_entries<'js, K, V, M>(ctx: &Ctx<'js>, map: M) -> Result<Array<'js>>\nwhere\n    M: IntoIterator<Item = (K, V)>,\n    K: IntoJs<'js>,\n    V: IntoJs<'js>,\n{\n    let array = Array::new(ctx.clone())?;\n    for (idx, (key, value)) in map.into_iter().enumerate() {\n        let entry = Array::new(ctx.clone())?;\n        entry.set(0, key)?;\n        entry.set(1, value)?;\n        array.set(idx, entry)?;\n    }\n\n    Ok(array)\n}\n\npub fn array_to_btree_map<'js>(\n    ctx: &Ctx<'js>,\n    array: Array<'js>,\n) -> Result<BTreeMap<String, Coerced<String>>> {\n    let value = object_from_entries(ctx, array)?;\n    let value = value.into_value();\n    BTreeMap::from_js(ctx, value)\n}\n\npub fn object_from_entries<'js>(ctx: &Ctx<'js>, array: Array<'js>) -> Result<Object<'js>> {\n    let obj = Object::new(ctx.clone())?;\n    for value in array.into_iter().flatten() {\n        if let Some(entry) = value.as_array() {\n            if let Ok(key) = entry.get::<Value>(0) {\n                if let Ok(value) = entry.get::<Value>(1) {\n                    let _ = obj.set(key, value); //ignore result of failed\n                }\n            }\n        }\n    }\n    Ok(obj)\n}\n"
  },
  {
    "path": "libs/llrt_utils/src/option.rs",
    "content": "use rquickjs::{\n    class::{Trace, Tracer},\n    function::{FromParam, ParamRequirement, ParamsAccessor},\n    Ctx, FromJs, IntoJs, JsLifetime, Result, Type, Value,\n};\n\n/// Helper type for treating an undefined value as None, without treating null as None\n#[derive(Clone)]\npub struct Undefined<T>(pub Option<T>);\n\nimpl<'js, T: FromJs<'js>> FromJs<'js> for Undefined<T> {\n    fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        if value.type_of() == Type::Undefined {\n            Ok(Self(None))\n        } else {\n            Ok(Self(Some(FromJs::from_js(ctx, value)?)))\n        }\n    }\n}\n\nimpl<'js, T: IntoJs<'js>> IntoJs<'js> for Undefined<T> {\n    fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {\n        match self.0 {\n            None => Ok(Value::new_undefined(ctx.clone())),\n            Some(val) => val.into_js(ctx),\n        }\n    }\n}\n\nimpl<T> Default for Undefined<T> {\n    fn default() -> Self {\n        Self(None)\n    }\n}\n\nunsafe impl<'js, T: JsLifetime<'js>> JsLifetime<'js> for Undefined<T> {\n    type Changed<'to> = Undefined<T::Changed<'to>>;\n}\n\nimpl<'js, T: Trace<'js>> Trace<'js> for Undefined<T> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.0.trace(tracer)\n    }\n}\n\n/// Helper type for converting an None into null instead of undefined.\n/// Needed while rquickjs::function::Null has no IntoJs implementation\n#[derive(Clone)]\npub struct Null<T>(pub Option<T>);\n\nimpl<'js, T: FromJs<'js>> FromJs<'js> for Null<T> {\n    fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        if value.type_of() == Type::Null {\n            Ok(Self(None))\n        } else {\n            Ok(Self(Some(FromJs::from_js(ctx, value)?)))\n        }\n    }\n}\n\nimpl<'js, T: IntoJs<'js>> IntoJs<'js> for Null<T> {\n    fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {\n        match self.0 {\n            None => Ok(Value::new_null(ctx.clone())),\n            Some(val) => val.into_js(ctx),\n        }\n    }\n}\n\nunsafe impl<'js, T: JsLifetime<'js>> JsLifetime<'js> for Null<T> {\n    type Changed<'to> = Null<T::Changed<'to>>;\n}\n\nimpl<'js, T: Trace<'js>> Trace<'js> for Null<T> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.0.trace(tracer)\n    }\n}\n\n/// Helper type for accepting no value, or null, but considering undefined as a value\npub struct NullableOpt<T>(pub Option<T>);\n\nimpl<'js, T: FromJs<'js>> FromParam<'js> for NullableOpt<T> {\n    fn param_requirement() -> ParamRequirement {\n        ParamRequirement::optional()\n    }\n\n    fn from_param<'a>(params: &mut ParamsAccessor<'a, 'js>) -> Result<Self> {\n        if !params.is_empty() {\n            let arg = params.arg();\n            if arg.is_null() {\n                Ok(NullableOpt(None))\n            } else {\n                let ctx = params.ctx().clone();\n                Ok(NullableOpt(Some(T::from_js(&ctx, arg)?)))\n            }\n        } else {\n            Ok(NullableOpt(None))\n        }\n    }\n}\n"
  },
  {
    "path": "libs/llrt_utils/src/primordials.rs",
    "content": "use std::any::type_name;\n\nuse rquickjs::{\n    atom::PredefinedAtom, function::Constructor, runtime::UserDataGuard, Ctx, Function, JsLifetime,\n    Object, Result, Symbol,\n};\n\nuse crate::{class::CUSTOM_INSPECT_SYMBOL_DESCRIPTION, result::ResultExt};\n\n#[derive(JsLifetime)]\npub struct BasePrimordials<'js> {\n    // Constructors\n    pub constructor_map: Constructor<'js>,\n    pub constructor_set: Constructor<'js>,\n    pub constructor_date: Constructor<'js>,\n    pub constructor_error: Constructor<'js>,\n    pub constructor_type_error: Constructor<'js>,\n    pub constructor_range_error: Constructor<'js>,\n    pub constructor_regexp: Constructor<'js>,\n    pub constructor_uint8array: Constructor<'js>,\n    pub constructor_array_buffer: Constructor<'js>,\n    pub constructor_proxy: Constructor<'js>,\n    pub constructor_object: Constructor<'js>,\n    pub constructor_bool: Constructor<'js>,\n    pub constructor_number: Constructor<'js>,\n    pub constructor_string: Constructor<'js>,\n\n    // Prototypes\n    pub prototype_object: Object<'js>,\n    pub prototype_date: Object<'js>,\n    pub prototype_regexp: Object<'js>,\n    pub prototype_set: Object<'js>,\n    pub prototype_map: Object<'js>,\n    pub prototype_error: Object<'js>,\n\n    // Functions\n    pub function_array_from: Function<'js>,\n    pub function_array_buffer_is_view: Function<'js>,\n    pub function_get_own_property_descriptor: Function<'js>,\n    pub function_parse_int: Function<'js>,\n    pub function_parse_float: Function<'js>,\n    pub function_symbol_for: Function<'js>,\n\n    // Symbols\n    pub symbol_custom_inspect: Symbol<'js>,\n}\n\npub trait Primordial<'js>\nwhere\n    Self: Sized + JsLifetime<'js>,\n{\n    fn get<'a>(ctx: &'a Ctx<'js>) -> Result<UserDataGuard<'a, Self>> {\n        let userdata = ctx.userdata::<Self>().or_throw_msg(\n            ctx,\n            &[\n                \"Userdata of \",\n                type_name::<Self>(),\n                \" not initialized. Call init(&ctx) on this type.\",\n            ]\n            .concat(),\n        )?;\n\n        Ok(userdata)\n    }\n\n    fn init<'a>(ctx: &'a Ctx<'js>) -> Result<()> {\n        if ctx.userdata::<Self>().is_none() {\n            let primoridals = Self::new(ctx)?;\n            let _ = ctx.store_userdata(primoridals);\n        }\n\n        Ok(())\n    }\n    fn new(ctx: &Ctx<'js>) -> Result<Self>;\n}\n\nimpl<'js> Primordial<'js> for BasePrimordials<'js> {\n    fn new(ctx: &Ctx<'js>) -> Result<Self> {\n        let globals = ctx.globals();\n\n        let constructor_object: Constructor = globals.get(PredefinedAtom::Object)?;\n        let prototype_object: Object = constructor_object.get(PredefinedAtom::Prototype)?;\n\n        let constructor_proxy: Constructor = globals.get(PredefinedAtom::Proxy)?;\n\n        let function_get_own_property_descriptor: Function =\n            constructor_object.get(PredefinedAtom::GetOwnPropertyDescriptor)?;\n\n        let constructor_date: Constructor = globals.get(PredefinedAtom::Date)?;\n        let prototype_date: Object = constructor_date.get(PredefinedAtom::Prototype)?;\n\n        let constructor_map: Constructor = globals.get(PredefinedAtom::Map)?;\n        let prototype_map: Object = constructor_map.get(PredefinedAtom::Prototype)?;\n\n        let constructor_set: Constructor = globals.get(PredefinedAtom::Set)?;\n        let prototype_set: Object = constructor_set.get(PredefinedAtom::Prototype)?;\n\n        let constructor_regexp: Constructor = globals.get(PredefinedAtom::RegExp)?;\n        let prototype_regexp: Object = constructor_regexp.get(PredefinedAtom::Prototype)?;\n\n        let constructor_uint8array: Constructor = globals.get(PredefinedAtom::Uint8Array)?;\n        let constructor_arraybuffer: Constructor = globals.get(PredefinedAtom::ArrayBuffer)?;\n\n        let constructor_error: Constructor = globals.get(PredefinedAtom::Error)?;\n        let constructor_type_error: Constructor = ctx.globals().get(PredefinedAtom::TypeError)?;\n        let constructor_range_error: Constructor = ctx.globals().get(PredefinedAtom::RangeError)?;\n        let prototype_error: Object = constructor_error.get(PredefinedAtom::Prototype)?;\n\n        let constructor_array: Object = globals.get(PredefinedAtom::Array)?;\n        let function_array_from: Function = constructor_array.get(PredefinedAtom::From)?;\n\n        let constructor_array_buffer: Object = globals.get(PredefinedAtom::ArrayBuffer)?;\n        let function_array_buffer_is_view: Function = constructor_array_buffer.get(\"isView\")?;\n\n        let constructor_bool: Constructor = globals.get(PredefinedAtom::Boolean)?;\n\n        let constructor_number: Constructor = globals.get(PredefinedAtom::Number)?;\n        let function_parse_float: Function = constructor_number.get(\"parseFloat\")?;\n        let function_parse_int: Function = constructor_number.get(\"parseInt\")?;\n\n        let constructor_string: Constructor = globals.get(PredefinedAtom::String)?;\n\n        let constructor_symbol: Constructor = globals.get(PredefinedAtom::Symbol)?;\n        let function_symbol_for: Function = constructor_symbol.get(PredefinedAtom::For)?;\n\n        let symbol_custom_inspect: Symbol<'js> =\n            function_symbol_for.call((CUSTOM_INSPECT_SYMBOL_DESCRIPTION,))?;\n\n        Ok(Self {\n            constructor_map,\n            constructor_set,\n            constructor_date,\n            constructor_proxy,\n            constructor_error,\n            constructor_type_error,\n            constructor_range_error,\n            constructor_regexp,\n            constructor_uint8array,\n            constructor_array_buffer: constructor_arraybuffer,\n            constructor_object,\n            constructor_bool,\n            constructor_number,\n            constructor_string,\n            prototype_object,\n            prototype_date,\n            prototype_regexp,\n            prototype_set,\n            prototype_map,\n            prototype_error,\n            function_array_from,\n            function_array_buffer_is_view,\n            function_get_own_property_descriptor,\n            function_parse_float,\n            function_parse_int,\n            function_symbol_for,\n            symbol_custom_inspect,\n        })\n    }\n}\n"
  },
  {
    "path": "libs/llrt_utils/src/provider.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#[derive(PartialEq)]\npub enum ProviderType {\n    None,\n    Resource(String), // Custom asynchronous resource\n    // Userland provider types\n    Immediate,   // [Immediate] Processing by setImmediate()\n    Interval,    // [Interval] Timer by setInterval()\n    MessagePort, // [MessagePort] Port for worker_threads\n    Microtask,   // [Microtask] Processing by queueMicrotask()\n    TickObject,  // [TickObject] Processing by process.nextTick()\n    Timeout,     // [Timeout] Timer by setTimeout()\n    // Internal provider types\n    FsReqCallback,      // [FSREQCALLBACK] Callback for file system operations\n    GetAddrInfoReqWrap, // [GETADDRINFOREQWRAP] When resolving DNS (dns.lookup(), etc.)\n    GetNameInfoReqWrap, // [GETNAMEINFOREQWRAP] DNS reverse lookup\n    PipeWrap,           // [PIPEWRAP] Pipe connection\n    StatWatcher,        // [STATWACHER] File monitoring such as fs.watch()\n    TcpWrap,            // [TCPWRAP] TCP socket wrap (net.Socket, etc.)\n    TimerWrap,          // [TIMERWRAP] Internal timer wrap (low level)\n    TlsWrap,            // [TLSWRAP] TLS socket (HTTPS, etc.)\n    UdpWrap,            // [UDPWRAP] UDP socket wrap (dgram module)\n}\n"
  },
  {
    "path": "libs/llrt_utils/src/result.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#![allow(clippy::uninlined_format_args)]\n\nuse std::{fmt::Write, result::Result as StdResult};\n\nuse rquickjs::{Ctx, Exception, Result};\n\npub trait ResultExt<T> {\n    fn or_throw_msg(self, ctx: &Ctx, msg: &str) -> Result<T>;\n    fn or_throw_range(self, ctx: &Ctx, msg: &str) -> Result<T>;\n    fn or_throw_type(self, ctx: &Ctx, msg: &str) -> Result<T>;\n    fn or_throw(self, ctx: &Ctx) -> Result<T>;\n}\n\npub trait OptionExt<T> {\n    fn and_then_ok<U, E, F>(self, f: F) -> StdResult<Option<U>, E>\n    where\n        F: FnOnce(T) -> StdResult<Option<U>, E>;\n\n    fn unwrap_or_else_ok<E, F>(self, f: F) -> StdResult<T, E>\n    where\n        F: FnOnce() -> StdResult<T, E>;\n}\n\nimpl<T, E: std::fmt::Display> ResultExt<T> for StdResult<T, E> {\n    fn or_throw_msg(self, ctx: &Ctx, msg: &str) -> Result<T> {\n        self.map_err(|e| {\n            let mut message = String::with_capacity(100);\n            message.push_str(msg);\n            message.push_str(\". \");\n            write!(message, \"{}\", e).unwrap();\n            Exception::throw_message(ctx, &message)\n        })\n    }\n\n    fn or_throw_range(self, ctx: &Ctx, msg: &str) -> Result<T> {\n        self.map_err(|e| {\n            let mut message = String::with_capacity(100);\n            if !message.is_empty() {\n                message.push_str(msg);\n                message.push_str(\". \");\n            }\n            write!(message, \"{}\", e).unwrap();\n            Exception::throw_range(ctx, &message)\n        })\n    }\n\n    fn or_throw_type(self, ctx: &Ctx, msg: &str) -> Result<T> {\n        self.map_err(|e| {\n            let mut message = String::with_capacity(100);\n            if !msg.is_empty() {\n                message.push_str(msg);\n                message.push_str(\". \");\n            }\n            write!(message, \"{}\", e).unwrap();\n            Exception::throw_type(ctx, &message)\n        })\n    }\n\n    fn or_throw(self, ctx: &Ctx) -> Result<T> {\n        self.map_err(|err| Exception::throw_message(ctx, &err.to_string()))\n    }\n}\n\nimpl<T> ResultExt<T> for Option<T> {\n    fn or_throw_msg(self, ctx: &Ctx, msg: &str) -> Result<T> {\n        self.ok_or_else(|| Exception::throw_message(ctx, msg))\n    }\n\n    fn or_throw_range(self, ctx: &Ctx, msg: &str) -> Result<T> {\n        self.ok_or_else(|| Exception::throw_range(ctx, msg))\n    }\n\n    fn or_throw_type(self, ctx: &Ctx, msg: &str) -> Result<T> {\n        self.ok_or_else(|| Exception::throw_type(ctx, msg))\n    }\n\n    fn or_throw(self, ctx: &Ctx) -> Result<T> {\n        self.ok_or_else(|| Exception::throw_message(ctx, \"Value is not present\"))\n    }\n}\n\nimpl<T> OptionExt<T> for Option<T> {\n    fn and_then_ok<U, E, F>(self, f: F) -> StdResult<Option<U>, E>\n    where\n        F: FnOnce(T) -> StdResult<Option<U>, E>,\n    {\n        match self {\n            Some(v) => f(v),\n            None => Ok(None),\n        }\n    }\n\n    fn unwrap_or_else_ok<E, F>(self, f: F) -> StdResult<T, E>\n    where\n        F: FnOnce() -> StdResult<T, E>,\n    {\n        match self {\n            Some(v) => Ok(v),\n            None => f(),\n        }\n    }\n}\n"
  },
  {
    "path": "libs/llrt_utils/src/reuse_list.rs",
    "content": "use std::fmt::Debug;\n\n#[derive(Default, Clone)]\npub struct ReuseList<T> {\n    items: Vec<Option<T>>,\n    slots: Vec<usize>,\n    last_slot_idx: usize,\n    len: usize,\n    slot_size: usize,\n}\n\nimpl<T: Debug> Debug for ReuseList<T> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"ReuseList\")\n            .field(\"items\", &self.items)\n            .field(\"slots\", &self.slots)\n            .finish()\n    }\n}\n\nimpl<T> ReuseList<T> {\n    pub fn new() -> Self {\n        Self::with_capacity(0)\n    }\n\n    //is empty\n    pub fn is_empty(&self) -> bool {\n        self.len == 0\n    }\n\n    //create a with capacity\n    pub fn with_capacity(capacity: usize) -> Self {\n        Self {\n            items: Vec::with_capacity(capacity),\n            slots: Vec::with_capacity(capacity >> 2),\n            last_slot_idx: 0,\n            len: 0,\n            slot_size: 0,\n        }\n    }\n\n    pub fn append(&mut self, item: T) -> usize {\n        if self.slot_size > 0 {\n            //reuse empty slot if valid\n            let slot = self.slots[self.last_slot_idx - 1];\n            if slot > 0 {\n                self.items[slot - 1] = Some(item);\n                self.slots[self.last_slot_idx - 1] = 0;\n                if self.last_slot_idx > 1 {\n                    self.last_slot_idx -= 1;\n                }\n\n                self.len += 1;\n                return slot - 1;\n            }\n        }\n        //no valid empty slots, append to end\n        self.items.push(Some(item));\n        self.len += 1;\n        self.items.len() - 1\n    }\n\n    pub fn remove(&mut self, index: usize) -> Option<T> {\n        if index >= self.items.len() {\n            return None;\n        }\n\n        let item = self.items[index].take();\n        if item.is_some() {\n            if self.slot_size > 0 && self.slots[self.last_slot_idx - 1] == 0 {\n                self.slots[self.last_slot_idx - 1] = index + 1;\n            } else {\n                self.slots.push(index + 1);\n                self.last_slot_idx += 1;\n                self.slot_size += 1;\n            }\n            self.len -= 1;\n        }\n        item\n    }\n\n    pub fn get(&self, index: usize) -> Option<&T> {\n        if index >= self.items.len() {\n            None\n        } else {\n            self.items[index].as_ref()\n        }\n    }\n\n    pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {\n        if index >= self.items.len() {\n            None\n        } else {\n            self.items[index].as_mut()\n        }\n    }\n\n    pub fn capacity(&self) -> usize {\n        self.items.capacity()\n    }\n\n    pub fn len(&self) -> usize {\n        self.len\n    }\n\n    pub fn iter(&self) -> impl Iterator<Item = &T> {\n        self.items.iter().filter_map(|x| x.as_ref())\n    }\n\n    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {\n        self.items.iter_mut().filter_map(|x| x.as_mut())\n    }\n\n    //implement clear\n    pub fn clear(&mut self) {\n        self.items.clear();\n        self.slots.clear();\n        self.last_slot_idx = 0;\n        self.len = 0;\n        self.slot_size = 0;\n    }\n\n    pub fn optimize(&mut self) {\n        let mut new_items = Vec::with_capacity(self.len);\n\n        for item in self.items.iter_mut() {\n            let a = item.take();\n            if a.is_some() {\n                new_items.push(a);\n            }\n        }\n        self.items = new_items;\n        self.slots.clear();\n        self.last_slot_idx = 0;\n        self.slot_size = 0;\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_new() {\n        let list: ReuseList<i32> = ReuseList::new();\n        assert_eq!(list.len(), 0);\n        assert_eq!(list.capacity(), 0);\n        assert_eq!(list.items.len(), 0);\n        assert_eq!(list.slots.len(), 0);\n    }\n\n    #[test]\n    fn test_with_capacity() {\n        let list: ReuseList<i32> = ReuseList::with_capacity(10);\n        assert_eq!(list.len(), 0);\n        assert_eq!(list.capacity(), 10);\n        assert_eq!(list.items.len(), 0);\n        assert_eq!(list.slots.len(), 0);\n    }\n\n    #[test]\n    fn test_append() {\n        let mut list = ReuseList::new();\n        assert_eq!(list.append(1), 0);\n        assert_eq!(list.append(2), 1);\n        assert_eq!(list.append(3), 2);\n        assert_eq!(list.len(), 3);\n\n        let items: Vec<i32> = list.iter().cloned().collect();\n        assert_eq!(items, vec![1, 2, 3]);\n        assert_eq!(list.items, vec![Some(1), Some(2), Some(3)]);\n        assert_eq!(list.slots, vec![]);\n    }\n\n    #[test]\n    fn test_remove() {\n        let mut list = ReuseList::new();\n        list.append(1);\n        list.append(2);\n        list.append(3);\n\n        assert_eq!(list.remove(1), Some(2));\n        assert_eq!(list.len(), 2);\n\n        let items: Vec<i32> = list.iter().cloned().collect();\n        assert_eq!(items, vec![1, 3]);\n        assert_eq!(list.items, vec![Some(1), None, Some(3)]);\n        assert_eq!(list.slots, vec![2]);\n\n        assert_eq!(list.remove(5), None);\n    }\n\n    #[test]\n    fn test_reuse_slots() {\n        let mut list = ReuseList::new();\n        list.append(1);\n        list.append(2);\n        list.append(3);\n\n        list.remove(1); // Remove 2\n        assert_eq!(list.append(4), 1); // Should reuse index 1\n\n        let items: Vec<i32> = list.iter().cloned().collect();\n        assert_eq!(items, vec![1, 4, 3]);\n        assert_eq!(list.items, vec![Some(1), Some(4), Some(3)]);\n        assert_eq!(list.slots, vec![0]);\n    }\n\n    #[test]\n    fn test_get() {\n        let mut list = ReuseList::new();\n        list.append(1);\n        list.append(2);\n\n        assert_eq!(list.get(0), Some(&1));\n        assert_eq!(list.get(1), Some(&2));\n        assert_eq!(list.get(2), None);\n        assert_eq!(list.items, vec![Some(1), Some(2)]);\n        assert_eq!(list.slots, vec![]);\n    }\n\n    #[test]\n    fn test_get_mut() {\n        let mut list = ReuseList::new();\n        list.append(1);\n        list.append(2);\n\n        if let Some(value) = list.get_mut(0) {\n            *value = 10;\n        }\n\n        assert_eq!(list.get(0), Some(&10));\n        assert_eq!(list.items, vec![Some(10), Some(2)]);\n        assert_eq!(list.slots, vec![]);\n    }\n\n    #[test]\n    fn test_iter() {\n        let mut list = ReuseList::new();\n        list.append(1);\n        list.append(2);\n        list.append(3);\n        list.remove(1);\n\n        let items: Vec<i32> = list.iter().cloned().collect();\n        assert_eq!(items, vec![1, 3]);\n        assert_eq!(list.items, vec![Some(1), None, Some(3)]);\n        assert_eq!(list.slots, vec![2]);\n    }\n\n    #[test]\n    fn test_iter_mut() {\n        let mut list = ReuseList::new();\n        list.append(1);\n        list.append(2);\n        list.append(3);\n\n        for item in list.iter_mut() {\n            *item *= 2;\n        }\n\n        let items: Vec<i32> = list.iter().cloned().collect();\n        assert_eq!(items, vec![2, 4, 6]);\n        assert_eq!(list.items, vec![Some(2), Some(4), Some(6)]);\n        assert_eq!(list.slots, vec![]);\n    }\n\n    #[test]\n    fn test_multiple_removes() {\n        let mut list = ReuseList::new();\n        for i in 0..5 {\n            list.append(i);\n        }\n\n        list.remove(1);\n        list.remove(3);\n\n        let items: Vec<i32> = list.iter().cloned().collect();\n        assert_eq!(items, vec![0, 2, 4]);\n        assert_eq!(list.items, vec![Some(0), None, Some(2), None, Some(4)]);\n        assert_eq!(list.slots, vec![2, 4]);\n\n        // Test reuse of both slots\n        list.append(10);\n        list.append(11);\n\n        let items: Vec<i32> = list.iter().cloned().collect();\n        assert_eq!(items, vec![0, 11, 2, 10, 4]);\n        assert_eq!(\n            list.items,\n            vec![Some(0), Some(11), Some(2), Some(10), Some(4)]\n        );\n        assert_eq!(list.slots, vec![0, 0]);\n\n        list.remove(0);\n\n        let items: Vec<i32> = list.iter().cloned().collect();\n        assert_eq!(items, vec![11, 2, 10, 4]);\n        assert_eq!(list.items, vec![None, Some(11), Some(2), Some(10), Some(4)]);\n        assert_eq!(list.slots, vec![1, 0]);\n\n        list.append(20);\n\n        let items: Vec<i32> = list.iter().cloned().collect();\n        assert_eq!(items, vec![20, 11, 2, 10, 4]);\n        assert_eq!(\n            list.items,\n            vec![Some(20), Some(11), Some(2), Some(10), Some(4)]\n        );\n        assert_eq!(list.slots, vec![0, 0]);\n\n        //remove all items\n        list.clear();\n    }\n\n    #[test]\n    fn test_optimize() {\n        let mut list = ReuseList::new();\n        list.append(1);\n        list.append(2);\n        list.append(3);\n        list.remove(1);\n\n        assert_eq!(list.items, vec![Some(1), None, Some(3)]);\n        assert_eq!(list.slots, vec![2]);\n\n        list.optimize();\n\n        assert_eq!(list.items, vec![Some(1), Some(3)]);\n        assert_eq!(list.slots, vec![]);\n        assert_eq!(list.last_slot_idx, 0);\n        assert_eq!(list.slot_size, 0);\n\n        let items: Vec<i32> = list.iter().cloned().collect();\n        assert_eq!(items, vec![1, 3]);\n    }\n}\n"
  },
  {
    "path": "libs/llrt_utils/src/signals.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse rquickjs::{prelude::Opt, Ctx, Exception, Result, Value};\n\nuse crate::result::ResultExt;\nuse std::io;\n\n#[cfg(unix)]\nmacro_rules! generate_signal_from_str_fn {\n    ($($signal:path),*) => {\n        pub fn signal_from_str(signal: &str) -> Option<i32> {\n            let signal = [\"libc::\", signal].concat();\n            match signal.as_str() {\n                $(stringify!($signal) => Some($signal),)*\n                _ => None,\n            }\n        }\n\n        pub fn signal_str_from_i32(signal: i32) -> Option<&'static str> {\n            $(if signal == $signal {\n                return Some(&stringify!($signal)[6..]);\n            })*\n            None\n        }\n    };\n}\n\n#[cfg(unix)]\ngenerate_signal_from_str_fn!(\n    libc::SIGHUP,\n    libc::SIGINT,\n    libc::SIGQUIT,\n    libc::SIGILL,\n    libc::SIGABRT,\n    libc::SIGFPE,\n    libc::SIGKILL,\n    libc::SIGSEGV,\n    libc::SIGPIPE,\n    libc::SIGALRM,\n    libc::SIGTERM\n);\n\n#[cfg(not(unix))]\nstatic WINDOWS_SIGTERM: i32 = -1;\n\npub fn parse_signal(signal: Option<Value<'_>>) -> Result<i32> {\n    let Some(val) = signal else {\n        #[cfg(unix)]\n        return Ok(libc::SIGTERM);\n        #[cfg(not(unix))]\n        return Ok(WINDOWS_SIGTERM);\n    };\n\n    if let Some(num) = val.as_number() {\n        let sig = num as i32;\n        #[cfg(unix)]\n        return Ok(sig);\n        // On Windows: 0 checks existence, anything else kills\n        #[cfg(not(unix))]\n        return Ok(if sig == 0 { 0 } else { WINDOWS_SIGTERM });\n    }\n\n    if let Some(str_val) = val.as_string() {\n        let s = str_val.to_string()?;\n\n        #[cfg(unix)]\n        let mapped_sig = signal_from_str(&s);\n\n        #[cfg(not(unix))]\n        let mapped_sig = match s.as_str() {\n            \"SIGINT\" | \"SIGTERM\" | \"SIGKILL\" | \"SIGQUIT\" | \"SIGHUP\" | \"SIGUSR1\" => {\n                Some(WINDOWS_SIGTERM)\n            },\n            _ => None,\n        };\n\n        return match mapped_sig {\n            Some(sig) => Ok(sig),\n            None => Err(Exception::throw_type(\n                val.ctx(),\n                &format!(\"Unknown signal: {}\", s),\n            )),\n        };\n    }\n\n    Err(Exception::throw_type(val.ctx(), \"Invalid signal type\"))\n}\n\n#[cfg(unix)]\npub fn kill_process_raw(pid: u32, signal: i32) -> io::Result<()> {\n    // libc::kill returns 0 on success, -1 on error\n    // SAFETY: kill is a safe system call as long as the signal value is valid, which is ensured by parse_signal\n    if unsafe { libc::kill(pid as i32, signal) } == 0 {\n        Ok(())\n    } else {\n        Err(io::Error::last_os_error())\n    }\n}\n\n#[cfg(windows)]\npub fn kill_process_raw(pid: u32, signal: i32) -> io::Result<()> {\n    use windows_sys::Win32::Foundation::CloseHandle;\n    use windows_sys::Win32::System::Threading::{OpenProcess, TerminateProcess, PROCESS_TERMINATE};\n\n    // SAFETY: OpenProcess is safe to call with valid parameters, and PROCESS_TERMINATE is a valid access right\n    let handle = unsafe { OpenProcess(PROCESS_TERMINATE, 0, pid) };\n    if handle == std::ptr::null_mut() {\n        return Err(io::Error::last_os_error());\n    }\n\n    let result = if signal == 0 {\n        Ok(())\n    } else {\n        // SAFETY: TerminateProcess is safe to call with a valid process handle obtained from OpenProcess\n        if unsafe { TerminateProcess(handle, 1) } != 0 {\n            Ok(())\n        } else {\n            Err(io::Error::last_os_error())\n        }\n    };\n\n    // SAFETY: CloseHandle is safe to call with a valid handle obtained from OpenProcess\n    unsafe { CloseHandle(handle) };\n    result\n}\n\npub fn kill(ctx: &Ctx<'_>, pid: u32, signal: Opt<Value<'_>>) -> Result<bool> {\n    let signal = parse_signal(signal.0)?;\n\n    kill_process_raw(pid, signal)\n        .map(|_| true)\n        .or_else(|e| {\n            // Handle \"Process Not Found\" / \"Existence Check\" logic\n            // If signal is 0 (check existence) and we hit a specific error, return Ok(false).\n\n            #[cfg(unix)]\n            let is_not_found = e.raw_os_error() == Some(libc::ESRCH); // Error 3\n\n            #[cfg(windows)]\n            let is_not_found = true; // On Windows, any OpenProcess failure during check implies \"not found\" (or not accessible)\n\n            if signal == 0 && is_not_found {\n                Ok(false)\n            } else {\n                Err(e)\n            }\n        })\n        .or_throw(ctx)\n}\n"
  },
  {
    "path": "libs/llrt_utils/src/string.rs",
    "content": "use rquickjs::{Coerced, Result, Value};\n\n#[inline]\npub fn get_string(value: &Value<'_>) -> Result<Option<String>> {\n    if let Some(val) = value.as_string() {\n        let string = val.to_string()?;\n        return Ok(Some(string));\n    }\n    Ok(None)\n}\n\npub fn get_coerced_string(value: &Value<'_>) -> Option<String> {\n    if let Ok(val) = value.get::<Coerced<String>>() {\n        return Some(val.0);\n    };\n    None\n}\n"
  },
  {
    "path": "libs/llrt_utils/src/sysinfo.rs",
    "content": "#[cfg(target_os = \"macos\")]\npub const PLATFORM: &str = \"darwin\";\n#[cfg(target_os = \"windows\")]\npub const PLATFORM: &str = \"win32\";\n#[cfg(not(any(target_os = \"macos\", target_os = \"windows\")))]\npub const PLATFORM: &str = std::env::consts::OS;\n\n#[cfg(any(target_arch = \"x86_64\", target_arch = \"x86\"))]\npub const ARCH: &str = \"x64\";\n#[cfg(target_arch = \"aarch64\")]\npub const ARCH: &str = \"arm64\";\n#[cfg(not(any(target_arch = \"x86_64\", target_arch = \"x86\", target_arch = \"aarch64\")))]\npub const ARCH: &str = std::env::consts::ARCH;\n"
  },
  {
    "path": "libs/llrt_utils/src/time.rs",
    "content": "use std::{\n    sync::atomic::{AtomicU64, Ordering},\n    time::SystemTime,\n};\n\nstatic TIME_ORIGIN: AtomicU64 = AtomicU64::new(0);\n\n/// Get the current time in nanoseconds.\n///\n/// # Safety\n/// - Good until the year 2554\n/// - Always use a checked substraction since this can return 0\npub fn now_nanos() -> u64 {\n    SystemTime::now()\n        .duration_since(std::time::UNIX_EPOCH)\n        .unwrap_or_default()\n        .as_nanos() as u64\n}\n\n/// Get the current time in millis.\n///\n/// # Safety\n/// - Good until the year 2554\n/// - Always use a checked substraction since this can return 0\npub fn now_millis() -> i64 {\n    SystemTime::now()\n        .duration_since(std::time::UNIX_EPOCH)\n        .unwrap_or_default()\n        .as_millis() as i64\n}\n\n/// Get the origin time in nanoseconds.\n///\n/// # Safety\n/// - Good until the year 2554\n/// - Always use a checked substraction since this can return 0\npub fn origin_nanos() -> u64 {\n    TIME_ORIGIN.load(Ordering::Relaxed)\n}\n\n// For accuracy reasons, this function should be executed when the vm is initialized\npub fn init() {\n    if TIME_ORIGIN.load(Ordering::Relaxed) == 0 {\n        let time_origin = now_nanos();\n        TIME_ORIGIN.store(time_origin, Ordering::Relaxed)\n    }\n}\n"
  },
  {
    "path": "linker/ar",
    "content": "#!/bin/bash\nset -e\n\nzig ar \"$@\""
  },
  {
    "path": "linker/cc",
    "content": "#!/bin/bash\nset -e\n\ntarget=$1\nshift\n\nnew_array=()\nfor value in \"$@\"\ndo\n    [[ $value != *self-contained/*crt* ]] && [[ $value != *lgcc_s* ]] && [[ $value != *lc_nonshared* ]] && [[ $value != *latomic* ]] && new_array+=($value)\ndone\n\nzig cc \"${new_array[@]}\" -target $target"
  },
  {
    "path": "linker/cc-aarch64-linux-gnu",
    "content": "#!/bin/bash\n$(dirname $(realpath \"$0\"))/cc aarch64-linux-gnu \"$@\""
  },
  {
    "path": "linker/cc-aarch64-linux-musl",
    "content": "#!/bin/bash\n$(dirname $(realpath \"$0\"))/cc aarch64-linux-musl \"$@\""
  },
  {
    "path": "linker/cc-x86_64-linux-gnu",
    "content": "#!/bin/bash\n$(dirname $(realpath \"$0\"))/cc x86_64-linux-gnu \"$@\""
  },
  {
    "path": "linker/cc-x86_64-linux-musl",
    "content": "#!/bin/bash\n$(dirname $(realpath \"$0\"))/cc x86_64-linux-musl \"$@\""
  },
  {
    "path": "linker/cxx",
    "content": "#!/bin/bash\nset -e\n\ntarget=$1\nshift\n\nnew_array=()\nfor value in \"$@\"\ndo\n    [[ $value != *self-contained/*crt* ]] && [[ $value != *lgcc_s* ]] && new_array+=($value)\ndone\n\nzig c++ \"${new_array[@]}\" -target $target"
  },
  {
    "path": "linker/cxx-aarch64-linux-gnu",
    "content": "#!/bin/bash\n$(dirname $(realpath \"$0\"))/cxx aarch64-linux-gnu \"$@\""
  },
  {
    "path": "linker/cxx-aarch64-linux-musl",
    "content": "#!/bin/bash\n$(dirname $(realpath \"$0\"))/cxx aarch64-linux-musl \"$@\""
  },
  {
    "path": "linker/cxx-x86_64-linux-gnu",
    "content": "#!/bin/bash\n$(dirname $(realpath \"$0\"))/cxx x86_64-linux-gnu \"$@\""
  },
  {
    "path": "linker/cxx-x86_64-linux-musl",
    "content": "#!/bin/bash\n$(dirname $(realpath \"$0\"))/cxx x86_64-linux-musl \"$@\""
  },
  {
    "path": "linker/ranlib",
    "content": "#!/bin/bash\nset -e\n\nzig ranlib \"$@\""
  },
  {
    "path": "llrt/Cargo.toml",
    "content": "[package]\nname = \"llrt\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense-file = \"LICENSE\"\n\n[features]\ndefault = [\"macro\", \"tls-ring\", \"crypto-rust\"]\nmacro = [\"llrt_core/macro\"]\nlambda = [\"llrt_core/lambda\"]\nno-sdk = [\"llrt_core/no-sdk\"]\nuncompressed = [\"llrt_core/uncompressed\"]\nbindgen = [\"llrt_core/bindgen\"]\n\n# TLS crypto backend features\ntls-ring = [\"llrt_core/tls-ring\"]\ntls-aws-lc = [\"llrt_core/tls-aws-lc\"]\ntls-graviola = [\"llrt_core/tls-graviola\"]\ntls-openssl = [\"llrt_core/tls-openssl\"]\n\n# Crypto provider features\ncrypto-rust = [\"llrt_core/crypto-rust\"]\ncrypto-ring = [\"llrt_core/crypto-ring\"]\ncrypto-ring-rust = [\"llrt_core/crypto-ring-rust\"]\ncrypto-graviola = [\"llrt_core/crypto-graviola\"]\ncrypto-graviola-rust = [\"llrt_core/crypto-graviola-rust\"]\ncrypto-openssl = [\"llrt_core/crypto-openssl\"]\n\n# OpenSSL vendored (builds OpenSSL from source)\nopenssl-vendored = [\"llrt_core/openssl-vendored\"]\n\n[dependencies]\nconstcat = { version = \"0.6\", default-features = false }\ncrossterm = { version = \"0.29\", features = [\n  \"events\",\n  \"windows\",\n], default-features = false }\njiff = { version = \"0.2\" }\nllrt_core = { path = \"../llrt_core\", default-features = false }\ntokio = { version = \"1\", features = [\n  \"macros\",\n  \"rt-multi-thread\",\n], default-features = false }\ntracing = { version = \"0.1\", features = [\"log\"], default-features = false }\ntracing-core = { version = \"0.1\", default-features = false }\n\n[target.'cfg(not(target_os = \"windows\"))'.dependencies]\nsnmalloc-rs = { version = \"0.3\", features = [\n  \"default\",\n  \"lto\",\n], default-features = false }\n\n[dev-dependencies]\nllrt_test = { version = \"0.8.1-beta\", path = \"../libs/llrt_test\" }\n\n[[bin]]\nname = \"llrt\"\npath = \"src/main.rs\"\n"
  },
  {
    "path": "llrt/src/base.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\npub use self::base::*;\n\n#[allow(clippy::module_inception)]\nmod base {\n    pub use llrt_core::bytecode;\n    #[cfg(not(feature = \"lambda\"))]\n    pub use llrt_core::compiler;\n    pub use llrt_core::environment;\n    pub use llrt_core::libs;\n    pub use llrt_core::modules;\n    pub use llrt_core::vm;\n}\npub use llrt_core::VERSION;\n\n// rquickjs components\n#[allow(unused_imports)]\npub use llrt_core::{\n    async_with, atom::PredefinedAtom, context::EvalOptions, function::Rest, runtime_client,\n    AsyncContext, CatchResultExt, Ctx, Error, Object, Promise,\n};\n"
  },
  {
    "path": "llrt/src/main.c",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#define _GNU_SOURCE\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <sys/types.h>\n#include <sys/time.h>\n#include <sys/mman.h>\n#include <err.h>\n#include <errno.h>\n#include <pthread.h>\n#include <sys/stat.h>\n#include <zstd.h>\n#include <stdarg.h>\n#include <sys/mman.h>\n#include <sys/syscall.h>\n\n#ifdef __x86_64__\n#define MEMFD_CREATE_SYSCALL_ID 319\n#else\n#define MEMFD_CREATE_SYSCALL_ID 279\n#endif\n\nint memfd_create_syscall(const char *name, unsigned flags)\n{\n\n  return syscall(MEMFD_CREATE_SYSCALL_ID, name, flags);\n}\n\n#define TIMESTAMP_BUFFER_SIZE 50\n\n// Global flag to cache whether logging is enabled\nstatic bool logEnabled = false;\n\n// Function to initialize the logging flag\nvoid initLoggingFlag()\n{\n  char *envValue = getenv(\"LLRT_LOG\");\n  logEnabled = (envValue != NULL);\n}\n\n// Function to get a human-readable timestamp\nvoid getTimestamp(char *timestampBuffer)\n{\n  struct timeval tv;\n  struct tm timeinfo;\n\n  gettimeofday(&tv, NULL);\n  localtime_r(&tv.tv_sec, &timeinfo);\n\n  strftime(timestampBuffer, 26, \"[%Y-%m-%dT%T\", &timeinfo);\n  snprintf(timestampBuffer + 20, 6, \".%03ld]\", tv.tv_usec / 1000);\n}\n\n// Function to print a log message\nvoid printLog(const char *level, const char *format, va_list args)\n{\n\n  char timestampBuffer[TIMESTAMP_BUFFER_SIZE];\n  getTimestamp(timestampBuffer);\n  printf(\"[%s]%s\", level, timestampBuffer);\n  vprintf(format, args);\n}\n\n// Log Info\nvoid logInfo(const char *format, ...)\n{\n  if (logEnabled)\n  {\n    va_list args;\n    va_start(args, format);\n    printLog(\"INFO\", format, args);\n    va_end(args);\n    fflush(stdout);\n  }\n}\n\n// Log Warning\nvoid logWarn(const char *format, ...)\n{\n  if (logEnabled)\n  {\n    va_list args;\n    va_start(args, format);\n    printLog(\"WARN\", format, args);\n    va_end(args);\n    fflush(stdout);\n  }\n}\n\n// Log Error\nvoid logError(const char *format, ...)\n{\n  if (logEnabled)\n  {\n    va_list args;\n    va_start(args, format);\n    printLog(\"ERROR\", format, args);\n    va_end(args);\n    fflush(stdout);\n  }\n}\n\nstatic uint32_t calculateSum(uint32_t *array, uint8_t size)\n{\n  uint32_t sum = 0;\n  for (uint8_t i = 0; i < size; i++)\n  {\n    sum += array[i];\n  }\n  return sum;\n}\n\nstatic double micro_seconds()\n{\n  struct timeval tv;\n  gettimeofday(&tv, NULL);\n  return tv.tv_sec * (1000.0 * 1000.0) + tv.tv_usec;\n}\n\ntypedef struct\n{\n  uint32_t srcSize;\n  uint32_t dstSize;\n  uint32_t id;\n  const void *inputBuffer;\n  const void *outputBuffer;\n} DecompressThreadArgs;\n\nstatic void *decompressPartial(void *arg)\n{\n  DecompressThreadArgs *args = (DecompressThreadArgs *)arg;\n  size_t srcSize = args->srcSize;\n  size_t dstSize = args->dstSize;\n\n  size_t const dSize = ZSTD_decompress((void *)args->outputBuffer, dstSize, args->inputBuffer, srcSize);\n\n  if (ZSTD_isError(dSize))\n  {\n    printf(\"%s!\\n\", ZSTD_getErrorName(dSize));\n    return (void *)1;\n  }\n  return (void *)0;\n}\n\nextern char **environ;\n\nstatic void readData(\n    const char *data,\n    uint8_t parts,\n    uint32_t **inputSizes,\n    uint32_t **outputSizes,\n    uint8_t **compressedData,\n    uint32_t *uncompressedSize)\n{\n  uint32_t metadataSize = sizeof(uint32_t) * parts;\n\n  // Extract input sizes\n  *inputSizes = (uint32_t *)&data[1];\n\n  // Extract output sizes\n  *outputSizes = (uint32_t *)&data[1 + metadataSize];\n\n  *uncompressedSize = calculateSum(*outputSizes, parts);\n\n  // Calculate the offset to the compressed data\n  uint8_t dataOffset = 1 + (2 * metadataSize);\n\n  *compressedData = (uint8_t *)&data[dataOffset];\n}\n\nstatic void decompress(char **uncompressedData, uint32_t *uncompressedSize, int outputFd)\n{\n\n#include \"data.c\"\n\n  uint8_t parts = data[0];\n  uint32_t *inputSizes;\n  uint32_t *outputSizes;\n  uint32_t inputOffset = 0;\n  uint32_t outputOffset = 0;\n  char *uncompressed;\n  uint8_t *compressedData;\n\n  pthread_t threads[parts];\n\n  if (parts > 1)\n  {\n    logInfo(\"Decompressing using %d threads\\n\", parts);\n  }\n  else\n  {\n    logInfo(\"Decompressing\\n\");\n  }\n\n  readData(data, parts, &inputSizes, &outputSizes, &compressedData, uncompressedSize);\n\n  if (ftruncate(outputFd, *uncompressedSize) == -1)\n  {\n    err(1, \"Failed to set file size\");\n  }\n\n  uncompressed = mmap(NULL, *uncompressedSize, PROT_READ | PROT_WRITE, MAP_SHARED, outputFd, 0);\n  if (uncompressed == MAP_FAILED || !uncompressed)\n  {\n    err(1, \"Memory mapping failed: Unable to map %u bytes. Make sure you have enough memory available\", *uncompressedSize);\n  }\n\n  DecompressThreadArgs args[parts];\n  for (uint32_t i = 0; i < parts; i++)\n  {\n    args[i].inputBuffer = compressedData + inputOffset;\n    args[i].outputBuffer = uncompressed + outputOffset;\n    args[i].srcSize = inputSizes[i];\n    args[i].dstSize = outputSizes[i];\n    args[i].id = i;\n    inputOffset += inputSizes[i];\n    outputOffset += outputSizes[i];\n    if (parts > 1)\n    {\n      pthread_create(&threads[i], NULL, decompressPartial, (void *)&args[i]);\n    }\n    else\n    {\n      if (decompressPartial((void *)&args[i]) > 0)\n      {\n        err(1, \"failed to decompress\");\n      }\n    }\n  }\n\n  if (parts > 1)\n  {\n    for (uint8_t i = 0; i < parts; i++)\n    {\n      void *result;\n      pthread_join(threads[i], &result);\n    }\n  }\n\n  *uncompressedData = uncompressed;\n}\n\nint main(int argc, char *argv[])\n{\n  initLoggingFlag();\n\n  logInfo(\"Runtime starting\\n\");\n\n  char *tmpAppname = strrchr(argv[0], '/');\n  char *appname = tmpAppname ? ++tmpAppname : argv[0];\n\n  double t0 = micro_seconds();\n\n  int outputFd = memfd_create_syscall(appname, 0);\n  if (outputFd == -1)\n  {\n    err(1, \"Could not create memfd\");\n  }\n\n  char *uncompressedData;\n  uint32_t uncompressedSize;\n\n  decompress(&uncompressedData, &uncompressedSize, outputFd);\n\n  double t1 = micro_seconds();\n  logInfo(\"Runtime starting\\n\");\n  logInfo(\"Extraction time: %10.4f ms\\n\", (t1 - t0) / 1000.0);\n\n  if (munmap(uncompressedData, uncompressedSize) == -1)\n  {\n    err(1, \"Failed to unmap memory\");\n  }\n\n  double t2 = micro_seconds();\n  logInfo(\"Extraction + write time: %10.4f ms\\n\", (t2 - t0) / 1000.0);\n\n  char **new_argv = malloc((size_t)(argc + 1) * sizeof *new_argv);\n  for (uint8_t i = 0; i < argc; ++i)\n  {\n    if (i == 0)\n    {\n      size_t length = strlen(appname) + 2;\n      new_argv[i] = malloc(length);\n      memcpy(new_argv[i], \"/\", 1);\n      memcpy(new_argv[i] + 1, appname, length);\n      setenv(\"_\", new_argv[i], true);\n    }\n    else\n    {\n      size_t length = strlen(argv[i]) + 1;\n      new_argv[i] = malloc(length);\n      memcpy(new_argv[i], argv[i], length);\n    }\n  }\n  new_argv[argc] = NULL;\n\n  unsigned long startTime = (unsigned long)(micro_seconds() / 1000.0);\n\n  char startTimeStr[16];\n  sprintf(startTimeStr, \"%lu\", startTime);\n\n  char *memorySizeStr = getenv(\"AWS_LAMBDA_FUNCTION_MEMORY_SIZE\");\n  int memorySize = memorySizeStr ? atoi(memorySizeStr) : 128;\n  double memoryFactor = 0.8;\n  if (memorySize > 512)\n  {\n    memoryFactor = 0.9;\n  }\n  if (memorySize > 1024)\n  {\n    memoryFactor = 0.92;\n  }\n  if (memorySize > 2048)\n  {\n    memoryFactor = 0.95;\n  }\n\n  char mimallocReserveMemoryMb[16];\n  sprintf(mimallocReserveMemoryMb, \"%iMiB\", (int)(memorySize * memoryFactor));\n\n  setenv(\"_START_TIME\", startTimeStr, false);\n  setenv(\"MIMALLOC_RESERVE_OS_MEMORY\", mimallocReserveMemoryMb, false);\n  setenv(\"MIMALLOC_LIMIT_OS_ALLOC\", \"1\", false);\n\n  logInfo(\"Starting app\\n\");\n\n  fexecve(outputFd, new_argv, environ);\n\n  logError(\"Failed to start executable\");\n\n  err(1, \"fexecve failed\");\n\n  return 1;\n}"
  },
  {
    "path": "llrt/src/main.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#![allow(clippy::uninlined_format_args)]\n\nuse std::{\n    env,\n    error::Error,\n    path::{Path, PathBuf},\n    process::{exit, ExitCode},\n    string::String,\n    sync::atomic::Ordering,\n    time::Instant,\n};\n\nmod base;\nmod minimal_tracer;\n#[cfg(not(feature = \"lambda\"))]\nmod repl;\n\nuse constcat::concat;\nuse llrt_core::modules::process::EXIT_CODE;\nuse minimal_tracer::MinimalTracer;\nuse tracing::trace;\n\n#[cfg(not(feature = \"lambda\"))]\nuse crate::base::compiler::compile_file;\nuse crate::base::{\n    bytecode::BYTECODE_EXT,\n    environment::ENV_LLRT_REGISTER_HOOKS,\n    libs::{\n        logging::print_error_and_exit,\n        utils::{\n            fs::DirectoryWalker,\n            io::{is_supported_ext, SUPPORTED_EXTENSIONS},\n            sysinfo::{ARCH, PLATFORM},\n        },\n    },\n    modules::path::name_extname,\n    runtime_client,\n    vm::Vm,\n    VERSION,\n};\n\n// rquickjs components\nuse crate::base::{async_with, CatchResultExt};\n\n#[cfg(not(target_os = \"windows\"))]\n#[global_allocator]\nstatic ALLOC: snmalloc_rs::SnMalloc = snmalloc_rs::SnMalloc;\n\n#[tokio::main]\nasync fn main() -> Result<ExitCode, Box<dyn Error + Send + Sync>> {\n    let now = Instant::now();\n\n    MinimalTracer::register()?;\n    trace!(\"Started runtime\");\n\n    let vm = Vm::new().await?;\n    trace!(\"Initialized VM in {}ms\", now.elapsed().as_millis());\n\n    if env::var(\"AWS_LAMBDA_RUNTIME_API\").is_ok() && env::var(\"_HANDLER\").is_ok() {\n        start_runtime(&vm).await\n    } else {\n        start_cli(&vm).await;\n    }\n\n    vm.idle().await?;\n\n    Ok(ExitCode::from(EXIT_CODE.load(Ordering::Relaxed)))\n}\n\npub const VERSION_STRING: &str = concat!(\"LLRT v\", VERSION, \" (\", PLATFORM, \", \", ARCH, \")\");\n\nfn print_version() {\n    println!(\"{VERSION_STRING}\");\n}\n\nfn usage() {\n    print_version();\n    println!(\n        r#\"\n\nUsage:\n  llrt <filename>\n  llrt -v | --version\n  llrt -h | --help\n  llrt -e | --eval <source>\n  llrt --import <file> [--import <file> ...] <main.js>\n  llrt compile input.js [output.lrt]\n  llrt test <test_args>\n\nOptions:\n  -v, --version     Print version information\n  -h, --help        Print this help message\n  -e, --eval        Evaluate the provided source code\n\n  --import <file>   Load and execute the module before running the main script.\n                    This can be used to register module hooks or modify global\n                    behavior. Multiple --import options may be provided and are\n                    executed in order.\n\n  compile           Compile JS to bytecode and compress it with zstd:\n                      if [output.lrt] is omitted, <input>.lrt is used.\n                      lrt file is expected to be executed by the llrt version\n                      that created it\n                      --executable      Create a self-contained executable that includes\n                                        the LLRT runtime\n\n  test              Run tests with provided arguments:\n                      <test_args> -d <directory> <test-filter>\n\n\"#\n    );\n}\n\nasync fn start_runtime(vm: &Vm) {\n    if let Ok(filename) = env::var(ENV_LLRT_REGISTER_HOOKS) {\n        vm.run_file(filename, true, true).await;\n    }\n\n    async_with!(vm.ctx => |ctx|{\n        if let Err(err) = runtime_client::start(&ctx).await.catch(&ctx) {\n            print_error_and_exit(&ctx, err)\n        }\n    })\n    .await;\n}\n\nasync fn start_cli(vm: &Vm) {\n    #[cfg(not(feature = \"lambda\"))]\n    {\n        use crate::base::bytecode::BYTECODE_SELF_CONTAINED_EXECUTABLE_MARKER;\n        use std::io::{Read, Seek, SeekFrom};\n\n        let executable_path = env::current_exe()\n            .unwrap_or_else(|_| PathBuf::from(env::args().next().unwrap_or_default()));\n        trace!(\n            \"Checking if {} is a self-contained executable\",\n            executable_path.display()\n        );\n\n        if let Ok(mut f) = std::fs::File::open(executable_path) {\n            let size_bytes_length: usize = size_of::<u64>();\n            let marker_length: usize = BYTECODE_SELF_CONTAINED_EXECUTABLE_MARKER.len();\n            let offset: usize = marker_length + size_bytes_length;\n            let negative_offset = -i64::from_ne_bytes(offset.to_ne_bytes());\n            let _ = f.seek(SeekFrom::End(negative_offset));\n            let mut end = vec![0; offset];\n            f.read_exact(&mut end).unwrap_or_else(|error| {\n                eprintln!(\"Failed to read end of the executable: {error:?}\");\n                exit(1);\n            });\n\n            if &end[size_bytes_length..] == BYTECODE_SELF_CONTAINED_EXECUTABLE_MARKER {\n                let size_bytes: [u8; size_of::<u64>()] =\n                    end[..size_bytes_length].try_into().unwrap_or_else(|error| {\n                        eprintln!(\"Failed to read length bytes: {error:?}\");\n                        exit(1);\n                    });\n                let size_number = u64::from_le_bytes(size_bytes);\n                let metadata = f.metadata().unwrap_or_else(|error| {\n                    eprintln!(\"Failed to get metadata of executable: {error:?}\");\n                    exit(1);\n                });\n                let unsigned_offset = u64::from_ne_bytes(offset.to_ne_bytes());\n                let start = metadata.len() - size_number - unsigned_offset;\n                let _ = f.seek(SeekFrom::Start(start));\n                let size = usize::from_ne_bytes(size_number.to_ne_bytes());\n                let mut module = vec![0; size];\n                f.read_exact(&mut module).unwrap_or_else(|error| {\n                    eprintln!(\"Failed to read embedded module: {error:?}\");\n                    exit(1);\n                });\n                return vm.run_bytecode(&module).await;\n            }\n        }\n    }\n\n    let args: Vec<String> = env::args().collect();\n\n    if args.len() <= 1 {\n        #[cfg(not(feature = \"lambda\"))]\n        {\n            repl::run_repl(&vm.ctx).await;\n        }\n        #[cfg(feature = \"lambda\")]\n        {\n            eprintln!(\"REPL not supported in \\\"lambda\\\" version.\");\n            exit(1);\n        }\n        #[allow(unreachable_code)]\n        return;\n    }\n\n    let mut i = 1;\n    while i < args.len() {\n        match args[i].as_str() {\n            \"-v\" | \"--version\" => {\n                print_version();\n                return;\n            },\n            \"-h\" | \"--help\" => {\n                usage();\n                return;\n            },\n            \"-e\" | \"--eval\" => {\n                if i + 1 >= args.len() {\n                    eprintln!(\"-e requires an argument\");\n                    exit(1);\n                }\n                let source = &args[i + 1];\n                vm.run(source.as_bytes(), false, false).await;\n                return;\n            },\n            \"--import\" => {\n                if i + 1 >= args.len() {\n                    eprintln!(\"--import requires a filename\");\n                    exit(1);\n                }\n                let file = &args[i + 1];\n                vm.run_file(file, true, true).await;\n                i += 2;\n                continue;\n            },\n            \"test\" => {\n                if let Err(error) = run_tests(vm, &args[i + 1..]).await {\n                    eprintln!(\"{error}\");\n                    exit(1);\n                }\n                return;\n            },\n            \"compile\" => {\n                #[cfg(not(feature = \"lambda\"))]\n                {\n                    if let Some(filename) = args.get(i + 1) {\n                        // Parse args for output_filename and --executable\n                        let mut output_filename = String::new();\n                        let mut create_executable = false;\n\n                        // Parse remaining arguments\n                        for arg in args.iter().skip(i + 2) {\n                            if arg == \"--executable\" {\n                                create_executable = true;\n                            } else if output_filename.is_empty() && !arg.starts_with(\"--\") {\n                                output_filename = arg.clone();\n                            }\n                        }\n\n                        // If no output filename was explicitly provided, generate one\n                        if output_filename.is_empty() {\n                            let mut buf = PathBuf::from(filename);\n                            buf.set_extension(\"lrt\");\n                            output_filename = buf.to_string_lossy().to_string();\n                        }\n\n                        let filename = Path::new(filename);\n                        let output_filename = Path::new(&output_filename);\n                        if let Err(error) =\n                            compile_file(filename, output_filename, create_executable).await\n                        {\n                            eprintln!(\"{error}\");\n                            exit(1);\n                        }\n                        return;\n                    } else {\n                        eprintln!(\"compile: input filename is required.\");\n                        exit(1);\n                    }\n                }\n                #[cfg(feature = \"lambda\")]\n                {\n                    eprintln!(\"Not supported in \\\"lambda\\\" version.\");\n                    exit(1);\n                }\n            },\n            _ => break,\n        }\n    }\n\n    if i >= args.len() {\n        eprintln!(\"No main script provided\");\n        exit(1);\n    }\n\n    let arg = &args[i];\n    let (_, ext) = name_extname(arg);\n\n    let filename = Path::new(arg);\n    let file_exists = filename.exists();\n\n    let global = ext == \".cjs\";\n\n    if is_supported_ext(ext) {\n        if file_exists {\n            return vm.run_file(arg, true, global).await;\n        } else {\n            eprintln!(\"No such file: {}\", arg);\n            exit(1);\n        }\n    } else {\n        if file_exists {\n            return vm.run_file(arg, true, false).await;\n        }\n        eprintln!(\"Unknown command: {}\", arg);\n        usage();\n        exit(1);\n    }\n}\n\nasync fn run_tests(vm: &Vm, args: &[std::string::String]) -> Result<(), String> {\n    let mut filters: Vec<&str> = Vec::with_capacity(args.len());\n\n    let mut root = \".\";\n\n    let mut skip_next = false;\n\n    for (i, arg) in args.iter().enumerate() {\n        if skip_next {\n            skip_next = false;\n            continue;\n        }\n        if arg == \"-d\" {\n            if let Some(dir) = args.get(i + 1) {\n                if !Path::new(dir).exists() {\n                    return Err([\"\\\"\", dir.as_str(), \"\\\" does not exist\"].concat());\n                }\n                root = dir;\n                skip_next = true;\n            }\n        } else {\n            filters.push(arg)\n        }\n    }\n\n    let now = Instant::now();\n\n    let mut entries: Vec<String> = Vec::with_capacity(100);\n    let has_filters = !filters.is_empty();\n\n    if has_filters {\n        trace!(\"Applying filters: {:?}\", filters);\n    }\n\n    trace!(\"Scanning directory \\\"{}\\\"\", root);\n\n    let mut directory_walker = DirectoryWalker::new(PathBuf::from(root), |name| {\n        name != \"node_modules\" && !name.starts_with('.')\n    });\n    directory_walker.set_recursive(true);\n\n    let test_js_extensions: Vec<String> = SUPPORTED_EXTENSIONS\n        .iter()\n        .filter(|&ext| *ext != BYTECODE_EXT)\n        .map(|ext| [\".test\", ext].concat())\n        .collect();\n\n    let pwd = env::current_dir().map_err(|e| e.to_string())?;\n    let pwd = pwd.to_string_lossy();\n    while let Some((entry, _)) = directory_walker.walk().await.map_err(|e| e.to_string())? {\n        if let Some(name) = entry.file_name() {\n            let name = name.to_string_lossy();\n            let name = name.as_ref();\n            for ext_name in &test_js_extensions {\n                if name.ends_with(ext_name)\n                    && (!has_filters || filters.iter().any(|&f| name.contains(f)))\n                {\n                    entries.push([pwd.as_ref(), \"/\", entry.to_string_lossy().as_ref()].concat());\n                }\n            }\n        };\n    }\n\n    entries.sort_unstable();\n\n    trace!(\"Found tests in {}ms\", now.elapsed().as_millis());\n\n    vm.run_with(|ctx| {\n        ctx.globals().set(\"__testEntries\", entries)?;\n        Ok(())\n    })\n    .await;\n\n    vm.run(\n        r#\"\n        import \"llrt:test/index\"\n    \"#,\n        false,\n        false,\n    )\n    .await;\n\n    Ok(())\n}\n"
  },
  {
    "path": "llrt/src/minimal_tracer.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{\n    env,\n    fmt::{self, Write},\n    sync::atomic::{AtomicUsize, Ordering},\n    write,\n};\n\nuse jiff::Timestamp;\nuse tracing::{field::Visit, Id, Level, Subscriber};\nuse tracing_core::{span, Field};\n\nuse crate::base::environment;\n\npub struct StringVisitor<'a> {\n    string: &'a mut String,\n}\nimpl<'a> StringVisitor<'a> {\n    pub(crate) fn new(string: &'a mut String) -> Self {\n        StringVisitor { string }\n    }\n}\n\nimpl Visit for StringVisitor<'_> {\n    fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {\n        if field.name() == \"message\" {\n            write!(self.string, \"{value:?} \").unwrap();\n        } else {\n            write!(self.string, \"{} = {:?}; \", field.name(), value).unwrap();\n        }\n    }\n}\n\nstruct LogFilter {\n    target: Option<String>,\n    level: Option<Level>,\n}\n\npub struct MinimalTracer {\n    enabled: bool,\n    filters: Vec<LogFilter>,\n}\n\nfn string_to_level(string: &str) -> Option<Level> {\n    match string.to_lowercase().as_str() {\n        \"info\" => Some(Level::INFO),\n        \"debug\" => Some(Level::DEBUG),\n        \"warn\" | \"warning\" => Some(Level::WARN),\n        \"trace\" => Some(Level::TRACE),\n        \"error\" => Some(Level::ERROR),\n        _ => None,\n    }\n}\n\nimpl MinimalTracer {\n    pub fn register() -> Result<(), tracing::subscriber::SetGlobalDefaultError> {\n        let mut enabled = false;\n        let mut filters: Vec<LogFilter> = Vec::with_capacity(10);\n        if let Ok(env_value) = env::var(environment::ENV_LLRT_LOG) {\n            enabled = true;\n            for filter in env_value.split(',') {\n                let mut target = Some(filter);\n                let mut level = None;\n                if let Some(equals_index) = target.unwrap().find('=') {\n                    let (first, second) = filter.split_at(equals_index);\n                    target = Some(first);\n                    level = string_to_level(&second[1..])\n                }\n                let target_level = string_to_level(target.unwrap());\n\n                if let Some(target_level) = target_level {\n                    level = Some(target_level);\n                    target = None;\n                }\n\n                filters.push(LogFilter {\n                    target: target.map(|v| v.to_string()),\n                    level,\n                });\n            }\n        }\n\n        tracing::subscriber::set_global_default(MinimalTracer { enabled, filters })\n    }\n}\n\nstatic AUTO_ID: AtomicUsize = AtomicUsize::new(1);\n\nimpl Subscriber for MinimalTracer {\n    fn enabled(&self, metadata: &tracing::Metadata<'_>) -> bool {\n        if self.enabled {\n            if self.filters.is_empty() {\n                return true;\n            }\n\n            let mut matches: bool;\n            for filter in &self.filters {\n                matches = true;\n                if let Some(level) = filter.level {\n                    if metadata.level() > &level {\n                        matches = false;\n                    }\n                }\n                if let Some(target) = &filter.target {\n                    if !metadata.target().starts_with(target) {\n                        matches = false;\n                    }\n                }\n                if matches {\n                    return true;\n                }\n            }\n            return false;\n        }\n        false\n    }\n\n    fn new_span(&self, _span: &span::Attributes<'_>) -> span::Id {\n        Id::from_u64(AUTO_ID.fetch_add(1, Ordering::Relaxed) as u64)\n    }\n\n    fn record(&self, _span: &span::Id, _values: &span::Record<'_>) {}\n\n    fn record_follows_from(&self, _span: &span::Id, _follows: &span::Id) {}\n\n    fn event(&self, event: &tracing::Event<'_>) {\n        let metadata = event.metadata();\n\n        let level = metadata.level();\n        let target = metadata.target();\n\n        let mut text = String::new();\n\n        let mut visitor = StringVisitor::new(&mut text);\n        event.record(&mut visitor);\n\n        let timestamp = Timestamp::now();\n\n        println!(\"{timestamp:.3} {level} {target}: {text}\");\n    }\n\n    fn enter(&self, _span: &span::Id) {}\n\n    fn exit(&self, _span: &span::Id) {}\n}\n"
  },
  {
    "path": "llrt/src/repl.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\r\n// SPDX-License-Identifier: Apache-2.0\r\n#![allow(clippy::uninlined_format_args)]\r\n\r\nuse std::{\r\n    collections::VecDeque,\r\n    env, fs,\r\n    io::{stdout, IsTerminal},\r\n    path::{Path, PathBuf},\r\n};\r\n\r\nuse crossterm::{\r\n    cursor,\r\n    event::{self, Event, KeyCode, KeyEvent, KeyModifiers},\r\n    execute,\r\n    style::Print,\r\n    terminal::{disable_raw_mode, enable_raw_mode, Clear, ClearType},\r\n};\r\n\r\nuse crate::base::libs::{\r\n    logging::format_values,\r\n    utils::{error::ErrorExtensions, result::ResultExt},\r\n};\r\n// rquickjs components\r\nuse crate::base::{\r\n    async_with, AsyncContext, CatchResultExt, Ctx, Error, EvalOptions, Object, PredefinedAtom,\r\n    Promise, Rest,\r\n};\r\n\r\nuse crate::VERSION_STRING;\r\n\r\nasync fn process_input(ctx: &Ctx<'_>, input: &str, tty: bool) -> String {\r\n    // First try to evaluate and format the input\r\n\r\n    let mut options: EvalOptions = EvalOptions::default();\r\n    options.promise = true;\r\n\r\n    match async {\r\n        let promise = ctx.eval_with_options::<Promise, _>(input.as_bytes(), options)?;\r\n        let future = promise.into_future::<Object>();\r\n        let value = future.await?.get(PredefinedAtom::Value)?;\r\n        format_values(ctx, Rest(vec![value]), tty, true)\r\n    }\r\n    .await\r\n    .catch(ctx)\r\n    {\r\n        Ok(v) => v,\r\n        Err(error) => {\r\n            match (|| {\r\n                let error_value = error.into_value(ctx)?;\r\n                format_values(ctx, Rest(vec![error_value]), tty, true)\r\n            })() {\r\n                Ok(s) => s,\r\n                Err(err) => err.to_string(),\r\n            }\r\n        },\r\n    }\r\n}\r\n\r\npub(crate) async fn run_repl(ctx: &AsyncContext) {\r\n    let is_tty = stdout().is_terminal();\r\n    async_with!(ctx => |ctx| {\r\n\r\n        println!(\"Welcome to {}\\nType \\\".exit\\\" or Ctrl+C or Ctrl+D to exit\", VERSION_STRING);\r\n\r\n        let history_file = if cfg!(windows) {\r\n            env::var(\"APPDATA\")\r\n                .ok()\r\n                .map(|path| PathBuf::from(path).join(\"llrtrepl\"))\r\n        } else {\r\n            env::var(\"HOME\")\r\n                .ok()\r\n                .map(|path| PathBuf::from(path).join(\".config\").join(\"llrtrepl\"))\r\n        };\r\n\r\n        let mut persist_history = false;\r\n\r\n        //initialize history\r\n        let mut history: VecDeque<String> = if let Some(ref history_file) = history_file {\r\n\r\n            if let Some(parent) = history_file.parent() {\r\n                fs::create_dir_all(parent).or_throw(&ctx)?;\r\n            }\r\n            persist_history = true;\r\n            if history_file.exists() {\r\n                fs::read_to_string(history_file)?\r\n                    .lines()\r\n                    .map(String::from)\r\n                    .collect()\r\n            } else {\r\n                VecDeque::new()\r\n            }\r\n        } else {\r\n            VecDeque::new()\r\n        };\r\n\r\n        let mut current_input = String::new();\r\n        let mut history_index = history.len();\r\n        let mut cursor_pos = 0;\r\n\r\n        println!(\"\");\r\n\r\n        let exit_repl = || {\r\n            execute!(\r\n                stdout(),\r\n                cursor::MoveToColumn(0),\r\n                Clear(ClearType::CurrentLine),\r\n            )\r\n        };\r\n\r\n        enable_raw_mode()?;\r\n\r\n        let mut added_input_chars = false;\r\n\r\n        loop {\r\n            execute!(\r\n                stdout(),\r\n                cursor::MoveToColumn(0),\r\n                Clear(ClearType::CurrentLine),\r\n                Print(format!(\"> {}\", current_input)),\r\n                cursor::MoveToColumn(cursor_pos as u16 + 2)\r\n            )?;\r\n\r\n            if let Event::Key(KeyEvent {\r\n                code,\r\n                modifiers,\r\n                #[cfg(windows)]\r\n                kind,\r\n                ..\r\n            }) = event::read()?\r\n            {\r\n                #[cfg(windows)]\r\n                if kind == event::KeyEventKind::Release {\r\n                  continue;\r\n                }\r\n                match code {\r\n                    KeyCode::Enter => {\r\n                        println!();\r\n                        let cmd: String = current_input.trim().into();\r\n                        if !cmd.is_empty() {\r\n                            if cmd == \".exit\" {\r\n                                exit_repl()?;\r\n                                break;\r\n                            }\r\n                            execute!(stdout(), cursor::MoveToColumn(0))?;\r\n                            disable_raw_mode()?;\r\n                            let output = process_input(&ctx, &cmd,is_tty).await;\r\n                            println!(\"{output}\");\r\n                            enable_raw_mode()?;\r\n\r\n                            //only push to history if we're not reusing the same command\r\n                            if added_input_chars {\r\n                                history.push_back(cmd);\r\n                                if history.len() > 100 {\r\n                                    history.pop_front();\r\n                                }\r\n                            }\r\n\r\n                            history_index = history.len();\r\n                            current_input.clear();\r\n                            cursor_pos = 0;\r\n                            if persist_history {\r\n                                write_history(&history, history_file.as_deref());\r\n                            }\r\n                            added_input_chars = false;\r\n                        }\r\n                    },\r\n                    KeyCode::Up => {\r\n                        if !history.is_empty() && history_index > 0 {\r\n                            added_input_chars = false;\r\n                            history_index -= 1;\r\n                            current_input = history[history_index].clone();\r\n                            cursor_pos = current_input.len();\r\n                        }\r\n                    },\r\n                    KeyCode::Down => {\r\n                        let history_len =  history.len();\r\n                        if  history_len > 0 {\r\n                            match history_index.cmp(&(history_len - 1)) {\r\n                                    std::cmp::Ordering::Less => {\r\n                                        added_input_chars = false;\r\n                                        history_index += 1;\r\n                                        current_input = history[history_index].clone();\r\n                                        cursor_pos = current_input.len();\r\n                                    }\r\n                                    std::cmp::Ordering::Equal => {\r\n                                        added_input_chars = false;\r\n                                        history_index = history_len;\r\n                                        current_input.clear();\r\n                                        cursor_pos = 0;\r\n                                    }\r\n                                    _ => {}\r\n                                }\r\n                        }\r\n                    },\r\n                    KeyCode::Left => {\r\n                        cursor_pos = cursor_pos.saturating_sub(1);\r\n                    },\r\n                    KeyCode::Right => {\r\n                        if cursor_pos < current_input.len() {\r\n                            cursor_pos += 1;\r\n                        }\r\n                    },\r\n                    KeyCode::Backspace => {\r\n                        if cursor_pos > 0 {\r\n                            current_input.remove(cursor_pos - 1);\r\n                            cursor_pos -= 1;\r\n                        }\r\n                    },\r\n                    KeyCode::Char(c) => {\r\n                        if modifiers == KeyModifiers::CONTROL && (c == 'c' || c == 'd') {\r\n                            exit_repl()?;\r\n                            break;\r\n                        }\r\n                        added_input_chars = true;\r\n                        current_input.insert(cursor_pos, c);\r\n                        cursor_pos += 1;\r\n                    },\r\n                    _ => {},\r\n                }\r\n            }\r\n        }\r\n\r\n        disable_raw_mode()?;\r\n\r\n        Ok::<_,Error>(())\r\n    })\r\n    .await\r\n    .expect(\"Failed to run REPL\")\r\n}\r\n\r\nfn write_history(history: &VecDeque<String>, history_file: Option<&Path>) {\r\n    if let Some(history_file) = history_file {\r\n        let _ = fs::write(\r\n            history_file,\r\n            history\r\n                .iter()\r\n                .map(|s| s.as_str())\r\n                .collect::<Vec<_>>()\r\n                .join(\"\\n\"),\r\n        );\r\n    }\r\n}\r\n\r\n#[cfg(test)]\r\nmod tests {\r\n\r\n    use llrt_core::libs::utils::primordials::{BasePrimordials, Primordial};\r\n    use llrt_test::test_async_with;\r\n\r\n    use crate::repl::process_input;\r\n\r\n    #[tokio::test]\r\n    async fn test_process_input() {\r\n        test_async_with(|ctx| {\r\n            Box::pin(async move {\r\n                BasePrimordials::init(&ctx).unwrap();\r\n                let output = process_input(&ctx, \"throw new Error('err')\", false).await;\r\n\r\n                assert_eq!(output, \"Error: err\\n  at <eval> (eval_script:1:10)\");\r\n\r\n                let output = process_input(&ctx, \"Promise.reject(1)\", false).await;\r\n\r\n                assert_eq!(output, \"Promise {\\n  <rejected> 1\\n}\");\r\n\r\n                let output = process_input(&ctx, \"1+1\", false).await;\r\n\r\n                assert_eq!(output, \"2\");\r\n\r\n                let output = process_input(&ctx, \"a\", false).await;\r\n\r\n                assert_eq!(\r\n                    output,\r\n                    \"ReferenceError: a is not defined\\n  at <eval> (eval_script:1:1)\"\r\n                );\r\n            })\r\n        })\r\n        .await;\r\n    }\r\n}\r\n"
  },
  {
    "path": "llrt_core/Cargo.toml",
    "content": "[package]\nname = \"llrt_core\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense-file = \"LICENSE\"\n\n[features]\ndefault = [\"macro\", \"tls-ring\", \"crypto-rust\"]\nlambda = []\nno-sdk = []\nuncompressed = []\nmacro = [\"rquickjs/macro\"]\nbindgen = [\"rquickjs/bindgen\"]\n\n# TLS crypto backend features\ntls-ring = [\"rustls/ring\", \"llrt_modules/tls-ring\"]\ntls-aws-lc = [\"rustls/aws_lc_rs\", \"llrt_modules/tls-aws-lc\"]\ntls-graviola = [\"llrt_modules/tls-graviola\"]\ntls-openssl = [\"llrt_modules/tls-openssl\", \"dep:openssl\"]\n\n# Crypto provider features\ncrypto-rust = [\"llrt_modules/crypto-rust\"]\ncrypto-ring = [\"llrt_modules/crypto-ring\"]\ncrypto-ring-rust = [\"llrt_modules/crypto-ring-rust\"]\ncrypto-graviola = [\"llrt_modules/crypto-graviola\"]\ncrypto-graviola-rust = [\"llrt_modules/crypto-graviola-rust\"]\ncrypto-openssl = [\"llrt_modules/crypto-openssl\"]\n\n# OpenSSL vendored (builds OpenSSL from source)\nopenssl-vendored = [\"openssl/vendored\"]\n\n[dependencies]\nbytes = { version = \"1\", default-features = false }\nhome = { version = \"0.5\", default-features = false }\nhttp-body-util = { version = \"0.1\", default-features = false }\nhyper = { version = \"1\", default-features = false }\nitoa = { version = \"1\", default-features = false }\njiff = { version = \"0.2\" }\nlibc = { version = \"0.2\", default-features = false }\nllrt_context = { path = \"../libs/llrt_context\" }\nllrt_encoding = { path = \"../libs/llrt_encoding\" }\nllrt_hooking = { path = \"../libs/llrt_hooking\" }\nllrt_json = { path = \"../libs/llrt_json\" }\nllrt_logging = { path = \"../libs/llrt_logging\" }\nllrt_modules = { path = \"../llrt_modules\", default-features = false, features = [\n  \"base\",\n  \"console\",\n] }\nllrt_numbers = { path = \"../libs/llrt_numbers\" }\nllrt_utils = { path = \"../libs/llrt_utils\", features = [\"all\"] }\nonce_cell = { version = \"1\", features = [\"std\"], default-features = false }\nphf = { version = \"0.13\", default-features = false }\nquick-xml = { version = \"0.39\", default-features = false }\nrand = { version = \"0.10.0\", features = [\n  \"alloc\",\n  \"thread_rng\",\n], default-features = false }\nrquickjs = { version = \"0.11\", features = [\n  \"futures\",\n  \"parallel\",\n  \"rust-alloc\",\n], default-features = false }\nrustls = { version = \"0.23\", features = [\"tls12\"], default-features = false }\nrustls-pemfile = { version = \"2\", features = [\"std\"], default-features = false }\nryu = { version = \"1\", default-features = false }\nsimd-json = { version = \"0.17\", default-features = false }\nterminal_size = { version = \"0.4\", default-features = false }\ntokio = { version = \"1\", features = [\"sync\", \"time\"], default-features = false }\ntracing = { version = \"0.1\", features = [\"log\"], default-features = false }\nzstd = { version = \"0.13\", default-features = false }\nopenssl = { version = \"0.10\", optional = true }\n\n[target.'cfg(target_os = \"windows\")'.dependencies]\nmd-5 = { version = \"0.11.0-rc.5\", default-features = false }\n[target.'cfg(not(target_os = \"windows\"))'.dependencies]\nmd-5 = { version = \"0.11.0-rc.5\", default-features = false }\n\n[build-dependencies]\nrquickjs = { version = \"0.11\", default-features = false }\nphf_codegen = { version = \"0.13\", default-features = false }\nllrt_build = { path = \"../libs/llrt_build\" }\nuuid = { version = \"1\", features = [\"v4\"], default-features = false }\nwalkdir = { version = \"2\", default-features = false }\n\n[dev-dependencies]\nwiremock = { version = \"0.6\", default-features = false }\nllrt_test = { path = \"../libs/llrt_test\" }\n"
  },
  {
    "path": "llrt_core/build.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#![allow(clippy::uninlined_format_args)]\n\nuse std::{\n    collections::HashSet,\n    env,\n    error::Error,\n    fs::{self, File},\n    io::Write,\n    io::{self, BufRead, BufReader, BufWriter},\n    path::{Path, PathBuf},\n    process::Command,\n    result::Result as StdResult,\n};\n\nuse rquickjs::{CatchResultExt, CaughtError, Context, Module, Runtime, WriteOptions};\nuse walkdir::WalkDir;\n\nconst BUNDLE_JS_DIR: &str = \"../bundle/js\";\n\ninclude!(\"src/bytecode.rs\");\n\nmacro_rules! info {\n    ($($tokens: tt)*) => {\n        println!(\"cargo:info={}\", format!($($tokens)*))\n    }\n}\n\nmacro_rules! rerun_if_changed {\n    ($file: expr) => {\n        println!(\"cargo:rerun-if-changed={}\", $file)\n    };\n}\n\ninclude!(\"src/compiler_common.rs\");\n\nfn main() -> StdResult<(), Box<dyn Error>> {\n    llrt_build::set_nightly_cfg();\n\n    rerun_if_changed!(BUNDLE_JS_DIR);\n    rerun_if_changed!(\"Cargo.toml\");\n\n    let out_dir = env::var(\"OUT_DIR\").unwrap();\n\n    // #[cfg(feature = \"lambda\")]\n    // {\n    generate_sdk_client_endpoint_map(&out_dir)?;\n    //}\n\n    generate_bytecode_cache(&out_dir)?;\n\n    Ok(())\n}\n\nfn generate_sdk_client_endpoint_map(out_dir: &str) -> StdResult<(), Box<dyn Error>> {\n    let file = File::open(\"../sdk.cfg\")?;\n    let reader = BufReader::new(file);\n\n    let sdk_client_endpoints_path = Path::new(out_dir).join(\"sdk_client_endpoints.rs\");\n    let mut sdk_client_endpoints_file = BufWriter::new(File::create(sdk_client_endpoints_path)?);\n\n    let mut ph_map = phf_codegen::Map::<String>::new();\n\n    for line in reader.lines() {\n        let line = line?;\n        let line = line.trim();\n        if !line.is_empty() && !line.starts_with('#') {\n            let mut line_iter = line.split(',');\n            let package_name = line_iter.next();\n            if let Some(package_name) = package_name {\n                let _client_name = line_iter.next();\n                let _full_sdk = line_iter.next_back();\n                let sdks_to_init = line_iter.collect::<Vec<&str>>().join(\",\");\n                let package_name = package_name.trim_start_matches(\"client-\");\n                let package_name = package_name.into();\n                if package_name == sdks_to_init {\n                    ph_map.entry(package_name, r#\"\"\"\"#);\n                } else {\n                    ph_map.entry(package_name, format!(\"\\\"{}\\\"\", sdks_to_init));\n                }\n            }\n        }\n    }\n    write!(\n        &mut sdk_client_endpoints_file,\n        \"// @generated by build.rs\\n\\npub static SDK_CLIENT_ENDPOINTS: phf::Map<&'static str, &'static str> = {}\",\n        ph_map.build()\n    )?;\n    writeln!(&mut sdk_client_endpoints_file, \";\")?;\n    sdk_client_endpoints_file.flush()?;\n    Ok(())\n}\n\nfn generate_bytecode_cache(out_dir: &str) -> StdResult<(), Box<dyn Error>> {\n    let resolver = (DummyResolver,);\n    let loader = (DummyLoader,);\n\n    let rt = Runtime::new()?;\n    rt.set_loader(resolver, loader);\n    let ctx = Context::full(&rt)?;\n\n    let bytecode_cache_path = Path::new(&out_dir).join(\"bytecode_cache.rs\");\n    let mut bytecode_cache_file = BufWriter::new(File::create(bytecode_cache_path)?);\n\n    let mut ph_map = phf_codegen::Map::<String>::new();\n    let mut lrt_filenames = vec![];\n    let mut total_bytes: usize = 0;\n\n    fs::write(\"../VERSION\", env!(\"CARGO_PKG_VERSION\")).expect(\"Unable to write VERSION file\");\n\n    #[cfg(feature = \"lambda\")]\n    let test_file = PathBuf::new().join(\"@llrt\").join(\"test.js\");\n\n    ctx.with(|ctx| {\n        for dir_ent in WalkDir::new(BUNDLE_JS_DIR).into_iter().flatten() {\n            let path = dir_ent.path();\n\n            let path = path.strip_prefix(BUNDLE_JS_DIR)?.to_owned();\n\n            let path_str = path.to_string_lossy().to_string();\n\n            if path_str.starts_with(\"__tests__\") || path.extension().unwrap_or_default() != \"js\" {\n                continue;\n            }\n\n            #[cfg(feature = \"lambda\")]\n            {\n                if path == test_file {\n                    continue;\n                }\n            }\n\n            #[cfg(feature = \"no-sdk\")]\n            {\n                if path_str.starts_with(\"@aws-sdk\")\n                    || path_str.starts_with(\"@smithy\")\n                    || path_str.starts_with(\"llrt-chunk-sdk\")\n                {\n                    continue;\n                }\n            }\n\n            let source = fs::read_to_string(dir_ent.path())\n                .unwrap_or_else(|_| panic!(\"Unable to load: {}\", dir_ent.path().to_string_lossy()));\n\n            let module_name = if !path_str.starts_with(\"llrt-\") {\n                path.with_extension(\"\")\n                    .to_string_lossy()\n                    .replace('\\\\', \"/\")\n                    .replace(\"@llrt/\", \"llrt:\")\n            } else {\n                path.to_string_lossy().to_string().replace('\\\\', \"/\")\n            };\n\n            info!(\"Compiling module: {}\", module_name);\n\n            let lrt_path = PathBuf::from(&out_dir).join(path.with_extension(BYTECODE_EXT));\n            let lrt_filename = lrt_path.to_string_lossy().to_string().replace('\\\\', \"/\");\n            lrt_filenames.push(lrt_filename.clone());\n            let bytes = {\n                {\n                    let module = Module::declare(ctx.clone(), module_name.clone(), source)?;\n                    module.write(WriteOptions::default())\n                }\n            }\n            .catch(&ctx)\n            .map_err(|err| match err {\n                CaughtError::Error(error) => error.to_string(),\n                CaughtError::Exception(ex) => ex.to_string(),\n                CaughtError::Value(value) => format!(\"{:?}\", value),\n            })?;\n\n            total_bytes += bytes.len();\n\n            fs::create_dir_all(lrt_path.parent().unwrap())?;\n            if cfg!(feature = \"uncompressed\") {\n                let uncompressed = add_bytecode_header(bytes, None);\n                fs::write(&lrt_path, uncompressed)?;\n            } else {\n                fs::write(&lrt_path, bytes)?;\n            }\n\n            info!(\"Done!\");\n\n            ph_map.entry(\n                module_name,\n                format!(\"include_bytes!(\\\"{}\\\")\", &lrt_filename),\n            );\n        }\n\n        StdResult::<_, Box<dyn Error>>::Ok(())\n    })?;\n\n    write!(\n        &mut bytecode_cache_file,\n        \"// @generated by build.rs\\n\\npub static BYTECODE_CACHE: phf::Map<&'static str, &[u8]> = {}\",\n        ph_map.build()\n    )?;\n    writeln!(&mut bytecode_cache_file, \";\")?;\n    bytecode_cache_file.flush()?;\n\n    info!(\n        \"\\n===============================\\nUncompressed bytecode size: {}\\n===============================\",\n        human_file_size(total_bytes)\n    );\n\n    let compression_dictionary_path = Path::new(out_dir)\n        .join(\"compression.dict\")\n        .to_string_lossy()\n        .to_string();\n\n    if cfg!(feature = \"uncompressed\") {\n        generate_compression_dictionary(&compression_dictionary_path, &lrt_filenames)?;\n    } else {\n        total_bytes = compress_bytecode(compression_dictionary_path, lrt_filenames)?;\n\n        info!(\n            \"\\n===============================\\nCompressed bytecode size: {}\\n===============================\",\n            human_file_size(total_bytes)\n        );\n    }\n    Ok(())\n}\n\nfn compress_bytecode(dictionary_path: String, source_files: Vec<String>) -> io::Result<usize> {\n    generate_compression_dictionary(&dictionary_path, &source_files)?;\n\n    let mut total_size = 0;\n    let tmp_dir = env::temp_dir();\n\n    for filename in source_files {\n        info!(\"Compressing {}...\", filename);\n\n        let tmp_filename = tmp_dir\n            .join(uuid::Uuid::new_v4().to_string())\n            .to_string_lossy()\n            .to_string();\n\n        fs::copy(&filename, &tmp_filename)?;\n\n        let uncompressed_file_size = PathBuf::from(&filename).metadata()?.len() as u32;\n\n        let output = Command::new(\"zstd\")\n            .args([\n                \"--ultra\",\n                \"-22\",\n                \"-f\",\n                \"-D\",\n                &dictionary_path,\n                &tmp_filename,\n                \"-o\",\n                &filename,\n            ])\n            .output()?;\n\n        if !output.status.success() {\n            return Err(io::Error::other(\"Failed to compress file\"));\n        }\n\n        let bytes = fs::read(&filename)?;\n        let compressed = add_bytecode_header(bytes, Some(uncompressed_file_size));\n        fs::write(&filename, compressed)?;\n\n        let compressed_file_size = PathBuf::from(&filename).metadata().unwrap().len() as usize;\n\n        total_size += compressed_file_size;\n    }\n\n    Ok(total_size)\n}\n\nfn generate_compression_dictionary(\n    dictionary_path: &str,\n    source_files: &[String],\n) -> Result<(), io::Error> {\n    info!(\"Generating compression dictionary...\");\n    let file_count = source_files.len();\n    let mut dictionary_filenames = source_files.to_owned();\n    let mut dictionary_file_set: HashSet<String> = HashSet::from_iter(dictionary_filenames.clone());\n    let mut cmd = Command::new(\"zstd\");\n    cmd.args([\n        \"--train\",\n        \"--train-fastcover=steps=60\",\n        \"--maxdict=40K\",\n        \"-o\",\n        dictionary_path,\n    ]);\n    if file_count < 5 {\n        dictionary_file_set.retain(|file_path| {\n            let metadata = fs::metadata(file_path).unwrap();\n            let file_size = metadata.len();\n            file_size >= 1024 // 1 kilobyte = 1024 bytes\n        });\n        cmd.arg(\"-B1K\");\n        dictionary_filenames = dictionary_file_set.into_iter().collect();\n    }\n    cmd.args(&dictionary_filenames);\n\n    // To avoid cmd being too long to execute\n    let out_dir = env::var(\"OUT_DIR\").unwrap();\n    let short_source_files: Vec<_> = source_files\n        .iter()\n        .map(|i| {\n            Path::new(i)\n                .strip_prefix(out_dir.clone())\n                .unwrap()\n                .to_string_lossy()\n                .to_string()\n        })\n        .collect();\n    let mut cmd = cmd.current_dir(out_dir).args(short_source_files).spawn()?;\n    let exit_status = cmd.wait()?;\n    if !exit_status.success() {\n        return Err(io::Error::other(\n            \"Failed to generate compression dictionary\",\n        ));\n    };\n    Ok(())\n}\n"
  },
  {
    "path": "llrt_core/src/builtins_inspect.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nuse crate::libs::utils::primordials::{BasePrimordials, Primordial};\nuse rquickjs::{\n    atom::PredefinedAtom, function::This, object::Accessor, Array, Ctx, Function, Object, Result,\n    Value,\n};\n\npub fn init(ctx: &Ctx<'_>) -> Result<()> {\n    let globals = ctx.globals();\n    let primordials = BasePrimordials::get(ctx)?;\n    let custom_inspect_symbol = primordials.symbol_custom_inspect.clone();\n\n    // Map\n    primordials\n        .prototype_map\n        .prop(custom_inspect_symbol.clone(), Accessor::from(map_inspect))?;\n\n    // Set\n    primordials\n        .prototype_set\n        .prop(custom_inspect_symbol.clone(), Accessor::from(set_inspect))?;\n\n    // DataView\n    let dataview_proto: Object = globals\n        .get::<_, Function>(PredefinedAtom::DataView)?\n        .get(PredefinedAtom::Prototype)?;\n    dataview_proto.prop(\n        custom_inspect_symbol.clone(),\n        Accessor::from(dataview_inspect),\n    )?;\n\n    // ArrayBuffer\n    let arraybuffer_proto: Object = globals\n        .get::<_, Function>(PredefinedAtom::ArrayBuffer)?\n        .get(PredefinedAtom::Prototype)?;\n    arraybuffer_proto.prop(custom_inspect_symbol, Accessor::from(arraybuffer_inspect))?;\n\n    Ok(())\n}\n\nfn map_inspect<'js>(ctx: Ctx<'js>, this: This<Object<'js>>) -> Result<Object<'js>> {\n    let obj = Object::new(ctx.clone())?;\n\n    let size: usize = this.get(\"size\")?;\n    obj.set(\"size\", size)?;\n\n    if size > 0 {\n        let entries_fn: Function = this.get(\"entries\")?;\n        let iterator: Object = entries_fn.call((This(this.0.clone()),))?;\n        let next_fn: Function = iterator.get(PredefinedAtom::Next)?;\n        let entries = Array::new(ctx)?;\n\n        for i in 0..size.min(100) {\n            let next_result: Object = next_fn.call((This(iterator.clone()),))?;\n            let done: bool = next_result.get(PredefinedAtom::Done)?;\n            if done {\n                break;\n            }\n            let entry: Array = next_result.get(PredefinedAtom::Value)?;\n            entries.set(i, entry)?;\n        }\n        obj.set(\"entries\", entries)?;\n    }\n    Ok(obj)\n}\n\nfn set_inspect<'js>(ctx: Ctx<'js>, this: This<Object<'js>>) -> Result<Object<'js>> {\n    let obj = Object::new(ctx.clone())?;\n    let size: usize = this.get(\"size\")?;\n    obj.set(\"size\", size)?;\n\n    if size > 0 {\n        let values_fn: Function = this.get(\"values\")?;\n        let iterator: Object = values_fn.call((This(this.0.clone()),))?;\n        let next_fn: Function = iterator.get(\"next\")?;\n        let values = Array::new(ctx)?;\n\n        for i in 0..size.min(100) {\n            let next_result: Object = next_fn.call((This(iterator.clone()),))?;\n            let done: bool = next_result.get(\"done\")?;\n            if done {\n                break;\n            }\n            let value: Value = next_result.get(\"value\")?;\n            values.set(i, value)?;\n        }\n        obj.set(\"values\", values)?;\n    }\n    Ok(obj)\n}\n\nfn dataview_inspect<'js>(ctx: Ctx<'js>, this: This<Object<'js>>) -> Result<Object<'js>> {\n    let obj = Object::new(ctx)?;\n    obj.set(\"byteLength\", this.get::<_, usize>(\"byteLength\")?)?;\n    obj.set(\"byteOffset\", this.get::<_, usize>(\"byteOffset\")?)?;\n    obj.set(\"buffer\", this.get::<_, Object>(\"buffer\")?)?;\n    Ok(obj)\n}\n\nfn arraybuffer_inspect<'js>(ctx: Ctx<'js>, this: This<Object<'js>>) -> Result<Object<'js>> {\n    let primordials = BasePrimordials::get(&ctx)?;\n    let obj = Object::new(ctx.clone())?;\n\n    let byte_length: usize = this.get(\"byteLength\")?;\n    let uint8_view: Object = primordials\n        .constructor_uint8array\n        .construct((this.0.clone(),))?;\n\n    let mut bytes = String::from(\"<\");\n    for i in 0..byte_length.min(8) {\n        if i > 0 {\n            bytes.push(' ');\n        }\n        let byte: u8 = uint8_view.get(i as u32)?;\n        bytes.push_str(&format!(\"{:02x}\", byte));\n    }\n    bytes.push('>');\n\n    obj.set(\"uint8Contents\", bytes)?;\n    obj.set(\"byteLength\", byte_length)?;\n    Ok(obj)\n}\n"
  },
  {
    "path": "llrt_core/src/bytecode.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\npub const BYTECODE_VERSION: &str = \"lrt01\";\npub const BYTECODE_COMPRESSED: u8 = b'c';\npub const BYTECODE_UNCOMPRESSED: u8 = b'u';\npub const BYTECODE_SELF_CONTAINED_EXECUTABLE_MARKER: &[u8] = \"lrtx\".as_bytes();\n\nmacro_rules! define_extension {\n    ($base:ident, $file:ident, $ext:expr) => {\n        #[allow(dead_code)]\n        pub const $base: &str = $ext;\n        #[allow(dead_code)]\n        pub const $file: &str = concat!(\".\", $ext);\n    };\n}\n\ndefine_extension!(BYTECODE_EXT, BYTECODE_FILE_EXT, \"lrt\");\npub const SIGNATURE_LENGTH: usize = BYTECODE_VERSION.len() + 1;\n\n#[allow(dead_code)]\npub fn add_bytecode_header(bytes: Vec<u8>, file_size: Option<u32>) -> Vec<u8> {\n    let mut compressed_bytes = Vec::with_capacity(bytes.len());\n    compressed_bytes.extend_from_slice(BYTECODE_VERSION.as_bytes());\n    if let Some(file_size) = file_size {\n        compressed_bytes.push(BYTECODE_COMPRESSED);\n        compressed_bytes.extend_from_slice(&file_size.to_le_bytes());\n    } else {\n        compressed_bytes.push(BYTECODE_UNCOMPRESSED)\n    }\n    compressed_bytes.extend_from_slice(&bytes);\n    compressed_bytes\n}\n"
  },
  {
    "path": "llrt_core/src/compiler.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{\n    env, fs, io,\n    path::{Path, PathBuf},\n};\n\nuse rquickjs::{CatchResultExt, Context, Module, Runtime, WriteOptions};\nuse tracing::trace;\nuse zstd::bulk::Compressor;\n\nuse crate::bytecode::{add_bytecode_header, BYTECODE_SELF_CONTAINED_EXECUTABLE_MARKER};\nuse crate::compiler_common::{human_file_size, DummyLoader, DummyResolver};\nuse crate::libs::{logging::print_error_and_exit, utils::result::ResultExt};\nuse crate::modules::embedded::COMPRESSION_DICT;\n\nfn compress_module(bytes: &[u8]) -> io::Result<Vec<u8>> {\n    let mut compressor = Compressor::with_dictionary(22, COMPRESSION_DICT)?;\n    let compressed_bytes = compressor.compress(bytes)?;\n    let uncompressed_len = bytes.len() as u32;\n\n    let compressed = add_bytecode_header(compressed_bytes, Some(uncompressed_len));\n    Ok(compressed)\n}\n\npub async fn compile_file(\n    input_filename: &Path,\n    output_filename: &Path,\n    create_executable: bool,\n) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n    let resolver = (DummyResolver,);\n    let loader = (DummyLoader,);\n\n    let rt = Runtime::new()?;\n    rt.set_loader(resolver, loader);\n    let ctx = Context::full(&rt)?;\n\n    let mut total_bytes: usize = 0;\n    let mut compressed_bytes: usize = 0;\n    let mut js_bytes: usize = 0;\n\n    ctx.with(|ctx| {\n        (|| {\n            let source = fs::read_to_string(input_filename).or_throw_msg(\n                &ctx,\n                &[\"Unable to load: \", &input_filename.to_string_lossy()].concat(),\n            )?;\n            js_bytes = source.len();\n\n            let module_name = input_filename\n                .with_extension(\"\")\n                .to_string_lossy()\n                .to_string();\n\n            trace!(\"Compiling module: {}\", module_name);\n\n            let module = Module::declare(ctx.clone(), module_name, source)?;\n            let bytes = module.write(WriteOptions::default())?;\n            let mut compressed = compress_module(&bytes)?;\n\n            total_bytes += bytes.len();\n            compressed_bytes += compressed.len();\n\n            if create_executable {\n                // Create the executable by prepending the LLRT runtime to the bytecode\n                let mut exe_content = Vec::new();\n\n                let executable_path = env::current_exe()\n                    .unwrap_or_else(|_| PathBuf::from(env::args().next().unwrap_or_default()));\n                let mut content = fs::read(executable_path)?;\n                exe_content.append(&mut content);\n\n                exe_content.append(&mut compressed);\n\n                let size = u64::try_from(compressed_bytes).unwrap();\n                let size_bytes = size.to_le_bytes();\n                exe_content.extend_from_slice(&size_bytes);\n\n                exe_content.extend_from_slice(BYTECODE_SELF_CONTAINED_EXECUTABLE_MARKER);\n\n                fs::write(output_filename, &exe_content)?;\n\n                // Set executable permissions on Unix systems\n                #[cfg(unix)]\n                {\n                    use std::os::unix::fs::PermissionsExt;\n                    let mut perms = fs::metadata(output_filename)?.permissions();\n                    perms.set_mode(0o755);\n                    fs::set_permissions(output_filename, perms)?;\n                }\n            } else {\n                fs::write(output_filename, &compressed)?;\n            }\n\n            Ok(())\n        })()\n        .catch(&ctx)\n        .unwrap_or_else(|err| print_error_and_exit(&ctx, err))\n    });\n\n    trace!(\"JS size: {}\", human_file_size(js_bytes));\n    trace!(\"Bytecode size: {}\", human_file_size(total_bytes));\n    trace!(\n        \"Compressed bytecode size: {}\",\n        human_file_size(compressed_bytes)\n    );\n\n    Ok(())\n}\n"
  },
  {
    "path": "llrt_core/src/compiler_common.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n// Shared with build.rs and compiler.rs\n\npub struct DummyLoader;\n\nimpl rquickjs::loader::Loader for DummyLoader {\n    fn load<'js>(\n        &mut self,\n        ctx: &rquickjs::Ctx<'js>,\n        name: &str,\n    ) -> rquickjs::Result<rquickjs::Module<'js, rquickjs::module::Declared>> {\n        rquickjs::module::Module::declare(ctx.clone(), name, \"\")\n    }\n}\n\npub struct DummyResolver;\n\nimpl rquickjs::loader::Resolver for DummyResolver {\n    fn resolve(\n        &mut self,\n        _ctx: &rquickjs::Ctx<'_>,\n        _base: &str,\n        name: &str,\n    ) -> rquickjs::Result<String> {\n        Ok(name.into())\n    }\n}\n\npub fn human_file_size(size: usize) -> String {\n    const UNITS: [&str; 6] = [\"B\", \"kB\", \"MB\", \"GB\", \"TB\", \"PB\"];\n    let fsize = size as f64;\n    let i = if size == 0 {\n        0\n    } else {\n        (fsize.log2() / 1024f64.log2()).floor() as i32\n    };\n    let size = fsize / 1024f64.powi(i);\n\n    let mut result = String::with_capacity(16);\n\n    // Convert float to integer with 3 decimal places\n    let scaled = (size * 1000.0).round() as i64;\n    let integral = scaled / 1000;\n    let fractional = scaled % 1000;\n\n    // Custom integer to string conversion\n    fn int_to_string(mut n: i64, buf: &mut String) {\n        if n == 0 {\n            buf.push('0');\n            return;\n        }\n        let mut digits = [0u8; 20];\n        let mut i = 0;\n        while n > 0 {\n            digits[i] = (n % 10) as u8;\n            n /= 10;\n            i += 1;\n        }\n        for &digit in digits[..i].iter().rev() {\n            buf.push((digit + b'0') as char);\n        }\n    }\n\n    // Convert integral part\n    int_to_string(integral, &mut result);\n    result.push('.');\n\n    let len_before = result.len();\n\n    // Convert fractional part with zero-padding\n    int_to_string(fractional, &mut result);\n    for _ in (result.len() - len_before)..3 {\n        result.push('0');\n    }\n\n    result.push(' ');\n    result.push_str(UNITS[i as usize]);\n    result\n}\n"
  },
  {
    "path": "llrt_core/src/environment.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\n//network\npub const ENV_LLRT_NET_ALLOW: &str = \"LLRT_NET_ALLOW\";\npub const ENV_LLRT_NET_DENY: &str = \"LLRT_NET_DENY\";\npub const ENV_LLRT_NET_POOL_IDLE_TIMEOUT: &str = \"LLRT_NET_POOL_IDLE_TIMEOUT\";\npub const ENV_LLRT_HTTP_VERSION: &str = \"LLRT_HTTP_VERSION\";\npub const ENV_LLRT_TLS_VERSION: &str = \"LLRT_TLS_VERSION\";\npub const ENV_LLRT_EXTRA_CA_CERTS: &str = \"LLRT_EXTRA_CA_CERTS\";\n\n//log\npub const ENV_LLRT_LOG: &str = \"LLRT_LOG\";\n\n//vm\npub const ENV_LLRT_GC_THRESHOLD_MB: &str = \"LLRT_GC_THRESHOLD_MB\";\n\n//runtime client\npub const ENV_LLRT_SDK_CONNECTION_WARMUP: &str = \"LLRT_SDK_CONNECTION_WARMUP\";\n\n//main\npub const ENV_LLRT_REGISTER_HOOKS: &str = \"LLRT_REGISTER_HOOKS\";\n"
  },
  {
    "path": "llrt_core/src/http.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{env, result::Result as StdResult};\n\nuse tracing::warn;\n\nuse crate::environment;\nuse crate::modules::https::{set_http_version, set_pool_idle_timeout_seconds, HttpVersion};\n\n#[cfg(any(feature = \"tls-ring\", feature = \"tls-aws-lc\", feature = \"tls-graviola\"))]\nuse std::{fs::File, io};\n\n#[cfg(any(feature = \"tls-ring\", feature = \"tls-aws-lc\", feature = \"tls-graviola\"))]\nuse rustls::{pki_types::CertificateDer, version, SupportedProtocolVersion};\n\n#[cfg(any(feature = \"tls-ring\", feature = \"tls-aws-lc\", feature = \"tls-graviola\"))]\nuse crate::modules::tls::{set_extra_ca_certs, set_tls_versions};\n\n#[cfg(feature = \"tls-openssl\")]\nuse crate::modules::tls::set_tls_version;\n\npub fn init() -> StdResult<(), Box<dyn std::error::Error + Send + Sync>> {\n    if let Some(pool_idle_timeout) = build_pool_idle_timeout() {\n        set_pool_idle_timeout_seconds(pool_idle_timeout);\n    }\n\n    #[cfg(any(feature = \"tls-ring\", feature = \"tls-aws-lc\", feature = \"tls-graviola\"))]\n    {\n        if let Some(extra_ca_certs) = build_extra_ca_certs()? {\n            set_extra_ca_certs(extra_ca_certs);\n        }\n        set_tls_versions(build_tls_versions());\n    }\n\n    #[cfg(feature = \"tls-openssl\")]\n    {\n        set_tls_version(build_tls_version_openssl());\n    }\n\n    set_http_version(build_http_version());\n\n    Ok(())\n}\n\nfn build_pool_idle_timeout() -> Option<u64> {\n    let Ok(env_value) = env::var(environment::ENV_LLRT_NET_POOL_IDLE_TIMEOUT) else {\n        return None;\n    };\n    let Ok(pool_idle_timeout) = env_value.parse::<u64>() else {\n        return None;\n    };\n\n    if pool_idle_timeout > 300 {\n        warn!(\n            r#\"\"{}\" is exceeds 300s (5min), risking errors due to possible server connection closures.\"#,\n            environment::ENV_LLRT_NET_POOL_IDLE_TIMEOUT\n        )\n    }\n    Some(pool_idle_timeout)\n}\n\n#[cfg(any(feature = \"tls-ring\", feature = \"tls-aws-lc\", feature = \"tls-graviola\"))]\nfn build_extra_ca_certs() -> StdResult<Option<Vec<CertificateDer<'static>>>, io::Error> {\n    if let Ok(extra_ca_certs) = env::var(environment::ENV_LLRT_EXTRA_CA_CERTS) {\n        if !extra_ca_certs.is_empty() {\n            let file = File::open(extra_ca_certs)\n                .map_err(|_| io::Error::other(\"Failed to open extra CA certificates file\"))?;\n            let mut reader = io::BufReader::new(file);\n            return Ok(Some(\n                rustls_pemfile::certs(&mut reader)\n                    .filter_map(io::Result::ok)\n                    .collect(),\n            ));\n        }\n    }\n    Ok(None)\n}\n\n#[cfg(any(feature = \"tls-ring\", feature = \"tls-aws-lc\", feature = \"tls-graviola\"))]\nfn build_tls_versions() -> Vec<&'static SupportedProtocolVersion> {\n    match env::var(environment::ENV_LLRT_TLS_VERSION).as_deref() {\n        Ok(\"1.3\") => vec![&version::TLS13, &version::TLS12],\n        _ => vec![&version::TLS12],\n    }\n}\n\n#[cfg(feature = \"tls-openssl\")]\nfn build_tls_version_openssl() -> Option<openssl::ssl::SslVersion> {\n    match env::var(environment::ENV_LLRT_TLS_VERSION).as_deref() {\n        Ok(\"1.3\") => Some(openssl::ssl::SslVersion::TLS1_3),\n        _ => Some(openssl::ssl::SslVersion::TLS1_2),\n    }\n}\n\nfn build_http_version() -> HttpVersion {\n    match env::var(environment::ENV_LLRT_HTTP_VERSION).as_deref() {\n        Ok(\"2\") => HttpVersion::Http2,\n        _ => HttpVersion::Http1_1,\n    }\n}\n"
  },
  {
    "path": "llrt_core/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\n#![allow(clippy::new_without_default)]\n#![allow(clippy::inherent_to_string)]\n\npub mod builtins_inspect;\npub mod bytecode;\npub mod compiler;\nmod compiler_common;\npub mod environment;\nmod http;\npub mod libs;\npub mod modules;\npub mod runtime_client;\nmod security;\npub mod vm;\n\npub use llrt_modules::VERSION;\n\npub use rquickjs::*;\n"
  },
  {
    "path": "llrt_core/src/libs.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\npub use self::libs::*;\n\n#[allow(clippy::module_inception)]\nmod libs {\n    pub use llrt_context as context;\n    pub use llrt_encoding as encoding;\n    pub use llrt_hooking as hooking;\n    pub use llrt_json as json;\n    pub use llrt_logging as logging;\n    pub use llrt_numbers as numbers;\n    pub use llrt_utils as utils;\n}\n"
  },
  {
    "path": "llrt_core/src/modules/console.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#![allow(clippy::uninlined_format_args)]\n\nuse std::{\n    env,\n    fmt::Write as FormatWrite,\n    io::{stderr, stdout, IsTerminal, Write},\n    sync::atomic::{AtomicBool, AtomicUsize, Ordering},\n};\n\nuse jiff::Timestamp;\nuse rquickjs::{\n    module::{Declarations, Exports, ModuleDef},\n    prelude::{Func, Rest},\n    Array, Class, Ctx, Object, Result, Value,\n};\n\nuse crate::libs::{\n    json::{escape::escape_json, stringify::json_stringify},\n    logging::{\n        build_formatted_string, replace_newline_with_carriage_return, FormatOptions, LogLevel,\n        NEWLINE, TIME_FORMAT,\n    },\n    utils::{\n        class::get_class_name,\n        module::{export_default, ModuleInfo},\n    },\n};\nuse crate::runtime_client;\n\nstatic AWS_LAMBDA_MODE: AtomicBool = AtomicBool::new(false);\nstatic AWS_LAMBDA_JSON_LOG_FORMAT: AtomicBool = AtomicBool::new(false);\nstatic AWS_LAMBDA_JSON_LOG_LEVEL: AtomicUsize = AtomicUsize::new(LogLevel::Info as usize);\n\nfn lambda_mode_initializer() {\n    let aws_lambda_json_log_format = env::var(\"AWS_LAMBDA_LOG_FORMAT\") == Ok(\"JSON\".to_string());\n    let aws_lambda_log_level = env::var(\"AWS_LAMBDA_LOG_LEVEL\").unwrap_or_default();\n    let log_level = LogLevel::from_str(&aws_lambda_log_level);\n\n    AWS_LAMBDA_JSON_LOG_LEVEL.store(log_level as usize, Ordering::Relaxed);\n    AWS_LAMBDA_MODE.store(true, Ordering::Relaxed);\n    AWS_LAMBDA_JSON_LOG_FORMAT.store(aws_lambda_json_log_format, Ordering::Relaxed);\n}\n\n#[derive(rquickjs::class::Trace, rquickjs::JsLifetime)]\n#[rquickjs::class]\npub struct Console {}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl Console {\n    #[qjs(constructor)]\n    pub fn new() -> Self {\n        // We ignore the parameters for now since we don't support stream\n        Self {}\n    }\n\n    pub fn log<'js>(&self, ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n        log(ctx, args)\n    }\n    pub fn clear(&self) {\n        clear()\n    }\n    pub fn debug<'js>(&self, ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n        log_debug(ctx, args)\n    }\n    pub fn info<'js>(&self, ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n        log(ctx, args)\n    }\n    pub fn trace<'js>(&self, ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n        log_trace(ctx, args)\n    }\n    pub fn error<'js>(&self, ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n        log_error(ctx, args)\n    }\n    pub fn warn<'js>(&self, ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n        log_warn(ctx, args)\n    }\n    pub fn assert<'js>(\n        &self,\n        ctx: Ctx<'js>,\n        expression: bool,\n        args: Rest<Value<'js>>,\n    ) -> Result<()> {\n        log_assert(ctx, expression, args)\n    }\n}\n\npub fn log_fatal<'js>(ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n    write_log(stderr(), &ctx, args, LogLevel::Fatal)\n}\n\npub fn log_error<'js>(ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n    write_log(stderr(), &ctx, args, LogLevel::Error)\n}\n\nfn log_warn<'js>(ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n    write_log(stderr(), &ctx, args, LogLevel::Warn)\n}\n\nfn log_debug<'js>(ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n    write_log(stdout(), &ctx, args, LogLevel::Debug)\n}\n\nfn log_trace<'js>(ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n    write_log(stdout(), &ctx, args, LogLevel::Trace)\n}\n\nfn log_assert<'js>(ctx: Ctx<'js>, expression: bool, args: Rest<Value<'js>>) -> Result<()> {\n    if !expression {\n        write_log(stderr(), &ctx, args, LogLevel::Error)?\n    }\n    Ok(())\n}\n\nfn log<'js>(ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n    write_log(stdout(), &ctx, args, LogLevel::Info)\n}\n\nfn clear() {\n    if stdout().is_terminal() {\n        let _ = stdout().write_all(b\"\\x1b[1;1H\\x1b[0J\");\n    }\n}\n\n#[allow(clippy::unused_io_amount)]\nfn write_log<'js, T>(\n    mut output: T,\n    ctx: &Ctx<'js>,\n    args: Rest<Value<'js>>,\n    level: LogLevel,\n) -> Result<()>\nwhere\n    T: Write + IsTerminal,\n{\n    let is_tty = output.is_terminal();\n    let mut result = String::new();\n    let mut is_lambda_mode = AWS_LAMBDA_MODE.load(Ordering::Relaxed);\n\n    if is_lambda_mode && is_tty {\n        is_lambda_mode = false;\n    }\n\n    if is_lambda_mode {\n        let is_json_log_format = AWS_LAMBDA_JSON_LOG_FORMAT.load(Ordering::Relaxed);\n        let max_log_level = AWS_LAMBDA_JSON_LOG_LEVEL.load(Ordering::Relaxed);\n        if !write_lambda_log(\n            ctx,\n            &mut result,\n            args,\n            level,\n            is_tty,\n            is_json_log_format,\n            max_log_level,\n            TIME_FORMAT,\n        )? {\n            return Ok(());\n        }\n    } else {\n        let mut options = FormatOptions::new(ctx, is_tty, true)?;\n        build_formatted_string(&mut result, ctx, args, &mut options)?;\n    }\n\n    result.push(NEWLINE);\n\n    //we don't care if output is interrupted\n    let _ = output.write_all(result.as_bytes());\n\n    Ok(())\n}\n\n#[inline(always)]\n#[allow(clippy::too_many_arguments)]\nfn write_lambda_log<'js>(\n    ctx: &Ctx<'js>,\n    result: &mut String,\n    args: Rest<Value<'js>>,\n    level: LogLevel,\n    is_tty: bool,\n    is_json_log_format: bool,\n    max_log_level: usize,\n    time_format: &str,\n) -> Result<bool> {\n    let mut is_newline = true;\n\n    //do not log if we don't meet the log level\n    if is_json_log_format && (level.clone() as usize) < max_log_level {\n        return Ok(false);\n    }\n    result.reserve(64);\n    if !is_tty {\n        is_newline = false;\n    }\n\n    let current_time = Timestamp::now();\n    let formatted_time = current_time.strftime(time_format);\n    let request_id = runtime_client::LAMBDA_REQUEST_ID.read().unwrap();\n\n    if is_json_log_format {\n        result.push('{');\n        //time\n        result.push_str(\"\\\"time\\\":\\\"\");\n        write!(result, \"{}\", formatted_time).unwrap();\n        result.push_str(\"\\\",\");\n\n        //request id\n        if let Some(id) = request_id.as_ref() {\n            result.push_str(\"\\\"requestId\\\":\\\"\");\n            result.push_str(id);\n            result.push_str(\"\\\",\");\n        }\n\n        //level\n        result.push_str(\"\\\"level\\\":\\\"\");\n        result.push_str(&level.to_string());\n        result.push('\\\"');\n    } else {\n        write!(result, \"{}\", formatted_time).unwrap();\n        result.push('\\t');\n\n        match request_id.as_ref() {\n            Some(id) => result.push_str(id),\n            None => result.push_str(\"n/a\"),\n        }\n\n        result.push('\\t');\n        result.push_str(&level.to_string());\n        result.push('\\t');\n    }\n\n    if is_json_log_format {\n        let mut values_string = String::with_capacity(64);\n\n        if args.0.len() == 1 {\n            let mut first_arg = unsafe { args.0.first().unwrap_unchecked() }.clone();\n\n            if first_arg.is_error() || first_arg.is_exception() {\n                if let Some(exception) = first_arg.as_exception() {\n                    let obj = Object::new(ctx.clone())?;\n                    obj.set(\"errorType\", get_class_name(exception.as_value()))?;\n                    if let Some(message) = exception.message() {\n                        obj.set(\"errorMessage\", message)?;\n                    }\n                    if let Some(stack) = exception.stack() {\n                        let stack_object = Array::new(ctx.clone())?;\n\n                        for (i, trace) in stack.split('\\n').enumerate() {\n                            stack_object.set(i, String::from(trace))?;\n                        }\n                        obj.set(\"stackTrace\", stack_object)?;\n                    }\n                    first_arg = obj.into_value();\n                }\n            }\n            if let Some(json_string) = json_stringify(ctx, first_arg)? {\n                //message\n                result.push(',');\n                result.push_str(\"\\\"message\\\":\");\n                result.push_str(&json_string);\n            }\n        } else {\n            //message\n            result.push(',');\n            result.push_str(\"\\\"message\\\":\\\"\");\n\n            let mut exception = None;\n\n            let mut options = FormatOptions::new(ctx, is_tty, true)?;\n\n            for arg in args.0.iter() {\n                if arg.is_error() && exception.is_none() {\n                    let exception_value = arg.clone();\n                    exception = Some(exception_value.into_exception().unwrap());\n                    break;\n                }\n            }\n\n            build_formatted_string(&mut values_string, ctx, args, &mut options)?;\n\n            result.push_str(&escape_json(values_string.as_bytes()));\n            result.push('\\\"');\n            if let Some(exception) = exception {\n                //error type\n                result.push_str(\",\\\"errorType\\\":\\\"\");\n                result\n                    .push_str(&get_class_name(exception.as_value())?.unwrap_or(\"Exception\".into()));\n                result.push_str(\"\\\",\");\n\n                //error message\n                if let Some(message) = exception.message() {\n                    result.push_str(\"\\\"errorMessage\\\":\\\"\");\n                    result.push_str(&message);\n                    result.push_str(\"\\\",\");\n                }\n\n                //stack trace\n                result.push_str(\"\\\"stackTrace\\\":[\");\n                let mut write_comma = false;\n                if let Some(stack) = exception.stack() {\n                    if !stack.is_empty() {\n                        for trace in stack.split('\\n') {\n                            if write_comma {\n                                result.push(',');\n                            }\n                            result.push('\\\"');\n                            result.push_str(trace);\n                            result.push('\\\"');\n                            write_comma = true;\n                        }\n                    }\n                }\n\n                result.push(']');\n            }\n        }\n\n        result.push('}');\n    } else {\n        let mut options = FormatOptions::new(ctx, is_tty && !is_json_log_format, is_newline)?;\n        build_formatted_string(result, ctx, args, &mut options)?;\n\n        replace_newline_with_carriage_return(result);\n    }\n\n    Ok(true)\n}\n\npub struct ConsoleModule;\n\nimpl ModuleDef for ConsoleModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(stringify!(Console))?;\n        declare.declare(\"default\")?;\n\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        export_default(ctx, exports, |default| {\n            Class::<Console>::define(default)?;\n\n            Ok(())\n        })\n    }\n}\n\nimpl From<ConsoleModule> for ModuleInfo<ConsoleModule> {\n    fn from(val: ConsoleModule) -> Self {\n        ModuleInfo {\n            name: \"console\",\n            module: val,\n        }\n    }\n}\n\npub fn init(ctx: &Ctx<'_>) -> Result<()> {\n    lambda_mode_initializer();\n\n    let globals = ctx.globals();\n\n    let console = Object::new(ctx.clone())?;\n\n    console.set(\"assert\", Func::from(log_assert))?;\n    console.set(\"clear\", Func::from(clear))?;\n    console.set(\"debug\", Func::from(log_debug))?;\n    console.set(\"error\", Func::from(log_error))?;\n    console.set(\"info\", Func::from(log))?;\n    console.set(\"log\", Func::from(log))?;\n    console.set(\"trace\", Func::from(log_trace))?;\n    console.set(\"warn\", Func::from(log_warn))?;\n\n    globals.set(\"console\", console)?;\n\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use llrt_test::test_sync_with;\n    use rquickjs::{function::Rest, Error, IntoJs, Null, Object, Undefined, Value};\n\n    use crate::libs::{\n        json::stringify::json_stringify_replacer_space,\n        logging::LogLevel,\n        utils::primordials::{BasePrimordials, Primordial},\n    };\n    use crate::modules::console::write_lambda_log;\n\n    #[tokio::test]\n    async fn json_log_format() {\n        test_sync_with(|ctx| {\n            BasePrimordials::init(&ctx)?;\n            let write_log = |args| {\n                let mut result = String::new();\n\n                write_lambda_log(\n                    &ctx,\n                    &mut result,\n                    Rest(args),\n                    LogLevel::Info,\n                    false,\n                    true,\n                    LogLevel::Info as usize,\n                    \"\",\n                )?;\n\n                //validate json\n                ctx.json_parse(result.clone())?;\n\n                Ok::<_, Error>(result)\n            };\n\n            assert_eq!(\n                write_log([\"Hello\".into_js(&ctx)?].into())?,\n                r#\"{\"time\":\"\",\"level\":\"INFO\",\"message\":\"Hello\"}\"#\n            );\n\n            assert_eq!(\n                write_log([1.into_js(&ctx)?].into())?,\n                r#\"{\"time\":\"\",\"level\":\"INFO\",\"message\":1}\"#\n            );\n\n            assert_eq!(\n                write_log([true.into_js(&ctx)?].into())?,\n                r#\"{\"time\":\"\",\"level\":\"INFO\",\"message\":true}\"#\n            );\n\n            assert_eq!(\n                write_log([Undefined.into_js(&ctx)?].into())?,\n                r#\"{\"time\":\"\",\"level\":\"INFO\"}\"#\n            );\n\n            assert_eq!(\n                write_log([Null.into_js(&ctx)?].into())?,\n                r#\"{\"time\":\"\",\"level\":\"INFO\",\"message\":null}\"#\n            );\n\n            let obj = Object::new(ctx.clone())?;\n            obj.set(\"a\", 1)?;\n            obj.set(\"b\", \"Hello\")?;\n\n            assert_eq!(\n                write_log([obj.clone().into_value()].into())?,\n                r#\"{\"time\":\"\",\"level\":\"INFO\",\"message\":{\"a\":1,\"b\":\"Hello\"}}\"#\n            );\n\n            //validate second argument passed\n            assert_eq!(\n                write_log([obj.into_value(), true.into_js(&ctx)?].into())?,\n                r#\"{\"time\":\"\",\"level\":\"INFO\",\"message\":\"{\\n  a: 1,\\n  b: 'Hello'\\n} true\"}\"#\n            );\n\n            //single error\n            let e1:Value = ctx.eval(r#\"new ReferenceError(\"some reference error\")\"#)?;\n            assert_eq!(\n                write_log([e1.clone()].into())?,\n                r#\"{\"time\":\"\",\"level\":\"INFO\",\"message\":{\"errorType\":\"ReferenceError\",\"errorMessage\":\"some reference error\",\"stackTrace\":[\"    at <eval> (eval_script:1:4)\",\"\"]}}\"#\n            );\n\n             //validate many args with additional errors\n            let e2:Value = ctx.eval(r#\"new SyntaxError(\"some syntax error\")\"#)?;\n            assert_eq!(\n                write_log([\"errors logged\".into_js(&ctx)?, e1, e2].into())?,\n                r#\"{\"time\":\"\",\"level\":\"INFO\",\"message\":\"errors logged ReferenceError: some reference error\\n  at <eval> (eval_script:1:4) SyntaxError: some syntax error\\n  at <eval> (eval_script:1:4)\",\"errorType\":\"ReferenceError\",\"errorMessage\":\"some reference error\",\"stackTrace\":[\"    at <eval> (eval_script:1:4)\",\"\"]}\"#\n            );\n\n            Ok(())\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn standard_log_format() {\n        test_sync_with(|ctx| {\n            BasePrimordials::init(&ctx)?;\n            let write_log = |args| {\n                let mut result = String::new();\n\n                write_lambda_log(\n                    &ctx,\n                    &mut result,\n                    Rest(args),\n                    LogLevel::Info,\n                    false,\n                    false,\n                    LogLevel::Info as usize,\n                    \"\",\n                )?;\n\n                Ok::<_, Error>(result)\n            };\n\n            assert_eq!(\n                write_log([\"Hello\".into_js(&ctx)?].into())?,\n               \"\\tn/a\\tINFO\\tHello\"\n            );\n\n            assert_eq!(\n                write_log([1.into_js(&ctx)?].into())?,\n                \"\\tn/a\\tINFO\\t1\"\n            );\n\n            assert_eq!(\n                write_log([true.into_js(&ctx)?].into())?,\n                \"\\tn/a\\tINFO\\ttrue\"\n            );\n\n            assert_eq!(\n                write_log([Undefined.into_js(&ctx)?].into())?,\n                \"\\tn/a\\tINFO\\tundefined\"\n            );\n\n            assert_eq!(\n                write_log([Null.into_js(&ctx)?].into())?,\n                \"\\tn/a\\tINFO\\tnull\"\n            );\n\n            let obj = Object::new(ctx.clone())?;\n            obj.set(\"a\", 1)?;\n            obj.set(\"b\", \"Hello\")?;\n\n            assert_eq!(\n                write_log([obj.clone().into_value()].into())?,\n                 \"\\tn/a\\tINFO\\t{\\r  a: 1,\\r  b: 'Hello'\\r}\"\n            );\n\n            //validate second argument passed\n            assert_eq!(\n                write_log([obj.clone().into_value(), true.into_js(&ctx)?].into())?,\n                \"\\tn/a\\tINFO\\t{\\r  a: 1,\\r  b: 'Hello'\\r} true\"\n            );\n\n            //single error\n            let e1:Value = ctx.eval(r#\"new ReferenceError(\"some reference error\")\"#)?;\n            assert_eq!(\n                write_log([e1.clone()].into())?,\n                \"\\tn/a\\tINFO\\tReferenceError: some reference error\\r  at <eval> (eval_script:1:4)\"\n            );\n\n             //validate many args with additional errors\n            let e2:Value = ctx.eval(r#\"new SyntaxError(\"some syntax error\")\"#)?;\n            assert_eq!(\n                write_log([\"errors logged\".into_js(&ctx)?, e1, e2].into())?,\n                \"\\tn/a\\tINFO\\terrors logged ReferenceError: some reference error\\r  at <eval> (eval_script:1:4) SyntaxError: some syntax error\\r  at <eval> (eval_script:1:4)\"\n            );\n\n            //newline replacement\n            assert_eq!(\n                write_log([\n                    \"event:\".into_js(&ctx)?,\n                    json_stringify_replacer_space(&ctx, obj.into_value(), None, Some(\"  \".into()))?.into_js(&ctx)?\n                ].into())?,\n               \"\\tn/a\\tINFO\\tevent: {\\r  \\\"a\\\": 1,\\r  \\\"b\\\": \\\"Hello\\\"\\r}\"\n            );\n\n            Ok(())\n        })\n        .await;\n    }\n}\n"
  },
  {
    "path": "llrt_core/src/modules/embedded/loader.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{io, result::Result as StdResult};\n\nuse once_cell::sync::Lazy;\nuse rquickjs::{loader::Loader, Ctx, Error, Module, Object, Result};\nuse tracing::trace;\nuse zstd::{bulk::Decompressor, dict::DecoderDictionary};\n\nuse crate::bytecode::{\n    BYTECODE_COMPRESSED, BYTECODE_FILE_EXT, BYTECODE_UNCOMPRESSED, BYTECODE_VERSION,\n    SIGNATURE_LENGTH,\n};\n\nuse super::{BYTECODE_CACHE, CJS_IMPORT_PREFIX, CJS_LOADER_PREFIX, COMPRESSION_DICT};\n\nstatic DECOMPRESSOR_DICT: Lazy<DecoderDictionary> =\n    Lazy::new(|| DecoderDictionary::copy(COMPRESSION_DICT));\n\n#[cfg(feature = \"lambda\")]\ninclude!(concat!(env!(\"OUT_DIR\"), \"/sdk_client_endpoints.rs\"));\n\n#[derive(Debug, Default)]\npub struct EmbeddedLoader;\n\nimpl EmbeddedLoader {\n    pub fn load_bytecode_module<'js>(ctx: Ctx<'js>, buf: &[u8]) -> Result<Module<'js>> {\n        let bytes = Self::get_module_bytecode(buf)?;\n        unsafe { Module::load(ctx, &bytes) }\n    }\n\n    #[inline]\n    pub fn uncompressed_size(input: &[u8]) -> StdResult<(usize, &[u8]), io::Error> {\n        let size = input.get(..4).ok_or(io::ErrorKind::InvalidInput)?;\n        let size: &[u8; 4] = size.try_into().map_err(|_| io::ErrorKind::InvalidInput)?;\n        let uncompressed_size = u32::from_le_bytes(*size) as usize;\n        let rest = &input[4..];\n        Ok((uncompressed_size, rest))\n    }\n\n    fn get_module_bytecode(input: &[u8]) -> Result<Vec<u8>> {\n        let (_, compressed, input) = Self::get_bytecode_signature(input)?;\n\n        if compressed {\n            let (size, input) = Self::uncompressed_size(input)?;\n            let mut buf = Vec::with_capacity(size);\n            let mut decompressor = Decompressor::with_prepared_dictionary(&DECOMPRESSOR_DICT)?;\n            decompressor.decompress_to_buffer(input, &mut buf)?;\n            return Ok(buf);\n        }\n\n        Ok(input.to_vec())\n    }\n\n    fn get_bytecode_signature(input: &[u8]) -> StdResult<(&[u8], bool, &[u8]), io::Error> {\n        let raw_signature = input\n            .get(..SIGNATURE_LENGTH)\n            .ok_or(io::Error::new::<String>(\n                io::ErrorKind::InvalidInput,\n                \"Invalid bytecode signature length\".into(),\n            ))?;\n\n        let (last, signature) = raw_signature.split_last().unwrap();\n\n        if signature != BYTECODE_VERSION.as_bytes() {\n            return Err(io::Error::new::<String>(\n                io::ErrorKind::InvalidInput,\n                \"Invalid bytecode version\".into(),\n            ));\n        }\n\n        let mut compressed = None;\n        if *last == BYTECODE_COMPRESSED {\n            compressed = Some(true)\n        } else if *last == BYTECODE_UNCOMPRESSED {\n            compressed = Some(false)\n        }\n\n        let rest = &input[SIGNATURE_LENGTH..];\n        Ok((\n            signature,\n            compressed.ok_or(io::Error::new::<String>(\n                io::ErrorKind::InvalidInput,\n                \"Invalid bytecode signature\".into(),\n            ))?,\n            rest,\n        ))\n    }\n\n    fn normalize_name(name: &str) -> (bool, bool, &str, &str) {\n        if !name.starts_with(\"__\") {\n            // If name doesn’t start with \"__\", return defaults\n            return (false, false, name, name);\n        }\n\n        if let Some(cjs_path) = name.strip_prefix(CJS_IMPORT_PREFIX) {\n            // If it starts with CJS_IMPORT_PREFIX, mark as from_cjs_import\n            return (true, false, name, cjs_path);\n        }\n\n        if let Some(cjs_path) = name.strip_prefix(CJS_LOADER_PREFIX) {\n            // If it starts with CJS_LOADER_PREFIX, mark as is_cjs\n            return (false, true, cjs_path, cjs_path);\n        }\n\n        // Default return if no prefixes match\n        (false, false, name, name)\n    }\n\n    fn load_module<'js>(name: &str, ctx: &Ctx<'js>) -> Result<(Module<'js>, Option<String>)> {\n        let ctx = ctx.clone();\n\n        let (_, _, normalized_name, path) = Self::normalize_name(name);\n\n        #[cfg(feature = \"lambda\")]\n        #[cfg(test)]\n        init_client_connection(&ctx, path)?;\n\n        if let Some(bytes) = BYTECODE_CACHE.get(path) {\n            #[cfg(not(test))]\n            #[cfg(feature = \"lambda\")]\n            init_client_connection(&ctx, path)?;\n\n            trace!(\"Loading embedded module: {}\\n\", path);\n\n            return Ok((Self::load_bytecode_module(ctx, bytes)?, Some(path.into())));\n        }\n\n        let bytes = std::fs::read(path)?;\n        let bytes: &[u8] = &bytes;\n\n        if normalized_name.ends_with(BYTECODE_FILE_EXT) {\n            trace!(\"Loading binary module: {}\\n\", path);\n            return Ok((Self::load_bytecode_module(ctx, bytes)?, Some(path.into())));\n        }\n\n        Err(Error::new_loading_message(path, \"unable to load\"))\n    }\n}\n\nimpl Loader for EmbeddedLoader {\n    fn load<'js>(&mut self, ctx: &Ctx<'js>, name: &str) -> Result<Module<'js>> {\n        let (module, url) = Self::load_module(name, ctx)?;\n        if let Some(url) = url {\n            let meta: Object = module.meta()?;\n            meta.prop(\"url\", url)?;\n        }\n\n        Ok(module)\n    }\n}\n\n#[cfg(test)]\n#[cfg(feature = \"lambda\")]\nfn init_client_connection(ctx: &Ctx<'_>, specifier: &str) -> Result<()> {\n    use crate::runtime_client::{check_client_inited, mark_client_inited};\n    use rquickjs::qjs;\n\n    if specifier.ends_with(\"sdk-runtime-init.mjs\") {\n        let rt = unsafe { qjs::JS_GetRuntime(ctx.as_raw().as_ptr()) };\n        let rt_ptr = rt as usize; //hack to move, is safe since runtime is still alive in spawn\n        if !check_client_inited(rt, \"endpoint\") {\n            tokio::task::spawn(async move {\n                tokio::time::sleep(std::time::Duration::from_millis(100)).await;\n                mark_client_inited(rt_ptr as _);\n            });\n        }\n    };\n    Ok(())\n}\n\n#[cfg(not(test))]\n#[cfg(feature = \"lambda\")]\nfn init_client_connection(ctx: &Ctx<'_>, specifier: &str) -> Result<()> {\n    use std::{\n        env,\n        time::{Duration, Instant},\n    };\n\n    use http_body_util::BodyExt;\n    use hyper::Uri;\n    use rquickjs::qjs;\n\n    use crate::environment::ENV_LLRT_SDK_CONNECTION_WARMUP;\n    use crate::libs::utils::result::ResultExt;\n    use crate::modules::https::HTTP_CLIENT;\n    use crate::runtime_client::{check_client_inited, mark_client_inited};\n\n    let disable_warmup = env::var(ENV_LLRT_SDK_CONNECTION_WARMUP).unwrap_or_default();\n    if disable_warmup == \"0\" || disable_warmup == \"false\" {\n        return Ok(());\n    }\n\n    let Some(sdk_import) = specifier.strip_prefix(\"@aws-sdk/\") else {\n        return Ok(());\n    };\n\n    let client_name = sdk_import.trim_start_matches(\"client-\");\n\n    let Some(endpoint) = SDK_CLIENT_ENDPOINTS.get(client_name) else {\n        return Ok(());\n    };\n\n    let endpoint = if endpoint.is_empty() {\n        client_name\n    } else {\n        endpoint\n    };\n\n    let mut region = env::var(\"AWS_REGION\").unwrap();\n    let mut region_separator = \".\";\n\n    //do not use regional endpoint for global services https://docs.aws.amazon.com/general/latest/gr/rande.html#global-endpoints\n    if matches!(\n        client_name,\n        \"iam\"\n            | \"route-53\"\n            | \"cloudfront\"\n            | \"waf\"\n            | \"shield\"\n            | \"global-accelerator\"\n            | \"organizations\"\n            | \"networkmanager\"\n    ) {\n        // the latency to do a roundtrip to a global endpoint can exceed the savings if the region is not us-east-1\n        if region != \"us-east-1\" {\n            trace!(\n                \"Ignoring init for global client: {} because region: {} not geographically close to us-east-1\",\n                client_name,\n                region\n            );\n            return Ok(());\n        }\n        region_separator = \"\";\n        region.clear();\n    };\n\n    let rt = unsafe { qjs::JS_GetRuntime(ctx.as_raw().as_ptr()) };\n    let rt_ptr = rt as usize; //hack to move, is safe since runtime is still alive in spawn\n\n    if check_client_inited(rt, endpoint) {\n        return Ok(());\n    }\n\n    let client = HTTP_CLIENT.as_ref().or_throw(ctx)?;\n\n    trace!(\"Started client init {}\", client_name);\n\n    let url_string = [\n        \"https://\",\n        endpoint,\n        region_separator,\n        &region,\n        \".amazonaws.com/sping\",\n    ]\n    .concat();\n\n    if let Ok(url) = url_string.parse::<Uri>() {\n        tokio::task::spawn(async move {\n            let start = Instant::now();\n            let get_future = client.get(url);\n\n            let result = tokio::time::timeout(Duration::from_secs(1), get_future).await;\n\n            if let Ok(Ok(mut res)) = result {\n                if res.body_mut().collect().await.is_ok() {\n                    trace!(\"Client connection initialized in {:?}\", start.elapsed())\n                } else {\n                    trace!(\"Failed to connect for client init {}\", &url_string)\n                }\n            } else {\n                trace!(\"Failed to connect for client init {}\", &url_string)\n            };\n            mark_client_inited(rt_ptr as _);\n        });\n    } else {\n        trace!(\"Failed to parse url for init\");\n        mark_client_inited(rt_ptr as _);\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "llrt_core/src/modules/embedded/mod.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::env;\n\nuse rquickjs::{Ctx, Function, Result};\n\nuse crate::modules::{CJS_IMPORT_PREFIX, CJS_LOADER_PREFIX};\n\nuse self::resolver::embedded_resolve;\n\npub mod loader;\npub mod resolver;\n\npub static COMPRESSION_DICT: &[u8] = include_bytes!(concat!(env!(\"OUT_DIR\"), \"/compression.dict\"));\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/bytecode_cache.rs\"));\n\npub fn init(ctx: &Ctx) -> Result<()> {\n    let globals = ctx.globals();\n\n    let embedded_hook = Function::new(ctx.clone(), move |x: String, y: String| {\n        embedded_resolve(&x, &y).map(|res| res.into_owned())\n    })?;\n\n    globals.set(\"__require_hook\", embedded_hook)?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "llrt_core/src/modules/embedded/resolver.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::borrow::Cow;\n\nuse rquickjs::{loader::Resolver, Ctx, Error, Result};\nuse tracing::trace;\n\nuse crate::modules::path;\n\nuse super::{BYTECODE_CACHE, CJS_IMPORT_PREFIX};\n\n#[derive(Debug, Default)]\npub struct EmbeddedResolver;\n\n#[allow(clippy::manual_strip)]\nimpl Resolver for EmbeddedResolver {\n    fn resolve(&mut self, _ctx: &Ctx, base: &str, name: &str) -> Result<String> {\n        let name = name.trim_start_matches(CJS_IMPORT_PREFIX);\n        let name = name.trim_start_matches(\"node:\").trim_end_matches(\"/\");\n\n        let base = base.trim_start_matches(CJS_IMPORT_PREFIX);\n\n        trace!(\"Try resolve '{}' from '{}'\", name, base);\n\n        embedded_resolve(name, base).map(|name| name.into_owned())\n    }\n}\n\npub fn embedded_resolve<'a>(x: &'a str, y: &str) -> Result<Cow<'a, str>> {\n    trace!(\"embedded_resolve(x, y):({}, {})\", x, y);\n\n    // If X is a bytecode cache,\n    if BYTECODE_CACHE.contains_key(x) {\n        trace!(\"+- Resolved by `BYTECODE_CACHE`: {}\", x);\n        return Ok(x.into());\n    }\n\n    let x_normalized = path::normalize(x);\n    if BYTECODE_CACHE.contains_key(&x_normalized) {\n        trace!(\"+- Resolved by `BYTECODE_CACHE`: {}\", x_normalized);\n        return Ok(x_normalized.into());\n    }\n\n    Err(Error::new_resolving(y.to_string(), x.to_string()))\n}\n"
  },
  {
    "path": "llrt_core/src/modules/js/@llrt/expect/jest-asymmetric-matchers.ts",
    "content": "/*\nMIT License\n\nCopyright (c) 2021-Present Anthony Fu <https://github.com/antfu>\nCopyright (c) 2021-Present Matias Capeletto <https://github.com/patak-dev>\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// Extracted and modified from Vitest:  https://github.com/vitest-dev/vitest/blob/7a31a1ae4223aed3adf260e63ac3b3f7fab3c9d7/packages/expect/src/jest-asymmetric-matchers.ts\n\nimport ChaiPlugin = Chai.ChaiPlugin;\n\nimport { equals, isA, pluralize } from \"./jest-utils\";\nimport { stringify } from \"./stringify\";\n\nexport interface AsymmetricMatcherInterface {\n  asymmetricMatch: (other: unknown) => boolean;\n  toString: () => string;\n  getExpectedType?: () => string;\n  toAsymmetricMatcher?: () => string;\n}\n\nexport abstract class AsymmetricMatcher<T>\n  implements AsymmetricMatcherInterface\n{\n  // should have \"jest\" to be compatible with its ecosystem\n  $$typeof = Symbol.for(\"jest.asymmetricMatcher\");\n\n  constructor(\n    protected sample: T,\n    protected inverse = false\n  ) {}\n\n  // protected getMatcherContext(expect?: Chai.ExpectStatic): State {\n  //   return {\n  //     equals,\n  //     isNot: this.inverse,\n  //     customTesters: getCustomEqualityTesters(),\n  //     utils: {\n  //       ...getMatcherUtils(),\n  //       diff,\n  //       stringify,\n  //       iterableEquality,\n  //       subsetEquality,\n  //     },\n  //   }\n  // }\n\n  abstract asymmetricMatch(other: unknown): boolean;\n  abstract toString(): string;\n  getExpectedType?(): string;\n  toAsymmetricMatcher?(): string;\n\n  // implement custom chai/loupe inspect for better AssertionError.message formatting\n  // https://github.com/chaijs/loupe/blob/9b8a6deabcd50adc056a64fb705896194710c5c6/src/index.ts#L29\n  [Symbol.for(\"chai/inspect\")](options: { depth: number; truncate: number }) {\n    // minimal pretty-format with simple manual truncation\n    const result = stringify(this, options.depth, { min: true });\n    if (result.length <= options.truncate) return result;\n    return `${this.toString()}{…}`;\n  }\n}\n\nexport class StringContaining extends AsymmetricMatcher<string> {\n  constructor(sample: string, inverse = false) {\n    if (!isA(\"String\", sample)) throw new Error(\"Expected is not a string\");\n\n    super(sample, inverse);\n  }\n\n  asymmetricMatch(other: string) {\n    const result = isA(\"String\", other) && other.includes(this.sample);\n\n    return this.inverse ? !result : result;\n  }\n\n  toString() {\n    return `String${this.inverse ? \"Not\" : \"\"}Containing`;\n  }\n\n  getExpectedType() {\n    return \"string\";\n  }\n}\n\nexport class Anything extends AsymmetricMatcher<void> {\n  asymmetricMatch(other: unknown) {\n    return other != null;\n  }\n\n  toString() {\n    return \"Anything\";\n  }\n\n  toAsymmetricMatcher() {\n    return \"Anything\";\n  }\n}\n\nexport class ObjectContaining extends AsymmetricMatcher<\n  Record<string, unknown>\n> {\n  constructor(sample: Record<string, unknown>, inverse = false) {\n    super(sample, inverse);\n  }\n\n  getPrototype(obj: object) {\n    if (Object.getPrototypeOf) return Object.getPrototypeOf(obj);\n\n    if (obj.constructor.prototype === obj) return null;\n\n    return obj.constructor.prototype;\n  }\n\n  hasProperty(obj: object | null, property: string): boolean {\n    if (!obj) return false;\n\n    if (Object.prototype.hasOwnProperty.call(obj, property)) return true;\n\n    return this.hasProperty(this.getPrototype(obj), property);\n  }\n\n  asymmetricMatch(other: any) {\n    if (typeof this.sample !== \"object\") {\n      throw new TypeError(\n        `You must provide an object to ${this.toString()}, not '${typeof this\n          .sample}'.`\n      );\n    }\n\n    let result = true;\n\n    // const matcherContext = this.getMatcherContext()\n    for (const property in this.sample) {\n      if (\n        !this.hasProperty(other, property) ||\n        !equals(this.sample[property], other[property], [])\n      ) {\n        result = false;\n        break;\n      }\n    }\n\n    return this.inverse ? !result : result;\n  }\n\n  toString() {\n    return `Object${this.inverse ? \"Not\" : \"\"}Containing`;\n  }\n\n  getExpectedType() {\n    return \"object\";\n  }\n}\n\nexport class ArrayContaining<T = unknown> extends AsymmetricMatcher<Array<T>> {\n  constructor(sample: Array<T>, inverse = false) {\n    super(sample, inverse);\n  }\n\n  asymmetricMatch(other: Array<T>) {\n    if (!Array.isArray(this.sample)) {\n      throw new TypeError(\n        `You must provide an array to ${this.toString()}, not '${typeof this\n          .sample}'.`\n      );\n    }\n\n    const result =\n      this.sample.length === 0 ||\n      (Array.isArray(other) &&\n        this.sample.every((item) =>\n          other.some((another) => equals(item, another, []))\n        ));\n\n    return this.inverse ? !result : result;\n  }\n\n  toString() {\n    return `Array${this.inverse ? \"Not\" : \"\"}Containing`;\n  }\n\n  getExpectedType() {\n    return \"array\";\n  }\n}\n\nexport class Any extends AsymmetricMatcher<any> {\n  constructor(sample: unknown) {\n    if (typeof sample === \"undefined\") {\n      throw new TypeError(\n        \"any() expects to be passed a constructor function. \" +\n          \"Please pass one or use anything() to match any object.\"\n      );\n    }\n    super(sample);\n  }\n\n  fnNameFor(func: Function) {\n    if (func.name) return func.name;\n\n    const functionToString = Function.prototype.toString;\n\n    const matches = functionToString\n      .call(func)\n      .match(/^(?:async)?\\s*function\\s*\\*?\\s*([\\w$]+)\\s*\\(/);\n    return matches ? matches[1] : \"<anonymous>\";\n  }\n\n  asymmetricMatch(other: unknown) {\n    if (this.sample === String)\n      return typeof other == \"string\" || other instanceof String;\n\n    if (this.sample === Number)\n      return typeof other == \"number\" || other instanceof Number;\n\n    if (this.sample === Function)\n      return typeof other == \"function\" || other instanceof Function;\n\n    if (this.sample === Boolean)\n      return typeof other == \"boolean\" || other instanceof Boolean;\n\n    if (this.sample === BigInt)\n      return typeof other == \"bigint\" || other instanceof BigInt;\n\n    if (this.sample === Symbol)\n      return typeof other == \"symbol\" || other instanceof Symbol;\n\n    if (this.sample === Object) return typeof other == \"object\";\n\n    return other instanceof this.sample;\n  }\n\n  toString() {\n    return \"Any\";\n  }\n\n  getExpectedType() {\n    if (this.sample === String) return \"string\";\n\n    if (this.sample === Number) return \"number\";\n\n    if (this.sample === Function) return \"function\";\n\n    if (this.sample === Object) return \"object\";\n\n    if (this.sample === Boolean) return \"boolean\";\n\n    return this.fnNameFor(this.sample);\n  }\n\n  toAsymmetricMatcher() {\n    return `Any<${this.fnNameFor(this.sample)}>`;\n  }\n}\n\nexport class StringMatching extends AsymmetricMatcher<RegExp> {\n  constructor(sample: string | RegExp, inverse = false) {\n    if (!isA(\"String\", sample) && !isA(\"RegExp\", sample))\n      throw new Error(\"Expected is not a String or a RegExp\");\n\n    super(new RegExp(sample), inverse);\n  }\n\n  asymmetricMatch(other: string) {\n    const result = isA(\"String\", other) && this.sample.test(other);\n\n    return this.inverse ? !result : result;\n  }\n\n  toString() {\n    return `String${this.inverse ? \"Not\" : \"\"}Matching`;\n  }\n\n  getExpectedType() {\n    return \"string\";\n  }\n}\n\nclass CloseTo extends AsymmetricMatcher<number> {\n  private readonly precision: number;\n\n  constructor(sample: number, precision = 2, inverse = false) {\n    if (!isA(\"Number\", sample)) throw new Error(\"Expected is not a Number\");\n\n    if (!isA(\"Number\", precision)) throw new Error(\"Precision is not a Number\");\n\n    super(sample);\n    this.inverse = inverse;\n    this.precision = precision;\n  }\n\n  asymmetricMatch(other: number) {\n    if (!isA(\"Number\", other)) return false;\n\n    let result = false;\n    if (\n      other === Number.POSITIVE_INFINITY &&\n      this.sample === Number.POSITIVE_INFINITY\n    ) {\n      result = true; // Infinity - Infinity is NaN\n    } else if (\n      other === Number.NEGATIVE_INFINITY &&\n      this.sample === Number.NEGATIVE_INFINITY\n    ) {\n      result = true; // -Infinity - -Infinity is NaN\n    } else {\n      result = Math.abs(this.sample - other) < 10 ** -this.precision / 2;\n    }\n    return this.inverse ? !result : result;\n  }\n\n  toString() {\n    return `Number${this.inverse ? \"Not\" : \"\"}CloseTo`;\n  }\n\n  override getExpectedType() {\n    return \"number\";\n  }\n\n  override toAsymmetricMatcher(): string {\n    return [\n      this.toString(),\n      this.sample,\n      `(${pluralize(\"digit\", this.precision)})`,\n    ].join(\" \");\n  }\n}\n\nexport const JestAsymmetricMatchers: ChaiPlugin = (chai, utils) => {\n  utils.addMethod(chai.expect, \"anything\", () => new Anything());\n\n  utils.addMethod(chai.expect, \"any\", (expected: unknown) => new Any(expected));\n\n  utils.addMethod(\n    chai.expect,\n    \"stringContaining\",\n    (expected: string) => new StringContaining(expected)\n  );\n\n  utils.addMethod(\n    chai.expect,\n    \"objectContaining\",\n    (expected: any) => new ObjectContaining(expected)\n  );\n\n  utils.addMethod(\n    chai.expect,\n    \"arrayContaining\",\n    <T = any>(expected: Array<T>) => new ArrayContaining<T>(expected)\n  );\n\n  utils.addMethod(\n    chai.expect,\n    \"stringMatching\",\n    (expected: any) => new StringMatching(expected)\n  );\n\n  utils.addMethod(\n    chai.expect,\n    \"closeTo\",\n    (expected: any, precision?: number) => new CloseTo(expected, precision)\n  );\n\n  // defineProperty does not work\n  (chai.expect as any).not = {\n    stringContaining: (expected: string) =>\n      new StringContaining(expected, true),\n    objectContaining: (expected: any) => new ObjectContaining(expected, true),\n    arrayContaining: <T = unknown>(expected: Array<T>) =>\n      new ArrayContaining<T>(expected, true),\n    stringMatching: (expected: string | RegExp) =>\n      new StringMatching(expected, true),\n    closeTo: (expected: any, precision?: number) =>\n      new CloseTo(expected, precision, true),\n  };\n};\n"
  },
  {
    "path": "llrt_core/src/modules/js/@llrt/expect/jest-expect.ts",
    "content": "/*\nMIT License\n\nCopyright (c) 2021-Present Anthony Fu <https://github.com/antfu>\nCopyright (c) 2021-Present Matias Capeletto <https://github.com/patak-dev>\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// Extracted and modified from Vitest:  https://github.com/vitest-dev/vitest/blob/a199ac2dd1322d7839d4d1350c983070da546805/packages/expect/src/jest-expect.ts\n\nimport {\n  arrayBufferEquality,\n  equals as jestEquals,\n  generateToBeMessage,\n  iterableEquality,\n  sparseArrayEquality,\n  subsetEquality,\n  typeEquality,\n} from \"./jest-utils\";\nimport ChaiPlugin = Chai.ChaiPlugin;\nimport Assertion = Chai.Assertion;\nimport { AsymmetricMatcher } from \"./jest-asymmetric-matchers\";\n\n// Jest Expect Compact\nexport const JestChaiExpect: ChaiPlugin = (chai, utils) => {\n  const { AssertionError } = chai;\n  // const c = () => getColors()\n  const customTesters: ((\n    a: any,\n    b: any,\n    customTesters?: Array<any>,\n    aStack?: Array<any>,\n    bStack?: Array<any>\n  ) => boolean | undefined)[] = [];\n\n  function def(\n    name: string | string[],\n    fn: (this: Chai.AssertionStatic & Assertion, ...args: any[]) => any\n  ) {\n    const addMethod = (n: string) => {\n      // const softWrapper = wrapSoft(utils, fn)\n      utils.addMethod(chai.Assertion.prototype, n, fn);\n      // utils.addMethod((globalThis as any)[JEST_MATCHERS_OBJECT].matchers, n, softWrapper)\n    };\n\n    if (Array.isArray(name)) name.forEach((n) => addMethod(n));\n    else addMethod(name);\n  }\n\n  ([\"throw\", \"throws\", \"Throw\"] as const).forEach((m) => {\n    utils.overwriteMethod(chai.Assertion.prototype, m, (_super: any) => {\n      return function (\n        this: Chai.Assertion & Chai.AssertionStatic,\n        ...args: any[]\n      ) {\n        const promise = utils.flag(this, \"promise\");\n        const object = utils.flag(this, \"object\");\n        const isNot = utils.flag(this, \"negate\") as boolean;\n        if (promise === \"rejects\") {\n          utils.flag(this, \"object\", () => {\n            throw object;\n          });\n        }\n        // if it got here, it's already resolved\n        // unless it tries to resolve to a function that should throw\n        // called as '.resolves[.not].toThrow()`\n        else if (promise === \"resolves\" && typeof object !== \"function\") {\n          if (!isNot) {\n            const message =\n              utils.flag(this, \"message\") ||\n              \"expected promise to throw an error, but it didn't\";\n            const error = {\n              showDiff: false,\n            };\n            throw new AssertionError(message, error, utils.flag(this, \"ssfi\"));\n          } else {\n            return;\n          }\n        }\n        _super.apply(this, args);\n      };\n    });\n  });\n\n  def(\"toEqual\", function (expected) {\n    const actual = utils.flag(this, \"object\");\n    const equal = jestEquals(actual, expected, [\n      ...customTesters,\n      iterableEquality,\n    ]);\n    return this.assert(\n      equal,\n      \"expected #{this} to deeply equal #{exp}\",\n      \"expected #{this} to not deeply equal #{exp}\",\n      expected,\n      actual\n    );\n  });\n\n  def(\"toStrictEqual\", function (expected) {\n    const obj = utils.flag(this, \"object\");\n    const equal = jestEquals(\n      obj,\n      expected,\n      [\n        ...customTesters,\n        iterableEquality,\n        typeEquality,\n        sparseArrayEquality,\n        arrayBufferEquality,\n      ],\n      true\n    );\n\n    return this.assert(\n      equal,\n      \"expected #{this} to strictly equal #{exp}\",\n      \"expected #{this} to not strictly equal #{exp}\",\n      expected,\n      obj\n    );\n  });\n  def(\"toBe\", function (expected) {\n    const actual = this._obj;\n    const pass = Object.is(actual, expected);\n\n    let deepEqualityName = \"\";\n\n    if (!pass) {\n      const toStrictEqualPass = jestEquals(\n        actual,\n        expected,\n        [\n          ...customTesters,\n          iterableEquality,\n          typeEquality,\n          sparseArrayEquality,\n          arrayBufferEquality,\n        ],\n        true\n      );\n\n      if (toStrictEqualPass) {\n        deepEqualityName = \"toStrictEqual\";\n      } else {\n        const toEqualPass = jestEquals(actual, expected, [\n          ...customTesters,\n          iterableEquality,\n        ]);\n\n        if (toEqualPass) deepEqualityName = \"toEqual\";\n      }\n    }\n\n    return this.assert(\n      pass,\n      generateToBeMessage(deepEqualityName),\n      \"expected #{this} not to be #{exp} // Object.is equality\",\n      expected,\n      actual\n    );\n  });\n  def(\"toMatchObject\", function (expected) {\n    const actual = this._obj;\n    return this.assert(\n      jestEquals(actual, expected, [\n        ...customTesters,\n        iterableEquality,\n        subsetEquality,\n      ]),\n      \"expected #{this} to match object #{exp}\",\n      \"expected #{this} to not match object #{exp}\",\n      expected,\n      actual\n    );\n  });\n  def(\"toMatch\", function (expected: string | RegExp) {\n    if (typeof expected === \"string\") return this.include(expected);\n    else return this.match(expected);\n  });\n  def(\"toContain\", function (item) {\n    const actual = this._obj as Iterable<unknown> | string;\n\n    // make \"actual\" indexable to have compatibility with jest\n    if (actual != null && typeof actual !== \"string\")\n      utils.flag(this, \"object\", Array.from(actual as Iterable<unknown>));\n    return this.contain(item);\n  });\n  def(\"toContainEqual\", function (expected) {\n    const obj = utils.flag(this, \"object\");\n    const index = Array.from(obj).findIndex((item) => {\n      return jestEquals(item, expected, customTesters);\n    });\n\n    this.assert(\n      index !== -1,\n      \"expected #{this} to deep equally contain #{exp}\",\n      \"expected #{this} to not deep equally contain #{exp}\",\n      expected\n    );\n  });\n  def(\"toBeTruthy\", function () {\n    const obj = utils.flag(this, \"object\");\n    this.assert(\n      Boolean(obj),\n      \"expected #{this} to be truthy\",\n      \"expected #{this} to not be truthy\",\n      obj,\n      false\n    );\n  });\n  def(\"toBeFalsy\", function () {\n    const obj = utils.flag(this, \"object\");\n    this.assert(\n      !obj,\n      \"expected #{this} to be falsy\",\n      \"expected #{this} to not be falsy\",\n      obj,\n      false\n    );\n  });\n  def(\"toBeGreaterThan\", function (expected: number | bigint) {\n    const actual = this._obj as number | bigint;\n    assertTypes(actual, \"actual\", [\"number\", \"bigint\"]);\n    assertTypes(expected, \"expected\", [\"number\", \"bigint\"]);\n    return this.assert(\n      actual > expected,\n      `expected ${actual} to be greater than ${expected}`,\n      `expected ${actual} to be not greater than ${expected}`,\n      actual,\n      expected,\n      false\n    );\n  });\n  def(\"toBeGreaterThanOrEqual\", function (expected: number | bigint) {\n    const actual = this._obj as number | bigint;\n    assertTypes(actual, \"actual\", [\"number\", \"bigint\"]);\n    assertTypes(expected, \"expected\", [\"number\", \"bigint\"]);\n    return this.assert(\n      actual >= expected,\n      `expected ${actual} to be greater than or equal to ${expected}`,\n      `expected ${actual} to be not greater than or equal to ${expected}`,\n      actual,\n      expected,\n      false\n    );\n  });\n  def(\"toBeLessThan\", function (expected: number | bigint) {\n    const actual = this._obj as number | bigint;\n    assertTypes(actual, \"actual\", [\"number\", \"bigint\"]);\n    assertTypes(expected, \"expected\", [\"number\", \"bigint\"]);\n    return this.assert(\n      actual < expected,\n      `expected ${actual} to be less than ${expected}`,\n      `expected ${actual} to be not less than ${expected}`,\n      actual,\n      expected,\n      false\n    );\n  });\n  def(\"toBeLessThanOrEqual\", function (expected: number | bigint) {\n    const actual = this._obj as number | bigint;\n    assertTypes(actual, \"actual\", [\"number\", \"bigint\"]);\n    assertTypes(expected, \"expected\", [\"number\", \"bigint\"]);\n    return this.assert(\n      actual <= expected,\n      `expected ${actual} to be less than or equal to ${expected}`,\n      `expected ${actual} to be not less than or equal to ${expected}`,\n      actual,\n      expected,\n      false\n    );\n  });\n  def(\"toBeNaN\", function () {\n    return this.be.NaN;\n  });\n  def(\"toBeUndefined\", function () {\n    return this.be.undefined;\n  });\n  def(\"toBeNull\", function () {\n    return this.be.null;\n  });\n  def(\"toBeDefined\", function () {\n    const negate = utils.flag(this, \"negate\");\n    utils.flag(this, \"negate\", false);\n\n    if (negate) return this.be.undefined;\n\n    return this.not.be.undefined;\n  });\n  def(\n    \"toBeTypeOf\",\n    function (\n      expected:\n        | \"bigint\"\n        | \"boolean\"\n        | \"function\"\n        | \"number\"\n        | \"object\"\n        | \"string\"\n        | \"symbol\"\n        | \"undefined\"\n    ) {\n      const actual = typeof this._obj;\n      const equal = expected === actual;\n      return this.assert(\n        equal,\n        \"expected #{this} to be type of #{exp}\",\n        \"expected #{this} not to be type of #{exp}\",\n        expected,\n        actual\n      );\n    }\n  );\n  def(\"toBeInstanceOf\", function (obj: any) {\n    return this.instanceOf(obj);\n  });\n  def(\"toHaveLength\", function (length: number) {\n    return this.have.length(length);\n  });\n  // destructuring, because it checks `arguments` inside, and value is passing as `undefined`\n  def(\n    \"toHaveProperty\",\n    function (...args: [property: string | (string | number)[], value?: any]) {\n      if (Array.isArray(args[0]))\n        args[0] = args[0]\n          .map((key) => String(key).replace(/([.[\\]])/g, \"\\\\$1\"))\n          .join(\".\");\n\n      const actual = this._obj as any;\n      const [propertyName, expected] = args;\n      const getValue = () => {\n        const hasOwn = Object.prototype.hasOwnProperty.call(\n          actual,\n          propertyName\n        );\n        if (hasOwn) return { value: actual[propertyName], exists: true };\n        return utils.getPathInfo(actual, propertyName);\n      };\n      const { value, exists } = getValue();\n      const pass =\n        exists &&\n        (args.length === 1 || jestEquals(expected, value, customTesters));\n\n      const valueString =\n        args.length === 1 ? \"\" : ` with value ${utils.objDisplay(expected)}`;\n\n      return this.assert(\n        pass,\n        `expected #{this} to have property \"${propertyName}\"${valueString}`,\n        `expected #{this} to not have property \"${propertyName}\"${valueString}`,\n        expected,\n        exists ? value : undefined\n      );\n    }\n  );\n  def(\"toBeCloseTo\", function (received: number, precision = 2) {\n    const expected = this._obj;\n    let pass = false;\n    let expectedDiff = 0;\n    let receivedDiff = 0;\n\n    if (\n      received === Number.POSITIVE_INFINITY &&\n      expected === Number.POSITIVE_INFINITY\n    ) {\n      pass = true;\n    } else if (\n      received === Number.NEGATIVE_INFINITY &&\n      expected === Number.NEGATIVE_INFINITY\n    ) {\n      pass = true;\n    } else {\n      expectedDiff = 10 ** -precision / 2;\n      receivedDiff = Math.abs(expected - received);\n      pass = receivedDiff < expectedDiff;\n    }\n    return this.assert(\n      pass,\n      `expected #{this} to be close to #{exp}, received difference is ${receivedDiff}, but expected ${expectedDiff}`,\n      `expected #{this} to not be close to #{exp}, received difference is ${receivedDiff}, but expected ${expectedDiff}`,\n      received,\n      expected,\n      false\n    );\n  });\n\n  const ordinalOf = (i: number) => {\n    const j = i % 10;\n    const k = i % 100;\n\n    if (j === 1 && k !== 11) return `${i}st`;\n\n    if (j === 2 && k !== 12) return `${i}nd`;\n\n    if (j === 3 && k !== 13) return `${i}rd`;\n\n    return `${i}th`;\n  };\n\n  def(\n    [\"toThrow\", \"toThrowError\"],\n    function (expected?: string | RegExp | Error) {\n      if (\n        typeof expected === \"string\" ||\n        typeof expected === \"undefined\" ||\n        expected instanceof RegExp\n      )\n        return this.throws(expected);\n\n      const obj = this._obj;\n      const promise = utils.flag(this, \"promise\");\n      const isNot = utils.flag(this, \"negate\") as boolean;\n      let thrown: any = null;\n\n      if (promise === \"rejects\") {\n        thrown = obj;\n      }\n      // if it got here, it's already resolved\n      // unless it tries to resolve to a function that should throw\n      // called as .resolves.toThrow(Error)\n      else if (promise === \"resolves\" && typeof obj !== \"function\") {\n        if (!isNot) {\n          const message =\n            utils.flag(this, \"message\") ||\n            \"expected promise to throw an error, but it didn't\";\n          const error = {\n            showDiff: false,\n          };\n          throw new AssertionError(message, error, utils.flag(this, \"ssfi\"));\n        } else {\n          return;\n        }\n      } else {\n        let isThrow = false;\n        try {\n          obj();\n        } catch (err) {\n          isThrow = true;\n          thrown = err;\n        }\n\n        if (!isThrow && !isNot) {\n          const message =\n            utils.flag(this, \"message\") ||\n            \"expected function to throw an error, but it didn't\";\n          const error = {\n            showDiff: false,\n          };\n          throw new AssertionError(message, error, utils.flag(this, \"ssfi\"));\n        }\n      }\n\n      if (typeof expected === \"function\") {\n        // @ts-ignore\n        const name = expected.name || expected.prototype.constructor.name;\n        return this.assert(\n          thrown && thrown instanceof expected,\n          `expected error to be instance of ${name}`,\n          `expected error not to be instance of ${name}`,\n          expected,\n          thrown\n        );\n      }\n\n      if (expected instanceof Error) {\n        return this.assert(\n          thrown && expected.message === thrown.message,\n          `expected error to have message: ${expected.message}`,\n          `expected error not to have message: ${expected.message}`,\n          expected.message,\n          thrown && thrown.message\n        );\n      }\n\n      if (\n        typeof expected === \"object\" &&\n        \"asymmetricMatch\" in expected &&\n        typeof (expected as any).asymmetricMatch === \"function\"\n      ) {\n        const matcher = expected as any as AsymmetricMatcher<any>;\n        return this.assert(\n          thrown && matcher.asymmetricMatch(thrown),\n          \"expected error to match asymmetric matcher\",\n          \"expected error not to match asymmetric matcher\",\n          matcher,\n          thrown\n        );\n      }\n\n      throw new Error(\n        `\"toThrow\" expects string, RegExp, function, Error instance or asymmetric matcher, got \"${typeof expected}\"`\n      );\n    }\n  );\n\n  def(\"toSatisfy\", function (matcher: Function, message?: string) {\n    return this.be.satisfy(matcher, message);\n  });\n\n  utils.addProperty(\n    chai.Assertion.prototype,\n    \"resolves\",\n    function __VITEST_RESOLVES__(this: any) {\n      const error = new Error(\"resolves\");\n      utils.flag(this, \"promise\", \"resolves\");\n      utils.flag(this, \"error\", error);\n      const test: any = utils.flag(this, \"vitest-test\");\n      const obj = utils.flag(this, \"object\");\n\n      if (typeof obj?.then !== \"function\")\n        throw new TypeError(\n          `You must provide a Promise to expect() when using .resolves, not '${typeof obj}'.`\n        );\n\n      const proxy: any = new Proxy(this, {\n        get: (target, key, receiver) => {\n          const result = Reflect.get(target, key, receiver);\n\n          if (typeof result !== \"function\")\n            return result instanceof chai.Assertion ? proxy : result;\n\n          return async (...args: any[]) => {\n            const promise = obj.then(\n              (value: any) => {\n                utils.flag(this, \"object\", value);\n                return result.call(this, ...args);\n              },\n              (err: any) => {\n                const _error = new AssertionError(\n                  `promise rejected \"${utils.inspect(err)}\" instead of resolving`,\n                  { showDiff: false }\n                ) as Error;\n                // @ts-ignore\n                _error.cause = err;\n                _error.stack = (error.stack as string).replace(\n                  error.message,\n                  _error.message\n                );\n                throw _error;\n              }\n            );\n\n            return recordAsyncExpect(test, promise);\n          };\n        },\n      });\n\n      return proxy;\n    }\n  );\n\n  utils.addProperty(\n    chai.Assertion.prototype,\n    \"rejects\",\n    function __VITEST_REJECTS__(this: any) {\n      const error = new Error(\"rejects\");\n      utils.flag(this, \"promise\", \"rejects\");\n      utils.flag(this, \"error\", error);\n      const test: any = utils.flag(this, \"vitest-test\");\n      const obj = utils.flag(this, \"object\");\n      const wrapper = typeof obj === \"function\" ? obj() : obj; // for jest compat\n\n      if (typeof wrapper?.then !== \"function\")\n        throw new TypeError(\n          `You must provide a Promise to expect() when using .rejects, not '${typeof wrapper}'.`\n        );\n\n      const proxy: any = new Proxy(this, {\n        get: (target, key, receiver) => {\n          const result = Reflect.get(target, key, receiver);\n\n          if (typeof result !== \"function\")\n            return result instanceof chai.Assertion ? proxy : result;\n\n          return async (...args: any[]) => {\n            const promise = wrapper.then(\n              (value: any) => {\n                const _error = new AssertionError(\n                  `promise resolved \"${utils.inspect(value)}\" instead of rejecting`,\n                  {\n                    showDiff: true,\n                    expected: new Error(\"rejected promise\"),\n                    actual: value,\n                  }\n                ) as any;\n                _error.stack = (error.stack as string).replace(\n                  error.message,\n                  _error.message\n                );\n                throw _error;\n              },\n              (err: any) => {\n                utils.flag(this, \"object\", err);\n                return result.call(this, ...args);\n              }\n            );\n\n            return recordAsyncExpect(test, promise);\n          };\n        },\n      });\n\n      return proxy;\n    }\n  );\n};\n\nexport function assertTypes(\n  value: unknown,\n  name: string,\n  types: string[]\n): void {\n  const receivedType = typeof value;\n  const pass = types.includes(receivedType);\n  if (!pass)\n    throw new TypeError(\n      `${name} value must be ${types.join(\" or \")}, received \"${receivedType}\"`\n    );\n}\n\nexport function recordAsyncExpect(\n  test: any,\n  promise: Promise<any> | PromiseLike<any>\n) {\n  // record promise for test, that resolves before test ends\n  if (test && promise instanceof Promise) {\n    // if promise is explicitly awaited, remove it from the list\n    promise = promise.finally(() => {\n      const index = test.promises.indexOf(promise);\n      if (index !== -1) test.promises.splice(index, 1);\n    });\n\n    // record promise\n    if (!test.promises) test.promises = [];\n    test.promises.push(promise);\n  }\n\n  return promise;\n}\n"
  },
  {
    "path": "llrt_core/src/modules/js/@llrt/expect/jest-utils.ts",
    "content": "/*\nCopyright (c) 2008-2016 Pivotal Labs\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\n// Extracted and modified from Vitest: https://github.com/vitest-dev/vitest/blob/463bee38463cd66f9b1f11983a787d9e0e3a7dea/packages/expect/src/jest-utils.ts\n\nexport function isObject(item: unknown): boolean {\n  return item != null && typeof item === \"object\" && !Array.isArray(item);\n}\n// import type { Tester, TesterContext } from './types'\n\n// Extracted out of jasmine 2.5.2\nexport function equals(\n  a: unknown,\n  b: unknown,\n  customTesters?: Array<any>,\n  strictCheck?: boolean\n): boolean {\n  customTesters = customTesters || [];\n  return eq(a, b, [], [], customTesters, strictCheck ? hasKey : hasDefinedKey);\n}\n\nconst functionToString = Function.prototype.toString;\n\nexport function isAsymmetric(obj: any) {\n  return (\n    !!obj &&\n    typeof obj === \"object\" &&\n    \"asymmetricMatch\" in obj &&\n    isA(\"Function\", obj.asymmetricMatch)\n  );\n}\n\nexport function hasAsymmetric(obj: any, seen = new Set()): boolean {\n  if (seen.has(obj)) return false;\n  seen.add(obj);\n  if (isAsymmetric(obj)) return true;\n  if (Array.isArray(obj)) return obj.some((i) => hasAsymmetric(i, seen));\n  if (obj instanceof Set)\n    return Array.from(obj).some((i) => hasAsymmetric(i, seen));\n  if (isObject(obj))\n    return Object.values(obj).some((v) => hasAsymmetric(v, seen));\n  return false;\n}\n\nfunction asymmetricMatch(a: any, b: any) {\n  const asymmetricA = isAsymmetric(a);\n  const asymmetricB = isAsymmetric(b);\n\n  if (asymmetricA && asymmetricB) return undefined;\n\n  if (asymmetricA) return a.asymmetricMatch(b);\n\n  if (asymmetricB) return b.asymmetricMatch(a);\n}\n\n// Equality function lovingly adapted from isEqual in\n//   [Underscore](http://underscorejs.org)\nfunction eq(\n  a: any,\n  b: any,\n  aStack: Array<unknown>,\n  bStack: Array<unknown>,\n  customTesters: Array<any>,\n  hasKey: any\n): boolean {\n  let result = true;\n\n  const asymmetricResult = asymmetricMatch(a, b);\n  if (asymmetricResult !== undefined) return asymmetricResult;\n\n  const testerContext: any = { equals };\n  for (let i = 0; i < customTesters.length; i++) {\n    const customTesterResult = customTesters[i].call(\n      testerContext,\n      a,\n      b,\n      customTesters\n    );\n    if (customTesterResult !== undefined) return customTesterResult;\n  }\n\n  if (a instanceof Error && b instanceof Error) return a.message === b.message;\n\n  if (typeof URL === \"function\" && a instanceof URL && b instanceof URL)\n    return a.href === b.href;\n\n  if (Object.is(a, b)) return true;\n\n  // A strict comparison is necessary because `null == undefined`.\n  if (a === null || b === null) return a === b;\n\n  const className = Object.prototype.toString.call(a);\n  if (className !== Object.prototype.toString.call(b)) return false;\n\n  switch (className) {\n    case \"[object Boolean]\":\n    case \"[object String]\":\n    case \"[object Number]\":\n      if (typeof a !== typeof b) {\n        // One is a primitive, one a `new Primitive()`\n        return false;\n      } else if (typeof a !== \"object\" && typeof b !== \"object\") {\n        // both are proper primitives\n        return Object.is(a, b);\n      } else {\n        // both are `new Primitive()`s\n        return Object.is(a.valueOf(), b.valueOf());\n      }\n    case \"[object Date]\": {\n      const numA = +a;\n      const numB = +b;\n      // Coerce dates to numeric primitive values. Dates are compared by their\n      // millisecond representations. Note that invalid dates with millisecond representations\n      // of `NaN` are equivalent.\n      return numA === numB || (Number.isNaN(numA) && Number.isNaN(numB));\n    }\n    // RegExps are compared by their source patterns and flags.\n    case \"[object RegExp]\":\n      return a.source === b.source && a.flags === b.flags;\n  }\n  if (typeof a !== \"object\" || typeof b !== \"object\") return false;\n\n  // Use DOM3 method isEqualNode (IE>=9)\n  if (isDomNode(a) && isDomNode(b)) return a.isEqualNode(b);\n\n  // Used to detect circular references.\n  let length = aStack.length;\n  while (length--) {\n    // Linear search. Performance is inversely proportional to the number of\n    // unique nested structures.\n    // circular references at same depth are equal\n    // circular reference is not equal to non-circular one\n    if (aStack[length] === a) return bStack[length] === b;\n    else if (bStack[length] === b) return false;\n  }\n  // Add the first object to the stack of traversed objects.\n  aStack.push(a);\n  bStack.push(b);\n  // Recursively compare objects and arrays.\n  // Compare array lengths to determine if a deep comparison is necessary.\n  if (className === \"[object Array]\" && a.length !== b.length) return false;\n\n  // Deep compare objects.\n  const aKeys = keys(a, hasKey);\n  let key;\n  let size = aKeys.length;\n\n  // Ensure that both objects contain the same number of properties before comparing deep equality.\n  if (keys(b, hasKey).length !== size) return false;\n\n  while (size--) {\n    key = aKeys[size];\n\n    // Deep compare each member\n    result =\n      hasKey(b, key) &&\n      eq(a[key], b[key], aStack, bStack, customTesters, hasKey);\n\n    if (!result) return false;\n  }\n  // Remove the first object from the stack of traversed objects.\n  aStack.pop();\n  bStack.pop();\n\n  return result;\n}\n\nfunction keys(obj: object, hasKey: (obj: object, key: string) => boolean) {\n  const keys = [];\n\n  for (const key in obj) {\n    if (hasKey(obj, key)) keys.push(key);\n  }\n  return keys.concat(\n    (Object.getOwnPropertySymbols(obj) as Array<any>).filter(\n      (symbol) =>\n        (Object.getOwnPropertyDescriptor(obj, symbol) as PropertyDescriptor)\n          .enumerable\n    )\n  );\n}\n\nfunction hasDefinedKey(obj: any, key: string) {\n  return hasKey(obj, key) && obj[key] !== undefined;\n}\n\nfunction hasKey(obj: any, key: string) {\n  return Object.prototype.hasOwnProperty.call(obj, key);\n}\n\nexport function isA(typeName: string, value: unknown) {\n  return Object.prototype.toString.apply(value) === `[object ${typeName}]`;\n}\n\nfunction isDomNode(obj: any): boolean {\n  return (\n    obj !== null &&\n    typeof obj === \"object\" &&\n    \"nodeType\" in obj &&\n    typeof obj.nodeType === \"number\" &&\n    \"nodeName\" in obj &&\n    typeof obj.nodeName === \"string\" &&\n    \"isEqualNode\" in obj &&\n    typeof obj.isEqualNode === \"function\"\n  );\n}\n\nexport function fnNameFor(func: Function) {\n  if (func.name) return func.name;\n\n  const matches = functionToString\n    .call(func)\n    .match(/^(?:async)?\\s*function\\s*\\*?\\s*([\\w$]+)\\s*\\(/);\n  return matches ? matches[1] : \"<anonymous>\";\n}\n\nfunction getPrototype(obj: object) {\n  if (Object.getPrototypeOf) return Object.getPrototypeOf(obj);\n\n  if (obj.constructor.prototype === obj) return null;\n\n  return obj.constructor.prototype;\n}\n\nexport function hasProperty(obj: object | null, property: string): boolean {\n  if (!obj) return false;\n\n  if (Object.prototype.hasOwnProperty.call(obj, property)) return true;\n\n  return hasProperty(getPrototype(obj), property);\n}\n\n// SENTINEL constants are from https://github.com/facebook/immutable-js\nconst IS_KEYED_SENTINEL = \"@@__IMMUTABLE_KEYED__@@\";\nconst IS_SET_SENTINEL = \"@@__IMMUTABLE_SET__@@\";\nconst IS_ORDERED_SENTINEL = \"@@__IMMUTABLE_ORDERED__@@\";\n\nexport function isImmutableUnorderedKeyed(maybeKeyed: any) {\n  return !!(\n    maybeKeyed &&\n    maybeKeyed[IS_KEYED_SENTINEL] &&\n    !maybeKeyed[IS_ORDERED_SENTINEL]\n  );\n}\n\nexport function isImmutableUnorderedSet(maybeSet: any) {\n  return !!(\n    maybeSet &&\n    maybeSet[IS_SET_SENTINEL] &&\n    !maybeSet[IS_ORDERED_SENTINEL]\n  );\n}\n\n/**\n * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\nconst IteratorSymbol = Symbol.iterator;\n\nfunction hasIterator(object: any) {\n  return !!(object != null && object[IteratorSymbol]);\n}\n\nexport function iterableEquality(\n  a: any,\n  b: any,\n  customTesters: Array<any> = [],\n  aStack: Array<any> = [],\n  bStack: Array<any> = []\n): boolean | undefined {\n  if (\n    typeof a !== \"object\" ||\n    typeof b !== \"object\" ||\n    Array.isArray(a) ||\n    Array.isArray(b) ||\n    !hasIterator(a) ||\n    !hasIterator(b)\n  )\n    return undefined;\n\n  if (a.constructor !== b.constructor) return false;\n\n  let length = aStack.length;\n  while (length--) {\n    // Linear search. Performance is inversely proportional to the number of\n    // unique nested structures.\n    // circular references at same depth are equal\n    // circular reference is not equal to non-circular one\n    if (aStack[length] === a) return bStack[length] === b;\n  }\n  aStack.push(a);\n  bStack.push(b);\n\n  const filteredCustomTesters: Array<any> = [\n    ...customTesters.filter((t) => t !== iterableEquality),\n    iterableEqualityWithStack,\n  ];\n\n  function iterableEqualityWithStack(a: any, b: any) {\n    return iterableEquality(\n      a,\n      b,\n      [...filteredCustomTesters],\n      [...aStack],\n      [...bStack]\n    );\n  }\n\n  if (a.size !== undefined) {\n    if (a.size !== b.size) {\n      return false;\n    } else if (isA(\"Set\", a) || isImmutableUnorderedSet(a)) {\n      let allFound = true;\n      for (const aValue of a) {\n        if (!b.has(aValue)) {\n          let has = false;\n          for (const bValue of b) {\n            const isEqual = equals(aValue, bValue, filteredCustomTesters);\n            if (isEqual === true) has = true;\n          }\n\n          if (has === false) {\n            allFound = false;\n            break;\n          }\n        }\n      }\n      // Remove the first value from the stack of traversed values.\n      aStack.pop();\n      bStack.pop();\n      return allFound;\n    } else if (isA(\"Map\", a) || isImmutableUnorderedKeyed(a)) {\n      let allFound = true;\n      for (const aEntry of a) {\n        if (\n          !b.has(aEntry[0]) ||\n          !equals(aEntry[1], b.get(aEntry[0]), filteredCustomTesters)\n        ) {\n          let has = false;\n          for (const bEntry of b) {\n            const matchedKey = equals(\n              aEntry[0],\n              bEntry[0],\n              filteredCustomTesters\n            );\n\n            let matchedValue = false;\n            if (matchedKey === true)\n              matchedValue = equals(\n                aEntry[1],\n                bEntry[1],\n                filteredCustomTesters\n              );\n\n            if (matchedValue === true) has = true;\n          }\n\n          if (has === false) {\n            allFound = false;\n            break;\n          }\n        }\n      }\n      // Remove the first value from the stack of traversed values.\n      aStack.pop();\n      bStack.pop();\n      return allFound;\n    }\n  }\n\n  const bIterator = b[IteratorSymbol]();\n\n  for (const aValue of a) {\n    const nextB = bIterator.next();\n    if (nextB.done || !equals(aValue, nextB.value, filteredCustomTesters))\n      return false;\n  }\n  if (!bIterator.next().done) return false;\n\n  // Remove the first value from the stack of traversed values.\n  aStack.pop();\n  bStack.pop();\n  return true;\n}\n\n/**\n * Checks if `hasOwnProperty(object, key)` up the prototype chain, stopping at `Object.prototype`.\n */\nfunction hasPropertyInObject(object: object, key: string): boolean {\n  const shouldTerminate =\n    !object || typeof object !== \"object\" || object === Object.prototype;\n\n  if (shouldTerminate) return false;\n\n  return (\n    Object.prototype.hasOwnProperty.call(object, key) ||\n    hasPropertyInObject(Object.getPrototypeOf(object), key)\n  );\n}\n\nfunction isObjectWithKeys(a: any) {\n  return (\n    isObject(a) &&\n    !(a instanceof Error) &&\n    !Array.isArray(a) &&\n    !(a instanceof Date)\n  );\n}\n\nexport function subsetEquality(\n  object: unknown,\n  subset: unknown,\n  customTesters: Array<any> = []\n): boolean | undefined {\n  const filteredCustomTesters = customTesters.filter(\n    (t) => t !== subsetEquality\n  );\n  // subsetEquality needs to keep track of the references\n  // it has already visited to avoid infinite loops in case\n  // there are circular references in the subset passed to it.\n  const subsetEqualityWithContext =\n    (seenReferences: WeakMap<object, boolean> = new WeakMap()) =>\n    (object: any, subset: any): boolean | undefined => {\n      if (!isObjectWithKeys(subset)) return undefined;\n\n      return Object.keys(subset).every((key) => {\n        if (isObjectWithKeys(subset[key])) {\n          if (seenReferences.has(subset[key]))\n            return equals(object[key], subset[key], filteredCustomTesters);\n\n          seenReferences.set(subset[key], true);\n        }\n        const result =\n          object != null &&\n          hasPropertyInObject(object, key) &&\n          equals(object[key], subset[key], [\n            ...filteredCustomTesters,\n            subsetEqualityWithContext(seenReferences),\n          ]);\n        // The main goal of using seenReference is to avoid circular node on tree.\n        // It will only happen within a parent and its child, not a node and nodes next to it (same level)\n        // We should keep the reference for a parent and its child only\n        // Thus we should delete the reference immediately so that it doesn't interfere\n        // other nodes within the same level on tree.\n        seenReferences.delete(subset[key]);\n        return result;\n      });\n    };\n\n  return subsetEqualityWithContext()(object, subset);\n}\n\nexport function typeEquality(a: any, b: any): boolean | undefined {\n  if (a == null || b == null || a.constructor === b.constructor)\n    return undefined;\n\n  return false;\n}\n\nexport function arrayBufferEquality(\n  a: unknown,\n  b: unknown\n): boolean | undefined {\n  let dataViewA = a as DataView;\n  let dataViewB = b as DataView;\n\n  if (!(a instanceof DataView && b instanceof DataView)) {\n    if (!(a instanceof ArrayBuffer) || !(b instanceof ArrayBuffer))\n      return undefined;\n\n    try {\n      dataViewA = new DataView(a);\n      dataViewB = new DataView(b);\n    } catch {\n      return undefined;\n    }\n  }\n\n  // Buffers are not equal when they do not have the same byte length\n  if (dataViewA.byteLength !== dataViewB.byteLength) return false;\n\n  // Check if every byte value is equal to each other\n  for (let i = 0; i < dataViewA.byteLength; i++) {\n    if (dataViewA.getUint8(i) !== dataViewB.getUint8(i)) return false;\n  }\n\n  return true;\n}\n\nexport function sparseArrayEquality(\n  a: unknown,\n  b: unknown,\n  customTesters: Array<any> = []\n): boolean | undefined {\n  if (!Array.isArray(a) || !Array.isArray(b)) return undefined;\n\n  // A sparse array [, , 1] will have keys [\"2\"] whereas [undefined, undefined, 1] will have keys [\"0\", \"1\", \"2\"]\n  const aKeys = Object.keys(a);\n  const bKeys = Object.keys(b);\n  const filteredCustomTesters = customTesters.filter(\n    (t) => t !== sparseArrayEquality\n  );\n  return equals(a, b, filteredCustomTesters, true) && equals(aKeys, bKeys);\n}\n\nexport function generateToBeMessage(\n  deepEqualityName: string,\n  expected = \"#{this}\",\n  actual = \"#{exp}\"\n) {\n  const toBeMessage = `expected ${expected} to be ${actual} // Object.is equality`;\n\n  if ([\"toStrictEqual\", \"toEqual\"].includes(deepEqualityName))\n    return `${toBeMessage}\\n\\nIf it should pass with deep equality, replace \"toBe\" with \"${deepEqualityName}\"\\n\\nExpected: ${expected}\\nReceived: serializes to the same string\\n`;\n\n  return toBeMessage;\n}\n\nexport function pluralize(word: string, count: number): string {\n  return `${count} ${word}${count === 1 ? \"\" : \"s\"}`;\n}\n"
  },
  {
    "path": "llrt_core/src/modules/js/@llrt/expect/stringify.ts",
    "content": "/*\nMIT License\n\nCopyright (c) 2021-Present Anthony Fu <https://github.com/antfu>\nCopyright (c) 2021-Present Matias Capeletto <https://github.com/patak-dev>\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// Extracted and modified from Vitest:  https://github.com/vitest-dev/vitest/blob/0f86ff98975a80191d6215b0d30ff6cd9f8388d3/packages/utils/src/stringify.ts\n\nimport type { PrettyFormatOptions } from \"pretty-format\";\nimport {\n  format as prettyFormat,\n  plugins as prettyFormatPlugins,\n} from \"pretty-format\";\n\nconst {\n  AsymmetricMatcher,\n  DOMCollection,\n  DOMElement,\n  Immutable,\n  ReactElement,\n  ReactTestComponent,\n} = prettyFormatPlugins;\n\nconst PLUGINS = [\n  ReactTestComponent,\n  ReactElement,\n  DOMElement,\n  DOMCollection,\n  Immutable,\n  AsymmetricMatcher,\n];\n\nexport function stringify(\n  object: unknown,\n  maxDepth = 10,\n  { maxLength, ...options }: PrettyFormatOptions & { maxLength?: number } = {}\n): string {\n  const MAX_LENGTH = maxLength ?? 10000;\n  let result;\n\n  try {\n    result = prettyFormat(object, {\n      maxDepth,\n      escapeString: false,\n      // min: true,\n      plugins: PLUGINS,\n      ...options,\n    });\n  } catch {\n    result = prettyFormat(object, {\n      callToJSON: false,\n      maxDepth,\n      escapeString: false,\n      // min: true,\n      plugins: PLUGINS,\n      ...options,\n    });\n  }\n\n  return result.length >= MAX_LENGTH && maxDepth > 1\n    ? stringify(object, Math.floor(maxDepth / 2))\n    : result;\n}\n"
  },
  {
    "path": "llrt_core/src/modules/js/@llrt/test/CircularBuffer.ts",
    "content": "export default class CircularBuffer {\n  private buffer: Buffer;\n  private maxSize: number;\n  private currentPosition: number;\n  private isFull: boolean;\n  private atCapacity: boolean;\n\n  constructor(maxSize: number, initialSize: number = maxSize / 8) {\n    this.maxSize = Math.ceil(maxSize / 8) * 8;\n    const adjustedInitialSize = Math.ceil(initialSize / 8) * 8;\n    this.buffer = Buffer.alloc(adjustedInitialSize);\n    this.currentPosition = 0;\n    this.isFull = false;\n    this.atCapacity = false;\n  }\n\n  private grow(targetSize: number): void {\n    const newSize = Math.min(\n      Math.pow(2, Math.ceil(Math.log2(targetSize))),\n      this.maxSize\n    );\n\n    if (newSize === this.maxSize) {\n      this.atCapacity = true;\n    }\n\n    const newBuffer = Buffer.alloc(newSize);\n\n    newBuffer.set(this.getContent());\n    this.buffer = newBuffer;\n    this.isFull = false;\n  }\n\n  clear() {\n    this.currentPosition = 0;\n    this.isFull = false;\n  }\n\n  append(data: Uint8Array): void {\n    //if data is larger than maxSize, just keep the last maxSize bytes\n    if (data.length >= this.maxSize) {\n      //we are not at max size yet\n      if (!this.atCapacity) {\n        this.buffer = Buffer.alloc(this.maxSize);\n      }\n      //copy over last bytes to fill buffer\n      this.buffer.set(data.slice(-this.maxSize));\n      this.currentPosition = 0;\n      this.isFull = true;\n      return;\n    }\n\n    if (\n      !this.atCapacity &&\n      this.currentPosition + data.length > this.buffer.length\n    ) {\n      this.grow(this.currentPosition + data.length);\n    }\n\n    //wrap around\n    if (this.currentPosition + data.length >= this.buffer.length) {\n      const firstPart = this.buffer.length - this.currentPosition;\n      this.buffer.set(data.subarray(0, firstPart), this.currentPosition);\n      this.buffer.set(data.subarray(firstPart));\n      this.currentPosition = data.length - firstPart;\n      this.isFull = true;\n    } else {\n      this.buffer.set(data, this.currentPosition);\n      this.currentPosition += data.length;\n    }\n  }\n\n  getContent(): Buffer {\n    if (!this.isFull) {\n      return this.buffer.subarray(0, this.currentPosition);\n    }\n\n    return Buffer.concat([\n      this.buffer.subarray(this.currentPosition),\n      this.buffer.subarray(0, this.currentPosition),\n    ]);\n  }\n}\n"
  },
  {
    "path": "llrt_core/src/modules/js/@llrt/test/Color.ts",
    "content": "const NAMES = [\n  \"black\",\n  \"red\",\n  \"green\",\n  \"yellow\",\n  \"blue\",\n  \"magenta\",\n  \"cyan\",\n  \"white\",\n  \"default\",\n] as const;\n\ntype BgType<T extends string> = T extends `${infer A}${infer B}`\n  ? `bg${Uppercase<A>}${B}`\n  : T;\n\ntype BrightType<T extends string> = `${T}Bright`;\n\ntype ColorNames = {\n  [k in (typeof NAMES)[number]]: number;\n} & {\n  [k in BgType<(typeof NAMES)[number]>]: number;\n} & {\n  [k in BrightType<(typeof NAMES)[number]>]: number;\n} & {\n  [k in BgType<BrightType<(typeof NAMES)[number]>>]: number;\n};\n\ntype Options = {\n  color?: number;\n  bgColor?: number;\n  bold?: boolean;\n  dim?: boolean;\n  italic?: boolean;\n  underline?: boolean;\n  strikethrough?: boolean;\n} & Partial<ColorNames>;\n\nclass Color {\n  private static CODES = (() => {\n    return NAMES.reduce<Record<string, number>>(\n      (acc, name: string, i: number) => {\n        let code = i + 30;\n\n        const COLOR = Color as any;\n\n        const bgName = `bg${name[0].toUpperCase()}${name.substring(1)}`;\n        const brightName = `${name}Bright`;\n        const bgBrightName = `${bgName}Bright`;\n        acc[name] = code;\n        acc[brightName] = code + 60;\n        acc[bgName] = code + 10;\n        acc[bgBrightName] = code + 70;\n\n        COLOR[name] = Color.colorizer(code);\n        COLOR[brightName] = Color.colorizer(code + 60);\n\n        COLOR[bgName] = Color.colorizer(0, {\n          bgColor: code + 10,\n        });\n        COLOR[bgBrightName] = Color.colorizer(0, {\n          bgColor: code + 70,\n        });\n\n        return acc;\n      },\n      {}\n    ) as ColorNames;\n  })();\n\n  static RESET: string = \"\\x1b[0m\";\n\n  static colorizer(\n    color: number,\n    options: Options = {},\n    option?: keyof Options\n  ) {\n    options.color = color;\n    if (option) {\n      const colorOption = Color.CODES && (Color.CODES as any)[option];\n      if (colorOption) {\n        if (option.startsWith(\"bg\")) {\n          options.bgColor = colorOption;\n        } else {\n          options.color = colorOption;\n        }\n      } else {\n        if (!options[option]) {\n          (options as any)[option] = true;\n        }\n      }\n    }\n\n    return new Proxy(() => {}, {\n      get(target: unknown, prop: any, receiver: any) {\n        return Color.colorizer(color, options, prop);\n      },\n      apply(target: unknown, thisArg: any, args: string[]) {\n        let colorCode = `${options.color}`;\n        let modes: number[] = [];\n\n        if (options.bgColor) {\n          colorCode = `${colorCode};${options.bgColor}`;\n        }\n\n        if (options.bold) {\n          modes.push(1);\n        }\n        if (options.dim) {\n          modes.push(2);\n        }\n        if (options.italic) {\n          modes.push(3);\n        }\n        if (options.underline) {\n          modes.push(4);\n        }\n        if (options.strikethrough) {\n          modes.push(9);\n        }\n\n        if (modes.length == 1) {\n          colorCode = `${modes[0]};${colorCode}`;\n          modes = [];\n        }\n\n        return `\\x1b[${colorCode}m${modes.map((m) => `\\x1b[${m}m`).join(\"\")}${args.join(\n          \" \"\n        )}${Color.RESET}`;\n      },\n    });\n  }\n}\n\ntype ColorizerReturnType = ((text: string) => string) & {\n  [k in keyof (ColorNames & Required<Options>)]: ColorizerReturnType;\n};\n\ntype ClassType = typeof Color & {\n  [k in keyof ColorNames]: ColorizerReturnType;\n};\n\nexport default Color as ClassType;\n"
  },
  {
    "path": "llrt_core/src/modules/js/@llrt/test/SocketClient.ts",
    "content": "import { Socket } from \"node:net\";\nimport { EventEmitter } from \"node:events\";\n\nclass SocketClient extends EventEmitter {\n  private host: string;\n  private port: number;\n  private socket: Socket;\n  private queue: Array<{\n    data: string;\n    resolve: (value: Buffer) => void;\n    reject: (reason?: any) => void;\n  }>;\n  private currentlySending: boolean;\n  private currentResolve?: (value: Buffer) => void;\n\n  constructor(host: string, port: number) {\n    super();\n    this.host = host;\n    this.port = port;\n    this.socket = new Socket();\n    this.queue = [];\n    this.currentlySending = false;\n\n    this.socket.on(\"data\", (data) => this.handleResponse(data));\n\n    this.socket.on(\"close\", () => {\n      return this.emit(\"close\");\n    });\n  }\n\n  public async connect(): Promise<void> {\n    return new Promise((resolve, reject) => {\n      const errorListener = (err: Error) => reject(err);\n      this.socket.on(\"error\", errorListener);\n      this.socket.connect(this.port, this.host, () => {\n        this.socket.off(\"error\", errorListener);\n        this.socket.on(\"error\", (err) => this.emit(\"error\", err));\n        resolve();\n      });\n    });\n  }\n\n  public async send(data: string): Promise<Buffer> {\n    return new Promise<Buffer>((resolve, reject) => {\n      this.queue.push({ data, resolve, reject });\n      this.processQueue();\n    });\n  }\n\n  private async processQueue(): Promise<void> {\n    if (this.currentlySending || this.queue.length === 0) return;\n\n    const { data, resolve, reject } = this.queue.shift()!;\n    this.currentlySending = true;\n\n    try {\n      this.currentResolve = resolve;\n      await this.sendData(data);\n    } catch (err) {\n      reject(err);\n      this.currentlySending = false;\n      this.processQueue();\n    }\n  }\n\n  private async sendData(data: string): Promise<void> {\n    return new Promise((resolve, reject) => {\n      this.socket.write(data, (err) => {\n        if (err) {\n          return reject(err);\n        }\n        resolve();\n      });\n    });\n  }\n\n  private handleResponse(data: Buffer): void {\n    if (this.currentResolve) {\n      this.currentResolve(data);\n      this.currentlySending = false;\n      this.processQueue();\n    }\n  }\n\n  async close(): Promise<void> {\n    return new Promise((resolve) => {\n      this.socket.end(() => {\n        this.socket.destroy();\n        resolve();\n      });\n    });\n  }\n}\n\nexport default SocketClient;\n"
  },
  {
    "path": "llrt_core/src/modules/js/@llrt/test/index.ts",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nimport net from \"node:net\";\nimport os from \"node:os\";\nimport { spawn, ChildProcess } from \"node:child_process\";\nimport path from \"node:path\";\nimport { SocketReqMsg } from \"./shared\";\nimport { platform } from \"node:os\";\nconst IS_WINDOWS = platform() === \"win32\";\nimport CircularBuffer from \"./CircularBuffer\";\n// @ts-ignore\nimport { dimensions } from \"llrt:util\";\n\ntype TestOptions = {\n  workerCount?: number;\n};\n\ntype TestProps = {\n  success: boolean;\n  started: number;\n  ended: number;\n};\n\ntype TestResult = TestProps & {\n  desc: string;\n  error: Error | null;\n};\n\ntype SuiteResult = TestProps & {\n  desc: string;\n  tests: TestResult[];\n  children: SuiteResult[];\n  parent: SuiteResult | null;\n};\n\ntype RootSuite = TestProps & {\n  results: SuiteResult[];\n  name: string;\n  printed: boolean;\n};\n\ntype WorkerData = {\n  writeInProgress: boolean;\n  stdOutBuffer: CircularBuffer;\n  stdErrBuffer: CircularBuffer;\n  completed: boolean;\n  childProc?: ChildProcess;\n  lastUpdate: number;\n  success: boolean;\n  connectionTimeout: Timeout | null;\n  currentTest: TestResult | null;\n  result: SuiteResult | null;\n  file: string;\n  currentPath: string[];\n  currentTimeout: number;\n};\n\nclass Color {\n  private static colorizer =\n    (\n      color: number | null,\n      bgColor: number | null = null,\n      style: number | null = null\n    ) =>\n    (text: string) =>\n      `\\x1b[${color || bgColor || style}m${text}${Color.RESET}`;\n\n  static GREEN = Color.colorizer(32);\n  static RED = Color.colorizer(31);\n  static GREEN_BACKGROUND = Color.colorizer(null, 42);\n  static RED_BACKGROUND = Color.colorizer(null, 41);\n  static DIM = Color.colorizer(null, null, 2);\n  static BOLD = Color.colorizer(null, null, 1);\n  static CYAN_BOLD = Color.colorizer(36, null, 1);\n  static RESET = \"\\x1b[0m\";\n}\n\ntype TestFailure = {\n  error: any;\n  desc: string[];\n  stdErr: string;\n  stdOut: string;\n};\n\nclass TestServer {\n  private static UPDATE_FPS = 15;\n  private static UPDATE_INTERVAL_MS = 1000 / TestServer.UPDATE_FPS;\n  private static DEFAULT_TIMEOUT_MS =\n    parseInt((process.env as any).TEST_TIMEOUT) || 5000;\n  private static DEFAULT_PROGRESS_BAR_WIDTH = 24;\n  private static SPINNER = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\n  private static TESTING_TEXT = \" Testing \";\n  private static CHECKMARK = \"\\u2714\";\n  private static CROSS = \"\\u2718\";\n  static ERROR_CODE_SOCKET_ERROR = 1;\n  static ERROR_CODE_SOCKET_WRITE_ERROR = 2;\n  static ERROR_CODE_PROCESS_ERROR = 4;\n  static ERROR_CODE_HANDLE_DATA = 8;\n\n  private server: net.Server | null = null;\n  private workerCount: number;\n  private workerIdBySocket: Map<net.Socket, number> = new Map();\n  private testFiles: string[];\n  private testFileNames: string[];\n  private fileQueue: string[];\n  private filesFailed: Map<string, TestFailure[]>;\n  private filesCompleted: Set<string>;\n  private completedWorkers: number = 0;\n  private workerData: Record<number, WorkerData> = {};\n  private workerDataFileInProgress: Map<string, WorkerData> = new Map();\n  private results: Map<string, RootSuite> = new Map();\n  private totalTests: number = 0;\n  private totalSuccess: number = 0;\n  private totalSkipped: number = 0;\n  private totalFailed: number = 0;\n  private totalOnly: number = 0;\n  private lastUpdate = 0;\n  private updateInterval: Timeout | null = null;\n  private spinnerFrameIndex = 0;\n  private started = 0;\n  private shutdownPending = false;\n  private nextWorkerId = 0;\n  private activeWorkers = 0;\n  private printFinalResults = false;\n\n  constructor(\n    testFiles: string[],\n    { workerCount = os.availableParallelism() }: TestOptions = {}\n  ) {\n    this.fileQueue = [...testFiles];\n    this.testFiles = [...testFiles];\n    this.testFileNames = testFiles.map((file) => path.basename(file));\n    this.filesFailed = new Map();\n    this.filesCompleted = new Set();\n    this.workerCount = Math.min(workerCount, testFiles.length);\n  }\n\n  public async start() {\n    if (this.testFiles.length === 0) {\n      this.printResults();\n      this.shutdown();\n      return;\n    }\n    this.started = performance.now();\n    const server = net.createServer((socket) =>\n      this.handleSocketConnected(socket)\n    );\n\n    this.server = server;\n\n    await new Promise<void>((resolve) => {\n      server.listen(resolve);\n    });\n\n    this.spawnWorkers();\n    this.updateInterval = setInterval(() => {\n      this.tick();\n    }, TestServer.UPDATE_INTERVAL_MS);\n  }\n\n  handleSocketConnected(socket: net.Socket) {\n    socket.on(\"data\", (data: Buffer) => {\n      let result;\n      try {\n        result = this.handleData(socket, data);\n      } catch (e: any) {\n        this.handleError(TestServer.ERROR_CODE_HANDLE_DATA, e);\n        return;\n      }\n      const { response, workerId } = result;\n      if (workerId === undefined) {\n        throw new Error(\"Could not determine workerId from socket or message\");\n      }\n      const workerData = this.workerData[workerId];\n      workerData.writeInProgress = true;\n      socket.write(JSON.stringify(response), (err) => {\n        workerData.writeInProgress = false;\n        if (err) {\n          return this.handleError(\n            TestServer.ERROR_CODE_SOCKET_WRITE_ERROR,\n            err,\n            {\n              socket,\n            }\n          );\n        }\n        if (this.shutdownPending) {\n          this.shutdown();\n        }\n      });\n    });\n    socket.on(\"error\", (error) => {\n      const workerId = this.workerIdBySocket.get(socket);\n      if (!workerId || !this.workerData[workerId].completed) {\n        if (workerId) {\n          const workerData = this.workerData[workerId];\n          const stdErr = workerData.stdErrBuffer.getContent().toString();\n          const stdOut = workerData.stdOutBuffer.getContent().toString();\n          let errorOutput = Color.RED_BACKGROUND(Color.BOLD(\"Worker Error:\\n\"));\n\n          if (stdErr) {\n            errorOutput += Color.RED(`\\nStd Err:\\n${stdErr}`);\n          }\n          if (stdOut) {\n            errorOutput += Color.RED(`\\nStd Out:\\n${stdOut}`);\n          }\n          console.error(errorOutput);\n        }\n        this.handleError(TestServer.ERROR_CODE_SOCKET_ERROR, error, {\n          socket,\n        });\n      }\n    });\n  }\n\n  spawnWorkers() {\n    while (this.activeWorkers < this.workerCount && this.fileQueue.length > 0) {\n      const file = this.fileQueue.shift()!;\n      const workerId = this.nextWorkerId++;\n\n      this.workerData[workerId] = {\n        writeInProgress: false,\n        currentTest: null,\n        success: true,\n        completed: false,\n        result: null,\n        file: file,\n        currentTimeout: TestServer.DEFAULT_TIMEOUT_MS,\n        lastUpdate: Date.now(),\n        currentPath: [],\n        connectionTimeout: null,\n        stdOutBuffer: new CircularBuffer(1024, 64),\n        stdErrBuffer: new CircularBuffer(1024, 64),\n      };\n\n      this.results.set(file, {\n        results: [],\n        name: path.basename(file),\n        success: true,\n        started: 0,\n        ended: 0,\n        printed: false,\n      });\n\n      this.workerDataFileInProgress.set(file, this.workerData[workerId]);\n      this.spawnWorker(workerId, file);\n      this.activeWorkers++;\n    }\n  }\n\n  private spawnWorker(id: number, file: string) {\n    const workerData = this.workerData[id];\n    const stdOutBuffer = workerData.stdOutBuffer;\n    const stdErrBuffer = workerData.stdErrBuffer;\n\n    let env: any = {\n      ...process.env,\n      __LLRT_TEST_SERVER_PORT: (this.server?.address() as any).port,\n      __LLRT_TEST_WORKER_ID: id.toString(),\n      __LLRT_TEST_FILE: file,\n    };\n    delete env.LLRT_LOG;\n    const proc = spawn(\n      process.argv0,\n      [\"-e\", `import(\"llrt:test/worker\").catch(console.error)`],\n      {\n        env,\n      }\n    );\n    proc.stderr.on(\"data\", (data) => {\n      stdErrBuffer.append(data);\n    });\n    proc.stdout.on(\"data\", (data) => {\n      stdOutBuffer.append(data);\n    });\n    proc.on(\"error\", (error) => {\n      this.handleError(TestServer.ERROR_CODE_PROCESS_ERROR, error, {\n        id,\n        ended: performance.now(),\n      });\n    });\n    proc.on(\"exit\", (code) => {\n      if (code != 0) {\n        this.handleError(\n          TestServer.ERROR_CODE_PROCESS_ERROR,\n          new Error(\"Worker process exited with a non-zero exit code\"),\n          {\n            id,\n            ended: performance.now(),\n          }\n        );\n        this.handleWorkerCompleted(id);\n      }\n    });\n    workerData.connectionTimeout = setTimeout(() => {\n      try {\n        proc.kill();\n      } catch {}\n    }, 5000);\n    workerData.childProc = proc;\n  }\n\n  handleError(code: number, error: Error, details?: any) {\n    switch (code) {\n      case TestServer.ERROR_CODE_HANDLE_DATA: {\n        console.error(`Error handling data,`, error);\n        process.exit(1);\n      }\n      case TestServer.ERROR_CODE_SOCKET_WRITE_ERROR:\n      case TestServer.ERROR_CODE_SOCKET_ERROR: {\n        console.error(`Socket error,`, error);\n        process.exit(1);\n      }\n      case TestServer.ERROR_CODE_PROCESS_ERROR: {\n        const { id: workerId, ended } = details;\n        this.handleTestError(workerId, error, ended);\n        break;\n      }\n    }\n  }\n\n  handleData(\n    socket: net.Socket,\n    data: Buffer\n  ): { response: object | null; workerId: number } {\n    const message = JSON.parse(data as any) as SocketReqMsg;\n    const { type } = message;\n\n    let workerId = this.workerIdBySocket.get(socket);\n    if (workerId === undefined && \"workerId\" in message) {\n      workerId = (message as any).workerId;\n    }\n\n    if (workerId !== undefined) {\n      this.workerData[workerId].lastUpdate = Date.now();\n    }\n\n    switch (type) {\n      case \"ready\": {\n        workerId = message.workerId;\n        this.workerIdBySocket.set(socket, workerId);\n        clearTimeout(this.workerData[workerId].connectionTimeout!);\n        break;\n      }\n      case \"module\": {\n        const { testCount, skipCount, onlyCount } = message;\n        this.totalTests += testCount;\n        this.totalSkipped += skipCount;\n        this.totalOnly += onlyCount;\n        break;\n      }\n      case \"start\": {\n        const { desc: describe, isSuite, started, timeout } = message;\n        const workerData = this.workerData[workerId];\n\n        workerData.currentTimeout = timeout || TestServer.DEFAULT_TIMEOUT_MS;\n\n        if (isSuite) {\n          const result: SuiteResult = {\n            desc: describe,\n            tests: [],\n            success: true,\n            children: [],\n            parent: workerData.result,\n            started: 0,\n            ended: 0,\n          };\n          if (!result.parent) {\n            const suite = this.results.get(workerData.file!)!;\n            suite.started = started;\n            suite.results.push(result);\n          } else {\n            workerData.result!.children.push(result);\n          }\n          workerData.result = result;\n        } else {\n          const test: TestResult = {\n            desc: describe,\n            success: true,\n            started,\n            ended: 0,\n            error: null,\n          };\n          workerData.result!.tests.push(test);\n          workerData.currentTest = test;\n        }\n        workerData.currentPath.push(describe);\n\n        break;\n      }\n      case \"end\": {\n        const { isSuite, ended, started } = message;\n        const workerData = this.workerData[workerId]!;\n        const currentResult = workerData.result!;\n        //if we're not in a test\n        workerData.lastUpdate = 0;\n        if (isSuite) {\n          currentResult.ended = ended;\n          currentResult.started = started;\n          workerData.result = currentResult.parent;\n          if (!workerData.result) {\n            const suite = this.results.get(workerData.file!)!;\n            suite.ended = ended;\n            suite.started = started;\n            if (workerData.success) {\n              this.filesCompleted.add(workerData.file!);\n            }\n          }\n        } else {\n          this.totalSuccess++;\n          const test = workerData.currentTest!;\n          test.ended = ended;\n          test.success = true;\n        }\n\n        workerData.currentPath.pop();\n\n        break;\n      }\n      case \"error\": {\n        const { error, ended, workerId: msgWorkerId } = message;\n        const effectiveWorkerId = workerId ?? msgWorkerId;\n        if (effectiveWorkerId !== undefined) {\n          this.handleTestError(effectiveWorkerId, error, ended);\n        } else {\n          console.error(\"Error from unknown worker:\", error);\n        }\n        break;\n      }\n      case \"completed\": {\n        this.handleWorkerCompleted(workerId!);\n        break;\n      }\n      default:\n        throw new Error(\"Unknown type\");\n    }\n    return { response: null, workerId: workerId! };\n  }\n  private handleWorkerCompleted(workerId: number) {\n    const workerData = this.workerData[workerId];\n    if (workerData.completed) {\n      return;\n    }\n    workerData.completed = true;\n    this.completedWorkers++;\n    this.activeWorkers--;\n\n    const shutdownOrPrint = () => {\n      if (\n        this.completedWorkers == this.testFiles.length &&\n        !this.printFinalResults\n      ) {\n        this.printFinalResults = true;\n        clearInterval(this.updateInterval!);\n        this.tick();\n        this.printResults();\n        if (!workerData.writeInProgress) {\n          this.shutdown();\n        } else {\n          this.shutdownPending = true;\n        }\n      }\n    };\n\n    if (workerData.childProc) {\n      const exitTimeout = setTimeout(() => {\n        const error = new Error(\n          \"Test did not exit within 1s. It does not properly clean up created resources (servers, timeouts etc)\"\n        );\n        this.handleTestError(workerId, error, performance.now());\n        try {\n          workerData.childProc?.kill();\n        } catch {}\n      }, 1000);\n\n      workerData.childProc?.once(\"exit\", () => {\n        clearTimeout(exitTimeout);\n        shutdownOrPrint();\n      });\n    } else {\n      shutdownOrPrint();\n    }\n    this.spawnWorkers();\n  }\n\n  shutdown() {\n    this.shutdownPending = false;\n    this.server?.close(() => {\n      //XXX force exit on windows\n      if (IS_WINDOWS) {\n        process.exit(0);\n      }\n    });\n  }\n  handleTestError(workerId: number, error: any, ended: number) {\n    const workerData = this.workerData[workerId];\n    const test = workerData.currentTest || {\n      desc: \"\",\n      success: false,\n      started: 0,\n      ended: 0,\n      error,\n    };\n    workerData.success = false;\n    const results = this.results.get(workerData.file!);\n    if (results) {\n      results.success = false;\n    }\n    const testFailures = this.filesFailed.get(workerData.file!) || [];\n    testFailures.push({\n      desc: workerData.currentPath.slice(1),\n      error,\n      stdErr: workerData.stdErrBuffer.getContent().toString(),\n      stdOut: workerData.stdOutBuffer.getContent().toString(),\n    });\n    workerData.stdErrBuffer.clear();\n    workerData.stdOutBuffer.clear();\n    this.filesFailed.set(workerData.file!, testFailures);\n    this.totalFailed++;\n    test.ended = ended;\n    test.error = error;\n    test.success = false;\n    workerData.currentPath.pop();\n  }\n\n  private tick() {\n    const now = Date.now();\n    const first = this.lastUpdate == 0;\n    if (now - this.lastUpdate > TestServer.UPDATE_INTERVAL_MS) {\n      this.spinnerFrameIndex =\n        (this.spinnerFrameIndex + 1) % TestServer.SPINNER.length;\n      this.lastUpdate = now;\n    }\n\n    //check for hanged tests\n    for (let id in this.workerData) {\n      const workerData = this.workerData[id];\n      if (\n        !workerData.completed &&\n        workerData.lastUpdate > 0 &&\n        now - workerData.lastUpdate >= workerData.currentTimeout\n      ) {\n        this.handleTestError(\n          id as any,\n          new Error(`Test timed out after ${workerData.currentTimeout}ms`),\n          performance.now()\n        );\n        try {\n          workerData.childProc?.kill();\n        } catch {}\n        workerData.childProc = undefined;\n        this.handleWorkerCompleted(parseInt(id));\n      }\n    }\n\n    let [terminalWidth] = dimensions();\n    let message = \"\";\n\n    if (!first) {\n      //clear last line\n      message = \"\\x1b[F\\x1b[2K\";\n    }\n\n    const spinnerFrame = TestServer.SPINNER[this.spinnerFrameIndex];\n\n    if (terminalWidth > 80) {\n      terminalWidth = 80;\n    }\n\n    const total = this.testFiles.length;\n    const progress = (this.filesCompleted.size + this.filesFailed.size) / total;\n\n    const progressText = `${this.totalSuccess}/${this.totalTests}`;\n\n    const progressbarWidth = Math.min(\n      TestServer.DEFAULT_PROGRESS_BAR_WIDTH,\n      Math.max(\n        10,\n        terminalWidth - (2 + progressText.length + 2) //[ + ] + spinner + spacing + progress text\n      )\n    );\n    let totalProgressBarWidth = progressbarWidth;\n    const showProgressBarDesc =\n      totalProgressBarWidth == TestServer.DEFAULT_PROGRESS_BAR_WIDTH;\n    if (showProgressBarDesc) {\n      totalProgressBarWidth += TestServer.TESTING_TEXT.length;\n    }\n    let isSuccess = false;\n    let isFailed = false;\n    let i = 0;\n    let suffix = \"\";\n    let overflow = false;\n\n    for (let file of this.testFiles) {\n      let results = this.results.get(file);\n      isSuccess = this.filesCompleted.has(file);\n      if (!isSuccess) {\n        isFailed = this.filesFailed.has(file);\n      }\n      if (results && (isSuccess || isFailed)) {\n        if (!results.printed) {\n          results.printed = true;\n          message += isSuccess\n            ? Color.GREEN(TestServer.CHECKMARK)\n            : Color.RED(TestServer.CROSS);\n          message += \" \";\n          message += results.name;\n          message += \"\\n\";\n        }\n        i++;\n        continue;\n      }\n\n      const inProgress = this.workerDataFileInProgress.has(file);\n      const filename = this.testFileNames[i];\n\n      if (\n        inProgress &&\n        totalProgressBarWidth + suffix.length + 4 < terminalWidth\n      ) {\n        if (\n          totalProgressBarWidth + suffix.length + filename.length + 4 <\n          terminalWidth\n        ) {\n          suffix += filename;\n          suffix += \", \";\n        } else {\n          overflow = true;\n          suffix += filename.slice(\n            0,\n            terminalWidth - (totalProgressBarWidth + suffix.length + 5)\n          );\n          suffix += \"...\";\n        }\n      }\n\n      i++;\n    }\n\n    if (!overflow) {\n      suffix = suffix.slice(0, -2);\n    }\n    const elapsed = Math.floor(progressbarWidth * progress);\n    const remaining = progressbarWidth - elapsed;\n\n    message += spinnerFrame;\n    if (showProgressBarDesc) {\n      message += Color.CYAN_BOLD(TestServer.TESTING_TEXT);\n    }\n    message += `[${\"=\".repeat(elapsed)}${\"-\".repeat(remaining)}]`;\n    message += progressText;\n    message += \": \";\n    message += Color.DIM(suffix);\n\n    console.log(message);\n  }\n  private printResults() {\n    const ended = performance.now();\n    let output = \"\";\n    for (let file of this.testFiles) {\n      const suite = this.results.get(file)!;\n\n      output += `${\n        suite.success\n          ? Color.GREEN_BACKGROUND(Color.BOLD(\" PASS \"))\n          : Color.RED_BACKGROUND(Color.BOLD(\" FAIL \"))\n      } ${suite.name} ${Color.DIM(TestServer.elapsed(suite))}\\n`;\n\n      for (let result of suite.results) {\n        output += this.printSuiteResult(result);\n      }\n      output += \"\\n\";\n    }\n\n    if (this.totalFailed == 0) {\n      output += Color.GREEN_BACKGROUND(\n        Color.BOLD(` ${TestServer.CHECKMARK} ALL PASS `)\n      );\n    } else {\n      output += Color.RED_BACKGROUND(\n        Color.BOLD(` ${TestServer.CHECKMARK} TESTS FAILED `)\n      );\n    }\n    output += ` ${Color.DIM(TestServer.elapsed({ started: this.started, ended }))}\\n`;\n    output += `${this.totalSuccess} passed, ${this.totalFailed} failed, ${this.totalSkipped} skipped, ${this.totalTests} tests\\n`;\n    console.log(output);\n    if (this.totalFailed > 0) {\n      output = \"\";\n      const sortedFilesFailed = new Map(\n        Array.from(this.filesFailed.entries()).sort(([keyA], [keyB]) =>\n          keyA.localeCompare(keyB)\n        )\n      );\n      for (let [file, testFailure] of sortedFilesFailed) {\n        output += `\\n${Color.RED_BACKGROUND(` ${file} `)}\\n`;\n\n        for (let failure of testFailure) {\n          output +=\n            failure.desc.map((d) => Color.BOLD(d)).join(\" > \") +\n            `\\n${this.formattedError(failure.error)}\\n`;\n          if (failure.stdOut) {\n            output += \"----- LAST STDOUT: -----\\n\" + failure.stdOut + \"\\n\";\n          }\n          if (failure.stdErr) {\n            output += \"----- LAST STDERR: -----\\n\" + failure.stdErr + \"\\n\";\n          }\n        }\n      }\n      process.exitCode = 1;\n      console.error(output);\n    }\n  }\n\n  private printSuiteResult(result: SuiteResult, depth = 0): string {\n    let output = \"\";\n    const indent = \"  \".repeat(depth);\n    for (let test of result.tests) {\n      const icon = test.success\n        ? Color.GREEN(TestServer.CHECKMARK)\n        : Color.RED(TestServer.CROSS);\n      output += `${indent}${icon} ${test.desc} ${Color.DIM(TestServer.elapsed(test))}\\n`;\n      if (test.error) {\n        output += this.formattedError(test.error) + \"\\n\";\n      }\n    }\n    const results = result.children;\n    for (let result of results) {\n      output += `${indent}${Color.BOLD(result.desc)} ${Color.DIM(TestServer.elapsed(result))}\\n`;\n      output += this.printSuiteResult(result, depth + 1);\n    }\n    return output;\n  }\n  private formattedError(error: Error, indent: string = \"\"): string {\n    let stack = error.stack || \"\";\n\n    if (indent && stack) {\n      stack = stack\n        .split(\"\\n\")\n        .map((line) => indent + line)\n        .join(\"\\n\");\n    }\n\n    return Color.RED(\n      `${indent}\\x1b[1m${error.name}:\\x1b[22m ${error.message}\\n${stack}`\n    );\n  }\n\n  static elapsed({\n    started,\n    ended,\n  }: {\n    started: number;\n    ended: number;\n  }): string {\n    return `${(ended - started).toFixed(3)}ms`;\n  }\n}\n\nconst testServer = new TestServer((globalThis as any).__testEntries, {\n  workerCount: undefined,\n});\nawait testServer.start();\n"
  },
  {
    "path": "llrt_core/src/modules/js/@llrt/test/shared.ts",
    "content": "export type SocketReqMsg =\n  | ReadyReqMsg\n  | ModuleReqMsg\n  | EndReqMsg\n  | StartReqMsg\n  | CompletedReqMsg\n  | ErrorReqMsg;\n\nexport type ReadyReqMsg = {\n  type: \"ready\";\n  workerId: number;\n};\n\nexport type ErrorReqMsg = {\n  type: \"error\";\n  error: any;\n  ended: number;\n  started: number;\n  workerId: number;\n};\n\nexport type ModuleReqMsg = {\n  type: \"module\";\n  testCount: number;\n  skipCount: number;\n  onlyCount: number;\n};\n\nexport type CompletedReqMsg = {\n  type: \"completed\";\n};\n\nexport type EndReqMsg = {\n  type: \"end\";\n  ended: number;\n  started: number;\n  isSuite: boolean;\n};\n\nexport type StartReqMsg = {\n  type: \"start\";\n  desc: string;\n  isSuite: boolean;\n  started: number;\n  timeout?: number;\n};\n\nexport type SocketResponseMap = {};\n\nexport type SocketRes<T extends SocketReqMsg> = T extends {\n  type: keyof SocketResponseMap;\n}\n  ? SocketResponseMap[T[\"type\"]]\n  : null;\n"
  },
  {
    "path": "llrt_core/src/modules/js/@llrt/test/worker.ts",
    "content": "import * as chai from \"chai\";\nimport { JestChaiExpect } from \"../expect/jest-expect\";\nimport { JestAsymmetricMatchers } from \"../expect/jest-asymmetric-matchers\";\nimport { SocketReqMsg, SocketResponseMap } from \"./shared\";\nimport SocketClient from \"./SocketClient\";\n\ntype Test = TestSettings & {\n  desc: string;\n  fn: (done?: (error?: any) => void) => Promise<void>;\n};\n\ntype TestSettings = {\n  only?: boolean;\n  skip?: boolean;\n  timeout?: number;\n};\n\ntype SuiteFunctionWithOptions = SuiteFunction & {\n  skip?: SuiteFunction;\n  only?: SuiteFunction;\n};\n\ntype SuiteFunction = (\n  desc: string,\n  fn: () => Promise<void>,\n  timeout?: number\n) => void;\n\ntype TestSuite = TestSettings &\n  TestSetup & {\n    tests?: Test[];\n    suites?: TestSuite[];\n    parent?: TestSuite;\n    containsOnly?: boolean;\n    desc: string;\n  };\n\ntype TestSetup = {\n  afterAll?: MaybeAsyncFunction[];\n  afterEach?: MaybeAsyncFunction[];\n  beforeAll?: MaybeAsyncFunction[];\n  beforeEach?: MaybeAsyncFunction[];\n};\n\ntype RootSuite = TestSettings &\n  TestSetup &\n  Required<Omit<TestSuite, \"parent\" | keyof TestSettings | keyof TestSetup>> & {\n    onlyCount: number;\n    testCount: number;\n    skipCount: number;\n    module: string;\n  };\n\ntype MaybeAsyncFunction = () => Promise<void> | void;\n\ntype MessageTypeMap = {\n  [K in SocketReqMsg[\"type\"]]: Extract<SocketReqMsg, { type: K }>;\n};\n\ntype MessagePayload<T extends SocketReqMsg[\"type\"]> = Omit<\n  MessageTypeMap[T],\n  \"type\"\n>;\n\ntype SocketReturnType<T> = T extends keyof SocketResponseMap\n  ? SocketResponseMap[T]\n  : null;\n\nclass TestAgent {\n  private static DEFAULT_TIMEOUT_MS =\n    parseInt((process.env as any).TEST_TIMEOUT) || 5000;\n\n  private static EMPTY_ARROW_FN_REGEX = /^(async)?\\s*\\(\\s*\\)\\s*=>/m;\n  private static EMPTY_FN_REGEX =\n    /^(async)?\\s*function\\s*[a-zA-Z0-9_-]*\\s*\\(\\s*\\)\\s*\\{/m;\n\n  private static EXPECT = (() => {\n    chai.use(JestChaiExpect);\n    chai.use(JestAsymmetricMatchers);\n    const expect = chai.expect as (value: any, message?: string) => any;\n    return Object.assign(expect, chai.expect);\n  })();\n\n  private workerId: number;\n  private client: SocketClient;\n  private rootSuite: RootSuite = TestAgent.createRootSuite();\n  private currentSuite!: TestSuite;\n  private currentSuites: TestSuite[] = [];\n  private suiteLoadPromises: (() => Promise<void>)[] = [];\n  private describe: SuiteFunctionWithOptions;\n  private testFunction: SuiteFunctionWithOptions;\n  private onlyCount: number = 0;\n\n  static createRootSuite(): RootSuite {\n    return {\n      tests: [],\n      suites: [],\n      containsOnly: false,\n      desc: \"root\",\n      testCount: 0,\n      skipCount: 0,\n      onlyCount: 0,\n      module: \"\",\n    };\n  }\n\n  constructor(workerId: number, serverPort: number) {\n    this.workerId = workerId;\n    this.client = new SocketClient(\"localhost\", serverPort);\n\n    this.client.on(\"error\", (err) => {\n      console.error(\"Worker Client Socket Error:\", workerId, err);\n    });\n\n    const testFunction = this.createTestFunction();\n    testFunction.only = this.createTestFunction({ only: true });\n    testFunction.skip = this.createTestFunction({ skip: true });\n\n    const describe = this.createDescribe();\n    describe.only = this.createDescribe({ only: true });\n    describe.skip = this.createDescribe({ skip: true });\n\n    this.describe = describe;\n    this.testFunction = testFunction;\n  }\n\n  private createDescribe({\n    only = false,\n    skip = false,\n  }: TestSettings = {}): SuiteFunctionWithOptions {\n    return (desc: string, fn: () => Promise<void>, timeout?: number) => {\n      this.suiteLoadPromises.push(async () => {\n        let parent: TestSuite = this.currentSuites.shift() ?? this.rootSuite;\n        this.currentSuite = {\n          tests: [],\n          suites: [],\n          parent,\n          only: only || parent.only,\n          skip,\n          desc,\n          timeout: timeout || parent.timeout,\n        };\n        parent.suites!!.push(this.currentSuite);\n        let beforeLength = this.suiteLoadPromises.length;\n\n        await fn();\n        let afterLength = this.suiteLoadPromises.length;\n\n        let items = this.suiteLoadPromises.splice(\n          beforeLength,\n          afterLength - beforeLength\n        );\n        if (items.length) {\n          this.suiteLoadPromises.unshift(...items);\n          let subSuites = new Array(items.length).fill(this.currentSuite);\n          this.currentSuites.unshift(...subSuites);\n        }\n      });\n    };\n  }\n\n  private createTestFunction({\n    only = false,\n    skip = false,\n  }: TestSettings = {}): SuiteFunctionWithOptions {\n    return (desc: string, fn: () => Promise<void>, timeout?: number) => {\n      let suite: TestSuite = this.currentSuite;\n      this.rootSuite.testCount++;\n      if (skip || suite?.skip) {\n        this.rootSuite.skipCount++;\n        return;\n      }\n      let onlyValue = only || suite.only;\n      if (onlyValue) {\n        this.onlyCount++;\n        suite.containsOnly = true;\n        let p = suite.parent;\n\n        while (p) {\n          p.containsOnly = true;\n          p = p?.parent;\n        }\n      }\n\n      const test = {\n        desc,\n        fn,\n        only: onlyValue,\n        timeout: timeout || suite.timeout,\n      };\n      suite.tests?.push(test);\n    };\n  }\n\n  private async runHook(\n    testSuite: TestSuite,\n    hook: keyof TestSetup,\n    timeout?: number\n  ) {\n    const hooks: MaybeAsyncFunction[] = [];\n    const walkParents = hook === \"beforeEach\" || hook === \"afterEach\";\n    let current: TestSuite | undefined = testSuite;\n    while (current) {\n      if (current[hook]) {\n        hooks.unshift(...current[hook]!);\n      }\n      current = walkParents ? current.parent : undefined;\n    }\n    for (const fn of hooks) {\n      await this.executeAsyncOrCallbackFn(fn, timeout);\n    }\n  }\n\n  private async executeAsyncOrCallbackFn(\n    fn: Function,\n    timeout: number = TestAgent.DEFAULT_TIMEOUT_MS\n  ) {\n    const fnBody = fn.toString();\n    const usesArgument = !(\n      TestAgent.EMPTY_ARROW_FN_REGEX.test(fnBody) ||\n      TestAgent.EMPTY_FN_REGEX.test(fnBody)\n    );\n    TestAgent.EMPTY_ARROW_FN_REGEX.lastIndex = -1;\n    TestAgent.EMPTY_FN_REGEX.lastIndex = -1;\n\n    const timeoutMessage = `Timeout after ${timeout}ms`;\n\n    if (usesArgument) {\n      await new Promise<void>((resolve, reject) => {\n        const timeoutId = setTimeout(() => reject(timeoutMessage), timeout);\n        const resolveWrapper = (error: any) => {\n          clearTimeout(timeoutId);\n          if (error) {\n            return reject(error);\n          }\n          resolve();\n        };\n        Promise.resolve(fn(resolveWrapper)).catch(reject);\n      });\n    } else {\n      let timeoutId: Timeout;\n      const timeoutPromise = new Promise<void>((_, reject) => {\n        timeoutId = setTimeout(() => reject(timeoutMessage), timeout);\n      });\n      try {\n        await Promise.race([Promise.resolve(fn()), timeoutPromise]);\n      } catch (e) {\n        clearTimeout(timeoutId!);\n        throw e;\n      }\n      clearTimeout(timeoutId!);\n    }\n  }\n\n  private sendWorkerId() {\n    return this.sendMessage(\"ready\", {\n      workerId: this.workerId,\n    });\n  }\n\n  private async complete() {\n    await this.sendMessage(\"completed\");\n    await this.client.close();\n  }\n\n  private async sendMessage<T extends SocketReqMsg[\"type\"]>(\n    type: T,\n    ...message: MessagePayload<T> extends Record<string, never>\n      ? []\n      : [MessagePayload<T>]\n  ): Promise<SocketReturnType<T>> {\n    const [messageData] = message!;\n\n    if (type == \"error\") {\n      const errorData = messageData as MessagePayload<\"error\">;\n\n      if (typeof errorData.error === \"string\") {\n        errorData.error = {\n          message: errorData.error,\n          name: \"Error\",\n        };\n      } else {\n        errorData.error = {\n          message: errorData.error.message,\n          stack: errorData.error.stack,\n          name: errorData.error.name,\n        };\n      }\n    }\n\n    const data = JSON.stringify({\n      type,\n      ...messageData,\n    });\n    const response = (await this.client.send(data)) as any;\n    return JSON.parse(response) as SocketReturnType<T>;\n  }\n\n  private async runTests(testSuite: TestSuite, tests: Test[] = []) {\n    for (const test of tests) {\n      if (test.skip || (this.onlyCount > 0 && !test.only)) {\n        continue;\n      }\n\n      let started = performance.now();\n\n      try {\n        await this.sendMessage(\"start\", {\n          started,\n          desc: test.desc,\n          isSuite: false,\n          timeout: test.timeout,\n        });\n\n        await this.runHook(testSuite, \"beforeEach\");\n\n        started = performance.now();\n\n        await this.executeAsyncOrCallbackFn(test.fn, test.timeout);\n\n        const end = performance.now();\n\n        await this.runHook(testSuite, \"afterEach\");\n\n        await this.sendMessage(\"end\", {\n          ended: end,\n          started,\n          isSuite: false,\n        });\n      } catch (error: any) {\n        await this.sendMessage(\"error\", {\n          error,\n          started,\n          ended: performance.now(),\n          workerId: this.workerId,\n        });\n      }\n    }\n  }\n\n  public async start(entry: string): Promise<void> {\n    const connectAndSend = this.connect().then(() => this.sendWorkerId());\n\n    const global: any = globalThis;\n    const started = performance.now();\n\n    try {\n      const rootSuite = TestAgent.createRootSuite();\n      this.rootSuite = rootSuite;\n      this.onlyCount = 0;\n\n      this.currentSuite = this.rootSuite;\n      this.currentSuites = [];\n\n      let index = entry.lastIndexOf(\"/\");\n      if (index !== -1) {\n        rootSuite.module = entry.substring(index + 1);\n      } else {\n        rootSuite.module = entry;\n      }\n\n      global.it = this.testFunction;\n      global.test = this.testFunction;\n      global.describe = this.describe;\n      global.expect = TestAgent.EXPECT;\n\n      global.beforeEach = (cb: MaybeAsyncFunction) => {\n        (this.currentSuite.beforeEach ??= []).push(cb);\n      };\n\n      global.beforeAll = (cb: MaybeAsyncFunction) => {\n        (this.currentSuite.beforeAll ??= []).push(cb);\n      };\n\n      global.afterEach = (cb: MaybeAsyncFunction) => {\n        (this.currentSuite.afterEach ??= []).push(cb);\n      };\n\n      global.afterAll = (cb: MaybeAsyncFunction) => {\n        (this.currentSuite.afterAll ??= []).push(cb);\n      };\n\n      await import(entry);\n      await connectAndSend;\n\n      while (this.suiteLoadPromises.length > 0) {\n        const suitePromise = this.suiteLoadPromises.shift()!;\n        await suitePromise();\n      }\n\n      await this.sendMessage(\"module\", {\n        skipCount: rootSuite.skipCount,\n        testCount: rootSuite.testCount,\n        onlyCount: rootSuite.onlyCount,\n      });\n\n      await this.runRootSuite();\n\n      delete global.it;\n      delete global.expect;\n      delete global.test;\n      delete global.describe;\n      delete global.beforeEach;\n      delete global.beforeAll;\n      delete global.afterEach;\n      delete global.afterAll;\n    } catch (error) {\n      try {\n        await this.sendMessage(\"error\", {\n          error,\n          started,\n          ended: performance.now(),\n          workerId: this.workerId,\n        });\n      } catch (e) {\n        console.error(\"Error sending error message:\", e);\n        process.exit(1);\n      }\n    }\n\n    await this.complete();\n  }\n  async runSuite(suite: TestSuite, started: number) {\n    await this.runHook(suite, \"beforeAll\", suite.timeout);\n    await this.runTests(suite, suite.tests);\n    for (const child of suite.suites ?? []) {\n      if (\n        child.skip ||\n        (this.onlyCount > 0 && !child.only && !child.containsOnly)\n      ) {\n        continue;\n      }\n      const childStarted = performance.now();\n      await this.sendMessage(\"start\", {\n        desc: child.desc,\n        isSuite: true,\n        started: childStarted,\n        timeout: child.timeout,\n      });\n      try {\n        await this.runSuite(child, childStarted);\n        await this.sendMessage(\"end\", {\n          isSuite: true,\n          started: childStarted,\n          ended: performance.now(),\n        });\n      } catch (error: any) {\n        await this.sendMessage(\"error\", {\n          error,\n          started,\n          ended: performance.now(),\n          workerId: this.workerId,\n        });\n      }\n    }\n    await this.runHook(suite, \"afterAll\", suite.timeout);\n  }\n\n  async runRootSuite() {\n    const testSuite = this.rootSuite;\n    const started = performance.now();\n\n    try {\n      await this.sendMessage(\"start\", {\n        desc: testSuite.module,\n        isSuite: true,\n        started,\n        timeout: testSuite.timeout,\n      });\n\n      await this.runSuite(testSuite, started);\n      await this.sendMessage(\"end\", {\n        isSuite: true,\n        started,\n        ended: performance.now(),\n      });\n    } catch (error: any) {\n      await this.sendMessage(\"error\", {\n        error,\n        started,\n        ended: performance.now(),\n        workerId: this.workerId,\n      });\n    }\n  }\n  async connect() {\n    await this.client.connect();\n  }\n}\n\n// Usage example\nconst {\n  __LLRT_TEST_SERVER_PORT: serverPortEnv,\n  __LLRT_TEST_WORKER_ID: workerIdEnv,\n  __LLRT_TEST_FILE: testFile,\n} = process.env;\n\nconst workerId = parseInt(workerIdEnv || \"\");\nconst serverPort = parseInt(serverPortEnv || \"\");\n\nif (isNaN(workerId) || isNaN(serverPort) || !testFile) {\n  throw new Error(\n    \"Test worker requires __LLRT_TEST_SERVER_PORT, __LLRT_TEST_WORKER_ID & __LLRT_TEST_FILE env\"\n  );\n}\n\nconst agent = new TestAgent(workerId, serverPort);\nawait agent.start(testFile);\n"
  },
  {
    "path": "llrt_core/src/modules/js/llrt.d.ts",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\ndeclare module \"hex\" {\n  export const decode: (text: string) => Uint8Array;\n  export const encode: (bytes: Uint8Array) => string;\n}\n\ndeclare module \"xml\" {\n  export class XMLParser {\n    constructor(options?: {\n      ignoreAttributes?: boolean;\n      attributeNamePrefix?: string;\n      textNodeName?: string;\n      attributeValueProcessor?: (\n        attrName: string,\n        attrValue: string,\n        jpath: string\n      ) => unknown;\n      tagValueProcessor?: (\n        attrName: string,\n        attrValue: string,\n        jpath: string,\n        hasAttributes: boolean\n      ) => unknown;\n    });\n    parse(xml: string): any;\n  }\n\n  export class XmlText {\n    constructor(private value: string) {}\n    toString(): string;\n  }\n\n  export class XmlNode {\n    readonly children: any[];\n    static of(name: string, childText?: string, withName?: string): XmlNode;\n    constructor(name: string, children?: any[]);\n    withName(name: string): XmlNode;\n    addAttribute(name: string, value: any): XmlNode;\n    addChildNode(child: any): XmlNode;\n    removeAttribute(name: string): XmlNode;\n    toString(): string;\n  }\n}\n\ndeclare module \"qjs\" {\n  interface MemoryInfo {\n    malloc_size: number;\n    malloc_limit: number;\n    memory_used_size: number;\n    malloc_count: number;\n    memory_used_count: number;\n    atom_count: number;\n    atom_size: number;\n    str_count: number;\n    str_size: number;\n    obj_count: number;\n    obj_size: number;\n    prop_count: number;\n    prop_size: number;\n    shape_count: number;\n    shape_size: number;\n    js_func_count: number;\n    js_func_size: number;\n    js_func_code_size: number;\n    js_func_pc2line_count: number;\n    js_func_pc2line_size: number;\n    c_func_count: number;\n    array_count: number;\n    fast_array_count: number;\n    fast_array_elements: number;\n    binary_object_count: number;\n    binary_object_size: number;\n  }\n  function ComputeMemoryUsage(): MemoryInfo;\n}\n\ndeclare module \"llrt:timezone\" {\n  interface Timezone {\n    /**\n     * Get the UTC offset in minutes for a timezone at a given time.\n     *\n     * @param timezone - IANA timezone name (e.g., \"America/Denver\", \"Asia/Tokyo\")\n     * @param epochMs - Unix timestamp in milliseconds\n     * @returns UTC offset in minutes (positive = ahead of UTC, negative = behind)\n     *\n     * @example\n     * // Get current offset for Denver (handles DST automatically)\n     * const offset = Timezone.getOffset(\"America/Denver\", Date.now());\n     * // Returns -420 (UTC-7) in winter, -360 (UTC-6) in summer\n     */\n    getOffset(timezone: string, epochMs: number): number;\n\n    /**\n     * List all available IANA timezone names.\n     *\n     * @returns Array of timezone names\n     *\n     * @example\n     * const zones = Timezone.list();\n     * // [\"Africa/Abidjan\", \"Africa/Accra\", ..., \"Pacific/Wallis\"]\n     */\n    list(): string[];\n\n    readonly [Symbol.toStringTag]: \"Timezone\";\n  }\n\n  export const Timezone: Timezone;\n  export default { Timezone: Timezone };\n}\n"
  },
  {
    "path": "llrt_core/src/modules/js/stream/promises.ts",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n// @ts-ignore\nimport { finished, pipeline } from \"readable-stream/lib/stream/promises.js\";\n\nexport { finished, pipeline };\n"
  },
  {
    "path": "llrt_core/src/modules/js/stream.ts",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nimport { EventEmitter as EE } from \"node:events\";\n// @ts-ignore\nimport { Readable } from \"readable-stream/lib/_stream_readable.js\";\n// @ts-ignore\nimport { Writable } from \"readable-stream/lib/_stream_writable.js\";\n// @ts-ignore\nimport { Duplex } from \"readable-stream/lib/_stream_duplex.js\";\n// @ts-ignore\nimport { Transform } from \"readable-stream/lib/_stream_transform.js\";\n// @ts-ignore\nimport { PassThrough } from \"readable-stream/lib/_stream_passthrough.js\";\n// @ts-ignore\nimport { finished } from \"readable-stream/lib/internal/streams/end-of-stream.js\";\n// @ts-ignore\nimport { pipeline } from \"readable-stream/lib/internal/streams/pipeline.js\";\n\nimport { inherits } from \"node:util\";\n\ninherits(Stream, EE);\nStream.Readable = Readable;\nStream.Writable = Writable;\nStream.Duplex = Duplex;\nStream.Transform = Transform;\nStream.PassThrough = PassThrough;\nStream.finished = finished;\nStream.pipeline = pipeline;\nStream.Stream = Stream;\n\n// old-style streams.  Note that the pipe method (the only relevant\n// part of this class) is overridden in the Readable class.\n\nfunction Stream(this: any) {\n  EE.call(this);\n}\n\nStream.prototype.pipe = function (dest: any, options: any) {\n  var source = this;\n\n  function ondata(chunk: any) {\n    if (dest.writable) {\n      if (false === dest.write(chunk) && source.pause) {\n        source.pause();\n      }\n    }\n  }\n\n  source.on(\"data\", ondata);\n\n  function ondrain() {\n    if (source.readable && source.resume) {\n      source.resume();\n    }\n  }\n\n  dest.on(\"drain\", ondrain);\n\n  // If the 'end' option is not supplied, dest.end() will be called when\n  // source gets the 'end' or 'close' events.  Only dest.end() once.\n  if (!dest._isStdio && (!options || options.end !== false)) {\n    source.on(\"end\", onend);\n    source.on(\"close\", onclose);\n  }\n\n  var didOnEnd = false;\n  function onend() {\n    if (didOnEnd) return;\n    didOnEnd = true;\n\n    dest.end();\n  }\n\n  function onclose() {\n    if (didOnEnd) return;\n    didOnEnd = true;\n\n    if (typeof dest.destroy === \"function\") dest.destroy();\n  }\n\n  // don't leave dangling pipes when there are errors.\n  function onerror(er: any) {\n    cleanup();\n    if (source.listenerCount(\"error\") === 0) {\n      throw er; // Unhandled stream error in pipe.\n    }\n  }\n\n  source.on(\"error\", onerror);\n  dest.on(\"error\", onerror);\n\n  // remove all the event listeners that were added.\n  function cleanup() {\n    source.removeListener(\"data\", ondata);\n    dest.removeListener(\"drain\", ondrain);\n\n    source.removeListener(\"end\", onend);\n    source.removeListener(\"close\", onclose);\n\n    source.removeListener(\"error\", onerror);\n    dest.removeListener(\"error\", onerror);\n\n    source.removeListener(\"end\", cleanup);\n    source.removeListener(\"close\", cleanup);\n\n    dest.removeListener(\"close\", cleanup);\n  }\n\n  source.on(\"end\", cleanup);\n  source.on(\"close\", cleanup);\n\n  dest.on(\"close\", cleanup);\n\n  dest.emit(\"pipe\", source);\n\n  // Allow for unix-like usage: A.pipe(B).pipe(C)\n  return dest;\n};\n\nexport default Stream;\nexport {\n  Readable,\n  Writable,\n  Duplex,\n  Transform,\n  PassThrough,\n  finished,\n  pipeline,\n  Stream,\n};\n"
  },
  {
    "path": "llrt_core/src/modules/llrt/hex.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse rquickjs::{\n    module::{Declarations, Exports, ModuleDef},\n    prelude::Func,\n    Ctx, Result, Value,\n};\n\nuse crate::libs::{\n    encoding::{bytes_from_hex, bytes_to_hex_string},\n    utils::{\n        bytes::{bytes_to_typed_array, ObjectBytes},\n        module::{export_default, ModuleInfo},\n        result::ResultExt,\n    },\n};\n\npub struct LlrtHexModule;\n\nimpl LlrtHexModule {\n    pub fn encode<'js>(ctx: Ctx<'js>, bytes: ObjectBytes<'js>) -> Result<String> {\n        Ok(bytes_to_hex_string(bytes.as_bytes(&ctx)?))\n    }\n\n    pub fn decode(ctx: Ctx, encoded: String) -> Result<Value> {\n        let bytes = bytes_from_hex(encoded.as_bytes())\n            .or_throw_msg(&ctx, \"Cannot decode unrecognized sequence\")?;\n\n        bytes_to_typed_array(ctx, &bytes)\n    }\n}\n\nimpl ModuleDef for LlrtHexModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(stringify!(encode))?;\n        declare.declare(stringify!(decode))?;\n        declare.declare(\"default\")?;\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        export_default(ctx, exports, |default| {\n            default.set(stringify!(encode), Func::from(Self::encode))?;\n            default.set(stringify!(decode), Func::from(Self::decode))?;\n            Ok(())\n        })?;\n\n        Ok(())\n    }\n}\n\nimpl From<LlrtHexModule> for ModuleInfo<LlrtHexModule> {\n    fn from(val: LlrtHexModule) -> Self {\n        ModuleInfo {\n            name: \"llrt:hex\",\n            module: val,\n        }\n    }\n}\n"
  },
  {
    "path": "llrt_core/src/modules/llrt/mod.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\npub mod hex;\npub mod qjs;\npub mod util;\npub mod xml;\n"
  },
  {
    "path": "llrt_core/src/modules/llrt/qjs.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse rquickjs::{\n    module::{Declarations, Exports, ModuleDef},\n    prelude::Func,\n    qjs, Ctx, IntoJs, Object, Result, Value,\n};\n\nuse crate::libs::utils::module::{export_default, ModuleInfo};\n\n// SAFETY:\n// - The associated runtime must not be accessed concurrently or destroyed\n//   while this function runs (QuickJS is not thread-safe).\n// - Undefined behavior may occur if called with an invalid or corrupted runtime.\nunsafe fn js_compute_memory_usage(ctx: &Ctx) -> qjs::JSMemoryUsage {\n    let mut usage: qjs::JSMemoryUsage = std::mem::zeroed();\n    let rt = qjs::JS_GetRuntime(ctx.as_raw().as_ptr());\n    qjs::JS_ComputeMemoryUsage(rt, &mut usage);\n    usage\n}\n\nfn compute_memory_usage(ctx: Ctx) -> Result<Value> {\n    let usage = unsafe { js_compute_memory_usage(&ctx) };\n\n    let obj = Object::new(ctx.clone())?;\n    obj.set(\"malloc_size\", usage.malloc_size)?;\n    obj.set(\"malloc_limit\", usage.malloc_limit)?;\n    obj.set(\"memory_used_size\", usage.memory_used_size)?;\n    obj.set(\"malloc_count\", usage.malloc_count)?;\n    obj.set(\"memory_used_count\", usage.memory_used_count)?;\n    obj.set(\"atom_count\", usage.atom_count)?;\n    obj.set(\"atom_size\", usage.atom_size)?;\n    obj.set(\"str_count\", usage.str_count)?;\n    obj.set(\"str_size\", usage.str_size)?;\n    obj.set(\"obj_count\", usage.obj_count)?;\n    obj.set(\"obj_size\", usage.obj_size)?;\n    obj.set(\"prop_count\", usage.prop_count)?;\n    obj.set(\"prop_size\", usage.prop_size)?;\n    obj.set(\"shape_count\", usage.shape_count)?;\n    obj.set(\"shape_size\", usage.shape_size)?;\n    obj.set(\"js_func_count\", usage.js_func_count)?;\n    obj.set(\"js_func_size\", usage.js_func_size)?;\n    obj.set(\"js_func_code_size\", usage.js_func_code_size)?;\n    obj.set(\"js_func_pc2line_count\", usage.js_func_pc2line_count)?;\n    obj.set(\"js_func_pc2line_size\", usage.js_func_pc2line_size)?;\n    obj.set(\"c_func_count\", usage.c_func_count)?;\n    obj.set(\"array_count\", usage.array_count)?;\n    obj.set(\"fast_array_count\", usage.fast_array_count)?;\n    obj.set(\"fast_array_elements\", usage.fast_array_elements)?;\n    obj.set(\"binary_object_count\", usage.binary_object_count)?;\n    obj.set(\"binary_object_size\", usage.binary_object_size)?;\n\n    obj.into_js(&ctx)\n}\n\npub struct LlrtQjsModule;\n\nimpl ModuleDef for LlrtQjsModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(\"ComputeMemoryUsage\")?;\n        declare.declare(\"default\")?;\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        export_default(ctx, exports, |default| {\n            default.set(\"ComputeMemoryUsage\", Func::from(compute_memory_usage))?;\n            Ok(())\n        })\n    }\n}\n\nimpl From<LlrtQjsModule> for ModuleInfo<LlrtQjsModule> {\n    fn from(val: LlrtQjsModule) -> Self {\n        ModuleInfo {\n            name: \"llrt:qjs\",\n            module: val,\n        }\n    }\n}\n"
  },
  {
    "path": "llrt_core/src/modules/llrt/util.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse rquickjs::{\n    context::EvalOptions,\n    module::{Declarations, Exports, ModuleDef},\n    prelude::{Func, Opt},\n    Array, Ctx, Object, Result, Value,\n};\n\nuse crate::libs::utils::{\n    module::{export_default, ModuleInfo},\n    object::ObjectExt,\n};\n\nfn dimensions(ctx: Ctx<'_>) -> Result<Array<'_>> {\n    let array = Array::new(ctx.clone())?;\n    match terminal_size::terminal_size() {\n        Some((width, height)) => {\n            array.set(0, width.0)?;\n            array.set(1, height.0)?;\n        },\n        None => {\n            array.set(0, 0)?;\n            array.set(1, 0)?;\n        },\n    }\n    Ok(array)\n}\n\nfn load<'js>(ctx: Ctx<'js>, filename: String, options: Opt<Object<'js>>) -> Result<Value<'js>> {\n    let mut eval_options = EvalOptions::default();\n    eval_options.strict = false;\n    eval_options.promise = true;\n\n    if let Some(options) = options.0 {\n        if let Some(global) = options.get_optional(\"global\")? {\n            eval_options.global = global;\n        }\n\n        if let Some(strict) = options.get_optional(\"strict\")? {\n            eval_options.strict = strict;\n        }\n    }\n\n    ctx.eval_file_with_options(filename, eval_options)\n}\n\nfn print(value: String, stdout: Opt<bool>) {\n    if stdout.0.unwrap_or_default() {\n        println!(\"{value}\");\n    } else {\n        eprintln!(\"{value}\")\n    }\n}\n\npub struct LlrtUtilModule;\n\nimpl ModuleDef for LlrtUtilModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(\"dimensions\")?;\n        declare.declare(\"load\")?;\n        declare.declare(\"print\")?;\n        declare.declare(\"default\")?;\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        export_default(ctx, exports, |default| {\n            default.set(\"dimensions\", Func::from(dimensions))?;\n            default.set(\"load\", Func::from(load))?;\n            default.set(\"print\", Func::from(print))?;\n            Ok(())\n        })\n    }\n}\n\nimpl From<LlrtUtilModule> for ModuleInfo<LlrtUtilModule> {\n    fn from(val: LlrtUtilModule) -> Self {\n        ModuleInfo {\n            name: \"llrt:util\",\n            module: val,\n        }\n    }\n}\n"
  },
  {
    "path": "llrt_core/src/modules/llrt/xml.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#![allow(clippy::uninlined_format_args)]\n\nuse std::{borrow::Cow, rc::Rc};\n\nuse quick_xml::{\n    escape::resolve_xml_entity,\n    events::{BytesStart, Event},\n    Reader,\n};\nuse rquickjs::{\n    class::{Trace, Tracer},\n    function::Opt,\n    module::{Declarations, Exports, ModuleDef},\n    object::Property,\n    prelude::This,\n    Array, Class, Ctx, Function, IntoJs, Object, Result, Value,\n};\n\nuse crate::libs::utils::{\n    bytes::ObjectBytes,\n    module::{export_default, ModuleInfo},\n    object::ObjectExt,\n    result::ResultExt,\n};\n\nconst AMP: &str = \"&amp;\";\nconst LT: &str = \"&lt;\";\nconst GT: &str = \"&gt;\";\nconst QUOT: &str = \"&quot;\";\nconst APOS: &str = \"&apos;\";\nconst CR: &str = \"&#x0D;\";\nconst LF: &str = \"&#x0A;\";\nconst NEL: &str = \"&#x85;\";\nconst LS: &str = \"&#x2028;\";\n\n#[rquickjs::class]\n#[derive(rquickjs::JsLifetime)]\nstruct XMLParser<'js> {\n    tag_value_processor: Option<Function<'js>>,\n    attribute_value_processor: Option<Function<'js>>,\n    attribute_name_prefix: Rc<str>,\n    ignore_attributes: bool,\n    text_node_name: Rc<str>,\n    entities: Vec<(Rc<str>, Rc<str>)>,\n}\n\nimpl<'js> Trace<'js> for XMLParser<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        if let Some(tag_value_processor) = &self.tag_value_processor {\n            tracer.mark(tag_value_processor)\n        }\n        if let Some(attribute_value_processor) = &self.attribute_value_processor {\n            tracer.mark(attribute_value_processor)\n        }\n    }\n}\n\nstruct StackObject<'js> {\n    obj: Object<'js>,\n    has_value: bool,\n}\nimpl<'js> StackObject<'js> {\n    fn new(ctx: Ctx<'js>) -> Result<Self> {\n        Ok(Self {\n            obj: Object::new(ctx)?,\n            has_value: false,\n        })\n    }\n\n    fn into_value(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {\n        if self.has_value {\n            return Ok(self.obj.into_value());\n        }\n        \"\".into_js(ctx)\n    }\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl<'js> XMLParser<'js> {\n    #[qjs(constructor)]\n    pub fn new(options: Opt<Object<'js>>) -> Result<Self> {\n        let mut tag_value_processor = None;\n        let mut attribute_value_processor = None;\n        let mut attribute_name_prefix = None;\n        let mut ignore_attributes = true;\n        let mut text_node_name = None;\n        if let Some(options) = options.0 {\n            tag_value_processor = options.get_optional(\"tagValueProcessor\")?;\n            attribute_value_processor = options.get_optional(\"attributeValueProcessor\")?;\n            if let Some(prefix) = options.get_optional::<_, String>(\"attributeNamePrefix\")? {\n                attribute_name_prefix = Some(prefix.into())\n            }\n            if let Some(attributes_ignored) = options.get_optional(\"ignoreAttributes\")? {\n                ignore_attributes = attributes_ignored\n            }\n            if let Some(name) = options.get_optional::<_, String>(\"textNodeName\")? {\n                text_node_name = Some(name.into())\n            }\n        }\n\n        let entities = Vec::new();\n\n        Ok(XMLParser {\n            tag_value_processor,\n            attribute_value_processor,\n            entities,\n            attribute_name_prefix: attribute_name_prefix.unwrap_or_else(|| \"@_\".into()),\n            ignore_attributes,\n            text_node_name: text_node_name.unwrap_or_else(|| \"#text\".into()),\n        })\n    }\n\n    pub fn add_entity(&mut self, key: String, value: String) {\n        if let Some((_, v)) = self.entities.iter_mut().find(|(k, _)| k.as_ref() == key) {\n            *v = key.into()\n        } else {\n            self.entities.push((key.into(), value.into()));\n        }\n    }\n\n    pub fn parse(&self, ctx: Ctx<'js>, bytes: ObjectBytes<'js>) -> Result<Object<'js>> {\n        let bytes = bytes.as_bytes(&ctx)?;\n        let mut reader = Reader::from_reader(bytes);\n        let config = reader.config_mut();\n        config.trim_text(true);\n\n        let mut current_obj = StackObject::new(ctx.clone())?;\n        current_obj.has_value = true;\n        let mut buf = Vec::new();\n        let mut current_key: Rc<str> = \"\".into();\n        let mut current_value: Option<String> = None;\n        let mut path: Vec<(Rc<str>, StackObject<'js>)> = vec![];\n        let mut has_attributes = false;\n\n        loop {\n            buf.clear();\n\n            match reader.read_event_into(&mut buf) {\n                Ok(Event::Empty(ref tag)) => {\n                    current_key = Self::get_tag_name(&ctx, &reader, tag)?;\n\n                    let mut obj = StackObject::new(ctx.clone())?;\n                    self.process_attributes(&ctx, &reader, &path, tag, &mut obj, &mut false)?;\n                    current_obj.has_value = true;\n\n                    Self::process_end(&ctx, &current_obj, obj.into_value(&ctx)?, &current_key)?;\n                },\n                Ok(Event::Start(ref tag)) => {\n                    has_attributes = false;\n                    current_key = Self::get_tag_name(&ctx, &reader, tag)?;\n                    path.push((current_key.clone(), current_obj));\n\n                    let obj = StackObject::new(ctx.clone())?;\n                    current_obj = obj;\n\n                    self.process_attributes(\n                        &ctx,\n                        &reader,\n                        &path,\n                        tag,\n                        &mut current_obj,\n                        &mut has_attributes,\n                    )?;\n                },\n                Ok(Event::End(_)) => {\n                    let (parent_tag, mut parent_obj) = path.pop().unwrap();\n                    parent_obj.has_value = true;\n                    let value = if let Some(value) = current_value.take() {\n                        value.into_js(&ctx)?\n                    } else {\n                        current_obj.into_value(&ctx)?\n                    };\n\n                    current_obj = parent_obj;\n\n                    Self::process_end(&ctx, &current_obj, value, &parent_tag)?;\n                },\n                Ok(Event::CData(text)) => {\n                    let text = text.escape().or_throw(&ctx)?;\n                    let tag_value = String::from_utf8_lossy(&text);\n                    self.process_text(\n                        &mut current_obj,\n                        &mut current_key,\n                        &mut current_value,\n                        &mut path,\n                        has_attributes,\n                        tag_value,\n                    )?;\n                },\n                Ok(Event::GeneralRef(ref text)) => {\n                    let text_ref = text.decode().or_throw(&ctx)?;\n                    let text_ref: &str = &text_ref;\n                    let tag_value = resolve_xml_entity(text_ref)\n                        .or_else(|| {\n                            self.entities\n                                .iter()\n                                .find(|(k, _)| k.as_ref() == text_ref)\n                                .map(|(_, v)| v.as_ref())\n                        })\n                        .unwrap_or(text_ref);\n                    match current_value {\n                        Some(ref mut val) => val.push_str(tag_value),\n                        None => current_value = Some(tag_value.to_owned()),\n                    }\n                },\n                Ok(Event::Text(ref text)) => {\n                    let tag_value = text.decode().or_throw(&ctx)?;\n\n                    self.process_text(\n                        &mut current_obj,\n                        &mut current_key,\n                        &mut current_value,\n                        &mut path,\n                        has_attributes,\n                        tag_value,\n                    )?;\n                },\n                Err(e) => panic!(\"Error at position {}: {:?}\", reader.buffer_position(), e),\n                Ok(Event::Eof) => break,\n                _ => {},\n            }\n        }\n        Ok(current_obj.obj)\n    }\n}\n\nimpl<'js> XMLParser<'js> {\n    fn process_text<'a>(\n        &self,\n        current_obj: &mut StackObject,\n        current_key: &mut Rc<str>,\n        current_value: &mut Option<String>,\n        path: &mut Vec<(Rc<str>, StackObject<'js>)>,\n        has_attributes: bool,\n        tag_value: Cow<'a, str>,\n    ) -> Result<()> {\n        let tag_value = self.process_tag_value(path, current_key, tag_value, has_attributes)?;\n        if has_attributes {\n            current_obj.has_value = true;\n            current_obj\n                .obj\n                .set(self.text_node_name.as_ref(), tag_value)?;\n        } else {\n            match current_value {\n                Some(ref mut val) => val.push_str(&tag_value),\n                None => *current_value = Some(tag_value),\n            }\n        }\n        Ok(())\n    }\n\n    fn get_tag_name(\n        ctx: &Ctx<'js>,\n        reader: &Reader<&[u8]>,\n        tag: &BytesStart<'_>,\n    ) -> Result<Rc<str>> {\n        let tag = tag.name();\n        let tag_name = reader.decoder().decode(tag.as_ref()).or_throw(ctx)?;\n        Ok(tag_name.as_ref().into())\n    }\n\n    fn process_end(\n        ctx: &Ctx<'js>,\n        current_obj: &StackObject<'js>,\n        value: Value<'js>,\n        tag: &str,\n    ) -> Result<()> {\n        if current_obj.obj.contains_key(tag)? {\n            let parent_value: Value = current_obj.obj.get(tag)?;\n            if !parent_value.is_array() {\n                let array = Array::new(ctx.clone())?;\n                array.set(0, parent_value)?;\n                array.set(1, value)?;\n                current_obj.obj.set(tag, array.as_value())?;\n            } else {\n                let array = parent_value.as_array().or_throw(ctx)?;\n                array.set(array.len(), value)?;\n                current_obj.obj.set(tag, array.as_value())?;\n            }\n        } else {\n            current_obj.obj.prop(\n                tag,\n                Property::from(value).configurable().enumerable().writable(),\n            )?;\n        }\n        Ok(())\n    }\n\n    fn set_attribute(\n        &self,\n        stack_object: &mut StackObject<'js>,\n        path: &[&str],\n        key: &str,\n        value: &str,\n    ) -> Result<()> {\n        if let Some(attribute_value_processor) = &self.attribute_value_processor {\n            let jpath = path.join(\".\");\n            let jpath = jpath.as_str();\n            if let Some(new_value) =\n                attribute_value_processor.call::<_, Option<String>>((key, value, jpath))?\n            {\n                stack_object.obj.set(key, new_value)?;\n                return Ok(());\n            }\n        }\n        stack_object.obj.set(key, value)?;\n        Ok(())\n    }\n\n    fn process_attributes(\n        &self,\n        ctx: &Ctx<'js>,\n        reader: &Reader<&[u8]>,\n        path: &[(Rc<str>, StackObject<'js>)],\n        tag: &BytesStart<'_>,\n        stack_object: &mut StackObject<'js>,\n        has_attributes: &mut bool,\n    ) -> Result<()> {\n        if !self.ignore_attributes {\n            let jpath_str = path.iter().map(|(k, _)| k.as_ref()).collect::<Vec<_>>();\n            for attribute in tag.attributes() {\n                stack_object.has_value = true;\n                *has_attributes = true;\n                let attr = attribute.or_throw(ctx)?;\n\n                let value = reader.decoder().decode(attr.value.as_ref()).or_throw(ctx)?;\n                let value = value.as_ref();\n\n                let key_slice = attr.key.as_ref();\n                if !self.attribute_name_prefix.is_empty() {\n                    let prefix_bytes = self.attribute_name_prefix.as_bytes();\n                    let mut key_bytes = Vec::with_capacity(prefix_bytes.len() + key_slice.len());\n                    key_bytes.extend_from_slice(prefix_bytes);\n                    key_bytes.extend_from_slice(key_slice);\n\n                    let key = reader.decoder().decode(&key_bytes).or_throw(ctx)?;\n                    self.set_attribute(stack_object, &jpath_str, key.as_ref(), value)?;\n                } else {\n                    let key = reader.decoder().decode(key_slice).or_throw(ctx)?;\n                    self.set_attribute(stack_object, &jpath_str, key.as_ref(), value)?;\n                };\n            }\n        }\n        Ok(())\n    }\n\n    fn process_tag_value(\n        &self,\n        path: &[(Rc<str>, StackObject<'js>)],\n        key: &str,\n        value: Cow<'_, str>,\n        has_attributes: bool,\n    ) -> Result<String> {\n        if value.is_empty() {\n            return Ok(value.into());\n        }\n\n        if let Some(tag_value_processor) = &self.tag_value_processor {\n            let jpath = path\n                .iter()\n                .map(|(k, _)| k.as_ref())\n                .collect::<Vec<_>>()\n                .join(\".\");\n\n            if let Some(new_value) = tag_value_processor.call::<_, Option<String>>((\n                key,\n                value.as_ref(),\n                jpath,\n                has_attributes,\n            ))? {\n                return Ok(new_value);\n            }\n        }\n        Ok(value.into())\n    }\n}\n\n#[derive(Debug, Clone, rquickjs::JsLifetime)]\n#[rquickjs::class]\nstruct XmlText {\n    value: Rc<str>,\n}\n\nimpl<'js> Trace<'js> for XmlText {\n    fn trace<'a>(&self, _tracer: Tracer<'a, 'js>) {}\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl XmlText {\n    #[qjs(constructor)]\n    fn new(value: String) -> Self {\n        let mut escaped = String::with_capacity(value.len());\n        escape_element(&mut escaped, &value);\n        XmlText {\n            value: escaped.into(),\n        }\n    }\n\n    fn to_string(&self) -> &str {\n        self.value.as_ref()\n    }\n}\n\n#[rquickjs::class]\n#[derive(Debug, Clone, rquickjs::class::Trace, rquickjs::JsLifetime)]\nstruct XmlNode<'js> {\n    #[qjs(skip_trace)]\n    name: String,\n    //child and attributes are always set to avoid branch checks when adding/removing values\n    children: Vec<Value<'js>>,\n    #[qjs(skip_trace)]\n    //vec iteration is faster since we rarely have more than 10 attrs and we want to retain insertion order\n    attributes: Vec<(String, String)>,\n}\n\nenum NodeStackEntry<'js> {\n    Node(Class<'js, XmlNode<'js>>),\n    End(String),\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl<'js> XmlNode<'js> {\n    #[qjs(constructor)]\n    fn new(name: String, children: Opt<Vec<Value<'js>>>) -> Result<Self> {\n        let node = XmlNode {\n            name,\n            attributes: Vec::new(),\n            children: children.0.unwrap_or_default(),\n        };\n\n        Ok(node)\n    }\n\n    #[qjs(static)]\n    fn of(\n        ctx: Ctx<'js>,\n        name: String,\n        child_text: Opt<String>,\n        with_name: Opt<String>,\n    ) -> Result<Value<'js>> {\n        let mut node = XmlNode {\n            name,\n            children: Vec::new(),\n            attributes: Vec::new(),\n        };\n\n        if let Some(text) = child_text.0 {\n            let xml_text = Class::instance(ctx.clone(), XmlText::new(text))?;\n            node.children.push(xml_text.into_value());\n        }\n\n        if let Some(new_name) = with_name.0 {\n            node.name = new_name;\n        }\n\n        node.into_js(&ctx)\n    }\n\n    fn with_name(this: This<Class<'js, Self>>, name: String) -> Class<'js, Self> {\n        this.borrow_mut().name = name;\n        this.0\n    }\n\n    fn add_attribute(\n        this: This<Class<'js, Self>>,\n        name: String,\n        value: String,\n    ) -> Class<'js, Self> {\n        let this2 = this.clone();\n        let mut borrow = this2.borrow_mut();\n        if let Some(pos) = borrow.attributes.iter().position(|(a, _)| a == &name) {\n            borrow.attributes[pos] = (name, value);\n        } else {\n            borrow.attributes.push((name, value));\n        }\n        this.0\n    }\n\n    fn add_child_node(this: This<Class<'js, Self>>, value: Value<'js>) -> Result<Class<'js, Self>> {\n        let this2 = this.clone();\n        this2.borrow_mut().children.push(value);\n        Ok(this.0)\n    }\n\n    fn remove_attribute(this: This<Class<'js, Self>>, name: String) -> Class<'js, Self> {\n        let this2 = this.clone();\n        let mut borrow = this2.borrow_mut();\n        if let Some(pos) = borrow.attributes.iter().position(|(a, _)| a == &name) {\n            borrow.attributes.remove(pos);\n        }\n        this.0\n    }\n\n    fn to_string(this: This<Class<'js, Self>>, ctx: Ctx<'js>) -> Result<String> {\n        let class = this.0;\n        let mut xml_text = String::with_capacity(8);\n\n        let mut stack = vec![NodeStackEntry::Node(class)];\n\n        while let Some(node) = stack.pop() {\n            match node {\n                NodeStackEntry::Node(node) => {\n                    let borrow = node.borrow();\n                    xml_text.push('<');\n                    xml_text.push_str(&borrow.name);\n\n                    for (attribute_name, attribute) in &borrow.attributes {\n                        xml_text.push(' ');\n                        xml_text.push_str(attribute_name);\n                        xml_text.push_str(\"=\\\"\");\n                        escape_attribute(&mut xml_text, attribute);\n                        xml_text.push('\"');\n                    }\n\n                    let has_children = !borrow.children.is_empty();\n                    if has_children {\n                        stack.push(NodeStackEntry::End(borrow.name.clone()));\n                        xml_text.push('>');\n\n                        // Add children to the stack in reverse order (to maintain original order)\n                        for child in borrow.children.iter().rev() {\n                            if let Some(obj) = child.as_object() {\n                                if let Some(node) = Class::<Self>::from_object(obj) {\n                                    stack.push(NodeStackEntry::Node(node))\n                                } else if let Some(text) = Class::<XmlText>::from_object(obj) {\n                                    xml_text.push_str(&text.borrow().value);\n                                } else {\n                                    let to_string_fn = obj.get::<_, Function>(\"toString\")?;\n                                    let string_value: String = to_string_fn.call(())?;\n                                    xml_text.push_str(&string_value);\n                                }\n                            } else {\n                                let string_value = child\n                                    .clone()\n                                    .try_into_string()\n                                    .map_err(|err| format!(\"Unable to convert {:?} to string\", err))\n                                    .or_throw(&ctx)?\n                                    .to_string()?;\n                                xml_text.push_str(&string_value);\n                            }\n                        }\n                    } else {\n                        xml_text.push_str(\"/>\");\n                    }\n                    drop(borrow);\n                },\n                NodeStackEntry::End(name) => {\n                    xml_text.push_str(\"</\");\n                    xml_text.push_str(&name);\n                    xml_text.push('>');\n                },\n            }\n        }\n\n        Ok(xml_text)\n    }\n}\n\nfn escape_attribute(text: &mut String, value: &str) {\n    text.reserve(value.len());\n    for c in value.chars() {\n        match c {\n            '&' => text.push_str(AMP),\n            '<' => text.push_str(LT),\n            '>' => text.push_str(GT),\n            '\"' => text.push_str(QUOT),\n            _ => text.push(c),\n        }\n    }\n}\n\nfn escape_element(text: &mut String, value: &str) {\n    text.reserve(value.len());\n    for c in value.chars() {\n        match c {\n            '&' => text.push_str(AMP),\n            '<' => text.push_str(LT),\n            '>' => text.push_str(GT),\n            '\\'' => text.push_str(APOS),\n            '\"' => text.push_str(QUOT),\n            '\\r' => text.push_str(CR),\n            '\\n' => text.push_str(LF),\n            '\\u{0085}' => text.push_str(NEL),\n            '\\u{2028}' => text.push_str(LS),\n            _ => text.push(c),\n        }\n    }\n}\n\npub struct LlrtXmlModule;\n\nimpl ModuleDef for LlrtXmlModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(stringify!(XMLParser))?;\n        declare.declare(stringify!(XmlText))?;\n        declare.declare(stringify!(XmlNode))?;\n\n        declare.declare(\"default\")?;\n\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        export_default(ctx, exports, |default| {\n            Class::<XMLParser>::define(default)?;\n            Class::<XmlText>::define(default)?;\n            Class::<XmlNode>::define(default)?;\n            Ok(())\n        })?;\n\n        Ok(())\n    }\n}\n\nimpl From<LlrtXmlModule> for ModuleInfo<LlrtXmlModule> {\n    fn from(val: LlrtXmlModule) -> Self {\n        ModuleInfo {\n            name: \"llrt:xml\",\n            module: val,\n        }\n    }\n}\n"
  },
  {
    "path": "llrt_core/src/modules/mod.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#[cfg(not(feature = \"lambda\"))]\npub use llrt_modules::console;\npub use llrt_modules::{\n    abort, assert, async_hooks, buffer, child_process, crypto, dns, events, exceptions, fetch, fs,\n    https, intl, module, navigator, net, os, path, perf_hooks, process, stream_web, string_decoder,\n    temporal, timers, tls, tty, url, util, zlib,\n};\npub use llrt_modules::{module_builder, package, CJS_IMPORT_PREFIX, CJS_LOADER_PREFIX};\n\n#[cfg(feature = \"lambda\")]\npub mod console;\npub mod embedded;\npub mod llrt;\n"
  },
  {
    "path": "llrt_core/src/runtime_client.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#![allow(clippy::uninlined_format_args)]\n\nuse std::{\n    env,\n    result::Result as StdResult,\n    sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},\n    time::Instant,\n};\n\nuse http_body_util::{combinators::BoxBody, BodyExt, Full};\nuse hyper::{\n    header::{HeaderMap, CONTENT_TYPE},\n    http::header::HeaderName,\n    Request, StatusCode,\n};\nuse jiff::Timestamp;\nuse once_cell::sync::Lazy;\nuse rquickjs::{\n    atom::PredefinedAtom, function::Rest, prelude::Func, promise::Promise, qjs, CatchResultExt,\n    CaughtError, Ctx, Exception, Function, IntoJs, Module, Object, Result, Value,\n};\nuse tracing::info;\n\nuse crate::libs::{\n    json::{\n        parse::json_parse,\n        stringify::{self, json_stringify},\n    },\n    logging::{format_values, replace_newline_with_carriage_return},\n    utils::{class::get_class_name, result::ResultExt},\n};\n\n#[cfg(not(test))]\nuse crate::modules::console::log_error;\nuse crate::modules::https::{HyperClient, HTTP_CLIENT};\nuse llrt_utils::latch::Latch;\n\nconst ENV_AWS_LAMBDA_FUNCTION_NAME: &str = \"AWS_LAMBDA_FUNCTION_NAME\";\nconst ENV_AWS_LAMBDA_FUNCTION_VERSION: &str = \"AWS_LAMBDA_FUNCTION_VERSION\";\nconst ENV_AWS_LAMBDA_FUNCTION_MEMORY_SIZE: &str = \"AWS_LAMBDA_FUNCTION_MEMORY_SIZE\";\nconst ENV_AWS_LAMBDA_LOG_GROUP_NAME: &str = \"AWS_LAMBDA_LOG_GROUP_NAME\";\nconst ENV_AWS_LAMBDA_LOG_STREAM_NAME: &str = \"AWS_LAMBDA_LOG_STREAM_NAME\";\nconst ENV_LAMBDA_TASK_ROOT: &str = \"LAMBDA_TASK_ROOT\";\nconst ENV_UNDERSCORE_HANDLER: &str = \"_HANDLER\";\nconst ENV_LAMBDA_HANDLER: &str = \"LAMBDA_HANDLER\";\nconst AWS_LAMBDA_RUNTIME_API: &str = \"AWS_LAMBDA_RUNTIME_API\";\nconst ENV_UNDERSCORE_EXIT_ITERATIONS: &str = \"_EXIT_ITERATIONS\";\nconst ENV_RUNTIME_PATH: &str = \"2018-06-01/runtime\";\nconst ENV_X_AMZN_TRACE_ID: &str = \"_X_AMZN_TRACE_ID\";\n\nstatic HEADER_TRACE_ID: HeaderName = HeaderName::from_static(\"lambda-runtime-trace-id\");\nstatic HEADER_DEADLINE_MS: HeaderName = HeaderName::from_static(\"lambda-runtime-deadline-ms\");\nstatic HEADER_REQUEST_ID: HeaderName = HeaderName::from_static(\"lambda-runtime-aws-request-id\");\nstatic HEADER_ERROR_TYPE: HeaderName =\n    HeaderName::from_static(\"lambda-runtime-function-error-type\");\nstatic HEADER_INVOKED_FUNCTION_ARN: HeaderName =\n    HeaderName::from_static(\"lambda-runtime-invoked-function-arn\");\nstatic HEADER_CLIENT_CONTEXT: HeaderName = HeaderName::from_static(\"lambda-runtime-client-context\");\nstatic HEADER_COGNITO_IDENTITY: HeaderName =\n    HeaderName::from_static(\"lambda-runtime-cognito-identity\");\n\npub struct SdkClientInitState {\n    rt: *mut qjs::JSRuntime,\n    latch: Arc<Latch>,\n    endpoints: Vec<Box<str>>, //we're likely to have a small number of clients\n}\nimpl SdkClientInitState {\n    fn new(rt: *mut qjs::JSRuntime) -> Self {\n        Self {\n            rt,\n            latch: Latch::default().into(),\n            endpoints: Vec::new(),\n        }\n    }\n}\n\nunsafe impl Sync for SdkClientInitState {}\nunsafe impl Send for SdkClientInitState {}\n\nfn get_sdk_client_init_state_mut<'a>(\n    guard: &'a mut RwLockWriteGuard<Vec<SdkClientInitState>>,\n    rt: *mut qjs::JSRuntime,\n) -> &'a mut SdkClientInitState {\n    let state = guard.iter_mut().find(|state| state.rt == rt);\n\n    //save a branch\n    unsafe { state.unwrap_unchecked() }\n}\n\nfn get_sdk_client_init_state<'a>(\n    guard: &'a RwLockReadGuard<Vec<SdkClientInitState>>,\n    rt: *mut qjs::JSRuntime,\n) -> &'a SdkClientInitState {\n    let state = guard.iter().find(|state| state.rt == rt);\n\n    //save a branch\n    unsafe { state.unwrap_unchecked() }\n}\n\npub static LAMBDA_REQUEST_ID: Lazy<RwLock<Option<String>>> = Lazy::new(|| RwLock::new(None));\n\nstatic SDK_CONNECTION_INIT_LATCH: Lazy<RwLock<Vec<SdkClientInitState>>> =\n    Lazy::new(|| RwLock::new(Vec::new()));\n\npub fn check_client_inited(rt: *mut qjs::JSRuntime, endpoint: &str) -> bool {\n    let mut write = SDK_CONNECTION_INIT_LATCH.write().unwrap();\n    let state = get_sdk_client_init_state_mut(&mut write, rt);\n    if state.endpoints.iter().any(|s| s.as_ref() == endpoint) {\n        return true;\n    }\n    state.endpoints.push(endpoint.into());\n    state.latch.increment();\n    false\n}\n\npub fn mark_client_inited(rt: *mut qjs::JSRuntime) {\n    let mut write = SDK_CONNECTION_INIT_LATCH.write().unwrap();\n    let state = get_sdk_client_init_state_mut(&mut write, rt);\n    state.latch.decrement();\n}\n\n#[derive(Clone)]\nstruct LambdaContext<'js, 'a> {\n    pub aws_request_id: String,\n    pub invoked_function_arn: String,\n    pub callback_waits_for_empty_event_loop: bool,\n    pub get_remaining_time_in_millis: Function<'js>,\n    pub client_context: Value<'js>,\n    pub cognito_identity_json: Value<'js>,\n    pub lambda_environment: &'a LambdaEnvironment,\n}\n\nimpl<'js> IntoJs<'js> for LambdaContext<'js, '_> {\n    fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {\n        let obj = Object::new(ctx.clone())?;\n        obj.set(\"awsRequestId\", self.aws_request_id)?;\n        obj.set(\"invokedFunctionArn\", self.invoked_function_arn)?;\n        obj.set(\"logGroupName\", &self.lambda_environment.log_group_name)?;\n        obj.set(\"logStreamName\", &self.lambda_environment.log_stream_name)?;\n        obj.set(\"functionName\", &self.lambda_environment.function_name)?;\n        obj.set(\"functionVersion\", &self.lambda_environment.function_version)?;\n        obj.set(\n            \"memoryLimitInMB\",\n            self.lambda_environment.memory_limit_in_mb,\n        )?;\n        obj.set(\n            \"callbackWaitsForEmptyEventLoop\",\n            self.callback_waits_for_empty_event_loop,\n        )?;\n        obj.set(\n            \"getRemainingTimeInMillis\",\n            self.get_remaining_time_in_millis,\n        )?;\n        obj.set(\"clientContext\", self.client_context)?;\n        obj.set(\"cognitoIdentityJson\", self.cognito_identity_json)?;\n        Ok(obj.into_value())\n    }\n}\n\n#[derive(Clone)]\nstruct LambdaEnvironment {\n    pub log_group_name: String,\n    pub log_stream_name: String,\n    pub function_name: String,\n    pub function_version: String,\n    pub memory_limit_in_mb: usize,\n}\n\nimpl LambdaEnvironment {\n    fn new() -> Self {\n        Self {\n            log_group_name: env::var(ENV_AWS_LAMBDA_LOG_GROUP_NAME).unwrap_or_default(),\n            log_stream_name: env::var(ENV_AWS_LAMBDA_LOG_STREAM_NAME).unwrap_or_default(),\n            function_name: env::var(ENV_AWS_LAMBDA_FUNCTION_NAME).unwrap_or_default(),\n            function_version: env::var(ENV_AWS_LAMBDA_FUNCTION_VERSION).unwrap_or_default(),\n            memory_limit_in_mb: env::var(ENV_AWS_LAMBDA_FUNCTION_MEMORY_SIZE)\n                .unwrap_or(\"128\".into())\n                .parse()\n                .unwrap_or_default(),\n        }\n    }\n}\n\nstruct NextInvocationResponse<'js, 'a> {\n    event: Value<'js>,\n    context: LambdaContext<'js, 'a>,\n}\n\nstruct RuntimeConfig {\n    runtime_api: String,\n    handler: String,\n    iterations: usize,\n}\n\nimpl RuntimeConfig {\n    fn default(ctx: &Ctx) -> Result<Self> {\n        Ok(Self {\n            runtime_api: env::var(AWS_LAMBDA_RUNTIME_API).map_err(|_| {\n                Exception::throw_message(\n                    ctx,\n                    concat!(\n                        \"Environment variable \",\n                        stringify!(AWS_LAMBDA_RUNTIME_API),\n                        \" is not defined.\",\n                    ),\n                )\n            })?,\n            handler: env::var(ENV_LAMBDA_HANDLER)\n                .or_else(|_| env::var(ENV_UNDERSCORE_HANDLER))\n                .map_err(|_| {\n                    Exception::throw_message(\n                        ctx,\n                        concat!(\n                            \"Environment variable \",\n                            stringify!(ENV_LAMBDA_HANDLER),\n                            \" or \",\n                            stringify!(ENV_UNDERSCORE_HANDLER),\n                            \" is not defined.\",\n                        ),\n                    )\n                })?,\n            iterations: env::var(ENV_UNDERSCORE_EXIT_ITERATIONS)\n                .ok()\n                .and_then(|i| i.parse().ok())\n                .unwrap_or_default(),\n        })\n    }\n}\n\npub async fn start(ctx: &Ctx<'_>) -> Result<()> {\n    start_with_cfg(ctx, RuntimeConfig::default(ctx)?).await\n}\n\nasync fn start_with_cfg(ctx: &Ctx<'_>, config: RuntimeConfig) -> Result<()> {\n    let (module_name, handler_name) = get_module_and_handler_name(ctx, &config.handler)?;\n    let task_root = get_task_root();\n\n    let rt = unsafe { qjs::JS_GetRuntime(ctx.as_raw().as_ptr()) };\n    {\n        let mut state_ref = SDK_CONNECTION_INIT_LATCH.write().unwrap();\n        state_ref.push(SdkClientInitState::new(rt));\n    }\n\n    let specifier: String = [task_root.as_str(), module_name].join(\"/\");\n\n    let import_promise = Module::import(ctx, specifier.as_bytes())?;\n\n    let latch = {\n        let state_ref = SDK_CONNECTION_INIT_LATCH.read().unwrap();\n        get_sdk_client_init_state(&state_ref, rt).latch.clone()\n    };\n    latch.wait().await;\n\n    let js_handler_module = import_promise.into_future::<Object>().await?;\n\n    let handler: Value = js_handler_module.get(handler_name)?;\n\n    if !handler.is_function() {\n        return Err(Exception::throw_message(\n            ctx,\n            &[\n                \"\\\"\",\n                handler_name,\n                \"\\\" is not a function in \\\"\",\n                module_name,\n                \"\\\"\",\n            ]\n            .concat(),\n        ));\n    }\n\n    let client = HTTP_CLIENT.as_ref().or_throw(ctx)?.clone();\n\n    let base_url = [\"http://\", &config.runtime_api, \"/\", ENV_RUNTIME_PATH].concat();\n    let handler = handler.as_function().unwrap();\n    if let Err(err) = start_process_events(ctx, &client, handler, base_url.as_str(), &config)\n        .await\n        .catch(ctx)\n    {\n        post_error(ctx, &client, &base_url, \"/init/error\", &err, None).await?;\n    }\n    Ok(())\n}\n\nasync fn next_invocation<'js, 'a>(\n    ctx: &Ctx<'js>,\n    client: &'a HyperClient,\n    uri: &str,\n    lambda_environment: &'a LambdaEnvironment,\n) -> Result<NextInvocationResponse<'js, 'a>> {\n    let req = Request::builder()\n        .method(\"GET\")\n        .uri(uri)\n        .header(CONTENT_TYPE, \"application/json\")\n        .body(BoxBody::new(Full::default()))\n        .or_throw(ctx)?;\n\n    let res = client.request(req).await.or_throw(ctx)?;\n\n    if res.status() != StatusCode::OK {\n        let res_bytes = res.collect().await.or_throw(ctx)?.to_bytes();\n        let res_str = String::from_utf8_lossy(res_bytes.as_ref());\n        return Err(Exception::throw_message(\n            ctx,\n            &[\"Unexpected /invocation/next response: \", &res_str].concat(),\n        ));\n    }\n\n    let headers = res.headers();\n\n    if let Some(trace_id_value) = headers.get(&HEADER_TRACE_ID) {\n        let trace_id_value = String::from_utf8_lossy(trace_id_value.as_bytes());\n        env::set_var(ENV_X_AMZN_TRACE_ID, trace_id_value.as_ref());\n    } else {\n        env::remove_var(ENV_X_AMZN_TRACE_ID);\n    };\n\n    let deadline_ms = get_header_value(headers, &HEADER_DEADLINE_MS)\n        .unwrap_or(\"0\".into())\n        .parse::<i64>()\n        .or_throw(ctx)?;\n\n    let get_remaining_time_in_millis = Func::from(move || {\n        let now = Timestamp::now();\n        deadline_ms - now.as_millisecond()\n    });\n    let get_remaining_time_in_millis = get_remaining_time_in_millis\n        .into_js(ctx)?\n        .into_function()\n        .unwrap();\n\n    let client_context = if let Some(json) = headers.get(&HEADER_CLIENT_CONTEXT) {\n        json_parse(ctx, json.as_bytes())\n    } else {\n        rquickjs::Undefined.into_js(ctx)\n    }?;\n    let cognito_identity_json = if let Some(json) = headers.get(&HEADER_COGNITO_IDENTITY) {\n        json_parse(ctx, json.as_bytes())\n    } else {\n        rquickjs::Undefined.into_js(ctx)\n    }?;\n    let context = LambdaContext {\n        aws_request_id: get_header_value(headers, &HEADER_REQUEST_ID).or_throw(ctx)?,\n        invoked_function_arn: get_header_value(headers, &HEADER_INVOKED_FUNCTION_ARN)\n            .unwrap_or(\"n/a\".into()),\n        callback_waits_for_empty_event_loop: true,\n        get_remaining_time_in_millis,\n        client_context,\n        cognito_identity_json,\n        lambda_environment,\n    };\n    let bytes = res.collect().await.or_throw(ctx)?.to_bytes();\n    let event: Value<'js> = json_parse(ctx, bytes)?;\n\n    Ok(NextInvocationResponse { event, context })\n}\n\nasync fn invoke_response<'js>(\n    ctx: &Ctx<'js>,\n    client: &HyperClient,\n    base_url: &str,\n    request_id: &str,\n    result: Value<'js>,\n) -> Result<()> {\n    let result_json = stringify::json_stringify(ctx, result)?;\n    let req = Request::builder()\n        .method(\"POST\")\n        .uri([base_url, \"/invocation/\", request_id, \"/response\"].concat())\n        .header(CONTENT_TYPE, \"application/json\")\n        .body(BoxBody::new(Full::from(bytes::Bytes::from(\n            result_json.unwrap_or_default(),\n        ))))\n        .or_throw(ctx)?;\n\n    let res = client.request(req).await.or_throw(ctx)?;\n    match res.status() {\n        StatusCode::ACCEPTED => Ok(()),\n        _ => {\n            let res_bytes = res.collect().await.or_throw(ctx)?.to_bytes();\n            let res_str = String::from_utf8_lossy(res_bytes.as_ref());\n            Err(Exception::throw_message(\n                ctx,\n                &[\"Unexpected /invocation/response response: \", &res_str].concat(),\n            ))\n        },\n    }\n}\n\n// handler: (event: any, context: Context) => Promise<any>\nasync fn start_process_events<'js>(\n    ctx: &Ctx<'js>,\n    client: &HyperClient,\n    handler: &Function<'js>,\n    base_url: &str,\n    config: &RuntimeConfig,\n) -> Result<()> {\n    let mut iterations = 0;\n    let next_invocation_url = [base_url, \"/invocation/next\"].concat();\n\n    let mut request_id = String::with_capacity(36); //length of uuid\n\n    let lambda_environment = LambdaEnvironment::new();\n\n    let promise_ctor: Value = ctx.globals().get(PredefinedAtom::Promise)?;\n\n    loop {\n        let now = Instant::now();\n\n        if let Err(err) = process_event(\n            ctx,\n            client,\n            handler,\n            base_url,\n            &next_invocation_url,\n            &mut request_id,\n            &lambda_environment,\n            &promise_ctor,\n        )\n        .await\n        {\n            if request_id.is_empty() {\n                return Err(err)?;\n            }\n\n            let err = CaughtError::from_error(ctx, err);\n\n            let error_path = [\"/invocation/\", &request_id, \"/error\"].concat();\n            post_error(ctx, client, base_url, &error_path, &err, Some(&request_id)).await?;\n        }\n        if config.iterations > 0 {\n            if iterations >= config.iterations - 1 {\n                info!(\"Done in {:?}\", now.elapsed().as_millis());\n                break;\n            }\n            iterations += 1;\n        }\n        request_id.clear();\n    }\n    Ok(())\n}\n\n#[allow(clippy::too_many_arguments)]\nasync fn process_event<'js>(\n    ctx: &Ctx<'js>,\n    client: &HyperClient,\n    handler: &Function<'js>,\n    base_url: &str,\n    next_invocation_url: &str,\n    request_id: &mut String,\n    lambda_environment: &LambdaEnvironment,\n    promise_constructor: &Value<'js>,\n) -> Result<()> {\n    let NextInvocationResponse { event, context } =\n        next_invocation(ctx, client, next_invocation_url, lambda_environment).await?;\n    request_id.clear();\n    request_id.push_str(&context.aws_request_id);\n    LAMBDA_REQUEST_ID\n        .write()\n        .unwrap()\n        .replace(context.aws_request_id.to_owned());\n\n    let js_context = context.into_js(ctx)?;\n    let handler_result =\n        handler.call::<_, Value>((event.clone(), js_context.as_value().clone()))?;\n\n    let result = match handler_result.as_object() {\n        Some(obj) if obj.is_instance_of(promise_constructor) => {\n            handler_result\n                .get::<Promise>()?\n                .into_future::<Value>()\n                .await?\n        },\n        _ => handler_result,\n    };\n    invoke_response(ctx, client, base_url, request_id, result).await?;\n    Ok(())\n}\n\nasync fn post_error<'js>(\n    ctx: &Ctx<'js>,\n    client: &HyperClient,\n    base_url: &str,\n    path: &str,\n    error: &CaughtError<'js>,\n    request_id: Option<&String>,\n) -> Result<()> {\n    let mut error_stack = None;\n    let mut error_type = None;\n    let error_msg = match error {\n        CaughtError::Error(err) => format!(\"Error: {:?}\", &err),\n        CaughtError::Exception(ex) => {\n            let error_name = get_class_name(ex)\n                .unwrap_or(None)\n                .unwrap_or(String::from(\"Error\"));\n\n            let mut str = String::with_capacity(100);\n            str.push_str(&error_name);\n            str.push_str(\": \");\n            str.push_str(&ex.message().unwrap_or_default());\n\n            error_type = Some(error_name);\n\n            if let Some(mut stack) = ex.stack() {\n                replace_newline_with_carriage_return(&mut stack);\n                error_stack = Some(stack);\n            }\n            str\n        },\n        CaughtError::Value(value) => {\n            let log_msg = format_values(ctx, Rest(vec![value.clone()]), false, true)\n                .unwrap_or(String::from(\"{unknown value}\"));\n            [\"Error: \", &log_msg].concat()\n        },\n    };\n\n    let error_type = error_type.unwrap_or_else(|| \"Error\".into());\n    let error_stack = error_stack.unwrap_or_default();\n\n    let error_object = Object::new(ctx.clone())?;\n    error_object.set(\"errorType\", &error_type)?;\n    error_object.set(\"errorMessage\", error_msg)?;\n    error_object.set(\"stackTrace\", error_stack)?;\n    error_object.set(\"requestId\", request_id.unwrap_or(&String::from(\"n/a\")))?;\n    let error_object = error_object.into_value();\n\n    #[cfg(not(test))]\n    {\n        log_error(ctx.clone(), Rest(vec![error_object.clone()]))?;\n    }\n\n    let error_body = json_stringify(ctx, error_object)?.unwrap_or_default();\n\n    let url = [base_url, path].concat();\n\n    let req = Request::builder()\n        .method(\"POST\")\n        .uri(url)\n        .header(CONTENT_TYPE, \"application/json\")\n        .header(&HEADER_ERROR_TYPE, error_type)\n        .body(BoxBody::new(Full::from(bytes::Bytes::from(error_body))))\n        .or_throw(ctx)?;\n    let res = client.request(req).await.or_throw(ctx)?;\n    if res.status() != StatusCode::ACCEPTED {\n        let res_bytes = res.collect().await.or_throw(ctx)?.to_bytes();\n        let res_str = String::from_utf8_lossy(res_bytes.as_ref());\n        return Err(Exception::throw_message(\n            ctx,\n            &[\"Unexpected \", path, \" response: \", &res_str].concat(),\n        ));\n    }\n    Ok(())\n}\n\nfn get_module_and_handler_name<'a>(ctx: &Ctx, handler: &'a str) -> Result<(&'a str, &'a str)> {\n    handler\n        .rfind('.')\n        .and_then(|pos| {\n            let (module_name, handler_name) = handler.split_at(pos);\n            if !module_name.is_empty() && handler_name.len() > 1 {\n                //removes the dot and make sure the length is greater than 0\n                Some((module_name, &handler_name[1..]))\n            } else {\n                None\n            }\n        })\n        .ok_or_else(|| {\n            Exception::throw_message(\n                ctx,\n                &[\n                    \"Invalid handler name or LAMBDA_HANDLER env value: \\\"\",\n                    handler,\n                    \"\\\": Should be in format {{filepath}}.{{method_name}}\",\n                ]\n                .concat(),\n            )\n        })\n}\n\nfn get_task_root() -> String {\n    env::var(ENV_LAMBDA_TASK_ROOT).unwrap_or_else(|_| {\n        env::current_dir()\n            .ok()\n            .and_then(|path| path.into_os_string().into_string().ok())\n            .unwrap_or_else(|| \"/\".to_string())\n    })\n}\n\nfn get_header_value(headers: &HeaderMap, header: &HeaderName) -> StdResult<String, String> {\n    headers\n        .get(header)\n        .map(|h| String::from_utf8_lossy(h.as_bytes()).to_string())\n        .ok_or_else(|| [\"Missing or invalid header: \", header.as_str()].concat())\n}\n\n#[cfg(test)]\nmod tests {\n\n    use hyper::header::CONTENT_TYPE;\n    use rquickjs::{async_with, CatchResultExt};\n    use wiremock::{matchers, Mock, MockServer, ResponseTemplate};\n\n    use crate::runtime_client::{\n        self, RuntimeConfig, ENV_RUNTIME_PATH, HEADER_INVOKED_FUNCTION_ARN, HEADER_REQUEST_ID,\n    };\n    use crate::vm::Vm;\n\n    #[tokio::test]\n    async fn runtime() {\n        let mock_server = MockServer::start().await;\n\n        fn uuid_v4() -> String {\n            let mut bytes = [0u8; 8];\n            for b in bytes.iter_mut() {\n                *b = rand::random();\n            }\n\n            format!(\n                \"{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}\",\n                bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]\n            )\n        }\n\n        Mock::given(matchers::method(\"GET\"))\n            .and(matchers::path(\"/\"))\n            .respond_with(ResponseTemplate::new(200))\n            .mount(&mock_server)\n            .await;\n\n        Mock::given(matchers::method(\"GET\"))\n            .and(matchers::path(format!(\n                \"{}/invocation/next\",\n                ENV_RUNTIME_PATH\n            )))\n            .respond_with(\n                ResponseTemplate::new(200)\n                    .insert_header(&HEADER_REQUEST_ID, uuid_v4())\n                    .insert_header(&HEADER_INVOKED_FUNCTION_ARN, \"n/a\")\n                    .set_body_string(r#\"{\"hello\": \"world\"}\"#),\n            )\n            .mount(&mock_server)\n            .await;\n\n        Mock::given(matchers::method(\"POST\"))\n            .and(matchers::path_regex(\n                r#\"invocation/[A-z0-9-]{1,}/response$\"#,\n            ))\n            .and(matchers::header(&CONTENT_TYPE, \"application/json\"))\n            .respond_with(ResponseTemplate::new(202))\n            .mount(&mock_server)\n            .await;\n\n        Mock::given(matchers::method(\"POST\"))\n            .and(matchers::path_regex(r#\"invocation/[A-z0-9-]{1,}/error$\"#))\n            .and(matchers::header(&CONTENT_TYPE, \"application/json\"))\n            .respond_with(ResponseTemplate::new(202))\n            .mount(&mock_server)\n            .await;\n\n        let runtime_api = format!(\"localhost:{}\", mock_server.address().port());\n\n        let vm = Vm::new().await.unwrap();\n\n        async fn run_with_handler(vm: &Vm, handler: &str, runtime_api: &str) {\n            println!(\"Testing {}\", handler);\n            let mock_config = RuntimeConfig {\n                runtime_api: runtime_api.into(),\n                handler: handler.into(),\n                iterations: 10,\n            };\n\n            async_with!(vm.ctx => |ctx|{\n                ctx.globals().set(\"__MOCK_ENDPOINT\", [\"http://\",runtime_api].concat()).unwrap();\n                runtime_client::start_with_cfg(&ctx,mock_config).await.catch(&ctx).unwrap()\n            })\n            .await;\n        }\n\n        run_with_handler(&vm, \"../fixtures/handler.handler\", &runtime_api).await;\n        run_with_handler(&vm, \"../fixtures/primitive-handler.handler\", &runtime_api).await;\n        run_with_handler(&vm, \"../fixtures/throwing-handler.handler\", &runtime_api).await;\n        run_with_handler(&vm, \"../fixtures/sdk-handler.handler\", &runtime_api).await;\n        run_with_handler(&vm, \"../fixtures/tla-webcall-handler.handler\", &runtime_api).await;\n        run_with_handler(&vm, \"../fixtures/cjs-handler.handler\", &runtime_api).await;\n\n        vm.runtime.idle().await;\n    }\n}\n"
  },
  {
    "path": "llrt_core/src/security.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{env, result::Result as StdResult};\n\nuse hyper::{http::uri::InvalidUri, Uri};\n\nuse crate::environment::{ENV_LLRT_NET_ALLOW, ENV_LLRT_NET_DENY};\nuse crate::modules::{fetch, net};\n\npub fn init() -> StdResult<(), Box<dyn std::error::Error + Send + Sync>> {\n    if let Ok(env_value) = env::var(ENV_LLRT_NET_ALLOW) {\n        let allow_list = build_access_list(env_value);\n        fetch::set_allow_list(build_http_access_list(&allow_list)?);\n        net::set_allow_list(allow_list);\n    }\n\n    if let Ok(env_value) = env::var(ENV_LLRT_NET_DENY) {\n        let deny_list = build_access_list(env_value);\n        fetch::set_deny_list(build_http_access_list(&deny_list)?);\n        net::set_deny_list(deny_list);\n    }\n\n    Ok(())\n}\n\nfn build_http_access_list(list: &[String]) -> StdResult<Vec<Uri>, InvalidUri> {\n    list.iter()\n        .flat_map(|entry| {\n            let with_http = [\"http://\", entry].concat();\n            let with_https = [\"https://\", entry].concat();\n            vec![with_http, with_https]\n        })\n        .map(|url| url.parse())\n        .collect()\n}\n\nfn build_access_list(env_value: String) -> Vec<String> {\n    env_value\n        .split_whitespace()\n        .map(|entry| {\n            //remove protocol\n            if let Some(idx) = entry.find(\"://\") {\n                entry[idx + 3..].to_string()\n            } else {\n                entry.to_string()\n            }\n        })\n        .collect()\n}\n"
  },
  {
    "path": "llrt_core/src/vm.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{env, result::Result as StdResult};\n\nuse rquickjs::{\n    context::EvalOptions, loader::FileResolver, prelude::Func, AsyncContext, AsyncRuntime,\n    CatchResultExt, Ctx, Error, Result, Value,\n};\n\nuse crate::libs::{\n    context::set_spawn_error_handler,\n    hooking::HOOKING_MODE,\n    json,\n    logging::print_error_and_exit,\n    numbers,\n    utils::{\n        clone::structured_clone,\n        primordials::{BasePrimordials, Primordial},\n        time,\n    },\n};\nuse crate::modules::{\n    async_hooks::promise_hook_tracker,\n    embedded::{loader::EmbeddedLoader, resolver::EmbeddedResolver},\n    module_builder::ModuleBuilder,\n    package::{loader::PackageLoader, resolver::PackageResolver},\n};\nuse crate::{environment, http, security};\n\npub struct Vm {\n    pub runtime: AsyncRuntime,\n    pub ctx: AsyncContext,\n}\n\npub struct VmOptions {\n    pub module_builder: ModuleBuilder,\n    pub max_stack_size: usize,\n    pub gc_threshold_mb: usize,\n}\n\nimpl Default for VmOptions {\n    fn default() -> Self {\n        #[allow(unused_mut)]\n        let mut module_builder = ModuleBuilder::default()\n            .with_global(crate::modules::embedded::init)\n            .with_global(crate::builtins_inspect::init)\n            .with_module(crate::modules::llrt::hex::LlrtHexModule)\n            .with_module(crate::modules::llrt::qjs::LlrtQjsModule)\n            .with_module(crate::modules::llrt::util::LlrtUtilModule)\n            .with_module(crate::modules::llrt::xml::LlrtXmlModule);\n\n        #[cfg(feature = \"lambda\")]\n        {\n            module_builder = module_builder\n                .with_global(crate::modules::console::init)\n                .with_module(crate::modules::console::ConsoleModule);\n        }\n\n        Self {\n            module_builder,\n            max_stack_size: 512 * 1024,\n            gc_threshold_mb: {\n                const DEFAULT_GC_THRESHOLD_MB: usize = 20;\n\n                let gc_threshold_mb: usize = env::var(environment::ENV_LLRT_GC_THRESHOLD_MB)\n                    .map(|threshold| threshold.parse().unwrap_or(DEFAULT_GC_THRESHOLD_MB))\n                    .unwrap_or(DEFAULT_GC_THRESHOLD_MB);\n\n                gc_threshold_mb * 1024 * 1024\n            },\n        }\n    }\n}\n\nimpl Vm {\n    pub const ENV_LAMBDA_TASK_ROOT: &'static str = \"LAMBDA_TASK_ROOT\";\n\n    pub async fn from_options(\n        vm_options: VmOptions,\n    ) -> StdResult<Self, Box<dyn std::error::Error + Send + Sync>> {\n        time::init();\n        http::init()?;\n        security::init()?;\n\n        let mut file_resolver = FileResolver::default();\n        let mut paths: Vec<&str> = Vec::with_capacity(10);\n\n        paths.push(\".\");\n\n        let task_root = env::var(Self::ENV_LAMBDA_TASK_ROOT).unwrap_or_else(|_| String::from(\"\"));\n        let task_root = task_root.as_str();\n        if cfg!(debug_assertions) {\n            paths.push(\"bundle\");\n        } else {\n            paths.push(\"/opt\");\n        }\n\n        if !task_root.is_empty() {\n            paths.push(task_root);\n        }\n\n        for path in paths.iter() {\n            file_resolver.add_path(*path);\n        }\n\n        let (module_resolver, module_loader, global_attachment) = vm_options.module_builder.build();\n        let resolver = (\n            module_resolver,\n            EmbeddedResolver,\n            PackageResolver,\n            file_resolver,\n        );\n        let loader = (module_loader, EmbeddedLoader, PackageLoader);\n\n        let runtime = AsyncRuntime::new()?;\n        runtime.set_max_stack_size(vm_options.max_stack_size).await;\n        runtime.set_gc_threshold(vm_options.gc_threshold_mb).await;\n        runtime.set_loader(resolver, loader).await;\n\n        let ctx = AsyncContext::full(&runtime).await?;\n        ctx.with(|ctx| {\n            (|| {\n                BasePrimordials::init(&ctx)?;\n                global_attachment.attach(&ctx)?;\n                self::init(&ctx)?;\n                Ok(())\n            })()\n            .catch(&ctx)\n            .unwrap_or_else(|err| print_error_and_exit(&ctx, err));\n            Ok::<_, Error>(())\n        })\n        .await?;\n\n        if HOOKING_MODE.to_owned() {\n            runtime.set_promise_hook(Some(promise_hook_tracker())).await;\n        }\n\n        Ok(Vm { runtime, ctx })\n    }\n\n    pub async fn new() -> StdResult<Self, Box<dyn std::error::Error + Send + Sync>> {\n        let vm = Self::from_options(VmOptions::default()).await?;\n        Ok(vm)\n    }\n\n    pub async fn run_with<F>(&self, f: F)\n    where\n        F: for<'js> FnOnce(&Ctx<'js>) -> Result<()> + std::marker::Send,\n    {\n        self.ctx\n            .with(|ctx| {\n                if let Err(err) = f(&ctx).catch(&ctx) {\n                    print_error_and_exit(&ctx, err);\n                }\n            })\n            .await;\n    }\n\n    pub async fn run<S: Into<Vec<u8>> + Send>(&self, source: S, strict: bool, global: bool) {\n        self.run_with(|ctx| {\n            let mut options = EvalOptions::default();\n            options.strict = strict;\n            options.promise = true;\n            options.global = global;\n            let _ = ctx.eval_with_options::<Value, _>(source, options)?;\n            Ok::<_, Error>(())\n        })\n        .await;\n    }\n\n    pub async fn run_file(&self, filename: impl AsRef<str>, strict: bool, global: bool) {\n        let source = [\n            r#\"import(\"\"#,\n            &filename.as_ref().replace('\\\\', \"/\"),\n            r#\"\").catch((e) => {console.error(e);process.exit(1)})\"#,\n        ]\n        .concat();\n\n        self.run(source, strict, global).await;\n    }\n\n    pub async fn run_bytecode(&self, bytecode: &[u8]) {\n        self.run_with(|ctx| {\n            EmbeddedLoader::load_bytecode_module(ctx.clone(), bytecode)\n                .map(|module| module.eval())\n                .map_err(|err| {\n                    eprintln!(\"Failed to evaluate module: {err:?}\");\n                    err\n                })\n                .map(|_| ())\n        })\n        .await;\n    }\n\n    pub async fn idle(self) -> StdResult<(), Box<dyn std::error::Error + Sync + Send>> {\n        self.runtime.idle().await;\n        Ok(())\n    }\n}\n\nfn init(ctx: &Ctx<'_>) -> Result<()> {\n    set_spawn_error_handler(|ctx, err| {\n        print_error_and_exit(ctx, err);\n    });\n\n    let globals = ctx.globals();\n\n    globals.set(\"__gc\", Func::from(|ctx: Ctx| ctx.run_gc()))?;\n    globals.set(\"global\", ctx.globals())?;\n    globals.set(\"self\", ctx.globals())?;\n    globals.set(\n        \"structuredClone\",\n        Func::from(|ctx, value, options| structured_clone(&ctx, value, options)),\n    )?;\n\n    numbers::redefine_prototype(ctx)?;\n    json::redefine_static_methods(ctx)?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "llrt_modules/Cargo.toml",
    "content": "[package]\nname = \"llrt_modules\"\ndescription = \"LLRT Modules for rquickjs\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\nreadme = \"README.md\"\n\n[features]\ndefault = [\"base\", \"console\", \"tls-ring\", \"crypto-rust\"]\nlambda = [\"base\"]\n\n# TLS crypto backend features\ntls-ring = [\"llrt_http?/tls-ring\", \"llrt_tls?/tls-ring\", \"llrt_fetch?/tls-ring\"]\ntls-aws-lc = [\n  \"llrt_http?/tls-aws-lc\",\n  \"llrt_tls?/tls-aws-lc\",\n  \"llrt_fetch?/tls-aws-lc\",\n]\ntls-graviola = [\n  \"llrt_http?/tls-graviola\",\n  \"llrt_tls?/tls-graviola\",\n  \"llrt_fetch?/tls-graviola\",\n]\ntls-openssl = [\"llrt_http?/tls-openssl\", \"llrt_tls?/tls-openssl\"]\n\n# Crypto provider features\ncrypto-rust = [\"llrt_crypto?/crypto-rust\"]\ncrypto-ring = [\"llrt_crypto?/crypto-ring\"]\ncrypto-ring-rust = [\"llrt_crypto?/crypto-ring-rust\"]\ncrypto-graviola = [\"llrt_crypto?/crypto-graviola\"]\ncrypto-graviola-rust = [\"llrt_crypto?/crypto-graviola-rust\"]\ncrypto-openssl = [\"llrt_crypto?/crypto-openssl\"]\n\n# OpenSSL vendored (builds OpenSSL from source)\nopenssl-vendored = [\"dep:openssl\", \"openssl/vendored\"]\n\nbase = [\n  \"abort\",\n  \"assert\",\n  \"async-hooks\",\n  \"buffer\",\n  \"child-process\",\n  \"crypto\",\n  \"dgram\",\n  \"dns\",\n  \"events\",\n  \"exceptions\",\n  \"fetch\",\n  \"fs\",\n  \"https\",\n  \"intl\",\n  \"navigator\",\n  \"net\",\n  \"os\",\n  \"path\",\n  \"perf-hooks\",\n  \"process\",\n  \"stream-web\",\n  \"string-decoder\",\n  \"temporal\",\n  \"timers\",\n  \"tls\",\n  \"tty\",\n  \"url\",\n  \"util\",\n  \"zlib\",\n]\n\n# Modules\nabort = [\"llrt_abort\"]\nassert = [\"llrt_assert\"]\nasync-hooks = [\"llrt_async_hooks\"]\nbuffer = [\"llrt_buffer\"]\nchild-process = [\"llrt_child_process\"]\nconsole = [\"llrt_console\"]\ncrypto = [\"llrt_crypto\"]\ndgram = [\"llrt_dgram\"]\ndns = [\"llrt_dns\"]\nevents = [\"llrt_events\"]\nexceptions = [\"llrt_exceptions\"]\nfetch = [\n  \"llrt_fetch\",\n  \"llrt_fetch?/http1\",\n  \"llrt_fetch?/http2\",\n  \"llrt_fetch?/compression-c\",\n  \"llrt_fetch?/webpki-roots\",\n]\nfs = [\"llrt_fs\"]\nhttps = [\n  \"llrt_http\",\n  \"llrt_http?/webpki-roots\",\n  \"llrt_http?/http1\",\n  \"llrt_http?/http2\",\n]\nintl = [\"llrt_intl\"]\nnavigator = [\"llrt_navigator\"]\nnet = [\"llrt_net\"]\nos = [\"llrt_os\"]\npath = [\"llrt_path\"]\nprocess = [\"llrt_process\"]\nperf-hooks = [\"llrt_perf_hooks\"]\nstream-web = [\"llrt_stream_web\"]\nstring-decoder = [\"llrt_string_decoder\"]\ntemporal = [\"llrt_temporal\"]\ntimers = [\"llrt_timers\"]\ntls = [\"llrt_tls\"]\ntty = [\"llrt_tty\"]\nurl = [\"llrt_url\"]\nutil = [\"llrt_util\"]\nzlib = [\"llrt_zlib\"]\n\n[dependencies]\nhome = { version = \"0.5\", default-features = false }\nllrt_hooking = { path = \"../libs/llrt_hooking\" }\nllrt_json = { path = \"../libs/llrt_json\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../libs/llrt_utils\" }\nonce_cell = { version = \"1\", features = [\"std\"], default-features = false }\nrquickjs = { version = \"0.11\", features = [\"loader\"], default-features = false }\nsimd-json = { version = \"0.17\", default-features = false }\ntokio = { version = \"1\", default-features = false }\ntracing = { version = \"0.1\", default-features = false }\n\n# Optional\nllrt_abort = { version = \"0.8.1-beta\", path = \"../modules/llrt_abort\", optional = true }\nllrt_assert = { version = \"0.8.1-beta\", path = \"../modules/llrt_assert\", optional = true }\nllrt_async_hooks = { version = \"0.8.1-beta\", path = \"../modules/llrt_async_hooks\", optional = true }\nllrt_buffer = { version = \"0.8.1-beta\", path = \"../modules/llrt_buffer\", optional = true }\nllrt_child_process = { version = \"0.8.1-beta\", path = \"../modules/llrt_child_process\", optional = true }\nllrt_console = { version = \"0.8.1-beta\", path = \"../modules/llrt_console\", optional = true }\nllrt_crypto = { version = \"0.8.1-beta\", path = \"../modules/llrt_crypto\", default-features = false, optional = true }\nllrt_dgram = { version = \"0.8.1-beta\", path = \"../modules/llrt_dgram\", optional = true }\nllrt_dns = { version = \"0.8.1-beta\", path = \"../modules/llrt_dns\", optional = true }\nllrt_events = { version = \"0.8.1-beta\", path = \"../modules/llrt_events\", optional = true }\nllrt_exceptions = { version = \"0.8.1-beta\", path = \"../modules/llrt_exceptions\", optional = true }\nllrt_fetch = { version = \"0.8.1-beta\", path = \"../modules/llrt_fetch\", default-features = false, optional = true }\nllrt_fs = { version = \"0.8.1-beta\", path = \"../modules/llrt_fs\", optional = true }\nllrt_http = { version = \"0.8.1-beta\", path = \"../modules/llrt_http\", default-features = false, optional = true }\nllrt_intl = { version = \"0.8.1-beta\", path = \"../modules/llrt_intl\", optional = true }\nllrt_navigator = { version = \"0.8.1-beta\", path = \"../modules/llrt_navigator\", optional = true }\nllrt_net = { version = \"0.8.1-beta\", path = \"../modules/llrt_net\", optional = true }\nllrt_os = { version = \"0.8.1-beta\", path = \"../modules/llrt_os\", default-features = false, optional = true }\nllrt_path = { version = \"0.8.1-beta\", path = \"../modules/llrt_path\", optional = true }\nllrt_process = { version = \"0.8.1-beta\", path = \"../modules/llrt_process\", optional = true }\nllrt_perf_hooks = { version = \"0.8.1-beta\", path = \"../modules/llrt_perf_hooks\", optional = true }\nllrt_stream_web = { version = \"0.8.1-beta\", path = \"../modules/llrt_stream_web\", optional = true }\nllrt_string_decoder = { version = \"0.8.1-beta\", path = \"../modules/llrt_string_decoder\", optional = true }\nllrt_temporal = { version = \"0.8.1-beta\", path = \"../modules/llrt_temporal\", optional = true }\nllrt_timers = { version = \"0.8.1-beta\", path = \"../modules/llrt_timers\", optional = true }\nllrt_tls = { version = \"0.8.1-beta\", path = \"../modules/llrt_tls\", default-features = false, optional = true }\nllrt_tty = { version = \"0.8.1-beta\", path = \"../modules/llrt_tty\", optional = true }\nllrt_url = { version = \"0.8.1-beta\", path = \"../modules/llrt_url\", optional = true }\nopenssl = { version = \"0.10\", optional = true }\nllrt_util = { version = \"0.8.1-beta\", path = \"../modules/llrt_util\", optional = true }\nllrt_zlib = { version = \"0.8.1-beta\", path = \"../modules/llrt_zlib\", optional = true }\n\n[dev-dependencies]\nllrt_test = { path = \"../libs/llrt_test\" }\ntokio = { version = \"1\", features = [\"macros\", \"rt\"] }\n"
  },
  {
    "path": "llrt_modules/README.md",
    "content": "# LLRT Modules\n\nLLRT Modules is a meta-module of [rquickjs](https://github.com/DelSkayn/rquickjs) modules that can be used independantly of LLRT (**L**ow **L**atency **R**un**t**ime). They aim to bring to [quickjs](https://bellard.org/quickjs/) APIs from [Node.js](https://nodejs.org/) and [WinterTC](https://wintertc.org/). You can use this meta-module, but each module is also a unique crate.\n\nLLRT (**L**ow **L**atency **R**un**t**ime) is a lightweight JavaScript runtime designed to address the growing demand for fast and efficient Serverless applications.\n\n## Usage\n\nThe package is not available in the crate registry yet, but you can clone the repo and import it as a local path.\n\nUse this script to set everything up:\n\n```bash\ncd your_project_dir\ngit clone https://github.com/awslabs/llrt.git\n\ncd llrt\nnpm i\nmake js\n```\n\nEach module has a feature flag, they are all enabled by default but if you prefer to can decide which one you need.\nCheck the [Compability matrix](#compatibility-matrix) for the full list.\n\n```toml\n[dependencies]\nllrt_modules = { path = \"llrt/llrt_modules\", default-features = true } # load from local path\nrquickjs = { version = \"0.11\", features = [\"full-async\"] }\ntokio = { version = \"1\", features = [\"full\"] }\n\n```\n\nOnce you have enable a module, you can import it in your runtime.\n\n> [!NOTE]\n> Some modules currently require that you call an `init` function **before** they evaluated.\n\n```rust\nuse llrt_modules::buffer;\nuse rquickjs::{async_with, context::EvalOptions, AsyncContext, AsyncRuntime, Error, Module};\n\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() -> Result<(), Error> {\n    let runtime = AsyncRuntime::new()?;\n    let context = AsyncContext::full(&runtime).await?;\n\n    async_with!(context => |ctx| {\n        buffer::init(&ctx)?;\n        let (_module, module_eval) = Module::evaluate_def::<buffer::BufferModule,_>(ctx.clone(), \"buffer\")?;\n        module_eval.into_future::<()>().await?;\n\n        let mut options = EvalOptions::default();\n        options.global = false;\n        if let Err(Error::Exception) = ctx.eval_with_options::<(), _>(\n            r#\"\n            import { Buffer } from \"node:buffer\";\n            Buffer.alloc(10);\n            \"#,\n            options\n        ){\n            println!(\"{:#?}\", ctx.catch());\n        };\n\n        Ok::<_, Error>(())\n    })\n    .await?;\n\n    Ok(())\n}\n```\n\nUsing ModuleBuilder makes it even simpler.\n\n```rust\nuse llrt_modules::module_builder::ModuleBuilder;\nuse rquickjs::{async_with, context::EvalOptions, AsyncContext, AsyncRuntime, Error, Module};\n\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() -> Result<(), Error> {\n    let runtime = AsyncRuntime::new()?;\n\n    let module_builder = ModuleBuilder::default();\n    let (module_resolver, module_loader, global_attachment) = module_builder.build();\n    runtime.set_loader((module_resolver,), (module_loader,)).await;\n\n    let context = AsyncContext::full(&runtime).await?;\n\n    async_with!(context => |ctx| {\n        global_attachment.attach(&ctx)?;\n\n        let mut options = EvalOptions::default();\n        options.global = false;\n        if let Err(Error::Exception) = ctx.eval_with_options::<(), _>(\n            r#\"\n            import { Buffer } from \"node:buffer\";\n            Buffer.alloc(10);\n            \"#,\n            options\n        ){\n            println!(\"{:#?}\", ctx.catch());\n        };\n\n        Ok::<_, Error>(())\n    })\n    .await?;\n\n    Ok(())\n}\n\n```\n\n## Compatibility matrix\n\n> [!NOTE]\n> Only a fraction of the Node.js APIs are supported. Below is a high level overview of partially supported APIs and modules.\n\n|                | Node.js | LLRT Modules | Feature          | Crate                 |\n| -------------- | ------- | ------------ | ---------------- | --------------------- |\n| abort          | ✔︎       | ✔︎️            | `abort`          | `llrt_abort`          |\n| assert         | ✔︎       | ⚠️           | `assert`         | `llrt_assert`         |\n| async_hooks    | ✔︎       | ⚠️           | `async-hooks`    | `llrt_async_hooks`    |\n| buffer         | ✔︎       | ⚠️           | `buffer`         | `llrt_buffer`         |\n| child process  | ✔︎       | ⚠️           | `child-process`  | `llrt_child_process`  |\n| console        | ✔︎       | ⚠️           | `console`        | `llrt_console`        |\n| crypto         | ✔︎       | ⚠️           | `crypto`         | `llrt_crypto`         |\n| dgram          | ✔︎       | ⚠️           | `dgram`          | `llrt_dgram`          |\n| dns            | ✔︎       | ⚠️           | `dns`            | `llrt_dns`            |\n| events         | ✔︎       | ⚠️           | `events`         | `llrt_events`         |\n| exceptions     | ✔︎       | ⚠️           | `exceptions`     | `llrt_exceptions`     |\n| fetch          | ✔︎       | ⚠️           | `fetch`          | `llrt_fetch`          |\n| fs/promises    | ✔︎       | ⚠️           | `fs`             | `llrt_fs`             |\n| fs             | ✔︎       | ⚠️           | `fs`             | `llrt_fs`             |\n| intl           | ✔︎       | ⚠️           | N/A              | `llrt_intl`           |\n| navigator      | ✔︎       | ⚠️           | `navigator`      | `llrt_navigator`      |\n| net            | ✔︎       | ⚠️           | `net`            | `llrt_net`            |\n| os             | ✔︎       | ⚠️           | `os`             | `llrt_os`             |\n| path           | ✔︎       | ⚠️           | `path`           | `llrt_path`           |\n| perf hooks     | ✔︎       | ⚠️           | `perf-hooks`     | `llrt_perf_hooks`     |\n| stream (lib)   | N/A     | ✔︎            | N/A              | `llrt_stream`         |\n| string_decoder | ✔︎       | ✔︎            | `string_decoder` | `llrt_string_decoder` |\n| timers         | ✔︎       | ⚠️           | `timers`         | `llrt_timers`         |\n| process        | ✔︎       | ⚠️           | `process`        | `llrt_process`        |\n| temporal       | ✔︎       | ⚠️           | N/A              | `llrt_temporal`       |\n| tty            | ✔︎       | ⚠️           | `tty`            | `llrt_tty`            |\n| url            | ✔︎       | ⚠️           | `url`            | `llrt_url`            |\n| util           | ✔︎       | ⚠️           | `util`           | `llrt_util`           |\n| zlib           | ✔︎       | ⚠️           | `zlib`           | `llrt_zlib`           |\n| Other modules  | ✔︎       | ✘            | N/A              | N/A                   |\n\n_⚠️ = partially supported_\n\n## License\n\nThis module is licensed under the Apache-2.0 License.\n"
  },
  {
    "path": "llrt_modules/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::env;\n\nuse once_cell::sync::Lazy;\n\npub mod module;\npub mod module_builder;\npub mod package;\n\npub use self::modules::*;\n\nmod modules {\n    #[cfg(feature = \"abort\")]\n    pub use llrt_abort as abort;\n    #[cfg(feature = \"assert\")]\n    pub use llrt_assert as assert;\n    #[cfg(feature = \"async-hooks\")]\n    pub use llrt_async_hooks as async_hooks;\n    #[cfg(feature = \"buffer\")]\n    pub use llrt_buffer as buffer;\n    #[cfg(feature = \"child-process\")]\n    pub use llrt_child_process as child_process;\n    #[cfg(feature = \"console\")]\n    pub use llrt_console as console;\n    #[cfg(feature = \"crypto\")]\n    pub use llrt_crypto as crypto;\n    #[cfg(feature = \"dgram\")]\n    pub use llrt_dgram as dgram;\n    #[cfg(feature = \"dns\")]\n    pub use llrt_dns as dns;\n    #[cfg(feature = \"events\")]\n    pub use llrt_events as events;\n    #[cfg(feature = \"exceptions\")]\n    pub use llrt_exceptions as exceptions;\n    #[cfg(feature = \"fetch\")]\n    pub use llrt_fetch as fetch;\n    #[cfg(feature = \"fs\")]\n    pub use llrt_fs as fs;\n    #[cfg(feature = \"https\")]\n    pub use llrt_http as https;\n    #[cfg(feature = \"intl\")]\n    pub use llrt_intl as intl;\n    #[cfg(feature = \"navigator\")]\n    pub use llrt_navigator as navigator;\n    #[cfg(feature = \"net\")]\n    pub use llrt_net as net;\n    #[cfg(feature = \"os\")]\n    pub use llrt_os as os;\n    #[cfg(feature = \"path\")]\n    pub use llrt_path as path;\n    #[cfg(feature = \"perf-hooks\")]\n    pub use llrt_perf_hooks as perf_hooks;\n    #[cfg(feature = \"process\")]\n    pub use llrt_process as process;\n    #[cfg(feature = \"stream-web\")]\n    pub use llrt_stream_web as stream_web;\n    #[cfg(feature = \"string-decoder\")]\n    pub use llrt_string_decoder as string_decoder;\n    #[cfg(feature = \"temporal\")]\n    pub use llrt_temporal as temporal;\n    #[cfg(feature = \"timers\")]\n    pub use llrt_timers as timers;\n    #[cfg(feature = \"tls\")]\n    pub use llrt_tls as tls;\n    #[cfg(feature = \"tty\")]\n    pub use llrt_tty as tty;\n    #[cfg(feature = \"url\")]\n    pub use llrt_url as url;\n    #[cfg(feature = \"util\")]\n    pub use llrt_util as util;\n    #[cfg(feature = \"zlib\")]\n    pub use llrt_zlib as zlib;\n}\n\npub const VERSION: &str = env!(\"CARGO_PKG_VERSION\");\n\n// added when .cjs files are imported\npub const CJS_IMPORT_PREFIX: &str = \"__cjs:\";\n// added to force CJS imports in loader\npub const CJS_LOADER_PREFIX: &str = \"__cjsm:\";\n\npub const ENV_LLRT_PLATFORM: &str = \"LLRT_PLATFORM\";\n\npub static LLRT_PLATFORM: Lazy<String> = Lazy::new(|| {\n    env::var(ENV_LLRT_PLATFORM)\n        .ok()\n        .filter(|platform| platform == \"node\")\n        .unwrap_or_else(|| \"browser\".to_string())\n});\n"
  },
  {
    "path": "llrt_modules/src/module/loader.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{\n    cell::{Cell, RefCell},\n    collections::HashMap,\n    rc::Rc,\n};\n\nuse llrt_utils::{any_of::AnyOf2, bytes::ObjectBytes, object::ObjectExt, result::ResultExt};\nuse rquickjs::{\n    loader::Loader,\n    module::ModuleDef,\n    prelude::{Func, Opt},\n    Ctx, Error, Module, Object, Result, Value,\n};\nuse tracing::trace;\n\nuse super::{Hook, ModuleHookState};\n\ntype LoadFn = for<'js> fn(Ctx<'js>, Vec<u8>) -> Result<Module<'js>>;\ntype Source<'js> = AnyOf2<String, ObjectBytes<'js>>;\n\n#[derive(Debug, Default)]\npub struct ModuleLoader {\n    modules: HashMap<String, LoadFn>,\n}\n\nimpl ModuleLoader {\n    fn load_func<'js, D: ModuleDef>(ctx: Ctx<'js>, name: Vec<u8>) -> Result<Module<'js>> {\n        Module::declare_def::<D, _>(ctx, name)\n    }\n\n    pub fn add_module<N: Into<String>, M: ModuleDef>(&mut self, name: N, _module: M) -> &mut Self {\n        self.modules.insert(name.into(), Self::load_func::<M>);\n        self\n    }\n\n    #[must_use]\n    pub fn with_module<N: Into<String>, M: ModuleDef>(mut self, name: N, module: M) -> Self {\n        self.add_module(name, module);\n        self\n    }\n}\n\nimpl Loader for ModuleLoader {\n    fn load<'js>(&mut self, ctx: &Ctx<'js>, name: &str) -> Result<Module<'js>> {\n        trace!(\"Try load '{}'\", name);\n        let (short_circuit, next_load, source) = module_hook_load(ctx, name)?;\n\n        if short_circuit {\n            trace!(\"+- Loading module via ShortCircuit: {}\\n\", name);\n            return match source {\n                AnyOf2::A(s) => Module::declare(ctx.clone(), name, s),\n                AnyOf2::B(b) => Module::declare(ctx.clone(), name, b.as_bytes(ctx)?),\n            };\n        };\n\n        let load = self\n            .modules\n            .remove(name)\n            .ok_or_else(|| Error::new_loading(name))?;\n\n        if next_load {\n            trace!(\"|  Determined as `nextResolve`: {}\", name);\n        } else {\n            trace!(\"|  Determined as `NormalCircuit`: {}\", name);\n        }\n\n        trace!(\"+- Loading module: {}\\n\", name);\n        (load)(ctx.clone(), Vec::from(name))\n    }\n}\n\npub fn module_hook_load<'js>(ctx: &Ctx<'js>, name: &str) -> Result<(bool, bool, Source<'js>)> {\n    let bind_state = ctx.userdata::<RefCell<ModuleHookState>>().or_throw(ctx)?;\n    let hooks = Rc::new(bind_state.borrow().hooks.clone());\n\n    if hooks.is_empty() {\n        return Ok((false, false, AnyOf2::A(\"\".into())));\n    }\n\n    let result = call_load_hooks(ctx, &hooks, name)?;\n\n    let short_circuit = result\n        .get_optional::<_, bool>(\"shortCircuit\")?\n        .unwrap_or(false);\n\n    let next_load = result\n        .get_optional::<_, bool>(\"__nextLoad\")?\n        .unwrap_or(false);\n\n    let source = result\n        .get_optional::<_, Source>(\"source\")?\n        .unwrap_or(AnyOf2::A(\"\".into()));\n\n    Ok((short_circuit, next_load, source))\n}\n\n#[allow(dependency_on_unit_never_type_fallback)]\nfn call_load_hooks<'js>(\n    ctx: &Ctx<'js>,\n    hooks: &Rc<Vec<Hook<'js>>>,\n    url: &str,\n) -> Result<Object<'js>> {\n    call_load_hooks_from(ctx, hooks, 0, url)\n}\n\nfn call_load_hooks_from<'js>(\n    ctx: &Ctx<'js>,\n    hooks: &Rc<Vec<Hook<'js>>>,\n    start_index: usize,\n    url: &str,\n) -> Result<Object<'js>> {\n    for index in start_index..hooks.len() {\n        let Some(load_fn) = &hooks[index].load else {\n            continue;\n        };\n\n        let called_next = Rc::new(Cell::new(false));\n        let called_next_ref = Rc::clone(&called_next);\n\n        let context = Object::new(ctx.clone())?;\n        let hooks_clone = Rc::clone(hooks);\n\n        let next_func = Func::new(\n            move |ctx: Ctx<'js>,\n                  new_url: String,\n                  _opt_ctx: Opt<Value<'js>>|\n                  -> Result<Object<'js>> {\n                called_next_ref.set(true);\n                call_load_hooks_from(&ctx, &hooks_clone, index + 1, &new_url)\n            },\n        );\n\n        let result = load_fn.call::<_, Object>((url, context, next_func))?;\n        result.set(\"__nextLoad\", called_next.get())?;\n\n        return Ok(result);\n    }\n\n    let obj = Object::new(ctx.clone())?;\n    obj.set(\"url\", url)?;\n    obj.set(\"shortCircuit\", false)?;\n    obj.set(\"__nextLoad\", false)?;\n    Ok(obj)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use llrt_test::test_async_with;\n    use rquickjs::Function;\n\n    #[tokio::test]\n    async fn test_hook_override_import() {\n        use llrt_test::ModuleEvaluator;\n\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                let _ = ctx.store_userdata(RefCell::new(ModuleHookState::default()));\n\n                let hook_code = r#\"\n                    globalThis.hookCalled = false;\n                    globalThis.nextLoadCalled = false;\n                    \n                    export function load(url, context, nextLoad) {\n                        globalThis.hookCalled = true;\n                        if (url === \"math\") {\n                            return {\n                                format: \"module\",\n                                shortCircuit: true,\n                                source: \"export function add(a, b) { return a + b + 1; }\"\n                            };\n                        }\n                        globalThis.nextLoadCalled = true;\n                        return nextLoad(url, context);\n                    }\n                \"#;\n\n                let hook_module = ModuleEvaluator::eval_js(ctx.clone(), \"hook\", hook_code)\n                    .await\n                    .unwrap();\n\n                let load_fn: Function = hook_module.get(\"load\").unwrap();\n                let hook = Hook {\n                    resolve: None,\n                    load: Some(load_fn),\n                };\n\n                let binding = ctx.userdata::<RefCell<ModuleHookState>>().unwrap();\n                binding.borrow_mut().hooks.push(hook);\n\n                let binding = ctx.userdata::<RefCell<ModuleHookState>>().unwrap();\n                let hooks = Rc::new(binding.borrow().hooks.clone());\n\n                let result = call_load_hooks(&ctx, &hooks, \"math\").unwrap();\n\n                let globals = ctx.globals();\n                assert!(globals.get::<_, bool>(\"hookCalled\").unwrap());\n                assert!(result.get::<_, bool>(\"shortCircuit\").unwrap());\n                assert_eq!(\n                    result.get::<_, String>(\"source\").unwrap(),\n                    \"export function add(a, b) { return a + b + 1; }\"\n                );\n\n                let result2 = call_load_hooks(&ctx, &hooks, \"other\").unwrap();\n                assert!(globals.get::<_, bool>(\"nextLoadCalled\").unwrap());\n                assert!(!result2.get::<_, bool>(\"shortCircuit\").unwrap());\n                assert_eq!(result2.get::<_, String>(\"url\").unwrap(), \"other\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_multiple_hooks_chain() {\n        use llrt_test::ModuleEvaluator;\n\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                let _ = ctx.store_userdata(RefCell::new(ModuleHookState::default()));\n\n                let hook1_code = r#\"\n                    export function load(url, context, nextLoad) {\n                        globalThis.hook1Called = true;\n                        if (url === \"skip\") {\n                            return nextLoad(url, context);\n                        }\n                        return nextLoad(\"modified-\" + url, context);\n                    }\n                \"#;\n\n                let hook2_code = r#\"\n                    export function load(url, context, nextLoad) {\n                        globalThis.hook2Called = true;\n                        globalThis.finalUrl = url;\n                        return {\n                            shortCircuit: true,\n                            source: \"export const value = 42;\"\n                        };\n                    }\n                \"#;\n\n                let hook1 = ModuleEvaluator::eval_js(ctx.clone(), \"hook1\", hook1_code)\n                    .await\n                    .unwrap();\n                let hook2 = ModuleEvaluator::eval_js(ctx.clone(), \"hook2\", hook2_code)\n                    .await\n                    .unwrap();\n\n                let binding = ctx.userdata::<RefCell<ModuleHookState>>().unwrap();\n                binding.borrow_mut().hooks.push(Hook {\n                    resolve: None,\n                    load: Some(hook1.get(\"load\").unwrap()),\n                });\n                binding.borrow_mut().hooks.push(Hook {\n                    resolve: None,\n                    load: Some(hook2.get(\"load\").unwrap()),\n                });\n\n                let binding = ctx.userdata::<RefCell<ModuleHookState>>().unwrap();\n                let hooks = Rc::new(binding.borrow().hooks.clone());\n\n                let result = call_load_hooks(&ctx, &hooks, \"test\").unwrap();\n\n                let globals = ctx.globals();\n                assert!(globals.get::<_, bool>(\"hook1Called\").unwrap());\n                assert!(globals.get::<_, bool>(\"hook2Called\").unwrap());\n                assert_eq!(\n                    globals.get::<_, String>(\"finalUrl\").unwrap(),\n                    \"modified-test\"\n                );\n                assert!(result.get::<_, bool>(\"shortCircuit\").unwrap());\n                assert_eq!(\n                    result.get::<_, String>(\"source\").unwrap(),\n                    \"export const value = 42;\"\n                );\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_hook_without_nextload() {\n        use llrt_test::ModuleEvaluator;\n\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                let _ = ctx.store_userdata(RefCell::new(ModuleHookState::default()));\n\n                let hook_code = r#\"\n                    export function load(url, context, nextLoad) {\n                        return {\n                            shortCircuit: true,\n                            source: \"export const intercepted = true;\"\n                        };\n                    }\n                \"#;\n\n                let hook_module = ModuleEvaluator::eval_js(ctx.clone(), \"hook\", hook_code)\n                    .await\n                    .unwrap();\n\n                let binding = ctx.userdata::<RefCell<ModuleHookState>>().unwrap();\n                binding.borrow_mut().hooks.push(Hook {\n                    resolve: None,\n                    load: Some(hook_module.get(\"load\").unwrap()),\n                });\n\n                let binding = ctx.userdata::<RefCell<ModuleHookState>>().unwrap();\n                let hooks = Rc::new(binding.borrow().hooks.clone());\n\n                let result = call_load_hooks(&ctx, &hooks, \"any\").unwrap();\n\n                assert!(result.get::<_, bool>(\"shortCircuit\").unwrap());\n                assert_eq!(\n                    result.get::<_, String>(\"source\").unwrap(),\n                    \"export const intercepted = true;\"\n                );\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_hook_passthrough_all() {\n        use llrt_test::ModuleEvaluator;\n\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                let _ = ctx.store_userdata(RefCell::new(ModuleHookState::default()));\n\n                let hook_code = r#\"\n                    export function load(url, context, nextLoad) {\n                        globalThis.passedThrough = url;\n                        return nextLoad(url, context);\n                    }\n                \"#;\n\n                let hook_module = ModuleEvaluator::eval_js(ctx.clone(), \"hook\", hook_code)\n                    .await\n                    .unwrap();\n\n                let binding = ctx.userdata::<RefCell<ModuleHookState>>().unwrap();\n                binding.borrow_mut().hooks.push(Hook {\n                    resolve: None,\n                    load: Some(hook_module.get(\"load\").unwrap()),\n                });\n\n                let binding = ctx.userdata::<RefCell<ModuleHookState>>().unwrap();\n                let hooks = Rc::new(binding.borrow().hooks.clone());\n\n                let result = call_load_hooks(&ctx, &hooks, \"passthrough\").unwrap();\n\n                let globals = ctx.globals();\n                assert_eq!(\n                    globals.get::<_, String>(\"passedThrough\").unwrap(),\n                    \"passthrough\"\n                );\n                assert!(!result.get::<_, bool>(\"shortCircuit\").unwrap());\n                assert_eq!(result.get::<_, String>(\"url\").unwrap(), \"passthrough\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_hook_conditional_intercept() {\n        use llrt_test::ModuleEvaluator;\n\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                let _ = ctx.store_userdata(RefCell::new(ModuleHookState::default()));\n\n                let hook_code = r#\"\n                    export function load(url, context, nextLoad) {\n                        if (url.startsWith(\"internal:\")) {\n                            return {\n                                shortCircuit: true,\n                                source: \"export const internal = true;\"\n                            };\n                        }\n                        return nextLoad(url, context);\n                    }\n                \"#;\n\n                let hook_module = ModuleEvaluator::eval_js(ctx.clone(), \"hook\", hook_code)\n                    .await\n                    .unwrap();\n\n                let binding = ctx.userdata::<RefCell<ModuleHookState>>().unwrap();\n                binding.borrow_mut().hooks.push(Hook {\n                    resolve: None,\n                    load: Some(hook_module.get(\"load\").unwrap()),\n                });\n\n                let binding = ctx.userdata::<RefCell<ModuleHookState>>().unwrap();\n                let hooks = Rc::new(binding.borrow().hooks.clone());\n\n                let result1 = call_load_hooks(&ctx, &hooks, \"internal:test\").unwrap();\n                assert!(result1.get::<_, bool>(\"shortCircuit\").unwrap());\n                assert_eq!(\n                    result1.get::<_, String>(\"source\").unwrap(),\n                    \"export const internal = true;\"\n                );\n\n                let result2 = call_load_hooks(&ctx, &hooks, \"external:test\").unwrap();\n                assert!(!result2.get::<_, bool>(\"shortCircuit\").unwrap());\n                assert_eq!(result2.get::<_, String>(\"url\").unwrap(), \"external:test\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_three_hooks_selective_intercept() {\n        use llrt_test::ModuleEvaluator;\n\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                let _ = ctx.store_userdata(RefCell::new(ModuleHookState::default()));\n\n                let hook1_code = r#\"\n                    export function load(url, context, nextLoad) {\n                        globalThis.order = [\"hook1\"];\n                        return nextLoad(url, context);\n                    }\n                \"#;\n\n                let hook2_code = r#\"\n                    export function load(url, context, nextLoad) {\n                        globalThis.order.push(\"hook2\");\n                        if (url === \"intercept-here\") {\n                            return {\n                                shortCircuit: true,\n                                source: \"export const from = 'hook2';\"\n                            };\n                        }\n                        return nextLoad(url, context);\n                    }\n                \"#;\n\n                let hook3_code = r#\"\n                    export function load(url, context, nextLoad) {\n                        globalThis.order.push(\"hook3\");\n                        return {\n                            shortCircuit: true,\n                            source: \"export const from = 'hook3';\"\n                        };\n                    }\n                \"#;\n\n                let hook1 = ModuleEvaluator::eval_js(ctx.clone(), \"hook1\", hook1_code)\n                    .await\n                    .unwrap();\n                let hook2 = ModuleEvaluator::eval_js(ctx.clone(), \"hook2\", hook2_code)\n                    .await\n                    .unwrap();\n                let hook3 = ModuleEvaluator::eval_js(ctx.clone(), \"hook3\", hook3_code)\n                    .await\n                    .unwrap();\n\n                let binding = ctx.userdata::<RefCell<ModuleHookState>>().unwrap();\n                binding.borrow_mut().hooks.push(Hook {\n                    resolve: None,\n                    load: Some(hook1.get(\"load\").unwrap()),\n                });\n                binding.borrow_mut().hooks.push(Hook {\n                    resolve: None,\n                    load: Some(hook2.get(\"load\").unwrap()),\n                });\n                binding.borrow_mut().hooks.push(Hook {\n                    resolve: None,\n                    load: Some(hook3.get(\"load\").unwrap()),\n                });\n\n                let binding = ctx.userdata::<RefCell<ModuleHookState>>().unwrap();\n                let hooks = Rc::new(binding.borrow().hooks.clone());\n\n                let result1 = call_load_hooks(&ctx, &hooks, \"intercept-here\").unwrap();\n                let globals = ctx.globals();\n                let order: Vec<String> = globals.get(\"order\").unwrap();\n                assert_eq!(order, vec![\"hook1\", \"hook2\"]);\n                assert_eq!(\n                    result1.get::<_, String>(\"source\").unwrap(),\n                    \"export const from = 'hook2';\"\n                );\n                assert!(result1.get::<_, bool>(\"shortCircuit\").unwrap());\n\n                let result2 = call_load_hooks(&ctx, &hooks, \"other\").unwrap();\n                let order2: Vec<String> = globals.get(\"order\").unwrap();\n                assert_eq!(order2, vec![\"hook1\", \"hook2\", \"hook3\"]);\n                assert_eq!(\n                    result2.get::<_, String>(\"source\").unwrap(),\n                    \"export const from = 'hook3';\"\n                );\n                assert!(result2.get::<_, bool>(\"shortCircuit\").unwrap());\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_hook_url_transformation_chain() {\n        use llrt_test::ModuleEvaluator;\n\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                let _ = ctx.store_userdata(RefCell::new(ModuleHookState::default()));\n\n                let hook1_code = r#\"\n                    export function load(url, context, nextLoad) {\n                        return nextLoad(url.replace(\"@\", \"node_modules/\"), context);\n                    }\n                \"#;\n\n                let hook2_code = r#\"\n                    export function load(url, context, nextLoad) {\n                        globalThis.transformedUrl = url;\n                        return nextLoad(url + \"/index.js\", context);\n                    }\n                \"#;\n\n                let hook3_code = r#\"\n                    export function load(url, context, nextLoad) {\n                        globalThis.finalUrl = url;\n                        return {\n                            shortCircuit: true,\n                            source: \"export default {};\"\n                        };\n                    }\n                \"#;\n\n                let hook1 = ModuleEvaluator::eval_js(ctx.clone(), \"hook1\", hook1_code)\n                    .await\n                    .unwrap();\n                let hook2 = ModuleEvaluator::eval_js(ctx.clone(), \"hook2\", hook2_code)\n                    .await\n                    .unwrap();\n                let hook3 = ModuleEvaluator::eval_js(ctx.clone(), \"hook3\", hook3_code)\n                    .await\n                    .unwrap();\n\n                let binding = ctx.userdata::<RefCell<ModuleHookState>>().unwrap();\n                binding.borrow_mut().hooks.push(Hook {\n                    resolve: None,\n                    load: Some(hook1.get(\"load\").unwrap()),\n                });\n                binding.borrow_mut().hooks.push(Hook {\n                    resolve: None,\n                    load: Some(hook2.get(\"load\").unwrap()),\n                });\n                binding.borrow_mut().hooks.push(Hook {\n                    resolve: None,\n                    load: Some(hook3.get(\"load\").unwrap()),\n                });\n\n                let binding = ctx.userdata::<RefCell<ModuleHookState>>().unwrap();\n                let hooks = Rc::new(binding.borrow().hooks.clone());\n\n                let result = call_load_hooks(&ctx, &hooks, \"@pkg/module\").unwrap();\n\n                let globals = ctx.globals();\n                assert_eq!(\n                    globals.get::<_, String>(\"transformedUrl\").unwrap(),\n                    \"node_modules/pkg/module\"\n                );\n                assert_eq!(\n                    globals.get::<_, String>(\"finalUrl\").unwrap(),\n                    \"node_modules/pkg/module/index.js\"\n                );\n                assert!(result.get::<_, bool>(\"shortCircuit\").unwrap());\n                assert_eq!(\n                    result.get::<_, String>(\"source\").unwrap(),\n                    \"export default {};\"\n                );\n            })\n        })\n        .await;\n    }\n}\n"
  },
  {
    "path": "llrt_modules/src/module/mod.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{\n    cell::RefCell,\n    collections::{HashMap, HashSet},\n    marker::PhantomData,\n    rc::Rc,\n};\n\nuse llrt_utils::{\n    ctx::CtxExt,\n    module::{export_default, ModuleInfo},\n    result::ResultExt,\n};\nuse rquickjs::{\n    module::{Declarations, Exports, ModuleDef},\n    object::Accessor,\n    prelude::Func,\n    Ctx, Error, Exception, Function, JsLifetime, Object, Result, Value,\n};\n\npub mod loader;\nmod require;\npub mod resolver;\n\nuse crate::CJS_IMPORT_PREFIX;\n\n#[derive(JsLifetime)]\npub struct ModuleNames<'js> {\n    list: HashSet<String>,\n    _marker: PhantomData<&'js ()>,\n}\n\nimpl ModuleNames<'_> {\n    pub fn new(names: HashSet<String>) -> Self {\n        Self {\n            list: names,\n            _marker: PhantomData,\n        }\n    }\n\n    pub fn get_list(&self) -> HashSet<String> {\n        self.list.clone()\n    }\n}\n\n#[derive(Default)]\npub struct RequireState<'js> {\n    pub cache: HashMap<Rc<str>, Value<'js>>,\n    pub exports: HashMap<Rc<str>, Value<'js>>,\n    pub progress: HashMap<Rc<str>, Object<'js>>,\n}\n\nunsafe impl<'js> JsLifetime<'js> for RequireState<'js> {\n    type Changed<'to> = RequireState<'to>;\n}\n\n#[derive(Clone, JsLifetime)]\nstruct Hook<'js> {\n    resolve: Option<Function<'js>>,\n    load: Option<Function<'js>>,\n}\n\n#[derive(JsLifetime)]\npub struct ModuleHookState<'js> {\n    hooks: Vec<Hook<'js>>,\n}\n\nimpl Default for ModuleHookState<'_> {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl ModuleHookState<'_> {\n    fn new() -> Self {\n        Self { hooks: Vec::new() }\n    }\n}\n\npub struct ModuleModule;\n\nfn create_require(ctx: Ctx<'_>) -> Result<Value<'_>> {\n    ctx.globals()\n        .get::<_, Function>(\"require\")\n        .map(|f| f.into())\n        .map_err(|_| Exception::throw_reference(&ctx, \"create_require is not supported\"))\n}\n\nfn is_builtin(ctx: Ctx<'_>, name: String) -> Result<bool> {\n    let module_list = ctx\n        .userdata::<ModuleNames>()\n        .ok_or_else(|| Exception::throw_reference(&ctx, \"is_builtin is not supported\"))?\n        .get_list();\n\n    Ok(module_list.contains(&name))\n}\n\npub fn register_hooks<'js>(ctx: Ctx<'js>, hooks_obj: Object<'js>) -> Result<()> {\n    let resolve = hooks_obj.get::<_, Function>(\"resolve\").ok();\n    let load = hooks_obj.get::<_, Function>(\"load\").ok();\n\n    let hook = Hook { resolve, load };\n\n    let binding = ctx.userdata::<RefCell<ModuleHookState>>().or_throw(&ctx)?;\n    let mut state = binding.borrow_mut();\n    state.hooks.push(hook);\n\n    Ok(())\n}\n\nimpl ModuleDef for ModuleModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(\"builtinModules\")?;\n        declare.declare(\"createRequire\")?;\n        declare.declare(\"isBuiltin\")?;\n        declare.declare(\"registerHooks\")?;\n        declare.declare(\"default\")?;\n\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        export_default(ctx, exports, |default| {\n            let module_list = ctx\n                .userdata::<ModuleNames>()\n                .map_or_else(HashSet::new, |v| v.get_list());\n\n            default.set(\"builtinModules\", module_list)?;\n            default.set(\"createRequire\", Func::from(create_require))?;\n            default.set(\"isBuiltin\", Func::from(is_builtin))?;\n            default.set(\"registerHooks\", Func::from(register_hooks))?;\n\n            Ok(())\n        })?;\n\n        Ok(())\n    }\n}\n\nimpl From<ModuleModule> for ModuleInfo<ModuleModule> {\n    fn from(val: ModuleModule) -> Self {\n        ModuleInfo {\n            name: \"module\",\n            module: val,\n        }\n    }\n}\n\npub fn init(ctx: &Ctx) -> Result<()> {\n    let globals = ctx.globals();\n\n    let _ = ctx.store_userdata(RefCell::new(RequireState::default()));\n    let _ = ctx.store_userdata(RefCell::new(ModuleHookState::default()));\n\n    let exports_accessor = Accessor::new(\n        |ctx| {\n            struct Args<'js>(Ctx<'js>);\n            let Args(ctx) = Args(ctx);\n            let name = ctx.get_script_or_module_name()?;\n            let name = name.trim_start_matches(CJS_IMPORT_PREFIX);\n\n            let binding = ctx.userdata::<RefCell<RequireState>>().unwrap();\n            let mut state = binding.borrow_mut();\n\n            if let Some(value) = state.exports.get(name) {\n                Ok::<_, Error>(value.clone())\n            } else {\n                let obj = Object::new(ctx.clone())?.into_value();\n                state.exports.insert(name.into(), obj.clone());\n                Ok::<_, Error>(obj)\n            }\n        },\n        |ctx, exports| {\n            struct Args<'js>(Ctx<'js>, Value<'js>);\n            let Args(ctx, exports) = Args(ctx, exports);\n            let name = ctx.get_script_or_module_name()?;\n            let name = name.trim_start_matches(CJS_IMPORT_PREFIX);\n            let binding = ctx.userdata::<RefCell<RequireState>>().unwrap();\n            let mut state = binding.borrow_mut();\n            state.exports.insert(name.into(), exports);\n            Ok::<_, Error>(())\n        },\n    )\n    .configurable()\n    .enumerable();\n\n    globals.prop(\"exports\", exports_accessor)?;\n    globals.set(\"require\", Func::from(require::require))?;\n\n    let module = Object::new(ctx.clone())?;\n    module.prop(\"exports\", exports_accessor)?;\n    globals.prop(\"module\", module)?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "llrt_modules/src/module/require.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{cell::RefCell, collections::HashSet, fs, rc::Rc};\n\nuse llrt_hooking::{invoke_async_hook, register_finalization_registry, HookType};\nuse llrt_json::parse::json_parse;\nuse llrt_utils::{ctx::CtxExt, io::BYTECODE_FILE_EXT, provider::ProviderType};\nuse rquickjs::{atom::PredefinedAtom, qjs, Ctx, Filter, Function, Module, Object, Result, Value};\nuse tokio::time::Instant;\nuse tracing::trace;\n\nuse crate::modules::{path::resolve_path, timers::poll_timers};\nuse crate::package::resolver::require_resolve;\nuse crate::CJS_IMPORT_PREFIX;\n\nuse super::{ModuleNames, RequireState};\n\npub fn require(ctx: Ctx<'_>, specifier: String) -> Result<Value<'_>> {\n    let globals = ctx.globals();\n    let hooked_fn: Option<Function> = globals.get(\"__require_hook\").ok();\n\n    struct Args<'js>(Ctx<'js>);\n    let Args(ctx) = Args(ctx);\n\n    let module_list = ctx\n        .userdata::<ModuleNames>()\n        .map_or_else(HashSet::new, |v| v.get_list());\n\n    let is_cjs_import = specifier.starts_with(CJS_IMPORT_PREFIX);\n\n    let import_name: Rc<str>;\n\n    let is_json = specifier.ends_with(\".json\");\n\n    trace!(\"Before specifier: {}\", specifier);\n\n    let import_specifier: Rc<str> = if !is_cjs_import {\n        let is_bytecode = specifier.ends_with(BYTECODE_FILE_EXT);\n        let is_bytecode_or_json = is_json || is_bytecode;\n        let specifier = if is_bytecode_or_json {\n            specifier\n        } else {\n            specifier\n                .trim_start_matches(\"node:\")\n                .trim_end_matches(\"/\")\n                .to_string()\n        };\n\n        if module_list.contains(specifier.as_str()) {\n            import_name = specifier.into();\n            import_name.clone()\n        } else {\n            let module_name = ctx.get_script_or_module_name()?;\n            let module_name = module_name.trim_start_matches(CJS_IMPORT_PREFIX);\n            let abs_path = resolve_path([module_name].iter())?;\n\n            let resolved_path =\n                require_resolve(&ctx, &specifier, &abs_path, hooked_fn, false)?.into_owned();\n            import_name = resolved_path.into();\n            if is_bytecode_or_json {\n                import_name.clone()\n            } else {\n                [CJS_IMPORT_PREFIX, &import_name].concat().into()\n            }\n        }\n    } else {\n        import_name = specifier[CJS_IMPORT_PREFIX.len()..].into();\n        specifier.into()\n    };\n\n    trace!(\"After specifier: {}\", import_specifier);\n\n    let binding = ctx.userdata::<RefCell<RequireState>>().unwrap();\n    let mut state = binding.borrow_mut();\n\n    if let Some(cached_value) = state.cache.get(import_name.as_ref()) {\n        return Ok(cached_value.clone());\n    }\n\n    if is_json {\n        let json = fs::read_to_string(import_name.as_ref())?;\n        let json = json_parse(&ctx, json)?;\n        state.cache.insert(import_name, json.clone());\n        return Ok(json);\n    }\n\n    if let Some(obj) = state.progress.get(&import_name) {\n        let value = obj.clone().into_value();\n        return Ok(value);\n    }\n\n    trace!(\"Require: {}\", import_specifier);\n\n    let obj = Object::new(ctx.clone())?;\n    state.progress.insert(import_name.clone(), obj.clone());\n    drop(state);\n\n    let import_promise = Module::import(&ctx, import_specifier.as_bytes())?;\n\n    let rt = unsafe { qjs::JS_GetRuntime(ctx.as_raw().as_ptr()) };\n\n    let mut deadline = Instant::now();\n\n    let mut executing_timers = Vec::new();\n\n    // SAFETY: Since it checks in advance whether it is an Object type, we can always get a pointer to the object.\n    let uid = unsafe { qjs::JS_VALUE_GET_PTR(obj.as_object().unwrap().as_raw()) } as usize;\n    register_finalization_registry(&ctx, obj.clone().into_value(), uid)?;\n    invoke_async_hook(&ctx, HookType::Init, ProviderType::TimerWrap, uid)?;\n\n    let imported_object = loop {\n        if let Some(x) = import_promise.result::<Object>() {\n            break x?;\n        }\n\n        if deadline < Instant::now() {\n            poll_timers(rt, &mut executing_timers, None, Some(&mut deadline))?;\n        }\n\n        ctx.execute_pending_job();\n    };\n\n    let binding = ctx.userdata::<RefCell<RequireState>>().unwrap();\n    let mut state = binding.borrow_mut();\n\n    let exports_obj = state.exports.get(&import_name).cloned();\n\n    state.progress.remove(import_name.as_ref());\n\n    if let Some(exports_obj) = exports_obj {\n        if exports_obj.type_of() == rquickjs::Type::Object {\n            drop(state);\n            let exports = unsafe { exports_obj.as_object().unwrap_unchecked() };\n\n            for prop in exports.own_props::<Value, Value>(Filter::new().private().string().symbol())\n            {\n                let (key, value) = prop?;\n                obj.set(key, value)?;\n            }\n        } else {\n            //we have explicitly set it\n            state.cache.insert(import_name, exports_obj.clone());\n            return Ok(exports_obj);\n        }\n    } else {\n        drop(state);\n    }\n\n    let binding = ctx.userdata::<RefCell<RequireState>>().unwrap();\n    let mut state = binding.borrow_mut();\n\n    let props = imported_object.props::<String, Value>();\n\n    let default_export: Option<Value> = imported_object.get(PredefinedAtom::Default)?;\n    if let Some(default_export) = default_export {\n        //if default export is object attach all named exports to\n        if let Some(default_object) = default_export.as_object() {\n            for prop in props {\n                let (key, value) = prop?;\n                if !default_object.contains_key(&key)? {\n                    default_object.set(key, value)?;\n                }\n            }\n            let default_object = default_object.clone().into_value();\n            state.cache.insert(import_name, default_object.clone());\n            return Ok(default_object);\n        }\n    }\n\n    for prop in props {\n        let (key, value) = prop?;\n        obj.set(key, value)?;\n    }\n\n    let value = obj.into_value();\n\n    state.cache.insert(import_name, value.clone());\n    Ok(value)\n}\n"
  },
  {
    "path": "llrt_modules/src/module/resolver.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{\n    cell::{Cell, RefCell},\n    collections::HashSet,\n    rc::Rc,\n};\n\nuse llrt_utils::{object::ObjectExt, result::ResultExt};\nuse rquickjs::{\n    loader::Resolver,\n    prelude::{Func, Opt},\n    Ctx, Error, Object, Result, Value,\n};\nuse tracing::trace;\n\nuse crate::CJS_IMPORT_PREFIX;\n\nuse super::{Hook, ModuleHookState};\n\n#[derive(Debug, Default)]\npub struct ModuleResolver {\n    modules: HashSet<String>,\n}\n\nimpl ModuleResolver {\n    #[must_use]\n    pub fn add_name<P: Into<String>>(mut self, path: P) -> Self {\n        self.modules.insert(path.into());\n        self\n    }\n}\n\nimpl Resolver for ModuleResolver {\n    fn resolve(&mut self, ctx: &Ctx<'_>, base: &str, name: &str) -> Result<String> {\n        let name = name.trim_start_matches(CJS_IMPORT_PREFIX);\n        let name = name.trim_start_matches(\"node:\").trim_end_matches(\"/\");\n\n        let base = base.trim_start_matches(CJS_IMPORT_PREFIX);\n\n        trace!(\"Try resolve '{}' from '{}'\", name, base);\n\n        let (short_circuit, next_resolve, x) = module_hook_resolve(ctx, name, base)?;\n\n        if short_circuit {\n            trace!(\"+- Resolved by `ShortCircuit`: {}\", x);\n            return Ok(x);\n        }\n\n        if next_resolve {\n            trace!(\"|  Determined as `nextResolve`: {}\", x);\n        } else {\n            trace!(\"|  Determined as `NormalCircuit`: {}\", x);\n        }\n\n        if self.modules.contains(&x) {\n            trace!(\"+- Resolved by `NativeModule`: {}\", x);\n            Ok(x)\n        } else {\n            Err(Error::new_resolving(base, x))\n        }\n    }\n}\n\npub fn module_hook_resolve<'js>(ctx: &Ctx<'js>, x: &str, y: &str) -> Result<(bool, bool, String)> {\n    trace!(\"|  module_hook_resolve(x, y):({}, {})\", x, y);\n\n    let bind_state = ctx.userdata::<RefCell<ModuleHookState>>().or_throw(ctx)?;\n    let hooks = Rc::new(bind_state.borrow().hooks.clone());\n\n    if hooks.is_empty() {\n        return Ok((false, false, x.into()));\n    }\n\n    let result = call_resolve_hooks(ctx, &hooks, x, y)?;\n\n    let short_circuit = result\n        .get_optional::<_, bool>(\"shortCircuit\")?\n        .unwrap_or(false);\n\n    let next_resolve = result\n        .get_optional::<_, bool>(\"__nextResolve\")?\n        .unwrap_or(false);\n\n    let url = result.get::<_, String>(\"url\")?;\n\n    Ok((short_circuit, next_resolve, url))\n}\n\n#[allow(dependency_on_unit_never_type_fallback)]\nfn call_resolve_hooks<'js>(\n    ctx: &Ctx<'js>,\n    hooks: &Rc<Vec<Hook<'js>>>,\n    spec: &str,\n    parent_url: &str,\n) -> Result<Object<'js>> {\n    call_resolve_hooks_from(ctx, hooks, 0, spec, parent_url)\n}\n\nfn call_resolve_hooks_from<'js>(\n    ctx: &Ctx<'js>,\n    hooks: &Rc<Vec<Hook<'js>>>,\n    start_index: usize,\n    spec: &str,\n    parent_url: &str,\n) -> Result<Object<'js>> {\n    for index in start_index..hooks.len() {\n        let Some(resolve_fn) = &hooks[index].resolve else {\n            continue;\n        };\n\n        let context = Object::new(ctx.clone())?;\n        context.set(\"parentURL\", parent_url)?;\n\n        let called_next = Rc::new(Cell::new(false));\n        let called_next_ref = Rc::clone(&called_next);\n\n        let spec_clone = spec.to_string();\n        let hooks_clone = Rc::clone(hooks);\n\n        let next_func = Func::new(\n            move |ctx: Ctx<'js>,\n                  new_spec: String,\n                  opt_ctx: Opt<Value<'js>>|\n                  -> Result<Object<'js>> {\n                let new_parent = if let Some(val) = opt_ctx.0 {\n                    if let Some(ctx_obj) = val.as_object() {\n                        ctx_obj\n                            .get::<_, String>(\"parentURL\")\n                            .unwrap_or_else(|_| spec_clone.clone())\n                    } else {\n                        spec_clone.clone()\n                    }\n                } else {\n                    spec_clone.clone()\n                };\n                called_next_ref.set(true);\n                call_resolve_hooks_from(&ctx, &hooks_clone, index + 1, &new_spec, &new_parent)\n            },\n        );\n\n        let result = resolve_fn.call::<_, Object>((spec, context, next_func))?;\n        result.set(\"__nextResolve\", called_next.get())?;\n\n        return Ok(result);\n    }\n\n    let obj = Object::new(ctx.clone())?;\n    obj.set(\"url\", spec)?;\n    obj.set(\"shortCircuit\", false)?;\n    obj.set(\"__nextResolve\", false)?;\n    Ok(obj)\n}\n"
  },
  {
    "path": "llrt_modules/src/module_builder.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::collections::HashSet;\n\nuse llrt_utils::module::ModuleInfo;\nuse rquickjs::{module::ModuleDef, Ctx, Result};\n\nuse crate::module::{loader::ModuleLoader, resolver::ModuleResolver, ModuleNames};\n\n#[derive(Debug, Default)]\npub struct GlobalAttachment {\n    names: HashSet<String>,\n    functions: Vec<fn(&Ctx<'_>) -> Result<()>>,\n}\n\nimpl GlobalAttachment {\n    pub fn add_function(mut self, init: fn(&Ctx<'_>) -> Result<()>) -> Self {\n        self.functions.push(init);\n        self\n    }\n\n    pub fn add_name<P: Into<String>>(mut self, path: P) -> Self {\n        self.names.insert(path.into());\n        self\n    }\n\n    pub fn attach(self, ctx: &Ctx<'_>) -> Result<()> {\n        if !self.names.is_empty() {\n            let _ = ctx.store_userdata(ModuleNames::new(self.names));\n        }\n        for init in self.functions {\n            init(ctx)?;\n        }\n        Ok(())\n    }\n}\n\npub struct ModuleBuilder {\n    module_resolver: ModuleResolver,\n    module_loader: ModuleLoader,\n    global_attachment: GlobalAttachment,\n}\n\nimpl Default for ModuleBuilder {\n    fn default() -> Self {\n        let mut builder = Self::new();\n\n        builder = builder\n            .with_global(crate::module::init)\n            .with_module(crate::module::ModuleModule);\n\n        #[cfg(feature = \"abort\")]\n        {\n            builder = builder.with_global(crate::modules::abort::init);\n        }\n        #[cfg(feature = \"assert\")]\n        {\n            builder = builder.with_module(crate::modules::assert::AssertModule);\n        }\n        #[cfg(feature = \"async-hooks\")]\n        {\n            builder = builder\n                .with_global(crate::modules::async_hooks::init)\n                .with_module(crate::modules::async_hooks::AsyncHooksModule);\n        }\n        #[cfg(feature = \"buffer\")]\n        {\n            builder = builder\n                .with_global(crate::modules::buffer::init)\n                .with_module(crate::modules::buffer::BufferModule);\n        }\n        #[cfg(feature = \"child-process\")]\n        {\n            builder = builder.with_module(crate::modules::child_process::ChildProcessModule);\n        }\n        #[cfg(feature = \"console\")]\n        {\n            builder = builder\n                .with_global(crate::modules::console::init)\n                .with_module(crate::modules::console::ConsoleModule);\n        }\n        #[cfg(feature = \"crypto\")]\n        {\n            builder = builder\n                .with_global(crate::modules::crypto::init)\n                .with_module(crate::modules::crypto::CryptoModule);\n        }\n        #[cfg(feature = \"dgram\")]\n        {\n            builder = builder.with_module(crate::modules::dgram::DgramModule);\n        }\n        #[cfg(feature = \"dns\")]\n        {\n            builder = builder.with_module(crate::modules::dns::DnsModule);\n        }\n        #[cfg(feature = \"events\")]\n        {\n            builder = builder\n                .with_global(crate::modules::events::init)\n                .with_module(crate::modules::events::EventsModule);\n        }\n        #[cfg(feature = \"exceptions\")]\n        {\n            builder = builder.with_global(crate::modules::exceptions::init);\n        }\n        #[cfg(feature = \"https\")]\n        {\n            builder = builder.with_module(crate::modules::https::HttpsModule);\n        }\n        #[cfg(feature = \"fetch\")]\n        {\n            builder = builder.with_global(crate::modules::fetch::init);\n        }\n        #[cfg(feature = \"fs\")]\n        {\n            builder = builder\n                .with_module(crate::modules::fs::FsPromisesModule)\n                .with_module(crate::modules::fs::FsModule);\n        }\n        #[cfg(feature = \"intl\")]\n        {\n            builder = builder.with_global(crate::modules::intl::init);\n        }\n        #[cfg(feature = \"navigator\")]\n        {\n            builder = builder.with_global(crate::modules::navigator::init);\n        }\n        #[cfg(feature = \"net\")]\n        {\n            builder = builder.with_module(crate::modules::net::NetModule);\n        }\n        #[cfg(feature = \"os\")]\n        {\n            builder = builder.with_module(crate::modules::os::OsModule);\n        }\n        #[cfg(feature = \"path\")]\n        {\n            builder = builder.with_module(crate::modules::path::PathModule);\n        }\n        #[cfg(feature = \"perf-hooks\")]\n        {\n            builder = builder\n                .with_global(crate::modules::perf_hooks::init)\n                .with_module(crate::modules::perf_hooks::PerfHooksModule);\n        }\n        #[cfg(feature = \"process\")]\n        {\n            builder = builder\n                .with_global(crate::modules::process::init)\n                .with_module(crate::modules::process::ProcessModule);\n        }\n        #[cfg(feature = \"stream-web\")]\n        {\n            builder = builder\n                .with_global(crate::modules::stream_web::init)\n                .with_module(crate::modules::stream_web::StreamWebModule);\n        }\n        #[cfg(feature = \"string-decoder\")]\n        {\n            builder = builder.with_module(crate::modules::string_decoder::StringDecoderModule);\n        }\n        #[cfg(feature = \"temporal\")]\n        {\n            builder = builder.with_global(crate::modules::temporal::init);\n        }\n        #[cfg(feature = \"timers\")]\n        {\n            builder = builder\n                .with_global(crate::modules::timers::init)\n                .with_module(crate::modules::timers::TimersModule);\n        }\n        #[cfg(feature = \"tty\")]\n        {\n            builder = builder.with_module(crate::modules::tty::TtyModule);\n        }\n        #[cfg(feature = \"url\")]\n        {\n            builder = builder\n                .with_global(crate::modules::url::init)\n                .with_module(crate::modules::url::UrlModule);\n        }\n        #[cfg(feature = \"util\")]\n        {\n            builder = builder\n                .with_global(crate::modules::util::init)\n                .with_module(crate::modules::util::UtilModule);\n        }\n        #[cfg(feature = \"zlib\")]\n        {\n            builder = builder.with_module(crate::modules::zlib::ZlibModule);\n        }\n\n        builder\n    }\n}\n\nimpl ModuleBuilder {\n    pub fn new() -> Self {\n        Self {\n            module_resolver: ModuleResolver::default(),\n            module_loader: ModuleLoader::default(),\n            global_attachment: GlobalAttachment::default(),\n        }\n    }\n\n    pub fn with_module<M: ModuleDef, I: Into<ModuleInfo<M>>>(mut self, module: I) -> Self {\n        let module_info: ModuleInfo<M> = module.into();\n\n        self.module_resolver = self.module_resolver.add_name(module_info.name);\n        self.module_loader = self\n            .module_loader\n            .with_module(module_info.name, module_info.module);\n        self.global_attachment = self.global_attachment.add_name(module_info.name);\n        self\n    }\n\n    pub fn with_global(mut self, init: fn(&Ctx<'_>) -> Result<()>) -> Self {\n        self.global_attachment = self.global_attachment.add_function(init);\n        self\n    }\n\n    pub fn build(self) -> (ModuleResolver, ModuleLoader, GlobalAttachment) {\n        (\n            self.module_resolver,\n            self.module_loader,\n            self.global_attachment,\n        )\n    }\n}\n"
  },
  {
    "path": "llrt_modules/src/package/loader.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{fs::File, io::Read};\n\nuse rquickjs::{loader::Loader, Ctx, Function, Module, Object, Result, Value};\nuse tracing::trace;\n\nuse crate::{CJS_IMPORT_PREFIX, CJS_LOADER_PREFIX};\n\n#[derive(Debug, Default)]\npub struct PackageLoader;\n\nimpl PackageLoader {\n    fn load_cjs_module<'js>(name: &str, ctx: Ctx<'js>) -> Result<Module<'js>> {\n        let cjs_specifier = [CJS_IMPORT_PREFIX, name].concat();\n        let require: Function = ctx.globals().get(\"require\")?;\n        let export_object: Value = require.call((&cjs_specifier,))?;\n        let mut module = String::with_capacity(name.len() + 512);\n        module.push_str(\"const value = require(\\\"\");\n\n        module.push_str(name);\n        module.push_str(\"\\\");export default value.default||value;\");\n        if let Some(obj) = export_object.as_object() {\n            let keys: Result<Vec<String>> = obj.keys().collect();\n            let keys = keys?;\n\n            if !keys.is_empty() {\n                module.push_str(\"const{\");\n\n                for p in keys.iter() {\n                    if p == \"default\" {\n                        continue;\n                    }\n                    module.push_str(p);\n                    module.push(',');\n                }\n                module.truncate(module.len() - 1);\n                module.push_str(\"}=value;\");\n                module.push_str(\"export{\");\n                for p in keys.iter() {\n                    if p == \"default\" {\n                        continue;\n                    }\n                    module.push_str(p);\n                    module.push(',');\n                }\n                module.truncate(module.len() - 1);\n                module.push_str(\"};\");\n            }\n        }\n        Module::declare(ctx, name, module)\n    }\n\n    fn normalize_name(name: &str) -> (bool, bool, &str, &str) {\n        if !name.starts_with(\"__\") {\n            // If name doesn’t start with \"__\", return defaults\n            return (false, false, name, name);\n        }\n\n        if let Some(cjs_path) = name.strip_prefix(CJS_IMPORT_PREFIX) {\n            // If it starts with CJS_IMPORT_PREFIX, mark as from_cjs_import\n            return (true, false, name, cjs_path);\n        }\n\n        if let Some(cjs_path) = name.strip_prefix(CJS_LOADER_PREFIX) {\n            // If it starts with CJS_LOADER_PREFIX, mark as is_cjs\n            return (false, true, cjs_path, cjs_path);\n        }\n\n        // Default return if no prefixes match\n        (false, false, name, name)\n    }\n\n    fn load_module<'js>(name: &str, ctx: &Ctx<'js>) -> Result<(Module<'js>, Option<String>)> {\n        let ctx = ctx.clone();\n\n        let (from_cjs_import, is_cjs, normalized_name, path) = Self::normalize_name(name);\n\n        trace!(\"+- Loading module: {}\\n\", normalized_name);\n\n        //json files can never be from CJS imports as they are handled by require\n        if !from_cjs_import {\n            if normalized_name.ends_with(\".json\") {\n                let mut file = File::open(path)?;\n                let prefix = \"export default JSON.parse(`\";\n                let suffix = \"`);\";\n                let mut json = String::with_capacity(prefix.len() + suffix.len());\n                json.push_str(prefix);\n                file.read_to_string(&mut json)?;\n                json.push_str(suffix);\n\n                return Ok((Module::declare(ctx, path, json)?, None));\n            }\n            if is_cjs || normalized_name.ends_with(\".cjs\") {\n                let url = [\"file://\", path].concat();\n                return Ok((Self::load_cjs_module(path, ctx)?, Some(url)));\n            }\n        }\n\n        let bytes = std::fs::read(path)?;\n        let mut bytes: &[u8] = &bytes;\n\n        if !from_cjs_import && bytes.starts_with(b\"#!\") {\n            bytes = bytes.splitn(2, |&c| c == b'\\n').nth(1).unwrap_or(bytes);\n        }\n\n        let url = [\"file://\", path].concat();\n        Ok((Module::declare(ctx, normalized_name, bytes)?, Some(url)))\n    }\n}\n\nimpl Loader for PackageLoader {\n    fn load<'js>(&mut self, ctx: &Ctx<'js>, name: &str) -> Result<Module<'js>> {\n        trace!(\"Try load '{}'\", name);\n        let (module, url) = Self::load_module(name, ctx)?;\n        if let Some(url) = url {\n            let meta: Object = module.meta()?;\n            meta.prop(\"url\", url)?;\n        }\n\n        Ok(module)\n    }\n}\n"
  },
  {
    "path": "llrt_modules/src/package/mod.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\npub mod loader;\npub mod resolver;\n"
  },
  {
    "path": "llrt_modules/src/package/resolver.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{\n    borrow::Cow,\n    cell::RefCell,\n    collections::HashMap,\n    fs,\n    path::{Path, PathBuf},\n    rc::Rc,\n    sync::Mutex,\n};\n\nuse llrt_utils::{\n    io::{is_supported_ext, JS_EXTENSIONS, SUPPORTED_EXTENSIONS},\n    result::ResultExt,\n};\nuse once_cell::sync::Lazy;\nuse rquickjs::{loader::Resolver, Ctx, Error, Function, Result};\nuse simd_json::{derived::ValueObjectAccessAsScalar, BorrowedValue};\nuse tracing::trace;\n\nuse crate::modules::path;\nuse crate::{CJS_IMPORT_PREFIX, CJS_LOADER_PREFIX, LLRT_PLATFORM};\n\nfn rc_string_to_cow<'a>(rc: Rc<String>) -> Cow<'a, str> {\n    match Rc::try_unwrap(rc) {\n        Ok(string) => Cow::Owned(string),\n        Err(rc) => Cow::Owned((*rc).clone()),\n    }\n}\n\n#[derive(Clone, Debug)]\nstruct NodePathList(pub NodePathListValues);\n\ntype NodePathListValues = Rc<RefCell<Vec<Rc<str>>>>;\n\nunsafe impl Send for NodePathList {}\n\nimpl NodePathList {\n    fn new() -> Self {\n        Self(Rc::new(RefCell::new(Vec::new())))\n    }\n}\n\n//None entry means that there are no parent modules\ntype NodeModulePaths = HashMap<Box<str>, Option<NodePathList>>;\n\nstatic NODE_MODULES_PATHS_CACHE: Lazy<Mutex<NodeModulePaths>> =\n    Lazy::new(|| Mutex::new(HashMap::new()));\n\nstatic HOME_NODE_MODULES: Lazy<Vec<Box<str>>> = Lazy::new(|| {\n    // Add global folders\n    let mut paths = Vec::with_capacity(2);\n    if let Some(home) = home::home_dir() {\n        let home_node_modules = home.join(\".node_modules\");\n        let home_node_libraries = home.join(\".node_libraries\");\n        if home_node_modules.is_dir() {\n            paths.push(Box::from(home_node_modules.to_string_lossy()));\n        }\n        if home_node_libraries.is_dir() {\n            paths.push(Box::from(home_node_libraries.to_string_lossy()));\n        }\n    }\n    paths\n});\n\nstatic FILESYSTEM_ROOT: Lazy<Box<str>> = Lazy::new(|| {\n    #[cfg(unix)]\n    {\n        \"/\".into()\n    }\n    #[cfg(windows)]\n    {\n        if let Some(path) = home::home_dir() {\n            if let Some(std::path::Component::Prefix(prefix)) = path.components().next() {\n                return prefix\n                    .as_os_str()\n                    .to_string_lossy()\n                    .into_owned()\n                    .into_boxed_str();\n            }\n        }\n\n        \"C:\".to_string().into_boxed_str()\n    }\n});\n\n#[derive(Debug, Default)]\npub struct PackageResolver;\n\n#[allow(clippy::manual_strip)]\nimpl Resolver for PackageResolver {\n    fn resolve(&mut self, ctx: &Ctx, base: &str, name: &str) -> Result<String> {\n        if name.starts_with(CJS_IMPORT_PREFIX) {\n            return Ok(name.to_string());\n        }\n\n        let base = base.trim_start_matches(CJS_IMPORT_PREFIX);\n\n        trace!(\"Try resolve '{}' from '{}'\", name, base);\n\n        require_resolve(ctx, name, base, None, true).map(|name| name.into_owned())\n    }\n}\n\n// [CJS Reference Implementation](https://nodejs.org/api/modules.html#all-together)\n// require(X) from module at path Y\n#[allow(clippy::type_complexity)]\npub fn require_resolve<'a>(\n    ctx: &Ctx<'_>,\n    x: &'a str,\n    y: &str,\n    hooked_fn: Option<Function<'_>>,\n    is_esm: bool,\n) -> Result<Cow<'a, str>> {\n    // trim schema\n    let x = x.trim_start_matches(\"file://\");\n\n    // resolve symlink\n    let y = if let Ok(path) = Path::new(y).read_link() {\n        if path.is_absolute() {\n            path.to_string_lossy().to_string()\n        } else {\n            [y, \"/../\", path.to_string_lossy().as_ref()].concat()\n        }\n    } else {\n        y.to_string()\n    };\n    let y = y.as_str();\n\n    trace!(\"require_resolve(x, y):({}, {})\", x, y);\n\n    // 1'. If X is a bytecode cache,\n    if let Some(hooked_resolve) = hooked_fn {\n        if let Ok(path) = hooked_resolve.call::<_, String>((x, y)) {\n            return Ok(path.into());\n        }\n    }\n\n    //fast path for when we have supported extensions\n    let (_, ext_name) = path::name_extname(x);\n    let is_supported_ext = is_supported_ext(ext_name);\n\n    let x_is_absolute = path::is_absolute(x);\n    let x_starts_with_current_dir = x.starts_with(\"./\");\n    let x_starts_with_parent_dir = x.starts_with(\"..\");\n\n    if is_supported_ext && Path::new(x).is_file() {\n        return resolved_by_file_exists(x.into());\n    }\n\n    let x_normalized = path::normalize(x);\n    if !x_starts_with_parent_dir && is_supported_ext && Path::new(&x_normalized).is_file() {\n        return resolved_by_file_exists(x_normalized.into());\n    }\n\n    // 2. If X begins with '/'\n    let y = if path::is_absolute(x) {\n        // a. set Y to be the file system root\n        &*FILESYSTEM_ROOT\n    } else {\n        y\n    };\n\n    // Normalize path Y to generate dirname(Y)\n    let dirname_y = if Path::new(y).is_dir() {\n        path::resolve_path([y].iter())?\n    } else {\n        let dirname_y = path::dirname(y);\n        path::resolve_path([&dirname_y].iter())?\n    };\n\n    // 3. If X begins with './' or '/' or '../'\n    if x_starts_with_current_dir || x_is_absolute || x_starts_with_parent_dir {\n        let y_plus_x = if x_is_absolute {\n            x.into()\n        } else if x_starts_with_current_dir {\n            [&dirname_y, \"/\", &x[2..]].concat()\n        } else {\n            [&dirname_y, \"/\", x].concat()\n        };\n\n        let y_plus_x = Rc::new(y_plus_x);\n\n        // a. LOAD_AS_FILE(Y + X)\n        if let Ok(Some(path)) = load_as_file(ctx, y_plus_x.clone()) {\n            trace!(\"+- Resolved by `LOAD_AS_FILE`: {}\", path);\n            return to_abs_path(path);\n        } else {\n            // b. LOAD_AS_DIRECTORY(Y + X)\n            if let Ok(Some(path)) = load_as_directory(ctx, y_plus_x) {\n                trace!(\"+- Resolved by `LOAD_AS_DIRECTORY`: {}\", path);\n                return to_abs_path(path);\n            }\n        }\n\n        // c. THROW \"not found\"\n        return Err(Error::new_resolving(y.to_owned(), x.to_owned()));\n    }\n\n    // 4. If X begins with '#'\n    if x.starts_with('#') {\n        // a. LOAD_PACKAGE_IMPORTS(X, dirname(Y))\n        if let Ok(Some(path)) = load_package_imports(ctx, x, &dirname_y) {\n            trace!(\"+- Resolved by `LOAD_PACKAGE_IMPORTS`: {}\", path);\n            return Ok(path.into());\n        }\n    }\n\n    // 5. LOAD_PACKAGE_SELF(X, dirname(Y))\n    if let Ok(Some(path)) = load_package_self(ctx, x, &dirname_y, is_esm) {\n        trace!(\"+- Resolved by `LOAD_PACKAGE_SELF`: {}\", path);\n        return to_abs_path(path.into());\n    }\n\n    // 6. LOAD_NODE_MODULES(X, dirname(Y))\n    if let Some(path) = load_node_modules(ctx, x, dirname_y, is_esm) {\n        trace!(\"+- Resolved by `LOAD_NODE_MODULES`: {}\", path);\n        return Ok(path);\n    }\n\n    // 6.5. LOAD_AS_FILE(X)\n    if let Ok(Some(path)) = load_as_file(ctx, Rc::new(x.to_owned())) {\n        trace!(\"+- Resolved by `LOAD_AS_FILE`: {}\", path);\n        return to_abs_path(path);\n    }\n\n    // 7. THROW \"not found\"\n    Err(Error::new_resolving(y.to_string(), x.to_string()))\n}\n\nfn resolved_by_file_exists(path: Cow<'_, str>) -> Result<Cow<'_, str>> {\n    trace!(\"+- Resolved by `FILE`: {}\", path);\n    to_abs_path(path)\n}\n\nfn to_abs_path(path: Cow<'_, str>) -> Result<Cow<'_, str>> {\n    Ok(if !path::is_absolute(&path) {\n        path::resolve_path_with_separator([path], true)?.into()\n    } else if cfg!(windows) {\n        path::replace_backslash(path).into()\n    } else {\n        path\n    })\n}\n\n// LOAD_AS_FILE(X)\nfn load_as_file<'a>(ctx: &Ctx<'_>, x: Rc<String>) -> Result<Option<Cow<'a, str>>> {\n    trace!(\"|  load_as_file(x): {}\", x);\n\n    // 1. If X is a file, load X as its file extension format. STOP\n    if Path::new(x.as_ref()).is_file() {\n        trace!(\"|  load_as_file(1): {}\", x);\n        return Ok(Some(rc_string_to_cow(x)));\n    }\n\n    let mut base_file = String::with_capacity(x.len() + 4);\n    base_file.push_str(x.as_ref());\n    let base_file_length = base_file.len();\n\n    let mut base_file = Some(base_file);\n\n    // 2. If X.js is a file,\n    for extension in SUPPORTED_EXTENSIONS.iter() {\n        if let Some(mut current_file) = base_file.take() {\n            current_file.truncate(base_file_length);\n            current_file.push_str(extension);\n\n            if Path::new(&current_file).is_file() {\n                // a. Find the closest package scope SCOPE to X.\n                match find_the_closest_package_scope(&x) {\n                    // b. If no scope was found\n                    None => {\n                        // 1. MAYBE_DETECT_AND_LOAD(X.js)\n                        trace!(\"|  load_as_file(2.b.1): {}\", current_file);\n                        return Ok(Some(current_file.into()));\n                    },\n                    Some(path) => {\n                        let mut package_json = fs::read(path.as_ref()).or_throw(ctx)?;\n                        let package_json =\n                            simd_json::to_borrowed_value(&mut package_json).or_throw(ctx)?;\n                        // c. If the SCOPE/package.json contains \"type\" field,\n                        if let Some(_type) = get_string_field(&package_json, \"type\") {\n                            // 1. If the \"type\" field is \"module\", load X.js as an ECMAScript module. STOP.\n                            // 2. If the \"type\" field is \"commonjs\", load X.js as an CommonJS module. STOP.\n                            if _type == \"module\" || _type == \"commonjs\" {\n                                trace!(\"|  load_as_file(2.c.[1|2]): {}\", current_file);\n                                return Ok(Some(current_file.into()));\n                            }\n                        }\n                    },\n                }\n                // d. MAYBE_DETECT_AND_LOAD(X.js)\n                trace!(\"|  load_as_file(2.d): {}\", current_file);\n                return Ok(Some(current_file.into()));\n            }\n            base_file = Some(current_file);\n        }\n    }\n\n    // 3. If X.json is a file, load X.json to a JavaScript Object. STOP\n    if let Some(mut current_file) = base_file.take() {\n        current_file.truncate(base_file_length);\n        current_file.push_str(\".json\");\n        if Path::new(&current_file).is_file() {\n            trace!(\"|  load_as_file(3): {}\", current_file);\n            return Ok(Some(current_file.into()));\n        }\n    }\n\n    // 4. If X.node is a file, load X.node as binary addon. STOP\n\n    Ok(None)\n}\n\n// LOAD_INDEX(X)\nfn load_index<'a>(ctx: &Ctx<'_>, x: Rc<String>) -> Result<Option<Cow<'a, str>>> {\n    trace!(\"|  load_index(x): {}\", x);\n\n    let mut base_file = String::with_capacity(x.len() + \"/index\".len() + 4);\n    base_file.push_str(x.as_ref());\n    base_file.push_str(\"/index\");\n    let base_file_length = base_file.len();\n\n    let mut base_file = Some(base_file);\n\n    // 1. If X/index.js is a file\n    for extension in SUPPORTED_EXTENSIONS.iter() {\n        if let Some(mut file) = base_file.take() {\n            file.truncate(base_file_length);\n            file.push_str(extension);\n            if Path::new(&file).is_file() {\n                // a. Find the closest package scope SCOPE to X.\n                match find_the_closest_package_scope(&x) {\n                    // b. If no scope was found, load X/index.js as a CommonJS module. STOP.\n                    None => {\n                        trace!(\"|  load_index(1.b): {}\", file);\n                        return Ok(Some(file.into()));\n                    },\n                    // c. If the SCOPE/package.json contains \"type\" field,\n                    Some(path) => {\n                        let mut package_json = fs::read(path.as_ref()).or_throw(ctx)?;\n                        let package_json =\n                            simd_json::to_borrowed_value(&mut package_json).or_throw(ctx)?;\n                        if let Some(_type) = get_string_field(&package_json, \"type\") {\n                            // 1. If the \"type\" field is \"module\", load X/index.js as an ECMAScript module. STOP.\n                            if _type == \"module\" {\n                                trace!(\"|  load_index(1.c.1): {}\", file);\n                                return Ok(Some(file.into()));\n                            }\n                        }\n                        // 2. Else, load X/index.js as an CommonJS module. STOP.\n                        trace!(\"|  load_index(1.c.2): {}\", file);\n                        return Ok(Some(file.into()));\n                    },\n                }\n            }\n\n            base_file = Some(file);\n        }\n    }\n\n    // 2. If X/index.json is a file, parse X/index.json to a JavaScript object. STOP\n    if let Some(mut file) = base_file.take() {\n        file.truncate(base_file_length);\n        file.push_str(\".json\");\n        if Path::new(&file).is_file() {\n            trace!(\"|  load_index(2): {}\", file);\n            return Ok(Some(file.into()));\n        }\n    }\n\n    // 3. If X/index.node is a file, load X/index.node as binary addon. STOP\n\n    Ok(None)\n}\n\n// LOAD_AS_DIRECTORY(X)\nfn load_as_directory<'a>(ctx: &Ctx<'_>, x: Rc<String>) -> Result<Option<Cow<'a, str>>> {\n    trace!(\"|  load_as_directory(x): {}\", x);\n\n    // 1. If X/package.json is a file,\n    let file = [&x, \"/package.json\"].concat();\n    if Path::new(&file).is_file() {\n        // a. Parse X/package.json, and look for \"main\" field.\n        let mut package_json = fs::read(file).or_throw(ctx)?;\n        let package_json = simd_json::to_borrowed_value(&mut package_json).or_throw(ctx)?;\n        // b. If \"main\" is a falsy value, GOTO 2.\n        if let Some(main) = get_string_field(&package_json, \"main\") {\n            // c. let M = X + (json main field)\n            let m = Rc::new([&x, \"/\", main].concat());\n            // d. LOAD_AS_FILE(M)\n            if let Ok(Some(path)) = load_as_file(ctx, m.clone()) {\n                trace!(\"|  load_as_directory(1.d): {}\", path);\n                return Ok(Some(path));\n            }\n            // e. LOAD_INDEX(M)\n            if let Ok(Some(path)) = load_index(ctx, m) {\n                trace!(\"|  load_as_directory(1.e): {}\", path);\n                return Ok(Some(path));\n            }\n            // f. LOAD_INDEX(X) DEPRECATED\n\n            // g. THROW \"not found\"\n            return Err(Error::new_resolving(\"\", x.to_string()));\n        }\n    }\n\n    // 2. LOAD_INDEX(X)\n    if let Ok(Some(path)) = load_index(ctx, x) {\n        trace!(\"|  load_as_directory(2): {}\", path);\n        return Ok(Some(path));\n    }\n\n    Ok(None)\n}\n\n// LOAD_NODE_MODULES(X, START)\nfn load_node_modules<'a>(\n    ctx: &Ctx<'_>,\n    x: &str,\n    start: String,\n    is_esm: bool,\n) -> Option<Cow<'a, str>> {\n    trace!(\"|  load_node_modules(x, start): ({}, {})\", x, start);\n\n    fn search_dir<'a>(ctx: &Ctx<'_>, dir: &str, x: &str, is_esm: bool) -> Option<Cow<'a, str>> {\n        // a. LOAD_PACKAGE_EXPORTS(X, DIR)\n        if let Ok(path) = load_package_exports(ctx, x, dir, is_esm) {\n            trace!(\"|  load_node_modules(2.a): {}\", path);\n            return Some(path);\n        }\n        let dir_slash_x = Rc::new([dir, \"/\", x].concat());\n        // b. LOAD_AS_FILE(DIR/X)\n        if let Ok(Some(path)) = load_as_file(ctx, dir_slash_x.clone()) {\n            trace!(\"|  load_node_modules(2.b): {}\", path);\n            return Some(path);\n        }\n        // c. LOAD_AS_DIRECTORY(DIR/X)\n        if let Ok(Some(path)) = load_as_directory(ctx, dir_slash_x.clone()) {\n            trace!(\"|  load_node_modules(2.c): {}\", path);\n            return Some(path);\n        }\n        None\n    }\n\n    // 1. let DIRS = NODE_MODULES_PATHS(START)\n    let mut cache = NODE_MODULES_PATHS_CACHE.lock().unwrap();\n\n    let start = start.into_boxed_str();\n\n    //fast path\n    if let Some(Some(dirs)) = cache.get(&start) {\n        for dir in dirs.0.borrow().iter() {\n            if let Some(path) = search_dir(ctx, dir, x, is_esm) {\n                return Some(path);\n            }\n        }\n    }\n\n    let path = Path::new(start.as_ref());\n    let results = NodePathList::new();\n    let mut paths_to_cache = Vec::new();\n    let mut current = Some(path);\n\n    let mut i = 0;\n    let mut last_found_index = 0;\n    while let Some(dir) = current {\n        let str_dir = dir.to_string_lossy();\n        if let Some(dirs) = cache.get(str_dir.as_ref()) {\n            if let Some(dirs) = dirs {\n                results\n                    .0\n                    .borrow_mut()\n                    .extend(dirs.0.borrow().clone().into_iter());\n            }\n            last_found_index = i;\n\n            //there are no modules beyond this point, just search globals\n            break;\n        }\n        if dir.file_name().is_some_and(|name| name != \"node_modules\") {\n            let node_modules = dir.join(\"node_modules\");\n            if node_modules.is_dir() {\n                last_found_index = i;\n                results\n                    .0\n                    .borrow_mut()\n                    .push(node_modules.to_string_lossy().into());\n            }\n        }\n        paths_to_cache.push(str_dir);\n        current = dir.parent();\n        i += 1;\n    }\n\n    for (i, path) in paths_to_cache.iter().enumerate() {\n        let path = path.to_string().into_boxed_str();\n        if i <= last_found_index {\n            cache.insert(path, Some(results.clone()));\n        } else {\n            cache.insert(path, None);\n            break;\n        }\n    }\n\n    for dir in results.0.borrow().iter() {\n        if let Some(path) = search_dir(ctx, dir, x, is_esm) {\n            return Some(path);\n        }\n    }\n\n    for dir in HOME_NODE_MODULES.iter() {\n        if let Some(path) = search_dir(ctx, dir, x, is_esm) {\n            return Some(path);\n        }\n    }\n\n    None\n}\n\n// LOAD_PACKAGE_IMPORTS(X, DIR)\nfn load_package_imports(ctx: &Ctx<'_>, x: &str, dir: &str) -> Result<Option<String>> {\n    trace!(\"|  load_package_imports(x, dir): ({}, {})\", x, dir);\n\n    // 1. Find the closest package scope SCOPE to DIR.\n    // 2. If no scope was found, return.\n    if let Some(path) = find_the_closest_package_scope(dir) {\n        let mut package_json_file = fs::read(path.as_ref()).or_throw(ctx)?;\n        let package_json: BorrowedValue =\n            simd_json::to_borrowed_value(&mut package_json_file).or_throw(ctx)?;\n\n        // 3. If the SCOPE/package.json \"imports\" is null or undefined, return.\n        // 4. If `--experimental-require-module` is enabled\n        //   a. let CONDITIONS = [\"node\", \"require\", \"module-sync\"]\n        //   b. Else, let CONDITIONS = [\"node\", \"require\"]\n        // 5. let MATCH = PACKAGE_IMPORTS_RESOLVE(X, pathToFileURL(SCOPE),\n        //   CONDITIONS) <a href=\"esm.md#resolver-algorithm-specification\">defined in the ESM resolver</a>.\n        // 6. RESOLVE_ESM_MATCH(MATCH).\n        if let Some(module_path) = package_imports_resolve(&package_json, x) {\n            trace!(\"|  load_package_imports(6): {}\", module_path);\n            let dir = path.as_ref().trim_end_matches(\"package.json\");\n            let module_path = to_abs_path(correct_extensions([dir, module_path].concat()))?;\n            return Ok(Some(module_path.into()));\n        }\n    };\n\n    Ok(None)\n}\n\n// LOAD_PACKAGE_EXPORTS(X, DIR)\nfn load_package_exports<'a>(\n    ctx: &Ctx<'_>,\n    x: &str,\n    dir: &str,\n    is_esm: bool,\n) -> Result<Cow<'a, str>> {\n    trace!(\"|  load_package_exports(x, dir): ({}, {})\", x, dir);\n    //1. Try to interpret X as a combination of NAME and SUBPATH where the name\n    //   may have a @scope/ prefix and the subpath begins with a slash (`/`).\n    let mut n = 1;\n    let (mut name, mut scope, mut is_last) = get_name_and_scope(x, n);\n\n    //2. If X does not match this pattern or DIR/NAME/package.json is not a file,\n    //   return.\n    let mut package_json_path = String::with_capacity(dir.len() + 64);\n    package_json_path.push_str(dir);\n    package_json_path.push('/');\n    let base_path_length = package_json_path.len();\n\n    let mut package_json_exists;\n\n    loop {\n        trace!(\n            \"|  split name and scope(name, scope): ({}, {})\",\n            name,\n            scope\n        );\n        package_json_path.push_str(scope);\n        package_json_path.push_str(\"/package.json\");\n\n        package_json_exists = Path::new(&package_json_path).exists();\n\n        if package_json_exists || is_last {\n            break;\n        }\n        n += 1;\n        (name, scope, is_last) = get_name_and_scope(x, n);\n        package_json_path.truncate(base_path_length);\n    }\n\n    let mut sub_module = None;\n\n    let (scope, name) = if name != \".\" && !package_json_exists {\n        package_json_path.truncate(base_path_length);\n        package_json_path.push_str(x);\n        package_json_path.push_str(\"/package.json\");\n        if !Path::new(&package_json_path).exists() {\n            return Err(Error::new_resolving(dir.to_string(), x.to_string()));\n        }\n        (x, \".\")\n    } else {\n        let base_path = &package_json_path[..base_path_length];\n\n        let trimmed_name = name.trim_start_matches(\".\");\n        let mut path =\n            String::with_capacity(base_path.len() + scope.len() + trimmed_name.len() + 4);\n        path.push_str(base_path);\n        path.push_str(scope);\n        if !trimmed_name.is_empty() {\n            path.push('/');\n        }\n\n        path.push_str(trimmed_name);\n        let base_path_length = path.len();\n\n        let mut path = Some(path);\n\n        for ext in JS_EXTENSIONS {\n            if let Some(mut current_path) = path.take() {\n                current_path.truncate(base_path_length);\n                current_path.push_str(ext);\n\n                if Path::new(&current_path).exists() {\n                    if *ext == \".mjs\" {\n                        //we know its an ESM module\n                        return Ok(current_path.into());\n                    }\n                    sub_module = Some(current_path);\n                    break;\n                }\n                path = Some(current_path);\n            }\n        }\n        (scope, name)\n    };\n\n    //3. Parse DIR/NAME/package.json, and look for \"exports\" field.\n    //4. If \"exports\" is null or undefined, return.\n    //5. let MATCH = PACKAGE_EXPORTS_RESOLVE(pathToFileURL(DIR/NAME), \".\" + SUBPATH,\n    //   `package.json` \"exports\", [\"node\", \"require\"]) <a href=\"esm.md#resolver-algorithm-specification\">defined in the ESM resolver</a>.\n    //6. RESOLVE_ESM_MATCH(MATCH)\n    let mut package_json = fs::read(&package_json_path).or_throw(ctx)?;\n    let package_json = simd_json::to_borrowed_value(&mut package_json).or_throw(ctx)?;\n\n    if let Some(sub_module) = sub_module {\n        if package_json.get_str(\"type\") != Some(\"module\") {\n            let sub_module = to_abs_path(sub_module.into())?;\n            if is_esm {\n                return Ok([CJS_LOADER_PREFIX, &sub_module].concat().into());\n            }\n            return Ok(sub_module);\n        }\n        return Ok(sub_module.into());\n    }\n\n    let (module_path, resolve_path, is_cjs) = package_exports_resolve(&package_json, name, is_esm)?;\n    let module_path = resolve_path.unwrap_or_else(|| module_path.to_string());\n    let module_path = to_abs_path(correct_extensions(\n        [dir, \"/\", scope, \"/\", &module_path].concat(),\n    ))?;\n\n    if is_cjs && is_esm {\n        return Ok([CJS_LOADER_PREFIX, &module_path].concat().into());\n    }\n\n    Ok(module_path)\n}\n\n// LOAD_PACKAGE_SELF(X, DIR)\nfn load_package_self(ctx: &Ctx<'_>, x: &str, dir: &str, is_esm: bool) -> Result<Option<String>> {\n    trace!(\"|  load_package_self(x, dir): ({}, {})\", x, dir);\n    let mut n = 1;\n    let (mut name, mut scope, mut is_last) = get_name_and_scope(x, n);\n\n    // 1. Find the closest package scope SCOPE to DIR.\n    let mut package_json_file: Vec<u8>;\n    let package_json: BorrowedValue;\n    let package_json_path: Box<str> = match find_the_closest_package_scope(dir) {\n        // 2. If no scope was found, return.\n        None => {\n            return Ok(None);\n        },\n        Some(path) => {\n            package_json_file = fs::read(path.as_ref()).or_throw(ctx)?;\n            package_json = simd_json::to_borrowed_value(&mut package_json_file).or_throw(ctx)?;\n            // 3. If the SCOPE/package.json \"exports\" is null or undefined, return.\n            loop {\n                trace!(\n                    \"|  split name and scope(name, scope): ({}, {})\",\n                    name,\n                    scope\n                );\n                // 4. If the SCOPE/package.json \"name\" is not the first segment of X, return.\n                if is_exports_field_exists(&package_json) {\n                    if let Some(name) = get_string_field(&package_json, \"name\") {\n                        if name == scope {\n                            break path;\n                        }\n                    }\n                }\n                if is_last {\n                    return Ok(None);\n                }\n                n += 1;\n                (name, scope, is_last) = get_name_and_scope(x, n);\n            }\n        },\n    };\n    // 5. let MATCH = PACKAGE_EXPORTS_RESOLVE(pathToFileURL(SCOPE),\n    //    \".\" + X.slice(\"name\".length), `package.json` \"exports\", [\"node\", \"require\"])\n    //    <a href=\"esm.md#resolver-algorithm-specification\">defined in the ESM resolver</a>.\n    // 6. RESOLVE_ESM_MATCH(MATCH)\n    if let Ok((path, resolve_path, _)) = package_exports_resolve(&package_json, name, is_esm) {\n        let path = resolve_path.unwrap_or_else(|| path.to_string());\n        trace!(\"|  load_package_self(2.c): {}\", path);\n        let dir = package_json_path.trim_end_matches(\"package.json\");\n        let module_path = correct_extensions([dir, &path].concat());\n        return Ok(Some(module_path.into()));\n    }\n\n    Ok(None)\n}\n\nfn get_name_and_scope(x: &str, n: usize) -> (&str, &str, bool) {\n    if let Some(pos) = (0..n).try_fold(x.len(), |p, _| x[..p].rfind('/')) {\n        (&x[pos + 1..], &x[..pos], false)\n    } else {\n        (\".\", x, true)\n    }\n}\n\n// Implementation equivalent to PACKAGE_EXPORTS_RESOLVE including RESOLVE_ESM_MATCH\nfn package_exports_resolve<'a>(\n    package_json: &'a BorrowedValue<'a>,\n    modules_name: &str,\n    is_esm: bool,\n) -> Result<(&'a str, Option<String>, bool)> {\n    let ident = if is_esm { \"import\" } else { \"require\" };\n\n    let modules_name = if modules_name != \".\" {\n        &[\"./\", modules_name].concat()\n    } else {\n        modules_name\n    };\n\n    let wildcard = if let Some(pos) = modules_name.rmatch_indices('/').nth(1) {\n        let (name, scope, _) = get_name_and_scope(modules_name, pos.0);\n        (Some(name), Some([scope, \"/*\"].concat()))\n    } else {\n        (None, None)\n    };\n\n    if let BorrowedValue::Object(map) = package_json {\n        let is_cjs =\n            !matches!(map.get(\"type\"), Some(BorrowedValue::String(ref _type)) if _type == \"module\");\n\n        if let Some(BorrowedValue::Object(exports)) = map.get(\"exports\") {\n            if let Some(BorrowedValue::Object(name)) = exports.get(modules_name) {\n                // Check for exports -> name -> platform(browser or node) -> [import | require]\n                if let Some(BorrowedValue::Object(platform)) = name.get(LLRT_PLATFORM.as_str()) {\n                    if let Some(BorrowedValue::String(ident)) = platform.get(ident) {\n                        return Ok((ident.as_ref(), None, is_cjs));\n                    }\n                }\n                // Check for exports -> name -> [import | require] -> default\n                if let Some(BorrowedValue::Object(ident)) = name.get(ident) {\n                    if let Some(BorrowedValue::String(default)) = ident.get(\"default\") {\n                        return Ok((default.as_ref(), None, is_cjs));\n                    }\n                }\n                // Check for exports -> name -> platform(browser or node)\n                if let Some(BorrowedValue::String(platform)) = name.get(LLRT_PLATFORM.as_str()) {\n                    return Ok((platform.as_ref(), None, is_cjs));\n                }\n                // Check for exports -> name -> [import | require]\n                if let Some(BorrowedValue::String(ident)) = name.get(ident) {\n                    return Ok((ident.as_ref(), None, is_cjs));\n                }\n                // Check for exports -> name -> default\n                if let Some(BorrowedValue::String(default)) = name.get(\"default\") {\n                    return Ok((default.as_ref(), None, is_cjs));\n                }\n            }\n            // Check for wildcard pattern\n            if let Some(scope) = wildcard.1 {\n                // Check for exports -> scope -> platform(browser or node) -> [import | require]\n                if let Some(BorrowedValue::Object(name)) = exports.get(scope.as_str()) {\n                    if let Some(BorrowedValue::Object(platform)) = name.get(LLRT_PLATFORM.as_str())\n                    {\n                        if let Some(BorrowedValue::String(ident)) = platform.get(ident) {\n                            let resolve_star = replace_star(ident, wildcard.0.unwrap());\n                            return Ok((ident.as_ref(), Some(resolve_star), is_cjs));\n                        }\n                    }\n                    // Check for exports -> scope -> [import | require] -> default\n                    if let Some(BorrowedValue::Object(ident)) = name.get(ident) {\n                        if let Some(BorrowedValue::String(default)) = ident.get(\"default\") {\n                            let resolve_star = replace_star(default, wildcard.0.unwrap());\n                            return Ok((default.as_ref(), Some(resolve_star), is_cjs));\n                        }\n                    }\n                    // Check for exports -> scope -> platform(browser or node)\n                    if let Some(BorrowedValue::String(platform)) = name.get(LLRT_PLATFORM.as_str())\n                    {\n                        let resolve_star = replace_star(platform, wildcard.0.unwrap());\n                        return Ok((platform.as_ref(), Some(resolve_star), is_cjs));\n                    }\n                    // Check for exports -> scope -> [import | require]\n                    if let Some(BorrowedValue::String(ident)) = name.get(ident) {\n                        let resolve_star = replace_star(ident, wildcard.0.unwrap());\n                        return Ok((ident.as_ref(), Some(resolve_star), is_cjs));\n                    }\n                    //  Check for exports -> scope -> default\n                    if let Some(BorrowedValue::String(default)) = name.get(\"default\") {\n                        let resolve_star = replace_star(default, wildcard.0.unwrap());\n                        return Ok((default.as_ref(), Some(resolve_star), is_cjs));\n                    }\n                }\n            }\n            // Check for exports -> [import | require] -> default\n            if let Some(BorrowedValue::Object(ident)) = exports.get(ident) {\n                if let Some(BorrowedValue::String(default)) = ident.get(\"default\") {\n                    return Ok((default.as_ref(), None, is_cjs));\n                }\n            }\n            // Check for exports -> [import | require]\n            if let Some(BorrowedValue::String(ident)) = exports.get(ident) {\n                return Ok((ident.as_ref(), None, is_cjs));\n            }\n            // [CJS only] Check for exports -> default\n            if !is_esm {\n                if let Some(BorrowedValue::String(default)) = exports.get(\"default\") {\n                    return Ok((default.as_ref(), None, is_cjs));\n                }\n            }\n        }\n        // Check for platform(browser or node) field\n        if let Some(BorrowedValue::String(platform)) = map.get(LLRT_PLATFORM.as_str()) {\n            return Ok((platform.as_ref(), None, is_cjs));\n        }\n        // [ESM only] Check for module field\n        if is_esm {\n            if let Some(BorrowedValue::String(module)) = map.get(\"module\") {\n                return Ok((module.as_ref(), None, is_cjs));\n            }\n        }\n        // Check for main field\n        if let Some(BorrowedValue::String(main)) = map.get(\"main\") {\n            return Ok((main.as_ref(), None, is_cjs));\n        }\n    }\n    Ok((\"./index.js\", None, true))\n}\n\nfn replace_star(scope: &str, name: &str) -> String {\n    scope.replace(\"*\", name)\n}\n\n// Implementation equivalent to PACKAGE_IMPORTS_RESOLVE including RESOLVE_ESM_MATCH\nfn package_imports_resolve<'a>(\n    package_json: &'a BorrowedValue<'a>,\n    modules_name: &str,\n) -> Option<&'a str> {\n    if let BorrowedValue::Object(map) = package_json {\n        if let Some(BorrowedValue::Object(imports)) = map.get(\"imports\") {\n            if let Some(BorrowedValue::Object(name)) = imports.get(modules_name) {\n                // Check for imports -> name -> platform(browser or node)\n                if let Some(BorrowedValue::String(platform)) = name.get(LLRT_PLATFORM.as_str()) {\n                    return Some(platform.as_ref());\n                }\n                // Check for imports -> name -> require\n                if let Some(BorrowedValue::String(require)) = name.get(\"require\") {\n                    return Some(require.as_ref());\n                }\n                // Check for imports -> name -> module-sync\n                if let Some(BorrowedValue::String(module_sync)) = name.get(\"module-sync\") {\n                    return Some(module_sync.as_ref());\n                }\n                // Check for imports -> name -> default\n                if let Some(BorrowedValue::String(default)) = name.get(\"default\") {\n                    return Some(default.as_ref());\n                }\n            }\n            // Check for imports -> name\n            if let Some(BorrowedValue::String(name)) = imports.get(modules_name) {\n                return Some(name.as_ref());\n            }\n        }\n    }\n    None\n}\n\nfn find_the_closest_package_scope(start: &str) -> Option<Box<str>> {\n    let mut current_dir = PathBuf::from(start);\n    loop {\n        let package_json_path = current_dir.join(\"package.json\");\n        if package_json_path.exists() {\n            return package_json_path.to_str().map(Box::from);\n        }\n        if !current_dir.pop() {\n            break;\n        }\n    }\n    None\n}\n\nfn get_string_field<'a>(package_json: &'a BorrowedValue<'a>, str: &str) -> Option<&'a str> {\n    if let BorrowedValue::Object(map) = package_json {\n        if let Some(BorrowedValue::String(val)) = map.get(str) {\n            return Some(val.as_ref());\n        }\n    }\n    None\n}\n\nfn is_exports_field_exists<'a>(package_json: &'a BorrowedValue<'a>) -> bool {\n    if let BorrowedValue::Object(map) = package_json {\n        if let Some(BorrowedValue::Object(_)) = map.get(\"exports\") {\n            return true;\n        }\n    }\n    false\n}\n\nfn correct_extensions<'a>(x: String) -> Cow<'a, str> {\n    let (x_is_file, x_is_dir) = if let Ok(md) = fs::metadata(&x) {\n        (md.is_file(), md.is_dir())\n    } else {\n        (false, false)\n    };\n\n    if x_is_file {\n        return x.into();\n    };\n\n    let index = if x_is_dir { \"/index\" } else { \"\" };\n\n    let mut base_path = String::with_capacity(x.len() + index.len() + 4); //add capacity for extention\n    base_path.push_str(&x);\n    base_path.push_str(index);\n    let base_path_length = base_path.len();\n\n    let mut path = Some(base_path);\n\n    for extension in JS_EXTENSIONS.iter() {\n        if let Some(mut current_path) = path.take() {\n            current_path.truncate(base_path_length);\n            current_path.push_str(extension);\n            if Path::new(&current_path).is_file() {\n                return current_path.into();\n            }\n            path = Some(current_path);\n        }\n    }\n    x.into()\n}\n"
  },
  {
    "path": "modules/llrt_abort/Cargo.toml",
    "content": "[package]\nname = \"llrt_abort\"\ndescription = \"LLRT Module abort\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[lib]\nname = \"llrt_abort\"\npath = \"src/lib.rs\"\n\n[features]\ndefault = [\"sleep-timers\"]\n\nsleep-timers = [\"llrt_timers\"]\nsleep-tokio = [\"tokio\"]\n\n[dependencies]\nllrt_async_hooks = { version = \"0.8.1-beta\", path = \"../llrt_async_hooks\" }\nllrt_exceptions = { version = \"0.8.1-beta\", path = \"../llrt_exceptions\" }\nllrt_events = { version = \"0.8.1-beta\", path = \"../llrt_events\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", default-features = false }\n\n# Optional\nllrt_timers = { version = \"0.8.1-beta\", path = \"../llrt_timers\", optional = true }\ntokio = { version = \"1\", features = [\n    \"time\",\n], default-features = false, optional = true }\n\n[dev-dependencies]\nllrt_test = { path = \"../../libs/llrt_test\" }\ntokio = { version = \"1\", features = [\"test-util\"], default-features = false }\n"
  },
  {
    "path": "modules/llrt_abort/src/abort_controller.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse rquickjs::{\n    atom::PredefinedAtom,\n    prelude::{Opt, This},\n    Class, Ctx, JsLifetime, Result, Value,\n};\n\nuse super::AbortSignal;\n\n#[rquickjs::class]\n#[derive(rquickjs::class::Trace)]\npub struct AbortController<'js> {\n    signal: Class<'js, AbortSignal<'js>>,\n}\n\nunsafe impl<'js> JsLifetime<'js> for AbortController<'js> {\n    type Changed<'to> = AbortController<'to>;\n}\n\n#[rquickjs::methods]\nimpl<'js> AbortController<'js> {\n    #[qjs(constructor)]\n    pub fn new(ctx: Ctx<'js>) -> Result<Self> {\n        let signal = AbortSignal::new();\n\n        let abort_controller = Self {\n            signal: Class::instance(ctx, signal)?,\n        };\n        Ok(abort_controller)\n    }\n\n    #[qjs(get)]\n    pub fn signal(&self) -> Class<'js, AbortSignal<'js>> {\n        self.signal.clone()\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    pub fn to_string_tag(&self) -> &'static str {\n        stringify!(AbortController)\n    }\n\n    pub fn abort(\n        ctx: Ctx<'js>,\n        this: This<Class<'js, Self>>,\n        reason: Opt<Value<'js>>,\n    ) -> Result<()> {\n        let instance = this.0.borrow();\n        let signal = instance.signal.clone();\n        let mut signal_borrow = signal.borrow_mut();\n        if signal_borrow.aborted {\n            //only once\n            return Ok(());\n        }\n        signal_borrow.set_reason(reason);\n        drop(signal_borrow);\n        AbortSignal::send_aborted(This(signal), ctx)?;\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "modules/llrt_abort/src/abort_signal.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::sync::{Arc, RwLock};\n\nuse llrt_events::{Emitter, EventEmitter, EventList};\nuse llrt_exceptions::{DOMException, DOMExceptionName};\nuse llrt_utils::mc_oneshot;\nuse rquickjs::{\n    atom::PredefinedAtom,\n    class::{Trace, Tracer},\n    function::OnceFn,\n    prelude::{Opt, This},\n    Array, Class, Ctx, Error, Exception, Function, JsLifetime, Result, Undefined, Value,\n};\n\n#[derive(Clone)]\n#[rquickjs::class]\npub struct AbortSignal<'js> {\n    emitter: EventEmitter<'js>,\n    pub aborted: bool,\n    reason: Option<Value<'js>>,\n    pub sender: mc_oneshot::Sender<Value<'js>>,\n}\n\nunsafe impl<'js> JsLifetime<'js> for AbortSignal<'js> {\n    type Changed<'to> = AbortSignal<'to>;\n}\n\nimpl<'js> Trace<'js> for AbortSignal<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        if let Some(reason) = &self.reason {\n            tracer.mark(reason);\n        }\n        self.emitter.trace(tracer);\n        self.sender.trace(tracer);\n    }\n}\n\nimpl<'js> Emitter<'js> for AbortSignal<'js> {\n    fn get_event_list(&self) -> Arc<RwLock<EventList<'js>>> {\n        self.emitter.get_event_list()\n    }\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl<'js> AbortSignal<'js> {\n    #[qjs(constructor)]\n    pub fn new() -> Self {\n        let (sender, _) = mc_oneshot::channel::<Value<'js>>();\n        Self {\n            emitter: EventEmitter::new(),\n            aborted: false,\n            reason: None,\n            sender,\n        }\n    }\n\n    #[qjs(get, rename = \"onabort\")]\n    pub fn get_on_abort(&self) -> Option<Function<'js>> {\n        Self::get_listeners_str(self, \"abort\").first().cloned()\n    }\n\n    #[qjs(set, rename = \"onabort\")]\n    pub fn set_on_abort(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        listener: Function<'js>,\n    ) -> Result<()> {\n        Self::add_event_listener_str(this, &ctx, \"abort\", listener, false, false)?;\n        Ok(())\n    }\n\n    pub fn remove_on_abort(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        listener: Function<'js>,\n    ) -> Result<()> {\n        Self::remove_event_listener_str(this, &ctx, \"abort\", listener)?;\n        Ok(())\n    }\n\n    pub fn throw_if_aborted(&self, ctx: Ctx<'js>) -> Result<()> {\n        if self.aborted {\n            return Err(ctx.throw(\n                self.reason\n                    .clone()\n                    .unwrap_or_else(|| Undefined.into_value(ctx.clone())),\n            ));\n        }\n        Ok(())\n    }\n\n    #[qjs(static)]\n    pub fn any(ctx: Ctx<'js>, signals: Array<'js>) -> Result<Class<'js, Self>> {\n        let mut new_signal = AbortSignal::new();\n\n        let mut signal_instances = Vec::with_capacity(signals.len());\n\n        for signal in signals.iter() {\n            let signal: Value = signal?;\n            let signal: Class<AbortSignal> = Class::from_value(&signal)\n                .map_err(|_| Exception::throw_type(&ctx, \"Value is not an AbortSignal instance\"))?;\n            let signal_borrow = signal.borrow();\n            if signal_borrow.aborted {\n                new_signal.aborted = true;\n                new_signal.reason.clone_from(&signal_borrow.reason);\n                let new_signal = Class::instance(ctx, new_signal)?;\n                return Ok(new_signal);\n            } else {\n                drop(signal_borrow);\n                signal_instances.push(signal);\n            }\n        }\n\n        let new_signal_instance = Class::instance(ctx.clone(), new_signal)?;\n        for signal in signal_instances {\n            let signal_instance_2 = new_signal_instance.clone();\n            Self::add_event_listener_str(\n                This(signal),\n                &ctx,\n                \"abort\",\n                Function::new(\n                    ctx.clone(),\n                    OnceFn::from(|ctx, signal| {\n                        struct Args<'js>(Ctx<'js>, This<Class<'js, AbortSignal<'js>>>);\n                        let Args(ctx, signal) = Args(ctx, signal);\n                        let mut borrow = signal_instance_2.borrow_mut();\n                        borrow.aborted = true;\n                        borrow.reason.clone_from(&signal.borrow().reason);\n                        drop(borrow);\n                        Self::send_aborted(This(signal_instance_2), ctx)\n                    }),\n                )?,\n                false,\n                true,\n            )?;\n        }\n\n        Ok(new_signal_instance)\n    }\n\n    #[qjs(get)]\n    pub fn aborted(&self) -> bool {\n        self.aborted\n    }\n\n    #[qjs(get)]\n    pub fn reason(&self) -> Option<Value<'js>> {\n        self.reason.clone()\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    pub fn to_string_tag(&self) -> &'static str {\n        stringify!(AbortSignal)\n    }\n\n    #[qjs(set, rename = \"reason\")]\n    pub fn set_reason(&mut self, reason: Opt<Value<'js>>) {\n        match reason.0 {\n            Some(new_reason) if !new_reason.is_undefined() => self.reason.replace(new_reason),\n            _ => self.reason.take(),\n        };\n    }\n\n    #[qjs(skip)]\n    pub fn send_aborted(this: This<Class<'js, Self>>, ctx: Ctx<'js>) -> Result<()> {\n        let mut borrow = this.borrow_mut();\n        borrow.aborted = true;\n        let reason = get_reason_or_dom_exception(\n            &ctx,\n            borrow.reason.as_ref(),\n            DOMExceptionName::AbortError,\n        )?;\n        borrow.reason = Some(reason.clone());\n        borrow.sender.send(reason);\n        drop(borrow);\n        Self::emit_str(this, &ctx, \"abort\", vec![], false)?;\n        Ok(())\n    }\n\n    #[qjs(static)]\n    pub fn abort(ctx: Ctx<'js>, reason: Opt<Value<'js>>) -> Result<Class<'js, Self>> {\n        let mut signal = Self::new();\n        signal.set_reason(reason);\n        let instance = Class::instance(ctx.clone(), signal)?;\n        Self::send_aborted(This(instance.clone()), ctx)?;\n        Ok(instance)\n    }\n\n    #[qjs(static)]\n    pub fn timeout(ctx: Ctx<'js>, milliseconds: u64) -> Result<Class<'js, Self>> {\n        let timeout_error =\n            get_reason_or_dom_exception(&ctx, None, DOMExceptionName::TimeoutError)?;\n\n        let signal = Self::new();\n        let signal_instance = Class::instance(ctx.clone(), signal)?;\n        let signal_instance2 = signal_instance.clone();\n\n        let cb = Function::new(\n            ctx.clone(),\n            OnceFn::from(move |ctx| {\n                let mut borrow = signal_instance.borrow_mut();\n                borrow.set_reason(Opt(Some(timeout_error)));\n                drop(borrow);\n                Self::send_aborted(This(signal_instance), ctx)?;\n                Ok::<_, Error>(())\n            }),\n        )?;\n\n        #[cfg(feature = \"sleep-timers\")]\n        {\n            llrt_timers::set_timeout_interval(\n                &ctx,\n                cb,\n                milliseconds,\n                llrt_utils::provider::ProviderType::Timeout,\n            )?;\n        }\n        #[cfg(all(not(feature = \"sleep-timers\"), feature = \"sleep-tokio\"))]\n        {\n            use llrt_utils::ctx::CtxExtension;\n            ctx.clone().spawn_exit_simple(async move {\n                tokio::time::sleep(std::time::Duration::from_millis(milliseconds)).await;\n                cb.call::<_, ()>(())?;\n                Ok(())\n            });\n        }\n        #[cfg(all(not(feature = \"sleep-tokio\"), not(feature = \"sleep-timers\")))]\n        {\n            compile_error!(\"Either the `sleep-tokio` or `sleep-timers` feature must be enabled\")\n        }\n\n        Ok(signal_instance2)\n    }\n}\n\nfn get_reason_or_dom_exception<'js>(\n    ctx: &Ctx<'js>,\n    reason: Option<&Value<'js>>,\n    name: DOMExceptionName,\n) -> Result<Value<'js>> {\n    let reason = if let Some(reason) = reason {\n        reason.clone()\n    } else {\n        let ex = DOMException::new_with_name(ctx, name, String::new())?;\n        Class::instance(ctx.clone(), ex)?.into_value()\n    };\n    Ok(reason)\n}\n\n#[cfg(test)]\nmod tests {\n    use std::time::Duration;\n\n    use llrt_test::test_async_with;\n\n    use super::*;\n\n    #[cfg(feature = \"sleep-timers\")]\n    #[tokio::test]\n    async fn test_abort_signal() {\n        test_async_with(|ctx| {\n            crate::init(&ctx).unwrap();\n            llrt_timers::init(&ctx).unwrap();\n            Box::pin(async move {\n                let signal = AbortSignal::timeout(ctx, 5).unwrap();\n\n                assert!(!signal.borrow().aborted());\n\n                tokio::time::sleep(Duration::from_millis(50)).await;\n\n                assert!(signal.borrow().aborted());\n                let reason = signal.borrow().reason().unwrap();\n                let reason = Class::<DOMException>::from_value(&reason).unwrap();\n                assert_eq!(reason.borrow().name(), \"TimeoutError\");\n            })\n        })\n        .await;\n    }\n}\n"
  },
  {
    "path": "modules/llrt_abort/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#![allow(clippy::new_without_default)]\nuse llrt_events::Emitter;\nuse llrt_utils::primordials::{BasePrimordials, Primordial};\nuse rquickjs::{Class, Ctx, Result};\n\npub use self::{abort_controller::AbortController, abort_signal::AbortSignal};\n\nmod abort_controller;\nmod abort_signal;\n\npub fn init(ctx: &Ctx<'_>) -> Result<()> {\n    let globals = ctx.globals();\n\n    BasePrimordials::init(ctx)?;\n\n    Class::<AbortController>::define(&globals)?;\n    Class::<AbortSignal>::define(&globals)?;\n\n    AbortSignal::add_event_emitter_prototype(ctx)?;\n    AbortSignal::add_event_target_prototype(ctx)?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "modules/llrt_assert/Cargo.toml",
    "content": "[package]\nname = \"llrt_assert\"\ndescription = \"LLRT Module assert\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[lib]\nname = \"llrt_assert\"\npath = \"src/lib.rs\"\n\n[dependencies]\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", default-features = false }\n\n[dev-dependencies]\nllrt_test = { path = \"../../libs/llrt_test\" }\n"
  },
  {
    "path": "modules/llrt_assert/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_utils::module::ModuleInfo;\nuse rquickjs::{\n    module::{Declarations, Exports, ModuleDef},\n    prelude::Opt,\n    Ctx, Exception, Function, Result, Type, Value,\n};\n\nfn ok(ctx: Ctx, value: Value, message: Opt<Value>) -> Result<()> {\n    match value.type_of() {\n        Type::Bool => {\n            if value.as_bool().unwrap() {\n                return Ok(());\n            }\n        },\n        Type::Float | Type::Int => {\n            if value.as_number().unwrap() != 0.0 {\n                return Ok(());\n            }\n        },\n        Type::String => {\n            if !value.as_string().unwrap().to_string().unwrap().is_empty() {\n                return Ok(());\n            }\n        },\n        Type::Array\n        | Type::BigInt\n        | Type::Constructor\n        | Type::Exception\n        | Type::Function\n        | Type::Proxy\n        | Type::Symbol\n        | Type::Object => {\n            return Ok(());\n        },\n        _ => {},\n    }\n\n    if let Some(obj) = message.0 {\n        match obj.type_of() {\n            Type::String => {\n                let msg = obj.as_string().unwrap().to_string().unwrap();\n                return Err(Exception::throw_message(&ctx, &msg));\n            },\n            Type::Exception => return Err(obj.as_exception().cloned().unwrap().throw()),\n            _ => {},\n        };\n    }\n\n    Err(Exception::throw_message(\n        &ctx,\n        \"AssertionError: The expression was evaluated to a falsy value\",\n    ))\n}\n\npub struct AssertModule;\n\nimpl ModuleDef for AssertModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(\"ok\")?;\n\n        declare.declare(\"default\")?;\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        let ok_function = Function::new(ctx.clone(), ok)?.with_name(\"ok\")?;\n        ok_function.set(\"ok\", ok_function.clone())?;\n\n        exports.export(\"ok\", ok_function.clone())?;\n        exports.export(\"default\", ok_function)?;\n        Ok(())\n    }\n}\n\nimpl From<AssertModule> for ModuleInfo<AssertModule> {\n    fn from(val: AssertModule) -> Self {\n        ModuleInfo {\n            name: \"assert\",\n            module: val,\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_async_hooks/Cargo.toml",
    "content": "[package]\nname = \"llrt_async_hooks\"\ndescription = \"LLRT Module async_hooks\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[lib]\nname = \"llrt_async_hooks\"\npath = \"src/lib.rs\"\n\n[dependencies]\nllrt_hooking = { version = \"0.8.1-beta\", path = \"../../libs/llrt_hooking\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", default-features = false }\ntracing = { version = \"0.1\", default-features = false }\n"
  },
  {
    "path": "modules/llrt_async_hooks/src/finalization_registry.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::cell::RefCell;\n\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{prelude::Func, Ctx, Result, Value};\nuse tracing::trace;\n\nuse super::{remove_id_map, update_current_id, AsyncHookState};\n\npub(crate) fn init_finalization_registry(ctx: &Ctx<'_>) -> Result<()> {\n    let global = ctx.globals();\n\n    global.set(\n        \"__invokeFinalizationHook\",\n        Func::from(invoke_finalization_hook),\n    )?;\n\n    let _: () = ctx.eval(\n        r#\"\n        globalThis.asyncFinalizationRegistry = (() => {\n            const registry = new FinalizationRegistry(__invokeFinalizationHook);\n            return {\n                register(target, heldValue) {\n                    registry.register(target, heldValue);\n                }\n            };\n        })();\n        \"#,\n    )?;\n\n    global.remove(\"__invokeFinalizationHook\")?;\n\n    Ok(())\n}\n\nfn invoke_finalization_hook<'js>(ctx: Ctx<'js>, uid: Value<'js>) -> Result<()> {\n    let bind_state = ctx.userdata::<RefCell<AsyncHookState>>().or_throw(&ctx)?;\n    let state = bind_state.borrow();\n    if state.hooks.is_empty() {\n        return Ok(());\n    }\n\n    let uid = uid.as_number().unwrap() as usize;\n\n    let current_id = remove_id_map(&ctx, uid)?;\n    if current_id.0 == 0 {\n        return Ok(());\n    }\n\n    update_current_id(&ctx, current_id)?;\n    trace!(\"Destroy[{}](async_id, trigger_id): {:?}\", uid, current_id);\n\n    for hook in &state.hooks {\n        if *hook.enabled.as_ref().borrow() {\n            if let Some(func) = &hook.destroy {\n                let _ = func\n                    .call::<_, ()>((current_id.0,))\n                    .or_else(|_| func.call::<_, ()>(()));\n            }\n        }\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "modules/llrt_async_hooks/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{cell::RefCell, collections::HashMap, marker::PhantomData, rc::Rc};\n\nuse llrt_hooking::register_finalization_registry;\nuse llrt_utils::{\n    module::{export_default, ModuleInfo},\n    result::ResultExt,\n};\nuse rquickjs::{\n    module::{Declarations, Exports, ModuleDef},\n    prelude::Func,\n    promise::PromiseHookType,\n    qjs,\n    runtime::PromiseHook,\n    Ctx, Function, JsLifetime, Object, Result, Value,\n};\nuse tracing::trace;\n\nmod finalization_registry;\n\nuse crate::finalization_registry::init_finalization_registry;\n\nstruct Hook<'js> {\n    enabled: Rc<RefCell<bool>>,\n    init: Option<Function<'js>>,\n    before: Option<Function<'js>>,\n    after: Option<Function<'js>>,\n    promise_resolve: Option<Function<'js>>,\n    destroy: Option<Function<'js>>,\n}\n\nstruct AsyncHookState<'js> {\n    hooks: Vec<Hook<'js>>,\n}\n\nimpl Default for AsyncHookState<'_> {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl AsyncHookState<'_> {\n    fn new() -> Self {\n        Self { hooks: Vec::new() }\n    }\n}\n\nunsafe impl<'js> JsLifetime<'js> for AsyncHookState<'js> {\n    type Changed<'to> = AsyncHookState<'to>;\n}\n\nstruct AsyncHookIds<'js> {\n    next_async_id: u64,\n    id_map: HashMap<usize, (u64, u64)>, // (execution_async_id, trigger_async_id)\n    current_id: (u64, u64),             // (execution_async_id, trigger_async_id)\n    _marker: PhantomData<&'js ()>,\n}\n\nimpl Default for AsyncHookIds<'_> {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl AsyncHookIds<'_> {\n    fn new() -> Self {\n        Self {\n            next_async_id: 1,\n            id_map: HashMap::new(),\n            current_id: (1, 1),\n            _marker: PhantomData,\n        }\n    }\n}\n\nunsafe impl<'js> JsLifetime<'js> for AsyncHookIds<'js> {\n    type Changed<'to> = AsyncHookIds<'to>;\n}\n\nfn create_hook<'js>(ctx: Ctx<'js>, hooks_obj: Object<'js>) -> Result<Value<'js>> {\n    let init = hooks_obj.get::<_, Function>(\"init\").ok();\n    let before = hooks_obj.get::<_, Function>(\"before\").ok();\n    let after = hooks_obj.get::<_, Function>(\"after\").ok();\n    let promise_resolve = hooks_obj.get::<_, Function>(\"promiseResolve\").ok();\n    let destroy = hooks_obj.get::<_, Function>(\"destroy\").ok();\n    let enabled = Rc::new(RefCell::new(false));\n\n    let hook = Hook {\n        enabled: enabled.clone(),\n        init,\n        before,\n        after,\n        promise_resolve,\n        destroy,\n    };\n\n    let binding = ctx.userdata::<RefCell<AsyncHookState>>().or_throw(&ctx)?;\n    let mut state = binding.borrow_mut();\n    state.hooks.push(hook);\n\n    let obj = Object::new(ctx.clone())?;\n    {\n        let enabled_clone = enabled.clone();\n        obj.set(\n            \"enable\",\n            Function::new(ctx.clone(), move || -> Result<()> {\n                *enabled_clone.borrow_mut() = true;\n                Ok(())\n            }),\n        )?;\n    }\n    {\n        let enabled_clone = enabled.clone();\n        obj.set(\n            \"disable\",\n            Function::new(ctx.clone(), move || -> Result<()> {\n                *enabled_clone.borrow_mut() = false;\n                Ok(())\n            }),\n        )?;\n    }\n\n    Ok(obj.into())\n}\n\nfn current_id() -> u64 {\n    // NOTE: This method is now obsolete. Therefore, it does not return a valid value.\n    // But we will define it because it is used by cls-hooked.\n    0\n}\n\nfn execution_async_id(ctx: Ctx<'_>) -> Result<u64> {\n    let bind_ids = ctx.userdata::<RefCell<AsyncHookIds>>().or_throw(&ctx)?;\n    let ids = bind_ids.borrow();\n    Ok(ids.current_id.0)\n}\n\nfn trigger_async_id(ctx: Ctx<'_>) -> Result<u64> {\n    let bind_ids = ctx.userdata::<RefCell<AsyncHookIds>>().or_throw(&ctx)?;\n    let ids = bind_ids.borrow();\n    Ok(ids.current_id.1)\n}\n\npub struct AsyncHooksModule;\n\nimpl ModuleDef for AsyncHooksModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(\"createHook\")?;\n        declare.declare(\"currentId\")?;\n        declare.declare(\"executionAsyncId\")?;\n        declare.declare(\"triggerAsyncId\")?;\n        declare.declare(\"default\")?;\n\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        export_default(ctx, exports, |default| {\n            default.set(\"createHook\", Func::from(create_hook))?;\n            default.set(\"currentId\", Func::from(current_id))?;\n            default.set(\"executionAsyncId\", Func::from(execution_async_id))?;\n            default.set(\"triggerAsyncId\", Func::from(trigger_async_id))?;\n\n            Ok(())\n        })?;\n\n        Ok(())\n    }\n}\n\nimpl From<AsyncHooksModule> for ModuleInfo<AsyncHooksModule> {\n    fn from(val: AsyncHooksModule) -> Self {\n        ModuleInfo {\n            name: \"async_hooks\",\n            module: val,\n        }\n    }\n}\n\npub fn init(ctx: &Ctx<'_>) -> Result<()> {\n    let global = ctx.globals();\n\n    let _ = ctx.store_userdata(RefCell::new(AsyncHookState::default()));\n    let _ = ctx.store_userdata(RefCell::new(AsyncHookIds::default()));\n\n    global.set(\n        \"invokeAsyncHook\",\n        Func::from(\n            move |ctx: Ctx<'_>, type_: String, async_type: String, uid: usize| {\n                let type_ = match type_.as_ref() {\n                    \"init\" => PromiseHookType::Init,\n                    \"before\" => PromiseHookType::Before,\n                    \"after\" => PromiseHookType::After,\n                    \"resolve\" => PromiseHookType::Resolve,\n                    _ => return,\n                };\n\n                let _ = invoke_async_hook(&ctx, type_, async_type.as_ref(), uid, None);\n            },\n        ),\n    )?;\n\n    init_finalization_registry(ctx)?;\n\n    Ok(())\n}\n\npub fn promise_hook_tracker() -> PromiseHook {\n    Box::new(\n        |ctx: Ctx<'_>, type_: PromiseHookType, promise: Value<'_>, parent: Value<'_>| {\n            // SAFETY: Since it checks in advance whether it is an Object type, we can always get a pointer to the object.\n            let object = promise\n                .as_object()\n                .map(|v| unsafe { qjs::JS_VALUE_GET_PTR(v.as_raw()) } as usize)\n                .unwrap();\n            let parent = parent\n                .as_object()\n                .map(|v| unsafe { qjs::JS_VALUE_GET_PTR(v.as_raw()) } as usize);\n\n            if type_ == PromiseHookType::Init {\n                let _ = register_finalization_registry(&ctx, promise, object);\n            }\n\n            let _ = invoke_async_hook(&ctx, type_, \"PROMISE\", object, parent);\n        },\n    )\n}\n\nfn invoke_async_hook(\n    ctx: &Ctx<'_>,\n    type_: PromiseHookType,\n    async_type: &str,\n    object: usize,\n    parent: Option<usize>,\n) -> Result<()> {\n    let bind_state = ctx.userdata::<RefCell<AsyncHookState>>().or_throw(ctx)?;\n    let state = bind_state.borrow();\n\n    if state.hooks.is_empty() {\n        return Ok(());\n    }\n\n    match type_ {\n        PromiseHookType::Init => {\n            let current_id = insert_id_map(ctx, object, parent, async_type == \"PROMISE\")?;\n            trace!(\"Init(async_id, trigger_id): {:?}\", current_id);\n            update_current_id(ctx, current_id)?;\n\n            for hook in &state.hooks {\n                if *hook.enabled.as_ref().borrow() {\n                    if let Some(func) = &hook.init {\n                        let _ = func\n                            .call::<_, ()>((current_id.0, async_type, current_id.1))\n                            .or_else(|_| func.call::<_, ()>((current_id.0, async_type)))\n                            .or_else(|_| func.call::<_, ()>((current_id.0,)))\n                            .or_else(|_| func.call::<_, ()>(()));\n                    }\n                }\n            }\n        },\n        PromiseHookType::Before | PromiseHookType::After | PromiseHookType::Resolve => {\n            let current_id = get_id_map(ctx, object)?;\n            if current_id.0 == 0 {\n                return Ok(());\n            }\n\n            let _type = match type_ {\n                PromiseHookType::Before => \"Before\",\n                PromiseHookType::After => \"After\",\n                PromiseHookType::Resolve => \"Resolve\",\n                _ => unreachable!(),\n            };\n            trace!(\"{}(async_id, trigger_id): {:?}\", _type, current_id);\n            update_current_id(ctx, current_id)?;\n\n            for hook in &state.hooks {\n                if *hook.enabled.as_ref().borrow() {\n                    if let Some(func) = match type_ {\n                        PromiseHookType::Before => &hook.before,\n                        PromiseHookType::After => &hook.after,\n                        PromiseHookType::Resolve => &hook.promise_resolve,\n                        _ => unreachable!(),\n                    } {\n                        let _ = func\n                            .call::<_, ()>((current_id.0,))\n                            .or_else(|_| func.call::<_, ()>(()));\n                    }\n                }\n            }\n        },\n    }\n    Ok(())\n}\n\nfn insert_id_map(\n    ctx: &Ctx<'_>,\n    target: usize,\n    parent: Option<usize>,\n    is_promise: bool,\n) -> Result<(u64, u64)> {\n    let bind_ids = ctx.userdata::<RefCell<AsyncHookIds>>().or_throw(ctx)?;\n    let mut ids = bind_ids.borrow_mut();\n    ids.next_async_id = ids.next_async_id.wrapping_add(1);\n    let async_id = ids.next_async_id;\n    let trigger_id = parent\n        .and_then(|tid| ids.id_map.get(&tid))\n        .map(|id| id.0)\n        .unwrap_or(if is_promise { 1 } else { ids.current_id.1 });\n    ids.id_map.insert(target, (async_id, trigger_id));\n    Ok((async_id, trigger_id))\n}\n\nfn get_id_map(ctx: &Ctx<'_>, target: usize) -> Result<(u64, u64)> {\n    let bind_ids = ctx.userdata::<RefCell<AsyncHookIds>>().or_throw(ctx)?;\n    let ids = bind_ids.borrow();\n    Ok(*ids.id_map.get(&target).unwrap_or(&(0, 0)))\n}\n\nfn remove_id_map(ctx: &Ctx<'_>, target: usize) -> Result<(u64, u64)> {\n    let bind_ids = ctx.userdata::<RefCell<AsyncHookIds>>().or_throw(ctx)?;\n    let mut ids = bind_ids.borrow_mut();\n    Ok(ids\n        .id_map\n        .remove_entry(&target)\n        .map(|(_, (async_id, trigger_id))| (async_id, trigger_id))\n        .unwrap_or((0, 0)))\n}\n\nfn update_current_id(ctx: &Ctx<'_>, id: (u64, u64)) -> Result<()> {\n    let bind_ids = ctx.userdata::<RefCell<AsyncHookIds>>().or_throw(ctx)?;\n    bind_ids.borrow_mut().current_id = id;\n    Ok(())\n}\n"
  },
  {
    "path": "modules/llrt_buffer/Cargo.toml",
    "content": "[package]\nname = \"llrt_buffer\"\ndescription = \"LLRT Module buffer\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[lib]\nname = \"llrt_buffer\"\npath = \"src/lib.rs\"\n\n[dependencies]\nitoa = { version = \"1\", default-features = false }\nllrt_encoding = { version = \"0.8.1-beta\", path = \"../../libs/llrt_encoding\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", features = [\n  \"futures\",\n], default-features = false }\nryu = { version = \"1\", default-features = false }\n\n[dev-dependencies]\nllrt_test = { path = \"../../libs/llrt_test\" }\ntokio = { version = \"1\", features = [\"full\"], default-features = false }\n"
  },
  {
    "path": "modules/llrt_buffer/src/array_buffer_view.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#![allow(clippy::uninlined_format_args)]\n\nuse std::ptr::NonNull;\n\nuse rquickjs::{ArrayBuffer, Ctx, Error, FromJs, IntoJs, Object, Result, TypedArray, Value};\n\nuse crate::Buffer;\n\npub struct ArrayBufferView<'js> {\n    value: Value<'js>,\n    buffer: Option<RawArrayBuffer>,\n}\n\nstruct RawArrayBuffer {\n    len: usize,\n    ptr: NonNull<u8>,\n}\n\nimpl RawArrayBuffer {\n    pub fn new(len: usize, ptr: NonNull<u8>) -> Self {\n        Self { len, ptr }\n    }\n}\n\nimpl<'js> IntoJs<'js> for ArrayBufferView<'js> {\n    fn into_js(self, _ctx: &Ctx<'js>) -> Result<Value<'js>> {\n        Ok(self.value)\n    }\n}\n\nimpl<'js> FromJs<'js> for ArrayBufferView<'js> {\n    fn from_js(_ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        let ty_name = value.type_name();\n        let obj = Object::from_value(value.clone())\n            .map_err(|_| Error::new_from_js(ty_name, \"ArrayBufferView\"))?;\n\n        if let Some(array_buffer) = ArrayBuffer::from_object(obj.clone()) {\n            let buffer = array_buffer\n                .as_raw()\n                .map(|raw| RawArrayBuffer::new(raw.len, raw.ptr));\n            return Ok(ArrayBufferView { value, buffer });\n        }\n\n        if let Ok(typed_array) = TypedArray::<i8>::from_object(obj.clone()) {\n            let buffer = typed_array\n                .as_raw()\n                .map(|raw| RawArrayBuffer::new(raw.len, raw.ptr));\n            return Ok(ArrayBufferView { value, buffer });\n        }\n\n        if let Ok(typed_array) = TypedArray::<u8>::from_object(obj.clone()) {\n            let buffer = typed_array\n                .as_raw()\n                .map(|raw| RawArrayBuffer::new(raw.len, raw.ptr));\n            return Ok(ArrayBufferView { value, buffer });\n        }\n\n        if let Ok(typed_array) = TypedArray::<i16>::from_object(obj.clone()) {\n            let buffer = typed_array\n                .as_raw()\n                .map(|raw| RawArrayBuffer::new(raw.len, raw.ptr));\n            return Ok(ArrayBufferView { value, buffer });\n        }\n\n        if let Ok(typed_array) = TypedArray::<u16>::from_object(obj.clone()) {\n            let buffer = typed_array\n                .as_raw()\n                .map(|raw| RawArrayBuffer::new(raw.len, raw.ptr));\n            return Ok(ArrayBufferView { value, buffer });\n        }\n\n        if let Ok(typed_array) = TypedArray::<i32>::from_object(obj.clone()) {\n            let buffer = typed_array\n                .as_raw()\n                .map(|raw| RawArrayBuffer::new(raw.len, raw.ptr));\n            return Ok(ArrayBufferView { value, buffer });\n        }\n\n        if let Ok(typed_array) = TypedArray::<u32>::from_object(obj.clone()) {\n            let buffer = typed_array\n                .as_raw()\n                .map(|raw| RawArrayBuffer::new(raw.len, raw.ptr));\n            return Ok(ArrayBufferView { value, buffer });\n        }\n\n        if let Ok(typed_array) = TypedArray::<f32>::from_object(obj.clone()) {\n            let buffer = typed_array\n                .as_raw()\n                .map(|raw| RawArrayBuffer::new(raw.len, raw.ptr));\n            return Ok(ArrayBufferView { value, buffer });\n        }\n\n        if let Ok(typed_array) = TypedArray::<f64>::from_object(obj.clone()) {\n            let buffer = typed_array\n                .as_raw()\n                .map(|raw| RawArrayBuffer::new(raw.len, raw.ptr));\n            return Ok(ArrayBufferView { value, buffer });\n        }\n\n        if let Ok(typed_array) = TypedArray::<i64>::from_object(obj.clone()) {\n            let buffer = typed_array\n                .as_raw()\n                .map(|raw| RawArrayBuffer::new(raw.len, raw.ptr));\n            return Ok(ArrayBufferView { value, buffer });\n        }\n\n        if let Ok(typed_array) = TypedArray::<u64>::from_object(obj.clone()) {\n            let buffer = typed_array\n                .as_raw()\n                .map(|raw| RawArrayBuffer::new(raw.len, raw.ptr));\n            return Ok(ArrayBufferView { value, buffer });\n        }\n\n        if let Ok(array_buffer) = obj.get::<_, ArrayBuffer>(\"buffer\") {\n            let buffer = array_buffer\n                .as_raw()\n                .map(|raw| RawArrayBuffer::new(raw.len, raw.ptr));\n            return Ok(ArrayBufferView { value, buffer });\n        }\n\n        Err(Error::new_from_js(ty_name, \"ArrayBufferView\"))\n    }\n}\n\nimpl<'js> ArrayBufferView<'js> {\n    pub fn from_buffer(ctx: &Ctx<'js>, buffer: Buffer) -> Result<Self> {\n        let value = buffer.into_js(ctx)?;\n        Self::from_js(ctx, value)\n    }\n\n    pub fn len(&self) -> usize {\n        self.buffer.as_ref().map(|b| b.len).unwrap_or(0)\n    }\n\n    #[allow(dead_code)]\n    pub fn is_empty(&self) -> bool {\n        self.len() == 0\n    }\n\n    pub fn as_bytes(&self) -> Option<&[u8]> {\n        self.buffer\n            .as_ref()\n            .map(|b| unsafe { std::slice::from_raw_parts(b.ptr.as_ptr(), b.len) })\n    }\n\n    /// Mutable buffer for the view.\n    ///\n    /// # Safety\n    /// This is only safe if you have a lock on the runtime.\n    /// Do not pass it directly to other threads.\n    pub fn as_bytes_mut(&mut self) -> Option<&mut [u8]> {\n        self.buffer\n            .as_ref()\n            .map(|b| unsafe { std::slice::from_raw_parts_mut(b.ptr.as_ptr(), b.len) })\n    }\n}\n"
  },
  {
    "path": "modules/llrt_buffer/src/blob.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::ops::RangeInclusive;\n\nuse llrt_utils::{\n    bytes::ObjectBytes,\n    primordials::{BasePrimordials, Primordial},\n    result::ResultExt,\n};\nuse rquickjs::{\n    atom::PredefinedAtom, class::Trace, function::Opt, Array, ArrayBuffer, Class, Coerced, Ctx,\n    Exception, FromJs, Result, Symbol, TypedArray, Value,\n};\n\nuse super::file::File;\n\nstatic CONSTRUCT_ERROR: &str =\n    \"Failed to construct 'Blob': The provided value cannot be converted to a sequence.\";\n\nenum EndingType {\n    Native,\n    Transparent,\n}\n\n#[cfg(windows)]\nconst LINE_ENDING: &[u8] = b\"\\r\\n\";\n#[cfg(not(windows))]\nconst LINE_ENDING: &[u8] = b\"\\n\";\n\n#[rquickjs::class]\n#[derive(Trace, Clone, rquickjs::JsLifetime)]\npub struct Blob {\n    #[qjs(skip_trace)]\n    data: Vec<u8>,\n    mime_type: String,\n}\n\nfn normalize_type(mut mime_type: String) -> String {\n    static INVALID_RANGE: RangeInclusive<u8> = 0x0020..=0x007E;\n\n    let bytes = unsafe { mime_type.as_bytes_mut() };\n    for byte in bytes {\n        if !INVALID_RANGE.contains(byte) {\n            return String::new();\n        }\n        byte.make_ascii_lowercase();\n    }\n    mime_type\n}\n\n#[rquickjs::methods]\nimpl Blob {\n    #[qjs(constructor)]\n    pub fn new<'js>(\n        ctx: Ctx<'js>,\n        parts: Opt<Value<'js>>,\n        options: Opt<Value<'js>>,\n    ) -> Result<Self> {\n        let mut endings = EndingType::Transparent;\n        let mut mime_type = String::new();\n\n        if let Some(opts) = options.0 {\n            if let Some(v) = opts.as_object() {\n                if let Some(x) = v.get::<_, Option<Coerced<String>>>(\"type\")? {\n                    mime_type = normalize_type(x.to_string());\n                }\n                if let Some(Coerced(endings_opt)) =\n                    v.get::<_, Option<Coerced<String>>>(\"endings\")?\n                {\n                    if endings_opt == \"native\" {\n                        endings = EndingType::Native;\n                    } else if endings_opt != \"transparent\" {\n                        return Err(Exception::throw_type(\n                            &ctx,\n                            r#\"expected 'endings' to be either 'transparent' or 'native'\"#,\n                        ));\n                    }\n                }\n            }\n        }\n\n        let data = if let Some(parts) = parts.0 {\n            bytes_from_parts(&ctx, parts, endings)?\n        } else {\n            Vec::new()\n        };\n\n        Ok(Self { data, mime_type })\n    }\n\n    #[qjs(get)]\n    pub fn size(&self) -> usize {\n        self.data.len()\n    }\n\n    #[qjs(get, rename = \"type\")]\n    pub fn mime_type(&self) -> String {\n        self.mime_type.clone()\n    }\n\n    pub async fn text(&self) -> String {\n        String::from_utf8_lossy(&self.data).to_string()\n    }\n\n    #[qjs(rename = \"arrayBuffer\")]\n    pub async fn array_buffer<'js>(&self, ctx: Ctx<'js>) -> Result<ArrayBuffer<'js>> {\n        ArrayBuffer::new(ctx, self.data.to_vec())\n    }\n\n    pub async fn bytes<'js>(&self, ctx: Ctx<'js>) -> Result<Value<'js>> {\n        TypedArray::new(ctx, self.data.to_vec()).map(|m| m.into_value())\n    }\n\n    pub fn slice(&self, start: Opt<isize>, end: Opt<isize>, content_type: Opt<String>) -> Blob {\n        let start = start.0.unwrap_or_default();\n        let start = if start < 0 {\n            (self.data.len() as isize + start).max(0) as usize\n        } else {\n            self.data.len().min(start as usize)\n        };\n        let end = end.0.unwrap_or_default();\n        let end = if end < 0 {\n            (self.data.len() as isize + end).max(0) as usize\n        } else {\n            self.data.len().min(end as usize)\n        };\n        let data = &self.data[start..end];\n        let mime_type = content_type.0.map(normalize_type).unwrap_or_default();\n\n        Blob {\n            mime_type,\n            data: data.to_vec(),\n        }\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    pub fn to_string_tag(&self) -> &'static str {\n        stringify!(Blob)\n    }\n}\n\nimpl Blob {\n    pub fn from_bytes(data: Vec<u8>, content_type: Option<String>) -> Self {\n        let mime_type = content_type.map(normalize_type).unwrap_or_default();\n        Self { mime_type, data }\n    }\n\n    pub fn get_bytes(&self) -> Vec<u8> {\n        self.data.clone()\n    }\n\n    //FIXME: cant use procedural macro for Symbol rename + static, see https://github.com/DelSkayn/rquickjs/issues/315\n    pub fn has_instance(value: Value<'_>) -> bool {\n        if let Some(obj) = value.as_object() {\n            return obj.instance_of::<Self>() || obj.instance_of::<File>();\n        }\n        false\n    }\n}\n\nfn bytes_from_parts<'js>(\n    ctx: &Ctx<'js>,\n    parts: Value<'js>,\n    endings: EndingType,\n) -> Result<Vec<u8>> {\n    let array = if let Some(obj) = parts.as_object() {\n        if obj.contains_key(Symbol::iterator(ctx.clone()))? {\n            BasePrimordials::get(ctx)?\n                .function_array_from\n                .call((parts.clone(),))?\n        } else {\n            parts\n                .into_array()\n                .ok_or_else(|| Exception::throw_type(ctx, CONSTRUCT_ERROR))?\n        }\n    } else {\n        return Err(Exception::throw_type(ctx, CONSTRUCT_ERROR));\n    };\n\n    let mut data = Vec::new();\n    for elem in array.iter::<Value>() {\n        let elem = elem?;\n        if let Some(arr) = elem.as_array() {\n            let string = array_to_string(arr)?;\n            data.extend_from_slice(string.as_bytes());\n            continue;\n        }\n        if let Some(object) = elem.as_object() {\n            if let Some(x) = Class::<Blob>::from_object(object) {\n                data.extend_from_slice(&x.borrow().data);\n                continue;\n            }\n            if let Some(x) = Class::<File>::from_object(object) {\n                let file = x.borrow();\n                let end = Some(file.size().try_into().or_throw(ctx)?);\n                let mime_type = Some(file.mime_type());\n                data.extend_from_slice(&file.slice(Opt(Some(0)), Opt(end), Opt(mime_type)).data);\n                continue;\n            }\n            if let Ok(x) = ObjectBytes::from(ctx, object) {\n                data.extend_from_slice(x.as_bytes(ctx).map_err(|_| {\n                    Exception::throw_type(ctx, \"Cannot create a blob with detached buffer\")\n                })?);\n                continue;\n            }\n            if let Some(x) = ArrayBuffer::from_object(object.clone()) {\n                data.extend_from_slice(x.as_bytes().ok_or_else(|| {\n                    Exception::throw_type(ctx, \"Cannot create a blob with detached buffer\")\n                })?);\n                continue;\n            }\n        }\n\n        let string = Coerced::<String>::from_js(ctx, elem)?.0;\n        if let EndingType::Transparent = endings {\n            data.extend_from_slice(string.as_bytes());\n        } else {\n            let len = string.len();\n            data.reserve(len);\n\n            let bytes = string.as_bytes();\n            let mut iter = bytes.iter();\n\n            let mut start = 0usize;\n            let mut i = 0usize;\n            let line_ending_is_n = LINE_ENDING[0] == b'\\n';\n\n            while let Some(byte) = iter.next() {\n                if byte == &b'\\r' {\n                    if let Some(next_byte) = iter.next() {\n                        data.extend(&bytes[start..i]);\n                        i += 1;\n                        start = i + 1;\n                        if next_byte != &b'\\n' {\n                            data.extend([b'\\r', *next_byte]);\n                        } else {\n                            data.extend(LINE_ENDING);\n                        }\n                    }\n                } else if byte == &b'\\n' && !line_ending_is_n {\n                    data.extend(&bytes[start..i]);\n                    data.extend(LINE_ENDING);\n                    start = i + 1;\n                };\n                i += 1;\n            }\n\n            if start < len {\n                data.extend(&bytes[start..len]);\n            }\n        }\n    }\n    Ok(data)\n}\n\nfn array_to_string(array: &Array) -> Result<String> {\n    let mut itoa_buffer = itoa::Buffer::new();\n    let mut ryu_buffer = ryu::Buffer::new();\n\n    let parts = array\n        .clone()\n        .into_iter()\n        .map(|value| {\n            let value = value?;\n            if let Some(string) = value.as_string() {\n                Ok(string.to_string()?)\n            } else if let Some(number) = value.as_int() {\n                Ok(itoa_buffer.format(number).to_string())\n            } else if let Some(number) = value.as_float() {\n                Ok(ryu_buffer.format(number).to_string())\n            } else {\n                Ok(String::new())\n            }\n        })\n        .collect::<Result<Vec<_>>>()?;\n\n    Ok(parts.join(\",\"))\n}\n"
  },
  {
    "path": "modules/llrt_buffer/src/buffer.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{mem::MaybeUninit, slice};\n\nuse llrt_encoding::{bytes_from_b64, bytes_to_b64_string, Encoder};\nuse llrt_utils::{\n    bytes::{get_array_bytes, get_start_end_indexes, ObjectBytes},\n    error_messages::{ERROR_MSG_ARRAY_BUFFER_DETACHED, ERROR_MSG_NOT_ARRAY_BUFFER},\n    iterable_enum,\n    primordials::Primordial,\n    result::ResultExt,\n    string::{get_coerced_string, get_string},\n};\nuse rquickjs::{\n    atom::PredefinedAtom,\n    function::{Constructor, Opt},\n    prelude::{Func, Rest, This},\n    Array, ArrayBuffer, Coerced, Ctx, Exception, Function, IntoJs, JsLifetime, Object, Result,\n    TypedArray, Value,\n};\n\n#[derive(JsLifetime)]\npub struct BufferPrimordials<'js> {\n    constructor: Constructor<'js>,\n}\n\nimpl<'js> Primordial<'js> for BufferPrimordials<'js> {\n    fn new(ctx: &Ctx<'js>) -> Result<Self>\n    where\n        Self: Sized,\n    {\n        let constructor: Constructor = ctx.globals().get(stringify!(Buffer))?;\n\n        Ok(Self { constructor })\n    }\n}\n\npub struct Buffer(pub Vec<u8>);\n\nimpl<'js> IntoJs<'js> for Buffer {\n    fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {\n        let array_buffer = ArrayBuffer::new(ctx.clone(), self.0)?;\n        Self::from_array_buffer(ctx, array_buffer)\n    }\n}\n\nimpl<'js> Buffer {\n    pub fn alloc(length: usize) -> Self {\n        Self(vec![0; length])\n    }\n\n    pub fn to_string(&self, ctx: &Ctx<'js>, encoding: &str) -> Result<String> {\n        Encoder::from_str(encoding)\n            .and_then(|enc| enc.encode_to_string(self.0.as_ref(), true))\n            .or_throw(ctx)\n    }\n\n    fn from_array_buffer(ctx: &Ctx<'js>, buffer: ArrayBuffer<'js>) -> Result<Value<'js>> {\n        BufferPrimordials::get(ctx)?\n            .constructor\n            .construct((buffer,))\n    }\n\n    fn from_array_buffer_offset_length(\n        ctx: &Ctx<'js>,\n        array_buffer: ArrayBuffer<'js>,\n        offset: usize,\n        length: usize,\n    ) -> Result<Value<'js>> {\n        BufferPrimordials::get(ctx)?\n            .constructor\n            .construct((array_buffer, offset, length))\n    }\n\n    fn from_encoding(\n        ctx: &Ctx<'js>,\n        mut bytes: Vec<u8>,\n        encoding: Option<String>,\n    ) -> Result<Value<'js>> {\n        if let Some(encoding) = encoding {\n            let encoder = Encoder::from_str(&encoding).or_throw(ctx)?;\n            bytes = encoder.decode(bytes).or_throw(ctx)?;\n        }\n        Buffer(bytes).into_js(ctx)\n    }\n\n    fn from_string_encoding(\n        ctx: &Ctx<'js>,\n        string: String,\n        encoding: Option<String>,\n    ) -> Result<Value<'js>> {\n        let bytes = if let Some(encoding) = encoding {\n            let encoder = Encoder::from_str(&encoding).or_throw(ctx)?;\n            encoder.decode_from_string(string).or_throw(ctx)?\n        } else {\n            string.into_bytes()\n        };\n        Buffer(bytes).into_js(ctx)\n    }\n}\n\n// Static Methods\nfn alloc<'js>(\n    ctx: Ctx<'js>,\n    length: usize,\n    fill: Opt<Value<'js>>,\n    encoding: Opt<String>,\n) -> Result<Value<'js>> {\n    if let Some(value) = fill.0 {\n        if let Some(value) = value.as_string() {\n            let string = value.to_string()?;\n\n            if let Some(encoding) = encoding.0 {\n                let encoder = Encoder::from_str(&encoding).or_throw(&ctx)?;\n                let bytes = encoder.decode_from_string(string).or_throw(&ctx)?;\n                return alloc_byte_ref(&ctx, &bytes, length);\n            }\n\n            let byte_ref = string.as_bytes();\n\n            return alloc_byte_ref(&ctx, byte_ref, length);\n        }\n        if let Some(value) = value.as_int() {\n            let bytes = vec![value as u8; length];\n            return Buffer(bytes).into_js(&ctx);\n        }\n        if let Some(obj) = value.as_object() {\n            if let Some(ob) = ObjectBytes::from_array_buffer(obj)? {\n                let bytes = ob.as_bytes(&ctx)?;\n                return alloc_byte_ref(&ctx, bytes, length);\n            }\n        }\n    }\n\n    Buffer(vec![0; length]).into_js(&ctx)\n}\n\nfn alloc_byte_ref<'js>(ctx: &Ctx<'js>, byte_ref: &[u8], length: usize) -> Result<Value<'js>> {\n    let mut bytes = vec![0; length];\n    let byte_ref_length = byte_ref.len();\n    for i in 0..length {\n        bytes[i] = byte_ref[i % byte_ref_length];\n    }\n    Buffer(bytes).into_js(ctx)\n}\n\nfn alloc_unsafe(ctx: Ctx<'_>, size: usize) -> Result<Value<'_>> {\n    let mut bytes: Vec<MaybeUninit<u8>> = Vec::with_capacity(size);\n    unsafe {\n        bytes.set_len(size);\n    }\n\n    Buffer(maybeuninit_to_u8(bytes)).into_js(&ctx)\n}\n\nfn maybeuninit_to_u8(vec: Vec<MaybeUninit<u8>>) -> Vec<u8> {\n    let len = vec.len();\n    let capacity = vec.capacity();\n    let ptr = vec.as_ptr() as *mut u8;\n\n    std::mem::forget(vec);\n\n    // This conversion is safe because MaybeUninit has the same memory layout as u8, meaning the underlying bytes are identical.\n    // Since Vec<MaybeUninit> and Vec share the same memory representation, a simple reinterpretation of the pointer is valid.\n    // Additionally, Vec::from_raw_parts correctly reconstructs the vector using the original length and capacity, ensuring that memory ownership remains consistent.\n    // The call to std::mem::forget(vec) prevents the original Vec<MaybeUninit> from being dropped, avoiding double frees or memory corruption.\n    // However, this conversion is only safe if all elements of MaybeUninit are properly initialized.\n    // If any uninitialized values exist, reading them as u8 would lead to undefined behavior.\n    unsafe { Vec::from_raw_parts(ptr, len, capacity) }\n}\n\nfn alloc_unsafe_slow(ctx: Ctx<'_>, size: usize) -> Result<Value<'_>> {\n    let layout = std::alloc::Layout::array::<u8>(size).or_throw(&ctx)?;\n\n    let bytes = unsafe {\n        let ptr = std::alloc::alloc(layout);\n        if ptr.is_null() {\n            return Err(Exception::throw_internal(&ctx, \"Memory allocation failed\"));\n        }\n        Vec::from_raw_parts(ptr, size, size)\n    };\n    Buffer(bytes).into_js(&ctx)\n}\n\nfn byte_length<'js>(ctx: Ctx<'js>, value: Value<'js>, encoding: Opt<String>) -> Result<usize> {\n    //slow path\n    if let Some(encoding) = encoding.0 {\n        let encoder = Encoder::from_str(&encoding).or_throw(&ctx)?;\n        let a = ObjectBytes::from(&ctx, &value)?;\n        let bytes = a.as_bytes(&ctx)?;\n        return Ok(encoder.decode(bytes).or_throw(&ctx)?.len());\n    }\n    //fast path\n    if let Some(val) = value.as_string() {\n        return Ok(val.to_string()?.len());\n    }\n\n    if value.is_array() {\n        let array = value.as_array().unwrap();\n\n        for val in array.iter::<u8>() {\n            val.or_throw_msg(&ctx, \"array value is not u8\")?;\n        }\n\n        return Ok(array.len());\n    }\n\n    if let Some(obj) = value.as_object() {\n        if let Some(ob) = ObjectBytes::from_array_buffer(obj)? {\n            return Ok(ob.as_bytes(&ctx)?.len());\n        }\n    }\n\n    Err(Exception::throw_message(\n        &ctx,\n        \"value must be typed DataView, Buffer, ArrayBuffer, Uint8Array or string\",\n    ))\n}\n\nfn concat<'js>(ctx: Ctx<'js>, list: Array<'js>, max_length: Opt<usize>) -> Result<Value<'js>> {\n    let mut bytes = Vec::new();\n    let mut total_length = 0;\n    let mut length;\n    for value in list.iter::<Object>() {\n        let typed_array = TypedArray::<u8>::from_object(value?)?;\n        let bytes_ref: &[u8] = typed_array.as_ref();\n\n        length = bytes_ref.len();\n\n        if length == 0 {\n            continue;\n        }\n\n        if let Some(max_length) = max_length.0 {\n            total_length += length;\n            if total_length > max_length {\n                let diff = max_length - (total_length - length);\n                bytes.extend_from_slice(&bytes_ref[0..diff]);\n                break;\n            }\n        }\n        bytes.extend_from_slice(bytes_ref);\n    }\n\n    Buffer(bytes).into_js(&ctx)\n}\n\nfn from<'js>(\n    ctx: Ctx<'js>,\n    value: Value<'js>,\n    offset_or_encoding: Opt<Value<'js>>,\n    length: Opt<usize>,\n) -> Result<Value<'js>> {\n    let mut encoding: Option<String> = None;\n    let mut offset = 0;\n\n    if let Some(offset_or_encoding) = offset_or_encoding.0 {\n        if offset_or_encoding.is_string() {\n            encoding = Some(offset_or_encoding.get()?);\n        } else if offset_or_encoding.is_number() {\n            offset = offset_or_encoding.get()?;\n        }\n    }\n\n    // WARN: This is currently bugged for strings that can't be converted to utf8\n    // See https://github.com/quickjs-ng/quickjs/issues/992\n    if let Some(string) = get_string(&value)? {\n        return Buffer::from_string_encoding(&ctx, string, encoding)?.into_js(&ctx);\n    }\n    if let Some(bytes) = get_array_bytes(&value, offset, length.0)? {\n        return Buffer::from_encoding(&ctx, bytes, encoding)?.into_js(&ctx);\n    }\n\n    if let Some(obj) = value.as_object() {\n        if let Some(ab_bytes) = ObjectBytes::from_array_buffer(obj)? {\n            let bytes = ab_bytes.as_bytes(&ctx)?;\n            let (start, end) = get_start_end_indexes(bytes.len(), length.0, offset);\n\n            //buffers from buffer should be copied\n            if obj\n                .get::<_, Option<String>>(PredefinedAtom::Meta)?\n                .as_deref()\n                == Some(stringify!(Buffer))\n                || encoding.is_some()\n            {\n                let bytes = bytes.into();\n                return Buffer::from_encoding(&ctx, bytes, encoding)?.into_js(&ctx);\n            } else {\n                let (array_buffer, _, source_offset) = ab_bytes.get_array_buffer()?.unwrap(); //we know it's an array buffer\n                return Buffer::from_array_buffer_offset_length(\n                    &ctx,\n                    array_buffer,\n                    start + source_offset,\n                    end - start,\n                );\n            }\n        }\n    }\n\n    if let Some(string) = get_coerced_string(&value) {\n        return Buffer::from_string_encoding(&ctx, string, encoding)?.into_js(&ctx);\n    }\n\n    Err(Exception::throw_message(\n        &ctx,\n        \"value must be typed DataView, Buffer, ArrayBuffer, Uint8Array or interpretable as string\",\n    ))\n}\n\nfn is_buffer<'js>(ctx: Ctx<'js>, value: Value<'js>) -> Result<bool> {\n    if let Some(object) = value.as_object() {\n        let constructor = BufferPrimordials::get(&ctx)?;\n        return Ok(object.is_instance_of(&constructor.constructor));\n    }\n\n    Ok(false)\n}\n\nfn is_encoding(value: Value) -> Result<bool> {\n    if let Some(js_string) = value.as_string() {\n        let std_string = js_string.to_string()?;\n        return Ok(Encoder::from_str(std_string.as_str()).is_ok());\n    }\n\n    Ok(false)\n}\n\n// Prototype Methods\nfn copy<'js>(\n    this: This<Object<'js>>,\n    ctx: Ctx<'js>,\n    target: ObjectBytes<'js>,\n    args: Rest<usize>,\n) -> Result<usize> {\n    let mut args_iter = args.0.into_iter();\n    let target_start = args_iter.next().unwrap_or_default();\n    let source_start = args_iter.next().unwrap_or_default();\n    let source_end = args_iter.next().unwrap_or_else(|| this.0.len());\n\n    let mut copyable_length = 0;\n\n    if source_start >= source_end {\n        return Ok(copyable_length);\n    }\n\n    let source_bytes = ObjectBytes::from(&ctx, this.0.as_inner())?;\n    let source_bytes = source_bytes.as_bytes(&ctx)?;\n\n    if let Some((array_buffer, _, _)) = target.get_array_buffer()? {\n        let raw = array_buffer\n            .as_raw()\n            .ok_or(ERROR_MSG_ARRAY_BUFFER_DETACHED)\n            .or_throw(&ctx)?;\n\n        let target_bytes = unsafe { slice::from_raw_parts_mut(raw.ptr.as_ptr(), raw.len) };\n\n        copyable_length = (source_end - source_start).min(raw.len - target_start);\n\n        target_bytes[target_start..target_start + copyable_length]\n            .copy_from_slice(&source_bytes[source_start..source_start + copyable_length]);\n    }\n\n    Ok(copyable_length)\n}\n\nfn subarray<'js>(\n    this: This<Object<'js>>,\n    ctx: Ctx<'js>,\n    start: Opt<isize>,\n    end: Opt<isize>,\n) -> Result<Value<'js>> {\n    let view = TypedArray::<u8>::from_object(this.0.clone())?;\n\n    let array_buffer = view.arraybuffer()?;\n    let view_offset = this.0.get::<_, isize>(\"byteOffset\")?;\n    let view_length = this.0.get::<_, isize>(\"byteLength\")?;\n\n    let start_index = start.map_or(0, |s| {\n        if s < 0 {\n            (view_length + s).max(0)\n        } else {\n            s.min(view_length)\n        }\n    });\n\n    let end_index = end.map_or(view_length, |e| {\n        if e < 0 {\n            (view_length + e).max(0)\n        } else {\n            e.min(view_length)\n        }\n    });\n\n    let length = (end_index - start_index).max(0) as usize;\n    let new_offset = (view_offset + start_index).max(0) as usize;\n\n    Buffer::from_array_buffer_offset_length(&ctx, array_buffer, new_offset, length)\n}\n\nfn to_string(\n    this: This<Object<'_>>,\n    ctx: Ctx,\n    encoding: Opt<String>,\n    start: Opt<i32>,\n    end: Opt<i32>,\n) -> Result<String> {\n    let typed_array = TypedArray::<u8>::from_object(this.0)?;\n    let bytes: &[u8] = typed_array.as_ref();\n\n    let start = start\n        .0\n        .map(|s| s.max(0) as usize)\n        .unwrap_or(0)\n        .min(bytes.len());\n    let end = end\n        .0\n        .map(|e| e.max(0) as usize)\n        .unwrap_or(bytes.len())\n        .min(bytes.len());\n    let bytes = &bytes[start..end];\n\n    let encoder = Encoder::from_optional_str(encoding.as_deref()).or_throw(&ctx)?;\n    encoder.encode_to_string(bytes, true).or_throw(&ctx)\n}\n\nfn write<'js>(\n    this: This<Object<'js>>,\n    ctx: Ctx<'js>,\n    string: String,\n    args: Rest<Value<'js>>,\n) -> Result<usize> {\n    let (offset, length, encoding) = get_write_parameters(&args, this.0.len())?;\n\n    let target = ObjectBytes::from(&ctx, this.0.as_inner())?;\n\n    let mut writable_length = 0;\n\n    if let Some((array_buffer, _, _)) = target.get_array_buffer()? {\n        let raw = array_buffer\n            .as_raw()\n            .ok_or(ERROR_MSG_ARRAY_BUFFER_DETACHED)\n            .or_throw(&ctx)?;\n\n        let target_bytes = unsafe { slice::from_raw_parts_mut(raw.ptr.as_ptr(), raw.len) };\n\n        let encoder = Encoder::from_str(&encoding).or_throw(&ctx)?;\n\n        if encoder.as_label() == \"utf-8\" {\n            let (source_slice, valid_length) = safe_byte_slice(&string, length.min(string.len()));\n            writable_length = valid_length;\n            target_bytes[offset..offset + writable_length].copy_from_slice(source_slice);\n        } else {\n            let decode_bytes = encoder.decode_from_string(string).or_throw(&ctx)?;\n            writable_length = length.min(decode_bytes.len());\n            target_bytes[offset..offset + writable_length]\n                .copy_from_slice(&decode_bytes[..writable_length]);\n        };\n    }\n\n    Ok(writable_length)\n}\n\nfn get_write_parameters(args: &Rest<Value<'_>>, len: usize) -> Result<(usize, usize, String)> {\n    let mut offset = 0;\n    let mut length = len;\n    let mut encoding = \"utf8\".to_owned();\n\n    if let Some(v1) = args.0.first() {\n        if let Some(s) = v1.as_string() {\n            return Ok((0, len, s.to_string()?));\n        }\n        offset = v1.as_int().unwrap_or(0) as usize;\n    }\n\n    if let Some(v2) = args.0.get(1) {\n        if let Some(s) = v2.as_string() {\n            return Ok((offset, len - offset, s.to_string()?));\n        }\n        length = v2\n            .as_int()\n            .map_or(len - offset, |l| (l as usize).min(len - offset));\n    }\n\n    if let Some(v3) = args.0.get(2) {\n        if let Some(s) = v3.as_string() {\n            encoding = s.to_string()?;\n        }\n    }\n\n    Ok((offset, length, encoding))\n}\n\nfn safe_byte_slice(s: &str, end: usize) -> (&[u8], usize) {\n    let bytes = s.as_bytes();\n\n    if bytes.len() <= end {\n        return (bytes, bytes.len());\n    }\n\n    let valid_end = s\n        .char_indices()\n        .map(|(i, _)| i)\n        .rfind(|&i| i <= end)\n        .unwrap_or(0);\n\n    (&bytes[0..valid_end], valid_end)\n}\n\n#[derive(Clone, Copy)]\npub enum Endian {\n    Little,\n    Big,\n}\n\n#[derive(Clone, Copy, PartialEq, Eq)]\npub enum NumberKind {\n    Int8,\n    UInt8,\n    Int16,\n    UInt16,\n    Int32,\n    UInt32,\n    Float32,\n    Float64,\n    BigInt,\n    BigUInt,\n}\n\nimpl NumberKind {\n    pub fn bits(&self) -> u8 {\n        match self {\n            NumberKind::Int8 => 8,\n            NumberKind::UInt8 => 8,\n            NumberKind::Int16 => 16,\n            NumberKind::UInt16 => 16,\n            NumberKind::Int32 => 32,\n            NumberKind::UInt32 => 32,\n            NumberKind::Float32 => 32,\n            NumberKind::Float64 => 64,\n            NumberKind::BigInt => 64,\n            NumberKind::BigUInt => 64,\n        }\n    }\n\n    pub fn is_signed(&self) -> bool {\n        matches!(\n            self,\n            NumberKind::Int8 | NumberKind::Int16 | NumberKind::Int32\n        )\n    }\n\n    pub fn prototype(&self) -> &'static [(Endian, &'static str, Option<&'static str>)] {\n        match self {\n            NumberKind::Int8 => &[(Endian::Little, \"Int8\", None)],\n            NumberKind::UInt8 => &[(Endian::Little, \"UInt8\", Some(\"Uint8\"))],\n            NumberKind::Int16 => &[\n                (Endian::Little, \"Int16LE\", None),\n                (Endian::Big, \"Int16BE\", None),\n            ],\n            NumberKind::UInt16 => &[\n                (Endian::Little, \"UInt16LE\", Some(\"Uint16LE\")),\n                (Endian::Big, \"UInt16BE\", Some(\"Uint16BE\")),\n            ],\n            NumberKind::Int32 => &[\n                (Endian::Little, \"Int32LE\", None),\n                (Endian::Big, \"Int32BE\", None),\n            ],\n            NumberKind::UInt32 => &[\n                (Endian::Little, \"UInt32LE\", Some(\"Uint32LE\")),\n                (Endian::Big, \"UInt32BE\", Some(\"Uint32BE\")),\n            ],\n            NumberKind::Float32 => &[\n                (Endian::Little, \"FloatLE\", None),\n                (Endian::Big, \"FloatBE\", None),\n            ],\n            NumberKind::Float64 => &[\n                (Endian::Little, \"DoubleLE\", None),\n                (Endian::Big, \"DoubleBE\", None),\n            ],\n            NumberKind::BigInt => &[\n                (Endian::Little, \"BigInt64LE\", None),\n                (Endian::Big, \"BigInt64BE\", None),\n            ],\n            NumberKind::BigUInt => &[\n                (Endian::Little, \"BigUInt64LE\", Some(\"BigUint64LE\")),\n                (Endian::Big, \"BigUInt64BE\", Some(\"BigUint64BE\")),\n            ],\n        }\n    }\n}\n\niterable_enum!(\n    NumberKind, Int8, UInt8, Int16, UInt16, Int32, UInt32, Float32, Float64, BigInt, BigUInt\n);\n\n#[allow(clippy::too_many_arguments)]\nfn write_buf<'js>(\n    this: &This<Object<'js>>,\n    ctx: &Ctx<'js>,\n    value: &Value<'js>,\n    offset: &Opt<usize>,\n    endian: Endian,\n    kind: NumberKind,\n) -> Result<usize> {\n    let offset = offset.0.unwrap_or_default();\n\n    // Extract and convert value\n    let (byte_count, bytes) = match kind {\n        NumberKind::BigInt => {\n            let Some(bigint) = value.as_big_int() else {\n                return Err(Exception::throw_type(ctx, \"Expected BigInt\"));\n            };\n            let (byte_count, val) = (8, bigint.clone().to_i64().or_throw(ctx)? as u64);\n            (byte_count, endian_bytes(val, endian))\n        },\n        NumberKind::BigUInt => {\n            return Err(Exception::throw_type(ctx, \"Uint64 is not supported\"));\n        },\n        NumberKind::Float32 => {\n            let Some(float_val) = value.as_float() else {\n                return Err(Exception::throw_type(ctx, \"Expected number\"));\n            };\n            match endian {\n                Endian::Big => (4, (float_val as f32).to_bits().to_be_bytes().to_vec()),\n                Endian::Little => (4, (float_val as f32).to_bits().to_le_bytes().to_vec()),\n            }\n        },\n        NumberKind::Float64 => {\n            let Some(float_val) = value.as_float() else {\n                return Err(Exception::throw_type(ctx, \"Expected number\"));\n            };\n            match endian {\n                Endian::Big => (8, float_val.to_bits().to_be_bytes().to_vec()),\n                Endian::Little => (8, float_val.to_bits().to_le_bytes().to_vec()),\n            }\n        },\n        NumberKind::Int8\n        | NumberKind::UInt8\n        | NumberKind::Int16\n        | NumberKind::UInt16\n        | NumberKind::Int32\n        | NumberKind::UInt32 => {\n            let Some(int_val) = value.as_number() else {\n                return Err(Exception::throw_type(ctx, \"Expected number\"));\n            };\n            let int_val = int_val as i64;\n            let bit_mask = (1i64 << kind.bits()) - 1;\n            let max_val = if kind.is_signed() {\n                (1i64 << (kind.bits() - 1)) - 1\n            } else {\n                bit_mask\n            };\n            let min_val = if kind.is_signed() { -max_val - 1 } else { 0 };\n\n            if int_val < min_val || int_val > max_val {\n                return Err(Exception::throw_range(ctx, \"Value out of range\"));\n            }\n\n            let masked = int_val & bit_mask;\n            (\n                (kind.bits() / 8) as usize,\n                shifted_bytes(masked as u64, kind.bits(), endian),\n            )\n        },\n    };\n\n    if offset >= this.0.len() || offset + byte_count > this.0.len() {\n        return Err(Exception::throw_range(\n            ctx,\n            \"The specified offset is out of range\",\n        ));\n    }\n\n    let target = ObjectBytes::from(ctx, this.0.as_inner())?;\n    let mut writable_length = 0;\n\n    if let Some((array_buffer, _, _)) = target.get_array_buffer()? {\n        let raw = array_buffer\n            .as_raw()\n            .ok_or(ERROR_MSG_ARRAY_BUFFER_DETACHED)\n            .or_throw(ctx)?;\n\n        let target_bytes = unsafe { slice::from_raw_parts_mut(raw.ptr.as_ptr(), raw.len) };\n\n        writable_length = offset + bytes.len();\n        target_bytes[offset..writable_length].copy_from_slice(&bytes);\n    }\n\n    Ok(writable_length)\n}\n\nfn read_buf<'js>(\n    this: &This<Object<'js>>,\n    ctx: &Ctx<'js>,\n    offset: &Opt<usize>,\n    endian: Endian,\n    kind: NumberKind,\n) -> Result<Value<'js>> {\n    // Retrieve the array buffer\n    let target = ObjectBytes::from(ctx, this.0.as_inner())?;\n    let Some((array_buffer, _, _)) = target.get_array_buffer()? else {\n        return Err(Exception::throw_message(ctx, ERROR_MSG_NOT_ARRAY_BUFFER));\n    };\n    let raw = array_buffer\n        .as_raw()\n        .ok_or(ERROR_MSG_ARRAY_BUFFER_DETACHED)\n        .or_throw(ctx)?;\n    let target_bytes = unsafe { slice::from_raw_parts_mut(raw.ptr.as_ptr(), raw.len) };\n\n    // Enforce the bounds\n    let start = offset.0.unwrap_or_default();\n    let end = start + (kind.bits() / 8) as usize;\n    if end > raw.len {\n        return Err(Exception::throw_range(\n            ctx,\n            \"The value of \\\"offset\\\" is out of range\",\n        ));\n    }\n\n    let bytes = &target_bytes[start..end];\n\n    let value = match kind {\n        NumberKind::BigInt => {\n            let value = match endian {\n                Endian::Big => i64::from_be_bytes(bytes.try_into().unwrap()),\n                Endian::Little => i64::from_le_bytes(bytes.try_into().unwrap()),\n            };\n            Value::new_big_int(ctx.clone(), value)\n        },\n        NumberKind::BigUInt => {\n            return Err(Exception::throw_type(ctx, \"Uint64 is not supported\"));\n        },\n        NumberKind::Float32 => {\n            let value = match endian {\n                Endian::Big => f32::from_be_bytes(bytes.try_into().unwrap()),\n                Endian::Little => f32::from_le_bytes(bytes.try_into().unwrap()),\n            };\n            Value::new_float(ctx.clone(), value as f64)\n        },\n        NumberKind::Float64 => {\n            let value = match endian {\n                Endian::Big => f64::from_be_bytes(bytes.try_into().unwrap()),\n                Endian::Little => f64::from_le_bytes(bytes.try_into().unwrap()),\n            };\n            Value::new_float(ctx.clone(), value)\n        },\n        NumberKind::Int8 => {\n            let value = match endian {\n                Endian::Big => i8::from_be_bytes(bytes.try_into().unwrap()),\n                Endian::Little => i8::from_le_bytes(bytes.try_into().unwrap()),\n            };\n            Value::new_int(ctx.clone(), value as i32)\n        },\n        NumberKind::UInt8 => {\n            let value = match endian {\n                Endian::Big => u8::from_be_bytes(bytes.try_into().unwrap()),\n                Endian::Little => u8::from_le_bytes(bytes.try_into().unwrap()),\n            };\n            Value::new_int(ctx.clone(), value as i32)\n        },\n        NumberKind::Int16 => {\n            let value = match endian {\n                Endian::Big => i16::from_be_bytes(bytes.try_into().unwrap()),\n                Endian::Little => i16::from_le_bytes(bytes.try_into().unwrap()),\n            };\n            Value::new_int(ctx.clone(), value as i32)\n        },\n        NumberKind::UInt16 => {\n            let value = match endian {\n                Endian::Big => u16::from_be_bytes(bytes.try_into().unwrap()),\n                Endian::Little => u16::from_le_bytes(bytes.try_into().unwrap()),\n            };\n            Value::new_int(ctx.clone(), value as i32)\n        },\n        NumberKind::Int32 => {\n            let value = match endian {\n                Endian::Big => i32::from_be_bytes(bytes.try_into().unwrap()),\n                Endian::Little => i32::from_le_bytes(bytes.try_into().unwrap()),\n            };\n            Value::new_int(ctx.clone(), value)\n        },\n        NumberKind::UInt32 => {\n            let value = match endian {\n                Endian::Big => u32::from_be_bytes(bytes.try_into().unwrap()),\n                Endian::Little => u32::from_le_bytes(bytes.try_into().unwrap()),\n            };\n            Value::new_float(ctx.clone(), value as f64)\n        },\n    };\n    Ok(value)\n}\n\n// Pure mathematical byte generation\nfn endian_bytes(mut val: u64, endian: Endian) -> Vec<u8> {\n    let mut bytes = vec![0u8; 8];\n\n    #[allow(clippy::needless_range_loop)]\n    for i in 0..8 {\n        bytes[i] = match endian {\n            Endian::Big => (val >> (56 - i * 8)) as u8,\n            Endian::Little => (val >> (i * 8)) as u8,\n        };\n        // Clear processed bits\n        match endian {\n            Endian::Big => val &= !(0xFF << ((7 - i) * 8)),\n            Endian::Little => val &= !(0xFF << (i * 8)),\n        }\n    }\n    bytes\n}\n\nfn shifted_bytes(mut val: u64, bits: u8, endian: Endian) -> Vec<u8> {\n    let byte_count = (bits / 8) as usize;\n    let mut bytes = vec![0u8; byte_count];\n\n    #[allow(clippy::needless_range_loop)]\n    for i in 0..byte_count {\n        let shift = match endian {\n            Endian::Big => (byte_count - 1 - i) * 8,\n            Endian::Little => i * 8,\n        };\n        bytes[i] = (val >> shift) as u8;\n        val &= !(0xFF << shift); // Clear processed bits\n    }\n    bytes\n}\n\npub(crate) fn set_prototype<'js>(ctx: &Ctx<'js>, constructor: Object<'js>) -> Result<()> {\n    let _ = &constructor.set(\"alloc\", Func::from(alloc))?;\n    let _ = &constructor.set(\"allocUnsafe\", Func::from(alloc_unsafe))?;\n    let _ = &constructor.set(\"allocUnsafeSlow\", Func::from(alloc_unsafe_slow))?;\n    let _ = &constructor.set(\"byteLength\", Func::from(byte_length))?;\n    let _ = &constructor.set(\"concat\", Func::from(concat))?;\n    let _ = &constructor.set(PredefinedAtom::From, Func::from(from))?;\n    let _ = &constructor.set(\"isBuffer\", Func::from(is_buffer))?;\n    let _ = &constructor.set(\"isEncoding\", Func::from(is_encoding))?;\n\n    let prototype: &Object = &constructor.get(PredefinedAtom::Prototype)?;\n    prototype.set(\"copy\", Func::from(copy))?;\n    prototype.set(\"subarray\", Func::from(subarray))?;\n    prototype.set(PredefinedAtom::ToString, Func::from(to_string))?;\n    prototype.set(\"write\", Func::from(write))?;\n\n    // Set all write and read methods\n    for kind in NumberKind::iter() {\n        for (endian, name, alias) in kind.prototype() {\n            let write_func = Function::new(ctx.clone(), |t, c, v, o| {\n                write_buf(&t, &c, &v, &o, *endian, *kind)\n            })?;\n            let read_func =\n                Function::new(ctx.clone(), |t, c, o| read_buf(&t, &c, &o, *endian, *kind))?;\n            if let Some(alias) = alias {\n                prototype.set([\"write\", alias].concat(), write_func.clone())?;\n                prototype.set([\"read\", alias].concat(), read_func.clone())?;\n            }\n            prototype.set([\"write\", name].concat(), write_func)?;\n            prototype.set([\"read\", name].concat(), read_func)?;\n        }\n    }\n\n    //not assessable from js\n    prototype.prop(PredefinedAtom::Meta, stringify!(Buffer))?;\n\n    ctx.globals().set(stringify!(Buffer), constructor)?;\n\n    Ok(())\n}\n\npub fn atob(ctx: Ctx<'_>, encoded_value: Coerced<String>) -> Result<rquickjs::String<'_>> {\n    let vec = bytes_from_b64(encoded_value.as_bytes()).or_throw(&ctx)?;\n    // Convert bytes to Latin-1 string where each byte becomes a character with that code point.\n    // This matches the WHATWG spec: atob returns a \"binary string\" where each character's\n    // code point is 0-255, directly representing one byte of data.\n    let str: String = vec.iter().map(|&b| b as char).collect();\n    rquickjs::String::from_str(ctx, &str)\n}\n\npub fn btoa(ctx: Ctx<'_>, value: Coerced<String>) -> Result<String> {\n    // Per WHATWG spec, btoa() treats input as a \"binary string\" where each character\n    // must have a code point 0-255. Characters > 255 cause InvalidCharacterError.\n    let s: &str = value.as_str();\n\n    // Fast path: ASCII is a 1:1 mapping to bytes 0-127 (SIMD optimized)\n    if s.is_ascii() {\n        return Ok(bytes_to_b64_string(s.as_bytes()));\n    }\n\n    // Slow path: Check for Latin-1 (0-255)\n    let bytes: Vec<u8> = s\n        .chars()\n        .map(|c| {\n            let code_point = c as u32;\n            if code_point > 255 {\n                Err(Exception::throw_message(\n                    &ctx,\n                    \"Invalid character: btoa() argument contains character with code point > 255\",\n                ))\n            } else {\n                Ok(code_point as u8)\n            }\n        })\n        .collect::<Result<Vec<u8>>>()?;\n    Ok(bytes_to_b64_string(&bytes))\n}\n\n#[cfg(test)]\nmod tests {\n    use llrt_test::{call_test, test_async_with, ModuleEvaluator};\n\n    use crate::BufferModule;\n\n    #[tokio::test]\n    async fn test_atob() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                crate::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<BufferModule>(ctx.clone(), \"buffer\")\n                    .await\n                    .unwrap();\n\n                let data = \"aGVsbG8gd29ybGQ=\".to_string();\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { atob } from 'buffer';\n\n                        export async function test(data) {\n                            return atob(data);\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<String, _>(&ctx, &module, (data,)).await;\n                assert_eq!(result, \"hello world\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_atob_high_bytes() {\n        // Test that atob correctly decodes bytes 128-255 as Latin-1 characters\n        // (each byte becomes a character with that code point)\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                crate::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<BufferModule>(ctx.clone(), \"buffer\")\n                    .await\n                    .unwrap();\n\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { atob } from 'buffer';\n\n                        export async function test() {\n                            // Test individual high-byte values\n                            // gA== decodes to byte 0x80 (128)\n                            // /w== decodes to byte 0xFF (255)\n                            const test128 = atob(\"gA==\");\n                            const test255 = atob(\"/w==\");\n\n                            // Each decoded byte should become a character\n                            // with that exact code point\n                            if (test128.charCodeAt(0) !== 128) {\n                                return `byte 128 failed: got ${test128.charCodeAt(0)}`;\n                            }\n                            if (test255.charCodeAt(0) !== 255) {\n                                return `byte 255 failed: got ${test255.charCodeAt(0)}`;\n                            }\n\n                            // Test all bytes 128-255 to ensure none are corrupted\n                            // Create base64 for bytes 128-255 and verify roundtrip\n                            const highBytes = new Uint8Array(128);\n                            for (let i = 0; i < 128; i++) {\n                                highBytes[i] = 128 + i;\n                            }\n                            const base64 = Buffer.from(highBytes).toString(\"base64\");\n                            const decoded = atob(base64);\n\n                            for (let i = 0; i < 128; i++) {\n                                const expected = 128 + i;\n                                const actual = decoded.charCodeAt(i);\n                                if (actual !== expected) {\n                                    return `byte ${expected} failed: got ${actual}`;\n                                }\n                            }\n\n                            return \"ok\";\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<String, _>(&ctx, &module, ()).await;\n                assert_eq!(result, \"ok\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_btoa() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                crate::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<BufferModule>(ctx.clone(), \"buffer\")\n                    .await\n                    .unwrap();\n\n                let data = \"hello world\".to_string();\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { btoa } from 'buffer';\n\n                        export async function test(data) {\n                            return btoa(data);\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<String, _>(&ctx, &module, (data,)).await;\n                assert_eq!(result, \"aGVsbG8gd29ybGQ=\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_btoa_high_bytes() {\n        // Test that btoa correctly encodes Latin-1 characters (code points 128-255)\n        // as single bytes per WHATWG spec (not UTF-8 encoded)\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                crate::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<BufferModule>(ctx.clone(), \"buffer\")\n                    .await\n                    .unwrap();\n\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { btoa, atob } from 'buffer';\n\n                        export async function test() {\n                            // Test byte 255 (0xFF): should encode as single byte\n                            // btoa(String.fromCharCode(255)) should give \"/w==\" not \"w78=\"\n                            const char255 = String.fromCharCode(255);\n                            const encoded255 = btoa(char255);\n                            if (encoded255 !== \"/w==\") {\n                                return `byte 255 encoding failed: got ${encoded255}, expected /w==`;\n                            }\n\n                            // Test byte 128 (0x80): should encode as single byte\n                            const char128 = String.fromCharCode(128);\n                            const encoded128 = btoa(char128);\n                            if (encoded128 !== \"gA==\") {\n                                return `byte 128 encoding failed: got ${encoded128}, expected gA==`;\n                            }\n\n                            // Test roundtrip for all bytes 0-255\n                            for (let i = 0; i <= 255; i++) {\n                                const char = String.fromCharCode(i);\n                                const encoded = btoa(char);\n                                const decoded = atob(encoded);\n                                if (decoded.charCodeAt(0) !== i || decoded.length !== 1) {\n                                    return `roundtrip failed for byte ${i}`;\n                                }\n                            }\n\n                            // Test that characters > 255 throw\n                            try {\n                                btoa(\"€\"); // U+20AC\n                                return \"btoa should have thrown for euro sign\";\n                            } catch (e) {\n                                // Expected\n                            }\n\n                            return \"ok\";\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<String, _>(&ctx, &module, ()).await;\n                assert_eq!(result, \"ok\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_subarray() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                crate::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<BufferModule>(ctx.clone(), \"buffer\")\n                    .await\n                    .unwrap();\n\n                let data = \"hello world\".to_string().into_bytes();\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { Buffer } from 'buffer';\n\n                        export async function test(data) {\n                            let buffer = Buffer.from(data);\n                            let sub = buffer.subarray(6, 11); // \"world\" part\n                            return sub.toString();\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<String, _>(&ctx, &module, (data,)).await;\n                assert_eq!(result, \"world\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_subarray_partial() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                crate::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<BufferModule>(ctx.clone(), \"buffer\")\n                    .await\n                    .unwrap();\n\n                let data = \"hello world\".to_string().into_bytes();\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { Buffer } from 'buffer';\n\n                        export async function test(data) {\n                            let buffer = Buffer.from(data);\n                            let sub = buffer.subarray(0, 5); // \"hello\" part\n                            return sub.toString();\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<String, _>(&ctx, &module, (data,)).await;\n                assert_eq!(result, \"hello\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_subarray_out_of_bounds() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                crate::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<BufferModule>(ctx.clone(), \"buffer\")\n                    .await\n                    .unwrap();\n\n                let data = \"hello world\".to_string().into_bytes();\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { Buffer } from 'buffer';\n\n                        export async function test(data) {\n                            let buffer = Buffer.from(data);\n                            let sub = buffer.subarray(6, 20); // \"world\" part but goes out of bounds\n                            return sub.toString();\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<String, _>(&ctx, &module, (data,)).await;\n                assert_eq!(result, \"world\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_read_int_32_be() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                crate::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<BufferModule>(ctx.clone(), \"buffer\")\n                    .await\n                    .unwrap();\n\n                let data = \"hello world\".to_string().into_bytes();\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { Buffer } from 'buffer';\n\n                        export async function test(data) {\n                            const buf = Buffer.from([1, 2, 3, 4, 0, 0, 0, 0]);\n                            return buf.readInt32BE();\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<i32, _>(&ctx, &module, (data,)).await;\n                assert_eq!(result, 0x01020304);\n            })\n        })\n        .await;\n    }\n}\n"
  },
  {
    "path": "modules/llrt_buffer/src/file.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_utils::time;\nuse rquickjs::{\n    atom::PredefinedAtom, class::Trace, function::Opt, ArrayBuffer, Coerced, Ctx, Exception,\n    IntoJs, Object, Result, Value,\n};\n\nuse super::blob::Blob;\n\n#[rquickjs::class]\n#[derive(Trace, Clone, rquickjs::JsLifetime)]\npub struct File {\n    #[qjs(skip_trace)]\n    blob: Blob,\n    filename: String,\n    last_modified: i64,\n}\n\n#[rquickjs::methods]\nimpl File {\n    #[qjs(constructor)]\n    fn new<'js>(\n        ctx: Ctx<'js>,\n        data: Value<'js>,\n        filename: Coerced<String>,\n        options: Opt<Value<'js>>,\n    ) -> Result<Self> {\n        let mut last_modified = time::now_millis();\n\n        if let Some(ref opts) = options.0 {\n            if opts.is_bool() || opts.is_float() || opts.is_int() || opts.is_string() {\n                return Err(Exception::throw_type(&ctx, \"Invalid options\"));\n            }\n\n            if let Some(v) = opts.as_object() {\n                if let Some(x) = v.get::<_, Option<Coerced<i64>>>(\"lastModified\")? {\n                    last_modified = x.0;\n                }\n            }\n        }\n\n        let blob = Blob::new(ctx, Opt(Some(data)), options)?;\n\n        Ok(Self {\n            blob,\n            filename: filename.0,\n            last_modified,\n        })\n    }\n\n    #[qjs(get)]\n    pub fn size(&self) -> usize {\n        self.blob.size()\n    }\n\n    #[qjs(get)]\n    pub fn name(&self) -> String {\n        self.filename.clone()\n    }\n\n    #[qjs(get, rename = \"type\")]\n    pub fn mime_type(&self) -> String {\n        self.blob.mime_type()\n    }\n\n    #[qjs(get, rename = \"lastModified\")]\n    pub fn last_modified(&self) -> i64 {\n        self.last_modified\n    }\n\n    pub fn slice(&self, start: Opt<isize>, end: Opt<isize>, content_type: Opt<String>) -> Blob {\n        self.blob.slice(start, end, content_type)\n    }\n\n    pub async fn text(&mut self) -> String {\n        self.blob.text().await\n    }\n\n    #[qjs(rename = \"arrayBuffer\")]\n    pub async fn array_buffer<'js>(&self, ctx: Ctx<'js>) -> Result<ArrayBuffer<'js>> {\n        self.blob.array_buffer(ctx).await\n    }\n\n    pub async fn bytes<'js>(&self, ctx: Ctx<'js>) -> Result<Value<'js>> {\n        self.blob.bytes(ctx).await\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    pub fn to_string_tag(&self) -> &'static str {\n        stringify!(File)\n    }\n}\nimpl File {\n    pub fn from_bytes<'js>(\n        ctx: &Ctx<'js>,\n        data: Vec<u8>,\n        filename: String,\n        mime_type: Option<String>,\n    ) -> Result<Self> {\n        let options = Opt(Some({\n            let obj = Object::new(ctx.clone())?;\n            obj.set(\n                \"type\",\n                mime_type\n                    .clone()\n                    .unwrap_or(\"application/octet-stream\".into())\n                    .into_js(ctx)?,\n            )?;\n            obj.into_js(ctx)?\n        }));\n        let blob = Blob::new(ctx.clone(), Opt(Some(data.into_js(ctx)?)), options)?;\n\n        Ok(Self {\n            blob,\n            filename,\n            last_modified: time::now_millis(),\n        })\n    }\n\n    pub fn get_blob(&self) -> Blob {\n        self.blob.clone()\n    }\n}\n"
  },
  {
    "path": "modules/llrt_buffer/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_utils::{\n    module::{export_default, ModuleInfo},\n    primordials::{BasePrimordials, Primordial},\n};\nuse rquickjs::{\n    atom::PredefinedAtom,\n    function::Constructor,\n    module::{Declarations, Exports, ModuleDef},\n    prelude::Func,\n    Class, Ctx, Object, Result,\n};\n\npub use self::array_buffer_view::*;\npub use self::blob::*;\npub use self::buffer::*;\npub use self::file::*;\n\nmod array_buffer_view;\nmod blob;\nmod buffer;\nmod file;\n\npub struct BufferModule;\n\nimpl ModuleDef for BufferModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(stringify!(Buffer))?;\n        declare.declare(\"atob\")?;\n        declare.declare(\"btoa\")?;\n        declare.declare(\"constants\")?;\n        declare.declare(\"default\")?;\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        let globals = ctx.globals();\n        let buf: Constructor = globals.get(stringify!(Buffer))?;\n\n        let constants = Object::new(ctx.clone())?;\n        constants.set(\"MAX_LENGTH\", u32::MAX)?; // For QuickJS\n        constants.set(\"MAX_STRING_LENGTH\", (1 << 30) - 1)?; // For QuickJS\n\n        export_default(ctx, exports, |default| {\n            default.set(stringify!(Buffer), buf)?;\n            default.set(\"atob\", Func::from(atob))?;\n            default.set(\"btoa\", Func::from(btoa))?;\n            default.set(\"constants\", constants)?;\n            Ok(())\n        })?;\n\n        Ok(())\n    }\n}\n\nimpl From<BufferModule> for ModuleInfo<BufferModule> {\n    fn from(val: BufferModule) -> Self {\n        ModuleInfo {\n            name: \"buffer\",\n            module: val,\n        }\n    }\n}\n\npub fn init<'js>(ctx: &Ctx<'js>) -> Result<()> {\n    let globals = ctx.globals();\n    BasePrimordials::init(ctx)?;\n\n    // Buffer\n    let buffer = ctx.eval::<Object<'js>, &str>(concat!(\n        \"class \",\n        stringify!(Buffer),\n        \" extends Uint8Array {}\\n\",\n        stringify!(Buffer),\n    ))?;\n    set_prototype(ctx, buffer)?;\n\n    BufferPrimordials::init(ctx)?;\n\n    // Blob\n    if let Some(constructor) = Class::<Blob>::create_constructor(ctx)? {\n        constructor.prop(\n            PredefinedAtom::SymbolHasInstance,\n            Func::from(Blob::has_instance),\n        )?;\n        globals.set(stringify!(Blob), constructor)?;\n    }\n\n    // File\n    Class::<File>::define(&globals)?;\n\n    //init primordials\n    let _ = BufferPrimordials::get(ctx)?;\n\n    // Conversion\n    globals.set(\"atob\", Func::from(atob))?;\n    globals.set(\"btoa\", Func::from(btoa))?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "modules/llrt_child_process/Cargo.toml",
    "content": "[package]\nname = \"llrt_child_process\"\ndescription = \"LLRT Module child_process\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[lib]\nname = \"llrt_child_process\"\npath = \"src/lib.rs\"\n\n[dependencies]\nitoa = { version = \"1\", default-features = false }\nllrt_buffer = { version = \"0.8.1-beta\", path = \"../llrt_buffer\" }\nllrt_context = { version = \"0.8.1-beta\", path = \"../../libs/llrt_context\" }\nllrt_events = { version = \"0.8.1-beta\", path = \"../llrt_events\" }\nllrt_stream = { version = \"0.8.1-beta\", path = \"../llrt_stream\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", default-features = false }\ntokio = { version = \"1\", features = [\"process\"], default-features = false }\n\n[target.'cfg(unix)'.dependencies]\nlibc = { version = \"0.2\", default-features = false }\n\n[dev-dependencies]\nllrt_test = { path = \"../../libs/llrt_test\" }\n"
  },
  {
    "path": "modules/llrt_child_process/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#![allow(clippy::uninlined_format_args)]\n\n#[cfg(windows)]\nuse std::os::windows::{\n    io::{FromRawHandle, RawHandle},\n    process::CommandExt,\n};\n#[cfg(unix)]\nuse std::os::{\n    fd::FromRawFd,\n    unix::process::{CommandExt, ExitStatusExt},\n};\nuse std::{\n    collections::HashMap,\n    io::Result as IoResult,\n    process::{Command as StdCommand, Stdio},\n    sync::{Arc, RwLock},\n};\n\nuse llrt_context::CtxExtension;\nuse llrt_events::{EmitError, Emitter, EventEmitter, EventList};\nuse llrt_stream::{\n    readable::{DefaultReadableStream, ReadableStream},\n    writable::{DefaultWritableStream, WritableStream},\n};\nuse llrt_utils::{\n    module::{export_default, ModuleInfo},\n    object::ObjectExt,\n    result::ResultExt,\n};\nuse rquickjs::{\n    class::{Trace, Tracer},\n    convert::Coerced,\n    module::{Declarations, Exports, ModuleDef},\n    prelude::{Func, Opt, Rest, This},\n    Class, Ctx, Error, Exception, IntoJs, Result, Value,\n};\nuse tokio::{\n    io::AsyncRead,\n    process::{Child, Command},\n    sync::{\n        broadcast::{channel as broadcast_channel, Receiver, Sender},\n        oneshot::Receiver as OneshotReceiver,\n    },\n};\n\n#[cfg(unix)]\nuse llrt_utils::signals::{kill, signal_str_from_i32};\n\n#[cfg(not(unix))]\nuse llrt_utils::signals::{kill_process_raw, parse_signal};\n\n#[allow(unused_variables)]\nfn prepare_shell_args(\n    shell: &str,\n    windows_verbatim_arguments: &mut bool,\n    cmd: String,\n    command_args: Option<Vec<String>>,\n) -> Vec<String> {\n    let mut string_args = cmd;\n\n    #[cfg(windows)]\n    let shell_is_cmd = shell.ends_with(\"cmd\") || shell.ends_with(\"cmd.exe\");\n\n    #[cfg(windows)]\n    {\n        if shell_is_cmd {\n            *windows_verbatim_arguments = true;\n            string_args.insert(0, '\"');\n        }\n    }\n\n    if let Some(command_args) = command_args {\n        //reserve at least arg length +1\n        let total_length = command_args.iter().map(|s| s.len() + 1).sum();\n        string_args.reserve(total_length);\n        string_args.push(' ');\n\n        for arg in command_args.iter() {\n            string_args.push_str(arg);\n            string_args.push(' ');\n        }\n    } else {\n        string_args.push(' ');\n    }\n\n    #[cfg(windows)]\n    {\n        if shell_is_cmd {\n            string_args.push('\"');\n            return vec![\n                String::from(\"/d\"),\n                String::from(\"/s\"),\n                String::from(\"/c\"),\n                string_args,\n            ];\n        }\n    }\n\n    vec![\"-c\".into(), string_args]\n}\n\n#[allow(dead_code)]\n#[rquickjs::class]\n#[derive(rquickjs::JsLifetime)]\npub struct ChildProcess<'js> {\n    emitter: EventEmitter<'js>,\n    args: Option<Vec<String>>,\n    command: String,\n    kill_tx: Option<Sender<()>>,\n    pid: Option<u32>,\n}\n\nimpl<'js> Trace<'js> for ChildProcess<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.emitter.trace(tracer);\n    }\n}\n\n#[derive(Clone)]\nenum StdioEnum {\n    Piped,\n    Ignore,\n    Inherit,\n    Fd(i32),\n}\nimpl StdioEnum {\n    fn to_stdio(&self) -> Stdio {\n        match self {\n            StdioEnum::Piped => Stdio::piped(),\n            StdioEnum::Ignore => Stdio::null(),\n            StdioEnum::Inherit => Stdio::inherit(),\n            StdioEnum::Fd(id) => {\n                #[cfg(unix)]\n                unsafe {\n                    Stdio::from_raw_fd(*id)\n                }\n                #[cfg(windows)]\n                unsafe {\n                    Stdio::from_raw_handle(*id as RawHandle)\n                }\n            },\n        }\n    }\n}\n\n#[rquickjs::methods]\nimpl<'js> ChildProcess<'js> {\n    #[qjs(get)]\n    fn pid(&self, ctx: Ctx<'js>) -> Result<Value<'js>> {\n        self.pid.into_js(&ctx)\n    }\n\n    #[allow(unused_variables)]\n    fn kill(&mut self, ctx: Ctx<'js>, signal: Opt<Value<'js>>) -> Result<bool> {\n        if let Some(pid) = self.pid {\n            #[cfg(unix)]\n            {\n                return kill(&ctx, pid, signal);\n            }\n\n            #[cfg(windows)]\n            {\n                let signal = parse_signal(signal.0)?;\n                if signal == 0 {\n                    return kill_process_raw(pid, 0)\n                        .map(|_| true)\n                        .or_else(|_| Ok(false));\n                }\n\n                if let Some(tx) = self.kill_tx.take() {\n                    return Ok(tx.send(()).is_ok());\n                }\n            }\n        }\n\n        Ok(false)\n    }\n}\n\nimpl<'js> ChildProcess<'js> {\n    fn new(\n        ctx: Ctx<'js>,\n        command: String,\n        args: Option<Vec<String>>,\n        child: IoResult<Child>,\n    ) -> Result<Class<'js, Self>> {\n        let (kill_tx, kill_rx) = broadcast_channel::<()>(1);\n\n        let instance = Self {\n            emitter: EventEmitter::new(),\n            command: command.clone(),\n            args,\n            pid: None,\n            kill_tx: Some(kill_tx),\n        };\n\n        let stdout_instance = DefaultReadableStream::new(ctx.clone())?;\n        let stderr_instance = DefaultReadableStream::new(ctx.clone())?;\n        let stdin_instance = DefaultWritableStream::new(ctx.clone())?;\n\n        let instance = Class::instance(ctx.clone(), instance)?;\n        let instance2 = instance.clone();\n        let instance3 = instance.clone();\n        let instance4 = instance.clone();\n\n        instance.set(\"stderr\", stderr_instance.clone())?;\n        instance.set(\"stdout\", stdout_instance.clone())?;\n        instance.set(\"stdin\", stdin_instance.clone())?;\n\n        match child {\n            Ok(mut child) => {\n                instance2.borrow_mut().pid = child.id();\n\n                if let Some(child_stdin) = child.stdin.take() {\n                    DefaultWritableStream::process(stdin_instance.clone(), &ctx, child_stdin)?;\n                };\n\n                let stdout_join_receiver =\n                    create_output(&ctx, child.stdout.take(), stdout_instance.clone())?;\n\n                let stderr_join_receiver =\n                    create_output(&ctx, child.stderr.take(), stderr_instance.clone())?;\n\n                let ctx2 = ctx.clone();\n                let ctx3 = ctx.clone();\n\n                ctx.spawn_exit(async move {\n                    let spawn_proc = async move {\n                        let mut exit_code = None;\n                        let mut exit_signal = None;\n\n                        wait_for_process(child, &ctx3, kill_rx, &mut exit_code, &mut exit_signal)\n                            .await?;\n\n                        let code = match exit_code {\n                            Some(c) => c.into_js(&ctx3)?,\n                            None => rquickjs::Null.into_value(ctx3.clone()),\n                        };\n                        let signal;\n                        #[cfg(unix)]\n                        {\n                            if let Some(s) = exit_signal {\n                                signal = signal_str_from_i32(s).into_js(&ctx3)?;\n                            } else {\n                                signal = rquickjs::Null.into_value(ctx3.clone());\n                            }\n                        }\n                        #[cfg(not(unix))]\n                        {\n                            signal = \"SIGKILL\".into_js(&ctx3)?;\n                        }\n\n                        ChildProcess::emit_str(\n                            This(instance2.clone()),\n                            &ctx3,\n                            \"exit\",\n                            vec![code.clone(), signal.clone()],\n                            false,\n                        )?;\n\n                        if let Some(stderr_join_receiver) = stderr_join_receiver {\n                            //ok if sender drops\n                            let _ = stderr_join_receiver.await;\n                        }\n                        if let Some(stdout_join_receiver) = stdout_join_receiver {\n                            //ok if sender drops\n                            let _ = stdout_join_receiver.await;\n                        }\n\n                        WritableStream::end(This(stdin_instance));\n\n                        ReadableStream::drain(stdout_instance, &ctx3)?;\n                        ReadableStream::drain(stderr_instance, &ctx3)?;\n\n                        ChildProcess::emit_str(\n                            This(instance2.clone()),\n                            &ctx3,\n                            \"close\",\n                            vec![code, signal],\n                            false,\n                        )?;\n\n                        Ok::<_, Error>(())\n                    };\n\n                    spawn_proc\n                        .await\n                        .emit_error(\"child_process\", &ctx2, instance4)?;\n\n                    Ok(())\n                })?;\n            },\n            Err(err) => {\n                let ctx3 = ctx.clone();\n\n                let err_message = format!(\"Child process failed to spawn \\\"{}\\\". {}\", command, err);\n\n                ctx.spawn_exit(async move {\n                    if !instance3.borrow().emitter.has_listener_str(\"error\") {\n                        return Err(Exception::throw_message(&ctx3, &err_message));\n                    }\n\n                    let ex = Exception::from_message(ctx3.clone(), &err_message)?;\n                    ChildProcess::emit_str(\n                        This(instance3),\n                        &ctx3,\n                        \"error\",\n                        vec![ex.into()],\n                        false,\n                    )?;\n                    Ok(())\n                })?;\n            },\n        }\n        Ok(instance)\n    }\n}\n\nasync fn wait_for_process(\n    mut child: Child,\n    ctx: &Ctx<'_>,\n    mut kill_rx: Receiver<()>,\n    exit_code: &mut Option<i32>,\n    _exit_signal: &mut Option<i32>,\n) -> Result<()> {\n    #[cfg(not(unix))]\n    let mut was_killed = false;\n    loop {\n        tokio::select! {\n            status = child.wait() => {\n                let exit_status = status.or_throw(ctx)?;\n\n                #[cfg(unix)]\n                {\n                    if let Some(sig) = exit_status.signal() {\n                        _exit_signal.replace(sig);\n                        // code is null when terminated by signal\n                    } else {\n                        exit_code.replace(exit_status.code().unwrap_or_default());\n                    }\n                }\n                #[cfg(not(unix))]\n                {\n                    if !was_killed {\n                        exit_code.replace(exit_status.code().unwrap_or_default());\n                    }\n                }\n                break;\n            }\n\n            Ok(()) = kill_rx.recv() => {\n                #[cfg(not(unix))]\n                {\n                    was_killed = true;\n                }\n                child.kill().await.or_throw(ctx)?;\n            }\n        }\n    }\n\n    Ok(())\n}\n\nimpl<'js> Emitter<'js> for ChildProcess<'js> {\n    fn get_event_list(&self) -> Arc<RwLock<EventList<'js>>> {\n        self.emitter.get_event_list()\n    }\n}\n\nfn spawn<'js>(\n    ctx: Ctx<'js>,\n    cmd: String,\n    args_and_opts: Rest<Value<'js>>,\n) -> Result<Class<'js, ChildProcess<'js>>> {\n    let args_0 = args_and_opts.first();\n    let args_1 = args_and_opts.get(1);\n\n    let mut opts = None;\n\n    if args_1.is_some() {\n        opts = args_1.and_then(|o| o.as_object()).map(|o| o.to_owned());\n    }\n\n    let mut command_args = if let Some(args_0) = args_0 {\n        if args_0.is_array() {\n            let args = args_0.clone().into_array().or_throw(&ctx)?;\n            let mut args_vec = Vec::with_capacity(args.len());\n            for arg in args.iter() {\n                let arg: Value = arg?;\n                let arg = arg\n                    .as_string()\n                    .or_throw_msg(&ctx, \"argument is not a string\")?;\n                let arg = arg.to_string()?;\n                args_vec.push(arg);\n            }\n            Some(args_vec)\n        } else if args_0.is_object() {\n            opts = args_0.as_object().map(|o| o.to_owned());\n            None\n        } else {\n            None\n        }\n    } else {\n        None\n    };\n\n    let mut windows_verbatim_arguments = if let Some(opts) = &opts {\n        opts.get_optional::<&str, bool>(\"windowsVerbatimArguments\")?\n            .unwrap_or_default()\n    } else {\n        false\n    };\n\n    let cmd = if let Some(opts) = &opts {\n        if opts\n            .get_optional::<&str, bool>(\"shell\")?\n            .unwrap_or_default()\n        {\n            #[cfg(windows)]\n            let shell = \"cmd.exe\".to_string();\n            #[cfg(not(windows))]\n            let shell = \"/bin/sh\".to_string();\n            command_args = Some(prepare_shell_args(\n                &shell,\n                &mut windows_verbatim_arguments,\n                cmd,\n                command_args,\n            ));\n            shell\n        } else if let Some(shell) = opts.get_optional::<&str, String>(\"shell\")? {\n            command_args = Some(prepare_shell_args(\n                &shell,\n                &mut windows_verbatim_arguments,\n                cmd,\n                command_args,\n            ));\n            shell\n        } else {\n            cmd\n        }\n    } else {\n        cmd\n    };\n\n    let mut command = StdCommand::new(cmd.clone());\n    if let Some(args) = &command_args {\n        #[cfg(windows)]\n        if windows_verbatim_arguments {\n            command.raw_arg(args.join(\" \"));\n        } else {\n            command.args(args);\n        }\n        #[cfg(not(windows))]\n        command.args(args);\n    }\n\n    let mut stdin = StdioEnum::Piped;\n    let mut stdout = StdioEnum::Piped;\n    let mut stderr = StdioEnum::Piped;\n    let mut detached = false;\n\n    if let Some(opts) = opts {\n        #[cfg(unix)]\n        {\n            if let Some(gid) = opts.get_optional(\"gid\")? {\n                command.gid(gid);\n            }\n\n            if let Some(uid) = opts.get_optional(\"uid\")? {\n                command.uid(uid);\n            }\n        }\n\n        detached = opts.get_optional(\"detached\")?.unwrap_or(false);\n\n        if let Some(cwd) = opts.get_optional::<_, String>(\"cwd\")? {\n            command.current_dir(&cwd);\n        }\n\n        if let Some(env) = opts.get_optional::<_, HashMap<String, Coerced<String>>>(\"env\")? {\n            let env: HashMap<String, String> = env\n                .iter()\n                .map(|(k, v)| (k.to_string(), v.to_string()))\n                .collect();\n            command.env_clear();\n            command.envs(env);\n        }\n\n        if let Some(stdio) = opts.get_optional::<_, Value<'js>>(\"stdio\")? {\n            if let Some(stdio_str) = stdio.as_string() {\n                let stdio = str_to_stdio(&ctx, &stdio_str.to_string()?)?;\n                stdin = stdio.clone();\n                stdout = stdio.clone();\n                stderr = stdio;\n            } else if let Some(stdio) = stdio.as_array() {\n                for (i, item) in stdio.iter::<Value>().enumerate() {\n                    let item = item?;\n                    let stdio = if item.is_undefined() || item.is_null() {\n                        StdioEnum::Piped\n                    } else if let Some(std_io_str) = item.as_string() {\n                        str_to_stdio(&ctx, &std_io_str.to_string()?)?\n                    } else if let Some(fd) = item.as_number() {\n                        StdioEnum::Fd(fd as i32)\n                    } else {\n                        StdioEnum::Piped\n                    };\n                    match i {\n                        0 => stdin = stdio,\n                        1 => stdout = stdio,\n                        2 => stderr = stdio,\n                        _ => {\n                            break;\n                        },\n                    }\n                }\n            }\n        }\n    }\n\n    command.stdin(stdin.to_stdio());\n    command.stdout(stdout.to_stdio());\n    command.stderr(stderr.to_stdio());\n\n    if detached {\n        #[cfg(unix)]\n        {\n            command.process_group(0);\n        }\n        #[cfg(windows)]\n        {\n            // DETACHED_PROCESS = 0x00000008\n            command.creation_flags(0x00000008);\n        }\n    }\n\n    //tokio command does not have all std command features stabilized\n    let mut command = Command::from(command);\n\n    ChildProcess::new(ctx.clone(), cmd, command_args, command.spawn())\n}\n\nfn str_to_stdio(ctx: &Ctx<'_>, input: &str) -> Result<StdioEnum> {\n    match input {\n        \"pipe\" => Ok(StdioEnum::Piped),\n        \"ignore\" => Ok(StdioEnum::Ignore),\n        \"inherit\" => Ok(StdioEnum::Inherit),\n        _ => Err(Exception::throw_type(\n            ctx,\n            &format!(\n                \"Invalid stdio \\\"{}\\\". Expected one of: pipe, ignore, inherit\",\n                input\n            ),\n        )),\n    }\n}\n\nfn create_output<'js, T>(\n    ctx: &Ctx<'js>,\n    output: Option<T>,\n    native_readable_stream: Class<'js, DefaultReadableStream<'js>>,\n) -> Result<Option<OneshotReceiver<bool>>>\nwhere\n    T: AsyncRead + Unpin + Send + 'static,\n{\n    if let Some(output) = output {\n        let receiver = DefaultReadableStream::process(native_readable_stream, ctx, output)?;\n        return Ok(Some(receiver));\n    }\n\n    Ok(None)\n}\n\npub struct ChildProcessModule;\n\nimpl ModuleDef for ChildProcessModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(\"spawn\")?;\n        declare.declare(\"default\")?;\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        ChildProcess::add_event_emitter_prototype(ctx)?;\n        DefaultWritableStream::add_writable_stream_prototype(ctx)?;\n        DefaultWritableStream::add_event_emitter_prototype(ctx)?;\n        DefaultReadableStream::add_readable_stream_prototype(ctx)?;\n        DefaultReadableStream::add_event_emitter_prototype(ctx)?;\n\n        export_default(ctx, exports, |default| {\n            default.set(\"spawn\", Func::from(spawn))?;\n            Ok(())\n        })?;\n\n        Ok(())\n    }\n}\n\nimpl From<ChildProcessModule> for ModuleInfo<ChildProcessModule> {\n    fn from(val: ChildProcessModule) -> Self {\n        ModuleInfo {\n            name: \"child_process\",\n            module: val,\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use llrt_buffer as buffer;\n    use llrt_test::{test_async_with, ModuleEvaluator};\n    use rquickjs::CatchResultExt;\n\n    #[tokio::test]\n    async fn test_spawn() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                buffer::init(&ctx).unwrap();\n\n                ModuleEvaluator::eval_rust::<ChildProcessModule>(ctx.clone(), \"node:child_process\")\n                    .await\n                    .unwrap();\n\n                let message: String = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                   import {spawn} from \"node:child_process\";\n\n                    let resolve = null;\n                    const deferred = new Promise(res => {\n                        resolve = res;\n                    });\n\n                    spawn(\"echo\", [\"hello\"]).stdout.on(\"data\", (data) => {\n                        resolve(data.toString().trim())\n                    });\n\n                    export default await deferred;\n\n                \"#,\n                )\n                .await\n                .catch(&ctx)\n                .unwrap()\n                .get(\"default\")\n                .unwrap();\n\n                assert_eq!(message, \"hello\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_spawn_shell() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                buffer::init(&ctx).unwrap();\n\n                ModuleEvaluator::eval_rust::<ChildProcessModule>(ctx.clone(), \"node:child_process\")\n                    .await\n                    .unwrap();\n\n                let message: String = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                    import {spawn} from \"node:child_process\";\n\n                    let resolve = null;\n                    const deferred = new Promise(res => {\n                        resolve = res;\n                    });\n\n                    spawn(\"echo\", [\"hello\"], {\n                        shell: true\n                    }).stdout.on(\"data\", (data) => {\n                        resolve(data.toString().trim())\n                    });\n\n                    export default await deferred;\n                \"#,\n                )\n                .await\n                .catch(&ctx)\n                .unwrap()\n                .get(\"default\")\n                .unwrap();\n\n                assert_eq!(message, \"hello\");\n            })\n        })\n        .await;\n    }\n}\n"
  },
  {
    "path": "modules/llrt_console/Cargo.toml",
    "content": "[package]\nname = \"llrt_console\"\ndescription = \"LLRT Module console\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[lib]\nname = \"llrt_console\"\npath = \"src/lib.rs\"\n\n[dependencies]\nllrt_logging = { version = \"0.8.1-beta\", path = \"../../libs/llrt_logging\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", default-features = false }\n"
  },
  {
    "path": "modules/llrt_console/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::io::{stderr, stdout, IsTerminal, Write};\n\nuse llrt_logging::{build_formatted_string, FormatOptions, NEWLINE};\nuse llrt_utils::module::{export_default, ModuleInfo};\nuse rquickjs::{\n    module::{Declarations, Exports, ModuleDef},\n    prelude::{Func, Rest},\n    Class, Ctx, Object, Result, Value,\n};\n\n#[derive(rquickjs::class::Trace, rquickjs::JsLifetime)]\n#[rquickjs::class]\npub struct Console {}\n\nimpl Default for Console {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl Console {\n    #[qjs(constructor)]\n    pub fn new() -> Self {\n        // We ignore the parameters for now since we don't support stream\n        Self {}\n    }\n\n    pub fn log<'js>(&self, ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n        log(ctx, args)\n    }\n    pub fn clear(&self) {\n        clear()\n    }\n    pub fn debug<'js>(&self, ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n        log_debug(ctx, args)\n    }\n    pub fn info<'js>(&self, ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n        log(ctx, args)\n    }\n    pub fn trace<'js>(&self, ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n        log_trace(ctx, args)\n    }\n    pub fn error<'js>(&self, ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n        log_error(ctx, args)\n    }\n    pub fn warn<'js>(&self, ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n        log_warn(ctx, args)\n    }\n    pub fn assert<'js>(\n        &self,\n        ctx: Ctx<'js>,\n        expression: bool,\n        args: Rest<Value<'js>>,\n    ) -> Result<()> {\n        log_assert(ctx, expression, args)\n    }\n}\n\npub fn log_fatal<'js>(ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n    write_log(stderr(), &ctx, args)\n}\n\npub fn log_error<'js>(ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n    write_log(stderr(), &ctx, args)\n}\n\nfn log_warn<'js>(ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n    write_log(stderr(), &ctx, args)\n}\n\nfn log_debug<'js>(ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n    write_log(stdout(), &ctx, args)\n}\n\nfn log_trace<'js>(ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n    write_log(stdout(), &ctx, args)\n}\n\nfn log_assert<'js>(ctx: Ctx<'js>, expression: bool, args: Rest<Value<'js>>) -> Result<()> {\n    if !expression {\n        write_log(stderr(), &ctx, args)?;\n    }\n    Ok(())\n}\n\nfn log<'js>(ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<()> {\n    write_log(stdout(), &ctx, args)\n}\n\nfn clear() {\n    let _ = stdout().write_all(b\"\\x1b[1;1H\\x1b[0J\");\n}\n\nfn write_log<'js, T>(mut output: T, ctx: &Ctx<'js>, args: Rest<Value<'js>>) -> Result<()>\nwhere\n    T: Write + IsTerminal,\n{\n    let is_tty = output.is_terminal();\n    let mut result = String::new();\n\n    let mut options = FormatOptions::new(ctx, is_tty, true)?;\n    build_formatted_string(&mut result, ctx, args, &mut options)?;\n\n    result.push(NEWLINE);\n\n    //we don't care if output is interrupted\n    let _ = output.write_all(result.as_bytes());\n\n    Ok(())\n}\n\npub struct ConsoleModule;\n\nimpl ModuleDef for ConsoleModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(stringify!(Console))?;\n        declare.declare(\"default\")?;\n\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        export_default(ctx, exports, |default| {\n            Class::<Console>::define(default)?;\n\n            Ok(())\n        })\n    }\n}\n\nimpl From<ConsoleModule> for ModuleInfo<ConsoleModule> {\n    fn from(val: ConsoleModule) -> Self {\n        ModuleInfo {\n            name: \"console\",\n            module: val,\n        }\n    }\n}\n\npub fn init(ctx: &Ctx<'_>) -> Result<()> {\n    let globals = ctx.globals();\n\n    let console = Object::new(ctx.clone())?;\n\n    console.set(\"assert\", Func::from(log_assert))?;\n    console.set(\"clear\", Func::from(clear))?;\n    console.set(\"debug\", Func::from(log_debug))?;\n    console.set(\"error\", Func::from(log_error))?;\n    console.set(\"info\", Func::from(log))?;\n    console.set(\"log\", Func::from(log))?;\n    console.set(\"trace\", Func::from(log_trace))?;\n    console.set(\"warn\", Func::from(log_warn))?;\n\n    globals.set(\"console\", console)?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "modules/llrt_crypto/Cargo.toml",
    "content": "[package]\nname = \"llrt_crypto\"\ndescription = \"LLRT Module crypto\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\nreadme = \"README.md\"\n\n[lib]\nname = \"llrt_crypto\"\npath = \"src/lib.rs\"\n\n[features]\ndefault = [\"crypto-rust\"]\n\n# Internal feature: enables DER parsing for SubtleCrypto key import/export\n_subtle-full = [\"llrt_json\", \"const-oid\", \"der\", \"pkcs8\", \"spki\"]\n\n# Internal feature: enables RustCrypto dependencies for key import/export\n_rustcrypto = [\n  \"_subtle-full\",\n  \"aes\",\n  \"aes-gcm\",\n  \"aes-kw\",\n  \"cbc\",\n  \"ctr\",\n  \"ecdsa\",\n  \"ed25519-dalek\",\n  \"elliptic-curve\",\n  \"hkdf\",\n  \"hmac\",\n  \"rsa\",\n  \"p256\",\n  \"p384\",\n  \"p521\",\n  \"pbkdf2\",\n  \"sha1\",\n  \"x25519-dalek\",\n]\n\ncrypto-rust = [\"_rustcrypto\"]\ncrypto-ring = [\"ring\"]\ncrypto-ring-rust = [\"ring\", \"_rustcrypto\"]\ncrypto-graviola = [\"graviola\"]\ncrypto-graviola-rust = [\"graviola\", \"_rustcrypto\"]\ncrypto-openssl = [\"openssl-sys\", \"openssl\", \"_subtle-full\"]\n\n[dependencies]\ncrc32c = { version = \"0.6\", default-features = false }\ncrc32fast = { version = \"1\", default-features = false }\nllrt_buffer = { version = \"0.8.1-beta\", path = \"../llrt_buffer\" }\nllrt_context = { version = \"0.8.1-beta\", path = \"../../libs/llrt_context\" }\nllrt_encoding = { version = \"0.8.1-beta\", path = \"../../libs/llrt_encoding\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nmd-5 = { version = \"0.11.0-rc.5\", default-features = false }\nonce_cell = { version = \"1\", features = [\"std\"], default-features = false }\nrand = { version = \"0.10.0\", features = [\n  \"std\",\n  \"std_rng\",\n  \"thread_rng\",\n], default-features = false }\nrquickjs = { version = \"0.11\", default-features = false }\n\n\n# optional\nllrt_json = { version = \"0.8.1-beta\", path = \"../../libs/llrt_json\", optional = true }\naes = { version = \"0.9.0-rc.4\", optional = true }\naes-gcm = { version = \"0.11.0-rc.3\", features = [\n  \"alloc\",\n], default-features = false, optional = true }\naes-kw = { version = \"0.3.0-rc.2\", features = [\n  \"oid\",\n], default-features = false, optional = true }\ncbc = { version = \"0.2.0-rc.3\", features = [\"alloc\"], optional = true }\nconst-oid = { version = \"0.10\", features = [\n  \"db\",\n], default-features = false, optional = true }\nctr = { version = \"0.10.0-rc.3\", default-features = false, optional = true }\nder = { version = \"0.8\", features = [\n  \"derive\",\n  \"alloc\",\n], default-features = false, optional = true }\necdsa = { version = \"0.17.0-rc.16\", default-features = false, optional = true }\ned25519-dalek = { version = \"3.0.0-pre.6\", features = [\n  \"alloc\",\n  \"pkcs8\",\n  \"rand_core\",\n], default-features = false, optional = true }\nelliptic-curve = { version = \"0.14.0-rc.28\", features = [\n  \"alloc\",\n  \"sec1\",\n], default-features = false, optional = true }\nhkdf = { version = \"0.13.0-rc.5\", default-features = false, optional = true }\nhmac = { version = \"0.13.0-rc.5\", default-features = false, optional = true }\nrsa = { version = \"0.10.0-rc.15\", features = [\n  \"std\",\n  \"sha2\",\n  \"encoding\",\n], default-features = false, optional = true }\np256 = { version = \"0.14.0-rc.7\", features = [\n  \"ecdh\",\n  \"ecdsa\",\n  \"pkcs8\",\n], default-features = false, optional = true }\np384 = { version = \"0.14.0-rc.7\", features = [\n  \"ecdh\",\n  \"ecdsa\",\n  \"pkcs8\",\n], default-features = false, optional = true }\np521 = { version = \"0.14.0-rc.7\", features = [\n  \"ecdh\",\n  \"ecdsa\",\n  \"pkcs8\",\n], default-features = false, optional = true }\npbkdf2 = { version = \"0.13.0-rc.9\", default-features = false, optional = true }\npkcs8 = { version = \"0.11.0-rc.11\", default-features = false, features = [\n  \"alloc\",\n], optional = true }\nsha1 = { version = \"0.11.0-rc.5\", default-features = false, optional = true }\nspki = { version = \"0.8.0-rc.4\", features = [\n  \"alloc\",\n], default-features = false, optional = true }\nx25519-dalek = { version = \"3.0.0-pre.6\", features = [\n  \"static_secrets\",\n  \"zeroize\",\n], default-features = false, optional = true }\n\n# Crypto provider dependencies\nring = { version = \"0.17\", default-features = false, optional = true }\nopenssl-sys = { version = \"0.9\", optional = true }\nopenssl = { version = \"0.10\", optional = true }\ngraviola = { version = \"0.3\", git = \"https://github.com/ctz/graviola.git\", optional = true }\n\n[dev-dependencies]\nllrt_test = { path = \"../../libs/llrt_test\" }\n"
  },
  {
    "path": "modules/llrt_crypto/src/crc32.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::hash::Hasher;\n\nuse crc32c::Crc32cHasher;\nuse llrt_utils::bytes::ObjectBytes;\nuse rquickjs::{prelude::This, Class, Ctx, Result};\n\n#[rquickjs::class]\n#[derive(rquickjs::class::Trace, rquickjs::JsLifetime)]\npub struct Crc32c {\n    #[qjs(skip_trace)]\n    hasher: crc32c::Crc32cHasher,\n}\n\n#[rquickjs::methods]\nimpl Crc32c {\n    #[qjs(constructor)]\n    fn new() -> Self {\n        Self {\n            hasher: Crc32cHasher::default(),\n        }\n    }\n\n    #[qjs(rename = \"digest\")]\n    fn crc32c_digest(&self) -> u64 {\n        self.hasher.finish()\n    }\n\n    #[qjs(rename = \"update\")]\n    fn crc32c_update<'js>(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        bytes: ObjectBytes<'js>,\n    ) -> Result<Class<'js, Self>> {\n        this.0.borrow_mut().hasher.write(bytes.as_bytes(&ctx)?);\n        Ok(this.0)\n    }\n}\n\n#[rquickjs::class]\n#[derive(rquickjs::class::Trace, rquickjs::JsLifetime)]\npub struct Crc32 {\n    #[qjs(skip_trace)]\n    hasher: crc32fast::Hasher,\n}\n\n#[rquickjs::methods]\nimpl Crc32 {\n    #[qjs(constructor)]\n    fn new() -> Self {\n        Self {\n            hasher: crc32fast::Hasher::new(),\n        }\n    }\n\n    #[qjs(rename = \"digest\")]\n    fn crc32_digest(&self) -> u64 {\n        self.hasher.finish()\n    }\n\n    #[qjs(rename = \"update\")]\n    fn crc32_update<'js>(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        bytes: ObjectBytes<'js>,\n    ) -> Result<Class<'js, Self>> {\n        this.0.borrow_mut().hasher.write(bytes.as_bytes(&ctx)?);\n        Ok(this.0)\n    }\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/hash.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_buffer::Buffer;\nuse llrt_utils::{bytes::ObjectBytes, iterable_enum, result::ResultExt};\nuse rquickjs::{\n    class::Trace, function::Opt, prelude::This, Class, Ctx, IntoJs, JsLifetime, Result, Value,\n};\n\nuse super::encoded_bytes;\nuse crate::provider::{CryptoProvider, HmacProvider, SimpleDigest};\nuse crate::CRYPTO_PROVIDER;\n\n#[derive(Debug, Clone, Copy)]\npub enum HashAlgorithm {\n    Md5,\n    Sha1,\n    Sha256,\n    Sha384,\n    Sha512,\n}\n\niterable_enum!(HashAlgorithm, Md5, Sha1, Sha256, Sha384, Sha512);\n\nimpl TryFrom<&str> for HashAlgorithm {\n    type Error = String;\n    fn try_from(s: &str) -> std::result::Result<Self, Self::Error> {\n        Ok(match s.to_ascii_uppercase().as_str() {\n            \"MD5\" => HashAlgorithm::Md5,\n            \"MD-5\" => HashAlgorithm::Md5,\n            \"SHA1\" => HashAlgorithm::Sha1,\n            \"SHA-1\" => HashAlgorithm::Sha1,\n            \"SHA256\" => HashAlgorithm::Sha256,\n            \"SHA-256\" => HashAlgorithm::Sha256,\n            \"SHA384\" => HashAlgorithm::Sha384,\n            \"SHA-384\" => HashAlgorithm::Sha384,\n            \"SHA512\" => HashAlgorithm::Sha512,\n            \"SHA-512\" => HashAlgorithm::Sha512,\n            _ => return Err([\"'\", s, \"' not available\"].concat()),\n        })\n    }\n}\n\nimpl HashAlgorithm {\n    pub fn class_name(&self) -> &'static str {\n        match self {\n            HashAlgorithm::Md5 => \"Md5\",\n            HashAlgorithm::Sha1 => \"Sha1\",\n            HashAlgorithm::Sha256 => \"Sha256\",\n            HashAlgorithm::Sha384 => \"Sha384\",\n            HashAlgorithm::Sha512 => \"Sha512\",\n        }\n    }\n\n    pub fn as_str(&self) -> &'static str {\n        match self {\n            HashAlgorithm::Md5 => \"MD5\",\n            HashAlgorithm::Sha1 => \"SHA-1\",\n            HashAlgorithm::Sha256 => \"SHA-256\",\n            HashAlgorithm::Sha384 => \"SHA-384\",\n            HashAlgorithm::Sha512 => \"SHA-512\",\n        }\n    }\n\n    pub fn as_numeric_str(&self) -> &'static str {\n        match self {\n            HashAlgorithm::Md5 => \"md5\",\n            HashAlgorithm::Sha1 => \"1\",\n            HashAlgorithm::Sha256 => \"256\",\n            HashAlgorithm::Sha384 => \"384\",\n            HashAlgorithm::Sha512 => \"512\",\n        }\n    }\n\n    pub fn digest_len(&self) -> usize {\n        match self {\n            HashAlgorithm::Md5 => 16,\n            HashAlgorithm::Sha1 => 20,\n            HashAlgorithm::Sha256 => 32,\n            HashAlgorithm::Sha384 => 48,\n            HashAlgorithm::Sha512 => 64,\n        }\n    }\n\n    pub fn block_len(&self) -> usize {\n        match self {\n            HashAlgorithm::Md5 => 64,\n            HashAlgorithm::Sha1 => 64,\n            HashAlgorithm::Sha256 => 64,\n            HashAlgorithm::Sha384 => 128,\n            HashAlgorithm::Sha512 => 128,\n        }\n    }\n}\n\ntype ProviderDigest = <crate::provider::DefaultProvider as CryptoProvider>::Digest;\ntype ProviderHmac = <crate::provider::DefaultProvider as CryptoProvider>::Hmac;\n\n#[derive(Trace, JsLifetime)]\n#[rquickjs::class]\npub struct Hash {\n    #[qjs(skip_trace)]\n    digest: Option<ProviderDigest>,\n    #[qjs(skip_trace)]\n    hmac: Option<ProviderHmac>,\n}\n\nimpl Hash {\n    pub fn new(ctx: Ctx<'_>, algorithm: String) -> Result<Self> {\n        let algorithm = HashAlgorithm::try_from(algorithm.as_str()).or_throw(&ctx)?;\n        Ok(Self {\n            digest: Some(CRYPTO_PROVIDER.digest(algorithm)),\n            hmac: None,\n        })\n    }\n\n    pub fn new_hmac<'js>(\n        ctx: Ctx<'js>,\n        algorithm: String,\n        secret: ObjectBytes<'js>,\n    ) -> Result<Self> {\n        let algorithm = HashAlgorithm::try_from(algorithm.as_str()).or_throw(&ctx)?;\n        let key = secret.as_bytes(&ctx)?;\n        Ok(Self {\n            digest: None,\n            hmac: Some(CRYPTO_PROVIDER.hmac(algorithm, key)),\n        })\n    }\n\n    fn do_update(&mut self, data: &[u8]) {\n        if let Some(ref mut d) = self.digest {\n            d.update(data);\n        } else if let Some(ref mut h) = self.hmac {\n            h.update(data);\n        }\n    }\n\n    fn do_finalize(&mut self) -> Option<Vec<u8>> {\n        if let Some(d) = self.digest.take() {\n            Some(d.finalize())\n        } else {\n            self.hmac.take().map(|h| h.finalize())\n        }\n    }\n}\n\n#[rquickjs::methods]\nimpl Hash {\n    #[qjs(rename = \"digest\")]\n    fn hash_digest<'js>(&mut self, ctx: Ctx<'js>, encoding: Opt<String>) -> Result<Value<'js>> {\n        let result = self\n            .do_finalize()\n            .ok_or_else(|| rquickjs::Exception::throw_message(&ctx, \"Digest already called\"))?;\n\n        let Some(encoding) = encoding.0 else {\n            return Buffer(result).into_js(&ctx);\n        };\n\n        match encoded_bytes(&ctx, &result, &encoding)? {\n            Some(encoded) => Ok(encoded),\n            None => Buffer(result).into_js(&ctx),\n        }\n    }\n\n    #[qjs(rename = \"update\")]\n    fn hash_update<'js>(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        bytes: ObjectBytes<'js>,\n    ) -> Result<Class<'js, Self>> {\n        let bytes = bytes.as_bytes(&ctx)?;\n        this.0.borrow_mut().do_update(bytes);\n        Ok(this.0)\n    }\n}\n\n#[derive(Trace, JsLifetime)]\n#[rquickjs::class]\npub struct Hmac {\n    #[qjs(skip_trace)]\n    hash: Hash,\n}\n\nimpl Hmac {\n    pub fn new<'js>(ctx: Ctx<'js>, algorithm: String, key_value: ObjectBytes<'js>) -> Result<Self> {\n        Ok(Self {\n            hash: Hash::new_hmac(ctx, algorithm, key_value)?,\n        })\n    }\n}\n\n#[rquickjs::methods]\nimpl Hmac {\n    fn digest<'js>(&mut self, ctx: Ctx<'js>, encoding: Opt<String>) -> Result<Value<'js>> {\n        self.hash.hash_digest(ctx, encoding)\n    }\n\n    fn update<'js>(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        bytes: ObjectBytes<'js>,\n    ) -> Result<Class<'js, Self>> {\n        let bytes = bytes.as_bytes(&ctx)?;\n        this.0.borrow_mut().hash.do_update(bytes);\n        Ok(this.0)\n    }\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\n// Compile-time checks for conflicting crypto features\n#[cfg(all(feature = \"crypto-rust\", feature = \"crypto-openssl\"))]\ncompile_error!(\"Features `crypto-rust` and `crypto-openssl` are mutually exclusive\");\n\n#[cfg(all(feature = \"crypto-rust\", feature = \"crypto-ring\"))]\ncompile_error!(\"Features `crypto-rust` and `crypto-ring` are mutually exclusive\");\n\n#[cfg(all(feature = \"crypto-rust\", feature = \"crypto-graviola\"))]\ncompile_error!(\"Features `crypto-rust` and `crypto-graviola` are mutually exclusive\");\n\n#[cfg(all(feature = \"crypto-openssl\", feature = \"crypto-ring\"))]\ncompile_error!(\"Features `crypto-openssl` and `crypto-ring` are mutually exclusive\");\n\n#[cfg(all(feature = \"crypto-openssl\", feature = \"crypto-graviola\"))]\ncompile_error!(\"Features `crypto-openssl` and `crypto-graviola` are mutually exclusive\");\n\n#[cfg(all(feature = \"crypto-ring\", feature = \"crypto-graviola\"))]\ncompile_error!(\"Features `crypto-ring` and `crypto-graviola` are mutually exclusive\");\n\nmod crc32;\nmod hash;\nmod subtle;\n\nmod provider;\n\nuse std::slice;\n\nuse llrt_buffer::Buffer;\nuse llrt_context::CtxExtension;\nuse llrt_encoding::{bytes_to_b64_string, bytes_to_hex_string};\nuse llrt_utils::{\n    bytes::{get_start_end_indexes, ObjectBytes},\n    error::ErrorExtensions,\n    error_messages::{ERROR_MSG_ARRAY_BUFFER_DETACHED, ERROR_MSG_NOT_ARRAY_BUFFER},\n    module::{export_default, ModuleInfo},\n    result::ResultExt,\n};\nuse once_cell::sync::Lazy;\nuse rand::RngExt;\nuse rquickjs::prelude::Async;\nuse rquickjs::{\n    atom::PredefinedAtom,\n    function::{Constructor, Opt},\n    module::{Declarations, Exports, ModuleDef},\n    prelude::{Func, Rest},\n    Class, Ctx, Error, Exception, Function, IntoJs, Null, Object, Result, Value,\n};\nuse subtle::{\n    subtle_decrypt, subtle_derive_bits, subtle_derive_key, subtle_digest, subtle_encrypt,\n    subtle_export_key, subtle_generate_key, subtle_import_key, subtle_sign, subtle_unwrap_key,\n    subtle_verify, subtle_wrap_key, CryptoKey, SubtleCrypto,\n};\n\nuse self::{\n    crc32::{Crc32, Crc32c},\n    hash::{Hash, HashAlgorithm, Hmac},\n};\n\nstatic CRYPTO_PROVIDER: Lazy<provider::DefaultProvider> =\n    Lazy::new(|| provider::DefaultProvider {});\n\nfn encoded_bytes<'js>(ctx: &Ctx<'js>, bytes: &[u8], encoding: &str) -> Result<Option<Value<'js>>> {\n    match encoding {\n        \"hex\" => {\n            let hex = bytes_to_hex_string(bytes);\n            let hex = rquickjs::String::from_str(ctx.clone(), &hex)?;\n            Ok(Some(Value::from_string(hex)))\n        },\n        \"base64\" => {\n            let b64 = bytes_to_b64_string(bytes);\n            let b64 = rquickjs::String::from_str(ctx.clone(), &b64)?;\n            Ok(Some(Value::from_string(b64)))\n        },\n        _ => Ok(None),\n    }\n}\n\n#[inline]\npub fn random_byte_array(length: usize) -> Vec<u8> {\n    let mut vec = vec![0u8; length];\n    rand::rng().fill(&mut vec[..]);\n    vec\n}\n\nfn get_random_bytes(ctx: Ctx, length: usize) -> Result<Value> {\n    let random_bytes = random_byte_array(length);\n    Buffer(random_bytes).into_js(&ctx)\n}\n\nfn get_random_int(first: i64, second: Opt<i64>) -> Result<i64> {\n    let mut rng = rand::rng();\n    let random_number = match second.0 {\n        Some(max) => rng.random_range(first..max),\n        None => rng.random_range(0..first),\n    };\n\n    Ok(random_number)\n}\n\nfn random_fill<'js>(ctx: Ctx<'js>, obj: Object<'js>, args: Rest<Value<'js>>) -> Result<()> {\n    let args_iter = args.0.into_iter();\n    let mut args_iter = args_iter.rev();\n\n    let callback: Function = args_iter\n        .next()\n        .and_then(|v| v.into_function())\n        .or_throw_msg(&ctx, \"Callback required\")?;\n    let size = args_iter\n        .next()\n        .and_then(|arg| arg.as_int())\n        .map(|i| i as usize);\n    let offset = args_iter\n        .next()\n        .and_then(|arg| arg.as_int())\n        .map(|i| i as usize);\n\n    ctx.clone().spawn_exit(async move {\n        if let Err(err) = random_fill_sync(ctx.clone(), obj.clone(), Opt(offset), Opt(size)) {\n            let err = err.into_value(&ctx)?;\n            () = callback.call((err,))?;\n\n            return Ok(());\n        }\n        () = callback.call((Null.into_js(&ctx), obj))?;\n        Ok::<_, Error>(())\n    })?;\n    Ok(())\n}\n\nfn random_fill_sync<'js>(\n    ctx: Ctx<'js>,\n    obj: Object<'js>,\n    offset: Opt<usize>,\n    size: Opt<usize>,\n) -> Result<Object<'js>> {\n    let offset = offset.unwrap_or(0);\n\n    if let Some(object_bytes) = ObjectBytes::from_array_buffer(&obj)? {\n        let (array_buffer, source_length, source_offset) = object_bytes\n            .get_array_buffer()?\n            .expect(ERROR_MSG_NOT_ARRAY_BUFFER);\n        let raw = array_buffer\n            .as_raw()\n            .ok_or(ERROR_MSG_ARRAY_BUFFER_DETACHED)\n            .or_throw(&ctx)?;\n\n        let (start, end) = get_start_end_indexes(source_length, size.0, offset);\n\n        let bytes = unsafe { slice::from_raw_parts_mut(raw.ptr.as_ptr(), source_length) };\n\n        rand::rng().fill(&mut bytes[start + source_offset..end - source_offset]);\n    }\n\n    Ok(obj)\n}\n\nfn get_random_values<'js>(ctx: Ctx<'js>, obj: Object<'js>) -> Result<Object<'js>> {\n    if let Some(object_bytes) = ObjectBytes::from_array_buffer(&obj)? {\n        if matches!(\n            object_bytes,\n            ObjectBytes::F64Array(_) | ObjectBytes::F32Array(_)\n        ) {\n            return Err(Exception::throw_message(&ctx, \"Unsupported TypedArray\"));\n        }\n\n        let (array_buffer, source_length, source_offset) = object_bytes\n            .get_array_buffer()?\n            .expect(ERROR_MSG_NOT_ARRAY_BUFFER);\n        let raw = array_buffer\n            .as_raw()\n            .ok_or(ERROR_MSG_ARRAY_BUFFER_DETACHED)\n            .or_throw(&ctx)?;\n\n        if source_length > 0x10000 {\n            return Err(Exception::throw_message(\n                &ctx,\n                \"QuotaExceededError: The requested length exceeds 65,536 bytes\",\n            ));\n        }\n\n        let bytes = unsafe {\n            std::slice::from_raw_parts_mut(raw.ptr.as_ptr().add(source_offset), source_length)\n        };\n\n        rand::rng().fill(bytes)\n    }\n\n    Ok(obj)\n}\n\nfn uuidv4() -> String {\n    let uuid = rand::random::<u128>() & 0xFFFFFFFFFFFF4FFFBFFFFFFFFFFFFFFF | 0x40008000000000000000;\n\n    static HEX_CHARS: &[u8; 16] = b\"0123456789abcdef\";\n    let bytes = uuid.to_be_bytes();\n\n    let mut buf = [0u8; 36];\n\n    // Precomputed positions for 32 hex digits (excluding hyphens)\n    static HEX_POS: [usize; 32] = [\n        0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 14, 15, 16, 17, 19, 20, 21, 22, 24, 25, 26, 27, 28,\n        29, 30, 31, 32, 33, 34, 35,\n    ];\n\n    // Map each byte to its hex representation\n    let mut hex_idx = 0;\n    for &byte in &bytes[..] {\n        let high = HEX_CHARS[(byte >> 4) as usize];\n        let low = HEX_CHARS[(byte & 0x0f) as usize];\n\n        buf[HEX_POS[hex_idx]] = high;\n        buf[HEX_POS[hex_idx + 1]] = low;\n        hex_idx += 2;\n    }\n\n    // Insert hyphens at standard positions\n    buf[8] = b'-';\n    buf[13] = b'-';\n    buf[18] = b'-';\n    buf[23] = b'-';\n\n    // SAFETY: The buffer only contains valid UTF-8 characters (hex digits and hyphens)\n    // that were explicitly set from the HEX_CHARS array and hyphen literals\n    unsafe { String::from_utf8_unchecked(buf.to_vec()) }\n}\n\n#[rquickjs::class]\n#[derive(rquickjs::JsLifetime, rquickjs::class::Trace)]\nstruct Crypto {}\n\n#[rquickjs::methods]\nimpl Crypto {\n    #[qjs(constructor)]\n    pub fn new(ctx: Ctx<'_>) -> Result<Self> {\n        Err(Exception::throw_type(&ctx, \"Illegal constructor\"))\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    pub fn to_string_tag(&self) -> &'static str {\n        stringify!(Crypto)\n    }\n}\n\npub fn init(ctx: &Ctx<'_>) -> Result<()> {\n    let globals = ctx.globals();\n\n    Class::<Crypto>::define(&globals)?;\n    let crypto = Class::instance(ctx.clone(), Crypto {})?;\n\n    crypto.set(\"createHash\", Func::from(Hash::new))?;\n    crypto.set(\"createHmac\", Func::from(Hmac::new))?;\n    crypto.set(\"randomBytes\", Func::from(get_random_bytes))?;\n    crypto.set(\"randomInt\", Func::from(get_random_int))?;\n    crypto.set(\"randomUUID\", Func::from(uuidv4))?;\n    crypto.set(\"randomFillSync\", Func::from(random_fill_sync))?;\n    crypto.set(\"randomFill\", Func::from(random_fill))?;\n    crypto.set(\"getRandomValues\", Func::from(get_random_values))?;\n\n    Class::<SubtleCrypto>::define(&globals)?;\n    Class::<CryptoKey>::define(&globals)?;\n\n    let subtle = Class::instance(ctx.clone(), SubtleCrypto {})?;\n    subtle.set(\"decrypt\", Func::from(Async(subtle_decrypt)))?;\n    subtle.set(\"deriveKey\", Func::from(Async(subtle_derive_key)))?;\n    subtle.set(\"deriveBits\", Func::from(Async(subtle_derive_bits)))?;\n    subtle.set(\"digest\", Func::from(Async(subtle_digest)))?;\n    subtle.set(\"encrypt\", Func::from(Async(subtle_encrypt)))?;\n    subtle.set(\"exportKey\", Func::from(Async(subtle_export_key)))?;\n    subtle.set(\"generateKey\", Func::from(Async(subtle_generate_key)))?;\n    subtle.set(\"importKey\", Func::from(Async(subtle_import_key)))?;\n    subtle.set(\"sign\", Func::from(Async(subtle_sign)))?;\n    subtle.set(\"verify\", Func::from(Async(subtle_verify)))?;\n    subtle.set(\"wrapKey\", Func::from(Async(subtle_wrap_key)))?;\n    subtle.set(\"unwrapKey\", Func::from(Async(subtle_unwrap_key)))?;\n    crypto.set(\"subtle\", subtle)?;\n\n    globals.set(\"crypto\", crypto)?;\n\n    Ok(())\n}\n\npub struct CryptoModule;\n\nimpl ModuleDef for CryptoModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(\"createHash\")?;\n        declare.declare(\"createHmac\")?;\n        declare.declare(\"Crc32\")?;\n        declare.declare(\"Crc32c\")?;\n        declare.declare(\"randomBytes\")?;\n        declare.declare(\"randomUUID\")?;\n        declare.declare(\"randomInt\")?;\n        declare.declare(\"randomFillSync\")?;\n        declare.declare(\"randomFill\")?;\n        declare.declare(\"getRandomValues\")?;\n\n        for algorithm in HashAlgorithm::iter() {\n            declare.declare(algorithm.class_name())?;\n        }\n\n        declare.declare(\"crypto\")?;\n        declare.declare(\"webcrypto\")?;\n        declare.declare(\"default\")?;\n\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        export_default(ctx, exports, |default| {\n            for algorithm in HashAlgorithm::iter() {\n                let class_name: &str = algorithm.class_name();\n                let algo_name = String::from(algorithm.as_str());\n\n                let ctor = Constructor::new_class::<Hash, _, _>(\n                    ctx.clone(),\n                    move |ctx: Ctx<'js>, secret: Opt<ObjectBytes<'js>>| match secret.0 {\n                        Some(secret) => Hash::new_hmac(ctx, algo_name.clone(), secret),\n                        None => Hash::new(ctx, algo_name.clone()),\n                    },\n                )?;\n\n                default.set(class_name, ctor)?;\n            }\n\n            let crypto: Object = ctx.globals().get(\"crypto\")?;\n\n            Class::<Crc32>::define(default)?;\n            Class::<Crc32c>::define(default)?;\n\n            default.set(\"createHash\", Func::from(Hash::new))?;\n            default.set(\"createHmac\", Func::from(Hmac::new))?;\n            default.set(\"randomBytes\", Func::from(get_random_bytes))?;\n            default.set(\"randomInt\", Func::from(get_random_int))?;\n            default.set(\"randomUUID\", Func::from(uuidv4))?;\n            default.set(\"randomFillSync\", Func::from(random_fill_sync))?;\n            default.set(\"randomFill\", Func::from(random_fill))?;\n            default.set(\"getRandomValues\", Func::from(get_random_values))?;\n            default.set(\"crypto\", crypto.clone())?;\n            default.set(\"webcrypto\", crypto)?;\n            Ok(())\n        })?;\n\n        Ok(())\n    }\n}\n\nimpl From<CryptoModule> for ModuleInfo<CryptoModule> {\n    fn from(val: CryptoModule) -> Self {\n        ModuleInfo {\n            name: \"crypto\",\n            module: val,\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/provider/graviola.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\n//! Graviola crypto provider - a high-performance crypto library using formally verified assembler.\n//!\n//! Supported: SHA256/384/512, HMAC, AES-GCM\n//! Not supported: Most other operations due to API limitations\n\nuse graviola::{\n    aead::AesGcm,\n    hashing::{hmac::Hmac, Hash, HashContext, Sha256, Sha384, Sha512},\n};\n\nuse crate::hash::HashAlgorithm;\nuse crate::provider::{AesMode, CryptoError, CryptoProvider, HmacProvider, SimpleDigest};\nuse crate::subtle::EllipticCurve;\n\npub struct GraviolaProvider;\n\npub enum GraviolaDigest {\n    Sha256(<Sha256 as Hash>::Context),\n    Sha384(<Sha384 as Hash>::Context),\n    Sha512(<Sha512 as Hash>::Context),\n}\n\nimpl SimpleDigest for GraviolaDigest {\n    fn update(&mut self, data: &[u8]) {\n        match self {\n            GraviolaDigest::Sha256(h) => h.update(data),\n            GraviolaDigest::Sha384(h) => h.update(data),\n            GraviolaDigest::Sha512(h) => h.update(data),\n        }\n    }\n\n    fn finalize(self) -> Vec<u8> {\n        match self {\n            GraviolaDigest::Sha256(h) => h.finish().as_ref().to_vec(),\n            GraviolaDigest::Sha384(h) => h.finish().as_ref().to_vec(),\n            GraviolaDigest::Sha512(h) => h.finish().as_ref().to_vec(),\n        }\n    }\n}\n\npub enum GraviolaHmac {\n    Sha256(Hmac<Sha256>),\n    Sha384(Hmac<Sha384>),\n    Sha512(Hmac<Sha512>),\n}\n\nimpl HmacProvider for GraviolaHmac {\n    fn update(&mut self, data: &[u8]) {\n        match self {\n            GraviolaHmac::Sha256(h) => h.update(data),\n            GraviolaHmac::Sha384(h) => h.update(data),\n            GraviolaHmac::Sha512(h) => h.update(data),\n        }\n    }\n\n    fn finalize(self) -> Vec<u8> {\n        match self {\n            GraviolaHmac::Sha256(h) => h.finish().as_ref().to_vec(),\n            GraviolaHmac::Sha384(h) => h.finish().as_ref().to_vec(),\n            GraviolaHmac::Sha512(h) => h.finish().as_ref().to_vec(),\n        }\n    }\n}\n\nimpl CryptoProvider for GraviolaProvider {\n    type Digest = GraviolaDigest;\n    type Hmac = GraviolaHmac;\n\n    fn digest(&self, algorithm: HashAlgorithm) -> Self::Digest {\n        match algorithm {\n            HashAlgorithm::Sha256 => GraviolaDigest::Sha256(Sha256::new()),\n            HashAlgorithm::Sha384 => GraviolaDigest::Sha384(Sha384::new()),\n            HashAlgorithm::Sha512 => GraviolaDigest::Sha512(Sha512::new()),\n            _ => panic!(\"Unsupported digest algorithm for Graviola\"),\n        }\n    }\n\n    fn hmac(&self, algorithm: HashAlgorithm, key: &[u8]) -> Self::Hmac {\n        match algorithm {\n            HashAlgorithm::Sha256 => GraviolaHmac::Sha256(Hmac::<Sha256>::new(key)),\n            HashAlgorithm::Sha384 => GraviolaHmac::Sha384(Hmac::<Sha384>::new(key)),\n            HashAlgorithm::Sha512 => GraviolaHmac::Sha512(Hmac::<Sha512>::new(key)),\n            _ => panic!(\"Unsupported HMAC algorithm for Graviola\"),\n        }\n    }\n\n    fn ecdsa_sign(\n        &self,\n        _curve: EllipticCurve,\n        _private_key_der: &[u8],\n        _digest: &[u8],\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn ecdsa_verify(\n        &self,\n        _curve: EllipticCurve,\n        _public_key_sec1: &[u8],\n        _signature: &[u8],\n        _digest: &[u8],\n    ) -> Result<bool, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn ed25519_sign(&self, _private_key_der: &[u8], _data: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn ed25519_verify(\n        &self,\n        _public_key_bytes: &[u8],\n        _signature: &[u8],\n        _data: &[u8],\n    ) -> Result<bool, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn rsa_pss_sign(\n        &self,\n        _private_key_der: &[u8],\n        _digest: &[u8],\n        _salt_length: usize,\n        _hash_alg: HashAlgorithm,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn rsa_pss_verify(\n        &self,\n        _public_key_der: &[u8],\n        _signature: &[u8],\n        _digest: &[u8],\n        _salt_length: usize,\n        _hash_alg: HashAlgorithm,\n    ) -> Result<bool, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn rsa_pkcs1v15_sign(\n        &self,\n        _private_key_der: &[u8],\n        _digest: &[u8],\n        _hash_alg: HashAlgorithm,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn rsa_pkcs1v15_verify(\n        &self,\n        _public_key_der: &[u8],\n        _signature: &[u8],\n        _digest: &[u8],\n        _hash_alg: HashAlgorithm,\n    ) -> Result<bool, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn rsa_oaep_encrypt(\n        &self,\n        _public_key_der: &[u8],\n        _data: &[u8],\n        _hash_alg: HashAlgorithm,\n        _label: Option<&[u8]>,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn rsa_oaep_decrypt(\n        &self,\n        _private_key_der: &[u8],\n        _data: &[u8],\n        _hash_alg: HashAlgorithm,\n        _label: Option<&[u8]>,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn ecdh_derive_bits(\n        &self,\n        _curve: EllipticCurve,\n        _private_key_der: &[u8],\n        _public_key_sec1: &[u8],\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn x25519_derive_bits(\n        &self,\n        _private_key: &[u8],\n        _public_key: &[u8],\n    ) -> Result<Vec<u8>, CryptoError> {\n        // Graviola doesn't expose from_bytes for X25519 PrivateKey\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn aes_encrypt(\n        &self,\n        mode: AesMode,\n        key: &[u8],\n        iv: &[u8],\n        data: &[u8],\n        additional_data: Option<&[u8]>,\n    ) -> Result<Vec<u8>, CryptoError> {\n        match mode {\n            AesMode::Gcm { .. } => {\n                let nonce: [u8; 12] = iv.try_into().map_err(|_| CryptoError::InvalidData(None))?;\n                if !matches!(key.len(), 16 | 32) {\n                    return Err(CryptoError::InvalidKey(None));\n                }\n                let aead = AesGcm::new(key);\n                let aad = additional_data.unwrap_or(&[]);\n                let mut ciphertext = data.to_vec();\n                let mut tag = [0u8; 16];\n                aead.encrypt(&nonce, aad, &mut ciphertext, &mut tag);\n                ciphertext.extend_from_slice(&tag);\n                Ok(ciphertext)\n            },\n            _ => Err(CryptoError::UnsupportedAlgorithm),\n        }\n    }\n\n    fn aes_decrypt(\n        &self,\n        mode: AesMode,\n        key: &[u8],\n        iv: &[u8],\n        data: &[u8],\n        additional_data: Option<&[u8]>,\n    ) -> Result<Vec<u8>, CryptoError> {\n        match mode {\n            AesMode::Gcm { .. } => {\n                let nonce: [u8; 12] = iv.try_into().map_err(|_| CryptoError::InvalidData(None))?;\n                if !matches!(key.len(), 16 | 32) {\n                    return Err(CryptoError::InvalidKey(None));\n                }\n                if data.len() < 16 {\n                    return Err(CryptoError::InvalidData(None));\n                }\n                let aead = AesGcm::new(key);\n                let aad = additional_data.unwrap_or(&[]);\n                let (ciphertext, tag) = data.split_at(data.len() - 16);\n                let tag: [u8; 16] = tag.try_into().unwrap();\n                let mut plaintext = ciphertext.to_vec();\n                aead.decrypt(&nonce, aad, &mut plaintext, &tag)\n                    .map_err(|_| CryptoError::DecryptionFailed(None))?;\n                Ok(plaintext)\n            },\n            _ => Err(CryptoError::UnsupportedAlgorithm),\n        }\n    }\n\n    fn aes_kw_wrap(&self, _kek: &[u8], _key: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn aes_kw_unwrap(&self, _kek: &[u8], _wrapped_key: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn hkdf_derive_key(\n        &self,\n        _key: &[u8],\n        _salt: &[u8],\n        _info: &[u8],\n        _length: usize,\n        _hash_alg: HashAlgorithm,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn pbkdf2_derive_key(\n        &self,\n        _password: &[u8],\n        _salt: &[u8],\n        _iterations: u32,\n        _length: usize,\n        _hash_alg: HashAlgorithm,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn generate_aes_key(&self, length_bits: u16) -> Result<Vec<u8>, CryptoError> {\n        if !matches!(length_bits, 128 | 256) {\n            return Err(CryptoError::InvalidLength);\n        }\n        Ok(crate::random_byte_array((length_bits / 8) as usize))\n    }\n\n    fn generate_hmac_key(\n        &self,\n        hash_alg: HashAlgorithm,\n        length_bits: u16,\n    ) -> Result<Vec<u8>, CryptoError> {\n        let length_bytes = if length_bits == 0 {\n            match hash_alg {\n                HashAlgorithm::Sha256 => 64,\n                HashAlgorithm::Sha384 | HashAlgorithm::Sha512 => 128,\n                _ => return Err(CryptoError::UnsupportedAlgorithm),\n            }\n        } else {\n            (length_bits / 8) as usize\n        };\n        Ok(crate::random_byte_array(length_bytes))\n    }\n\n    fn generate_ec_key(&self, _curve: EllipticCurve) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn generate_ed25519_key(&self) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn generate_x25519_key(&self) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {\n        // Graviola doesn't expose as_bytes for X25519 PrivateKey\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn generate_rsa_key(\n        &self,\n        _modulus_length: u32,\n        _public_exponent: &[u8],\n    ) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn import_rsa_public_key_pkcs1(\n        &self,\n        _der: &[u8],\n    ) -> Result<super::RsaImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_rsa_private_key_pkcs1(\n        &self,\n        _der: &[u8],\n    ) -> Result<super::RsaImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_rsa_public_key_spki(\n        &self,\n        _der: &[u8],\n    ) -> Result<super::RsaImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_rsa_private_key_pkcs8(\n        &self,\n        _der: &[u8],\n    ) -> Result<super::RsaImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_rsa_public_key_pkcs1(&self, _key_data: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_rsa_public_key_spki(&self, _key_data: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_rsa_private_key_pkcs8(&self, _key_data: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_ec_public_key_sec1(\n        &self,\n        _data: &[u8],\n        _curve: EllipticCurve,\n    ) -> Result<super::EcImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_ec_public_key_spki(&self, _der: &[u8]) -> Result<super::EcImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_ec_private_key_pkcs8(\n        &self,\n        _der: &[u8],\n    ) -> Result<super::EcImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_ec_private_key_sec1(\n        &self,\n        _data: &[u8],\n        _curve: EllipticCurve,\n    ) -> Result<super::EcImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_ec_public_key_sec1(\n        &self,\n        _key_data: &[u8],\n        _curve: EllipticCurve,\n        _is_private: bool,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_ec_public_key_spki(\n        &self,\n        _key_data: &[u8],\n        _curve: EllipticCurve,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_ec_private_key_pkcs8(\n        &self,\n        _key_data: &[u8],\n        _curve: EllipticCurve,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_okp_public_key_raw(\n        &self,\n        _data: &[u8],\n    ) -> Result<super::OkpImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_okp_public_key_spki(\n        &self,\n        _der: &[u8],\n        _expected_oid: &[u8],\n    ) -> Result<super::OkpImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_okp_private_key_pkcs8(\n        &self,\n        _der: &[u8],\n        _expected_oid: &[u8],\n    ) -> Result<super::OkpImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_okp_public_key_raw(\n        &self,\n        _key_data: &[u8],\n        _is_private: bool,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_okp_public_key_spki(\n        &self,\n        _key_data: &[u8],\n        _oid: &[u8],\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_okp_private_key_pkcs8(\n        &self,\n        _key_data: &[u8],\n        _oid: &[u8],\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_rsa_jwk(\n        &self,\n        _jwk: super::RsaJwkImport<'_>,\n    ) -> Result<super::RsaImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_rsa_jwk(\n        &self,\n        _key_data: &[u8],\n        _is_private: bool,\n    ) -> Result<super::RsaJwkExport, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_ec_jwk(\n        &self,\n        _jwk: super::EcJwkImport<'_>,\n        _curve: EllipticCurve,\n    ) -> Result<super::EcImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_ec_jwk(\n        &self,\n        _key_data: &[u8],\n        _curve: EllipticCurve,\n        _is_private: bool,\n    ) -> Result<super::EcJwkExport, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_okp_jwk(\n        &self,\n        _jwk: super::OkpJwkImport<'_>,\n        _is_ed25519: bool,\n    ) -> Result<super::OkpImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_okp_jwk(\n        &self,\n        _key_data: &[u8],\n        _is_private: bool,\n        _is_ed25519: bool,\n    ) -> Result<super::OkpJwkExport, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n}\n\n// Hybrid types for graviola-rust: Graviola for SHA256/384/512, RustCrypto for MD5/SHA1\n#[cfg(feature = \"crypto-graviola-rust\")]\npub enum GraviolaRustDigest {\n    Graviola(GraviolaDigest),\n    Rust(super::rust::RustDigest),\n}\n\n#[cfg(feature = \"crypto-graviola-rust\")]\nimpl GraviolaRustDigest {\n    pub fn new(algorithm: HashAlgorithm) -> Self {\n        match algorithm {\n            HashAlgorithm::Sha256 | HashAlgorithm::Sha384 | HashAlgorithm::Sha512 => {\n                Self::Graviola(GraviolaProvider.digest(algorithm))\n            },\n            _ => Self::Rust(super::rust::RustCryptoProvider.digest(algorithm)),\n        }\n    }\n}\n\n#[cfg(feature = \"crypto-graviola-rust\")]\nimpl SimpleDigest for GraviolaRustDigest {\n    fn update(&mut self, data: &[u8]) {\n        match self {\n            Self::Graviola(d) => d.update(data),\n            Self::Rust(d) => d.update(data),\n        }\n    }\n    fn finalize(self) -> Vec<u8> {\n        match self {\n            Self::Graviola(d) => d.finalize(),\n            Self::Rust(d) => d.finalize(),\n        }\n    }\n}\n\n#[cfg(feature = \"crypto-graviola-rust\")]\npub enum GraviolaRustHmac {\n    Graviola(GraviolaHmac),\n    Rust(super::rust::RustHmac),\n}\n\n#[cfg(feature = \"crypto-graviola-rust\")]\nimpl GraviolaRustHmac {\n    pub fn new(algorithm: HashAlgorithm, key: &[u8]) -> Self {\n        match algorithm {\n            HashAlgorithm::Sha256 | HashAlgorithm::Sha384 | HashAlgorithm::Sha512 => {\n                Self::Graviola(GraviolaProvider.hmac(algorithm, key))\n            },\n            _ => Self::Rust(super::rust::RustCryptoProvider.hmac(algorithm, key)),\n        }\n    }\n}\n\n#[cfg(feature = \"crypto-graviola-rust\")]\nimpl HmacProvider for GraviolaRustHmac {\n    fn update(&mut self, data: &[u8]) {\n        match self {\n            Self::Graviola(h) => h.update(data),\n            Self::Rust(h) => h.update(data),\n        }\n    }\n    fn finalize(self) -> Vec<u8> {\n        match self {\n            Self::Graviola(h) => h.finalize(),\n            Self::Rust(h) => h.finalize(),\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/provider/mod.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\n// Ensure only one crypto provider is selected\n#[cfg(all(feature = \"crypto-rust\", feature = \"crypto-openssl\"))]\ncompile_error!(\"Features `crypto-rust` and `crypto-openssl` are mutually exclusive\");\n\n#[cfg(all(feature = \"crypto-rust\", feature = \"crypto-ring\"))]\ncompile_error!(\"Features `crypto-rust` and `crypto-ring` are mutually exclusive\");\n\n#[cfg(all(feature = \"crypto-rust\", feature = \"crypto-graviola\"))]\ncompile_error!(\"Features `crypto-rust` and `crypto-graviola` are mutually exclusive\");\n\n#[cfg(all(feature = \"crypto-ring\", feature = \"crypto-openssl\"))]\ncompile_error!(\"Features `crypto-ring` and `crypto-openssl` are mutually exclusive\");\n\n#[cfg(all(feature = \"crypto-ring\", feature = \"crypto-graviola\"))]\ncompile_error!(\"Features `crypto-ring` and `crypto-graviola` are mutually exclusive\");\n\n#[cfg(all(feature = \"crypto-openssl\", feature = \"crypto-graviola\"))]\ncompile_error!(\"Features `crypto-openssl` and `crypto-graviola` are mutually exclusive\");\n\n#[cfg(all(feature = \"crypto-ring-rust\", feature = \"crypto-graviola-rust\"))]\ncompile_error!(\"Features `crypto-ring-rust` and `crypto-graviola-rust` are mutually exclusive\");\n\n#[cfg(any(feature = \"crypto-graviola\", feature = \"crypto-graviola-rust\"))]\nmod graviola;\n\n#[cfg(feature = \"crypto-openssl\")]\nmod openssl;\n\n#[cfg(any(feature = \"crypto-ring\", feature = \"crypto-ring-rust\"))]\nmod ring;\n\n#[cfg(feature = \"_rustcrypto\")]\nmod rust;\n\nuse crate::hash::HashAlgorithm;\nuse crate::subtle::EllipticCurve;\n\n#[derive(Debug)]\n#[allow(dead_code)]\npub struct RsaImportResult {\n    pub key_data: Vec<u8>,\n    pub modulus_length: u32,\n    pub public_exponent: Vec<u8>,\n    pub is_private: bool,\n}\n\n#[derive(Debug)]\n#[allow(dead_code)]\npub struct EcImportResult {\n    pub key_data: Vec<u8>,\n    pub is_private: bool,\n}\n\n#[derive(Debug)]\n#[allow(dead_code)]\npub struct OkpImportResult {\n    pub key_data: Vec<u8>,\n    pub is_private: bool,\n}\n\n/// RSA JWK components for import (all values are raw bytes, not base64)\n#[derive(Debug)]\n#[allow(dead_code)]\npub struct RsaJwkImport<'a> {\n    pub n: &'a [u8],          // modulus\n    pub e: &'a [u8],          // public exponent\n    pub d: Option<&'a [u8]>,  // private exponent\n    pub p: Option<&'a [u8]>,  // first prime\n    pub q: Option<&'a [u8]>,  // second prime\n    pub dp: Option<&'a [u8]>, // first factor CRT exponent\n    pub dq: Option<&'a [u8]>, // second factor CRT exponent\n    pub qi: Option<&'a [u8]>, // first CRT coefficient\n}\n\n/// RSA JWK components for export\n#[derive(Debug)]\n#[allow(dead_code)]\npub struct RsaJwkExport {\n    pub n: Vec<u8>,\n    pub e: Vec<u8>,\n    pub d: Option<Vec<u8>>,\n    pub p: Option<Vec<u8>>,\n    pub q: Option<Vec<u8>>,\n    pub dp: Option<Vec<u8>>,\n    pub dq: Option<Vec<u8>>,\n    pub qi: Option<Vec<u8>>,\n}\n\n/// EC JWK components for import (all values are raw bytes)\n#[derive(Debug)]\n#[allow(dead_code)]\npub struct EcJwkImport<'a> {\n    pub x: &'a [u8],\n    pub y: &'a [u8],\n    pub d: Option<&'a [u8]>,\n}\n\n/// EC JWK components for export\n#[derive(Debug)]\n#[allow(dead_code)]\npub struct EcJwkExport {\n    pub x: Vec<u8>,\n    pub y: Vec<u8>,\n    pub d: Option<Vec<u8>>,\n}\n\n/// OKP (Ed25519/X25519) JWK components for import\n#[derive(Debug)]\n#[allow(dead_code)]\npub struct OkpJwkImport<'a> {\n    pub x: &'a [u8],         // public key\n    pub d: Option<&'a [u8]>, // private key\n}\n\n/// OKP JWK components for export\n#[derive(Debug)]\n#[allow(dead_code)]\npub struct OkpJwkExport {\n    pub x: Vec<u8>,\n    pub d: Option<Vec<u8>>,\n}\n\npub trait SimpleDigest: Send {\n    fn update(&mut self, data: &[u8]);\n    fn finalize(self) -> Vec<u8>\n    where\n        Self: Sized;\n}\n\n#[derive(Debug, Clone, Copy)]\n#[allow(dead_code)]\npub enum AesMode {\n    Ctr { counter_length: u32 },\n    Cbc,\n    Gcm { tag_length: u8 },\n}\n\n#[allow(dead_code)]\npub trait CryptoProvider {\n    type Digest: SimpleDigest;\n    type Hmac: HmacProvider;\n\n    // Digest operations\n    fn digest(&self, algorithm: HashAlgorithm) -> Self::Digest;\n\n    // HMAC operations\n    fn hmac(&self, algorithm: HashAlgorithm, key: &[u8]) -> Self::Hmac;\n\n    // ECDSA operations\n    fn ecdsa_sign(\n        &self,\n        curve: EllipticCurve,\n        private_key_der: &[u8],\n        digest: &[u8],\n    ) -> Result<Vec<u8>, CryptoError>;\n    fn ecdsa_verify(\n        &self,\n        curve: EllipticCurve,\n        public_key_sec1: &[u8],\n        signature: &[u8],\n        digest: &[u8],\n    ) -> Result<bool, CryptoError>;\n\n    // EdDSA operations\n    fn ed25519_sign(&self, private_key_der: &[u8], data: &[u8]) -> Result<Vec<u8>, CryptoError>;\n    fn ed25519_verify(\n        &self,\n        public_key_bytes: &[u8],\n        signature: &[u8],\n        data: &[u8],\n    ) -> Result<bool, CryptoError>;\n\n    // RSA operations\n    fn rsa_pss_sign(\n        &self,\n        private_key_der: &[u8],\n        digest: &[u8],\n        salt_length: usize,\n        hash_alg: HashAlgorithm,\n    ) -> Result<Vec<u8>, CryptoError>;\n    fn rsa_pss_verify(\n        &self,\n        public_key_der: &[u8],\n        signature: &[u8],\n        digest: &[u8],\n        salt_length: usize,\n        hash_alg: HashAlgorithm,\n    ) -> Result<bool, CryptoError>;\n    fn rsa_pkcs1v15_sign(\n        &self,\n        private_key_der: &[u8],\n        digest: &[u8],\n        hash_alg: HashAlgorithm,\n    ) -> Result<Vec<u8>, CryptoError>;\n    fn rsa_pkcs1v15_verify(\n        &self,\n        public_key_der: &[u8],\n        signature: &[u8],\n        digest: &[u8],\n        hash_alg: HashAlgorithm,\n    ) -> Result<bool, CryptoError>;\n    fn rsa_oaep_encrypt(\n        &self,\n        public_key_der: &[u8],\n        data: &[u8],\n        hash_alg: HashAlgorithm,\n        label: Option<&[u8]>,\n    ) -> Result<Vec<u8>, CryptoError>;\n    fn rsa_oaep_decrypt(\n        &self,\n        private_key_der: &[u8],\n        data: &[u8],\n        hash_alg: HashAlgorithm,\n        label: Option<&[u8]>,\n    ) -> Result<Vec<u8>, CryptoError>;\n\n    // ECDH operations\n    fn ecdh_derive_bits(\n        &self,\n        curve: EllipticCurve,\n        private_key_der: &[u8],\n        public_key_sec1: &[u8],\n    ) -> Result<Vec<u8>, CryptoError>;\n\n    // X25519 operations\n    fn x25519_derive_bits(\n        &self,\n        private_key: &[u8],\n        public_key: &[u8],\n    ) -> Result<Vec<u8>, CryptoError>;\n\n    // AES operations\n    fn aes_encrypt(\n        &self,\n        mode: AesMode,\n        key: &[u8],\n        iv: &[u8],\n        data: &[u8],\n        additional_data: Option<&[u8]>,\n    ) -> Result<Vec<u8>, CryptoError>;\n    fn aes_decrypt(\n        &self,\n        mode: AesMode,\n        key: &[u8],\n        iv: &[u8],\n        data: &[u8],\n        additional_data: Option<&[u8]>,\n    ) -> Result<Vec<u8>, CryptoError>;\n\n    // AES-KW operations\n    fn aes_kw_wrap(&self, kek: &[u8], key: &[u8]) -> Result<Vec<u8>, CryptoError>;\n    fn aes_kw_unwrap(&self, kek: &[u8], wrapped_key: &[u8]) -> Result<Vec<u8>, CryptoError>;\n\n    // KDF operations\n    fn hkdf_derive_key(\n        &self,\n        key: &[u8],\n        salt: &[u8],\n        info: &[u8],\n        length: usize,\n        hash_alg: HashAlgorithm,\n    ) -> Result<Vec<u8>, CryptoError>;\n    fn pbkdf2_derive_key(\n        &self,\n        password: &[u8],\n        salt: &[u8],\n        iterations: u32,\n        length: usize,\n        hash_alg: HashAlgorithm,\n    ) -> Result<Vec<u8>, CryptoError>;\n\n    fn generate_aes_key(&self, length_bits: u16) -> Result<Vec<u8>, CryptoError>;\n    fn generate_hmac_key(\n        &self,\n        hash_alg: HashAlgorithm,\n        length_bits: u16,\n    ) -> Result<Vec<u8>, CryptoError>;\n    fn generate_ec_key(&self, curve: EllipticCurve) -> Result<(Vec<u8>, Vec<u8>), CryptoError>; // (private, public)\n    fn generate_ed25519_key(&self) -> Result<(Vec<u8>, Vec<u8>), CryptoError>;\n    fn generate_x25519_key(&self) -> Result<(Vec<u8>, Vec<u8>), CryptoError>;\n    fn generate_rsa_key(\n        &self,\n        modulus_length: u32,\n        public_exponent: &[u8],\n    ) -> Result<(Vec<u8>, Vec<u8>), CryptoError>;\n\n    // RSA key import from DER formats\n    fn import_rsa_public_key_pkcs1(&self, der: &[u8]) -> Result<RsaImportResult, CryptoError>;\n    fn import_rsa_private_key_pkcs1(&self, der: &[u8]) -> Result<RsaImportResult, CryptoError>;\n    fn import_rsa_public_key_spki(&self, der: &[u8]) -> Result<RsaImportResult, CryptoError>;\n    fn import_rsa_private_key_pkcs8(&self, der: &[u8]) -> Result<RsaImportResult, CryptoError>;\n\n    // RSA key export to DER formats\n    fn export_rsa_public_key_pkcs1(&self, key_data: &[u8]) -> Result<Vec<u8>, CryptoError>;\n    fn export_rsa_public_key_spki(&self, key_data: &[u8]) -> Result<Vec<u8>, CryptoError>;\n    fn export_rsa_private_key_pkcs8(&self, key_data: &[u8]) -> Result<Vec<u8>, CryptoError>;\n\n    // EC key import from DER formats\n    fn import_ec_public_key_sec1(\n        &self,\n        data: &[u8],\n        curve: EllipticCurve,\n    ) -> Result<EcImportResult, CryptoError>;\n    fn import_ec_public_key_spki(&self, der: &[u8]) -> Result<EcImportResult, CryptoError>;\n    fn import_ec_private_key_pkcs8(&self, der: &[u8]) -> Result<EcImportResult, CryptoError>;\n    fn import_ec_private_key_sec1(\n        &self,\n        data: &[u8],\n        curve: EllipticCurve,\n    ) -> Result<EcImportResult, CryptoError>;\n\n    // EC key export\n    fn export_ec_public_key_sec1(\n        &self,\n        key_data: &[u8],\n        curve: EllipticCurve,\n        is_private: bool,\n    ) -> Result<Vec<u8>, CryptoError>;\n    fn export_ec_public_key_spki(\n        &self,\n        key_data: &[u8],\n        curve: EllipticCurve,\n    ) -> Result<Vec<u8>, CryptoError>;\n    fn export_ec_private_key_pkcs8(\n        &self,\n        key_data: &[u8],\n        curve: EllipticCurve,\n    ) -> Result<Vec<u8>, CryptoError>;\n\n    // OKP (Ed25519/X25519) key import\n    fn import_okp_public_key_raw(&self, data: &[u8]) -> Result<OkpImportResult, CryptoError>;\n    fn import_okp_public_key_spki(\n        &self,\n        der: &[u8],\n        expected_oid: &[u8],\n    ) -> Result<OkpImportResult, CryptoError>;\n    fn import_okp_private_key_pkcs8(\n        &self,\n        der: &[u8],\n        expected_oid: &[u8],\n    ) -> Result<OkpImportResult, CryptoError>;\n\n    // OKP key export\n    fn export_okp_public_key_raw(\n        &self,\n        key_data: &[u8],\n        is_private: bool,\n    ) -> Result<Vec<u8>, CryptoError>;\n    fn export_okp_public_key_spki(\n        &self,\n        key_data: &[u8],\n        oid: &[u8],\n    ) -> Result<Vec<u8>, CryptoError>;\n    fn export_okp_private_key_pkcs8(\n        &self,\n        key_data: &[u8],\n        oid: &[u8],\n    ) -> Result<Vec<u8>, CryptoError>;\n\n    // JWK import/export\n    fn import_rsa_jwk(&self, jwk: RsaJwkImport<'_>) -> Result<RsaImportResult, CryptoError>;\n    fn export_rsa_jwk(\n        &self,\n        key_data: &[u8],\n        is_private: bool,\n    ) -> Result<RsaJwkExport, CryptoError>;\n    fn import_ec_jwk(\n        &self,\n        jwk: EcJwkImport<'_>,\n        curve: EllipticCurve,\n    ) -> Result<EcImportResult, CryptoError>;\n    fn export_ec_jwk(\n        &self,\n        key_data: &[u8],\n        curve: EllipticCurve,\n        is_private: bool,\n    ) -> Result<EcJwkExport, CryptoError>;\n\n    // OKP JWK import/export\n    fn import_okp_jwk(\n        &self,\n        jwk: OkpJwkImport<'_>,\n        is_ed25519: bool,\n    ) -> Result<OkpImportResult, CryptoError>;\n    fn export_okp_jwk(\n        &self,\n        key_data: &[u8],\n        is_private: bool,\n        is_ed25519: bool,\n    ) -> Result<OkpJwkExport, CryptoError>;\n}\n\npub trait HmacProvider: Send {\n    fn update(&mut self, data: &[u8]);\n    fn finalize(self) -> Vec<u8>\n    where\n        Self: Sized;\n}\n\n#[derive(Debug)]\n#[allow(dead_code)]\npub enum CryptoError {\n    InvalidKey(Option<Box<str>>),\n    InvalidData(Option<Box<str>>),\n    InvalidSignature(Option<Box<str>>),\n    InvalidLength,\n    SigningFailed(Option<Box<str>>),\n    VerificationFailed,\n    OperationFailed(Option<Box<str>>),\n    UnsupportedAlgorithm,\n    DerivationFailed(Option<Box<str>>),\n    EncryptionFailed(Option<Box<str>>),\n    DecryptionFailed(Option<Box<str>>),\n}\n\nimpl std::fmt::Display for CryptoError {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            CryptoError::InvalidKey(None) => write!(f, \"Invalid key\"),\n            CryptoError::InvalidKey(Some(msg)) => write!(f, \"Invalid key: {}\", msg),\n            CryptoError::InvalidData(None) => write!(f, \"Invalid data\"),\n            CryptoError::InvalidData(Some(msg)) => write!(f, \"Invalid data: {}\", msg),\n            CryptoError::InvalidSignature(None) => write!(f, \"Invalid signature\"),\n            CryptoError::InvalidSignature(Some(msg)) => write!(f, \"Invalid signature: {}\", msg),\n            CryptoError::InvalidLength => write!(f, \"Invalid length\"),\n            CryptoError::SigningFailed(None) => write!(f, \"Signing failed\"),\n            CryptoError::SigningFailed(Some(msg)) => write!(f, \"Signing failed: {}\", msg),\n            CryptoError::VerificationFailed => write!(f, \"Verification failed\"),\n            CryptoError::OperationFailed(None) => write!(f, \"Operation failed\"),\n            CryptoError::OperationFailed(Some(msg)) => write!(f, \"Operation failed: {}\", msg),\n            CryptoError::UnsupportedAlgorithm => write!(f, \"Unsupported algorithm\"),\n            CryptoError::DerivationFailed(None) => write!(f, \"Derivation failed\"),\n            CryptoError::DerivationFailed(Some(msg)) => write!(f, \"Derivation failed: {}\", msg),\n            CryptoError::EncryptionFailed(None) => write!(f, \"Encryption failed\"),\n            CryptoError::EncryptionFailed(Some(msg)) => write!(f, \"Encryption failed: {}\", msg),\n            CryptoError::DecryptionFailed(None) => write!(f, \"Decryption failed\"),\n            CryptoError::DecryptionFailed(Some(msg)) => write!(f, \"Decryption failed: {}\", msg),\n        }\n    }\n}\n\nimpl std::error::Error for CryptoError {}\n\n#[cfg(feature = \"crypto-openssl\")]\npub type DefaultProvider = openssl::OpenSslProvider;\n\n#[cfg(feature = \"crypto-rust\")]\npub type DefaultProvider = rust::RustCryptoProvider;\n\n#[cfg(feature = \"crypto-ring\")]\npub type DefaultProvider = ring::RingProvider;\n\n#[cfg(feature = \"crypto-ring-rust\")]\npub type DefaultProvider = RingRustProvider;\n\n#[cfg(all(feature = \"crypto-graviola\", not(feature = \"crypto-graviola-rust\")))]\npub type DefaultProvider = graviola::GraviolaProvider;\n\n#[cfg(feature = \"crypto-graviola-rust\")]\npub type DefaultProvider = GraviolaRustProvider;\n\n// Macro to generate hybrid providers that delegate to RustCrypto\n#[cfg(any(feature = \"crypto-ring-rust\", feature = \"crypto-graviola-rust\"))]\nmacro_rules! impl_hybrid_provider {\n    ($name:ident, $digest:ty, $hmac:ty, $digest_fn:expr, $hmac_fn:expr, $aes_encrypt:expr, $aes_decrypt:expr) => {\n        pub struct $name;\n        impl CryptoProvider for $name {\n            type Digest = $digest;\n            type Hmac = $hmac;\n            fn digest(&self, alg: HashAlgorithm) -> Self::Digest {\n                $digest_fn(alg)\n            }\n            fn hmac(&self, alg: HashAlgorithm, key: &[u8]) -> Self::Hmac {\n                $hmac_fn(alg, key)\n            }\n            fn ecdsa_sign(\n                &self,\n                c: EllipticCurve,\n                k: &[u8],\n                d: &[u8],\n            ) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.ecdsa_sign(c, k, d)\n            }\n            fn ecdsa_verify(\n                &self,\n                c: EllipticCurve,\n                k: &[u8],\n                s: &[u8],\n                d: &[u8],\n            ) -> Result<bool, CryptoError> {\n                rust::RustCryptoProvider.ecdsa_verify(c, k, s, d)\n            }\n            fn ed25519_sign(&self, k: &[u8], d: &[u8]) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.ed25519_sign(k, d)\n            }\n            fn ed25519_verify(&self, k: &[u8], s: &[u8], d: &[u8]) -> Result<bool, CryptoError> {\n                rust::RustCryptoProvider.ed25519_verify(k, s, d)\n            }\n            fn rsa_pss_sign(\n                &self,\n                k: &[u8],\n                d: &[u8],\n                s: usize,\n                a: HashAlgorithm,\n            ) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.rsa_pss_sign(k, d, s, a)\n            }\n            fn rsa_pss_verify(\n                &self,\n                k: &[u8],\n                s: &[u8],\n                d: &[u8],\n                sl: usize,\n                a: HashAlgorithm,\n            ) -> Result<bool, CryptoError> {\n                rust::RustCryptoProvider.rsa_pss_verify(k, s, d, sl, a)\n            }\n            fn rsa_pkcs1v15_sign(\n                &self,\n                k: &[u8],\n                d: &[u8],\n                a: HashAlgorithm,\n            ) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.rsa_pkcs1v15_sign(k, d, a)\n            }\n            fn rsa_pkcs1v15_verify(\n                &self,\n                k: &[u8],\n                s: &[u8],\n                d: &[u8],\n                a: HashAlgorithm,\n            ) -> Result<bool, CryptoError> {\n                rust::RustCryptoProvider.rsa_pkcs1v15_verify(k, s, d, a)\n            }\n            fn rsa_oaep_encrypt(\n                &self,\n                k: &[u8],\n                d: &[u8],\n                a: HashAlgorithm,\n                l: Option<&[u8]>,\n            ) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.rsa_oaep_encrypt(k, d, a, l)\n            }\n            fn rsa_oaep_decrypt(\n                &self,\n                k: &[u8],\n                d: &[u8],\n                a: HashAlgorithm,\n                l: Option<&[u8]>,\n            ) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.rsa_oaep_decrypt(k, d, a, l)\n            }\n            fn ecdh_derive_bits(\n                &self,\n                c: EllipticCurve,\n                pk: &[u8],\n                pubk: &[u8],\n            ) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.ecdh_derive_bits(c, pk, pubk)\n            }\n            fn x25519_derive_bits(&self, pk: &[u8], pubk: &[u8]) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.x25519_derive_bits(pk, pubk)\n            }\n            fn aes_encrypt(\n                &self,\n                m: AesMode,\n                k: &[u8],\n                iv: &[u8],\n                d: &[u8],\n                aad: Option<&[u8]>,\n            ) -> Result<Vec<u8>, CryptoError> {\n                $aes_encrypt(m, k, iv, d, aad)\n            }\n            fn aes_decrypt(\n                &self,\n                m: AesMode,\n                k: &[u8],\n                iv: &[u8],\n                d: &[u8],\n                aad: Option<&[u8]>,\n            ) -> Result<Vec<u8>, CryptoError> {\n                $aes_decrypt(m, k, iv, d, aad)\n            }\n            fn aes_kw_wrap(&self, kek: &[u8], k: &[u8]) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.aes_kw_wrap(kek, k)\n            }\n            fn aes_kw_unwrap(&self, kek: &[u8], w: &[u8]) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.aes_kw_unwrap(kek, w)\n            }\n            fn hkdf_derive_key(\n                &self,\n                k: &[u8],\n                s: &[u8],\n                i: &[u8],\n                l: usize,\n                a: HashAlgorithm,\n            ) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.hkdf_derive_key(k, s, i, l, a)\n            }\n            fn pbkdf2_derive_key(\n                &self,\n                p: &[u8],\n                s: &[u8],\n                i: u32,\n                l: usize,\n                a: HashAlgorithm,\n            ) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.pbkdf2_derive_key(p, s, i, l, a)\n            }\n            fn generate_aes_key(&self, b: u16) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.generate_aes_key(b)\n            }\n            fn generate_hmac_key(&self, a: HashAlgorithm, b: u16) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.generate_hmac_key(a, b)\n            }\n            fn generate_ec_key(&self, c: EllipticCurve) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {\n                rust::RustCryptoProvider.generate_ec_key(c)\n            }\n            fn generate_ed25519_key(&self) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {\n                rust::RustCryptoProvider.generate_ed25519_key()\n            }\n            fn generate_x25519_key(&self) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {\n                rust::RustCryptoProvider.generate_x25519_key()\n            }\n            fn generate_rsa_key(\n                &self,\n                b: u32,\n                e: &[u8],\n            ) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {\n                rust::RustCryptoProvider.generate_rsa_key(b, e)\n            }\n            fn import_rsa_public_key_pkcs1(\n                &self,\n                d: &[u8],\n            ) -> Result<RsaImportResult, CryptoError> {\n                rust::RustCryptoProvider.import_rsa_public_key_pkcs1(d)\n            }\n            fn import_rsa_private_key_pkcs1(\n                &self,\n                d: &[u8],\n            ) -> Result<RsaImportResult, CryptoError> {\n                rust::RustCryptoProvider.import_rsa_private_key_pkcs1(d)\n            }\n            fn import_rsa_public_key_spki(&self, d: &[u8]) -> Result<RsaImportResult, CryptoError> {\n                rust::RustCryptoProvider.import_rsa_public_key_spki(d)\n            }\n            fn import_rsa_private_key_pkcs8(\n                &self,\n                d: &[u8],\n            ) -> Result<RsaImportResult, CryptoError> {\n                rust::RustCryptoProvider.import_rsa_private_key_pkcs8(d)\n            }\n            fn export_rsa_public_key_pkcs1(&self, d: &[u8]) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.export_rsa_public_key_pkcs1(d)\n            }\n            fn export_rsa_public_key_spki(&self, d: &[u8]) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.export_rsa_public_key_spki(d)\n            }\n            fn export_rsa_private_key_pkcs8(&self, d: &[u8]) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.export_rsa_private_key_pkcs8(d)\n            }\n            fn import_ec_public_key_sec1(\n                &self,\n                d: &[u8],\n                c: EllipticCurve,\n            ) -> Result<EcImportResult, CryptoError> {\n                rust::RustCryptoProvider.import_ec_public_key_sec1(d, c)\n            }\n            fn import_ec_public_key_spki(&self, d: &[u8]) -> Result<EcImportResult, CryptoError> {\n                rust::RustCryptoProvider.import_ec_public_key_spki(d)\n            }\n            fn import_ec_private_key_pkcs8(&self, d: &[u8]) -> Result<EcImportResult, CryptoError> {\n                rust::RustCryptoProvider.import_ec_private_key_pkcs8(d)\n            }\n            fn import_ec_private_key_sec1(\n                &self,\n                d: &[u8],\n                c: EllipticCurve,\n            ) -> Result<EcImportResult, CryptoError> {\n                rust::RustCryptoProvider.import_ec_private_key_sec1(d, c)\n            }\n            fn export_ec_public_key_sec1(\n                &self,\n                d: &[u8],\n                c: EllipticCurve,\n                p: bool,\n            ) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.export_ec_public_key_sec1(d, c, p)\n            }\n            fn export_ec_public_key_spki(\n                &self,\n                d: &[u8],\n                c: EllipticCurve,\n            ) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.export_ec_public_key_spki(d, c)\n            }\n            fn export_ec_private_key_pkcs8(\n                &self,\n                d: &[u8],\n                c: EllipticCurve,\n            ) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.export_ec_private_key_pkcs8(d, c)\n            }\n            fn import_okp_public_key_raw(&self, d: &[u8]) -> Result<OkpImportResult, CryptoError> {\n                rust::RustCryptoProvider.import_okp_public_key_raw(d)\n            }\n            fn import_okp_public_key_spki(\n                &self,\n                d: &[u8],\n                o: &[u8],\n            ) -> Result<OkpImportResult, CryptoError> {\n                rust::RustCryptoProvider.import_okp_public_key_spki(d, o)\n            }\n            fn import_okp_private_key_pkcs8(\n                &self,\n                d: &[u8],\n                o: &[u8],\n            ) -> Result<OkpImportResult, CryptoError> {\n                rust::RustCryptoProvider.import_okp_private_key_pkcs8(d, o)\n            }\n            fn export_okp_public_key_raw(&self, d: &[u8], p: bool) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.export_okp_public_key_raw(d, p)\n            }\n            fn export_okp_public_key_spki(\n                &self,\n                d: &[u8],\n                o: &[u8],\n            ) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.export_okp_public_key_spki(d, o)\n            }\n            fn export_okp_private_key_pkcs8(\n                &self,\n                d: &[u8],\n                o: &[u8],\n            ) -> Result<Vec<u8>, CryptoError> {\n                rust::RustCryptoProvider.export_okp_private_key_pkcs8(d, o)\n            }\n            fn import_rsa_jwk(&self, j: RsaJwkImport<'_>) -> Result<RsaImportResult, CryptoError> {\n                rust::RustCryptoProvider.import_rsa_jwk(j)\n            }\n            fn export_rsa_jwk(&self, d: &[u8], p: bool) -> Result<RsaJwkExport, CryptoError> {\n                rust::RustCryptoProvider.export_rsa_jwk(d, p)\n            }\n            fn import_ec_jwk(\n                &self,\n                j: EcJwkImport<'_>,\n                c: EllipticCurve,\n            ) -> Result<EcImportResult, CryptoError> {\n                rust::RustCryptoProvider.import_ec_jwk(j, c)\n            }\n            fn export_ec_jwk(\n                &self,\n                d: &[u8],\n                c: EllipticCurve,\n                p: bool,\n            ) -> Result<EcJwkExport, CryptoError> {\n                rust::RustCryptoProvider.export_ec_jwk(d, c, p)\n            }\n            fn import_okp_jwk(\n                &self,\n                j: OkpJwkImport<'_>,\n                is_ed25519: bool,\n            ) -> Result<OkpImportResult, CryptoError> {\n                rust::RustCryptoProvider.import_okp_jwk(j, is_ed25519)\n            }\n            fn export_okp_jwk(\n                &self,\n                d: &[u8],\n                is_private: bool,\n                is_ed25519: bool,\n            ) -> Result<OkpJwkExport, CryptoError> {\n                rust::RustCryptoProvider.export_okp_jwk(d, is_private, is_ed25519)\n            }\n        }\n    };\n}\n\n#[cfg(feature = \"crypto-ring-rust\")]\nimpl_hybrid_provider!(\n    RingRustProvider,\n    ring::RingDigestType,\n    ring::RingHmacType,\n    |a| ring::RingProvider.digest(a),\n    |a, k| ring::RingProvider.hmac(a, k),\n    |m, k, iv, d, aad| rust::RustCryptoProvider.aes_encrypt(m, k, iv, d, aad),\n    |m, k, iv, d, aad| rust::RustCryptoProvider.aes_decrypt(m, k, iv, d, aad)\n);\n\n#[cfg(feature = \"crypto-graviola-rust\")]\nfn graviola_aes_supported() -> bool {\n    #[cfg(target_arch = \"aarch64\")]\n    {\n        std::arch::is_aarch64_feature_detected!(\"aes\")\n    }\n    #[cfg(target_arch = \"x86_64\")]\n    {\n        std::arch::is_x86_feature_detected!(\"aes\")\n    }\n    #[cfg(not(any(target_arch = \"aarch64\", target_arch = \"x86_64\")))]\n    {\n        false\n    }\n}\n\n#[cfg(feature = \"crypto-graviola-rust\")]\nimpl_hybrid_provider!(\n    GraviolaRustProvider,\n    graviola::GraviolaRustDigest,\n    graviola::GraviolaRustHmac,\n    graviola::GraviolaRustDigest::new,\n    graviola::GraviolaRustHmac::new,\n    |m: AesMode, k: &[u8], iv: &[u8], d: &[u8], aad: Option<&[u8]>| {\n        if graviola_aes_supported()\n            && matches!(m, AesMode::Gcm { .. })\n            && matches!(k.len(), 16 | 32)\n        {\n            graviola::GraviolaProvider.aes_encrypt(m, k, iv, d, aad)\n        } else {\n            rust::RustCryptoProvider.aes_encrypt(m, k, iv, d, aad)\n        }\n    },\n    |m: AesMode, k: &[u8], iv: &[u8], d: &[u8], aad: Option<&[u8]>| {\n        if graviola_aes_supported()\n            && matches!(m, AesMode::Gcm { .. })\n            && matches!(k.len(), 16 | 32)\n        {\n            graviola::GraviolaProvider.aes_decrypt(m, k, iv, d, aad)\n        } else {\n            rust::RustCryptoProvider.aes_decrypt(m, k, iv, d, aad)\n        }\n    }\n);\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    fn provider() -> impl CryptoProvider {\n        #[cfg(feature = \"crypto-rust\")]\n        return rust::RustCryptoProvider;\n        #[cfg(feature = \"crypto-ring-rust\")]\n        return RingRustProvider;\n        #[cfg(feature = \"crypto-graviola-rust\")]\n        return GraviolaRustProvider;\n        #[cfg(feature = \"crypto-openssl\")]\n        return openssl::OpenSslProvider;\n        #[cfg(feature = \"crypto-ring\")]\n        return ring::RingProvider;\n        #[cfg(all(feature = \"crypto-graviola\", not(feature = \"crypto-graviola-rust\")))]\n        return graviola::GraviolaProvider;\n    }\n\n    fn to_hex(bytes: &[u8]) -> String {\n        bytes.iter().map(|b| format!(\"{:02x}\", b)).collect()\n    }\n\n    // SHA digest tests\n    #[test]\n    fn test_sha256_digest() {\n        let p = provider();\n        let mut digest = p.digest(HashAlgorithm::Sha256);\n        digest.update(b\"hello world\");\n        let result = digest.finalize();\n        assert_eq!(result.len(), 32);\n        assert_eq!(\n            to_hex(&result),\n            \"b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9\"\n        );\n    }\n\n    #[test]\n    fn test_sha384_digest() {\n        let p = provider();\n        let mut digest = p.digest(HashAlgorithm::Sha384);\n        digest.update(b\"hello world\");\n        let result = digest.finalize();\n        assert_eq!(result.len(), 48);\n    }\n\n    #[test]\n    fn test_sha512_digest() {\n        let p = provider();\n        let mut digest = p.digest(HashAlgorithm::Sha512);\n        digest.update(b\"hello world\");\n        let result = digest.finalize();\n        assert_eq!(result.len(), 64);\n    }\n\n    // HMAC tests\n    #[test]\n    fn test_hmac_sha256() {\n        let p = provider();\n        let key = b\"secret key\";\n        let mut hmac = p.hmac(HashAlgorithm::Sha256, key);\n        hmac.update(b\"hello world\");\n        let result = hmac.finalize();\n        assert_eq!(result.len(), 32);\n    }\n\n    // AES-GCM tests - only for providers that support AES\n    #[cfg(any(\n        feature = \"crypto-rust\",\n        feature = \"crypto-openssl\",\n        feature = \"crypto-ring-rust\",\n        feature = \"crypto-graviola-rust\"\n    ))]\n    #[test]\n    fn test_aes_gcm_128_roundtrip() {\n        let p = provider();\n        let key = [0u8; 16];\n        let iv = [0u8; 12];\n        let plaintext = b\"hello world\";\n        let aad = b\"additional data\";\n\n        let ciphertext = p\n            .aes_encrypt(\n                AesMode::Gcm { tag_length: 128 },\n                &key,\n                &iv,\n                plaintext,\n                Some(aad),\n            )\n            .unwrap();\n\n        assert_eq!(ciphertext.len(), plaintext.len() + 16); // plaintext + tag\n\n        let decrypted = p\n            .aes_decrypt(\n                AesMode::Gcm { tag_length: 128 },\n                &key,\n                &iv,\n                &ciphertext,\n                Some(aad),\n            )\n            .unwrap();\n\n        assert_eq!(decrypted, plaintext);\n    }\n\n    #[cfg(any(\n        feature = \"crypto-rust\",\n        feature = \"crypto-openssl\",\n        feature = \"crypto-ring-rust\",\n        feature = \"crypto-graviola-rust\"\n    ))]\n    #[test]\n    fn test_aes_gcm_256_roundtrip() {\n        let p = provider();\n        let key = [0u8; 32];\n        let iv = [0u8; 12];\n        let plaintext = b\"hello world\";\n\n        let ciphertext = p\n            .aes_encrypt(AesMode::Gcm { tag_length: 128 }, &key, &iv, plaintext, None)\n            .unwrap();\n\n        let decrypted = p\n            .aes_decrypt(\n                AesMode::Gcm { tag_length: 128 },\n                &key,\n                &iv,\n                &ciphertext,\n                None,\n            )\n            .unwrap();\n\n        assert_eq!(decrypted, plaintext);\n    }\n\n    #[cfg(any(\n        feature = \"crypto-rust\",\n        feature = \"crypto-openssl\",\n        feature = \"crypto-ring-rust\",\n        feature = \"crypto-graviola-rust\"\n    ))]\n    #[test]\n    fn test_aes_gcm_wrong_key_fails() {\n        let p = provider();\n        let key = [0u8; 16];\n        let wrong_key = [1u8; 16];\n        let iv = [0u8; 12];\n        let plaintext = b\"hello world\";\n\n        let ciphertext = p\n            .aes_encrypt(AesMode::Gcm { tag_length: 128 }, &key, &iv, plaintext, None)\n            .unwrap();\n\n        let result = p.aes_decrypt(\n            AesMode::Gcm { tag_length: 128 },\n            &wrong_key,\n            &iv,\n            &ciphertext,\n            None,\n        );\n\n        assert!(result.is_err());\n    }\n\n    // Key generation tests - only for providers that support key generation\n    #[cfg(any(\n        feature = \"crypto-rust\",\n        feature = \"crypto-openssl\",\n        feature = \"crypto-ring-rust\",\n        feature = \"crypto-graviola-rust\"\n    ))]\n    #[test]\n    fn test_generate_aes_key_128() {\n        let p = provider();\n        let key = p.generate_aes_key(128).unwrap();\n        assert_eq!(key.len(), 16);\n    }\n\n    #[cfg(any(\n        feature = \"crypto-rust\",\n        feature = \"crypto-openssl\",\n        feature = \"crypto-ring-rust\",\n        feature = \"crypto-graviola-rust\"\n    ))]\n    #[test]\n    fn test_generate_aes_key_256() {\n        let p = provider();\n        let key = p.generate_aes_key(256).unwrap();\n        assert_eq!(key.len(), 32);\n    }\n\n    #[cfg(any(\n        feature = \"crypto-rust\",\n        feature = \"crypto-openssl\",\n        feature = \"crypto-ring-rust\",\n        feature = \"crypto-graviola-rust\"\n    ))]\n    #[test]\n    fn test_generate_hmac_key() {\n        let p = provider();\n        let key = p.generate_hmac_key(HashAlgorithm::Sha256, 256).unwrap();\n        assert_eq!(key.len(), 32);\n    }\n\n    // Tests that require full crypto support\n    #[cfg(any(\n        feature = \"crypto-rust\",\n        feature = \"crypto-openssl\",\n        feature = \"crypto-ring-rust\",\n        feature = \"crypto-graviola-rust\"\n    ))]\n    mod full_provider_tests {\n        use super::*;\n\n        #[test]\n        fn test_aes_cbc_roundtrip() {\n            let p = provider();\n            let key = [0u8; 16];\n            let iv = [0u8; 16];\n            let plaintext = b\"hello world12345\"; // 16 bytes for block alignment\n\n            let ciphertext = p\n                .aes_encrypt(AesMode::Cbc, &key, &iv, plaintext, None)\n                .unwrap();\n\n            let decrypted = p\n                .aes_decrypt(AesMode::Cbc, &key, &iv, &ciphertext, None)\n                .unwrap();\n\n            assert_eq!(decrypted, plaintext);\n        }\n\n        #[test]\n        fn test_aes_ctr_roundtrip() {\n            let p = provider();\n            let key = [0u8; 16];\n            let iv = [0u8; 16];\n            let plaintext = b\"hello world\";\n\n            let ciphertext = p\n                .aes_encrypt(\n                    AesMode::Ctr { counter_length: 64 },\n                    &key,\n                    &iv,\n                    plaintext,\n                    None,\n                )\n                .unwrap();\n\n            let decrypted = p\n                .aes_decrypt(\n                    AesMode::Ctr { counter_length: 64 },\n                    &key,\n                    &iv,\n                    &ciphertext,\n                    None,\n                )\n                .unwrap();\n\n            assert_eq!(decrypted, plaintext);\n        }\n\n        #[test]\n        fn test_aes_kw_roundtrip() {\n            let p = provider();\n            let kek = [0u8; 16];\n            let key_to_wrap = [1u8; 16];\n\n            let wrapped = p.aes_kw_wrap(&kek, &key_to_wrap).unwrap();\n            let unwrapped = p.aes_kw_unwrap(&kek, &wrapped).unwrap();\n\n            assert_eq!(unwrapped, key_to_wrap);\n        }\n\n        #[test]\n        fn test_hkdf_derive() {\n            let p = provider();\n            let ikm = b\"input key material\";\n            let salt = b\"salt\";\n            let info = b\"info\";\n\n            let derived = p\n                .hkdf_derive_key(ikm, salt, info, 32, HashAlgorithm::Sha256)\n                .unwrap();\n\n            assert_eq!(derived.len(), 32);\n        }\n\n        #[test]\n        fn test_pbkdf2_derive() {\n            let p = provider();\n            let password = b\"password\";\n            let salt = b\"salt\";\n\n            let derived = p\n                .pbkdf2_derive_key(password, salt, 1000, 32, HashAlgorithm::Sha256)\n                .unwrap();\n\n            assert_eq!(derived.len(), 32);\n        }\n\n        #[test]\n        fn test_ec_p256_sign_verify() {\n            let p = provider();\n            let (private_key, public_key) = p.generate_ec_key(EllipticCurve::P256).unwrap();\n\n            // Create a digest to sign\n            let mut digest = p.digest(HashAlgorithm::Sha256);\n            digest.update(b\"message to sign\");\n            let hash = digest.finalize();\n\n            let signature = p\n                .ecdsa_sign(EllipticCurve::P256, &private_key, &hash)\n                .unwrap();\n\n            let valid = p\n                .ecdsa_verify(EllipticCurve::P256, &public_key, &signature, &hash)\n                .unwrap();\n\n            assert!(valid);\n        }\n\n        #[test]\n        fn test_ec_p384_sign_verify() {\n            let p = provider();\n            let (private_key, public_key) = p.generate_ec_key(EllipticCurve::P384).unwrap();\n\n            let mut digest = p.digest(HashAlgorithm::Sha384);\n            digest.update(b\"message to sign\");\n            let hash = digest.finalize();\n\n            let signature = p\n                .ecdsa_sign(EllipticCurve::P384, &private_key, &hash)\n                .unwrap();\n\n            let valid = p\n                .ecdsa_verify(EllipticCurve::P384, &public_key, &signature, &hash)\n                .unwrap();\n\n            assert!(valid);\n        }\n\n        #[test]\n        fn test_ed25519_sign_verify() {\n            let p = provider();\n            let (private_key, public_key) = p.generate_ed25519_key().unwrap();\n\n            let message = b\"message to sign\";\n            let signature = p.ed25519_sign(&private_key, message).unwrap();\n\n            let valid = p.ed25519_verify(&public_key, &signature, message).unwrap();\n\n            assert!(valid);\n        }\n\n        #[test]\n        fn test_x25519_key_exchange() {\n            let p = provider();\n            let (alice_private, alice_public) = p.generate_x25519_key().unwrap();\n            let (bob_private, bob_public) = p.generate_x25519_key().unwrap();\n\n            let alice_shared = p.x25519_derive_bits(&alice_private, &bob_public).unwrap();\n            let bob_shared = p.x25519_derive_bits(&bob_private, &alice_public).unwrap();\n\n            assert_eq!(alice_shared, bob_shared);\n            assert_eq!(alice_shared.len(), 32);\n        }\n\n        #[test]\n        fn test_ecdh_p256_key_exchange() {\n            let p = provider();\n            let (alice_private, alice_public) = p.generate_ec_key(EllipticCurve::P256).unwrap();\n            let (bob_private, bob_public) = p.generate_ec_key(EllipticCurve::P256).unwrap();\n\n            let alice_shared = p\n                .ecdh_derive_bits(EllipticCurve::P256, &alice_private, &bob_public)\n                .unwrap();\n            let bob_shared = p\n                .ecdh_derive_bits(EllipticCurve::P256, &bob_private, &alice_public)\n                .unwrap();\n\n            assert_eq!(alice_shared, bob_shared);\n        }\n\n        #[test]\n        fn test_rsa_pss_sign_verify() {\n            let p = provider();\n            let (private_key, public_key) = p.generate_rsa_key(2048, &[1, 0, 1]).unwrap();\n\n            let mut digest = p.digest(HashAlgorithm::Sha256);\n            digest.update(b\"message to sign\");\n            let hash = digest.finalize();\n\n            let signature = p\n                .rsa_pss_sign(&private_key, &hash, 32, HashAlgorithm::Sha256)\n                .unwrap();\n\n            let valid = p\n                .rsa_pss_verify(&public_key, &signature, &hash, 32, HashAlgorithm::Sha256)\n                .unwrap();\n\n            assert!(valid);\n        }\n\n        #[test]\n        fn test_rsa_pkcs1v15_sign_verify() {\n            let p = provider();\n            let (private_key, public_key) = p.generate_rsa_key(2048, &[1, 0, 1]).unwrap();\n\n            let mut digest = p.digest(HashAlgorithm::Sha256);\n            digest.update(b\"message to sign\");\n            let hash = digest.finalize();\n\n            let signature = p\n                .rsa_pkcs1v15_sign(&private_key, &hash, HashAlgorithm::Sha256)\n                .unwrap();\n\n            let valid = p\n                .rsa_pkcs1v15_verify(&public_key, &signature, &hash, HashAlgorithm::Sha256)\n                .unwrap();\n\n            assert!(valid);\n        }\n\n        #[test]\n        fn test_rsa_oaep_encrypt_decrypt() {\n            let p = provider();\n            let (private_key, public_key) = p.generate_rsa_key(2048, &[1, 0, 1]).unwrap();\n\n            let plaintext = b\"secret message\";\n\n            let ciphertext = p\n                .rsa_oaep_encrypt(&public_key, plaintext, HashAlgorithm::Sha256, None)\n                .unwrap();\n\n            let decrypted = p\n                .rsa_oaep_decrypt(&private_key, &ciphertext, HashAlgorithm::Sha256, None)\n                .unwrap();\n\n            assert_eq!(decrypted, plaintext);\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/provider/openssl.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\n//! OpenSSL crypto provider - uses OpenSSL for cryptographic operations.\n\nuse openssl::bn::BigNum;\nuse openssl::derive::Deriver;\nuse openssl::ec::{EcGroup, EcKey};\nuse openssl::ecdsa::EcdsaSig;\nuse openssl::hash::{Hasher, MessageDigest};\nuse openssl::md::Md;\nuse openssl::nid::Nid;\nuse openssl::pkey::{Id, PKey};\nuse openssl::pkey_ctx::PkeyCtx;\nuse openssl::rand::rand_bytes;\nuse openssl::rsa::{Padding, Rsa};\nuse openssl::sign::{Signer, Verifier};\nuse openssl::symm::{self, Cipher};\n\nuse crate::hash::HashAlgorithm;\nuse crate::provider::{AesMode, CryptoError, CryptoProvider, HmacProvider, SimpleDigest};\nuse crate::subtle::EllipticCurve;\n\npub struct OpenSslProvider;\n\npub enum OpenSslDigest {\n    Md5(Hasher),\n    Sha1(Hasher),\n    Sha256(Hasher),\n    Sha384(Hasher),\n    Sha512(Hasher),\n}\n\nimpl SimpleDigest for OpenSslDigest {\n    fn update(&mut self, data: &[u8]) {\n        match self {\n            OpenSslDigest::Md5(h)\n            | OpenSslDigest::Sha1(h)\n            | OpenSslDigest::Sha256(h)\n            | OpenSslDigest::Sha384(h)\n            | OpenSslDigest::Sha512(h) => {\n                let _ = h.update(data);\n            },\n        }\n    }\n\n    fn finalize(mut self) -> Vec<u8> {\n        match self {\n            OpenSslDigest::Md5(ref mut h)\n            | OpenSslDigest::Sha1(ref mut h)\n            | OpenSslDigest::Sha256(ref mut h)\n            | OpenSslDigest::Sha384(ref mut h)\n            | OpenSslDigest::Sha512(ref mut h) => {\n                h.finish().map(|d| d.to_vec()).unwrap_or_default()\n            },\n        }\n    }\n}\n\npub struct OpenSslHmac {\n    signer: Signer<'static>,\n}\n\nimpl HmacProvider for OpenSslHmac {\n    fn update(&mut self, data: &[u8]) {\n        let _ = self.signer.update(data);\n    }\n\n    fn finalize(self) -> Vec<u8> {\n        self.signer.sign_to_vec().unwrap_or_default()\n    }\n}\n\nfn get_message_digest(alg: HashAlgorithm) -> MessageDigest {\n    match alg {\n        HashAlgorithm::Md5 => MessageDigest::md5(),\n        HashAlgorithm::Sha1 => MessageDigest::sha1(),\n        HashAlgorithm::Sha256 => MessageDigest::sha256(),\n        HashAlgorithm::Sha384 => MessageDigest::sha384(),\n        HashAlgorithm::Sha512 => MessageDigest::sha512(),\n    }\n}\n\nfn get_md(alg: HashAlgorithm) -> &'static openssl::md::MdRef {\n    match alg {\n        HashAlgorithm::Md5 => Md::md5(),\n        HashAlgorithm::Sha1 => Md::sha1(),\n        HashAlgorithm::Sha256 => Md::sha256(),\n        HashAlgorithm::Sha384 => Md::sha384(),\n        HashAlgorithm::Sha512 => Md::sha512(),\n    }\n}\n\nfn curve_to_nid(curve: EllipticCurve) -> Nid {\n    match curve {\n        EllipticCurve::P256 => Nid::X9_62_PRIME256V1,\n        EllipticCurve::P384 => Nid::SECP384R1,\n        EllipticCurve::P521 => Nid::SECP521R1,\n    }\n}\n\nfn get_ec_group(curve: EllipticCurve) -> Result<EcGroup, CryptoError> {\n    let nid = curve_to_nid(curve);\n    EcGroup::from_curve_name(nid)\n        .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))\n}\n\nimpl CryptoProvider for OpenSslProvider {\n    type Digest = OpenSslDigest;\n    type Hmac = OpenSslHmac;\n\n    fn digest(&self, algorithm: HashAlgorithm) -> Self::Digest {\n        let md = get_message_digest(algorithm);\n        let hasher = Hasher::new(md).expect(\"Failed to create hasher\");\n        match algorithm {\n            HashAlgorithm::Md5 => OpenSslDigest::Md5(hasher),\n            HashAlgorithm::Sha1 => OpenSslDigest::Sha1(hasher),\n            HashAlgorithm::Sha256 => OpenSslDigest::Sha256(hasher),\n            HashAlgorithm::Sha384 => OpenSslDigest::Sha384(hasher),\n            HashAlgorithm::Sha512 => OpenSslDigest::Sha512(hasher),\n        }\n    }\n\n    fn hmac(&self, algorithm: HashAlgorithm, key: &[u8]) -> Self::Hmac {\n        let md = get_message_digest(algorithm);\n        let pkey = PKey::hmac(key).expect(\"Failed to create HMAC key\");\n        let signer = unsafe {\n            std::mem::transmute::<Signer<'_>, Signer<'static>>(\n                Signer::new(md, &pkey).expect(\"Failed to create signer\"),\n            )\n        };\n        OpenSslHmac { signer }\n    }\n\n    fn ecdsa_sign(\n        &self,\n        curve: EllipticCurve,\n        private_key_der: &[u8],\n        digest: &[u8],\n    ) -> Result<Vec<u8>, CryptoError> {\n        let group = get_ec_group(curve)?;\n        let ec_key = EcKey::private_key_from_der(private_key_der)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let sig = EcdsaSig::sign(digest, &ec_key)\n            .map_err(|e| CryptoError::SigningFailed(Some(e.to_string().into())))?;\n        let r = sig.r().to_vec();\n        let s = sig.s().to_vec();\n        let coord_len = (group.degree() as usize).div_ceil(8);\n        let mut result = vec![0u8; coord_len * 2];\n        result[coord_len - r.len()..coord_len].copy_from_slice(&r);\n        result[coord_len * 2 - s.len()..].copy_from_slice(&s);\n        Ok(result)\n    }\n\n    fn ecdsa_verify(\n        &self,\n        curve: EllipticCurve,\n        public_key_sec1: &[u8],\n        signature: &[u8],\n        digest: &[u8],\n    ) -> Result<bool, CryptoError> {\n        let group = get_ec_group(curve)?;\n        let ec_key = EcKey::public_key_from_der(public_key_sec1).or_else(|_| {\n            let point = openssl::ec::EcPoint::from_bytes(\n                &group,\n                public_key_sec1,\n                &mut openssl::bn::BigNumContext::new().unwrap(),\n            )\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            EcKey::from_public_key(&group, &point)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))\n        })?;\n        let coord_len = signature.len() / 2;\n        let r = BigNum::from_slice(&signature[..coord_len])\n            .map_err(|e| CryptoError::InvalidSignature(Some(e.to_string().into())))?;\n        let s = BigNum::from_slice(&signature[coord_len..])\n            .map_err(|e| CryptoError::InvalidSignature(Some(e.to_string().into())))?;\n        let sig = EcdsaSig::from_private_components(r, s)\n            .map_err(|e| CryptoError::InvalidSignature(Some(e.to_string().into())))?;\n        Ok(sig.verify(digest, &ec_key).unwrap_or(false))\n    }\n\n    fn ed25519_sign(&self, private_key_der: &[u8], data: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        let pkey = PKey::private_key_from_der(private_key_der)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let mut signer = Signer::new_without_digest(&pkey)\n            .map_err(|e| CryptoError::SigningFailed(Some(e.to_string().into())))?;\n        signer\n            .sign_oneshot_to_vec(data)\n            .map_err(|e| CryptoError::SigningFailed(Some(e.to_string().into())))\n    }\n\n    fn ed25519_verify(\n        &self,\n        public_key_bytes: &[u8],\n        signature: &[u8],\n        data: &[u8],\n    ) -> Result<bool, CryptoError> {\n        let pkey = PKey::public_key_from_raw_bytes(public_key_bytes, Id::ED25519)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let mut verifier = Verifier::new_without_digest(&pkey)\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        Ok(verifier.verify_oneshot(signature, data).unwrap_or(false))\n    }\n\n    fn rsa_pss_sign(\n        &self,\n        private_key_der: &[u8],\n        digest: &[u8],\n        salt_length: usize,\n        hash_alg: HashAlgorithm,\n    ) -> Result<Vec<u8>, CryptoError> {\n        let rsa = Rsa::private_key_from_der(private_key_der)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let pkey =\n            PKey::from_rsa(rsa).map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let md = get_message_digest(hash_alg);\n        let mut signer = Signer::new(md, &pkey)\n            .map_err(|e| CryptoError::SigningFailed(Some(e.to_string().into())))?;\n        signer\n            .set_rsa_padding(Padding::PKCS1_PSS)\n            .map_err(|e| CryptoError::SigningFailed(Some(e.to_string().into())))?;\n        signer\n            .set_rsa_pss_saltlen(openssl::sign::RsaPssSaltlen::custom(salt_length as i32))\n            .map_err(|e| CryptoError::SigningFailed(Some(e.to_string().into())))?;\n        signer\n            .set_rsa_mgf1_md(md)\n            .map_err(|e| CryptoError::SigningFailed(Some(e.to_string().into())))?;\n        signer\n            .update(digest)\n            .map_err(|e| CryptoError::SigningFailed(Some(e.to_string().into())))?;\n        signer\n            .sign_to_vec()\n            .map_err(|e| CryptoError::SigningFailed(Some(e.to_string().into())))\n    }\n\n    fn rsa_pss_verify(\n        &self,\n        public_key_der: &[u8],\n        signature: &[u8],\n        digest: &[u8],\n        salt_length: usize,\n        hash_alg: HashAlgorithm,\n    ) -> Result<bool, CryptoError> {\n        let rsa = Rsa::public_key_from_der(public_key_der)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let pkey =\n            PKey::from_rsa(rsa).map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let md = get_message_digest(hash_alg);\n        let mut verifier = Verifier::new(md, &pkey)\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        verifier\n            .set_rsa_padding(Padding::PKCS1_PSS)\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        verifier\n            .set_rsa_pss_saltlen(openssl::sign::RsaPssSaltlen::custom(salt_length as i32))\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        verifier\n            .set_rsa_mgf1_md(md)\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        verifier\n            .update(digest)\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        Ok(verifier.verify(signature).unwrap_or(false))\n    }\n\n    fn rsa_pkcs1v15_sign(\n        &self,\n        private_key_der: &[u8],\n        digest: &[u8],\n        hash_alg: HashAlgorithm,\n    ) -> Result<Vec<u8>, CryptoError> {\n        let rsa = Rsa::private_key_from_der(private_key_der)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let pkey =\n            PKey::from_rsa(rsa).map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let md = get_message_digest(hash_alg);\n        let mut signer = Signer::new(md, &pkey)\n            .map_err(|e| CryptoError::SigningFailed(Some(e.to_string().into())))?;\n        signer\n            .set_rsa_padding(Padding::PKCS1)\n            .map_err(|e| CryptoError::SigningFailed(Some(e.to_string().into())))?;\n        signer\n            .update(digest)\n            .map_err(|e| CryptoError::SigningFailed(Some(e.to_string().into())))?;\n        signer\n            .sign_to_vec()\n            .map_err(|e| CryptoError::SigningFailed(Some(e.to_string().into())))\n    }\n\n    fn rsa_pkcs1v15_verify(\n        &self,\n        public_key_der: &[u8],\n        signature: &[u8],\n        digest: &[u8],\n        hash_alg: HashAlgorithm,\n    ) -> Result<bool, CryptoError> {\n        let rsa = Rsa::public_key_from_der(public_key_der)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let pkey =\n            PKey::from_rsa(rsa).map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let md = get_message_digest(hash_alg);\n        let mut verifier = Verifier::new(md, &pkey)\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        verifier\n            .set_rsa_padding(Padding::PKCS1)\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        verifier\n            .update(digest)\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        Ok(verifier.verify(signature).unwrap_or(false))\n    }\n\n    fn rsa_oaep_encrypt(\n        &self,\n        public_key_der: &[u8],\n        data: &[u8],\n        hash_alg: HashAlgorithm,\n        label: Option<&[u8]>,\n    ) -> Result<Vec<u8>, CryptoError> {\n        let rsa = Rsa::public_key_from_der(public_key_der)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let pkey =\n            PKey::from_rsa(rsa).map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let mut ctx = PkeyCtx::new(&pkey)\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        ctx.encrypt_init()\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        ctx.set_rsa_padding(Padding::PKCS1_OAEP)\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        ctx.set_rsa_oaep_md(get_md(hash_alg))\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        ctx.set_rsa_mgf1_md(get_md(hash_alg))\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        if let Some(lbl) = label {\n            ctx.set_rsa_oaep_label(lbl)\n                .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        }\n        let mut out = vec![0u8; pkey.size()];\n        let len = ctx\n            .encrypt(data, Some(&mut out))\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        out.truncate(len);\n        Ok(out)\n    }\n\n    fn rsa_oaep_decrypt(\n        &self,\n        private_key_der: &[u8],\n        data: &[u8],\n        hash_alg: HashAlgorithm,\n        label: Option<&[u8]>,\n    ) -> Result<Vec<u8>, CryptoError> {\n        let rsa = Rsa::private_key_from_der(private_key_der)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let pkey =\n            PKey::from_rsa(rsa).map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let mut ctx = PkeyCtx::new(&pkey)\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        ctx.decrypt_init()\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        ctx.set_rsa_padding(Padding::PKCS1_OAEP)\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        ctx.set_rsa_oaep_md(get_md(hash_alg))\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        ctx.set_rsa_mgf1_md(get_md(hash_alg))\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        if let Some(lbl) = label {\n            ctx.set_rsa_oaep_label(lbl)\n                .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        }\n        let mut out = vec![0u8; pkey.size()];\n        let len = ctx\n            .decrypt(data, Some(&mut out))\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        out.truncate(len);\n        Ok(out)\n    }\n\n    fn ecdh_derive_bits(\n        &self,\n        curve: EllipticCurve,\n        private_key_der: &[u8],\n        public_key_sec1: &[u8],\n    ) -> Result<Vec<u8>, CryptoError> {\n        let group = get_ec_group(curve)?;\n        let private_ec = EcKey::private_key_from_der(private_key_der)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let private_pkey = PKey::from_ec_key(private_ec)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let public_ec = EcKey::public_key_from_der(public_key_sec1).or_else(|_| {\n            let point = openssl::ec::EcPoint::from_bytes(\n                &group,\n                public_key_sec1,\n                &mut openssl::bn::BigNumContext::new().unwrap(),\n            )\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            EcKey::from_public_key(&group, &point)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))\n        })?;\n        let public_pkey = PKey::from_ec_key(public_ec)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let mut deriver = Deriver::new(&private_pkey)\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        deriver\n            .set_peer(&public_pkey)\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        deriver\n            .derive_to_vec()\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))\n    }\n\n    fn x25519_derive_bits(\n        &self,\n        private_key: &[u8],\n        public_key: &[u8],\n    ) -> Result<Vec<u8>, CryptoError> {\n        let private_pkey = PKey::private_key_from_raw_bytes(private_key, Id::X25519)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let public_pkey = PKey::public_key_from_raw_bytes(public_key, Id::X25519)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let mut deriver = Deriver::new(&private_pkey)\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        deriver\n            .set_peer(&public_pkey)\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        deriver\n            .derive_to_vec()\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))\n    }\n\n    fn aes_encrypt(\n        &self,\n        mode: AesMode,\n        key: &[u8],\n        iv: &[u8],\n        data: &[u8],\n        additional_data: Option<&[u8]>,\n    ) -> Result<Vec<u8>, CryptoError> {\n        match mode {\n            AesMode::Cbc => {\n                let cipher = match key.len() {\n                    16 => Cipher::aes_128_cbc(),\n                    24 => Cipher::aes_192_cbc(),\n                    32 => Cipher::aes_256_cbc(),\n                    _ => {\n                        return Err(CryptoError::InvalidKey(Some(\n                            \"Invalid AES key length\".into(),\n                        )))\n                    },\n                };\n                symm::encrypt(cipher, key, Some(iv), data)\n                    .map_err(|e| CryptoError::EncryptionFailed(Some(e.to_string().into())))\n            },\n            AesMode::Ctr { .. } => {\n                let cipher = match key.len() {\n                    16 => Cipher::aes_128_ctr(),\n                    24 => Cipher::aes_192_ctr(),\n                    32 => Cipher::aes_256_ctr(),\n                    _ => {\n                        return Err(CryptoError::InvalidKey(Some(\n                            \"Invalid AES key length\".into(),\n                        )))\n                    },\n                };\n                symm::encrypt(cipher, key, Some(iv), data)\n                    .map_err(|e| CryptoError::EncryptionFailed(Some(e.to_string().into())))\n            },\n            AesMode::Gcm { tag_length } => {\n                let cipher = match key.len() {\n                    16 => Cipher::aes_128_gcm(),\n                    24 => Cipher::aes_192_gcm(),\n                    32 => Cipher::aes_256_gcm(),\n                    _ => {\n                        return Err(CryptoError::InvalidKey(Some(\n                            \"Invalid AES key length\".into(),\n                        )))\n                    },\n                };\n                let tag_len = (tag_length / 8) as usize;\n                let mut tag = vec![0u8; tag_len];\n                let ciphertext = symm::encrypt_aead(\n                    cipher,\n                    key,\n                    Some(iv),\n                    additional_data.unwrap_or(&[]),\n                    data,\n                    &mut tag,\n                )\n                .map_err(|e| CryptoError::EncryptionFailed(Some(e.to_string().into())))?;\n                let mut result = ciphertext;\n                result.extend_from_slice(&tag);\n                Ok(result)\n            },\n        }\n    }\n\n    fn aes_decrypt(\n        &self,\n        mode: AesMode,\n        key: &[u8],\n        iv: &[u8],\n        data: &[u8],\n        additional_data: Option<&[u8]>,\n    ) -> Result<Vec<u8>, CryptoError> {\n        match mode {\n            AesMode::Cbc => {\n                let cipher = match key.len() {\n                    16 => Cipher::aes_128_cbc(),\n                    24 => Cipher::aes_192_cbc(),\n                    32 => Cipher::aes_256_cbc(),\n                    _ => {\n                        return Err(CryptoError::InvalidKey(Some(\n                            \"Invalid AES key length\".into(),\n                        )))\n                    },\n                };\n                symm::decrypt(cipher, key, Some(iv), data)\n                    .map_err(|e| CryptoError::DecryptionFailed(Some(e.to_string().into())))\n            },\n            AesMode::Ctr { .. } => {\n                let cipher = match key.len() {\n                    16 => Cipher::aes_128_ctr(),\n                    24 => Cipher::aes_192_ctr(),\n                    32 => Cipher::aes_256_ctr(),\n                    _ => {\n                        return Err(CryptoError::InvalidKey(Some(\n                            \"Invalid AES key length\".into(),\n                        )))\n                    },\n                };\n                symm::decrypt(cipher, key, Some(iv), data)\n                    .map_err(|e| CryptoError::DecryptionFailed(Some(e.to_string().into())))\n            },\n            AesMode::Gcm { tag_length } => {\n                let cipher = match key.len() {\n                    16 => Cipher::aes_128_gcm(),\n                    24 => Cipher::aes_192_gcm(),\n                    32 => Cipher::aes_256_gcm(),\n                    _ => {\n                        return Err(CryptoError::InvalidKey(Some(\n                            \"Invalid AES key length\".into(),\n                        )))\n                    },\n                };\n                let tag_len = (tag_length / 8) as usize;\n                if data.len() < tag_len {\n                    return Err(CryptoError::InvalidData(Some(\n                        \"Data too short for GCM tag\".into(),\n                    )));\n                }\n                let (ciphertext, tag) = data.split_at(data.len() - tag_len);\n                symm::decrypt_aead(\n                    cipher,\n                    key,\n                    Some(iv),\n                    additional_data.unwrap_or(&[]),\n                    ciphertext,\n                    tag,\n                )\n                .map_err(|e| CryptoError::DecryptionFailed(Some(e.to_string().into())))\n            },\n        }\n    }\n\n    fn aes_kw_wrap(&self, kek: &[u8], key: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        use openssl::aes::{wrap_key, AesKey};\n        let aes_key = AesKey::new_encrypt(kek).map_err(|_| CryptoError::InvalidKey(None))?;\n        let mut out = vec![0u8; key.len() + 8];\n        wrap_key(&aes_key, None, &mut out, key).map_err(|_| CryptoError::OperationFailed(None))?;\n        Ok(out)\n    }\n\n    fn aes_kw_unwrap(&self, kek: &[u8], wrapped_key: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        use openssl::aes::{unwrap_key, AesKey};\n        let aes_key = AesKey::new_decrypt(kek).map_err(|_| CryptoError::InvalidKey(None))?;\n        let mut out = vec![0u8; wrapped_key.len() - 8];\n        unwrap_key(&aes_key, None, &mut out, wrapped_key)\n            .map_err(|_| CryptoError::OperationFailed(None))?;\n        Ok(out)\n    }\n\n    fn hkdf_derive_key(\n        &self,\n        key: &[u8],\n        salt: &[u8],\n        info: &[u8],\n        length: usize,\n        hash_alg: HashAlgorithm,\n    ) -> Result<Vec<u8>, CryptoError> {\n        use openssl::pkey_ctx::HkdfMode;\n        let md = get_md(hash_alg);\n        let mut ctx = PkeyCtx::new_id(Id::HKDF)\n            .map_err(|e| CryptoError::DerivationFailed(Some(e.to_string().into())))?;\n        ctx.derive_init()\n            .map_err(|e| CryptoError::DerivationFailed(Some(e.to_string().into())))?;\n        ctx.set_hkdf_md(md)\n            .map_err(|e| CryptoError::DerivationFailed(Some(e.to_string().into())))?;\n        ctx.set_hkdf_mode(HkdfMode::EXTRACT_THEN_EXPAND)\n            .map_err(|e| CryptoError::DerivationFailed(Some(e.to_string().into())))?;\n        ctx.set_hkdf_key(key)\n            .map_err(|e| CryptoError::DerivationFailed(Some(e.to_string().into())))?;\n        if !salt.is_empty() {\n            ctx.set_hkdf_salt(salt)\n                .map_err(|e| CryptoError::DerivationFailed(Some(e.to_string().into())))?;\n        }\n        if !info.is_empty() {\n            ctx.add_hkdf_info(info)\n                .map_err(|e| CryptoError::DerivationFailed(Some(e.to_string().into())))?;\n        }\n        let mut out = vec![0u8; length];\n        ctx.derive(Some(&mut out))\n            .map_err(|e| CryptoError::DerivationFailed(Some(e.to_string().into())))?;\n        Ok(out)\n    }\n\n    fn pbkdf2_derive_key(\n        &self,\n        password: &[u8],\n        salt: &[u8],\n        iterations: u32,\n        length: usize,\n        hash_alg: HashAlgorithm,\n    ) -> Result<Vec<u8>, CryptoError> {\n        let md = get_message_digest(hash_alg);\n        let mut out = vec![0u8; length];\n        openssl::pkcs5::pbkdf2_hmac(password, salt, iterations as usize, md, &mut out)\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        Ok(out)\n    }\n\n    fn generate_aes_key(&self, length_bits: u16) -> Result<Vec<u8>, CryptoError> {\n        let length_bytes = (length_bits / 8) as usize;\n        let mut key = vec![0u8; length_bytes];\n        rand_bytes(&mut key)\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        Ok(key)\n    }\n\n    fn generate_hmac_key(\n        &self,\n        hash_alg: HashAlgorithm,\n        length_bits: u16,\n    ) -> Result<Vec<u8>, CryptoError> {\n        let length_bytes = if length_bits == 0 {\n            match hash_alg {\n                HashAlgorithm::Md5 => 16,\n                HashAlgorithm::Sha1 => 20,\n                HashAlgorithm::Sha256 => 32,\n                HashAlgorithm::Sha384 => 48,\n                HashAlgorithm::Sha512 => 64,\n            }\n        } else {\n            (length_bits / 8) as usize\n        };\n        let mut key = vec![0u8; length_bytes];\n        rand_bytes(&mut key)\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        Ok(key)\n    }\n\n    fn generate_ec_key(&self, curve: EllipticCurve) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {\n        let group = get_ec_group(curve)?;\n        let ec_key = EcKey::generate(&group)\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        let pkey = PKey::from_ec_key(ec_key.clone())\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        // Return PKCS#8 DER for private key (consistent with RustCrypto)\n        let private_der = pkey\n            .private_key_to_der()\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        // Return SEC1 uncompressed point for public key (consistent with RustCrypto)\n        let mut bn_ctx = openssl::bn::BigNumContext::new()\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        let public_sec1 = ec_key\n            .public_key()\n            .to_bytes(\n                &group,\n                openssl::ec::PointConversionForm::UNCOMPRESSED,\n                &mut bn_ctx,\n            )\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        Ok((private_der, public_sec1))\n    }\n\n    fn generate_ed25519_key(&self) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {\n        let pkey = PKey::generate_ed25519()\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        let private_der = pkey\n            .private_key_to_der()\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        let public_raw = pkey\n            .raw_public_key()\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        Ok((private_der, public_raw))\n    }\n\n    fn generate_x25519_key(&self) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {\n        let pkey = PKey::generate_x25519()\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        let private_raw = pkey\n            .raw_private_key()\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        let public_raw = pkey\n            .raw_public_key()\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        Ok((private_raw, public_raw))\n    }\n\n    fn generate_rsa_key(\n        &self,\n        modulus_length: u32,\n        public_exponent: &[u8],\n    ) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {\n        let exp = BigNum::from_slice(public_exponent)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let rsa = Rsa::generate_with_e(modulus_length, &exp)\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        let private_der = rsa\n            .private_key_to_der()\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        let public_der = rsa\n            .public_key_to_der()\n            .map_err(|e| CryptoError::OperationFailed(Some(e.to_string().into())))?;\n        Ok((private_der, public_der))\n    }\n\n    fn import_rsa_public_key_pkcs1(\n        &self,\n        der: &[u8],\n    ) -> Result<super::RsaImportResult, CryptoError> {\n        let rsa = Rsa::public_key_from_der(der)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let modulus_length = rsa.n().num_bits() as u32;\n        let public_exponent = rsa.e().to_vec();\n        let key_data = rsa\n            .public_key_to_der()\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        Ok(super::RsaImportResult {\n            key_data,\n            modulus_length,\n            public_exponent,\n            is_private: false,\n        })\n    }\n\n    fn import_rsa_private_key_pkcs1(\n        &self,\n        der: &[u8],\n    ) -> Result<super::RsaImportResult, CryptoError> {\n        let rsa = Rsa::private_key_from_der(der)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let modulus_length = rsa.n().num_bits() as u32;\n        let public_exponent = rsa.e().to_vec();\n        let key_data = rsa\n            .private_key_to_der()\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        Ok(super::RsaImportResult {\n            key_data,\n            modulus_length,\n            public_exponent,\n            is_private: true,\n        })\n    }\n\n    fn import_rsa_public_key_spki(\n        &self,\n        der: &[u8],\n    ) -> Result<super::RsaImportResult, CryptoError> {\n        let pkey = PKey::public_key_from_der(der)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let rsa = pkey\n            .rsa()\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let modulus_length = rsa.n().num_bits() as u32;\n        let public_exponent = rsa.e().to_vec();\n        let key_data = rsa\n            .public_key_to_der()\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        Ok(super::RsaImportResult {\n            key_data,\n            modulus_length,\n            public_exponent,\n            is_private: false,\n        })\n    }\n\n    fn import_rsa_private_key_pkcs8(\n        &self,\n        der: &[u8],\n    ) -> Result<super::RsaImportResult, CryptoError> {\n        let pkey = PKey::private_key_from_der(der)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let rsa = pkey\n            .rsa()\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let modulus_length = rsa.n().num_bits() as u32;\n        let public_exponent = rsa.e().to_vec();\n        let key_data = rsa\n            .private_key_to_der()\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        Ok(super::RsaImportResult {\n            key_data,\n            modulus_length,\n            public_exponent,\n            is_private: true,\n        })\n    }\n\n    fn export_rsa_public_key_pkcs1(&self, key_data: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        let rsa = Rsa::public_key_from_der(key_data)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        rsa.public_key_to_der()\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))\n    }\n\n    fn export_rsa_public_key_spki(&self, key_data: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        let rsa = Rsa::public_key_from_der(key_data)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let pkey =\n            PKey::from_rsa(rsa).map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        pkey.public_key_to_der()\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))\n    }\n\n    fn export_rsa_private_key_pkcs8(&self, key_data: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        let rsa = Rsa::private_key_from_der(key_data)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let pkey =\n            PKey::from_rsa(rsa).map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        pkey.private_key_to_der()\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))\n    }\n\n    fn import_ec_public_key_sec1(\n        &self,\n        data: &[u8],\n        curve: EllipticCurve,\n    ) -> Result<super::EcImportResult, CryptoError> {\n        let nid = curve_to_nid(curve);\n        let group = EcGroup::from_curve_name(nid)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let mut ctx = openssl::bn::BigNumContext::new()\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let point = openssl::ec::EcPoint::from_bytes(&group, data, &mut ctx)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let ec_key = EcKey::from_public_key(&group, &point)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let pkey = PKey::from_ec_key(ec_key)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        Ok(super::EcImportResult {\n            key_data: pkey\n                .public_key_to_der()\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?,\n            is_private: false,\n        })\n    }\n\n    fn import_ec_public_key_spki(&self, der: &[u8]) -> Result<super::EcImportResult, CryptoError> {\n        let pkey = PKey::public_key_from_der(der)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        Ok(super::EcImportResult {\n            key_data: pkey\n                .public_key_to_der()\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?,\n            is_private: false,\n        })\n    }\n\n    fn import_ec_private_key_pkcs8(\n        &self,\n        der: &[u8],\n    ) -> Result<super::EcImportResult, CryptoError> {\n        let pkey = PKey::private_key_from_der(der)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        Ok(super::EcImportResult {\n            key_data: pkey\n                .private_key_to_der()\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?,\n            is_private: true,\n        })\n    }\n\n    fn import_ec_private_key_sec1(\n        &self,\n        data: &[u8],\n        curve: EllipticCurve,\n    ) -> Result<super::EcImportResult, CryptoError> {\n        let nid = curve_to_nid(curve);\n        let group = EcGroup::from_curve_name(nid)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let bn = BigNum::from_slice(data)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let ec_key = EcKey::from_private_components(&group, &bn, group.generator())\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let pkey = PKey::from_ec_key(ec_key)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        Ok(super::EcImportResult {\n            key_data: pkey\n                .private_key_to_der()\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?,\n            is_private: true,\n        })\n    }\n\n    fn export_ec_public_key_sec1(\n        &self,\n        key_data: &[u8],\n        _curve: EllipticCurve,\n        is_private: bool,\n    ) -> Result<Vec<u8>, CryptoError> {\n        let mut ctx = openssl::bn::BigNumContext::new()\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        if is_private {\n            let ec_key = PKey::private_key_from_der(key_data)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?\n                .ec_key()\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            ec_key\n                .public_key()\n                .to_bytes(\n                    ec_key.group(),\n                    openssl::ec::PointConversionForm::UNCOMPRESSED,\n                    &mut ctx,\n                )\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))\n        } else {\n            let ec_key = PKey::public_key_from_der(key_data)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?\n                .ec_key()\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            ec_key\n                .public_key()\n                .to_bytes(\n                    ec_key.group(),\n                    openssl::ec::PointConversionForm::UNCOMPRESSED,\n                    &mut ctx,\n                )\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))\n        }\n    }\n\n    fn export_ec_public_key_spki(\n        &self,\n        key_data: &[u8],\n        _curve: EllipticCurve,\n    ) -> Result<Vec<u8>, CryptoError> {\n        let pkey = PKey::public_key_from_der(key_data)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        pkey.public_key_to_der()\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))\n    }\n\n    fn export_ec_private_key_pkcs8(\n        &self,\n        key_data: &[u8],\n        _curve: EllipticCurve,\n    ) -> Result<Vec<u8>, CryptoError> {\n        let pkey = PKey::private_key_from_der(key_data)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        pkey.private_key_to_der()\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))\n    }\n\n    fn import_okp_public_key_raw(\n        &self,\n        data: &[u8],\n    ) -> Result<super::OkpImportResult, CryptoError> {\n        if data.len() != 32 {\n            return Err(CryptoError::InvalidKey(None));\n        }\n        Ok(super::OkpImportResult {\n            key_data: data.to_vec(),\n            is_private: false,\n        })\n    }\n\n    fn import_okp_public_key_spki(\n        &self,\n        der: &[u8],\n        _expected_oid: &[u8],\n    ) -> Result<super::OkpImportResult, CryptoError> {\n        let pkey = PKey::public_key_from_der(der)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let raw = pkey\n            .raw_public_key()\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        Ok(super::OkpImportResult {\n            key_data: raw,\n            is_private: false,\n        })\n    }\n\n    fn import_okp_private_key_pkcs8(\n        &self,\n        der: &[u8],\n        _expected_oid: &[u8],\n    ) -> Result<super::OkpImportResult, CryptoError> {\n        Ok(super::OkpImportResult {\n            key_data: der.to_vec(),\n            is_private: true,\n        })\n    }\n\n    fn export_okp_public_key_raw(\n        &self,\n        key_data: &[u8],\n        is_private: bool,\n    ) -> Result<Vec<u8>, CryptoError> {\n        if is_private {\n            let pkey = PKey::private_key_from_der(key_data)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            pkey.raw_public_key()\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))\n        } else {\n            Ok(key_data.to_vec())\n        }\n    }\n\n    fn export_okp_public_key_spki(\n        &self,\n        key_data: &[u8],\n        _oid: &[u8],\n    ) -> Result<Vec<u8>, CryptoError> {\n        // key_data is raw public key, need to wrap in SPKI\n        let pkey = PKey::public_key_from_raw_bytes(key_data, Id::ED25519)\n            .or_else(|_| PKey::public_key_from_raw_bytes(key_data, Id::X25519))\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        pkey.public_key_to_der()\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))\n    }\n\n    fn export_okp_private_key_pkcs8(\n        &self,\n        key_data: &[u8],\n        _oid: &[u8],\n    ) -> Result<Vec<u8>, CryptoError> {\n        // key_data is already PKCS8\n        Ok(key_data.to_vec())\n    }\n\n    fn import_rsa_jwk(\n        &self,\n        jwk: super::RsaJwkImport<'_>,\n    ) -> Result<super::RsaImportResult, CryptoError> {\n        let n = BigNum::from_slice(jwk.n)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let e = BigNum::from_slice(jwk.e)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let modulus_length = n.num_bits() as u32;\n        let pub_exp_bytes = jwk.e.to_vec();\n\n        if let (\n            Some(d_bytes),\n            Some(p_bytes),\n            Some(q_bytes),\n            Some(dp_bytes),\n            Some(dq_bytes),\n            Some(qi_bytes),\n        ) = (jwk.d, jwk.p, jwk.q, jwk.dp, jwk.dq, jwk.qi)\n        {\n            let d = BigNum::from_slice(d_bytes)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            let p = BigNum::from_slice(p_bytes)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            let q = BigNum::from_slice(q_bytes)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            let dp = BigNum::from_slice(dp_bytes)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            let dq = BigNum::from_slice(dq_bytes)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            let qi = BigNum::from_slice(qi_bytes)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n\n            let rsa = Rsa::from_private_components(n, e, d, p, q, dp, dq, qi)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            let pkey = PKey::from_rsa(rsa)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            Ok(super::RsaImportResult {\n                key_data: pkey\n                    .private_key_to_der()\n                    .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?,\n                modulus_length,\n                public_exponent: pub_exp_bytes,\n                is_private: true,\n            })\n        } else {\n            let rsa = Rsa::from_public_components(n, e)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            let pkey = PKey::from_rsa(rsa)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            Ok(super::RsaImportResult {\n                key_data: pkey\n                    .public_key_to_der()\n                    .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?,\n                modulus_length,\n                public_exponent: pub_exp_bytes,\n                is_private: false,\n            })\n        }\n    }\n\n    fn export_rsa_jwk(\n        &self,\n        key_data: &[u8],\n        is_private: bool,\n    ) -> Result<super::RsaJwkExport, CryptoError> {\n        if is_private {\n            let pkey = PKey::private_key_from_der(key_data)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            let rsa = pkey\n                .rsa()\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            Ok(super::RsaJwkExport {\n                n: rsa.n().to_vec(),\n                e: rsa.e().to_vec(),\n                d: Some(rsa.d().to_vec()),\n                p: rsa.p().map(|v| v.to_vec()),\n                q: rsa.q().map(|v| v.to_vec()),\n                dp: rsa.dmp1().map(|v| v.to_vec()),\n                dq: rsa.dmq1().map(|v| v.to_vec()),\n                qi: rsa.iqmp().map(|v| v.to_vec()),\n            })\n        } else {\n            let pkey = PKey::public_key_from_der(key_data)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            let rsa = pkey\n                .rsa()\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            Ok(super::RsaJwkExport {\n                n: rsa.n().to_vec(),\n                e: rsa.e().to_vec(),\n                d: None,\n                p: None,\n                q: None,\n                dp: None,\n                dq: None,\n                qi: None,\n            })\n        }\n    }\n\n    fn import_ec_jwk(\n        &self,\n        jwk: super::EcJwkImport<'_>,\n        curve: EllipticCurve,\n    ) -> Result<super::EcImportResult, CryptoError> {\n        let nid = curve_to_nid(curve);\n        let group = EcGroup::from_curve_name(nid)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let x = BigNum::from_slice(jwk.x)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let y = BigNum::from_slice(jwk.y)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let pub_key = EcKey::from_public_key_affine_coordinates(&group, &x, &y)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n\n        if let Some(d_bytes) = jwk.d {\n            let d = BigNum::from_slice(d_bytes)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            let priv_key = EcKey::from_private_components(&group, &d, pub_key.public_key())\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            let pkey = PKey::from_ec_key(priv_key)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            Ok(super::EcImportResult {\n                key_data: pkey\n                    .private_key_to_der()\n                    .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?,\n                is_private: true,\n            })\n        } else {\n            // Return SEC1 uncompressed point for public key (consistent with generate_ec_key)\n            let mut ctx = openssl::bn::BigNumContext::new()\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            let sec1 = pub_key\n                .public_key()\n                .to_bytes(\n                    &group,\n                    openssl::ec::PointConversionForm::UNCOMPRESSED,\n                    &mut ctx,\n                )\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            Ok(super::EcImportResult {\n                key_data: sec1,\n                is_private: false,\n            })\n        }\n    }\n\n    fn export_ec_jwk(\n        &self,\n        key_data: &[u8],\n        curve: EllipticCurve,\n        is_private: bool,\n    ) -> Result<super::EcJwkExport, CryptoError> {\n        let nid = curve_to_nid(curve);\n        let group = EcGroup::from_curve_name(nid)\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n        let mut ctx = openssl::bn::BigNumContext::new()\n            .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n\n        if is_private {\n            let pkey = PKey::private_key_from_der(key_data)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            let ec_key = pkey\n                .ec_key()\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            let mut x =\n                BigNum::new().map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            let mut y =\n                BigNum::new().map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            ec_key\n                .public_key()\n                .affine_coordinates(&group, &mut x, &mut y, &mut ctx)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            Ok(super::EcJwkExport {\n                x: x.to_vec(),\n                y: y.to_vec(),\n                d: Some(ec_key.private_key().to_vec()),\n            })\n        } else {\n            // key_data is SEC1 uncompressed point (0x04 || x || y)\n            let coord_len = match curve {\n                EllipticCurve::P256 => 32,\n                EllipticCurve::P384 => 48,\n                EllipticCurve::P521 => 66,\n            };\n            if key_data.len() != 1 + 2 * coord_len || key_data[0] != 0x04 {\n                return Err(CryptoError::InvalidKey(None));\n            }\n            let x = key_data[1..1 + coord_len].to_vec();\n            let y = key_data[1 + coord_len..].to_vec();\n            Ok(super::EcJwkExport { x, y, d: None })\n        }\n    }\n\n    fn import_okp_jwk(\n        &self,\n        jwk: super::OkpJwkImport<'_>,\n        is_ed25519: bool,\n    ) -> Result<super::OkpImportResult, CryptoError> {\n        let id = if is_ed25519 { Id::ED25519 } else { Id::X25519 };\n        if let Some(d) = jwk.d {\n            // Private key\n            let pkey = PKey::private_key_from_raw_bytes(d, id)\n                .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n            if is_ed25519 {\n                // Ed25519: return PKCS8 DER\n                Ok(super::OkpImportResult {\n                    key_data: pkey\n                        .private_key_to_der()\n                        .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?,\n                    is_private: true,\n                })\n            } else {\n                // X25519: return raw bytes\n                Ok(super::OkpImportResult {\n                    key_data: d.to_vec(),\n                    is_private: true,\n                })\n            }\n        } else {\n            // Public key - store raw bytes\n            Ok(super::OkpImportResult {\n                key_data: jwk.x.to_vec(),\n                is_private: false,\n            })\n        }\n    }\n\n    fn export_okp_jwk(\n        &self,\n        key_data: &[u8],\n        is_private: bool,\n        is_ed25519: bool,\n    ) -> Result<super::OkpJwkExport, CryptoError> {\n        if is_private {\n            if is_ed25519 {\n                // Ed25519: key_data is PKCS8 DER\n                let pkey = PKey::private_key_from_der(key_data)\n                    .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n                let d = pkey\n                    .raw_private_key()\n                    .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n                let x = pkey\n                    .raw_public_key()\n                    .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n                Ok(super::OkpJwkExport { x, d: Some(d) })\n            } else {\n                // X25519: key_data is raw 32-byte secret\n                let pkey = PKey::private_key_from_raw_bytes(key_data, Id::X25519)\n                    .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n                let x = pkey\n                    .raw_public_key()\n                    .map_err(|e| CryptoError::InvalidKey(Some(e.to_string().into())))?;\n                Ok(super::OkpJwkExport {\n                    x,\n                    d: Some(key_data.to_vec()),\n                })\n            }\n        } else {\n            // Public key - key_data is raw bytes\n            Ok(super::OkpJwkExport {\n                x: key_data.to_vec(),\n                d: None,\n            })\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/provider/ring.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nuse crate::hash::HashAlgorithm;\nuse crate::provider::{AesMode, CryptoError, CryptoProvider, HmacProvider, SimpleDigest};\nuse crate::subtle::EllipticCurve;\nuse md5::{Digest, Md5 as Md5Hasher};\nuse ring::{digest, hmac};\n\npub struct RingProvider;\n\npub enum RingDigestType {\n    Sha1(RingDigest),\n    Sha256(RingDigest),\n    Sha384(RingDigest),\n    Sha512(RingDigest),\n    Md5(RingMd5),\n}\n\npub enum RingHmacType {\n    Sha1(RingHmacSha1),\n    Sha256(RingHmacSha256),\n    Sha384(RingHmacSha384),\n    Sha512(RingHmacSha512),\n}\n\nimpl SimpleDigest for RingDigestType {\n    fn update(&mut self, data: &[u8]) {\n        match self {\n            RingDigestType::Sha1(d) => d.update(data),\n            RingDigestType::Sha256(d) => d.update(data),\n            RingDigestType::Sha384(d) => d.update(data),\n            RingDigestType::Sha512(d) => d.update(data),\n            RingDigestType::Md5(d) => d.update(data),\n        }\n    }\n\n    fn finalize(self) -> Vec<u8> {\n        match self {\n            RingDigestType::Sha1(d) => d.finalize(),\n            RingDigestType::Sha256(d) => d.finalize(),\n            RingDigestType::Sha384(d) => d.finalize(),\n            RingDigestType::Sha512(d) => d.finalize(),\n            RingDigestType::Md5(d) => d.finalize(),\n        }\n    }\n}\n\nimpl HmacProvider for RingHmacType {\n    fn update(&mut self, data: &[u8]) {\n        match self {\n            RingHmacType::Sha1(h) => h.update(data),\n            RingHmacType::Sha256(h) => h.update(data),\n            RingHmacType::Sha384(h) => h.update(data),\n            RingHmacType::Sha512(h) => h.update(data),\n        }\n    }\n\n    fn finalize(self) -> Vec<u8> {\n        match self {\n            RingHmacType::Sha1(h) => h.finalize(),\n            RingHmacType::Sha256(h) => h.finalize(),\n            RingHmacType::Sha384(h) => h.finalize(),\n            RingHmacType::Sha512(h) => h.finalize(),\n        }\n    }\n}\n\n// Simple wrapper for Ring digest\npub struct RingDigest {\n    algorithm: &'static digest::Algorithm,\n    data: Vec<u8>,\n}\n\nimpl RingDigest {\n    fn new(algorithm: &'static digest::Algorithm) -> Self {\n        Self {\n            algorithm,\n            data: Vec::new(),\n        }\n    }\n}\n\nimpl SimpleDigest for RingDigest {\n    fn update(&mut self, data: &[u8]) {\n        self.data.extend_from_slice(data);\n    }\n\n    fn finalize(self) -> Vec<u8> {\n        digest::digest(self.algorithm, &self.data).as_ref().to_vec()\n    }\n}\n\n// MD5 wrapper\npub struct RingMd5(Md5Hasher);\n\nimpl SimpleDigest for RingMd5 {\n    fn update(&mut self, data: &[u8]) {\n        Digest::update(&mut self.0, data);\n    }\n\n    fn finalize(self) -> Vec<u8> {\n        self.0.finalize().to_vec()\n    }\n}\n\n// HMAC implementations\npub struct RingHmacSha1(hmac::Context);\npub struct RingHmacSha256(hmac::Context);\npub struct RingHmacSha384(hmac::Context);\npub struct RingHmacSha512(hmac::Context);\n\nimpl HmacProvider for RingHmacSha1 {\n    fn update(&mut self, data: &[u8]) {\n        self.0.update(data);\n    }\n    fn finalize(self) -> Vec<u8> {\n        self.0.sign().as_ref().to_vec()\n    }\n}\nimpl HmacProvider for RingHmacSha256 {\n    fn update(&mut self, data: &[u8]) {\n        self.0.update(data);\n    }\n    fn finalize(self) -> Vec<u8> {\n        self.0.sign().as_ref().to_vec()\n    }\n}\nimpl HmacProvider for RingHmacSha384 {\n    fn update(&mut self, data: &[u8]) {\n        self.0.update(data);\n    }\n    fn finalize(self) -> Vec<u8> {\n        self.0.sign().as_ref().to_vec()\n    }\n}\nimpl HmacProvider for RingHmacSha512 {\n    fn update(&mut self, data: &[u8]) {\n        self.0.update(data);\n    }\n    fn finalize(self) -> Vec<u8> {\n        self.0.sign().as_ref().to_vec()\n    }\n}\n\nimpl CryptoProvider for RingProvider {\n    type Digest = RingDigestType;\n    type Hmac = RingHmacType;\n\n    fn digest(&self, algorithm: HashAlgorithm) -> Self::Digest {\n        match algorithm {\n            HashAlgorithm::Md5 => RingDigestType::Md5(RingMd5(Md5Hasher::new())),\n            HashAlgorithm::Sha1 => {\n                RingDigestType::Sha1(RingDigest::new(&digest::SHA1_FOR_LEGACY_USE_ONLY))\n            },\n            HashAlgorithm::Sha256 => RingDigestType::Sha256(RingDigest::new(&digest::SHA256)),\n            HashAlgorithm::Sha384 => RingDigestType::Sha384(RingDigest::new(&digest::SHA384)),\n            HashAlgorithm::Sha512 => RingDigestType::Sha512(RingDigest::new(&digest::SHA512)),\n        }\n    }\n\n    fn hmac(&self, algorithm: HashAlgorithm, key: &[u8]) -> Self::Hmac {\n        match algorithm {\n            HashAlgorithm::Md5 => {\n                panic!(\"HMAC-MD5 not supported by Ring provider\");\n            },\n            HashAlgorithm::Sha1 => RingHmacType::Sha1(RingHmacSha1(hmac::Context::with_key(\n                &hmac::Key::new(hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY, key),\n            ))),\n            HashAlgorithm::Sha256 => RingHmacType::Sha256(RingHmacSha256(hmac::Context::with_key(\n                &hmac::Key::new(hmac::HMAC_SHA256, key),\n            ))),\n            HashAlgorithm::Sha384 => RingHmacType::Sha384(RingHmacSha384(hmac::Context::with_key(\n                &hmac::Key::new(hmac::HMAC_SHA384, key),\n            ))),\n            HashAlgorithm::Sha512 => RingHmacType::Sha512(RingHmacSha512(hmac::Context::with_key(\n                &hmac::Key::new(hmac::HMAC_SHA512, key),\n            ))),\n        }\n    }\n\n    fn ecdsa_sign(\n        &self,\n        _curve: EllipticCurve,\n        _private_key_der: &[u8],\n        _digest: &[u8],\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn ecdsa_verify(\n        &self,\n        _curve: EllipticCurve,\n        _public_key_sec1: &[u8],\n        _signature: &[u8],\n        _digest: &[u8],\n    ) -> Result<bool, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn ed25519_sign(&self, _private_key_der: &[u8], _data: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn ed25519_verify(\n        &self,\n        _public_key_bytes: &[u8],\n        _signature: &[u8],\n        _data: &[u8],\n    ) -> Result<bool, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn rsa_pss_sign(\n        &self,\n        _private_key_der: &[u8],\n        _digest: &[u8],\n        _salt_length: usize,\n        _hash_alg: HashAlgorithm,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn rsa_pss_verify(\n        &self,\n        _public_key_der: &[u8],\n        _signature: &[u8],\n        _digest: &[u8],\n        _salt_length: usize,\n        _hash_alg: HashAlgorithm,\n    ) -> Result<bool, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn rsa_pkcs1v15_sign(\n        &self,\n        _private_key_der: &[u8],\n        _digest: &[u8],\n        _hash_alg: HashAlgorithm,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn rsa_pkcs1v15_verify(\n        &self,\n        _public_key_der: &[u8],\n        _signature: &[u8],\n        _digest: &[u8],\n        _hash_alg: HashAlgorithm,\n    ) -> Result<bool, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn rsa_oaep_encrypt(\n        &self,\n        _public_key_der: &[u8],\n        _data: &[u8],\n        _hash_alg: HashAlgorithm,\n        _label: Option<&[u8]>,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn rsa_oaep_decrypt(\n        &self,\n        _private_key_der: &[u8],\n        _data: &[u8],\n        _hash_alg: HashAlgorithm,\n        _label: Option<&[u8]>,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn ecdh_derive_bits(\n        &self,\n        _curve: EllipticCurve,\n        _private_key_der: &[u8],\n        _public_key_sec1: &[u8],\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn x25519_derive_bits(\n        &self,\n        _private_key: &[u8],\n        _public_key: &[u8],\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn aes_encrypt(\n        &self,\n        _mode: AesMode,\n        _key: &[u8],\n        _iv: &[u8],\n        _data: &[u8],\n        _additional_data: Option<&[u8]>,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn aes_decrypt(\n        &self,\n        _mode: AesMode,\n        _key: &[u8],\n        _iv: &[u8],\n        _data: &[u8],\n        _additional_data: Option<&[u8]>,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn aes_kw_wrap(&self, _kek: &[u8], _key: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn aes_kw_unwrap(&self, _kek: &[u8], _wrapped_key: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn hkdf_derive_key(\n        &self,\n        _key: &[u8],\n        _salt: &[u8],\n        _info: &[u8],\n        _length: usize,\n        _hash_alg: HashAlgorithm,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn pbkdf2_derive_key(\n        &self,\n        _password: &[u8],\n        _salt: &[u8],\n        _iterations: u32,\n        _length: usize,\n        _hash_alg: HashAlgorithm,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn generate_aes_key(&self, _length_bits: u16) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn generate_hmac_key(\n        &self,\n        _hash_alg: HashAlgorithm,\n        _length_bits: u16,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn generate_ec_key(&self, _curve: EllipticCurve) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn generate_ed25519_key(&self) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn generate_x25519_key(&self) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn generate_rsa_key(\n        &self,\n        _modulus_length: u32,\n        _public_exponent: &[u8],\n    ) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n\n    fn import_rsa_public_key_pkcs1(\n        &self,\n        _der: &[u8],\n    ) -> Result<super::RsaImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_rsa_private_key_pkcs1(\n        &self,\n        _der: &[u8],\n    ) -> Result<super::RsaImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_rsa_public_key_spki(\n        &self,\n        _der: &[u8],\n    ) -> Result<super::RsaImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_rsa_private_key_pkcs8(\n        &self,\n        _der: &[u8],\n    ) -> Result<super::RsaImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_rsa_public_key_pkcs1(&self, _key_data: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_rsa_public_key_spki(&self, _key_data: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_rsa_private_key_pkcs8(&self, _key_data: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_ec_public_key_sec1(\n        &self,\n        _data: &[u8],\n        _curve: EllipticCurve,\n    ) -> Result<super::EcImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_ec_public_key_spki(&self, _der: &[u8]) -> Result<super::EcImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_ec_private_key_pkcs8(\n        &self,\n        _der: &[u8],\n    ) -> Result<super::EcImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_ec_private_key_sec1(\n        &self,\n        _data: &[u8],\n        _curve: EllipticCurve,\n    ) -> Result<super::EcImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_ec_public_key_sec1(\n        &self,\n        _key_data: &[u8],\n        _curve: EllipticCurve,\n        _is_private: bool,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_ec_public_key_spki(\n        &self,\n        _key_data: &[u8],\n        _curve: EllipticCurve,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_ec_private_key_pkcs8(\n        &self,\n        _key_data: &[u8],\n        _curve: EllipticCurve,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_okp_public_key_raw(\n        &self,\n        _data: &[u8],\n    ) -> Result<super::OkpImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_okp_public_key_spki(\n        &self,\n        _der: &[u8],\n        _expected_oid: &[u8],\n    ) -> Result<super::OkpImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_okp_private_key_pkcs8(\n        &self,\n        _der: &[u8],\n        _expected_oid: &[u8],\n    ) -> Result<super::OkpImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_okp_public_key_raw(\n        &self,\n        _key_data: &[u8],\n        _is_private: bool,\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_okp_public_key_spki(\n        &self,\n        _key_data: &[u8],\n        _oid: &[u8],\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_okp_private_key_pkcs8(\n        &self,\n        _key_data: &[u8],\n        _oid: &[u8],\n    ) -> Result<Vec<u8>, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_rsa_jwk(\n        &self,\n        _jwk: super::RsaJwkImport<'_>,\n    ) -> Result<super::RsaImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_rsa_jwk(\n        &self,\n        _key_data: &[u8],\n        _is_private: bool,\n    ) -> Result<super::RsaJwkExport, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_ec_jwk(\n        &self,\n        _jwk: super::EcJwkImport<'_>,\n        _curve: EllipticCurve,\n    ) -> Result<super::EcImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_ec_jwk(\n        &self,\n        _key_data: &[u8],\n        _curve: EllipticCurve,\n        _is_private: bool,\n    ) -> Result<super::EcJwkExport, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn import_okp_jwk(\n        &self,\n        _jwk: super::OkpJwkImport<'_>,\n        _is_ed25519: bool,\n    ) -> Result<super::OkpImportResult, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n    fn export_okp_jwk(\n        &self,\n        _key_data: &[u8],\n        _is_private: bool,\n        _is_ed25519: bool,\n    ) -> Result<super::OkpJwkExport, CryptoError> {\n        Err(CryptoError::UnsupportedAlgorithm)\n    }\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/provider/rust/aes_variants.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\n//! AES cipher variant types for SubtleCrypto operations.\n//! Only available when the `_rustcrypto` feature is enabled.\n\nuse aes::cipher::BlockModeDecrypt;\nuse aes::cipher::BlockModeEncrypt;\n\nuse aes::{\n    cipher::{\n        block_padding::{Error as PaddingError, Pkcs7},\n        consts::{U12, U13, U14, U15, U16},\n        InvalidLength, KeyIvInit, StreamCipher, StreamCipherError,\n    },\n    Aes128, Aes192, Aes256,\n};\nuse aes_gcm::{\n    aead::{Aead, Payload},\n    AesGcm, KeyInit, Nonce,\n};\nuse ctr::{Ctr128BE, Ctr32BE, Ctr64BE};\n\n#[allow(dead_code)]\npub enum AesCbcEncVariant {\n    Aes128(cbc::Encryptor<aes::Aes128>),\n    Aes192(cbc::Encryptor<aes::Aes192>),\n    Aes256(cbc::Encryptor<aes::Aes256>),\n}\n\n#[allow(dead_code)]\nimpl AesCbcEncVariant {\n    pub fn new(key_len: u16, key: &[u8], iv: &[u8]) -> std::result::Result<Self, InvalidLength> {\n        let variant: AesCbcEncVariant = match key_len {\n            128 => Self::Aes128(cbc::Encryptor::new_from_slices(key, iv)?),\n            192 => Self::Aes192(cbc::Encryptor::new_from_slices(key, iv)?),\n            256 => Self::Aes256(cbc::Encryptor::new_from_slices(key, iv)?),\n            _ => return Err(InvalidLength),\n        };\n\n        Ok(variant)\n    }\n\n    pub fn encrypt(self, data: &[u8]) -> Vec<u8> {\n        match self {\n            Self::Aes128(v) => v.encrypt_padded_vec::<Pkcs7>(data),\n            Self::Aes192(v) => v.encrypt_padded_vec::<Pkcs7>(data),\n            Self::Aes256(v) => v.encrypt_padded_vec::<Pkcs7>(data),\n        }\n    }\n}\n\n#[allow(dead_code)]\npub enum AesCbcDecVariant {\n    Aes128(cbc::Decryptor<aes::Aes128>),\n    Aes192(cbc::Decryptor<aes::Aes192>),\n    Aes256(cbc::Decryptor<aes::Aes256>),\n}\n\n#[allow(dead_code)]\nimpl AesCbcDecVariant {\n    pub fn new(key_len: u16, key: &[u8], iv: &[u8]) -> std::result::Result<Self, InvalidLength> {\n        let variant: AesCbcDecVariant = match key_len {\n            128 => Self::Aes128(cbc::Decryptor::new_from_slices(key, iv)?),\n            192 => Self::Aes192(cbc::Decryptor::new_from_slices(key, iv)?),\n            256 => Self::Aes256(cbc::Decryptor::new_from_slices(key, iv)?),\n            _ => return Err(InvalidLength),\n        };\n\n        Ok(variant)\n    }\n\n    pub fn decrypt(self, data: &[u8]) -> std::result::Result<Vec<u8>, PaddingError> {\n        Ok(match self {\n            Self::Aes128(v) => v.decrypt_padded_vec::<Pkcs7>(data)?,\n            Self::Aes192(v) => v.decrypt_padded_vec::<Pkcs7>(data)?,\n            Self::Aes256(v) => v.decrypt_padded_vec::<Pkcs7>(data)?,\n        })\n    }\n}\n\n#[allow(dead_code)]\npub enum AesCtrVariant {\n    Aes128Ctr32(Ctr32BE<aes::Aes128>),\n    Aes128Ctr64(Ctr64BE<aes::Aes128>),\n    Aes128Ctr128(Ctr128BE<aes::Aes128>),\n    Aes192Ctr32(Ctr32BE<aes::Aes192>),\n    Aes192Ctr64(Ctr64BE<aes::Aes192>),\n    Aes192Ctr128(Ctr128BE<aes::Aes192>),\n    Aes256Ctr32(Ctr32BE<aes::Aes256>),\n    Aes256Ctr64(Ctr64BE<aes::Aes256>),\n    Aes256Ctr128(Ctr128BE<aes::Aes256>),\n}\n\n#[allow(dead_code)]\nimpl AesCtrVariant {\n    pub fn new(\n        key_len: u16,\n        encryption_length: u32,\n        key: &[u8],\n        counter: &[u8],\n    ) -> std::result::Result<Self, InvalidLength> {\n        let variant: AesCtrVariant = match (key_len, encryption_length) {\n            (128, 32) => Self::Aes128Ctr32(Ctr32BE::new_from_slices(key, counter)?),\n            (128, 64) => Self::Aes128Ctr64(Ctr64BE::new_from_slices(key, counter)?),\n            (128, 128) => Self::Aes128Ctr128(Ctr128BE::new_from_slices(key, counter)?),\n            (192, 32) => Self::Aes192Ctr32(Ctr32BE::new_from_slices(key, counter)?),\n            (192, 64) => Self::Aes192Ctr64(Ctr64BE::new_from_slices(key, counter)?),\n            (192, 128) => Self::Aes192Ctr128(Ctr128BE::new_from_slices(key, counter)?),\n            (256, 32) => Self::Aes256Ctr32(Ctr32BE::new_from_slices(key, counter)?),\n            (256, 64) => Self::Aes256Ctr64(Ctr64BE::new_from_slices(key, counter)?),\n            (256, 128) => Self::Aes256Ctr128(Ctr128BE::new_from_slices(key, counter)?),\n            _ => return Err(InvalidLength),\n        };\n\n        Ok(variant)\n    }\n\n    pub fn encrypt(&mut self, data: &[u8]) -> std::result::Result<Vec<u8>, StreamCipherError> {\n        let mut ciphertext = data.to_vec();\n        match self {\n            Self::Aes128Ctr32(v) => v.try_apply_keystream(&mut ciphertext)?,\n            Self::Aes128Ctr64(v) => v.try_apply_keystream(&mut ciphertext)?,\n            Self::Aes128Ctr128(v) => v.try_apply_keystream(&mut ciphertext)?,\n            Self::Aes192Ctr32(v) => v.try_apply_keystream(&mut ciphertext)?,\n            Self::Aes192Ctr64(v) => v.try_apply_keystream(&mut ciphertext)?,\n            Self::Aes192Ctr128(v) => v.try_apply_keystream(&mut ciphertext)?,\n            Self::Aes256Ctr32(v) => v.try_apply_keystream(&mut ciphertext)?,\n            Self::Aes256Ctr64(v) => v.try_apply_keystream(&mut ciphertext)?,\n            Self::Aes256Ctr128(v) => v.try_apply_keystream(&mut ciphertext)?,\n        }\n        Ok(ciphertext)\n    }\n\n    pub fn decrypt(&mut self, data: &[u8]) -> std::result::Result<Vec<u8>, StreamCipherError> {\n        let mut ciphertext = data.to_vec();\n        match self {\n            Self::Aes128Ctr32(v) => v.try_apply_keystream(&mut ciphertext)?,\n            Self::Aes128Ctr64(v) => v.try_apply_keystream(&mut ciphertext)?,\n            Self::Aes128Ctr128(v) => v.try_apply_keystream(&mut ciphertext)?,\n            Self::Aes192Ctr32(v) => v.try_apply_keystream(&mut ciphertext)?,\n            Self::Aes192Ctr64(v) => v.try_apply_keystream(&mut ciphertext)?,\n            Self::Aes192Ctr128(v) => v.try_apply_keystream(&mut ciphertext)?,\n            Self::Aes256Ctr32(v) => v.try_apply_keystream(&mut ciphertext)?,\n            Self::Aes256Ctr64(v) => v.try_apply_keystream(&mut ciphertext)?,\n            Self::Aes256Ctr128(v) => v.try_apply_keystream(&mut ciphertext)?,\n        }\n        Ok(ciphertext)\n    }\n}\n\npub enum AesGcmVariant {\n    Aes128Gcm96(AesGcm<Aes128, U12, U12>),\n    Aes192Gcm96(AesGcm<Aes192, U12, U12>),\n    Aes256Gcm96(AesGcm<Aes256, U12, U12>),\n    Aes128Gcm104(AesGcm<Aes128, U12, U13>),\n    Aes192Gcm104(AesGcm<Aes192, U12, U13>),\n    Aes256Gcm104(AesGcm<Aes256, U12, U13>),\n    Aes128Gcm112(AesGcm<Aes128, U12, U14>),\n    Aes192Gcm112(AesGcm<Aes192, U12, U14>),\n    Aes256Gcm112(AesGcm<Aes256, U12, U14>),\n    Aes128Gcm120(AesGcm<Aes128, U12, U15>),\n    Aes192Gcm120(AesGcm<Aes192, U12, U15>),\n    Aes256Gcm120(AesGcm<Aes256, U12, U15>),\n    Aes128Gcm128(AesGcm<Aes128, U12, U16>),\n    Aes192Gcm128(AesGcm<Aes192, U12, U16>),\n    Aes256Gcm128(AesGcm<Aes256, U12, U16>),\n}\n\n#[allow(dead_code)]\nimpl AesGcmVariant {\n    pub fn new(\n        key_len: u16,\n        tag_length: u8,\n        key: &[u8],\n    ) -> std::result::Result<Self, InvalidLength> {\n        let variant = match (key_len, tag_length) {\n            (128, 96) => Self::Aes128Gcm96(AesGcm::new_from_slice(key)?),\n            (192, 96) => Self::Aes192Gcm96(AesGcm::new_from_slice(key)?),\n            (256, 96) => Self::Aes256Gcm96(AesGcm::new_from_slice(key)?),\n            (128, 104) => Self::Aes128Gcm104(AesGcm::new_from_slice(key)?),\n            (192, 104) => Self::Aes192Gcm104(AesGcm::new_from_slice(key)?),\n            (256, 104) => Self::Aes256Gcm104(AesGcm::new_from_slice(key)?),\n            (128, 112) => Self::Aes128Gcm112(AesGcm::new_from_slice(key)?),\n            (192, 112) => Self::Aes192Gcm112(AesGcm::new_from_slice(key)?),\n            (256, 112) => Self::Aes256Gcm112(AesGcm::new_from_slice(key)?),\n            (128, 120) => Self::Aes128Gcm120(AesGcm::new_from_slice(key)?),\n            (192, 120) => Self::Aes192Gcm120(AesGcm::new_from_slice(key)?),\n            (256, 120) => Self::Aes256Gcm120(AesGcm::new_from_slice(key)?),\n            (128, 128) => Self::Aes128Gcm128(AesGcm::new_from_slice(key)?),\n            (192, 128) => Self::Aes192Gcm128(AesGcm::new_from_slice(key)?),\n            (256, 128) => Self::Aes256Gcm128(AesGcm::new_from_slice(key)?),\n            _ => return Err(InvalidLength),\n        };\n\n        Ok(variant)\n    }\n\n    pub fn encrypt(\n        &self,\n        nonce: &[u8],\n        msg: &[u8],\n        aad: Option<&[u8]>,\n    ) -> std::result::Result<Vec<u8>, aes_gcm::Error> {\n        let plaintext: Payload = Payload {\n            msg,\n            aad: aad.unwrap_or_default(),\n        };\n        let nonce: &ctr::cipher::Array<_, _> =\n            &Nonce::<U12>::try_from(nonce).map_err(|_| aes_gcm::Error)?;\n        match self {\n            Self::Aes128Gcm96(v) => v.encrypt(nonce, plaintext),\n            Self::Aes192Gcm96(v) => v.encrypt(nonce, plaintext),\n            Self::Aes256Gcm96(v) => v.encrypt(nonce, plaintext),\n            Self::Aes128Gcm104(v) => v.encrypt(nonce, plaintext),\n            Self::Aes192Gcm104(v) => v.encrypt(nonce, plaintext),\n            Self::Aes256Gcm104(v) => v.encrypt(nonce, plaintext),\n            Self::Aes128Gcm112(v) => v.encrypt(nonce, plaintext),\n            Self::Aes192Gcm112(v) => v.encrypt(nonce, plaintext),\n            Self::Aes256Gcm112(v) => v.encrypt(nonce, plaintext),\n            Self::Aes128Gcm120(v) => v.encrypt(nonce, plaintext),\n            Self::Aes192Gcm120(v) => v.encrypt(nonce, plaintext),\n            Self::Aes256Gcm120(v) => v.encrypt(nonce, plaintext),\n            Self::Aes128Gcm128(v) => v.encrypt(nonce, plaintext),\n            Self::Aes192Gcm128(v) => v.encrypt(nonce, plaintext),\n            Self::Aes256Gcm128(v) => v.encrypt(nonce, plaintext),\n        }\n    }\n\n    pub fn decrypt(\n        &self,\n        nonce: &[u8],\n        msg: &[u8],\n        aad: Option<&[u8]>,\n    ) -> std::result::Result<Vec<u8>, aes_gcm::Error> {\n        let ciphertext: Payload = Payload {\n            msg,\n            aad: aad.unwrap_or_default(),\n        };\n        let nonce: &ctr::cipher::Array<_, _> =\n            &Nonce::<U12>::try_from(nonce).map_err(|_| aes_gcm::Error)?;\n        match self {\n            Self::Aes128Gcm96(v) => v.decrypt(nonce, ciphertext),\n            Self::Aes192Gcm96(v) => v.decrypt(nonce, ciphertext),\n            Self::Aes256Gcm96(v) => v.decrypt(nonce, ciphertext),\n            Self::Aes128Gcm104(v) => v.decrypt(nonce, ciphertext),\n            Self::Aes192Gcm104(v) => v.decrypt(nonce, ciphertext),\n            Self::Aes256Gcm104(v) => v.decrypt(nonce, ciphertext),\n            Self::Aes128Gcm112(v) => v.decrypt(nonce, ciphertext),\n            Self::Aes192Gcm112(v) => v.decrypt(nonce, ciphertext),\n            Self::Aes256Gcm112(v) => v.decrypt(nonce, ciphertext),\n            Self::Aes128Gcm120(v) => v.decrypt(nonce, ciphertext),\n            Self::Aes192Gcm120(v) => v.decrypt(nonce, ciphertext),\n            Self::Aes256Gcm120(v) => v.decrypt(nonce, ciphertext),\n            Self::Aes128Gcm128(v) => v.decrypt(nonce, ciphertext),\n            Self::Aes192Gcm128(v) => v.decrypt(nonce, ciphertext),\n            Self::Aes256Gcm128(v) => v.decrypt(nonce, ciphertext),\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/provider/rust/mod.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nmod aes_variants;\n\nuse std::num::NonZeroU32;\n\nuse aes::cipher::{\n    block_padding::Pkcs7, BlockModeDecrypt, BlockModeEncrypt, KeyIvInit, StreamCipher,\n    StreamCipherError,\n};\nuse aes_gcm::{\n    aead::{Aead, Payload},\n    KeyInit, Nonce,\n};\nuse aes_kw::{KwAes128, KwAes192, KwAes256};\nuse cbc::{Decryptor, Encryptor};\nuse ctr::{cipher::Array, Ctr128BE, Ctr32BE, Ctr64BE};\nuse der::Encode;\nuse ecdsa::signature::hazmat::PrehashVerifier;\nuse ed25519_dalek::{Signature, Signer, Verifier, VerifyingKey};\nuse elliptic_curve::{consts::U12, sec1::ToSec1Point, Generate};\nuse hkdf::Hkdf;\nuse hmac::{Hmac as HmacImpl, Mac};\nuse p256::{\n    ecdsa::{\n        Signature as P256Signature, SigningKey as P256SigningKey, VerifyingKey as P256VerifyingKey,\n    },\n    SecretKey as P256SecretKey,\n};\nuse p384::{\n    ecdsa::{\n        Signature as P384Signature, SigningKey as P384SigningKey, VerifyingKey as P384VerifyingKey,\n    },\n    SecretKey as P384SecretKey,\n};\nuse p521::{\n    ecdsa::{\n        Signature as P521Signature, SigningKey as P521SigningKey, VerifyingKey as P521VerifyingKey,\n    },\n    SecretKey as P521SecretKey,\n};\nuse pbkdf2::pbkdf2;\nuse pkcs8::{DecodePrivateKey, EncodePrivateKey};\nuse rsa::pkcs1::{\n    DecodeRsaPrivateKey, DecodeRsaPublicKey, EncodeRsaPrivateKey, EncodeRsaPublicKey,\n};\nuse rsa::signature::hazmat::PrehashSigner;\nuse rsa::{\n    pss::Pss,\n    sha2::{Digest, Sha256, Sha384, Sha512},\n    BoxedUint, Oaep, Pkcs1v15Sign, RsaPrivateKey, RsaPublicKey,\n};\nuse sha1::Sha1;\n\nuse crate::{\n    hash::HashAlgorithm,\n    provider::{AesMode, CryptoError, CryptoProvider, HmacProvider, SimpleDigest},\n    random_byte_array,\n    subtle::EllipticCurve,\n};\n\nuse aes_variants::AesGcmVariant;\n\nimpl From<aes::cipher::InvalidLength> for CryptoError {\n    fn from(_: aes::cipher::InvalidLength) -> Self {\n        CryptoError::InvalidLength\n    }\n}\n\nimpl From<StreamCipherError> for CryptoError {\n    fn from(_: StreamCipherError) -> Self {\n        CryptoError::OperationFailed(None)\n    }\n}\n\n// Digest implementation using sha2/md5 crates\npub enum RustDigest {\n    Md5(md5::Md5),\n    Sha1(Sha1),\n    Sha256(Sha256),\n    Sha384(Sha384),\n    Sha512(Sha512),\n}\n\nimpl SimpleDigest for RustDigest {\n    fn update(&mut self, data: &[u8]) {\n        match self {\n            RustDigest::Md5(h) => Digest::update(h, data),\n            RustDigest::Sha1(h) => Digest::update(h, data),\n            RustDigest::Sha256(h) => Digest::update(h, data),\n            RustDigest::Sha384(h) => Digest::update(h, data),\n            RustDigest::Sha512(h) => Digest::update(h, data),\n        }\n    }\n\n    fn finalize(self) -> Vec<u8> {\n        match self {\n            RustDigest::Md5(h) => h.finalize().to_vec(),\n            RustDigest::Sha1(h) => h.finalize().to_vec(),\n            RustDigest::Sha256(h) => h.finalize().to_vec(),\n            RustDigest::Sha384(h) => h.finalize().to_vec(),\n            RustDigest::Sha512(h) => h.finalize().to_vec(),\n        }\n    }\n}\n\n// HMAC implementation using hmac crate\npub enum RustHmac {\n    Sha1(HmacImpl<Sha1>),\n    Sha256(HmacImpl<Sha256>),\n    Sha384(HmacImpl<Sha384>),\n    Sha512(HmacImpl<Sha512>),\n}\n\nimpl HmacProvider for RustHmac {\n    fn update(&mut self, data: &[u8]) {\n        match self {\n            RustHmac::Sha1(h) => Mac::update(h, data),\n            RustHmac::Sha256(h) => Mac::update(h, data),\n            RustHmac::Sha384(h) => Mac::update(h, data),\n            RustHmac::Sha512(h) => Mac::update(h, data),\n        }\n    }\n\n    fn finalize(self) -> Vec<u8> {\n        match self {\n            RustHmac::Sha1(h) => h.finalize().into_bytes().to_vec(),\n            RustHmac::Sha256(h) => h.finalize().into_bytes().to_vec(),\n            RustHmac::Sha384(h) => h.finalize().into_bytes().to_vec(),\n            RustHmac::Sha512(h) => h.finalize().into_bytes().to_vec(),\n        }\n    }\n}\n\n// Main Crypto Provider\n#[derive(Default)]\npub struct RustCryptoProvider;\n\nimpl CryptoProvider for RustCryptoProvider {\n    type Digest = RustDigest;\n    type Hmac = RustHmac;\n\n    fn digest(&self, algorithm: HashAlgorithm) -> Self::Digest {\n        match algorithm {\n            HashAlgorithm::Md5 => RustDigest::Md5(md5::Md5::new()),\n            HashAlgorithm::Sha1 => RustDigest::Sha1(Sha1::new()),\n            HashAlgorithm::Sha256 => RustDigest::Sha256(Sha256::new()),\n            HashAlgorithm::Sha384 => RustDigest::Sha384(Sha384::new()),\n            HashAlgorithm::Sha512 => RustDigest::Sha512(Sha512::new()),\n        }\n    }\n\n    fn hmac(&self, algorithm: HashAlgorithm, key: &[u8]) -> Self::Hmac {\n        match algorithm {\n            HashAlgorithm::Md5 => panic!(\"HMAC-MD5 not supported\"),\n            HashAlgorithm::Sha1 => RustHmac::Sha1(HmacImpl::<Sha1>::new_from_slice(key).unwrap()),\n            HashAlgorithm::Sha256 => {\n                RustHmac::Sha256(HmacImpl::<Sha256>::new_from_slice(key).unwrap())\n            },\n            HashAlgorithm::Sha384 => {\n                RustHmac::Sha384(HmacImpl::<Sha384>::new_from_slice(key).unwrap())\n            },\n            HashAlgorithm::Sha512 => {\n                RustHmac::Sha512(HmacImpl::<Sha512>::new_from_slice(key).unwrap())\n            },\n        }\n    }\n\n    fn ecdsa_sign(\n        &self,\n        curve: EllipticCurve,\n        private_key_der: &[u8],\n        digest: &[u8],\n    ) -> Result<Vec<u8>, CryptoError> {\n        match curve {\n            EllipticCurve::P256 => {\n                let secret_key = P256SecretKey::from_pkcs8_der(private_key_der)\n                    .map_err(|_| CryptoError::InvalidKey(None))?;\n                let signing_key = P256SigningKey::from(secret_key);\n                let signature: p256::ecdsa::Signature = signing_key\n                    .sign_prehash(digest)\n                    .map_err(|_| CryptoError::SigningFailed(None))?;\n                Ok(signature.to_bytes().to_vec())\n            },\n            EllipticCurve::P384 => {\n                let secret_key = P384SecretKey::from_pkcs8_der(private_key_der)\n                    .map_err(|_| CryptoError::InvalidKey(None))?;\n                let signing_key = P384SigningKey::from(secret_key);\n                let signature: p384::ecdsa::Signature = signing_key\n                    .sign_prehash(digest)\n                    .map_err(|_| CryptoError::SigningFailed(None))?;\n                Ok(signature.to_bytes().to_vec())\n            },\n            EllipticCurve::P521 => {\n                let secret_key = P521SecretKey::from_pkcs8_der(private_key_der)\n                    .map_err(|_| CryptoError::InvalidKey(None))?;\n                let signing_key = P521SigningKey::from(secret_key);\n                let signature: p521::ecdsa::Signature = signing_key\n                    .sign_prehash(digest)\n                    .map_err(|_| CryptoError::SigningFailed(None))?;\n                Ok(signature.to_bytes().to_vec())\n            },\n        }\n    }\n\n    fn ecdsa_verify(\n        &self,\n        curve: EllipticCurve,\n        public_key_sec1: &[u8],\n        signature: &[u8],\n        digest: &[u8],\n    ) -> Result<bool, CryptoError> {\n        match curve {\n            EllipticCurve::P256 => {\n                let verifying_key = P256VerifyingKey::from_sec1_bytes(public_key_sec1)\n                    .map_err(|_| CryptoError::InvalidKey(None))?;\n                let sig = P256Signature::from_slice(signature)\n                    .map_err(|_| CryptoError::InvalidSignature(None))?;\n                Ok(verifying_key.verify_prehash(digest, &sig).is_ok())\n            },\n            EllipticCurve::P384 => {\n                let verifying_key = P384VerifyingKey::from_sec1_bytes(public_key_sec1)\n                    .map_err(|_| CryptoError::InvalidKey(None))?;\n                let sig = P384Signature::from_slice(signature)\n                    .map_err(|_| CryptoError::InvalidSignature(None))?;\n                Ok(verifying_key.verify_prehash(digest, &sig).is_ok())\n            },\n            EllipticCurve::P521 => {\n                let verifying_key = P521VerifyingKey::from_sec1_bytes(public_key_sec1)\n                    .map_err(|_| CryptoError::InvalidKey(None))?;\n                let sig = P521Signature::from_slice(signature)\n                    .map_err(|_| CryptoError::InvalidSignature(None))?;\n                Ok(verifying_key.verify_prehash(digest, &sig).is_ok())\n            },\n        }\n    }\n\n    fn ed25519_sign(&self, private_key_der: &[u8], data: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        let signing_key = ed25519_dalek::SigningKey::from_pkcs8_der(private_key_der)\n            .map_err(|_| CryptoError::InvalidKey(None))?;\n        let signature = signing_key\n            .try_sign(data)\n            .map_err(|_| CryptoError::InvalidSignature(None))?;\n        Ok(signature.to_bytes().to_vec())\n    }\n\n    fn ed25519_verify(\n        &self,\n        public_key_bytes: &[u8],\n        signature: &[u8],\n        data: &[u8],\n    ) -> Result<bool, CryptoError> {\n        let public_key = VerifyingKey::from_bytes(\n            public_key_bytes\n                .try_into()\n                .map_err(|_| CryptoError::InvalidKey(None))?,\n        )\n        .map_err(|_| CryptoError::InvalidKey(None))?;\n        let signature = Signature::from_bytes(\n            signature\n                .try_into()\n                .map_err(|_| CryptoError::InvalidSignature(None))?,\n        );\n        Ok(public_key.verify(data, &signature).is_ok())\n    }\n\n    fn rsa_pss_sign(\n        &self,\n        private_key_der: &[u8],\n        digest: &[u8],\n        salt_length: usize,\n        hash_alg: HashAlgorithm,\n    ) -> Result<Vec<u8>, CryptoError> {\n        let mut rng = rand::rng();\n        let private_key = RsaPrivateKey::from_pkcs1_der(private_key_der)\n            .map_err(|_| CryptoError::InvalidKey(None))?;\n\n        match hash_alg {\n            HashAlgorithm::Sha256 => private_key\n                .sign_with_rng(&mut rng, Pss::<Sha256>::new_with_salt(salt_length), digest)\n                .map_err(|_| CryptoError::SigningFailed(None)),\n            HashAlgorithm::Sha384 => private_key\n                .sign_with_rng(&mut rng, Pss::<Sha384>::new_with_salt(salt_length), digest)\n                .map_err(|_| CryptoError::SigningFailed(None)),\n            HashAlgorithm::Sha512 => private_key\n                .sign_with_rng(&mut rng, Pss::<Sha512>::new_with_salt(salt_length), digest)\n                .map_err(|_| CryptoError::SigningFailed(None)),\n            _ => Err(CryptoError::UnsupportedAlgorithm),\n        }\n    }\n\n    fn rsa_pss_verify(\n        &self,\n        public_key_der: &[u8],\n        signature: &[u8],\n        digest: &[u8],\n        salt_length: usize,\n        hash_alg: HashAlgorithm,\n    ) -> Result<bool, CryptoError> {\n        let public_key = RsaPublicKey::from_pkcs1_der(public_key_der)\n            .map_err(|_| CryptoError::InvalidKey(None))?;\n\n        match hash_alg {\n            HashAlgorithm::Sha256 => Ok(public_key\n                .verify(Pss::<Sha256>::new_with_salt(salt_length), digest, signature)\n                .is_ok()),\n            HashAlgorithm::Sha384 => Ok(public_key\n                .verify(Pss::<Sha384>::new_with_salt(salt_length), digest, signature)\n                .is_ok()),\n            HashAlgorithm::Sha512 => Ok(public_key\n                .verify(Pss::<Sha512>::new_with_salt(salt_length), digest, signature)\n                .is_ok()),\n            _ => Err(CryptoError::UnsupportedAlgorithm),\n        }\n    }\n\n    fn rsa_pkcs1v15_sign(\n        &self,\n        private_key_der: &[u8],\n        digest: &[u8],\n        hash_alg: HashAlgorithm,\n    ) -> Result<Vec<u8>, CryptoError> {\n        let mut rng = rand::rng();\n        let private_key = RsaPrivateKey::from_pkcs1_der(private_key_der)\n            .map_err(|_| CryptoError::InvalidKey(None))?;\n\n        match hash_alg {\n            HashAlgorithm::Sha256 => private_key\n                .sign_with_rng(&mut rng, Pkcs1v15Sign::new::<Sha256>(), digest)\n                .map_err(|_| CryptoError::SigningFailed(None)),\n            HashAlgorithm::Sha384 => private_key\n                .sign_with_rng(&mut rng, Pkcs1v15Sign::new::<Sha384>(), digest)\n                .map_err(|_| CryptoError::SigningFailed(None)),\n            HashAlgorithm::Sha512 => private_key\n                .sign_with_rng(&mut rng, Pkcs1v15Sign::new::<Sha512>(), digest)\n                .map_err(|_| CryptoError::SigningFailed(None)),\n            _ => Err(CryptoError::UnsupportedAlgorithm),\n        }\n    }\n\n    fn rsa_pkcs1v15_verify(\n        &self,\n        public_key_der: &[u8],\n        signature: &[u8],\n        digest: &[u8],\n        hash_alg: HashAlgorithm,\n    ) -> Result<bool, CryptoError> {\n        let public_key = RsaPublicKey::from_pkcs1_der(public_key_der)\n            .map_err(|_| CryptoError::InvalidKey(None))?;\n\n        match hash_alg {\n            HashAlgorithm::Sha256 => Ok(public_key\n                .verify(Pkcs1v15Sign::new::<Sha256>(), digest, signature)\n                .is_ok()),\n            HashAlgorithm::Sha384 => Ok(public_key\n                .verify(Pkcs1v15Sign::new::<Sha384>(), digest, signature)\n                .is_ok()),\n            HashAlgorithm::Sha512 => Ok(public_key\n                .verify(Pkcs1v15Sign::new::<Sha512>(), digest, signature)\n                .is_ok()),\n            _ => Err(CryptoError::UnsupportedAlgorithm),\n        }\n    }\n\n    fn rsa_oaep_encrypt(\n        &self,\n        public_key_der: &[u8],\n        data: &[u8],\n        hash_alg: HashAlgorithm,\n        label: Option<&[u8]>,\n    ) -> Result<Vec<u8>, CryptoError> {\n        let mut rng = rand::rng();\n        let public_key = RsaPublicKey::from_pkcs1_der(public_key_der)\n            .map_err(|_| CryptoError::InvalidKey(None))?;\n\n        match hash_alg {\n            HashAlgorithm::Sha1 => {\n                let mut padding = Oaep::<Sha1>::new();\n                if let Some(l) = label {\n                    if !l.is_empty() {\n                        padding.label = Some(l.into());\n                    }\n                }\n                public_key\n                    .encrypt(&mut rng, padding, data)\n                    .map_err(|_| CryptoError::EncryptionFailed(None))\n            },\n            HashAlgorithm::Sha256 => {\n                let mut padding = Oaep::<Sha256>::new();\n                if let Some(l) = label {\n                    if !l.is_empty() {\n                        padding.label = Some(l.into());\n                    }\n                }\n                public_key\n                    .encrypt(&mut rng, padding, data)\n                    .map_err(|_| CryptoError::EncryptionFailed(None))\n            },\n            HashAlgorithm::Sha384 => {\n                let mut padding = Oaep::<Sha384>::new();\n                if let Some(l) = label {\n                    if !l.is_empty() {\n                        padding.label = Some(l.into());\n                    }\n                }\n                public_key\n                    .encrypt(&mut rng, padding, data)\n                    .map_err(|_| CryptoError::EncryptionFailed(None))\n            },\n            HashAlgorithm::Sha512 => {\n                let mut padding = Oaep::<Sha512>::new();\n                if let Some(l) = label {\n                    if !l.is_empty() {\n                        padding.label = Some(l.into());\n                    }\n                }\n                public_key\n                    .encrypt(&mut rng, padding, data)\n                    .map_err(|_| CryptoError::EncryptionFailed(None))\n            },\n            _ => Err(CryptoError::UnsupportedAlgorithm),\n        }\n    }\n\n    fn rsa_oaep_decrypt(\n        &self,\n        private_key_der: &[u8],\n        data: &[u8],\n        hash_alg: HashAlgorithm,\n        label: Option<&[u8]>,\n    ) -> Result<Vec<u8>, CryptoError> {\n        let private_key = RsaPrivateKey::from_pkcs1_der(private_key_der)\n            .map_err(|_| CryptoError::InvalidKey(None))?;\n\n        match hash_alg {\n            HashAlgorithm::Sha1 => {\n                let mut padding = Oaep::<Sha1>::new();\n                if let Some(l) = label {\n                    if !l.is_empty() {\n                        padding.label = Some(l.into());\n                    }\n                }\n                private_key\n                    .decrypt(padding, data)\n                    .map_err(|_| CryptoError::DecryptionFailed(None))\n            },\n            HashAlgorithm::Sha256 => {\n                let mut padding = Oaep::<Sha256>::new();\n                if let Some(l) = label {\n                    if !l.is_empty() {\n                        padding.label = Some(l.into());\n                    }\n                }\n                private_key\n                    .decrypt(padding, data)\n                    .map_err(|_| CryptoError::DecryptionFailed(None))\n            },\n            HashAlgorithm::Sha384 => {\n                let mut padding = Oaep::<Sha384>::new();\n                if let Some(l) = label {\n                    if !l.is_empty() {\n                        padding.label = Some(l.into());\n                    }\n                }\n                private_key\n                    .decrypt(padding, data)\n                    .map_err(|_| CryptoError::DecryptionFailed(None))\n            },\n            HashAlgorithm::Sha512 => {\n                let mut padding = Oaep::<Sha512>::new();\n                if let Some(l) = label {\n                    if !l.is_empty() {\n                        padding.label = Some(l.into());\n                    }\n                }\n                private_key\n                    .decrypt(padding, data)\n                    .map_err(|_| CryptoError::DecryptionFailed(None))\n            },\n            _ => Err(CryptoError::UnsupportedAlgorithm),\n        }\n    }\n\n    fn ecdh_derive_bits(\n        &self,\n        curve: EllipticCurve,\n        private_key_der: &[u8],\n        public_key_sec1: &[u8],\n    ) -> Result<Vec<u8>, CryptoError> {\n        match curve {\n            EllipticCurve::P256 => {\n                let secret_key = P256SecretKey::from_pkcs8_der(private_key_der)\n                    .map_err(|_| CryptoError::InvalidKey(None))?;\n                let public_key = p256::PublicKey::from_sec1_bytes(public_key_sec1)\n                    .map_err(|_| CryptoError::InvalidKey(None))?;\n                let shared_secret = p256::elliptic_curve::ecdh::diffie_hellman(\n                    secret_key.to_nonzero_scalar(),\n                    public_key.as_affine(),\n                );\n                Ok(shared_secret.raw_secret_bytes().to_vec())\n            },\n            EllipticCurve::P384 => {\n                let secret_key = P384SecretKey::from_pkcs8_der(private_key_der)\n                    .map_err(|_| CryptoError::InvalidKey(None))?;\n                let public_key = p384::PublicKey::from_sec1_bytes(public_key_sec1)\n                    .map_err(|_| CryptoError::InvalidKey(None))?;\n                let shared_secret = p384::elliptic_curve::ecdh::diffie_hellman(\n                    secret_key.to_nonzero_scalar(),\n                    public_key.as_affine(),\n                );\n                Ok(shared_secret.raw_secret_bytes().to_vec())\n            },\n            EllipticCurve::P521 => {\n                let secret_key = P521SecretKey::from_pkcs8_der(private_key_der)\n                    .map_err(|_| CryptoError::InvalidKey(None))?;\n                let public_key = p521::PublicKey::from_sec1_bytes(public_key_sec1)\n                    .map_err(|_| CryptoError::InvalidKey(None))?;\n                let shared_secret = p521::elliptic_curve::ecdh::diffie_hellman(\n                    secret_key.to_nonzero_scalar(),\n                    public_key.as_affine(),\n                );\n                Ok(shared_secret.raw_secret_bytes().to_vec())\n            },\n        }\n    }\n\n    fn x25519_derive_bits(\n        &self,\n        private_key: &[u8],\n        public_key: &[u8],\n    ) -> Result<Vec<u8>, CryptoError> {\n        let private_array: [u8; 32] = private_key\n            .try_into()\n            .map_err(|_| CryptoError::InvalidKey(None))?;\n        let public_array: [u8; 32] = public_key\n            .try_into()\n            .map_err(|_| CryptoError::InvalidKey(None))?;\n\n        let secret_key = x25519_dalek::StaticSecret::from(private_array);\n        let public_key = x25519_dalek::PublicKey::from(public_array);\n        let shared_secret = secret_key.diffie_hellman(&public_key);\n\n        Ok(shared_secret.as_bytes().to_vec())\n    }\n\n    fn aes_encrypt(\n        &self,\n        mode: AesMode,\n        key: &[u8],\n        iv: &[u8],\n        data: &[u8],\n        additional_data: Option<&[u8]>,\n    ) -> Result<Vec<u8>, CryptoError> {\n        match mode {\n            AesMode::Cbc => match key.len() {\n                16 => {\n                    let encryptor = Encryptor::<aes::Aes128>::new_from_slices(key, iv)?;\n                    Ok(encryptor.encrypt_padded_vec::<Pkcs7>(data))\n                },\n                24 => {\n                    let encryptor = Encryptor::<aes::Aes192>::new_from_slices(key, iv)?;\n                    Ok(encryptor.encrypt_padded_vec::<Pkcs7>(data))\n                },\n                32 => {\n                    let encryptor = Encryptor::<aes::Aes256>::new_from_slices(key, iv)?;\n                    Ok(encryptor.encrypt_padded_vec::<Pkcs7>(data))\n                },\n                _ => Err(CryptoError::InvalidKey(None)),\n            },\n            AesMode::Ctr { counter_length } => {\n                let mut ciphertext = data.to_vec();\n                match (key.len(), counter_length) {\n                    (16, 32) => {\n                        let mut cipher = Ctr32BE::<aes::Aes128>::new_from_slices(key, iv)?;\n                        cipher.try_apply_keystream(&mut ciphertext)?;\n                    },\n                    (16, 64) => {\n                        let mut cipher = Ctr64BE::<aes::Aes128>::new_from_slices(key, iv)?;\n                        cipher.try_apply_keystream(&mut ciphertext)?;\n                    },\n                    (16, 128) => {\n                        let mut cipher = Ctr128BE::<aes::Aes128>::new_from_slices(key, iv)?;\n                        cipher.try_apply_keystream(&mut ciphertext)?;\n                    },\n                    (24, 32) => {\n                        let mut cipher = Ctr32BE::<aes::Aes192>::new_from_slices(key, iv)?;\n                        cipher.try_apply_keystream(&mut ciphertext)?;\n                    },\n                    (24, 64) => {\n                        let mut cipher = Ctr64BE::<aes::Aes192>::new_from_slices(key, iv)?;\n                        cipher.try_apply_keystream(&mut ciphertext)?;\n                    },\n                    (24, 128) => {\n                        let mut cipher = Ctr128BE::<aes::Aes192>::new_from_slices(key, iv)?;\n                        cipher.try_apply_keystream(&mut ciphertext)?;\n                    },\n                    (32, 32) => {\n                        let mut cipher = Ctr32BE::<aes::Aes256>::new_from_slices(key, iv)?;\n                        cipher.try_apply_keystream(&mut ciphertext)?;\n                    },\n                    (32, 64) => {\n                        let mut cipher = Ctr64BE::<aes::Aes256>::new_from_slices(key, iv)?;\n                        cipher.try_apply_keystream(&mut ciphertext)?;\n                    },\n                    (32, 128) => {\n                        let mut cipher = Ctr128BE::<aes::Aes256>::new_from_slices(key, iv)?;\n                        cipher.try_apply_keystream(&mut ciphertext)?;\n                    },\n                    _ => return Err(CryptoError::InvalidKey(None)),\n                }\n                Ok(ciphertext)\n            },\n            AesMode::Gcm { tag_length } => {\n                let variant = AesGcmVariant::new((key.len() * 8) as u16, tag_length, key)?;\n                let nonce: &Array<_, _> =\n                    &Nonce::<U12>::try_from(iv).map_err(|_| CryptoError::InvalidData(None))?;\n\n                let plaintext = Payload {\n                    msg: data,\n                    aad: additional_data.unwrap_or_default(),\n                };\n\n                match variant {\n                    AesGcmVariant::Aes128Gcm96(v) => v.encrypt(nonce, plaintext),\n                    AesGcmVariant::Aes192Gcm96(v) => v.encrypt(nonce, plaintext),\n                    AesGcmVariant::Aes256Gcm96(v) => v.encrypt(nonce, plaintext),\n                    AesGcmVariant::Aes128Gcm104(v) => v.encrypt(nonce, plaintext),\n                    AesGcmVariant::Aes192Gcm104(v) => v.encrypt(nonce, plaintext),\n                    AesGcmVariant::Aes256Gcm104(v) => v.encrypt(nonce, plaintext),\n                    AesGcmVariant::Aes128Gcm112(v) => v.encrypt(nonce, plaintext),\n                    AesGcmVariant::Aes192Gcm112(v) => v.encrypt(nonce, plaintext),\n                    AesGcmVariant::Aes256Gcm112(v) => v.encrypt(nonce, plaintext),\n                    AesGcmVariant::Aes128Gcm120(v) => v.encrypt(nonce, plaintext),\n                    AesGcmVariant::Aes192Gcm120(v) => v.encrypt(nonce, plaintext),\n                    AesGcmVariant::Aes256Gcm120(v) => v.encrypt(nonce, plaintext),\n                    AesGcmVariant::Aes128Gcm128(v) => v.encrypt(nonce, plaintext),\n                    AesGcmVariant::Aes192Gcm128(v) => v.encrypt(nonce, plaintext),\n                    AesGcmVariant::Aes256Gcm128(v) => v.encrypt(nonce, plaintext),\n                }\n                .map_err(|_| CryptoError::EncryptionFailed(None))\n            },\n        }\n    }\n\n    fn aes_decrypt(\n        &self,\n        mode: AesMode,\n        key: &[u8],\n        iv: &[u8],\n        data: &[u8],\n        additional_data: Option<&[u8]>,\n    ) -> Result<Vec<u8>, CryptoError> {\n        match mode {\n            AesMode::Cbc => match key.len() {\n                16 => {\n                    let decryptor = Decryptor::<aes::Aes128>::new_from_slices(key, iv)?;\n                    decryptor\n                        .decrypt_padded_vec::<Pkcs7>(data)\n                        .map_err(|_| CryptoError::DecryptionFailed(None))\n                },\n                24 => {\n                    let decryptor = Decryptor::<aes::Aes192>::new_from_slices(key, iv)?;\n                    decryptor\n                        .decrypt_padded_vec::<Pkcs7>(data)\n                        .map_err(|_| CryptoError::DecryptionFailed(None))\n                },\n                32 => {\n                    let decryptor = Decryptor::<aes::Aes256>::new_from_slices(key, iv)?;\n                    decryptor\n                        .decrypt_padded_vec::<Pkcs7>(data)\n                        .map_err(|_| CryptoError::DecryptionFailed(None))\n                },\n                _ => Err(CryptoError::InvalidKey(None)),\n            },\n            AesMode::Ctr { .. } => {\n                // CTR decryption is the same as encryption\n                self.aes_encrypt(mode, key, iv, data, additional_data)\n            },\n            AesMode::Gcm { tag_length } => {\n                let variant = AesGcmVariant::new((key.len() * 8) as u16, tag_length, key)?;\n                let nonce: &Array<_, _> =\n                    &Nonce::<U12>::try_from(iv).map_err(|_| CryptoError::InvalidData(None))?;\n\n                let ciphertext = Payload {\n                    msg: data,\n                    aad: additional_data.unwrap_or_default(),\n                };\n\n                match variant {\n                    AesGcmVariant::Aes128Gcm96(v) => v.decrypt(nonce, ciphertext),\n                    AesGcmVariant::Aes192Gcm96(v) => v.decrypt(nonce, ciphertext),\n                    AesGcmVariant::Aes256Gcm96(v) => v.decrypt(nonce, ciphertext),\n                    AesGcmVariant::Aes128Gcm104(v) => v.decrypt(nonce, ciphertext),\n                    AesGcmVariant::Aes192Gcm104(v) => v.decrypt(nonce, ciphertext),\n                    AesGcmVariant::Aes256Gcm104(v) => v.decrypt(nonce, ciphertext),\n                    AesGcmVariant::Aes128Gcm112(v) => v.decrypt(nonce, ciphertext),\n                    AesGcmVariant::Aes192Gcm112(v) => v.decrypt(nonce, ciphertext),\n                    AesGcmVariant::Aes256Gcm112(v) => v.decrypt(nonce, ciphertext),\n                    AesGcmVariant::Aes128Gcm120(v) => v.decrypt(nonce, ciphertext),\n                    AesGcmVariant::Aes192Gcm120(v) => v.decrypt(nonce, ciphertext),\n                    AesGcmVariant::Aes256Gcm120(v) => v.decrypt(nonce, ciphertext),\n                    AesGcmVariant::Aes128Gcm128(v) => v.decrypt(nonce, ciphertext),\n                    AesGcmVariant::Aes192Gcm128(v) => v.decrypt(nonce, ciphertext),\n                    AesGcmVariant::Aes256Gcm128(v) => v.decrypt(nonce, ciphertext),\n                }\n                .map_err(|_| CryptoError::DecryptionFailed(None))\n            },\n        }\n    }\n\n    fn aes_kw_wrap(&self, kek: &[u8], key: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        match kek.len() {\n            16 => {\n                let kw =\n                    KwAes128::new_from_slice(kek).map_err(|_| CryptoError::InvalidKey(None))?;\n                let mut buf = vec![0u8; key.len() + 8];\n                let result = kw\n                    .wrap_key(key, &mut buf)\n                    .map_err(|_| CryptoError::OperationFailed(None))?;\n                Ok(result.to_vec())\n            },\n            24 => {\n                let kw =\n                    KwAes192::new_from_slice(kek).map_err(|_| CryptoError::InvalidKey(None))?;\n                let mut buf = vec![0u8; key.len() + 8];\n                let result = kw\n                    .wrap_key(key, &mut buf)\n                    .map_err(|_| CryptoError::OperationFailed(None))?;\n                Ok(result.to_vec())\n            },\n            32 => {\n                let kw =\n                    KwAes256::new_from_slice(kek).map_err(|_| CryptoError::InvalidKey(None))?;\n                let mut buf = vec![0u8; key.len() + 8];\n                let result = kw\n                    .wrap_key(key, &mut buf)\n                    .map_err(|_| CryptoError::OperationFailed(None))?;\n                Ok(result.to_vec())\n            },\n            _ => Err(CryptoError::InvalidKey(None)),\n        }\n    }\n\n    fn aes_kw_unwrap(&self, kek: &[u8], wrapped_key: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        match kek.len() {\n            16 => {\n                let kw =\n                    KwAes128::new_from_slice(kek).map_err(|_| CryptoError::InvalidKey(None))?;\n                let mut buf = vec![0u8; wrapped_key.len()];\n                let result = kw\n                    .unwrap_key(wrapped_key, &mut buf)\n                    .map_err(|_| CryptoError::OperationFailed(None))?;\n                Ok(result.to_vec())\n            },\n            24 => {\n                let kw =\n                    KwAes192::new_from_slice(kek).map_err(|_| CryptoError::InvalidKey(None))?;\n                let mut buf = vec![0u8; wrapped_key.len()];\n                let result = kw\n                    .unwrap_key(wrapped_key, &mut buf)\n                    .map_err(|_| CryptoError::OperationFailed(None))?;\n                Ok(result.to_vec())\n            },\n            32 => {\n                let kw =\n                    KwAes256::new_from_slice(kek).map_err(|_| CryptoError::InvalidKey(None))?;\n                let mut buf = vec![0u8; wrapped_key.len()];\n                let result = kw\n                    .unwrap_key(wrapped_key, &mut buf)\n                    .map_err(|_| CryptoError::OperationFailed(None))?;\n                Ok(result.to_vec())\n            },\n            _ => Err(CryptoError::InvalidKey(None)),\n        }\n    }\n\n    fn hkdf_derive_key(\n        &self,\n        key: &[u8],\n        salt: &[u8],\n        info: &[u8],\n        length: usize,\n        hash_alg: HashAlgorithm,\n    ) -> Result<Vec<u8>, CryptoError> {\n        let mut out = vec![0u8; length];\n\n        match hash_alg {\n            HashAlgorithm::Sha1 => {\n                let prk = Hkdf::<Sha1>::new(Some(salt), key);\n                prk.expand(info, &mut out)\n            },\n            HashAlgorithm::Sha256 => {\n                let prk = Hkdf::<Sha256>::new(Some(salt), key);\n                prk.expand(info, &mut out)\n            },\n            HashAlgorithm::Sha384 => {\n                let prk = Hkdf::<Sha384>::new(Some(salt), key);\n                prk.expand(info, &mut out)\n            },\n            HashAlgorithm::Sha512 => {\n                let prk = Hkdf::<Sha512>::new(Some(salt), key);\n                prk.expand(info, &mut out)\n            },\n            _ => return Err(CryptoError::UnsupportedAlgorithm),\n        }\n        .map_err(|_| CryptoError::DerivationFailed(None))?;\n        Ok(out)\n    }\n\n    fn pbkdf2_derive_key(\n        &self,\n        password: &[u8],\n        salt: &[u8],\n        iterations: u32,\n        length: usize,\n        hash_alg: HashAlgorithm,\n    ) -> Result<Vec<u8>, CryptoError> {\n        let mut out = vec![0; length];\n        let iterations = NonZeroU32::new(iterations).ok_or(CryptoError::InvalidData(None))?;\n        match hash_alg {\n            HashAlgorithm::Sha1 => {\n                pbkdf2::<HmacImpl<Sha1>>(password, salt, iterations.get(), &mut out)\n            },\n            HashAlgorithm::Sha256 => {\n                pbkdf2::<HmacImpl<Sha256>>(password, salt, iterations.get(), &mut out)\n            },\n            HashAlgorithm::Sha384 => {\n                pbkdf2::<HmacImpl<Sha384>>(password, salt, iterations.get(), &mut out)\n            },\n            HashAlgorithm::Sha512 => {\n                pbkdf2::<HmacImpl<Sha512>>(password, salt, iterations.get(), &mut out)\n            },\n            _ => return Err(CryptoError::UnsupportedAlgorithm),\n        }\n        .map_err(|_| CryptoError::InvalidLength)?;\n        Ok(out)\n    }\n\n    fn generate_aes_key(&self, length_bits: u16) -> Result<Vec<u8>, CryptoError> {\n        let length_bytes = (length_bits / 8) as usize;\n        if !matches!(length_bits, 128 | 192 | 256) {\n            return Err(CryptoError::InvalidLength);\n        }\n        Ok(random_byte_array(length_bytes))\n    }\n\n    fn generate_hmac_key(\n        &self,\n        hash_alg: HashAlgorithm,\n        length_bits: u16,\n    ) -> Result<Vec<u8>, CryptoError> {\n        let length_bytes = if length_bits == 0 {\n            hash_alg.block_len()\n        } else {\n            (length_bits / 8) as usize\n        };\n\n        if length_bytes > 128 {\n            return Err(CryptoError::InvalidLength);\n        }\n\n        Ok(random_byte_array(length_bytes))\n    }\n\n    fn generate_ec_key(&self, curve: EllipticCurve) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {\n        let mut rng = rand::rng();\n\n        match curve {\n            EllipticCurve::P256 => {\n                let key = P256SecretKey::try_generate_from_rng(&mut rng)\n                    .map_err(|_| CryptoError::OperationFailed(None))?;\n                let pkcs8 = key\n                    .to_pkcs8_der()\n                    .map_err(|_| CryptoError::OperationFailed(None))?;\n                let private_key = pkcs8.as_bytes().to_vec();\n                let public_key = key.public_key().to_sec1_bytes().to_vec();\n                Ok((private_key, public_key))\n            },\n            EllipticCurve::P384 => {\n                let key = P384SecretKey::try_generate_from_rng(&mut rng)\n                    .map_err(|_| CryptoError::OperationFailed(None))?;\n                let pkcs8 = key\n                    .to_pkcs8_der()\n                    .map_err(|_| CryptoError::OperationFailed(None))?;\n                let private_key = pkcs8.as_bytes().to_vec();\n                let public_key = key.public_key().to_sec1_bytes().to_vec();\n                Ok((private_key, public_key))\n            },\n            EllipticCurve::P521 => {\n                let key = P521SecretKey::try_generate_from_rng(&mut rng)\n                    .map_err(|_| CryptoError::OperationFailed(None))?;\n                let pkcs8 = key\n                    .to_pkcs8_der()\n                    .map_err(|_| CryptoError::OperationFailed(None))?;\n                let private_key = pkcs8.as_bytes().to_vec();\n                let public_key = key.public_key().to_sec1_bytes().to_vec();\n                Ok((private_key, public_key))\n            },\n        }\n    }\n\n    fn generate_ed25519_key(&self) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {\n        let mut rng = rand::rng();\n        let private_key = ed25519_dalek::SigningKey::generate(&mut rng)\n            .to_pkcs8_der()\n            .map_err(|_| CryptoError::OperationFailed(None))?\n            .as_bytes()\n            .to_vec();\n        let signing_key = ed25519_dalek::SigningKey::from_pkcs8_der(&private_key)\n            .map_err(|_| CryptoError::OperationFailed(None))?;\n        let public_key = signing_key.verifying_key().to_bytes().to_vec();\n        Ok((private_key, public_key))\n    }\n\n    fn generate_x25519_key(&self) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {\n        let mut rng = rand::rng();\n        let secret_key = x25519_dalek::StaticSecret::random_from_rng(&mut rng);\n        let private_key = secret_key.as_bytes().to_vec();\n        let public_key = x25519_dalek::PublicKey::from(&secret_key)\n            .as_bytes()\n            .to_vec();\n        Ok((private_key, public_key))\n    }\n\n    fn generate_rsa_key(\n        &self,\n        modulus_length: u32,\n        public_exponent: &[u8],\n    ) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {\n        let exponent: u64 = match public_exponent {\n            [0x01, 0x00, 0x01] => 65537,\n            [0x03] => 3,\n            bytes\n                if bytes.ends_with(&[0x03]) && bytes[..bytes.len() - 1].iter().all(|&b| b == 0) =>\n            {\n                3\n            },\n            _ => return Err(CryptoError::InvalidData(None)),\n        };\n\n        let exp = BoxedUint::from(exponent);\n        let mut rng = rand::rng();\n        let rsa_private_key = RsaPrivateKey::new_with_exp(&mut rng, modulus_length as usize, exp)\n            .map_err(|_| CryptoError::OperationFailed(None))?;\n\n        let public_key = rsa_private_key\n            .to_public_key()\n            .to_pkcs1_der()\n            .map_err(|_| CryptoError::OperationFailed(None))?;\n        let private_key = rsa_private_key\n            .to_pkcs1_der()\n            .map_err(|_| CryptoError::OperationFailed(None))?;\n\n        Ok((\n            private_key.as_bytes().to_vec(),\n            public_key.as_bytes().to_vec(),\n        ))\n    }\n\n    fn import_rsa_public_key_pkcs1(\n        &self,\n        der: &[u8],\n    ) -> Result<super::RsaImportResult, CryptoError> {\n        use der::Decode;\n        let public_key =\n            rsa::pkcs1::RsaPublicKey::from_der(der).map_err(|_| CryptoError::InvalidKey(None))?;\n        let modulus_length = public_key.modulus.as_bytes().len() * 8;\n        let public_exponent = public_key.public_exponent.as_bytes().to_vec();\n        let key_data = public_key\n            .to_der()\n            .map_err(|_| CryptoError::InvalidKey(None))?;\n        Ok(super::RsaImportResult {\n            key_data,\n            modulus_length: modulus_length as u32,\n            public_exponent,\n            is_private: false,\n        })\n    }\n\n    fn import_rsa_private_key_pkcs1(\n        &self,\n        der: &[u8],\n    ) -> Result<super::RsaImportResult, CryptoError> {\n        use der::Decode;\n        let private_key =\n            rsa::pkcs1::RsaPrivateKey::from_der(der).map_err(|_| CryptoError::InvalidKey(None))?;\n        let modulus_length = private_key.modulus.as_bytes().len() * 8;\n        let public_exponent = private_key.public_exponent.as_bytes().to_vec();\n        let key_data = private_key\n            .to_der()\n            .map_err(|_| CryptoError::InvalidKey(None))?;\n        Ok(super::RsaImportResult {\n            key_data,\n            modulus_length: modulus_length as u32,\n            public_exponent,\n            is_private: true,\n        })\n    }\n\n    fn import_rsa_public_key_spki(\n        &self,\n        der: &[u8],\n    ) -> Result<super::RsaImportResult, CryptoError> {\n        use der::Decode;\n        let spki = spki::SubjectPublicKeyInfoRef::try_from(der)\n            .map_err(|_| CryptoError::InvalidKey(None))?;\n        let public_key = rsa::pkcs1::RsaPublicKey::from_der(spki.subject_public_key.raw_bytes())\n            .map_err(|_| CryptoError::InvalidKey(None))?;\n        let modulus_length = public_key.modulus.as_bytes().len() * 8;\n        let public_exponent = public_key.public_exponent.as_bytes().to_vec();\n        let key_data = public_key\n            .to_der()\n            .map_err(|_| CryptoError::InvalidKey(None))?;\n        Ok(super::RsaImportResult {\n            key_data,\n            modulus_length: modulus_length as u32,\n            public_exponent,\n            is_private: false,\n        })\n    }\n\n    fn import_rsa_private_key_pkcs8(\n        &self,\n        der: &[u8],\n    ) -> Result<super::RsaImportResult, CryptoError> {\n        use der::Decode;\n        let pk_info =\n            pkcs8::PrivateKeyInfoRef::from_der(der).map_err(|_| CryptoError::InvalidKey(None))?;\n        let private_key = rsa::pkcs1::RsaPrivateKey::from_der(pk_info.private_key.as_bytes())\n            .map_err(|_| CryptoError::InvalidKey(None))?;\n        let modulus_length = private_key.modulus.as_bytes().len() * 8;\n        let public_exponent = private_key.public_exponent.as_bytes().to_vec();\n        let key_data = pk_info\n            .private_key\n            .to_der()\n            .map_err(|_| CryptoError::InvalidKey(None))?;\n        Ok(super::RsaImportResult {\n            key_data,\n            modulus_length: modulus_length as u32,\n            public_exponent,\n            is_private: true,\n        })\n    }\n\n    fn export_rsa_public_key_pkcs1(&self, key_data: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        // key_data is already PKCS1 DER\n        Ok(key_data.to_vec())\n    }\n\n    fn export_rsa_public_key_spki(&self, key_data: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        use der::{Decode, Encode};\n        let public_key = rsa::pkcs1::RsaPublicKey::from_der(key_data)\n            .map_err(|_| CryptoError::InvalidKey(None))?;\n        let spki = spki::SubjectPublicKeyInfo {\n            algorithm: spki::AlgorithmIdentifier::<der::asn1::Any> {\n                oid: const_oid::db::rfc5912::RSA_ENCRYPTION,\n                parameters: Some(der::asn1::Null.into()),\n            },\n            subject_public_key: spki::der::asn1::BitString::from_bytes(\n                &public_key\n                    .to_der()\n                    .map_err(|_| CryptoError::InvalidKey(None))?,\n            )\n            .map_err(|_| CryptoError::InvalidKey(None))?,\n        };\n        spki.to_der().map_err(|_| CryptoError::InvalidKey(None))\n    }\n\n    fn export_rsa_private_key_pkcs8(&self, key_data: &[u8]) -> Result<Vec<u8>, CryptoError> {\n        let private_key =\n            RsaPrivateKey::from_pkcs1_der(key_data).map_err(|_| CryptoError::InvalidKey(None))?;\n        private_key\n            .to_pkcs8_der()\n            .map(|doc| doc.as_bytes().to_vec())\n            .map_err(|_| CryptoError::InvalidKey(None))\n    }\n\n    fn import_ec_public_key_sec1(\n        &self,\n        data: &[u8],\n        _curve: EllipticCurve,\n    ) -> Result<super::EcImportResult, CryptoError> {\n        Ok(super::EcImportResult {\n            key_data: data.to_vec(),\n            is_private: false,\n        })\n    }\n\n    fn import_ec_public_key_spki(&self, der: &[u8]) -> Result<super::EcImportResult, CryptoError> {\n        let spki = spki::SubjectPublicKeyInfoRef::try_from(der)\n            .map_err(|_| CryptoError::InvalidKey(None))?;\n        Ok(super::EcImportResult {\n            key_data: spki.subject_public_key.raw_bytes().to_vec(),\n            is_private: false,\n        })\n    }\n\n    fn import_ec_private_key_pkcs8(\n        &self,\n        der: &[u8],\n    ) -> Result<super::EcImportResult, CryptoError> {\n        Ok(super::EcImportResult {\n            key_data: der.to_vec(),\n            is_private: true,\n        })\n    }\n\n    fn import_ec_private_key_sec1(\n        &self,\n        data: &[u8],\n        curve: EllipticCurve,\n    ) -> Result<super::EcImportResult, CryptoError> {\n        // Convert SEC1 private key to PKCS8\n        let pkcs8_der = match curve {\n            EllipticCurve::P256 => {\n                let key =\n                    P256SecretKey::from_slice(data).map_err(|_| CryptoError::InvalidKey(None))?;\n                key.to_pkcs8_der()\n                    .map_err(|_| CryptoError::InvalidKey(None))?\n                    .as_bytes()\n                    .to_vec()\n            },\n            EllipticCurve::P384 => {\n                let key =\n                    P384SecretKey::from_slice(data).map_err(|_| CryptoError::InvalidKey(None))?;\n                key.to_pkcs8_der()\n                    .map_err(|_| CryptoError::InvalidKey(None))?\n                    .as_bytes()\n                    .to_vec()\n            },\n            EllipticCurve::P521 => {\n                let key =\n                    P521SecretKey::from_slice(data).map_err(|_| CryptoError::InvalidKey(None))?;\n                key.to_pkcs8_der()\n                    .map_err(|_| CryptoError::InvalidKey(None))?\n                    .as_bytes()\n                    .to_vec()\n            },\n        };\n        Ok(super::EcImportResult {\n            key_data: pkcs8_der,\n            is_private: true,\n        })\n    }\n\n    fn export_ec_public_key_sec1(\n        &self,\n        key_data: &[u8],\n        curve: EllipticCurve,\n        is_private: bool,\n    ) -> Result<Vec<u8>, CryptoError> {\n        if is_private {\n            // Extract public key from PKCS8 private key\n            match curve {\n                EllipticCurve::P256 => {\n                    let key = P256SecretKey::from_pkcs8_der(key_data)\n                        .map_err(|_| CryptoError::InvalidKey(None))?;\n                    Ok(key.public_key().to_sec1_point(false).as_bytes().to_vec())\n                },\n                EllipticCurve::P384 => {\n                    let key = P384SecretKey::from_pkcs8_der(key_data)\n                        .map_err(|_| CryptoError::InvalidKey(None))?;\n                    Ok(key.public_key().to_sec1_point(false).as_bytes().to_vec())\n                },\n                EllipticCurve::P521 => {\n                    let key = P521SecretKey::from_pkcs8_der(key_data)\n                        .map_err(|_| CryptoError::InvalidKey(None))?;\n                    Ok(key.public_key().to_sec1_point(false).as_bytes().to_vec())\n                },\n            }\n        } else {\n            // key_data is already SEC1 encoded\n            Ok(key_data.to_vec())\n        }\n    }\n\n    fn export_ec_public_key_spki(\n        &self,\n        key_data: &[u8],\n        curve: EllipticCurve,\n    ) -> Result<Vec<u8>, CryptoError> {\n        use der::Encode;\n        use elliptic_curve::pkcs8::AssociatedOid;\n        let curve_oid = match curve {\n            EllipticCurve::P256 => p256::NistP256::OID,\n            EllipticCurve::P384 => p384::NistP384::OID,\n            EllipticCurve::P521 => p521::NistP521::OID,\n        };\n        let spki = spki::SubjectPublicKeyInfo {\n            algorithm: spki::AlgorithmIdentifier::<der::asn1::ObjectIdentifier> {\n                oid: elliptic_curve::ALGORITHM_OID,\n                parameters: Some(curve_oid),\n            },\n            subject_public_key: spki::der::asn1::BitString::from_bytes(key_data)\n                .map_err(|_| CryptoError::InvalidKey(None))?,\n        };\n        spki.to_der().map_err(|_| CryptoError::InvalidKey(None))\n    }\n\n    fn export_ec_private_key_pkcs8(\n        &self,\n        key_data: &[u8],\n        _curve: EllipticCurve,\n    ) -> Result<Vec<u8>, CryptoError> {\n        // key_data is already PKCS8\n        Ok(key_data.to_vec())\n    }\n\n    fn import_okp_public_key_raw(\n        &self,\n        data: &[u8],\n    ) -> Result<super::OkpImportResult, CryptoError> {\n        if data.len() != 32 {\n            return Err(CryptoError::InvalidKey(None));\n        }\n        Ok(super::OkpImportResult {\n            key_data: data.to_vec(),\n            is_private: false,\n        })\n    }\n\n    fn import_okp_public_key_spki(\n        &self,\n        der: &[u8],\n        _expected_oid: &[u8],\n    ) -> Result<super::OkpImportResult, CryptoError> {\n        let spki = spki::SubjectPublicKeyInfoRef::try_from(der)\n            .map_err(|_| CryptoError::InvalidKey(None))?;\n        Ok(super::OkpImportResult {\n            key_data: spki.subject_public_key.raw_bytes().to_vec(),\n            is_private: false,\n        })\n    }\n\n    fn import_okp_private_key_pkcs8(\n        &self,\n        der: &[u8],\n        _expected_oid: &[u8],\n    ) -> Result<super::OkpImportResult, CryptoError> {\n        Ok(super::OkpImportResult {\n            key_data: der.to_vec(),\n            is_private: true,\n        })\n    }\n\n    fn export_okp_public_key_raw(\n        &self,\n        key_data: &[u8],\n        is_private: bool,\n    ) -> Result<Vec<u8>, CryptoError> {\n        if is_private {\n            // Extract public key from PKCS8 - for X25519/Ed25519\n            use der::Decode;\n            let pk_info = pkcs8::PrivateKeyInfoRef::from_der(key_data)\n                .map_err(|_| CryptoError::InvalidKey(None))?;\n            // The private key is wrapped in an OCTET STRING, skip the tag+length (2 bytes)\n            let private_key_bytes = pk_info.private_key.as_bytes();\n            let seed = if private_key_bytes.len() > 2 && private_key_bytes[0] == 0x04 {\n                &private_key_bytes[2..]\n            } else {\n                private_key_bytes\n            };\n            let bytes: [u8; 32] = seed.try_into().map_err(|_| CryptoError::InvalidKey(None))?;\n            let secret = x25519_dalek::StaticSecret::from(bytes);\n            let public = x25519_dalek::PublicKey::from(&secret);\n            Ok(public.as_bytes().to_vec())\n        } else {\n            Ok(key_data.to_vec())\n        }\n    }\n\n    fn export_okp_public_key_spki(\n        &self,\n        key_data: &[u8],\n        oid: &[u8],\n    ) -> Result<Vec<u8>, CryptoError> {\n        use der::Encode;\n        let oid = const_oid::ObjectIdentifier::from_bytes(oid)\n            .map_err(|_| CryptoError::InvalidKey(None))?;\n        let spki = spki::SubjectPublicKeyInfo {\n            algorithm: spki::AlgorithmIdentifierOwned {\n                oid,\n                parameters: None,\n            },\n            subject_public_key: spki::der::asn1::BitString::from_bytes(key_data)\n                .map_err(|_| CryptoError::InvalidKey(None))?,\n        };\n        spki.to_der().map_err(|_| CryptoError::InvalidKey(None))\n    }\n\n    fn export_okp_private_key_pkcs8(\n        &self,\n        key_data: &[u8],\n        _oid: &[u8],\n    ) -> Result<Vec<u8>, CryptoError> {\n        // key_data is already PKCS8\n        Ok(key_data.to_vec())\n    }\n\n    fn import_rsa_jwk(\n        &self,\n        jwk: super::RsaJwkImport<'_>,\n    ) -> Result<super::RsaImportResult, CryptoError> {\n        use der::{asn1::UintRef, Encode};\n        let modulus = UintRef::new(jwk.n).map_err(|_| CryptoError::InvalidKey(None))?;\n        let public_exponent = UintRef::new(jwk.e).map_err(|_| CryptoError::InvalidKey(None))?;\n        let modulus_length = (modulus.as_bytes().len() * 8) as u32;\n        let pub_exp_bytes = public_exponent.as_bytes().to_vec();\n\n        if let (Some(d), Some(p), Some(q), Some(dp), Some(dq), Some(qi)) =\n            (jwk.d, jwk.p, jwk.q, jwk.dp, jwk.dq, jwk.qi)\n        {\n            let private_key = rsa::pkcs1::RsaPrivateKey {\n                modulus,\n                public_exponent,\n                private_exponent: UintRef::new(d).map_err(|_| CryptoError::InvalidKey(None))?,\n                prime1: UintRef::new(p).map_err(|_| CryptoError::InvalidKey(None))?,\n                prime2: UintRef::new(q).map_err(|_| CryptoError::InvalidKey(None))?,\n                exponent1: UintRef::new(dp).map_err(|_| CryptoError::InvalidKey(None))?,\n                exponent2: UintRef::new(dq).map_err(|_| CryptoError::InvalidKey(None))?,\n                coefficient: UintRef::new(qi).map_err(|_| CryptoError::InvalidKey(None))?,\n                other_prime_infos: None,\n            };\n            Ok(super::RsaImportResult {\n                key_data: private_key\n                    .to_der()\n                    .map_err(|_| CryptoError::InvalidKey(None))?,\n                modulus_length,\n                public_exponent: pub_exp_bytes,\n                is_private: true,\n            })\n        } else {\n            let public_key = rsa::pkcs1::RsaPublicKey {\n                modulus,\n                public_exponent,\n            };\n            Ok(super::RsaImportResult {\n                key_data: public_key\n                    .to_der()\n                    .map_err(|_| CryptoError::InvalidKey(None))?,\n                modulus_length,\n                public_exponent: pub_exp_bytes,\n                is_private: false,\n            })\n        }\n    }\n\n    fn export_rsa_jwk(\n        &self,\n        key_data: &[u8],\n        is_private: bool,\n    ) -> Result<super::RsaJwkExport, CryptoError> {\n        use der::Decode;\n        if is_private {\n            let key = rsa::pkcs1::RsaPrivateKey::from_der(key_data)\n                .map_err(|_| CryptoError::InvalidKey(None))?;\n            Ok(super::RsaJwkExport {\n                n: key.modulus.as_bytes().to_vec(),\n                e: key.public_exponent.as_bytes().to_vec(),\n                d: Some(key.private_exponent.as_bytes().to_vec()),\n                p: Some(key.prime1.as_bytes().to_vec()),\n                q: Some(key.prime2.as_bytes().to_vec()),\n                dp: Some(key.exponent1.as_bytes().to_vec()),\n                dq: Some(key.exponent2.as_bytes().to_vec()),\n                qi: Some(key.coefficient.as_bytes().to_vec()),\n            })\n        } else {\n            let key = rsa::pkcs1::RsaPublicKey::from_der(key_data)\n                .map_err(|_| CryptoError::InvalidKey(None))?;\n            Ok(super::RsaJwkExport {\n                n: key.modulus.as_bytes().to_vec(),\n                e: key.public_exponent.as_bytes().to_vec(),\n                d: None,\n                p: None,\n                q: None,\n                dp: None,\n                dq: None,\n                qi: None,\n            })\n        }\n    }\n\n    fn import_ec_jwk(\n        &self,\n        jwk: super::EcJwkImport<'_>,\n        curve: EllipticCurve,\n    ) -> Result<super::EcImportResult, CryptoError> {\n        if let Some(d) = jwk.d {\n            // Private key - convert to PKCS8\n            let pkcs8_der = match curve {\n                EllipticCurve::P256 => {\n                    let key =\n                        P256SecretKey::from_slice(d).map_err(|_| CryptoError::InvalidKey(None))?;\n                    key.to_pkcs8_der()\n                        .map_err(|_| CryptoError::InvalidKey(None))?\n                        .as_bytes()\n                        .to_vec()\n                },\n                EllipticCurve::P384 => {\n                    let key =\n                        P384SecretKey::from_slice(d).map_err(|_| CryptoError::InvalidKey(None))?;\n                    key.to_pkcs8_der()\n                        .map_err(|_| CryptoError::InvalidKey(None))?\n                        .as_bytes()\n                        .to_vec()\n                },\n                EllipticCurve::P521 => {\n                    let key =\n                        P521SecretKey::from_slice(d).map_err(|_| CryptoError::InvalidKey(None))?;\n                    key.to_pkcs8_der()\n                        .map_err(|_| CryptoError::InvalidKey(None))?\n                        .as_bytes()\n                        .to_vec()\n                },\n            };\n            Ok(super::EcImportResult {\n                key_data: pkcs8_der,\n                is_private: true,\n            })\n        } else {\n            // Public key - encode as SEC1 uncompressed point\n            let mut point = Vec::with_capacity(1 + jwk.x.len() + jwk.y.len());\n            point.push(0x04); // uncompressed\n            point.extend_from_slice(jwk.x);\n            point.extend_from_slice(jwk.y);\n            Ok(super::EcImportResult {\n                key_data: point,\n                is_private: false,\n            })\n        }\n    }\n\n    fn export_ec_jwk(\n        &self,\n        key_data: &[u8],\n        curve: EllipticCurve,\n        is_private: bool,\n    ) -> Result<super::EcJwkExport, CryptoError> {\n        let coord_len = match curve {\n            EllipticCurve::P256 => 32,\n            EllipticCurve::P384 => 48,\n            EllipticCurve::P521 => 66,\n        };\n        if is_private {\n            // key_data is PKCS8 - use elliptic_curve's SecretKey to parse it\n            let (x, y, d) = match curve {\n                EllipticCurve::P256 => {\n                    let sk = P256SecretKey::from_pkcs8_der(key_data)\n                        .map_err(|_| CryptoError::InvalidKey(None))?;\n                    let pk = sk.public_key();\n                    let pt = pk.to_sec1_point(false);\n                    (\n                        pt.x().unwrap().to_vec(),\n                        pt.y().unwrap().to_vec(),\n                        sk.to_bytes().to_vec(),\n                    )\n                },\n                EllipticCurve::P384 => {\n                    let sk = P384SecretKey::from_pkcs8_der(key_data)\n                        .map_err(|_| CryptoError::InvalidKey(None))?;\n                    let pk = sk.public_key();\n                    let pt = pk.to_sec1_point(false);\n                    (\n                        pt.x().unwrap().to_vec(),\n                        pt.y().unwrap().to_vec(),\n                        sk.to_bytes().to_vec(),\n                    )\n                },\n                EllipticCurve::P521 => {\n                    let sk = P521SecretKey::from_pkcs8_der(key_data)\n                        .map_err(|_| CryptoError::InvalidKey(None))?;\n                    let pk = sk.public_key();\n                    let pt = pk.to_sec1_point(false);\n                    (\n                        pt.x().unwrap().to_vec(),\n                        pt.y().unwrap().to_vec(),\n                        sk.to_bytes().to_vec(),\n                    )\n                },\n            };\n            Ok(super::EcJwkExport { x, y, d: Some(d) })\n        } else {\n            // key_data is SEC1 uncompressed point (0x04 || x || y)\n            if key_data.len() != 1 + 2 * coord_len || key_data[0] != 0x04 {\n                return Err(CryptoError::InvalidKey(None));\n            }\n            let x = key_data[1..1 + coord_len].to_vec();\n            let y = key_data[1 + coord_len..].to_vec();\n            Ok(super::EcJwkExport { x, y, d: None })\n        }\n    }\n\n    fn import_okp_jwk(\n        &self,\n        jwk: super::OkpJwkImport<'_>,\n        is_ed25519: bool,\n    ) -> Result<super::OkpImportResult, CryptoError> {\n        if let Some(d) = jwk.d {\n            // Private key - for Ed25519 we need PKCS8, for X25519 we store raw\n            if is_ed25519 {\n                // Ed25519: construct PKCS8 from raw private key\n                use der::{\n                    asn1::{BitStringRef, OctetStringRef},\n                    Encode,\n                };\n                let pk_info = pkcs8::PrivateKeyInfoRef {\n                    algorithm: spki::AlgorithmIdentifier {\n                        oid: const_oid::db::rfc8410::ID_ED_25519,\n                        parameters: None,\n                    },\n                    private_key: OctetStringRef::new(d)\n                        .map_err(|_| CryptoError::InvalidKey(None))?,\n                    public_key: Some(\n                        BitStringRef::from_bytes(jwk.x)\n                            .map_err(|_| CryptoError::InvalidKey(None))?,\n                    ),\n                };\n                let der = pk_info\n                    .to_der()\n                    .map_err(|_| CryptoError::InvalidKey(None))?;\n                Ok(super::OkpImportResult {\n                    key_data: der,\n                    is_private: true,\n                })\n            } else {\n                // X25519: store raw 32-byte secret\n                Ok(super::OkpImportResult {\n                    key_data: d.to_vec(),\n                    is_private: true,\n                })\n            }\n        } else {\n            // Public key - store raw bytes\n            Ok(super::OkpImportResult {\n                key_data: jwk.x.to_vec(),\n                is_private: false,\n            })\n        }\n    }\n\n    fn export_okp_jwk(\n        &self,\n        key_data: &[u8],\n        is_private: bool,\n        is_ed25519: bool,\n    ) -> Result<super::OkpJwkExport, CryptoError> {\n        if is_private {\n            if is_ed25519 {\n                // Ed25519: key_data is PKCS8\n                use der::Decode;\n                let pk_info = pkcs8::PrivateKeyInfoRef::from_der(key_data)\n                    .map_err(|_| CryptoError::InvalidKey(None))?;\n                let d = pk_info.private_key.as_bytes();\n                let x = pk_info\n                    .public_key\n                    .ok_or(CryptoError::InvalidKey(None))?\n                    .raw_bytes()\n                    .to_vec();\n                Ok(super::OkpJwkExport {\n                    x,\n                    d: Some(d.to_vec()),\n                })\n            } else {\n                // X25519: key_data is raw 32-byte secret\n                let secret = x25519_dalek::StaticSecret::from(\n                    <[u8; 32]>::try_from(key_data).map_err(|_| CryptoError::InvalidKey(None))?,\n                );\n                let public = x25519_dalek::PublicKey::from(&secret);\n                Ok(super::OkpJwkExport {\n                    x: public.as_bytes().to_vec(),\n                    d: Some(key_data.to_vec()),\n                })\n            }\n        } else {\n            // Public key - key_data is raw bytes\n            Ok(super::OkpJwkExport {\n                x: key_data.to_vec(),\n                d: None,\n            })\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/subtle/crypto_key.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::rc::Rc;\n\nuse llrt_utils::str_enum;\nuse rquickjs::{\n    atom::PredefinedAtom,\n    class::{Trace, Tracer},\n    Ctx, Exception, Result, Value,\n};\n\nuse super::key_algorithm::KeyAlgorithm;\n\n#[derive(PartialEq, Clone, Copy)]\npub enum KeyKind {\n    Secret,\n    Private,\n    Public,\n}\n\nstr_enum!(KeyKind,Secret => \"secret\", Private => \"private\", Public => \"public\");\n\n#[rquickjs::class]\n#[derive(rquickjs::JsLifetime)]\npub struct CryptoKey {\n    pub kind: KeyKind,\n    pub extractable: bool,\n    pub algorithm: KeyAlgorithm,\n    pub name: Box<str>,\n    pub usages: Vec<String>,\n    pub handle: Rc<[u8]>,\n}\n\nimpl CryptoKey {\n    pub fn new<N, H>(\n        kind: KeyKind,\n        name: N,\n        extractable: bool,\n        algorithm: KeyAlgorithm,\n        usages: Vec<String>,\n        handle: H,\n    ) -> Self\n    where\n        N: Into<Box<str>>,\n        H: Into<Rc<[u8]>>,\n    {\n        Self {\n            kind,\n            extractable,\n            algorithm,\n            name: name.into(),\n            usages,\n            handle: handle.into(),\n        }\n    }\n}\n\nimpl<'js> Trace<'js> for CryptoKey {\n    fn trace<'a>(&self, _: Tracer<'a, 'js>) {}\n}\n\n#[rquickjs::methods]\nimpl CryptoKey {\n    #[qjs(constructor)]\n    fn constructor(ctx: Ctx<'_>) -> Result<Self> {\n        Err(Exception::throw_type(&ctx, \"Illegal constructor\"))\n    }\n\n    #[qjs(get, rename = \"type\")]\n    pub fn get_type(&self) -> &str {\n        self.kind.as_str()\n    }\n\n    #[qjs(get)]\n    pub fn extractable(&self) -> bool {\n        self.extractable\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    pub fn to_string_tag(&self) -> &'static str {\n        stringify!(CryptoKey)\n    }\n\n    #[qjs(get)]\n    pub fn algorithm<'js>(&self, ctx: Ctx<'js>) -> Result<Value<'js>> {\n        self.algorithm\n            .as_object(&ctx, self.name.as_ref())\n            .map(|a| a.into_value())\n    }\n\n    #[qjs(get)]\n    pub fn usages(&self) -> Vec<String> {\n        self.usages.clone()\n    }\n}\n\nimpl CryptoKey {\n    pub fn check_validity(&self, usage: &str) -> std::result::Result<(), String> {\n        for key in self.usages.iter() {\n            if key == usage {\n                return Ok(());\n            }\n        }\n        Err([\n            \"CryptoKey with '\",\n            self.name.as_ref(),\n            \"', doesn't support '\",\n            usage,\n            \"'\",\n        ]\n        .concat())\n    }\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/subtle/derive.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{Array, ArrayBuffer, Class, Ctx, Exception, Result, Value};\n\nuse crate::{provider::CryptoProvider, subtle::CryptoKey, CRYPTO_PROVIDER};\n\nuse super::{\n    algorithm_mismatch_error, algorithm_not_supported_error,\n    crypto_key::KeyKind,\n    derive_algorithm::DeriveAlgorithm,\n    key_algorithm::{\n        EcAlgorithm, KeyAlgorithm, KeyAlgorithmMode, KeyAlgorithmWithUsages, KeyDerivation,\n    },\n};\n\npub async fn subtle_derive_bits<'js>(\n    ctx: Ctx<'js>,\n    algorithm: DeriveAlgorithm,\n    base_key: Class<'js, CryptoKey>,\n    length: u32,\n) -> Result<ArrayBuffer<'js>> {\n    let base_key = base_key.borrow();\n    base_key.check_validity(\"deriveBits\").or_throw(&ctx)?;\n\n    let bytes = derive_bits(&ctx, &algorithm, &base_key, length)?;\n    ArrayBuffer::new(ctx, bytes)\n}\n\nfn derive_bits(\n    ctx: &Ctx<'_>,\n    algorithm: &DeriveAlgorithm,\n    base_key: &CryptoKey,\n    length: u32,\n) -> Result<Vec<u8>> {\n    match algorithm {\n        DeriveAlgorithm::Ecdh { curve, public_key } => {\n            if let KeyAlgorithm::Ec {\n                curve: base_key_curve,\n                algorithm,\n            } = &base_key.algorithm\n            {\n                if curve == base_key_curve\n                    && base_key.kind == KeyKind::Private\n                    && matches!(algorithm, EcAlgorithm::Ecdh)\n                {\n                    let handle = &base_key.handle;\n                    return CRYPTO_PROVIDER\n                        .ecdh_derive_bits(*curve, handle, public_key)\n                        .or_throw(ctx);\n                }\n                return Err(Exception::throw_message(\n                    ctx,\n                    \"ECDH curve must be same as baseKey\",\n                ));\n            }\n            algorithm_mismatch_error(ctx, \"ECDH\")\n        },\n        DeriveAlgorithm::X25519 { public_key } => {\n            if !matches!(base_key.algorithm, KeyAlgorithm::X25519) {\n                return algorithm_mismatch_error(ctx, \"X25519\");\n            }\n\n            CRYPTO_PROVIDER\n                .x25519_derive_bits(&base_key.handle, public_key)\n                .or_throw(ctx)\n        },\n        DeriveAlgorithm::Derive(KeyDerivation::Hkdf { hash, salt, info }) => {\n            if !matches!(base_key.algorithm, KeyAlgorithm::HkdfImport) {\n                return algorithm_mismatch_error(ctx, \"HKDF\");\n            }\n            let out_length = (length / 8).try_into().or_throw(ctx)?;\n            CRYPTO_PROVIDER\n                .hkdf_derive_key(&base_key.handle, salt, info, out_length, *hash)\n                .or_throw(ctx)\n        },\n        DeriveAlgorithm::Derive(KeyDerivation::Pbkdf2 {\n            hash,\n            salt,\n            iterations,\n        }) => {\n            if !matches!(base_key.algorithm, KeyAlgorithm::Pbkdf2Import) {\n                return algorithm_mismatch_error(ctx, \"PBKDF2\");\n            }\n            let out_length = (length / 8).try_into().or_throw(ctx)?;\n            CRYPTO_PROVIDER\n                .pbkdf2_derive_key(&base_key.handle, salt, *iterations, out_length, *hash)\n                .or_throw(ctx)\n        },\n    }\n}\n\npub async fn subtle_derive_key<'js>(\n    ctx: Ctx<'js>,\n    algorithm: DeriveAlgorithm,\n    base_key: Class<'js, CryptoKey>,\n    derived_key_algorithm: Value<'js>,\n    extractable: bool,\n    key_usages: Array<'js>,\n) -> Result<Class<'js, CryptoKey>> {\n    let KeyAlgorithmWithUsages {\n        algorithm: derived_key_algorithm,\n        name,\n        public_usages,\n        ..\n    } = KeyAlgorithm::from_js(\n        &ctx,\n        KeyAlgorithmMode::Derive,\n        derived_key_algorithm,\n        key_usages,\n    )?;\n\n    let length = match &derived_key_algorithm {\n        KeyAlgorithm::Aes { length } => *length,\n        KeyAlgorithm::Hmac { length, .. } => *length,\n        KeyAlgorithm::Derive { .. } => 0,\n        _ => {\n            return algorithm_not_supported_error(&ctx);\n        },\n    };\n\n    let base_key = &base_key.borrow();\n\n    let bytes = derive_bits(&ctx, &algorithm, base_key, length as u32)?;\n\n    let key = CryptoKey::new(\n        KeyKind::Secret,\n        name,\n        extractable,\n        derived_key_algorithm,\n        public_usages,\n        bytes,\n    );\n\n    Class::instance(ctx, key)\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/subtle/derive_algorithm.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::rc::Rc;\n\nuse llrt_utils::object::ObjectExt;\nuse rquickjs::{Class, Ctx, Exception, FromJs, Result, Value};\n\nuse super::{\n    algorithm_mismatch_error,\n    key_algorithm::{KeyAlgorithm, KeyDerivation},\n    CryptoKey, EllipticCurve,\n};\n\n#[derive(Debug)]\npub enum DeriveAlgorithm {\n    X25519 {\n        public_key: Rc<[u8]>,\n    },\n    Ecdh {\n        curve: EllipticCurve,\n        public_key: Rc<[u8]>,\n    },\n    Derive(KeyDerivation),\n}\n\nimpl<'js> FromJs<'js> for DeriveAlgorithm {\n    fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        let obj = value.into_object_or_throw(ctx, \"algorithm\")?;\n\n        let name: String = obj.get_required(\"name\", \"algorithm\")?;\n\n        Ok(match name.as_str() {\n            \"X25519\" => {\n                let public_key: Class<CryptoKey> = obj.get_required(\"public\", \"algorithm\")?;\n                let public_key = public_key.borrow();\n\n                if !matches!(public_key.algorithm, KeyAlgorithm::X25519) {\n                    return algorithm_mismatch_error(ctx, &name);\n                }\n\n                DeriveAlgorithm::X25519 {\n                    public_key: public_key.handle.clone(),\n                }\n            },\n            \"ECDH\" => {\n                let public_key: Class<CryptoKey> = obj.get_required(\"public\", \"algorithm\")?;\n                let public_key = public_key.borrow();\n\n                if let KeyAlgorithm::Ec { curve, .. } = &public_key.algorithm {\n                    DeriveAlgorithm::Ecdh {\n                        curve: *curve,\n                        public_key: public_key.handle.clone(),\n                    }\n                } else {\n                    return algorithm_mismatch_error(ctx, &name);\n                }\n            },\n            \"HKDF\" => DeriveAlgorithm::Derive(KeyDerivation::for_hkdf_object(ctx, obj)?),\n            \"PBKDF2\" => DeriveAlgorithm::Derive(KeyDerivation::for_pbkf2_object(&ctx, obj)?),\n            _ => {\n                return Err(Exception::throw_message(\n                    ctx,\n                    \"Algorithm 'name' must be X25519 | ECDH | HKDF | PBKDF2\",\n                ))\n            },\n        })\n    }\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/subtle/digest.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_utils::{bytes::ObjectBytes, object::ObjectExt, result::ResultExt};\nuse rquickjs::{ArrayBuffer, Ctx, Result, Value};\n\nuse crate::{\n    hash::HashAlgorithm,\n    provider::{CryptoProvider, SimpleDigest},\n    CRYPTO_PROVIDER,\n};\n\npub async fn subtle_digest<'js>(\n    ctx: Ctx<'js>,\n    algorithm: Value<'js>,\n    data: ObjectBytes<'js>,\n) -> Result<ArrayBuffer<'js>> {\n    let algorithm = if let Some(algorithm) = algorithm.as_string() {\n        algorithm.to_string().or_throw(&ctx)?\n    } else {\n        algorithm.get_required::<_, String>(\"name\", \"algorithm\")?\n    };\n\n    let hash_algorithm = HashAlgorithm::try_from(algorithm.as_str()).or_throw(&ctx)?;\n    let bytes = digest(&hash_algorithm, data.as_bytes(&ctx)?);\n    ArrayBuffer::new(ctx, bytes)\n}\n\npub fn digest(hash_algorithm: &HashAlgorithm, data: &[u8]) -> Vec<u8> {\n    let mut hasher = CRYPTO_PROVIDER.digest(*hash_algorithm);\n    hasher.update(data);\n    hasher.finalize()\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/subtle/encryption.rs",
    "content": "use std::borrow::Cow;\n\n// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_utils::{bytes::ObjectBytes, result::ResultExt};\n\nuse rquickjs::{ArrayBuffer, Class, Ctx, Exception, Result};\n\nuse crate::{\n    provider::{AesMode, CryptoProvider},\n    CRYPTO_PROVIDER,\n};\n\nuse super::{\n    algorithm_mismatch_error, encryption_algorithm::EncryptionAlgorithm,\n    key_algorithm::KeyAlgorithm, validate_aes_length, CryptoKey, EncryptionMode,\n};\n\npub async fn subtle_decrypt<'js>(\n    ctx: Ctx<'js>,\n    algorithm: EncryptionAlgorithm,\n    key: Class<'js, CryptoKey>,\n    data: ObjectBytes<'js>,\n) -> Result<ArrayBuffer<'js>> {\n    let key = key.borrow();\n    key.check_validity(\"decrypt\").or_throw(&ctx)?;\n    let bytes = encrypt_decrypt(\n        &ctx,\n        &algorithm,\n        &key,\n        data.as_bytes(&ctx)?,\n        EncryptionMode::Encryption,\n        EncryptionOperation::Decrypt,\n    )?;\n    ArrayBuffer::new(ctx, bytes)\n}\n\npub async fn subtle_encrypt<'js>(\n    ctx: Ctx<'js>,\n    algorithm: EncryptionAlgorithm,\n    key: Class<'js, CryptoKey>,\n    data: ObjectBytes<'js>,\n) -> Result<ArrayBuffer<'js>> {\n    let key = key.borrow();\n    key.check_validity(\"encrypt\").or_throw(&ctx)?;\n\n    let bytes = encrypt_decrypt(\n        &ctx,\n        &algorithm,\n        &key,\n        data.as_bytes(&ctx)?,\n        EncryptionMode::Encryption,\n        EncryptionOperation::Encrypt,\n    )?;\n    ArrayBuffer::new(ctx, bytes)\n}\n\npub enum EncryptionOperation {\n    Encrypt,\n    Decrypt,\n}\n\npub fn encrypt_decrypt(\n    ctx: &Ctx<'_>,\n    algorithm: &EncryptionAlgorithm,\n    key: &CryptoKey,\n    data: &[u8],\n    mode: EncryptionMode,\n    operation: EncryptionOperation,\n) -> Result<Vec<u8>> {\n    let handle = key.handle.as_ref();\n    let bytes = match algorithm {\n        EncryptionAlgorithm::AesCbc { iv } => {\n            validate_aes_length(ctx, key, handle, \"AES-CBC\")?;\n\n            match operation {\n                EncryptionOperation::Encrypt => CRYPTO_PROVIDER\n                    .aes_encrypt(AesMode::Cbc, handle, iv, data, None)\n                    .or_throw(ctx)?,\n                EncryptionOperation::Decrypt => CRYPTO_PROVIDER\n                    .aes_decrypt(AesMode::Cbc, handle, iv, data, None)\n                    .or_throw(ctx)?,\n            }\n        },\n        EncryptionAlgorithm::AesCtr {\n            counter,\n            length: encryption_length,\n        } => {\n            validate_aes_length(ctx, key, handle, \"AES-CTR\")?;\n            match operation {\n                EncryptionOperation::Encrypt => CRYPTO_PROVIDER\n                    .aes_encrypt(\n                        AesMode::Ctr {\n                            counter_length: *encryption_length,\n                        },\n                        handle,\n                        counter,\n                        data,\n                        None,\n                    )\n                    .or_throw(ctx)?,\n                EncryptionOperation::Decrypt => CRYPTO_PROVIDER\n                    .aes_decrypt(\n                        AesMode::Ctr {\n                            counter_length: *encryption_length,\n                        },\n                        handle,\n                        counter,\n                        data,\n                        None,\n                    )\n                    .or_throw(ctx)?,\n            }\n        },\n        EncryptionAlgorithm::AesGcm {\n            iv,\n            tag_length,\n            additional_data,\n        } => {\n            validate_aes_length(ctx, key, handle, \"AES-GCM\")?;\n            let aad = additional_data.as_deref();\n\n            match operation {\n                EncryptionOperation::Encrypt => CRYPTO_PROVIDER\n                    .aes_encrypt(\n                        AesMode::Gcm {\n                            tag_length: *tag_length,\n                        },\n                        handle,\n                        iv,\n                        data,\n                        aad,\n                    )\n                    .or_throw(ctx)?,\n                EncryptionOperation::Decrypt => {\n                    let tag_len = (*tag_length as usize) / 8;\n                    if data.len() < tag_len {\n                        return Err(Exception::throw_message(ctx, \"Invalid ciphertext length\"));\n                    }\n                    // Pass the full data (ciphertext + tag) to the decrypt function\n                    CRYPTO_PROVIDER\n                        .aes_decrypt(\n                            AesMode::Gcm {\n                                tag_length: *tag_length,\n                            },\n                            handle,\n                            iv,\n                            data,\n                            aad,\n                        )\n                        .or_throw(ctx)?\n                },\n            }\n        },\n        EncryptionAlgorithm::AesKw => {\n            let padding = match mode {\n                EncryptionMode::Encryption => {\n                    return Err(Exception::throw_message(\n                        ctx,\n                        \"AES-KW can only be used for wrapping keys\",\n                    ));\n                },\n                EncryptionMode::Wrapping(padding) => padding,\n            };\n\n            match operation {\n                EncryptionOperation::Encrypt => {\n                    // Pad data to multiple of 8 bytes if needed\n                    let mut padded_data = Cow::Borrowed(data);\n                    if !data.len().is_multiple_of(8) {\n                        let pad_len = 8 - (data.len() % 8);\n                        let mut padded = data.to_vec();\n                        padded.extend(std::iter::repeat_n(padding, pad_len));\n                        padded_data = Cow::Owned(padded)\n                    }\n                    CRYPTO_PROVIDER\n                        .aes_kw_wrap(handle, &padded_data)\n                        .or_throw(ctx)?\n                },\n                EncryptionOperation::Decrypt => {\n                    let unwrapped = CRYPTO_PROVIDER.aes_kw_unwrap(handle, data).or_throw(ctx)?;\n                    // Remove padding if present\n                    if padding != 0 {\n                        let trimmed: Vec<u8> = unwrapped\n                            .into_iter()\n                            .rev()\n                            .skip_while(|&b| b == padding)\n                            .collect::<Vec<_>>()\n                            .into_iter()\n                            .rev()\n                            .collect();\n                        trimmed\n                    } else {\n                        unwrapped\n                    }\n                },\n            }\n        },\n        EncryptionAlgorithm::RsaOaep { label } => {\n            let hash = match &key.algorithm {\n                KeyAlgorithm::Rsa { hash, .. } => hash,\n                _ => return algorithm_mismatch_error(ctx, \"RSA-OAEP\"),\n            };\n\n            match operation {\n                EncryptionOperation::Encrypt => CRYPTO_PROVIDER\n                    .rsa_oaep_encrypt(handle, data, *hash, label.as_deref())\n                    .or_throw(ctx)?,\n                EncryptionOperation::Decrypt => CRYPTO_PROVIDER\n                    .rsa_oaep_decrypt(handle, data, *hash, label.as_deref())\n                    .or_throw(ctx)?,\n            }\n        },\n    };\n    Ok(bytes)\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/subtle/encryption_algorithm.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_utils::{bytes::ObjectBytes, object::ObjectExt};\nuse rquickjs::{Ctx, Exception, FromJs, Result, Value};\n\nuse super::algorithm_not_supported_error;\n\n#[derive(Debug)]\npub enum EncryptionAlgorithm {\n    AesCbc {\n        iv: Box<[u8]>,\n    },\n    AesCtr {\n        counter: Box<[u8]>,\n        length: u32,\n    },\n    AesGcm {\n        iv: Box<[u8]>,\n        tag_length: u8,\n        additional_data: Option<Box<[u8]>>,\n    },\n    RsaOaep {\n        label: Option<Box<[u8]>>,\n    },\n    AesKw,\n}\n\nimpl<'js> FromJs<'js> for EncryptionAlgorithm {\n    fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        let obj = value.into_object_or_throw(ctx, \"algorithm\")?;\n\n        let name: String = obj.get_required(\"name\", \"algorithm\")?;\n\n        match name.as_str() {\n            \"AES-CBC\" => {\n                let iv = obj\n                    .get_required::<_, ObjectBytes>(\"iv\", \"algorithm\")?\n                    .into_bytes(ctx)?\n                    .into_boxed_slice();\n\n                if iv.len() != 16 {\n                    return Err(Exception::throw_message(\n                        ctx,\n                        \"invalid length of iv. Currently supported 16 bytes\",\n                    ));\n                }\n\n                Ok(EncryptionAlgorithm::AesCbc { iv })\n            },\n            \"AES-CTR\" => {\n                let counter = obj\n                    .get_required::<_, ObjectBytes>(\"counter\", \"algorithm\")?\n                    .into_bytes(ctx)?\n                    .into_boxed_slice();\n\n                let length = obj.get_required::<_, u32>(\"length\", \"algorithm\")?;\n\n                if !matches!(length, 32 | 64 | 128) {\n                    return Err(Exception::throw_message(\n                        ctx,\n                        \"invalid counter length. Currently supported 32/64/128 bits\",\n                    ));\n                }\n\n                Ok(EncryptionAlgorithm::AesCtr { counter, length })\n            },\n            \"AES-GCM\" => {\n                let iv = obj\n                    .get_required::<_, ObjectBytes>(\"iv\", \"algorithm\")?\n                    .into_bytes(ctx)?\n                    .into_boxed_slice();\n\n                //FIXME only 12? 96 maybe recommended?\n                if iv.len() != 12 {\n                    return Err(Exception::throw_type(\n                        ctx,\n                        \"invalid length of iv. Currently supported 12 bytes\",\n                    ));\n                }\n\n                let additional_data = obj\n                    .get_optional::<_, ObjectBytes>(\"additionalData\")?\n                    .map(|v| v.into_bytes(ctx))\n                    .transpose()?\n                    .map(|vec| vec.into_boxed_slice());\n\n                let tag_length = obj.get_optional::<_, u8>(\"tagLength\")?.unwrap_or(128);\n\n                //ensure tag length is supported using a match statement 32, 64, 96, 104, 112, 120, or 128\n                if !matches!(tag_length, 96 | 104 | 112 | 120 | 128) {\n                    return Err(Exception::throw_message(\n                        ctx,\n                        \"Invalid tagLength. Currently supported 96/104/112/120/128 bits\",\n                    ));\n                }\n\n                Ok(EncryptionAlgorithm::AesGcm {\n                    iv,\n                    additional_data,\n                    tag_length,\n                })\n            },\n            \"RSA-OAEP\" => {\n                let label = obj\n                    .get_optional::<_, ObjectBytes>(\"label\")?\n                    .map(|bytes| bytes.into_bytes(ctx))\n                    .transpose()?\n                    .map(|vec| vec.into_boxed_slice());\n\n                Ok(EncryptionAlgorithm::RsaOaep { label })\n            },\n            \"AES-KW\" => Ok(EncryptionAlgorithm::AesKw),\n            _ => algorithm_not_supported_error(ctx),\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/subtle/export_key.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\n//! Unified key export implementation using CryptoProvider trait.\n\nuse llrt_encoding::bytes_to_b64_url_safe_string;\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{ArrayBuffer, Class, Ctx, Exception, Object, Result};\n\nuse crate::provider::CryptoProvider;\nuse crate::CRYPTO_PROVIDER;\n\nuse super::{\n    crypto_key::KeyKind,\n    key_algorithm::{KeyAlgorithm, KeyFormat},\n    CryptoKey,\n};\n\npub fn algorithm_export_error<T>(ctx: &Ctx<'_>, algorithm: &str, format: &str) -> Result<T> {\n    Err(Exception::throw_message(\n        ctx,\n        &[\"Export of \", algorithm, \" as \", format, \" is not supported\"].concat(),\n    ))\n}\n\npub enum ExportOutput<'js> {\n    Bytes(Vec<u8>),\n    Object(Object<'js>),\n}\n\npub async fn subtle_export_key<'js>(\n    ctx: Ctx<'js>,\n    format: KeyFormat,\n    key: Class<'js, CryptoKey>,\n) -> Result<Object<'js>> {\n    let key = key.borrow();\n    let export = export_key(&ctx, format, &key)?;\n    Ok(match export {\n        ExportOutput::Bytes(bytes) => ArrayBuffer::new(ctx, bytes)?.into_object(),\n        ExportOutput::Object(object) => object,\n    })\n}\n\npub fn export_key<'js>(\n    ctx: &Ctx<'js>,\n    format: KeyFormat,\n    key: &CryptoKey,\n) -> Result<ExportOutput<'js>> {\n    if !key.extractable {\n        return Err(Exception::throw_type(\n            ctx,\n            \"The CryptoKey is non extractable\",\n        ));\n    }\n    let bytes = match format {\n        KeyFormat::Jwk => return Ok(ExportOutput::Object(export_jwk(ctx, key)?)),\n        KeyFormat::Raw => export_raw(ctx, key),\n        KeyFormat::Spki => export_spki(ctx, key),\n        KeyFormat::Pkcs8 => export_pkcs8(ctx, key),\n    }?;\n    Ok(ExportOutput::Bytes(bytes))\n}\n\nfn export_raw(ctx: &Ctx<'_>, key: &CryptoKey) -> Result<Vec<u8>> {\n    if key.kind == KeyKind::Private {\n        return Err(Exception::throw_type(\n            ctx,\n            \"Private Crypto keys can't be exported as raw format\",\n        ));\n    }\n    match &key.algorithm {\n        KeyAlgorithm::Aes { .. } | KeyAlgorithm::Hmac { .. } => Ok(key.handle.to_vec()),\n        KeyAlgorithm::Ec { curve, .. } => CRYPTO_PROVIDER\n            .export_ec_public_key_sec1(&key.handle, *curve, false)\n            .or_throw(ctx),\n        KeyAlgorithm::Ed25519 => CRYPTO_PROVIDER\n            .export_okp_public_key_raw(&key.handle, false)\n            .or_throw(ctx),\n        KeyAlgorithm::X25519 => CRYPTO_PROVIDER\n            .export_okp_public_key_raw(&key.handle, false)\n            .or_throw(ctx),\n        KeyAlgorithm::Rsa { .. } => CRYPTO_PROVIDER\n            .export_rsa_public_key_pkcs1(&key.handle)\n            .or_throw(ctx),\n        _ => algorithm_export_error(ctx, &key.name, \"raw\"),\n    }\n}\n\nfn export_pkcs8(ctx: &Ctx<'_>, key: &CryptoKey) -> Result<Vec<u8>> {\n    if key.kind != KeyKind::Private {\n        return Err(Exception::throw_type(\n            ctx,\n            \"Public or Secret Crypto keys can't be exported as pkcs8 format\",\n        ));\n    }\n    match &key.algorithm {\n        KeyAlgorithm::Ec { curve, .. } => CRYPTO_PROVIDER\n            .export_ec_private_key_pkcs8(&key.handle, *curve)\n            .or_throw(ctx),\n        KeyAlgorithm::Ed25519 => CRYPTO_PROVIDER\n            .export_okp_private_key_pkcs8(\n                &key.handle,\n                const_oid::db::rfc8410::ID_ED_25519.as_bytes(),\n            )\n            .or_throw(ctx),\n        KeyAlgorithm::X25519 => CRYPTO_PROVIDER\n            .export_okp_private_key_pkcs8(\n                &key.handle,\n                const_oid::db::rfc8410::ID_X_25519.as_bytes(),\n            )\n            .or_throw(ctx),\n        KeyAlgorithm::Rsa { .. } => CRYPTO_PROVIDER\n            .export_rsa_private_key_pkcs8(&key.handle)\n            .or_throw(ctx),\n        _ => algorithm_export_error(ctx, &key.name, \"pkcs8\"),\n    }\n}\n\nfn export_spki(ctx: &Ctx<'_>, key: &CryptoKey) -> Result<Vec<u8>> {\n    if key.kind != KeyKind::Public {\n        return Err(Exception::throw_type(\n            ctx,\n            \"Private or Secret Crypto keys can't be exported as spki format\",\n        ));\n    }\n    match &key.algorithm {\n        KeyAlgorithm::Ec { curve, .. } => CRYPTO_PROVIDER\n            .export_ec_public_key_spki(&key.handle, *curve)\n            .or_throw(ctx),\n        KeyAlgorithm::Ed25519 => CRYPTO_PROVIDER\n            .export_okp_public_key_spki(&key.handle, const_oid::db::rfc8410::ID_ED_25519.as_bytes())\n            .or_throw(ctx),\n        KeyAlgorithm::X25519 => CRYPTO_PROVIDER\n            .export_okp_public_key_spki(&key.handle, const_oid::db::rfc8410::ID_X_25519.as_bytes())\n            .or_throw(ctx),\n        KeyAlgorithm::Rsa { .. } => CRYPTO_PROVIDER\n            .export_rsa_public_key_spki(&key.handle)\n            .or_throw(ctx),\n        _ => algorithm_export_error(ctx, &key.name, \"spki\"),\n    }\n}\n\nfn export_jwk<'js>(ctx: &Ctx<'js>, key: &CryptoKey) -> Result<Object<'js>> {\n    let obj = Object::new(ctx.clone())?;\n    obj.set(\"key_ops\", key.usages())?;\n    obj.set(\"ext\", true)?;\n\n    match &key.algorithm {\n        KeyAlgorithm::Aes { length } => {\n            let prefix = match length {\n                128 => \"A128\",\n                192 => \"A192\",\n                256 => \"A256\",\n                _ => unreachable!(),\n            };\n            let suffix = &key.name[(\"AES-\".len())..];\n            obj.set(\"kty\", \"oct\")?;\n            obj.set(\"k\", bytes_to_b64_url_safe_string(&key.handle))?;\n            obj.set(\"alg\", [prefix, suffix].concat())?;\n        },\n        KeyAlgorithm::Hmac { hash, .. } => {\n            obj.set(\"kty\", \"oct\")?;\n            obj.set(\"alg\", [\"HS\", &hash.as_str()[4..]].concat())?;\n            obj.set(\"k\", bytes_to_b64_url_safe_string(&key.handle))?;\n        },\n        KeyAlgorithm::Ec { curve, .. } => {\n            let jwk = CRYPTO_PROVIDER\n                .export_ec_jwk(&key.handle, *curve, key.kind == KeyKind::Private)\n                .or_throw(ctx)?;\n            obj.set(\"kty\", \"EC\")?;\n            obj.set(\"crv\", curve.as_str())?;\n            obj.set(\"x\", bytes_to_b64_url_safe_string(&jwk.x))?;\n            obj.set(\"y\", bytes_to_b64_url_safe_string(&jwk.y))?;\n            if let Some(d) = jwk.d {\n                obj.set(\"d\", bytes_to_b64_url_safe_string(&d))?;\n            }\n        },\n        KeyAlgorithm::Ed25519 => {\n            let jwk = CRYPTO_PROVIDER\n                .export_okp_jwk(&key.handle, key.kind == KeyKind::Private, true)\n                .or_throw(ctx)?;\n            obj.set(\"kty\", \"OKP\")?;\n            obj.set(\"crv\", \"Ed25519\")?;\n            obj.set(\"x\", bytes_to_b64_url_safe_string(&jwk.x))?;\n            if let Some(d) = jwk.d {\n                obj.set(\"d\", bytes_to_b64_url_safe_string(&d))?;\n            }\n        },\n        KeyAlgorithm::X25519 => {\n            let jwk = CRYPTO_PROVIDER\n                .export_okp_jwk(&key.handle, key.kind == KeyKind::Private, false)\n                .or_throw(ctx)?;\n            obj.set(\"kty\", \"OKP\")?;\n            obj.set(\"crv\", \"X25519\")?;\n            obj.set(\"x\", bytes_to_b64_url_safe_string(&jwk.x))?;\n            if let Some(d) = jwk.d {\n                obj.set(\"d\", bytes_to_b64_url_safe_string(&d))?;\n            }\n        },\n        KeyAlgorithm::Rsa { hash, .. } => {\n            let jwk = CRYPTO_PROVIDER\n                .export_rsa_jwk(&key.handle, key.kind == KeyKind::Private)\n                .or_throw(ctx)?;\n            let alg_suffix = hash.as_numeric_str();\n            let alg_prefix = match key.name.as_ref() {\n                \"RSASSA-PKCS1-v1_5\" => \"RS\",\n                \"RSA-PSS\" => \"PS\",\n                \"RSA-OAEP\" => \"RSA-OAEP-\",\n                _ => unreachable!(),\n            };\n            obj.set(\"kty\", \"RSA\")?;\n            obj.set(\"n\", bytes_to_b64_url_safe_string(&jwk.n))?;\n            obj.set(\"e\", bytes_to_b64_url_safe_string(&jwk.e))?;\n            obj.set(\"alg\", [alg_prefix, alg_suffix].concat())?;\n            if let Some(d) = jwk.d {\n                obj.set(\"d\", bytes_to_b64_url_safe_string(&d))?;\n                obj.set(\"p\", bytes_to_b64_url_safe_string(&jwk.p.unwrap()))?;\n                obj.set(\"q\", bytes_to_b64_url_safe_string(&jwk.q.unwrap()))?;\n                obj.set(\"dp\", bytes_to_b64_url_safe_string(&jwk.dp.unwrap()))?;\n                obj.set(\"dq\", bytes_to_b64_url_safe_string(&jwk.dq.unwrap()))?;\n                obj.set(\"qi\", bytes_to_b64_url_safe_string(&jwk.qi.unwrap()))?;\n            }\n        },\n        _ => return algorithm_export_error(ctx, &key.name, \"jwk\"),\n    }\n    Ok(obj)\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/subtle/generate_key.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse rquickjs::{object::Property, Array, Class, Ctx, Exception, Object, Result, Value};\n\nuse crate::{provider::CryptoProvider, CRYPTO_PROVIDER};\n\nuse crate::{hash::HashAlgorithm, subtle::CryptoKey};\n\nuse super::{\n    algorithm_not_supported_error,\n    crypto_key::KeyKind,\n    key_algorithm::{KeyAlgorithm, KeyAlgorithmMode, KeyAlgorithmWithUsages},\n};\n\npub async fn subtle_generate_key<'js>(\n    ctx: Ctx<'js>,\n    algorithm: Value<'js>,\n    extractable: bool,\n    key_usages: Array<'js>,\n) -> Result<Value<'js>> {\n    let KeyAlgorithmWithUsages {\n        name,\n        algorithm: key_algorithm,\n        private_usages,\n        public_usages,\n    } = KeyAlgorithm::from_js(&ctx, KeyAlgorithmMode::Generate, algorithm, key_usages)?;\n\n    let (private_key, public_or_secret_key) = generate_key(&ctx, &key_algorithm)?;\n\n    if matches!(\n        key_algorithm,\n        KeyAlgorithm::Aes { .. } | KeyAlgorithm::Hmac { .. }\n    ) {\n        return Ok(Class::instance(\n            ctx,\n            CryptoKey::new(\n                KeyKind::Secret,\n                name,\n                extractable,\n                key_algorithm,\n                public_usages,\n                public_or_secret_key,\n            ),\n        )?\n        .into_value());\n    }\n\n    let private_key = Class::instance(\n        ctx.clone(),\n        CryptoKey::new(\n            KeyKind::Private,\n            name.clone(),\n            extractable,\n            key_algorithm.clone(),\n            private_usages,\n            private_key,\n        ),\n    )?;\n\n    let public_key = Class::instance(\n        ctx.clone(),\n        CryptoKey::new(\n            KeyKind::Public,\n            name,\n            extractable,\n            key_algorithm,\n            public_usages,\n            public_or_secret_key,\n        ),\n    )?;\n\n    let key_pair = Object::new(ctx.clone())?;\n    key_pair.prop(\"privateKey\", Property::from(private_key).enumerable())?;\n    key_pair.prop(\"publicKey\", Property::from(public_key).enumerable())?;\n    Ok(key_pair.into_value())\n}\n\nfn generate_key(ctx: &Ctx<'_>, algorithm: &KeyAlgorithm) -> Result<(Vec<u8>, Vec<u8>)> {\n    match algorithm {\n        KeyAlgorithm::Aes { length } => {\n            // Default to AES-256\n            let key = CRYPTO_PROVIDER.generate_aes_key(*length).map_err(|e| {\n                Exception::throw_message(ctx, &format!(\"AES key generation failed: {}\", e))\n            })?;\n            Ok((vec![], key))\n        },\n        KeyAlgorithm::Hmac { hash, length } => {\n            let key = CRYPTO_PROVIDER\n                .generate_hmac_key(*hash, *length)\n                .map_err(|e| {\n                    Exception::throw_message(ctx, &format!(\"HMAC key generation failed: {}\", e))\n                })?;\n            Ok((vec![], key))\n        },\n        KeyAlgorithm::Ec { curve, .. } => CRYPTO_PROVIDER.generate_ec_key(*curve).map_err(|e| {\n            Exception::throw_message(ctx, &format!(\"EC key generation failed: {}\", e))\n        }),\n        KeyAlgorithm::Ed25519 => CRYPTO_PROVIDER.generate_ed25519_key().map_err(|e| {\n            Exception::throw_message(ctx, &format!(\"Ed25519 key generation failed: {}\", e))\n        }),\n        KeyAlgorithm::X25519 => CRYPTO_PROVIDER.generate_x25519_key().map_err(|e| {\n            Exception::throw_message(ctx, &format!(\"X25519 key generation failed: {}\", e))\n        }),\n        KeyAlgorithm::Rsa {\n            modulus_length,\n            public_exponent,\n            ..\n        } => CRYPTO_PROVIDER\n            .generate_rsa_key(*modulus_length, public_exponent.as_ref())\n            .map_err(|e| {\n                Exception::throw_message(ctx, &format!(\"RSA key generation failed: {}\", e))\n            }),\n        _ => algorithm_not_supported_error(ctx),\n    }\n}\n\n#[allow(dead_code)]\nfn generate_symmetric_key(_ctx: &Ctx<'_>, length: usize) -> Result<Vec<u8>> {\n    Ok(crate::random_byte_array(length))\n}\n\n#[allow(dead_code)]\npub fn get_hash_length(ctx: &Ctx, hash: &HashAlgorithm, length: u16) -> Result<usize> {\n    if length == 0 {\n        return Ok(hash.block_len());\n    }\n\n    if !length.is_multiple_of(8) || (length / 8) as usize > 128 {\n        return Err(Exception::throw_message(ctx, \"Invalid HMAC key length\"));\n    }\n\n    Ok((length / 8) as usize)\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/subtle/import_key.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_utils::{bytes::ObjectBytes, object::ObjectExt};\nuse rquickjs::{Array, Class, Ctx, FromJs, Result, Value};\n\nuse crate::subtle::CryptoKey;\n\nuse super::{\n    crypto_key::KeyKind,\n    key_algorithm::{\n        KeyAlgorithm, KeyAlgorithmMode, KeyAlgorithmWithUsages, KeyFormat, KeyFormatData,\n    },\n};\n\npub async fn subtle_import_key<'js>(\n    ctx: Ctx<'js>,\n    format: KeyFormat,\n    key_data: Value<'js>,\n    algorithm: Value<'js>,\n    extractable: bool,\n    key_usages: Array<'js>,\n) -> Result<Class<'js, CryptoKey>> {\n    let format = match format {\n        KeyFormat::Raw => KeyFormatData::Raw(ObjectBytes::from_js(&ctx, key_data)?),\n        KeyFormat::Pkcs8 => KeyFormatData::Pkcs8(ObjectBytes::from_js(&ctx, key_data)?),\n        KeyFormat::Spki => KeyFormatData::Spki(ObjectBytes::from_js(&ctx, key_data)?),\n        KeyFormat::Jwk => KeyFormatData::Jwk(key_data.into_object_or_throw(&ctx, \"keyData\")?),\n    };\n\n    import_key(ctx, format, algorithm, extractable, key_usages)\n}\n\npub fn import_key<'js>(\n    ctx: Ctx<'js>,\n    format: KeyFormatData<'js>,\n    algorithm: Value<'js>,\n    extractable: bool,\n    key_usages: Array<'js>,\n) -> Result<Class<'js, CryptoKey>> {\n    let mut kind = KeyKind::Public;\n    let mut data = Vec::new();\n\n    let KeyAlgorithmWithUsages {\n        name,\n        algorithm: key_algorithm,\n        public_usages,\n        private_usages,\n    } = KeyAlgorithm::from_js(\n        &ctx,\n        KeyAlgorithmMode::Import {\n            kind: &mut kind,\n            data: &mut data,\n            format,\n        },\n        algorithm,\n        key_usages,\n    )?;\n\n    let usages = match kind {\n        KeyKind::Public | KeyKind::Secret => public_usages,\n        KeyKind::Private => private_usages,\n    };\n\n    Class::instance(\n        ctx,\n        CryptoKey::new(kind, name, extractable, key_algorithm, usages, data),\n    )\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/subtle/key_algorithm.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#![allow(clippy::uninlined_format_args)]\n\nuse std::rc::Rc;\n\n#[cfg(feature = \"_subtle-full\")]\nuse der::{asn1::OctetStringRef, Decode, Encode};\n#[cfg(feature = \"_subtle-full\")]\nuse llrt_encoding::bytes_from_b64_url_safe;\nuse llrt_utils::{bytes::ObjectBytes, object::ObjectExt, result::ResultExt, str_enum};\n#[cfg(feature = \"_subtle-full\")]\nuse pkcs8::PrivateKeyInfoRef;\nuse rquickjs::{\n    atom::PredefinedAtom, Array, Ctx, Exception, FromJs, Object, Result, TypedArray, Value,\n};\n#[cfg(feature = \"_subtle-full\")]\nuse spki::{AlgorithmIdentifier, ObjectIdentifier};\n\nuse crate::hash::HashAlgorithm;\n\n#[cfg(feature = \"_subtle-full\")]\nuse super::algorithm_mismatch_error;\nuse super::{\n    algorithm_not_supported_error, crypto_key::KeyKind, to_name_and_maybe_object, EllipticCurve,\n};\n\n#[derive(Clone, Copy, PartialEq)]\npub enum KeyUsage {\n    //7 values, can be max 255 (u8) 0b11111111\n    Encrypt,\n    Decrypt,\n    WrapKey,\n    UnwrapKey,\n    Sign,\n    Verify,\n    DeriveKey,\n    DeriveBits,\n}\n\nimpl TryFrom<&str> for KeyUsage {\n    type Error = String;\n\n    fn try_from(s: &str) -> std::result::Result<Self, Self::Error> {\n        Ok(match s {\n            \"encrypt\" => KeyUsage::Encrypt,\n            \"decrypt\" => KeyUsage::Decrypt,\n            \"wrapKey\" => KeyUsage::WrapKey,\n            \"unwrapKey\" => KeyUsage::UnwrapKey,\n            \"sign\" => KeyUsage::Sign,\n            \"verify\" => KeyUsage::Verify,\n            \"deriveKey\" => KeyUsage::DeriveKey,\n            \"deriveBits\" => KeyUsage::DeriveBits,\n            _ => return Err([\"Invalid key usage: \", s].concat()),\n        })\n    }\n}\n\nimpl KeyUsage {\n    fn classify_and_check_usages<'js>(\n        ctx: &Ctx<'js>,\n        key_usage_algorithm: KeyUsageAlgorithm,\n        key_usages: &Array<'js>,\n        private_usages: &mut Vec<String>,\n        public_usages: &mut Vec<String>,\n        kind: Option<&KeyKind>,\n    ) -> Result<()> {\n        let (mut private_usages_mask, mut public_usages_mask) = key_usage_algorithm.masks();\n\n        match kind {\n            Some(KeyKind::Private) => public_usages_mask = 0,\n            Some(KeyKind::Secret) | Some(KeyKind::Public) => private_usages_mask = 0,\n            None => {},\n        };\n\n        let allowed_usages = private_usages_mask | public_usages_mask;\n\n        let mut generated_public_usages = Vec::with_capacity(4);\n        let mut generated_private_usages = Vec::with_capacity(4);\n\n        let mut has_any_usages = false;\n\n        for usage in key_usages.iter::<String>() {\n            has_any_usages = true;\n            let value = usage?;\n            let usage = KeyUsage::try_from(value.as_str()).or_throw(ctx)?;\n            let usage = usage.mask();\n            if allowed_usages & usage != usage {\n                return Err(Exception::throw_message(\n                    ctx,\n                    &[\"Invalid key usage '\", &value, \"'\"].concat(),\n                ));\n            }\n\n            if private_usages_mask == public_usages_mask {\n                generated_private_usages.push(value.clone());\n                generated_public_usages.push(value);\n            } else if private_usages_mask & usage == usage {\n                generated_private_usages.push(value);\n            } else if public_usages_mask & usage == usage {\n                generated_public_usages.push(value);\n            }\n        }\n\n        *private_usages = generated_private_usages;\n        *public_usages = generated_public_usages;\n\n        if !has_any_usages {\n            return Err(Exception::throw_message(ctx, \"Key usages empty\"));\n        }\n\n        if private_usages_mask > 0 && private_usages.is_empty() {\n            return Err(Exception::throw_message(\n                ctx,\n                \"No required private key usages provided\",\n            ));\n        }\n\n        if private_usages != public_usages {\n            let valid_usage = match kind {\n                Some(KeyKind::Secret) | Some(KeyKind::Public) => {\n                    private_usages.is_empty() && !public_usages.is_empty()\n                },\n                Some(KeyKind::Private) => !private_usages.is_empty() && public_usages.is_empty(),\n                None => true,\n            };\n\n            if !valid_usage {\n                return Err(Exception::throw_message(ctx, \"Invalid key usage\"));\n            }\n        }\n\n        Ok(())\n    }\n\n    const fn mask(self) -> u16 {\n        1 << self as u16\n    }\n}\n\n#[repr(u16)]\n#[derive(Clone, Copy)]\npub enum KeyUsageAlgorithm {\n    //single mask algorithms (symmetric)\n    AesKw = KeyUsage::WrapKey.mask() | KeyUsage::UnwrapKey.mask(),\n    //all non-KW AES\n    Symmetric = (KeyUsage::Encrypt.mask())\n        | (KeyUsage::Decrypt.mask())\n        | (KeyUsage::WrapKey.mask())\n        | (KeyUsage::UnwrapKey.mask()),\n\n    Hmac = (KeyUsage::Sign.mask()) | (KeyUsage::Verify.mask()),\n\n    //two mask algorithms (asymmetric) - use high bits as for private, low bits for public\n    //HKDF, PBKDF2, X25519\n    Derive = ((KeyUsage::DeriveKey.mask() | KeyUsage::DeriveBits.mask()) << 8)\n        | KeyUsage::DeriveKey.mask()\n        | KeyUsage::DeriveBits.mask(),\n\n    RsaOaep = ((KeyUsage::Decrypt.mask() | KeyUsage::UnwrapKey.mask()) << 8) //private\n    | KeyUsage::Encrypt.mask() | KeyUsage::WrapKey.mask(), //public\n\n    //ECDSA, ED25519, all non-OEAP RSA\n    Sign = (KeyUsage::Sign.mask() << 8) //private\n        | KeyUsage::Verify.mask(), //public\n}\nimpl KeyUsageAlgorithm {\n    fn masks(&self) -> (u16, u16) {\n        let value = *self as u16;\n        let private_mask = value >> 8;\n        let public_mask = value & 0xFF;\n        (private_mask, public_mask)\n    }\n}\n\n#[derive(Debug, Clone)]\npub enum KeyDerivation {\n    Hkdf {\n        hash: HashAlgorithm,\n        salt: Box<[u8]>,\n        info: Box<[u8]>,\n    },\n    Pbkdf2 {\n        hash: HashAlgorithm,\n        salt: Box<[u8]>,\n        iterations: u32,\n    },\n}\n\nimpl KeyDerivation {\n    pub fn for_hkdf_object<'js>(ctx: &Ctx<'js>, obj: Object<'js>) -> Result<Self> {\n        let hash = extract_sha_hash(ctx, &obj)?;\n\n        let salt = obj\n            .get_required::<_, ObjectBytes>(\"salt\", \"algorithm\")?\n            .into_bytes(ctx)?\n            .into_boxed_slice();\n\n        let info = obj\n            .get_required::<_, ObjectBytes>(\"info\", \"algorithm\")?\n            .into_bytes(ctx)?\n            .into_boxed_slice();\n\n        Ok(KeyDerivation::Hkdf { hash, salt, info })\n    }\n\n    pub fn for_pbkf2_object<'js>(ctx: &&Ctx<'js>, obj: Object<'js>) -> Result<Self> {\n        let hash = extract_sha_hash(ctx, &obj)?;\n\n        let salt = obj\n            .get_required::<_, ObjectBytes>(\"salt\", \"algorithm\")?\n            .into_bytes(ctx)?\n            .into_boxed_slice();\n\n        let iterations = obj.get_required(\"iterations\", \"algorithm\")?;\n        Ok(KeyDerivation::Pbkdf2 {\n            hash,\n            salt,\n            iterations,\n        })\n    }\n}\n\n#[derive(Debug, Clone)]\npub enum EcAlgorithm {\n    Ecdh,\n    Ecdsa,\n}\n\n#[derive(Debug, Clone)]\npub enum KeyAlgorithm {\n    Aes {\n        length: u16,\n    },\n    Ec {\n        curve: EllipticCurve,\n        algorithm: EcAlgorithm,\n    },\n    X25519,\n    Ed25519,\n    Hmac {\n        hash: HashAlgorithm,\n        length: u16,\n    },\n    Rsa {\n        modulus_length: u32,\n        public_exponent: Rc<Box<[u8]>>,\n        hash: HashAlgorithm,\n    },\n    Derive(KeyDerivation),\n    HkdfImport,\n    Pbkdf2Import,\n}\n\npub enum KeyFormat {\n    Jwk,\n    Raw,\n    Spki,\n    Pkcs8,\n}\n\nstr_enum!(KeyFormat, Jwk => \"jwk\", Raw => \"raw\", Spki => \"spki\", Pkcs8 => \"pkcs8\");\n\nimpl<'js> FromJs<'js> for KeyFormat {\n    fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        if let Some(string) = value.as_string() {\n            let string = string.to_string()?;\n            match string.as_str() {\n                \"jwk\" => return Ok(KeyFormat::Jwk),\n                \"raw\" => return Ok(KeyFormat::Raw),\n                \"spki\" => return Ok(KeyFormat::Spki),\n                \"pkcs8\" => return Ok(KeyFormat::Pkcs8),\n                _ => {},\n            };\n        }\n        Err(Exception::throw_message(\n            ctx,\n            \"Key import/export format must be 'jwk','raw','spki' or 'pkcs8'\",\n        ))\n    }\n}\n\npub enum KeyFormatData<'js> {\n    Jwk(Object<'js>),\n    Raw(ObjectBytes<'js>),\n    Spki(ObjectBytes<'js>),\n    Pkcs8(ObjectBytes<'js>),\n}\n\npub enum KeyAlgorithmMode<'a, 'js> {\n    Import {\n        format: KeyFormatData<'js>,\n        kind: &'a mut KeyKind,\n        data: &'a mut Vec<u8>,\n    },\n    Generate,\n    Derive,\n}\n\npub struct KeyAlgorithmWithUsages {\n    pub name: String,\n    pub algorithm: KeyAlgorithm,\n    pub public_usages: Vec<String>,\n    pub private_usages: Vec<String>,\n}\n\nfn from_ed25519<'js>(\n    ctx: &Ctx<'js>,\n    mode: KeyAlgorithmMode<'_, 'js>,\n    algorithm_name: &str,\n    usages: &Array<'js>,\n    private_usages: &mut Vec<String>,\n    public_usages: &mut Vec<String>,\n) -> Result<KeyAlgorithm> {\n    #[cfg(feature = \"_subtle-full\")]\n    #[inline]\n    fn import<'js>(\n        ctx: &Ctx<'js>,\n        mode: KeyAlgorithmMode<'_, 'js>,\n        algorithm_name: &str,\n    ) -> Result<Option<KeyKind>> {\n        if let KeyAlgorithmMode::Import { format, kind, data } = mode {\n            import_okp_key(\n                ctx,\n                format,\n                kind,\n                data,\n                const_oid::db::rfc8410::ID_ED_25519,\n                algorithm_name,\n            )?;\n            Ok(Some(*kind))\n        } else {\n            Ok(None)\n        }\n    }\n\n    #[cfg(not(feature = \"_subtle-full\"))]\n    #[inline]\n    fn import<'js>(\n        _ctx: &Ctx<'js>,\n        _mode: KeyAlgorithmMode<'_, 'js>,\n        _algorithm_name: &str,\n    ) -> Result<Option<KeyKind>> {\n        Ok(None)\n    }\n\n    let key_kind = import(ctx, mode, algorithm_name)?;\n    KeyUsage::classify_and_check_usages(\n        ctx,\n        KeyUsageAlgorithm::Sign,\n        usages,\n        private_usages,\n        public_usages,\n        key_kind.as_ref(),\n    )?;\n    Ok(KeyAlgorithm::Ed25519)\n}\n\nfn from_x25519<'js>(\n    ctx: &Ctx<'js>,\n    mode: KeyAlgorithmMode<'_, 'js>,\n    algorithm_name: &str,\n    usages: &Array<'js>,\n    private_usages: &mut Vec<String>,\n    public_usages: &mut Vec<String>,\n) -> Result<KeyAlgorithm> {\n    #[cfg(feature = \"_subtle-full\")]\n    #[inline]\n    fn import<'js>(\n        ctx: &Ctx<'js>,\n        mode: KeyAlgorithmMode<'_, 'js>,\n        algorithm_name: &str,\n    ) -> Result<Option<KeyKind>> {\n        if let KeyAlgorithmMode::Import { format, kind, data } = mode {\n            import_okp_key(\n                ctx,\n                format,\n                kind,\n                data,\n                const_oid::db::rfc8410::ID_X_25519,\n                algorithm_name,\n            )?;\n            Ok(Some(*kind))\n        } else {\n            Ok(None)\n        }\n    }\n\n    #[cfg(not(feature = \"_subtle-full\"))]\n    #[inline]\n    fn import<'js>(\n        _ctx: &Ctx<'js>,\n        _mode: KeyAlgorithmMode<'_, 'js>,\n        _algorithm_name: &str,\n    ) -> Result<Option<KeyKind>> {\n        Ok(None)\n    }\n\n    let key_kind = import(ctx, mode, algorithm_name)?;\n    KeyUsage::classify_and_check_usages(\n        ctx,\n        KeyUsageAlgorithm::Derive,\n        usages,\n        private_usages,\n        public_usages,\n        key_kind.as_ref(),\n    )?;\n    Ok(KeyAlgorithm::X25519)\n}\n\nfn from_aes<'js>(\n    ctx: &Ctx<'js>,\n    mode: KeyAlgorithmMode<'_, 'js>,\n    obj: std::result::Result<Object<'js>, &str>,\n    algorithm_name: &str,\n    usages: &Array<'js>,\n    private_usages: &mut Vec<String>,\n    public_usages: &mut Vec<String>,\n) -> Result<KeyAlgorithm> {\n    #[cfg(feature = \"_subtle-full\")]\n    #[inline]\n    fn import<'js>(\n        ctx: &Ctx<'js>,\n        mode: KeyAlgorithmMode<'_, 'js>,\n        obj: std::result::Result<Object<'js>, &str>,\n        algorithm_name: &str,\n    ) -> Result<(u16, Option<KeyKind>)> {\n        if let KeyAlgorithmMode::Import { data, format, kind } = mode {\n            let length =\n                import_symmetric_key(ctx, format, kind, data, algorithm_name, None)? as u16;\n            Ok((length, Some(*kind)))\n        } else {\n            let length: u16 = obj.or_throw(ctx)?.get_required(\"length\", \"algorithm\")?;\n            Ok((length, None))\n        }\n    }\n\n    #[cfg(not(feature = \"_subtle-full\"))]\n    #[inline]\n    fn import<'js>(\n        ctx: &Ctx<'js>,\n        _mode: KeyAlgorithmMode<'_, 'js>,\n        obj: std::result::Result<Object<'js>, &str>,\n        _algorithm_name: &str,\n    ) -> Result<(u16, Option<KeyKind>)> {\n        let length: u16 = obj.or_throw(ctx)?.get_required(\"length\", \"algorithm\")?;\n        Ok((length, None))\n    }\n\n    let (length, key_kind) = import(ctx, mode, obj, algorithm_name)?;\n\n    if !matches!(length, 128 | 192 | 256) {\n        return Err(Exception::throw_message(\n            ctx,\n            &format!(\n                \"Algorithm 'length' must be one of: 128, 192, or 256 = {}\",\n                length\n            ),\n        ));\n    }\n\n    KeyUsage::classify_and_check_usages(\n        ctx,\n        if algorithm_name == \"AES-KW\" {\n            KeyUsageAlgorithm::AesKw\n        } else {\n            KeyUsageAlgorithm::Symmetric\n        },\n        usages,\n        private_usages,\n        public_usages,\n        key_kind.as_ref(),\n    )?;\n\n    Ok(KeyAlgorithm::Aes { length })\n}\n\nfn from_hmac<'js>(\n    ctx: &Ctx<'js>,\n    mode: KeyAlgorithmMode<'_, 'js>,\n    obj: std::result::Result<Object<'js>, &str>,\n    algorithm_name: &str,\n    usages: &Array<'js>,\n    private_usages: &mut Vec<String>,\n    public_usages: &mut Vec<String>,\n) -> Result<KeyAlgorithm> {\n    let obj = obj.or_throw(ctx)?;\n    let hash = extract_sha_hash(ctx, &obj)?;\n    let mut length: u16 = obj.get_optional(\"length\")?.unwrap_or_default();\n\n    #[cfg(feature = \"_subtle-full\")]\n    #[inline]\n    fn import<'js>(\n        ctx: &Ctx<'js>,\n        mode: KeyAlgorithmMode<'_, 'js>,\n        algorithm_name: &str,\n        hash: &HashAlgorithm,\n        length: &mut u16,\n    ) -> Result<Option<KeyKind>> {\n        if let KeyAlgorithmMode::Import { data, format, kind } = mode {\n            let data_length =\n                import_symmetric_key(ctx, format, kind, data, algorithm_name, Some(hash))?;\n            if *length == 0 {\n                *length = data_length as u16;\n            }\n            Ok(Some(*kind))\n        } else {\n            Ok(None)\n        }\n    }\n\n    #[cfg(not(feature = \"_subtle-full\"))]\n    #[inline]\n    fn import<'js>(\n        _ctx: &Ctx<'js>,\n        _mode: KeyAlgorithmMode<'_, 'js>,\n        _algorithm_name: &str,\n        _hash: &HashAlgorithm,\n        _length: &mut u16,\n    ) -> Result<Option<KeyKind>> {\n        Ok(None)\n    }\n\n    let key_kind = import(ctx, mode, algorithm_name, &hash, &mut length)?;\n\n    KeyUsage::classify_and_check_usages(\n        ctx,\n        KeyUsageAlgorithm::Hmac,\n        usages,\n        private_usages,\n        public_usages,\n        key_kind.as_ref(),\n    )?;\n\n    Ok(KeyAlgorithm::Hmac { hash, length })\n}\n\nfn from_rsa<'js>(\n    ctx: &Ctx<'js>,\n    mode: KeyAlgorithmMode<'_, 'js>,\n    obj: std::result::Result<Object<'js>, &str>,\n    algorithm_name: &str,\n    usages: &Array<'js>,\n    private_usages: &mut Vec<String>,\n    public_usages: &mut Vec<String>,\n) -> Result<KeyAlgorithm> {\n    let obj = obj.or_throw(ctx)?;\n    let hash = extract_sha_hash(ctx, &obj)?;\n\n    #[cfg(feature = \"_subtle-full\")]\n    #[inline]\n    fn import<'js>(\n        ctx: &Ctx<'js>,\n        mode: KeyAlgorithmMode<'_, 'js>,\n        obj: &Object<'js>,\n        algorithm_name: &str,\n        hash: &HashAlgorithm,\n    ) -> Result<(u32, Box<[u8]>, Option<KeyKind>)> {\n        if let KeyAlgorithmMode::Import { format, kind, data } = mode {\n            let (mod_length, exp) = import_rsa_key(ctx, format, kind, data, algorithm_name, hash)?;\n            Ok((mod_length, exp, Some(*kind)))\n        } else {\n            let modulus_length = obj.get_required(\"modulusLength\", \"algorithm\")?;\n            let public_exponent: TypedArray<u8> =\n                obj.get_required(\"publicExponent\", \"algorithm\")?;\n            let public_exponent = public_exponent\n                .as_bytes()\n                .ok_or_else(|| Exception::throw_message(ctx, \"Array buffer has been detached\"))?\n                .to_owned()\n                .into_boxed_slice();\n            Ok((modulus_length, public_exponent, None))\n        }\n    }\n\n    #[cfg(not(feature = \"_subtle-full\"))]\n    #[inline]\n    fn import<'js>(\n        ctx: &Ctx<'js>,\n        _mode: KeyAlgorithmMode<'_, 'js>,\n        obj: &Object<'js>,\n        _algorithm_name: &str,\n        _hash: &HashAlgorithm,\n    ) -> Result<(u32, Box<[u8]>, Option<KeyKind>)> {\n        let modulus_length = obj.get_required(\"modulusLength\", \"algorithm\")?;\n        let public_exponent: TypedArray<u8> = obj.get_required(\"publicExponent\", \"algorithm\")?;\n        let public_exponent = public_exponent\n            .as_bytes()\n            .ok_or_else(|| Exception::throw_message(ctx, \"Array buffer has been detached\"))?\n            .to_owned()\n            .into_boxed_slice();\n        Ok((modulus_length, public_exponent, None))\n    }\n\n    let (modulus_length, public_exponent, key_kind) =\n        import(ctx, mode, &obj, algorithm_name, &hash)?;\n\n    KeyUsage::classify_and_check_usages(\n        ctx,\n        if algorithm_name == \"RSA-OAEP\" {\n            KeyUsageAlgorithm::RsaOaep\n        } else {\n            KeyUsageAlgorithm::Sign\n        },\n        usages,\n        private_usages,\n        public_usages,\n        key_kind.as_ref(),\n    )?;\n\n    Ok(KeyAlgorithm::Rsa {\n        modulus_length,\n        public_exponent: Rc::new(public_exponent),\n        hash,\n    })\n}\n\nfn from_hkdf<'js>(\n    ctx: &Ctx<'js>,\n    mode: KeyAlgorithmMode<'_, 'js>,\n    obj: std::result::Result<Object<'js>, &str>,\n    algorithm_name: &str,\n    usages: &Array<'js>,\n    private_usages: &mut Vec<String>,\n    public_usages: &mut Vec<String>,\n) -> Result<KeyAlgorithm> {\n    #[cfg(feature = \"_subtle-full\")]\n    #[inline]\n    fn import<'js>(\n        ctx: &Ctx<'js>,\n        mode: KeyAlgorithmMode<'_, 'js>,\n        obj: std::result::Result<Object<'js>, &str>,\n        algorithm_name: &str,\n    ) -> Result<(KeyAlgorithm, Option<KeyKind>)> {\n        match mode {\n            KeyAlgorithmMode::Import { format, kind, data } => {\n                import_derive_key(ctx, format, kind, data, algorithm_name)?;\n                Ok((KeyAlgorithm::HkdfImport, Some(*kind)))\n            },\n            KeyAlgorithmMode::Derive => {\n                let obj = obj.or_throw(ctx)?;\n                Ok((\n                    KeyAlgorithm::Derive(KeyDerivation::for_hkdf_object(ctx, obj)?),\n                    None,\n                ))\n            },\n            _ => algorithm_not_supported_error(ctx),\n        }\n    }\n\n    #[cfg(not(feature = \"_subtle-full\"))]\n    #[inline]\n    fn import<'js>(\n        ctx: &Ctx<'js>,\n        mode: KeyAlgorithmMode<'_, 'js>,\n        obj: std::result::Result<Object<'js>, &str>,\n        _algorithm_name: &str,\n    ) -> Result<(KeyAlgorithm, Option<KeyKind>)> {\n        match mode {\n            KeyAlgorithmMode::Derive => {\n                let obj = obj.or_throw(ctx)?;\n                Ok((\n                    KeyAlgorithm::Derive(KeyDerivation::for_hkdf_object(ctx, obj)?),\n                    None,\n                ))\n            },\n            _ => algorithm_not_supported_error(ctx),\n        }\n    }\n\n    let (algorithm, key_kind) = import(ctx, mode, obj, algorithm_name)?;\n\n    KeyUsage::classify_and_check_usages(\n        ctx,\n        KeyUsageAlgorithm::Derive,\n        usages,\n        private_usages,\n        public_usages,\n        key_kind.as_ref(),\n    )?;\n\n    Ok(algorithm)\n}\n\nfn from_pbkdf2<'js>(\n    ctx: &Ctx<'js>,\n    mode: KeyAlgorithmMode<'_, 'js>,\n    obj: std::result::Result<Object<'js>, &str>,\n    algorithm_name: &str,\n    usages: &Array<'js>,\n    private_usages: &mut Vec<String>,\n    public_usages: &mut Vec<String>,\n) -> Result<KeyAlgorithm> {\n    #[cfg(feature = \"_subtle-full\")]\n    #[inline]\n    fn import<'js>(\n        ctx: &Ctx<'js>,\n        mode: KeyAlgorithmMode<'_, 'js>,\n        obj: std::result::Result<Object<'js>, &str>,\n        algorithm_name: &str,\n    ) -> Result<(KeyAlgorithm, Option<KeyKind>)> {\n        match mode {\n            KeyAlgorithmMode::Import { format, kind, data } => {\n                import_derive_key(ctx, format, kind, data, algorithm_name)?;\n                Ok((KeyAlgorithm::Pbkdf2Import, Some(*kind)))\n            },\n            KeyAlgorithmMode::Derive => {\n                let obj = obj.or_throw(ctx)?;\n                Ok((\n                    KeyAlgorithm::Derive(KeyDerivation::for_pbkf2_object(&ctx, obj)?),\n                    None,\n                ))\n            },\n            _ => algorithm_not_supported_error(ctx),\n        }\n    }\n\n    #[cfg(not(feature = \"_subtle-full\"))]\n    #[inline]\n    fn import<'js>(\n        ctx: &Ctx<'js>,\n        mode: KeyAlgorithmMode<'_, 'js>,\n        obj: std::result::Result<Object<'js>, &str>,\n        _algorithm_name: &str,\n    ) -> Result<(KeyAlgorithm, Option<KeyKind>)> {\n        match mode {\n            KeyAlgorithmMode::Derive => {\n                let obj = obj.or_throw(ctx)?;\n                Ok((\n                    KeyAlgorithm::Derive(KeyDerivation::for_pbkf2_object(&ctx, obj)?),\n                    None,\n                ))\n            },\n            _ => algorithm_not_supported_error(ctx),\n        }\n    }\n\n    let (algorithm, key_kind) = import(ctx, mode, obj, algorithm_name)?;\n\n    KeyUsage::classify_and_check_usages(\n        ctx,\n        KeyUsageAlgorithm::Derive,\n        usages,\n        private_usages,\n        public_usages,\n        key_kind.as_ref(),\n    )?;\n\n    Ok(algorithm)\n}\n\nimpl KeyAlgorithm {\n    pub fn from_js<'js>(\n        ctx: &Ctx<'js>,\n        mode: KeyAlgorithmMode<'_, 'js>,\n        value: Value<'js>,\n        usages: Array<'js>,\n    ) -> Result<KeyAlgorithmWithUsages> {\n        // When _subtle-full is not enabled, Import mode is not supported\n        #[cfg(not(feature = \"_subtle-full\"))]\n        if matches!(mode, KeyAlgorithmMode::Import { .. }) {\n            return Err(Exception::throw_message(\n                ctx,\n                \"Key import is not supported with this crypto provider\",\n            ));\n        }\n\n        let (name, obj) = to_name_and_maybe_object(ctx, value)?;\n        let mut public_usages = vec![];\n        let mut private_usages = vec![];\n        let algorithm_name = name.as_str();\n        let algorithm = match algorithm_name {\n            \"Ed25519\" => from_ed25519(\n                ctx,\n                mode,\n                algorithm_name,\n                &usages,\n                &mut private_usages,\n                &mut public_usages,\n            )?,\n            \"X25519\" => from_x25519(\n                ctx,\n                mode,\n                algorithm_name,\n                &usages,\n                &mut private_usages,\n                &mut public_usages,\n            )?,\n            \"AES-CBC\" | \"AES-CTR\" | \"AES-GCM\" | \"AES-KW\" => from_aes(\n                ctx,\n                mode,\n                obj,\n                algorithm_name,\n                &usages,\n                &mut private_usages,\n                &mut public_usages,\n            )?,\n            \"ECDH\" => Self::from_ec(\n                ctx,\n                mode,\n                obj,\n                algorithm_name,\n                EcAlgorithm::Ecdh,\n                &usages,\n                &mut private_usages,\n                &mut public_usages,\n                KeyUsageAlgorithm::Derive,\n            )?,\n            \"ECDSA\" => Self::from_ec(\n                ctx,\n                mode,\n                obj,\n                algorithm_name,\n                EcAlgorithm::Ecdsa,\n                &usages,\n                &mut private_usages,\n                &mut public_usages,\n                KeyUsageAlgorithm::Sign,\n            )?,\n            \"HMAC\" => from_hmac(\n                ctx,\n                mode,\n                obj,\n                algorithm_name,\n                &usages,\n                &mut private_usages,\n                &mut public_usages,\n            )?,\n            \"RSA-OAEP\" | \"RSA-PSS\" | \"RSASSA-PKCS1-v1_5\" => from_rsa(\n                ctx,\n                mode,\n                obj,\n                algorithm_name,\n                &usages,\n                &mut private_usages,\n                &mut public_usages,\n            )?,\n            \"HKDF\" => from_hkdf(\n                ctx,\n                mode,\n                obj,\n                algorithm_name,\n                &usages,\n                &mut private_usages,\n                &mut public_usages,\n            )?,\n            \"PBKDF2\" => from_pbkdf2(\n                ctx,\n                mode,\n                obj,\n                algorithm_name,\n                &usages,\n                &mut private_usages,\n                &mut public_usages,\n            )?,\n            _ => return algorithm_not_supported_error(ctx),\n        };\n\n        Ok(KeyAlgorithmWithUsages {\n            name,\n            algorithm,\n            public_usages,\n            private_usages,\n        })\n    }\n\n    pub fn as_object<'js, T: AsRef<str>>(&self, ctx: &Ctx<'js>, name: T) -> Result<Object<'js>> {\n        let obj = Object::new(ctx.clone())?;\n        obj.set(PredefinedAtom::Name, name.as_ref())?;\n        match self {\n            KeyAlgorithm::Aes { length } => {\n                obj.set(PredefinedAtom::Length, length)?;\n            },\n            KeyAlgorithm::Ec { curve, .. } => {\n                obj.set(\"namedCurve\", curve.as_str())?;\n            },\n\n            KeyAlgorithm::Hmac { hash, length } => {\n                let hash_obj = create_hash_object(ctx, hash)?;\n                obj.set(\"hash\", hash_obj)?;\n\n                obj.set(PredefinedAtom::Length, length)?;\n            },\n            KeyAlgorithm::Rsa {\n                modulus_length,\n                public_exponent,\n                hash,\n            } => {\n                let public_exponent = public_exponent.as_ref().to_vec();\n                let array = TypedArray::new(ctx.clone(), public_exponent)?;\n\n                let hash_obj = create_hash_object(ctx, hash)?;\n                obj.set(\"hash\", hash_obj)?;\n\n                obj.set(\"modulusLength\", modulus_length)?;\n                obj.set(\"publicExponent\", array)?;\n            },\n            KeyAlgorithm::Derive(KeyDerivation::Hkdf { hash, salt, info }) => {\n                let salt = TypedArray::<u8>::new(ctx.clone(), salt.to_vec())?;\n                let info = TypedArray::<u8>::new(ctx.clone(), info.to_vec())?;\n\n                obj.set(\"hash\", hash.as_str())?;\n                obj.set(\"salt\", salt)?;\n                obj.set(\"info\", info)?;\n            },\n            KeyAlgorithm::Derive(KeyDerivation::Pbkdf2 {\n                hash,\n                salt,\n                iterations,\n            }) => {\n                let salt = TypedArray::<u8>::new(ctx.clone(), salt.to_vec())?;\n                obj.set(\"hash\", hash.as_str())?;\n                obj.set(\"salt\", salt)?;\n                obj.set(\"iterations\", iterations)?;\n            },\n            _ => {},\n        };\n        Ok(obj)\n    }\n\n    #[allow(clippy::too_many_arguments)]\n    fn from_ec<'js>(\n        ctx: &Ctx<'js>,\n        #[allow(unused_variables)] mode: KeyAlgorithmMode<'_, 'js>,\n        obj: std::result::Result<Object<'js>, &str>,\n        #[allow(unused_variables)] algorithm_name: &str,\n        algorithm: EcAlgorithm,\n        key_usages: &Array<'js>,\n        private_usages: &mut Vec<String>,\n        public_usages: &mut Vec<String>,\n        key_usage_algorithm: KeyUsageAlgorithm,\n    ) -> Result<KeyAlgorithm> {\n        let obj = obj.or_throw(ctx)?;\n        let curve_name: String = obj.get_required(\"namedCurve\", \"algorithm\")?;\n        let curve = EllipticCurve::try_from(curve_name.as_str()).or_throw(ctx)?;\n\n        #[cfg(feature = \"_subtle-full\")]\n        let key_kind = if let KeyAlgorithmMode::Import { format, kind, data } = mode {\n            import_ec_key(ctx, format, kind, data, algorithm_name, &curve, &curve_name)?;\n            Some(kind)\n        } else {\n            None\n        };\n        #[cfg(not(feature = \"_subtle-full\"))]\n        let key_kind: Option<&KeyKind> = None;\n\n        KeyUsage::classify_and_check_usages(\n            ctx,\n            key_usage_algorithm,\n            key_usages,\n            private_usages,\n            public_usages,\n            key_kind.as_deref(),\n        )?;\n\n        Ok(KeyAlgorithm::Ec { curve, algorithm })\n    }\n}\n\n#[cfg(feature = \"_subtle-full\")]\nfn import_derive_key<'js>(\n    ctx: &Ctx<'js>,\n    format: KeyFormatData<'js>,\n    kind: &mut KeyKind,\n    data: &mut Vec<u8>,\n    algorithm_name: &str,\n) -> Result<()> {\n    if let KeyFormatData::Raw(object_bytes) = format {\n        *data = object_bytes.into_bytes(ctx)?;\n        *kind = KeyKind::Secret;\n    } else {\n        return Err(Exception::throw_message(\n            ctx,\n            &[algorithm_name, \" only supports 'raw' import format\"].concat(),\n        ));\n    }\n\n    Ok(())\n}\n\n#[cfg(feature = \"_subtle-full\")]\nfn import_rsa_key<'js>(\n    ctx: &Ctx<'js>,\n    format: KeyFormatData<'js>,\n    kind: &mut KeyKind,\n    data: &mut Vec<u8>,\n    algorithm_name: &str,\n    hash: &HashAlgorithm,\n) -> Result<(u32, Box<[u8]>)> {\n    use crate::{\n        provider::{CryptoProvider, RsaJwkImport},\n        CRYPTO_PROVIDER,\n    };\n\n    let validate_oid = |other_oid: const_oid::ObjectIdentifier| -> Result<()> {\n        if other_oid != const_oid::db::rfc5912::RSA_ENCRYPTION {\n            return algorithm_mismatch_error(ctx, algorithm_name);\n        }\n        Ok(())\n    };\n\n    let (modulus_length, public_exponent) = match format {\n        KeyFormatData::Jwk(object) => {\n            let kty: String = object.get_required(\"kty\", \"keyData\")?;\n            let alg: String = object.get_required(\"alg\", \"keyData\")?;\n            if kty != \"RSA\" {\n                return algorithm_mismatch_error(ctx, algorithm_name);\n            }\n            let prefix = &alg[..2];\n            let numeric_hash_str = match prefix {\n                \"RS\" => {\n                    if algorithm_name == \"RSA-OAEP\" {\n                        if !alg.starts_with(algorithm_name) {\n                            return algorithm_mismatch_error(ctx, algorithm_name);\n                        }\n                        &alg[\"RSA-OAEP-\".len()..]\n                    } else if algorithm_name != \"RSASSA-PKCS1-v1_5\" {\n                        return algorithm_mismatch_error(ctx, algorithm_name);\n                    } else {\n                        &alg[\"RS\".len()..]\n                    }\n                },\n                \"PS\" => {\n                    if algorithm_name != \"RSA-PSS\" {\n                        return algorithm_mismatch_error(ctx, algorithm_name);\n                    }\n                    &alg[\"PS\".len()..]\n                },\n                _ => return algorithm_mismatch_error(ctx, algorithm_name),\n            };\n            if numeric_hash_str != hash.as_numeric_str() {\n                return hash_mismatch_error(ctx, hash);\n            }\n\n            let n: String = object.get_required(\"n\", \"keyData\")?;\n            let e: String = object.get_required(\"e\", \"keyData\")?;\n            let n_bytes = bytes_from_b64_url_safe(n.as_bytes()).or_throw(ctx)?;\n            let e_bytes = bytes_from_b64_url_safe(e.as_bytes()).or_throw(ctx)?;\n\n            let result = if let Some(d) = object.get_optional::<_, String>(\"d\")? {\n                let p: String = object.get_required(\"p\", \"keyData\")?;\n                let q: String = object.get_required(\"q\", \"keyData\")?;\n                let dp: String = object.get_required(\"dp\", \"keyData\")?;\n                let dq: String = object.get_required(\"dq\", \"keyData\")?;\n                let qi: String = object.get_required(\"qi\", \"keyData\")?;\n\n                let d_bytes = bytes_from_b64_url_safe(d.as_bytes()).or_throw(ctx)?;\n                let p_bytes = bytes_from_b64_url_safe(p.as_bytes()).or_throw(ctx)?;\n                let q_bytes = bytes_from_b64_url_safe(q.as_bytes()).or_throw(ctx)?;\n                let dp_bytes = bytes_from_b64_url_safe(dp.as_bytes()).or_throw(ctx)?;\n                let dq_bytes = bytes_from_b64_url_safe(dq.as_bytes()).or_throw(ctx)?;\n                let qi_bytes = bytes_from_b64_url_safe(qi.as_bytes()).or_throw(ctx)?;\n\n                let jwk = RsaJwkImport {\n                    n: &n_bytes,\n                    e: &e_bytes,\n                    d: Some(&d_bytes),\n                    p: Some(&p_bytes),\n                    q: Some(&q_bytes),\n                    dp: Some(&dp_bytes),\n                    dq: Some(&dq_bytes),\n                    qi: Some(&qi_bytes),\n                };\n                CRYPTO_PROVIDER.import_rsa_jwk(jwk).or_throw(ctx)?\n            } else {\n                let jwk = RsaJwkImport {\n                    n: &n_bytes,\n                    e: &e_bytes,\n                    d: None,\n                    p: None,\n                    q: None,\n                    dp: None,\n                    dq: None,\n                    qi: None,\n                };\n                CRYPTO_PROVIDER.import_rsa_jwk(jwk).or_throw(ctx)?\n            };\n\n            *data = result.key_data;\n            *kind = if result.is_private {\n                KeyKind::Private\n            } else {\n                KeyKind::Public\n            };\n            (result.modulus_length as usize, result.public_exponent)\n        },\n        KeyFormatData::Raw(object_bytes) => {\n            let result = CRYPTO_PROVIDER\n                .import_rsa_public_key_pkcs1(object_bytes.as_bytes(ctx)?)\n                .or_throw(ctx)?;\n            *data = result.key_data;\n            *kind = KeyKind::Public;\n            (result.modulus_length as usize, result.public_exponent)\n        },\n        KeyFormatData::Pkcs8(object_bytes) => {\n            let pk_info = PrivateKeyInfoRef::from_der(object_bytes.as_bytes(ctx)?).or_throw(ctx)?;\n            validate_oid(pk_info.algorithm.oid)?;\n            let result = CRYPTO_PROVIDER\n                .import_rsa_private_key_pkcs8(object_bytes.as_bytes(ctx)?)\n                .or_throw(ctx)?;\n            *data = result.key_data;\n            *kind = KeyKind::Private;\n            (result.modulus_length as usize, result.public_exponent)\n        },\n        KeyFormatData::Spki(object_bytes) => {\n            let pk_info = spki::SubjectPublicKeyInfoRef::try_from(object_bytes.as_bytes(ctx)?)\n                .or_throw(ctx)?;\n            validate_oid(pk_info.algorithm.oid)?;\n            let result = CRYPTO_PROVIDER\n                .import_rsa_public_key_spki(object_bytes.as_bytes(ctx)?)\n                .or_throw(ctx)?;\n            *data = result.key_data;\n            *kind = KeyKind::Public;\n            (result.modulus_length as usize, result.public_exponent)\n        },\n    };\n\n    let public_exponent = public_exponent.into_boxed_slice();\n    Ok((modulus_length as u32, public_exponent))\n}\n\n#[cfg(feature = \"_subtle-full\")]\nfn import_symmetric_key<'js>(\n    ctx: &Ctx<'js>,\n    format: KeyFormatData<'js>,\n    kind: &mut KeyKind,\n    data: &mut Vec<u8>,\n    algorithm_name: &str,\n    hash: Option<&HashAlgorithm>,\n) -> Result<usize> {\n    *kind = KeyKind::Secret;\n\n    match format {\n        KeyFormatData::Jwk(object) => {\n            let kty: String = object.get_required(\"kty\", \"keyData\")?;\n            if kty == \"oct\" {\n                let k: String = object.get_required(\"k\", \"keyData\")?;\n                let alg: String = object.get_required(\"alg\", \"keyData\")?;\n\n                let prefix = &alg[..1];\n\n                match (prefix, hash) {\n                    //HMAC - HS256, HS512 etc\n                    (\"H\", Some(hash)) => {\n                        if &alg[2..] != hash.as_numeric_str() {\n                            return hash_mismatch_error(ctx, hash);\n                        }\n                    },\n                    //AES - A256KW, A256GCM, A256CRT, A512CBC etc\n                    (\"A\", None) => {\n                        //extract AES-{suffix}\n                        let (_, name_suffix) = algorithm_name.split_once(\"-\").unwrap_or_default();\n                        let aes_variant = &alg[4..];\n\n                        if aes_variant != name_suffix {\n                            return algorithm_mismatch_error(ctx, algorithm_name);\n                        }\n                    },\n                    _ => return algorithm_mismatch_error(ctx, algorithm_name),\n                }\n\n                *data = bytes_from_b64_url_safe(k.as_bytes()).or_throw(ctx)?;\n                return Ok(data.len() * 8);\n            }\n        },\n        KeyFormatData::Raw(object_bytes) => {\n            let bytes = object_bytes.into_bytes(ctx)?;\n\n            *data = bytes;\n            return Ok(data.len() * 8);\n        },\n        _ => {},\n    }\n    algorithm_mismatch_error(ctx, algorithm_name)\n}\n\n// EC algorithm OID for validation\n#[cfg(feature = \"_subtle-full\")]\nconst EC_ALGORITHM_OID: const_oid::ObjectIdentifier =\n    const_oid::ObjectIdentifier::new_unwrap(\"1.2.840.10045.2.1\");\n\n#[cfg(feature = \"_subtle-full\")]\nfn import_ec_key<'js>(\n    ctx: &Ctx<'js>,\n    format: KeyFormatData<'js>,\n    kind: &mut KeyKind,\n    data: &mut Vec<u8>,\n    algorithm_name: &str,\n    curve: &EllipticCurve,\n    curve_name: &str,\n) -> Result<()> {\n    use crate::{\n        provider::{CryptoProvider, EcJwkImport},\n        CRYPTO_PROVIDER,\n    };\n\n    let validate_oid = |other_oid: const_oid::ObjectIdentifier| -> Result<()> {\n        if other_oid != EC_ALGORITHM_OID {\n            return algorithm_mismatch_error(ctx, algorithm_name);\n        }\n        Ok(())\n    };\n\n    // Get expected coordinate length for the curve\n    let coord_len = match curve {\n        EllipticCurve::P256 => 32,\n        EllipticCurve::P384 => 48,\n        EllipticCurve::P521 => 66,\n    };\n\n    match format {\n        KeyFormatData::Jwk(object) => {\n            let kty: String = object.get_required(\"kty\", \"keyData\")?;\n            if kty != \"EC\" {\n                return algorithm_mismatch_error(ctx, algorithm_name);\n            }\n\n            let jwk_crv: String = object.get_required(\"crv\", \"keyData\")?;\n            if curve_name != jwk_crv {\n                return Err(Exception::throw_type(\n                    ctx,\n                    &[\"Key is using a \", curve_name].concat(),\n                ));\n            }\n\n            let x: String = object.get_required(\"x\", \"keyData\")?;\n            let y: String = object.get_required(\"y\", \"keyData\")?;\n            let mut x_bytes = bytes_from_b64_url_safe(x.as_bytes()).or_throw(ctx)?;\n            let mut y_bytes = bytes_from_b64_url_safe(y.as_bytes()).or_throw(ctx)?;\n\n            // Pad to coordinate length if needed\n            if x_bytes.len() < coord_len {\n                let mut padded = vec![0u8; coord_len - x_bytes.len()];\n                padded.extend_from_slice(&x_bytes);\n                x_bytes = padded;\n            }\n            if y_bytes.len() < coord_len {\n                let mut padded = vec![0u8; coord_len - y_bytes.len()];\n                padded.extend_from_slice(&y_bytes);\n                y_bytes = padded;\n            }\n\n            let d_bytes = if let Some(d) = object.get_optional::<_, String>(\"d\")? {\n                let mut d_bytes = bytes_from_b64_url_safe(d.as_bytes()).or_throw(ctx)?;\n                if d_bytes.len() < coord_len {\n                    let mut padded = vec![0u8; coord_len - d_bytes.len()];\n                    padded.extend_from_slice(&d_bytes);\n                    d_bytes = padded;\n                }\n                Some(d_bytes)\n            } else {\n                None\n            };\n\n            let jwk = EcJwkImport {\n                x: &x_bytes,\n                y: &y_bytes,\n                d: d_bytes.as_deref(),\n            };\n\n            let result = CRYPTO_PROVIDER.import_ec_jwk(jwk, *curve).or_throw(ctx)?;\n            *data = result.key_data;\n            *kind = if result.is_private {\n                KeyKind::Private\n            } else {\n                KeyKind::Public\n            };\n        },\n        KeyFormatData::Raw(object_bytes) => {\n            let bytes = object_bytes.as_bytes(ctx)?;\n            let result = CRYPTO_PROVIDER\n                .import_ec_public_key_sec1(bytes, *curve)\n                .or_throw(ctx)?;\n            *data = result.key_data;\n            *kind = KeyKind::Public;\n        },\n        KeyFormatData::Spki(object_bytes) => {\n            let spki = spki::SubjectPublicKeyInfoRef::try_from(object_bytes.as_bytes(ctx)?)\n                .or_throw(ctx)?;\n            validate_oid(spki.algorithm.oid)?;\n            let result = CRYPTO_PROVIDER\n                .import_ec_public_key_spki(object_bytes.as_bytes(ctx)?)\n                .or_throw(ctx)?;\n            *data = result.key_data;\n            *kind = KeyKind::Public;\n        },\n        KeyFormatData::Pkcs8(object_bytes) => {\n            let pkcs8 = PrivateKeyInfoRef::try_from(object_bytes.as_bytes(ctx)?).or_throw(ctx)?;\n            validate_oid(pkcs8.algorithm.oid)?;\n            let result = CRYPTO_PROVIDER\n                .import_ec_private_key_pkcs8(object_bytes.as_bytes(ctx)?)\n                .or_throw(ctx)?;\n            *data = result.key_data;\n            *kind = KeyKind::Private;\n        },\n    };\n    Ok(())\n}\n\n#[cfg(feature = \"_subtle-full\")]\nfn import_okp_key<'js>(\n    ctx: &Ctx<'js>,\n    format: KeyFormatData<'js>,\n    kind: &mut KeyKind,\n    data: &mut Vec<u8>,\n    oid: ObjectIdentifier,\n    algorithm_name: &str,\n) -> Result<()> {\n    let validate_oid = |other_oid: const_oid::ObjectIdentifier| -> Result<()> {\n        if other_oid != oid {\n            return algorithm_mismatch_error(ctx, algorithm_name);\n        }\n        Ok(())\n    };\n\n    match format {\n        KeyFormatData::Jwk(object) => {\n            let crv: String = object.get_required(\"crv\", \"keyData\")?;\n            if crv != algorithm_name {\n                return algorithm_mismatch_error(ctx, algorithm_name);\n            }\n            let x: String = object.get_required(\"x\", \"keyData\")?;\n            let public_key = bytes_from_b64_url_safe(x.as_bytes()).or_throw(ctx)?;\n\n            if let Some(d) = object.get_optional::<_, String>(\"d\")? {\n                let private_key = bytes_from_b64_url_safe(d.as_bytes()).or_throw(ctx)?;\n\n                let pk_info = PrivateKeyInfoRef::new(\n                    AlgorithmIdentifier {\n                        oid,\n                        parameters: None,\n                    },\n                    OctetStringRef::new(private_key.as_slice()).or_throw(ctx)?,\n                );\n\n                *data = pk_info.to_der().or_throw(ctx)?;\n                *kind = KeyKind::Private;\n            } else {\n                *data = public_key;\n                *kind = KeyKind::Public;\n            }\n        },\n        KeyFormatData::Raw(object_bytes) => {\n            let bytes = object_bytes.into_bytes(ctx)?;\n            if bytes.len() != 32 {\n                return Err(Exception::throw_type(\n                    ctx,\n                    &[algorithm_name, \" keys must be 32 bytes long\"].concat(),\n                ));\n            }\n            *data = bytes;\n            *kind = KeyKind::Public;\n        },\n        KeyFormatData::Spki(object_bytes) => {\n            let spki = spki::SubjectPublicKeyInfoRef::try_from(object_bytes.as_bytes(ctx)?)\n                .or_throw(ctx)?;\n            validate_oid(spki.algorithm.oid)?;\n            *data = spki.subject_public_key.raw_bytes().into();\n            *kind = KeyKind::Public;\n        },\n        KeyFormatData::Pkcs8(object_bytes) => {\n            let pkcs8 = PrivateKeyInfoRef::try_from(object_bytes.as_bytes(ctx)?).or_throw(ctx)?;\n            validate_oid(pkcs8.algorithm.oid)?;\n            *data = object_bytes.into_bytes(ctx)?;\n            *kind = KeyKind::Private;\n        },\n    };\n    Ok(())\n}\n\npub fn extract_sha_hash<'js>(ctx: &Ctx<'js>, obj: &Object<'js>) -> Result<HashAlgorithm> {\n    let hash: Value = obj.get_required(\"hash\", \"algorithm\")?;\n    let hash = if let Some(string) = hash.as_string() {\n        string.to_string()\n    } else if let Some(obj) = hash.into_object() {\n        obj.get_required(\"name\", \"hash\")\n    } else {\n        return Err(Exception::throw_message(\n            ctx,\n            \"hash must be a string or an object\",\n        ));\n    }?;\n    HashAlgorithm::try_from(hash.as_str()).or_throw(ctx)\n}\n\nfn create_hash_object<'js>(ctx: &Ctx<'js>, hash: &HashAlgorithm) -> Result<Object<'js>> {\n    let hash_obj = Object::new(ctx.clone())?;\n    hash_obj.set(PredefinedAtom::Name, hash.as_str())?;\n    Ok(hash_obj)\n}\n\n#[cfg(feature = \"_subtle-full\")]\npub fn hash_mismatch_error<T>(ctx: &Ctx<'_>, hash: &HashAlgorithm) -> Result<T> {\n    Err(Exception::throw_message(\n        ctx,\n        &[\"Algorithm hash expected to be \", hash.as_str()].concat(),\n    ))\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/subtle/mod.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nmod crypto_key;\nmod derive;\nmod derive_algorithm;\nmod digest;\nmod encryption;\nmod encryption_algorithm;\n#[cfg(feature = \"_subtle-full\")]\nmod export_key;\nmod generate_key;\n#[cfg(feature = \"_subtle-full\")]\nmod import_key;\n#[cfg(feature = \"_subtle-full\")]\nmod key_algorithm;\nmod sign;\nmod sign_algorithm;\nmod verify;\n#[cfg(feature = \"_subtle-full\")]\nmod wrapping;\n\npub use crypto_key::CryptoKey;\npub use derive::subtle_derive_bits;\npub use derive::subtle_derive_key;\npub use digest::subtle_digest;\npub use encryption::subtle_decrypt;\npub use encryption::subtle_encrypt;\n#[cfg(feature = \"_subtle-full\")]\npub use export_key::subtle_export_key;\npub use generate_key::subtle_generate_key;\n#[cfg(feature = \"_subtle-full\")]\npub use import_key::subtle_import_key;\n#[cfg(feature = \"_subtle-full\")]\nuse key_algorithm::KeyAlgorithm;\npub use sign::subtle_sign;\npub use verify::subtle_verify;\n#[cfg(feature = \"_subtle-full\")]\npub use wrapping::subtle_unwrap_key;\n#[cfg(feature = \"_subtle-full\")]\npub use wrapping::subtle_wrap_key;\n\n// Stub implementations for limited crypto providers (no _subtle-full)\n#[cfg(not(feature = \"_subtle-full\"))]\nmod key_algorithm;\n#[cfg(not(feature = \"_subtle-full\"))]\nuse key_algorithm::KeyAlgorithm;\n\nuse llrt_utils::{object::ObjectExt, str_enum};\nuse rquickjs::{atom::PredefinedAtom, Ctx, Exception, Object, Result, Value};\n\nuse crate::provider::{CryptoProvider, SimpleDigest};\n\nuse crate::hash::HashAlgorithm;\n\n#[rquickjs::class]\n#[derive(rquickjs::JsLifetime, rquickjs::class::Trace)]\npub struct SubtleCrypto {}\n\n#[rquickjs::methods]\nimpl SubtleCrypto {\n    #[qjs(constructor)]\n    pub fn new(ctx: Ctx<'_>) -> Result<Self> {\n        Err(Exception::throw_type(&ctx, \"Illegal constructor\"))\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    pub fn to_string_tag(&self) -> &'static str {\n        stringify!(SubtleCrypto)\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum EllipticCurve {\n    P256,\n    P384,\n    P521,\n}\n\nstr_enum!(EllipticCurve,P256 => \"P-256\", P384 => \"P-384\", P521 => \"P-521\");\n\npub enum EncryptionMode {\n    Encryption,\n    #[allow(dead_code)]\n    Wrapping(u8), //padding byte\n}\n\npub fn rsa_hash_digest<'a>(\n    ctx: &Ctx<'_>,\n    key: &'a CryptoKey,\n    data: &'a [u8],\n    algorithm_name: &str,\n) -> Result<(&'a HashAlgorithm, Vec<u8>)> {\n    let hash = match &key.algorithm {\n        KeyAlgorithm::Rsa { hash, .. } => hash,\n        _ => return algorithm_mismatch_error(ctx, algorithm_name),\n    };\n    if !matches!(\n        hash,\n        HashAlgorithm::Sha256 | HashAlgorithm::Sha384 | HashAlgorithm::Sha512\n    ) {\n        return Err(Exception::throw_message(\n            ctx,\n            \"Only Sha-256, Sha-384 or Sha-512 is supported for RSA\",\n        ));\n    }\n\n    let mut hasher = crate::CRYPTO_PROVIDER.digest(*hash);\n    hasher.update(data);\n    let digest = hasher.finalize();\n\n    Ok((hash, digest))\n}\n\npub fn validate_aes_length(\n    ctx: &Ctx<'_>,\n    key: &CryptoKey,\n    handle: &[u8],\n    expected_algorithm: &str,\n) -> Result<()> {\n    let length = match key.algorithm {\n        KeyAlgorithm::Aes { length } => length,\n        _ => return algorithm_mismatch_error(ctx, expected_algorithm),\n    };\n    if length != handle.len() as u16 * 8 {\n        return Err(Exception::throw_message(\n            ctx,\n            &[\n                \"Invalid key handle length for \",\n                expected_algorithm,\n                \". Expected \",\n                &length.to_string(),\n                \" bits, found \",\n                &handle.len().to_string(),\n                \" bits\",\n            ]\n            .concat(),\n        ));\n    }\n    Ok(())\n}\n\npub fn to_name_and_maybe_object<'js, 'a>(\n    ctx: &Ctx<'js>,\n    value: Value<'js>,\n) -> Result<(String, std::result::Result<Object<'js>, &'a str>)> {\n    let obj;\n    let name = if let Some(string) = value.as_string() {\n        obj = Err(\"Not an object\");\n        string.to_string()?\n    } else if let Some(object) = value.into_object() {\n        let name = object.get_required(\"name\", \"algorithm\")?;\n        obj = Ok(object);\n        name\n    } else {\n        return Err(Exception::throw_message(\n            ctx,\n            \"algorithm must be a string or an object\",\n        ));\n    };\n    Ok((name, obj))\n}\n\npub fn algorithm_mismatch_error<T>(ctx: &Ctx<'_>, expected_algorithm: &str) -> Result<T> {\n    Err(Exception::throw_message(\n        ctx,\n        &[\"Key algorithm must be \", expected_algorithm].concat(),\n    ))\n}\n\npub fn algorithm_not_supported_error<T>(ctx: &Ctx<'_>) -> Result<T> {\n    Err(Exception::throw_message(ctx, \"Algorithm not supported\"))\n}\n\n// Stub implementations for providers without _subtle-full\n#[cfg(not(feature = \"_subtle-full\"))]\nmod stubs;\n#[cfg(not(feature = \"_subtle-full\"))]\npub use stubs::subtle_export_key;\n#[cfg(not(feature = \"_subtle-full\"))]\npub use stubs::subtle_import_key;\n#[cfg(not(feature = \"_subtle-full\"))]\npub use stubs::subtle_unwrap_key;\n#[cfg(not(feature = \"_subtle-full\"))]\npub use stubs::subtle_wrap_key;\n"
  },
  {
    "path": "modules/llrt_crypto/src/subtle/sign.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse crate::provider::{CryptoProvider, HmacProvider};\nuse llrt_utils::{bytes::ObjectBytes, result::ResultExt};\nuse rquickjs::{ArrayBuffer, Class, Ctx, Result};\n\nuse crate::{subtle::CryptoKey, CRYPTO_PROVIDER};\n\nuse super::{\n    algorithm_mismatch_error, key_algorithm::KeyAlgorithm, rsa_hash_digest,\n    sign_algorithm::SigningAlgorithm,\n};\n\npub async fn subtle_sign<'js>(\n    ctx: Ctx<'js>,\n    algorithm: SigningAlgorithm,\n    key: Class<'js, CryptoKey>,\n    data: ObjectBytes<'js>,\n) -> Result<ArrayBuffer<'js>> {\n    let key = key.borrow();\n    key.check_validity(\"sign\").or_throw(&ctx)?;\n\n    let bytes = sign(&ctx, &algorithm, &key, data.as_bytes(&ctx)?)?;\n    ArrayBuffer::new(ctx, bytes)\n}\n\nfn sign(\n    ctx: &Ctx<'_>,\n    algorithm: &SigningAlgorithm,\n    key: &CryptoKey,\n    data: &[u8],\n) -> Result<Vec<u8>> {\n    let handle = key.handle.as_ref();\n    Ok(match algorithm {\n        SigningAlgorithm::Ecdsa { hash } => {\n            let curve = match &key.algorithm {\n                KeyAlgorithm::Ec { curve, .. } => curve,\n                _ => return algorithm_mismatch_error(ctx, \"ECDSA\"),\n            };\n\n            let digest = crate::subtle::digest::digest(hash, data);\n\n            crate::CRYPTO_PROVIDER\n                .ecdsa_sign(*curve, handle, &digest)\n                .or_throw(ctx)?\n        },\n        SigningAlgorithm::Ed25519 => {\n            if !matches!(&key.algorithm, KeyAlgorithm::Ed25519) {\n                return algorithm_mismatch_error(ctx, \"Ed25519\");\n            }\n            crate::CRYPTO_PROVIDER\n                .ed25519_sign(handle, data)\n                .or_throw(ctx)?\n        },\n        SigningAlgorithm::Hmac => {\n            let hash = if let KeyAlgorithm::Hmac { hash, .. } = &key.algorithm {\n                hash\n            } else {\n                return algorithm_mismatch_error(ctx, \"HMAC\");\n            };\n\n            let mut hmac = CRYPTO_PROVIDER.hmac(*hash, handle);\n            hmac.update(data);\n            hmac.finalize()\n        },\n        SigningAlgorithm::RsaPss { salt_length } => {\n            let (hash, digest) = rsa_hash_digest(ctx, key, data, \"RSA-PSS\")?;\n            crate::CRYPTO_PROVIDER\n                .rsa_pss_sign(&key.handle, digest.as_ref(), *salt_length as usize, *hash)\n                .or_throw(ctx)?\n        },\n        SigningAlgorithm::RsassaPkcs1v15 => {\n            let (hash, digest) = rsa_hash_digest(ctx, key, data, \"RSASSA-PKCS1-v1_5\")?;\n            crate::CRYPTO_PROVIDER\n                .rsa_pkcs1v15_sign(&key.handle, digest.as_ref(), *hash)\n                .or_throw(ctx)?\n        },\n    })\n}\n\n// // Helper function for RSA signing\n// fn rsa_sign<F>(\n//     ctx: &Ctx<'_>,\n//     key: &CryptoKey,\n//     algorithm_name: &str,\n//     data: &[u8],\n//     sign_fn: F,\n// ) -> Result<Vec<u8>>\n// where\n//     F: FnOnce(&HashAlgorithm, &[u8], &rsa::RsaPrivateKey) -> Result<Vec<u8>>,\n// {\n//     let (hash, digest) = rsa_hash_digest(ctx, key, data, algorithm_name)?;\n\n//     sign_fn(hash, digest.as_ref())\n// }\n"
  },
  {
    "path": "modules/llrt_crypto/src/subtle/sign_algorithm.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_utils::{object::ObjectExt, result::ResultExt};\nuse rquickjs::{Ctx, FromJs, Result, Value};\n\nuse crate::hash::HashAlgorithm;\n\nuse super::{\n    algorithm_not_supported_error, key_algorithm::extract_sha_hash, to_name_and_maybe_object,\n};\n\n#[derive(Debug)]\npub enum SigningAlgorithm {\n    Ecdsa { hash: HashAlgorithm },\n    Ed25519,\n    RsaPss { salt_length: u32 },\n    RsassaPkcs1v15,\n    Hmac,\n}\n\nimpl<'js> FromJs<'js> for SigningAlgorithm {\n    fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        let (name, obj) = to_name_and_maybe_object(ctx, value)?;\n\n        let algorithm = match name.as_str() {\n            \"Ed25519\" => SigningAlgorithm::Ed25519,\n            \"HMAC\" => SigningAlgorithm::Hmac,\n            \"RSASSA-PKCS1-v1_5\" => SigningAlgorithm::RsassaPkcs1v15,\n            \"ECDSA\" => {\n                let obj = obj.or_throw(ctx)?;\n                let hash = extract_sha_hash(ctx, &obj)?;\n                SigningAlgorithm::Ecdsa { hash }\n            },\n            \"RSA-PSS\" => {\n                let salt_length = obj.or_throw(ctx)?.get_required(\"saltLength\", \"algorithm\")?;\n\n                SigningAlgorithm::RsaPss { salt_length }\n            },\n            _ => return algorithm_not_supported_error(ctx),\n        };\n        Ok(algorithm)\n    }\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/subtle/stubs.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\n//! Stub implementations for SubtleCrypto operations when `_rustcrypto` feature is disabled.\n//! These return errors indicating the operation is not supported.\n\nuse rquickjs::{Ctx, Exception, Object, Result, Value};\n\nuse super::crypto_key::CryptoKey;\nuse super::encryption_algorithm;\nuse super::key_algorithm;\n\npub async fn subtle_export_key<'js>(\n    ctx: Ctx<'js>,\n    _format: key_algorithm::KeyFormat,\n    _key: rquickjs::Class<'js, CryptoKey>,\n) -> Result<Object<'js>> {\n    Err(Exception::throw_message(\n        &ctx,\n        \"exportKey is not supported with this crypto provider\",\n    ))\n}\n\npub async fn subtle_import_key<'js>(\n    ctx: Ctx<'js>,\n    _format: key_algorithm::KeyFormat,\n    _key_data: Value<'js>,\n    _algorithm: Value<'js>,\n    _extractable: bool,\n    _key_usages: rquickjs::Array<'js>,\n) -> Result<rquickjs::Class<'js, CryptoKey>> {\n    Err(Exception::throw_message(\n        &ctx,\n        \"importKey is not supported with this crypto provider\",\n    ))\n}\n\npub async fn subtle_wrap_key<'js>(\n    ctx: Ctx<'js>,\n    _format: key_algorithm::KeyFormat,\n    _key: rquickjs::Class<'js, CryptoKey>,\n    _wrapping_key: rquickjs::Class<'js, CryptoKey>,\n    _wrap_algo: encryption_algorithm::EncryptionAlgorithm,\n) -> Result<rquickjs::ArrayBuffer<'js>> {\n    Err(Exception::throw_message(\n        &ctx,\n        \"wrapKey is not supported with this crypto provider\",\n    ))\n}\n\npub async fn subtle_unwrap_key<'js>(\n    _format: key_algorithm::KeyFormat,\n    wrapped_key: rquickjs::ArrayBuffer<'js>,\n    _unwrapping_key: rquickjs::Class<'js, CryptoKey>,\n    _unwrap_algo: encryption_algorithm::EncryptionAlgorithm,\n    _unwrapped_key_algo: Value<'js>,\n    _extractable: bool,\n    _key_usages: rquickjs::Array<'js>,\n) -> Result<rquickjs::Class<'js, CryptoKey>> {\n    let ctx = wrapped_key.ctx().clone();\n    Err(Exception::throw_message(\n        &ctx,\n        \"unwrapKey is not supported with this crypto provider\",\n    ))\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/subtle/verify.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse crate::provider::{CryptoProvider, HmacProvider};\nuse llrt_utils::{bytes::ObjectBytes, result::ResultExt};\nuse rquickjs::{Class, Ctx, Result};\n\nuse crate::{\n    subtle::{digest, CryptoKey},\n    CRYPTO_PROVIDER,\n};\n\nuse super::{\n    algorithm_mismatch_error, key_algorithm::KeyAlgorithm, rsa_hash_digest,\n    sign_algorithm::SigningAlgorithm,\n};\n\npub async fn subtle_verify<'js>(\n    ctx: Ctx<'js>,\n    algorithm: SigningAlgorithm,\n    key: Class<'js, CryptoKey>,\n    signature: ObjectBytes<'js>,\n    data: ObjectBytes<'js>,\n) -> Result<bool> {\n    let key = key.borrow();\n    key.check_validity(\"verify\").or_throw(&ctx)?;\n\n    verify(\n        &ctx,\n        &algorithm,\n        &key,\n        signature.as_bytes(&ctx)?,\n        data.as_bytes(&ctx)?,\n    )\n}\n\nfn verify(\n    ctx: &Ctx<'_>,\n    algorithm: &SigningAlgorithm,\n    key: &CryptoKey,\n    signature: &[u8],\n    data: &[u8],\n) -> Result<bool> {\n    let handle = key.handle.as_ref();\n    Ok(match algorithm {\n        SigningAlgorithm::Ecdsa { hash } => {\n            let curve = match &key.algorithm {\n                KeyAlgorithm::Ec { curve, .. } => curve,\n                _ => return algorithm_mismatch_error(ctx, \"ECDSA\"),\n            };\n\n            let digest = digest::digest(hash, data);\n\n            crate::CRYPTO_PROVIDER\n                .ecdsa_verify(*curve, handle, signature, &digest)\n                .or_throw(ctx)?\n        },\n        SigningAlgorithm::Ed25519 => {\n            if !matches!(&key.algorithm, KeyAlgorithm::Ed25519) {\n                return algorithm_mismatch_error(ctx, \"Ed25519\");\n            }\n\n            crate::CRYPTO_PROVIDER\n                .ed25519_verify(handle, signature, data)\n                .or_throw(ctx)?\n        },\n        SigningAlgorithm::Hmac => {\n            let hash = match &key.algorithm {\n                KeyAlgorithm::Hmac { hash, .. } => hash,\n                _ => return algorithm_mismatch_error(ctx, \"HMAC\"),\n            };\n\n            let mut hmac = CRYPTO_PROVIDER.hmac(*hash, handle);\n            hmac.update(data);\n            let computed_signature = hmac.finalize();\n\n            computed_signature == signature\n        },\n        SigningAlgorithm::RsaPss { salt_length } => {\n            let (hash, digest) = rsa_hash_digest(ctx, key, data, \"RSA-PSS\")?;\n            crate::CRYPTO_PROVIDER\n                .rsa_pss_verify(\n                    &key.handle,\n                    signature,\n                    digest.as_ref(),\n                    *salt_length as usize,\n                    *hash,\n                )\n                .or_throw(ctx)?\n        },\n        SigningAlgorithm::RsassaPkcs1v15 => {\n            let (hash, digest) = rsa_hash_digest(ctx, key, data, \"RSASSA-PKCS1-v1_5\")?;\n            crate::CRYPTO_PROVIDER\n                .rsa_pkcs1v15_verify(&key.handle, signature, digest.as_ref(), *hash)\n                .or_throw(ctx)?\n        },\n    })\n}\n"
  },
  {
    "path": "modules/llrt_crypto/src/subtle/wrapping.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_json::{parse::json_parse, stringify::json_stringify};\nuse llrt_utils::{bytes::ObjectBytes, object::ObjectExt, result::ResultExt};\nuse rquickjs::{Array, ArrayBuffer, Class, Ctx, Exception, Result, Value};\n\nuse crate::subtle::CryptoKey;\n\nuse super::{\n    encryption::{self, encrypt_decrypt},\n    encryption_algorithm::EncryptionAlgorithm,\n    export_key::{export_key, ExportOutput},\n    import_key::import_key,\n    key_algorithm::{KeyFormat, KeyFormatData},\n    EncryptionMode,\n};\n\npub async fn subtle_wrap_key<'js>(\n    ctx: Ctx<'js>,\n    format: KeyFormat,\n    key: Class<'js, CryptoKey>,\n    wrapping_key: Class<'js, CryptoKey>,\n    wrap_algo: EncryptionAlgorithm,\n) -> Result<ArrayBuffer<'js>> {\n    let key = key.borrow();\n\n    let export = export_key(&ctx, format, &key)?;\n\n    let (bytes, padding) = match export {\n        ExportOutput::Bytes(bytes) => (bytes, 0),\n        ExportOutput::Object(value) => {\n            let json = json_stringify(&ctx, value.into_value())?.unwrap();\n            (json.into_bytes(), b' ')\n        },\n    };\n\n    let wrapping_key = wrapping_key.borrow();\n    wrapping_key.check_validity(\"wrapKey\").or_throw(&ctx)?;\n\n    let bytes = encrypt_decrypt(\n        &ctx,\n        &wrap_algo,\n        &wrapping_key,\n        &bytes,\n        EncryptionMode::Wrapping(padding),\n        encryption::EncryptionOperation::Encrypt,\n    )?;\n\n    ArrayBuffer::new(ctx, bytes)\n}\n\n//cant take more than 7 args\npub async fn subtle_unwrap_key<'js>(\n    format: KeyFormat,\n    wrapped_key: ArrayBuffer<'js>,\n    unwrapping_key: Class<'js, CryptoKey>,\n    unwrap_algo: EncryptionAlgorithm,\n    unwrapped_key_algo: Value<'js>,\n    extractable: bool,\n    key_usages: Array<'js>,\n) -> Result<Class<'js, CryptoKey>> {\n    let unwrapping_key = unwrapping_key.borrow();\n    let ctx = wrapped_key.ctx().clone();\n    unwrapping_key.check_validity(\"unwrapKey\").or_throw(&ctx)?;\n\n    let bytes = wrapped_key\n        .as_bytes()\n        .ok_or_else(|| Exception::throw_message(&ctx, \"ArrayBuffer is detached\"))?;\n\n    let padding = match format {\n        KeyFormat::Jwk => b' ',\n        _ => 0,\n    };\n\n    let bytes = encrypt_decrypt(\n        &ctx,\n        &unwrap_algo,\n        &unwrapping_key,\n        bytes,\n        EncryptionMode::Wrapping(padding),\n        encryption::EncryptionOperation::Decrypt,\n    )?;\n\n    let key_format = match format {\n        KeyFormat::Jwk => {\n            KeyFormatData::Jwk(json_parse(&ctx, bytes)?.into_object_or_throw(&ctx, \"wrappedKey\")?)\n        },\n        KeyFormat::Raw => KeyFormatData::Raw(ObjectBytes::Vec(bytes)),\n        KeyFormat::Spki => KeyFormatData::Spki(ObjectBytes::Vec(bytes)),\n        KeyFormat::Pkcs8 => KeyFormatData::Pkcs8(ObjectBytes::Vec(bytes)),\n    };\n\n    import_key(ctx, key_format, unwrapped_key_algo, extractable, key_usages)\n}\n"
  },
  {
    "path": "modules/llrt_dgram/Cargo.toml",
    "content": "[package]\nname = \"llrt_dgram\"\ndescription = \"LLRT Module dgram\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\nreadme = \"README.md\"\n\n[lib]\nname = \"llrt_dgram\"\npath = \"src/lib.rs\"\n\n[dependencies]\nitoa = { version = \"1\", default-features = false }\nllrt_buffer = { version = \"0.8.1-beta\", path = \"../llrt_buffer\" }\nllrt_context = { version = \"0.8.1-beta\", path = \"../../libs/llrt_context\" }\nllrt_events = { version = \"0.8.1-beta\", path = \"../llrt_events\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", default-features = false }\ntokio = { version = \"1\", features = [\n    \"net\",\n    \"macros\",\n], default-features = false }\ntracing = { version = \"0.1\", default-features = false }\n\n[dev-dependencies]\nllrt_test = { path = \"../../libs/llrt_test\" }\ntokio = { version = \"1\", features = [\"rt\", \"macros\"] }\n"
  },
  {
    "path": "modules/llrt_dgram/README.md",
    "content": "# llrt_dgram\n\nLLRT implementation of Node.js `dgram` module for UDP datagram sockets.\n\n## Features\n\n- UDP socket support (IPv4 and IPv6)\n- Send and receive datagrams\n- Event-driven API compatible with Node.js\n- Async/await support\n\n## Supported APIs\n\n- `dgram.createSocket(type[, callback])`\n- `socket.send(msg, port, address[, callback])`\n- `socket.bind([port][, address][, callback])`\n- `socket.close([callback])`\n- `socket.address()`\n- `socket.unref()`\n- `socket.ref()`\n\n## Events\n\n- `'message'` - Emitted when a new datagram is available\n- `'listening'` - Emitted when socket begins listening for datagrams\n- `'close'` - Emitted after socket is closed\n- `'error'` - Emitted when an error occurs\n"
  },
  {
    "path": "modules/llrt_dgram/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_events::Emitter;\nuse llrt_utils::module::{export_default, ModuleInfo};\nuse rquickjs::{\n    module::{Declarations, Exports, ModuleDef},\n    prelude::Func,\n    Class, Ctx, Result, Value,\n};\n\nmod socket;\n\nuse self::socket::Socket;\n\npub struct DgramModule;\n\nimpl ModuleDef for DgramModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(\"createSocket\")?;\n        declare.declare(stringify!(Socket))?;\n        declare.declare(\"default\")?;\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        export_default(ctx, exports, |default| {\n            Class::<Socket>::define(default)?;\n            Socket::add_event_emitter_prototype(ctx)?;\n\n            default.set(\n                \"createSocket\",\n                Func::from(|ctx: Ctx<'js>, type_or_options: Value<'js>| {\n                    Socket::ctor(ctx, type_or_options)\n                }),\n            )?;\n\n            Ok(())\n        })?;\n        Ok(())\n    }\n}\n\nimpl From<DgramModule> for ModuleInfo<DgramModule> {\n    fn from(val: DgramModule) -> Self {\n        ModuleInfo {\n            name: \"dgram\",\n            module: val,\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use llrt_test::{test_async_with, ModuleEvaluator};\n\n    use super::*;\n\n    #[tokio::test]\n    async fn test_module_loads() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                // Test that the dgram module can be loaded without errors\n                let result = ModuleEvaluator::eval_rust::<DgramModule>(ctx.clone(), \"dgram\").await;\n                assert!(result.is_ok(), \"Dgram module should load successfully\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_create_socket_function_exists() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                ModuleEvaluator::eval_rust::<DgramModule>(ctx.clone(), \"dgram\")\n                    .await\n                    .unwrap();\n\n                let result = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import dgram from 'dgram';\n                        typeof dgram.createSocket === 'function'\n                    \"#,\n                )\n                .await;\n\n                assert!(result.is_ok(), \"createSocket should be accessible\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_socket_creation() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                ModuleEvaluator::eval_rust::<DgramModule>(ctx.clone(), \"dgram\")\n                    .await\n                    .unwrap();\n\n                let result = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import dgram from 'dgram';\n                        try {\n                            const socket = dgram.createSocket('udp4');\n                            true\n                        } catch (e) {\n                            false\n                        }\n                    \"#,\n                )\n                .await;\n\n                assert!(result.is_ok(), \"Socket creation should not throw\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_bind_failure_emits_error() {\n        // Test that bind failure on invalid address emits error event\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                ModuleEvaluator::eval_rust::<DgramModule>(ctx.clone(), \"dgram\")\n                    .await\n                    .unwrap();\n\n                let result = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import dgram from 'dgram';\n                        export async function test() {\n                            return new Promise((resolve, reject) => {\n                                const socket = dgram.createSocket('udp4');\n                                let errorReceived = false;\n                                \n                                socket.on('error', (err) => {\n                                    errorReceived = true;\n                                    resolve('error_received');\n                                });\n                                \n                                // Bind to invalid address should fail\n                                socket.bind(12345, '999.999.999.999');\n                                \n                                // Timeout to ensure we don't hang forever\n                                setTimeout(() => {\n                                    resolve(errorReceived ? 'error_received' : 'timeout');\n                                }, 100);\n                            });\n                        }\n                    \"#,\n                )\n                .await;\n\n                assert!(result.is_ok(), \"Test module should evaluate\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_close_clears_send_channel() {\n        // Test that close properly cleans up send channel\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                ModuleEvaluator::eval_rust::<DgramModule>(ctx.clone(), \"dgram\")\n                    .await\n                    .unwrap();\n\n                let result = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import dgram from 'dgram';\n                        export async function test() {\n                            return new Promise((resolve) => {\n                                const socket = dgram.createSocket('udp4');\n                                \n                                socket.on('listening', () => {\n                                    socket.close(() => {\n                                        resolve('closed');\n                                    });\n                                });\n                                \n                                socket.on('error', (err) => {\n                                    resolve('error: ' + err.message);\n                                });\n                                \n                                socket.bind(0); // Random port\n                            });\n                        }\n                    \"#,\n                )\n                .await;\n\n                assert!(result.is_ok(), \"Test module should evaluate\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_send_after_close_fails() {\n        // Test that sending after close returns error\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                ModuleEvaluator::eval_rust::<DgramModule>(ctx.clone(), \"dgram\")\n                    .await\n                    .unwrap();\n\n                let result = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import dgram from 'dgram';\n                        export async function test() {\n                            return new Promise((resolve) => {\n                                const socket = dgram.createSocket('udp4');\n                                \n                                socket.on('listening', () => {\n                                    socket.close();\n                                    try {\n                                        socket.send('test', 12345, 'localhost');\n                                        resolve('no_error');\n                                    } catch (e) {\n                                        resolve('error_thrown');\n                                    }\n                                });\n                                \n                                socket.bind(0);\n                            });\n                        }\n                    \"#,\n                )\n                .await;\n\n                assert!(result.is_ok(), \"Test module should evaluate\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_double_close_fails() {\n        // Test that closing twice throws error\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                ModuleEvaluator::eval_rust::<DgramModule>(ctx.clone(), \"dgram\")\n                    .await\n                    .unwrap();\n\n                let result = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import dgram from 'dgram';\n                        export async function test() {\n                            return new Promise((resolve) => {\n                                const socket = dgram.createSocket('udp4');\n                                \n                                socket.on('listening', () => {\n                                    socket.close();\n                                    try {\n                                        socket.close();\n                                        resolve('no_error');\n                                    } catch (e) {\n                                        resolve('error_thrown');\n                                    }\n                                });\n                                \n                                socket.bind(0);\n                            });\n                        }\n                    \"#,\n                )\n                .await;\n\n                assert!(result.is_ok(), \"Test module should evaluate\");\n            })\n        })\n        .await;\n    }\n}\n"
  },
  {
    "path": "modules/llrt_dgram/src/socket.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::sync::{\n    atomic::{AtomicBool, Ordering},\n    Arc, RwLock,\n};\n\nuse llrt_buffer::Buffer;\nuse llrt_context::CtxExtension;\nuse llrt_events::{EmitError, Emitter, EventEmitter, EventKey, EventList};\nuse llrt_utils::{bytes::ObjectBytes, latch::Latch, object::ObjectExt, result::ResultExt};\nuse rquickjs::{\n    class::{Trace, Tracer},\n    prelude::{Opt, Rest, This},\n    Class, Ctx, Exception, FromJs, Function, IntoJs, JsLifetime, Object, Result, Value,\n};\nuse tokio::{\n    net::UdpSocket,\n    sync::{broadcast, mpsc, oneshot},\n};\nuse tracing::trace;\n\ntype SendResult = std::result::Result<usize, String>;\ntype SendMessage = (Vec<u8>, String, Option<oneshot::Sender<SendResult>>);\n\n#[rquickjs::class]\npub struct Socket<'js> {\n    emitter: EventEmitter<'js>,\n    socket: Option<Arc<UdpSocket>>,\n    is_bound: Arc<AtomicBool>,\n    is_closed: Arc<AtomicBool>,\n    local_address: Option<String>,\n    local_port: Option<u16>,\n    local_family: Option<String>,\n    receiver_running: Arc<AtomicBool>,\n    close_tx: broadcast::Sender<()>,\n    send_tx: Option<mpsc::UnboundedSender<SendMessage>>,\n    ready_latch: Arc<Latch>,\n}\n\nunsafe impl<'js> JsLifetime<'js> for Socket<'js> {\n    type Changed<'to> = Socket<'to>;\n}\n\nimpl<'js> Trace<'js> for Socket<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.emitter.trace(tracer);\n    }\n}\n\nimpl<'js> Emitter<'js> for Socket<'js> {\n    fn get_event_list(&self) -> Arc<RwLock<EventList<'js>>> {\n        self.emitter.get_event_list()\n    }\n\n    fn on_event_changed(&mut self, _event: EventKey<'js>, _added: bool) -> Result<()> {\n        Ok(())\n    }\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl<'js> Socket<'js> {\n    #[qjs(constructor)]\n    pub fn ctor(ctx: Ctx<'js>, type_or_options: Value<'js>) -> Result<Class<'js, Self>> {\n        let socket_type = if let Some(obj) = type_or_options.as_object() {\n            obj.get_optional::<_, String>(\"type\")?\n                .unwrap_or_else(|| \"udp4\".to_string())\n        } else if let Some(type_str) = type_or_options.as_string() {\n            type_str.to_string()?\n        } else {\n            \"udp4\".to_string()\n        };\n\n        // Validate socket type\n        if socket_type != \"udp4\" && socket_type != \"udp6\" {\n            return Err(Exception::throw_type(\n                &ctx,\n                &format!(\"Invalid socket type: {}\", socket_type),\n            ));\n        }\n\n        let emitter = EventEmitter::new();\n        let (close_tx, _) = broadcast::channel(1);\n\n        let instance = Self {\n            emitter,\n            socket: None,\n            is_bound: Arc::new(AtomicBool::new(false)),\n            is_closed: Arc::new(AtomicBool::new(false)),\n            local_address: None,\n            local_port: None,\n            local_family: Some(if socket_type == \"udp4\" {\n                \"IPv4\".to_string()\n            } else {\n                \"IPv6\".to_string()\n            }),\n            receiver_running: Arc::new(AtomicBool::new(false)),\n            close_tx,\n            send_tx: None,\n            ready_latch: Arc::new(Latch::default()),\n        };\n\n        Class::instance(ctx, instance)\n    }\n\n    fn start_listening(\n        socket_class: Class<'js, Self>,\n        ctx: Ctx<'js>,\n        bind_addr: String,\n    ) -> Result<()> {\n        // Check state and get Arc clones in single borrow\n        let (is_closed, receiver_running, ready_latch) = {\n            let borrow = socket_class.borrow();\n            if borrow.is_bound.load(Ordering::SeqCst) {\n                return Err(Exception::throw_message(&ctx, \"ERR_SOCKET_ALREADY_BOUND\"));\n            }\n            if borrow.is_closed.load(Ordering::SeqCst) {\n                return Err(Exception::throw_message(\n                    &ctx,\n                    \"ERR_SOCKET_DGRAM_NOT_RUNNING\",\n                ));\n            }\n            (\n                borrow.is_closed.clone(),\n                borrow.receiver_running.clone(),\n                borrow.ready_latch.clone(),\n            )\n        };\n\n        // Increment latch before spawning - will be decremented when send_tx is ready or on error\n        ready_latch.increment();\n\n        let socket_class2 = socket_class.clone();\n        let socket_class3 = socket_class.clone();\n        ctx.clone().spawn_exit(async move {\n            let bind_result = async {\n                let socket = match UdpSocket::bind(&bind_addr).await {\n                    Ok(s) => s,\n                    Err(e) => {\n                        ready_latch.decrement();\n                        return Err(e).or_throw(&ctx);\n                    },\n                };\n                let local_addr = match socket.local_addr() {\n                    Ok(a) => a,\n                    Err(e) => {\n                        ready_latch.decrement();\n                        return Err(e).or_throw(&ctx);\n                    },\n                };\n\n                let socket_arc = Arc::new(socket);\n\n                // Create MPSC channel for send operations BEFORE starting loops\n                let (send_tx, mut send_rx) = mpsc::unbounded_channel::<SendMessage>();\n\n                let (recv_close_rx, send_close_rx) = {\n                    let mut borrow = socket_class.borrow_mut();\n                    borrow.socket = Some(socket_arc.clone());\n                    borrow.local_address = Some(local_addr.ip().to_string());\n                    borrow.local_port = Some(local_addr.port());\n                    borrow.is_bound.store(true, Ordering::SeqCst);\n                    borrow.send_tx = Some(send_tx);\n                    (borrow.close_tx.subscribe(), borrow.close_tx.subscribe())\n                };\n\n                // Signal that send channel is ready\n                ready_latch.decrement();\n\n                trace!(\"UDP socket bound to {}\", local_addr);\n\n                // Emit 'listening' event\n                Self::emit_str(This(socket_class.clone()), &ctx, \"listening\", vec![], false)?;\n\n                // Start receiver loop\n                let recv_started = receiver_running\n                    .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)\n                    .is_ok();\n\n                if recv_started {\n                    let recv_socket = socket_arc.clone();\n                    let recv_class = socket_class.clone();\n                    let recv_closed = is_closed.clone();\n                    let recv_running = receiver_running.clone();\n                    let recv_ctx = ctx.clone();\n                    let mut close_rx = recv_close_rx;\n\n                    ctx.clone().spawn_exit(async move {\n                        let recv_result = async {\n                            let mut buf = vec![0u8; 65536];\n\n                            loop {\n                                tokio::select! {\n                                    _ = close_rx.recv() => {\n                                        break;\n                                    }\n                                    result = recv_socket.recv_from(&mut buf) => {\n                                        match result {\n                                            Ok((size, peer_addr)) => {\n                                                let data = Buffer(buf[..size].to_vec()).into_js(&recv_ctx)?;\n                                                let info = Object::new(recv_ctx.clone())?;\n                                                info.set(\"address\", peer_addr.ip().to_string())?;\n                                                info.set(\"port\", peer_addr.port())?;\n                                                info.set(\n                                                    \"family\",\n                                                    if peer_addr.is_ipv4() { \"IPv4\" } else { \"IPv6\" },\n                                                )?;\n\n                                                let info_val: Value = info.into();\n                                                Self::emit_str(\n                                                    This(recv_class.clone()),\n                                                    &recv_ctx,\n                                                    \"message\",\n                                                    vec![data, info_val],\n                                                    false,\n                                                )?;\n                                            },\n                                            Err(e) => {\n                                                if recv_closed.load(Ordering::SeqCst) {\n                                                    break;\n                                                }\n                                                return Err(Exception::throw_message(\n                                                    &recv_ctx,\n                                                    &format!(\"UDP receive error: {}\", e),\n                                                ));\n                                            },\n                                        }\n                                    }\n                                }\n                            }\n\n                            recv_running.store(false, Ordering::SeqCst);\n                            Ok(())\n                        }\n                        .await;\n\n                        recv_result.emit_error(\"recv\", &recv_ctx, recv_class)?;\n                        Ok(())\n                    })?;\n                }\n\n                // Start sender loop\n                let send_socket = socket_arc.clone();\n                let mut close_rx = send_close_rx;\n                let send_ctx = ctx.clone();\n                ctx.spawn_exit(async move {\n                    let send_result = {\n                        loop {\n                            tokio::select! {\n                                _ = close_rx.recv() => {\n                                    break;\n                                }\n                                msg = send_rx.recv() => {\n                                    let Some((bytes, dest_addr, result_tx)) = msg else {\n                                        break;\n                                    };\n\n                                    let result = send_socket.send_to(&bytes, &dest_addr).await;\n                                    if let Some(result_tx) = result_tx{\n                                        result_tx.send(result.map_err(|e| e.to_string())).map_err(|_|Exception::throw_message(&send_ctx, \"Failed to call callback in send, channel closed!\"))?;\n                                        continue;\n                                    }\n                                    result.or_throw(&send_ctx)?;\n                                }\n                            }\n                        };\n                        Ok(())\n                    };\n                    send_result.emit_error(\"receive\", &send_ctx, socket_class3)?;\n                    Ok(())\n                })?;\n\n                Ok(())\n            }\n            .await;\n\n            bind_result.emit_error(\"bind\", &ctx, socket_class2)?;\n            Ok(())\n        })?;\n\n        Ok(())\n    }\n\n    #[qjs(skip)]\n    fn ensure_listening(this: Class<'js, Self>, ctx: Ctx<'js>) -> Result<Arc<Latch>> {\n        // Check if already bound and get latch\n        let (is_bound, ready_latch) = {\n            let borrow = this.borrow();\n            (\n                borrow.is_bound.load(Ordering::SeqCst),\n                borrow.ready_latch.clone(),\n            )\n        };\n\n        if !is_bound {\n            // Auto-bind to random port\n            let bind_addr = \"0.0.0.0:0\".to_string();\n            Self::start_listening(this.clone(), ctx.clone(), bind_addr)?;\n        }\n\n        Ok(ready_latch)\n    }\n\n    pub fn bind(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        args: Rest<Value<'js>>,\n    ) -> Result<Class<'js, Self>> {\n        let mut port = 0u16;\n        let mut address = \"0.0.0.0\".to_string();\n        let mut callback: Option<Function> = None;\n\n        // Parse arguments: can be (port, address, callback), (port, callback), (callback), or (options, callback)\n        let mut args_iter = args.0.into_iter();\n\n        if let Some(first_arg) = args_iter.next() {\n            if let Some(func) = first_arg.as_function() {\n                // bind(callback)\n                callback = Some(func.clone());\n            } else if let Some(num) = first_arg.as_int() {\n                // bind(port, ...)\n                port = num as u16;\n                if let Some(second_arg) = args_iter.next() {\n                    if let Some(func) = second_arg.as_function() {\n                        // bind(port, callback)\n                        callback = Some(func.clone());\n                    } else if let Some(addr_str) = second_arg.as_string() {\n                        // bind(port, address, ...)\n                        address = addr_str.to_string()?;\n                        if let Some(third_arg) = args_iter.next() {\n                            if let Some(func) = third_arg.as_function() {\n                                // bind(port, address, callback)\n                                callback = Some(func.clone());\n                            }\n                        }\n                    }\n                }\n            } else if let Some(obj) = first_arg.as_object() {\n                // bind(options, callback)\n                if let Some(p) = obj.get::<_, Option<u16>>(\"port\")? {\n                    port = p;\n                }\n                if let Some(addr) = obj.get::<_, Option<String>>(\"address\")? {\n                    address = addr;\n                }\n                if let Some(second_arg) = args_iter.next() {\n                    if let Some(func) = second_arg.as_function() {\n                        callback = Some(func.clone());\n                    }\n                }\n            }\n        }\n\n        if let Some(cb) = callback {\n            Self::add_event_listener_str(This(this.clone()), &ctx, \"listening\", cb, true, true)?;\n        }\n\n        let bind_addr = [&address, \":\", &port.to_string()].concat();\n\n        Self::start_listening(this.0.clone(), ctx, bind_addr)?;\n\n        Ok(this.0)\n    }\n\n    pub fn send(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        msg: Value<'js>,\n        port: u16,\n        address: Opt<String>,\n        callback: Opt<Function<'js>>,\n    ) -> Result<()> {\n        let address = address.0.unwrap_or_else(|| \"localhost\".to_string());\n\n        // Extract bytes from message\n        let bytes: Vec<u8> = if let Some(str_val) = msg.as_string() {\n            str_val.to_string()?.into_bytes()\n        } else {\n            ObjectBytes::from_js(&ctx, msg)?\n                .try_into()\n                .map_err(|e: std::rc::Rc<str>| Exception::throw_type(&ctx, &e))?\n        };\n\n        // Check if socket is closed\n        {\n            let borrow = this.borrow();\n            if borrow.is_closed.load(Ordering::SeqCst) {\n                return Err(Exception::throw_message(&ctx, \"Socket is closed\"));\n            }\n        }\n\n        // Format destination address\n        let dest_addr = [&address, \":\", &port.to_string()].concat();\n\n        // Ensure listener is started and get latch to wait on\n        let ready_latch = Self::ensure_listening(this.0.clone(), ctx.clone())?;\n\n        let socket_class = this.0.clone();\n        let socket_class2 = this.0.clone();\n\n        let cb = callback.0;\n\n        ctx.clone().spawn_exit(async move {\n            let send_result = async {\n                // Wait for send channel to be ready\n                ready_latch.wait().await;\n\n                // Send to the channel\n                let result_rx = {\n                    let (result_tx, result_rx) = if cb.is_some() {\n                        let (result_tx, result_rx) = oneshot::channel();\n                        (Some(result_tx), Some(result_rx))\n                    } else {\n                        (None, None)\n                    };\n\n                    let borrow = socket_class.borrow();\n                    let send_tx = borrow.send_tx.as_ref().ok_or_else(|| {\n                        Exception::throw_message(&ctx, \"Failed to initialize socket\")\n                    })?;\n\n                    send_tx\n                        .send((bytes, dest_addr, result_tx))\n                        .map_err(|_| Exception::throw_message(&ctx, \"Failed to send message\"))?;\n                    result_rx\n                };\n\n                //we dont have any callback\n                let Some(result_rx) = result_rx else {\n                    return Ok(());\n                };\n\n                // Wait for result\n                let result = result_rx.await.unwrap_or(Err(\"Socket closed\".to_string()));\n\n                let Some(cb) = cb else {\n                    result.or_throw(&ctx)?;\n                    return Ok(());\n                };\n\n                // Callback handles both success and error\n                match result {\n                    Ok(sent) => {\n                        cb.call::<_, ()>((Value::new_null(ctx.clone()), sent))?;\n                    },\n                    Err(e) => {\n                        let err = Exception::from_message(ctx.clone(), &e)?;\n                        cb.call::<_, ()>((err,))?;\n                    },\n                }\n\n                Ok(())\n            }\n            .await;\n\n            send_result.emit_error(\"send\", &ctx, socket_class2)?;\n            Ok(())\n        })?;\n\n        Ok(())\n    }\n\n    pub fn close(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        callback: Opt<Function<'js>>,\n    ) -> Result<Class<'js, Self>> {\n        let already_closed = {\n            let borrow = this.borrow();\n            let was_closed = borrow\n                .is_closed\n                .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)\n                .is_err();\n            if !was_closed {\n                // Send close signal to interrupt receive/send loops\n                let _ = borrow.close_tx.send(());\n            }\n            was_closed\n        };\n\n        if already_closed {\n            return Err(Exception::throw_message(\n                &ctx,\n                \"ERR_SOCKET_DGRAM_NOT_RUNNING\",\n            ));\n        }\n\n        if let Some(cb) = callback.0 {\n            Self::add_event_listener_str(This(this.clone()), &ctx, \"close\", cb, true, true)?;\n        }\n\n        // Drop the socket and clear send channel\n        {\n            let mut borrow = this.borrow_mut();\n            borrow.socket = None;\n            borrow.send_tx = None;\n        }\n\n        // Emit close event directly (don't rely on sender loop which may not have started)\n        let this_clone = this.0.clone();\n        ctx.clone().spawn_exit(async move {\n            Self::emit_str(This(this_clone), &ctx, \"close\", vec![], false)?;\n            Ok(())\n        })?;\n\n        Ok(this.0)\n    }\n\n    pub fn address(this: This<Class<'js, Self>>, ctx: Ctx<'js>) -> Result<Object<'js>> {\n        let borrow = this.borrow();\n\n        let obj = Object::new(ctx)?;\n\n        if let Some(addr) = &borrow.local_address {\n            obj.set(\"address\", addr.clone())?;\n        }\n        if let Some(port) = borrow.local_port {\n            obj.set(\"port\", port)?;\n        }\n        if let Some(family) = &borrow.local_family {\n            obj.set(\"family\", family.clone())?;\n        }\n\n        Ok(obj)\n    }\n\n    pub fn unref(this: This<Class<'js, Self>>) -> Result<Class<'js, Self>> {\n        // In Node.js, unref() allows the process to exit if this is the only active handle\n        // In LLRT's context, this is a no-op but we keep it for API compatibility\n        trace!(\"Socket.unref() called - no-op for API compatibility\");\n        Ok(this.0)\n    }\n\n    #[qjs(rename = \"ref\")]\n    pub fn r#ref(this: This<Class<'js, Self>>) -> Result<Class<'js, Self>> {\n        // Counterpart to unref(), also a no-op in LLRT\n        trace!(\"Socket.ref() called - no-op for API compatibility\");\n        Ok(this.0)\n    }\n}\n"
  },
  {
    "path": "modules/llrt_dns/Cargo.toml",
    "content": "[package]\nname = \"llrt_dns\"\ndescription = \"LLRT Module dns\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\nreadme = \"README.md\"\n\n[lib]\nname = \"llrt_dns\"\npath = \"src/lib.rs\"\n\n[dependencies]\neither = { version = \"1\", default-features = false }\nllrt_context = { version = \"0.8.1-beta\", path = \"../../libs/llrt_context\" }\nllrt_hooking = { version = \"0.8.1-beta\", path = \"../../libs/llrt_hooking\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", features = [\n  \"macro\",\n  \"either\",\n], default-features = false }\ntokio = { version = \"1\", features = [\"net\"], default-features = false }\n\n[dev-dependencies]\nllrt_test = { path = \"../../libs/llrt_test\" }\ntokio = { version = \"1\", features = [\n  \"macros\",\n  \"test-util\",\n], default-features = false }\n"
  },
  {
    "path": "modules/llrt_dns/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_utils::module::{export_default, ModuleInfo};\nuse rquickjs::{\n    module::{Declarations, Exports, ModuleDef},\n    prelude::Func,\n    Ctx, Result,\n};\n\nuse crate::lookup::lookup;\n\nmod lookup;\n\npub struct DnsModule;\n\nimpl ModuleDef for DnsModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(\"lookup\")?;\n\n        declare.declare(\"default\")?;\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        export_default(ctx, exports, |default| {\n            default.set(\"lookup\", Func::from(lookup))?;\n            Ok(())\n        })?;\n\n        Ok(())\n    }\n}\n\nimpl From<DnsModule> for ModuleInfo<DnsModule> {\n    fn from(val: DnsModule) -> Self {\n        ModuleInfo {\n            name: \"dns\",\n            module: val,\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_dns/src/lookup.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::net::SocketAddr;\nuse std::result::Result as StdResult;\n\nuse either::Either;\nuse llrt_context::CtxExtension;\nuse llrt_hooking::{invoke_async_hook, register_finalization_registry, HookType};\nuse llrt_utils::{provider::ProviderType, result::ResultExt};\nuse rquickjs::{\n    prelude::Opt, qjs, Ctx, Error, Exception, FromJs, Function, IntoJs, Null, Object, Result, Value,\n};\n\nconst ERROR_MSG_OPTIONS_FAMILY: &str = \"The argument 'family' must be one of: 0, 4, 6\";\nconst ERROR_MSG_OPTIONS_ORDER: &str =\n    \"The argument 'order' must be one of: 'verbatim', 'ipv4first', 'ipv6first'\";\n\npub fn lookup<'js>(\n    ctx: Ctx<'js>,\n    hostname: String,\n    options_or_callback: Either<Function<'js>, LookupOptions>,\n    callback: Opt<Function<'js>>,\n) -> Result<()> {\n    let (cb, options) = match options_or_callback {\n        Either::Left(cb) => (cb, LookupOptions::default()),\n        Either::Right(options) => {\n            let cb = callback\n                .0\n                .or_throw_msg(&ctx, \"Callback parameter is missing\")?;\n            (cb, options)\n        },\n    };\n\n    // SAFETY: Since it checks in advance whether it is an Function type, we can always get a pointer to the Function.\n    let uid = unsafe { qjs::JS_VALUE_GET_PTR(cb.as_raw()) } as usize;\n    register_finalization_registry(&ctx, cb.clone().into_value(), uid)?;\n    invoke_async_hook(&ctx, HookType::Init, ProviderType::GetAddrInfoReqWrap, uid)?;\n\n    ctx.clone().spawn_exit(async move {\n        match lookup_host(&hostname, options.family, options.order).await {\n            Ok(addrs) => {\n                invoke_async_hook(&ctx, HookType::Before, ProviderType::None, uid)?;\n                if options.all {\n                    () = cb.call((Null.into_js(&ctx), addrs))?;\n                } else {\n                    let addr = addrs.into_iter().next();\n                    if let Some(addr) = addr {\n                        () = cb.call((Null.into_js(&ctx), addr.address, addr.family))?;\n                    } else {\n                        () =\n                            cb.call((Exception::from_message(ctx.clone(), \"No address found\"),))?;\n                    }\n                }\n                invoke_async_hook(&ctx, HookType::After, ProviderType::None, uid)?;\n                Ok::<_, Error>(())\n            },\n            Err(err) => {\n                invoke_async_hook(&ctx, HookType::Before, ProviderType::None, uid)?;\n                () = cb.call((Exception::from_message(ctx.clone(), &err.to_string()),))?;\n                invoke_async_hook(&ctx, HookType::After, ProviderType::None, uid)?;\n                Ok(())\n            },\n        }\n    })?;\n    Ok(())\n}\n\nasync fn lookup_host(\n    hostname: &str,\n    family: i32,\n    order: LookupOrder,\n) -> StdResult<Vec<LookupValue>, std::io::Error> {\n    let mut addrs = tokio::net::lookup_host((hostname, 0))\n        .await?\n        .filter_map(|addr| {\n            if matches!(family, 4 | 0) {\n                if let SocketAddr::V4(ipv4) = addr {\n                    return Some(LookupValue {\n                        address: ipv4.ip().to_string(),\n                        family: 4,\n                    });\n                }\n            }\n            if matches!(family, 6 | 0) {\n                if let SocketAddr::V6(ipv6) = addr {\n                    return Some(LookupValue {\n                        address: ipv6.ip().to_string(),\n                        family: 6,\n                    });\n                }\n            }\n            None\n        })\n        .collect();\n    match order {\n        LookupOrder::Verbatim => Ok(addrs),\n        LookupOrder::Ipv4First => {\n            addrs.sort_by(|a, b| a.family.cmp(&b.family));\n            Ok(addrs)\n        },\n        LookupOrder::Ipv6First => {\n            addrs.sort_by(|a, b| b.family.cmp(&a.family));\n            Ok(addrs)\n        },\n    }\n}\n\nstruct LookupValue {\n    address: String,\n    family: i32,\n}\n\nimpl<'js> IntoJs<'js> for LookupValue {\n    fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {\n        let object = Object::new(ctx.clone())?;\n        object.set(\"address\", self.address)?;\n        object.set(\"family\", self.family)?;\n        Ok(object.into_value())\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum LookupOrder {\n    Verbatim,\n    Ipv4First,\n    Ipv6First,\n}\n\npub struct LookupOptions {\n    family: i32,\n    all: bool,\n    order: LookupOrder,\n}\n\nimpl Default for LookupOptions {\n    fn default() -> Self {\n        Self {\n            family: 0,\n            all: false,\n            order: LookupOrder::Verbatim,\n        }\n    }\n}\n\nimpl<'js> FromJs<'js> for LookupOptions {\n    fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        let mut family = 0;\n        let mut all = false;\n        let mut order = LookupOrder::Verbatim;\n\n        if let Some(v) = value.as_int() {\n            if !matches!(v, 4 | 6 | 0) {\n                return Err(Exception::throw_type(ctx, ERROR_MSG_OPTIONS_FAMILY));\n            }\n            family = v;\n        } else if let Some(options) = value.as_object() {\n            // Parse family\n            if let Ok(family_value) = options.get::<_, Value<'js>>(\"family\") {\n                if let Some(v) = family_value.as_int() {\n                    if !matches!(v, 4 | 6 | 0) {\n                        return Err(Exception::throw_type(ctx, ERROR_MSG_OPTIONS_FAMILY));\n                    }\n                    family = v;\n                } else if let Some(v) = family_value.as_string() {\n                    let family_string = v.to_string()?;\n                    match family_string.as_str() {\n                        \"IPv4\" => family = 4,\n                        \"IPv6\" => family = 6,\n                        _ => {\n                            return Err(Exception::throw_type(ctx, ERROR_MSG_OPTIONS_FAMILY));\n                        },\n                    }\n                } else if family_value.is_null() || family_value.is_undefined() {\n                    // Use default family\n                } else {\n                    return Err(Exception::throw_type(ctx, ERROR_MSG_OPTIONS_FAMILY));\n                }\n            }\n\n            // Parse all\n            if let Ok(all_value) = options.get::<_, bool>(\"all\") {\n                all = all_value;\n            }\n\n            // Parse order\n            if let Ok(order_value) = options.get::<_, String>(\"order\") {\n                match order_value.as_str() {\n                    \"verbatim\" => order = LookupOrder::Verbatim,\n                    \"ipv4first\" => order = LookupOrder::Ipv4First,\n                    \"ipv6first\" => order = LookupOrder::Ipv6First,\n                    _ => {\n                        return Err(Exception::throw_type(ctx, ERROR_MSG_OPTIONS_ORDER));\n                    },\n                }\n            }\n        } else if value.is_null() || value.is_undefined() {\n            // Use default options\n        } else {\n            return Err(Exception::throw_type(ctx, ERROR_MSG_OPTIONS_FAMILY));\n        }\n\n        Ok(LookupOptions { family, all, order })\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use llrt_test::{call_test, call_test_err, test_async_with, ModuleEvaluator};\n    use llrt_utils::primordials::{BasePrimordials, Primordial};\n\n    use crate::DnsModule;\n\n    #[tokio::test]\n    async fn test_lookup() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                BasePrimordials::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<DnsModule>(ctx.clone(), \"dns\")\n                    .await\n                    .unwrap();\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { lookup } from 'dns';\n\n                        export async function test(hostname) {\n                            return new Promise((resolve, reject) => {\n                                lookup(hostname, (err, address, family) => {\n                                    if (err) reject(err);\n                                    else resolve(`${address}:${family}`);\n                                });\n                            });\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n\n                let result = call_test::<String, _>(&ctx, &module, (\"www.amazon.com\",)).await;\n\n                assert!(result.ends_with(\":4\") || result.ends_with(\":6\"));\n            })\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_lookup_v6() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                BasePrimordials::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<DnsModule>(ctx.clone(), \"dns\")\n                    .await\n                    .unwrap();\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { lookup } from 'dns';\n\n                        export async function test(hostname) {\n                            return new Promise((resolve, reject) => {\n                                lookup(hostname, 6, (err, address, family) => {\n                                    if (err) reject(err);\n                                    else resolve(`${address}:${family}`);\n                                });\n                            });\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n\n                let result = call_test_err::<String, _>(&ctx, &module, (\"www.amazon.com\",)).await;\n\n                // Not all systems support IPv6 resolution so we need to support it\n                match result {\n                    Ok(result) => assert!(result.ends_with(\":6\")),\n                    Err(err) => assert!(err.to_string().contains(\"No address found\")),\n                }\n            })\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_lookup_all() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                BasePrimordials::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<DnsModule>(ctx.clone(), \"dns\")\n                    .await\n                    .unwrap();\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { lookup } from 'dns';\n\n                        export async function test(hostname) {\n                            return new Promise((resolve, reject) => {\n                                lookup(hostname, { all: true }, (err, addresses) => {\n                                    if (err) reject(err);\n                                    else resolve(addresses.map(addr => `${addr.address}:${addr.family}`));\n                                });\n                            });\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n\n                let result = call_test::<Vec<String>, _>(&ctx, &module, (\"www.amazon.com\",)).await;\n\n                assert!(!result.is_empty());\n                assert!(result.iter().all(|addr| addr.ends_with(\":4\") || addr.ends_with(\":6\")));\n            })\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_lookup_order() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                BasePrimordials::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<DnsModule>(ctx.clone(), \"dns\")\n                    .await\n                    .unwrap();\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { lookup } from 'dns';\n\n                        export async function test(hostname) {\n                            return new Promise((resolve, reject) => {\n                                lookup(hostname, { all: true, order: 'ipv6first' }, (err, addresses) => {\n                                    if (err) reject(err);\n                                    else resolve(addresses.map(addr => `${addr.address}:${addr.family}`));\n                                });\n                            });\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n\n                let result = call_test::<Vec<String>, _>(&ctx, &module, (\"www.amazon.com\",)).await;\n\n                assert!(!result.is_empty());\n                let first_ipv4 = result.iter().position(|addr| addr.ends_with(\":4\")).unwrap();\n                let last_ipv6 = result.iter().rposition(|addr| addr.ends_with(\":6\")).unwrap_or(result.len().saturating_sub(1));\n                assert!(last_ipv6 <= first_ipv4);\n            })\n        })\n        .await\n    }\n}\n"
  },
  {
    "path": "modules/llrt_events/Cargo.toml",
    "content": "[package]\nname = \"llrt_events\"\ndescription = \"LLRT Module events\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[lib]\nname = \"llrt_events\"\npath = \"src/lib.rs\"\n\n[dependencies]\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", default-features = false }\ntracing = { version = \"0.1\", default-features = false }\n"
  },
  {
    "path": "modules/llrt_events/src/custom_event.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse rquickjs::{prelude::Opt, Ctx, IntoJs, Null, Result, Value};\n\nuse llrt_utils::object::ObjectExt;\n\n#[rquickjs::class]\n#[derive(rquickjs::class::Trace, rquickjs::JsLifetime)]\npub struct CustomEvent<'js> {\n    event_type: String,\n    detail: Option<Value<'js>>,\n}\n\n#[rquickjs::methods]\nimpl<'js> CustomEvent<'js> {\n    #[qjs(constructor)]\n    pub fn new(event_type: String, options: Opt<Value<'js>>) -> Result<Self> {\n        let mut detail = None;\n        if let Some(options) = options.0 {\n            if let Some(opt) = options.get_optional(\"detail\")? {\n                detail = opt;\n            }\n        }\n        Ok(Self { event_type, detail })\n    }\n\n    #[qjs(get)]\n    pub fn detail(&self, ctx: Ctx<'js>) -> Result<Value<'js>> {\n        if let Some(detail) = &self.detail {\n            return Ok(detail.clone());\n        }\n        Null.into_js(&ctx)\n    }\n\n    #[qjs(get, rename = \"type\")]\n    pub fn event_type(&self) -> String {\n        self.event_type.clone()\n    }\n}\n"
  },
  {
    "path": "modules/llrt_events/src/event.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse rquickjs::{prelude::Opt, Result, Value};\n\nuse llrt_utils::object::ObjectExt;\n\n#[rquickjs::class]\n#[derive(rquickjs::class::Trace, rquickjs::JsLifetime)]\npub struct Event {\n    event_type: String,\n    bubbles: bool,\n    cancelable: bool,\n    composed: bool,\n}\n\n#[rquickjs::methods]\nimpl Event {\n    #[qjs(constructor)]\n    pub fn new(event_type: String, options: Opt<Value<'_>>) -> Result<Self> {\n        let mut bubbles = false;\n        let mut cancelable = false;\n        let mut composed = false;\n        if let Some(options) = options.0 {\n            if let Some(opt) = options.get_optional(\"bubbles\")? {\n                bubbles = opt;\n            }\n            if let Some(opt) = options.get_optional(\"cancelable\")? {\n                cancelable = opt;\n            }\n            if let Some(opt) = options.get_optional(\"composed\")? {\n                composed = opt;\n            }\n        }\n        Ok(Self {\n            event_type,\n            bubbles,\n            cancelable,\n            composed,\n        })\n    }\n\n    #[qjs(get)]\n    pub fn bubbles(&self) -> bool {\n        self.bubbles\n    }\n\n    #[qjs(get)]\n    pub fn cancelable(&self) -> bool {\n        self.cancelable\n    }\n\n    #[qjs(get)]\n    pub fn composed(&self) -> bool {\n        self.composed\n    }\n\n    #[qjs(get, rename = \"type\")]\n    pub fn event_type(&self) -> String {\n        self.event_type.clone()\n    }\n}\n"
  },
  {
    "path": "modules/llrt_events/src/event_target.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::sync::{Arc, RwLock};\n\nuse rquickjs::{\n    class::{Trace, Tracer},\n    JsLifetime,\n};\n\nuse super::{Emitter, EventList, Events};\n\n#[rquickjs::class]\n#[derive(Clone)]\npub struct EventTarget<'js> {\n    pub events: Events<'js>,\n}\n\nunsafe impl<'js> JsLifetime<'js> for EventTarget<'js> {\n    type Changed<'to> = EventTarget<'to>;\n}\n\nimpl<'js> Emitter<'js> for EventTarget<'js> {\n    fn get_event_list(&self) -> Arc<RwLock<EventList<'js>>> {\n        self.events.clone()\n    }\n}\n\nimpl<'js> Trace<'js> for EventTarget<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.trace_event_emitter(tracer);\n    }\n}\n\n#[rquickjs::methods]\nimpl<'js> EventTarget<'js> {\n    #[qjs(constructor)]\n    pub fn new() -> Self {\n        Self {\n            #[allow(clippy::arc_with_non_send_sync)]\n            events: Arc::new(RwLock::new(Vec::new())),\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_events/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#![allow(\n    clippy::mutable_key_type,\n    clippy::for_kv_map,\n    clippy::new_without_default\n)]\nuse std::{\n    rc::Rc,\n    sync::{Arc, RwLock},\n};\n\nuse llrt_utils::{\n    error::ErrorExtensions, module::ModuleInfo, object::ObjectExt, result::ResultExt,\n};\nuse rquickjs::{\n    class::{JsClass, OwnedBorrow, Trace, Tracer},\n    module::{Declarations, Exports, ModuleDef},\n    prelude::{Func, Opt, Rest, This},\n    CatchResultExt, Class, Ctx, Function, JsLifetime, Object, Result, String as JsString, Symbol,\n    Value,\n};\nuse tracing::trace;\n\nuse self::{custom_event::CustomEvent, event::Event, event_target::EventTarget};\n\npub mod custom_event;\npub mod event;\npub mod event_target;\n\n#[derive(Clone, Debug)]\npub enum EventKey<'js> {\n    Symbol(Symbol<'js>),\n    String(Rc<str>),\n}\n\nimpl<'js> EventKey<'js> {\n    fn from_value(ctx: &Ctx, value: Value<'js>) -> Result<Self> {\n        if value.is_string() {\n            let key: String = value.get()?;\n            Ok(EventKey::String(key.into()))\n        } else {\n            let sym = value.into_symbol().ok_or(\"Not a symbol\").or_throw(ctx)?;\n            Ok(EventKey::Symbol(sym))\n        }\n    }\n}\n\nimpl Eq for EventKey<'_> {}\n\nimpl PartialEq for EventKey<'_> {\n    fn eq(&self, other: &Self) -> bool {\n        match (self, other) {\n            (EventKey::Symbol(symbol1), EventKey::Symbol(symbol2)) => symbol1 == symbol2,\n            (EventKey::String(str1), EventKey::String(str2)) => str1 == str2,\n            _ => false,\n        }\n    }\n}\n\npub struct EventItem<'js> {\n    callback: Function<'js>,\n    once: bool,\n}\n\npub type EventList<'js> = Vec<(EventKey<'js>, Vec<EventItem<'js>>)>;\npub type Events<'js> = Arc<RwLock<EventList<'js>>>;\n\n#[rquickjs::class]\n#[derive(Clone)]\npub struct EventEmitter<'js> {\n    pub events: Events<'js>,\n}\n\nunsafe impl<'js> JsLifetime<'js> for EventEmitter<'js> {\n    type Changed<'to> = EventEmitter<'to>;\n}\n\nimpl<'js> Emitter<'js> for EventEmitter<'js> {\n    fn get_event_list(&self) -> Arc<RwLock<EventList<'js>>> {\n        self.events.clone()\n    }\n}\n\nimpl<'js> Trace<'js> for EventEmitter<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.trace_event_emitter(tracer);\n    }\n}\n\n#[rquickjs::methods]\nimpl<'js> EventEmitter<'js> {\n    #[qjs(constructor)]\n    pub fn new() -> Self {\n        Self {\n            #[allow(clippy::arc_with_non_send_sync)]\n            events: Arc::new(RwLock::new(Vec::new())),\n        }\n    }\n}\n\npub trait EmitError<'js> {\n    fn emit_error<C>(self, id: &'static str, ctx: &Ctx<'js>, this: Class<'js, C>) -> Result<bool>\n    where\n        C: Emitter<'js>;\n}\n\nimpl<'js, T> EmitError<'js> for Result<T> {\n    fn emit_error<C>(self, id: &'static str, ctx: &Ctx<'js>, this: Class<'js, C>) -> Result<bool>\n    where\n        C: Emitter<'js>,\n    {\n        if let Err(err) = self.catch(ctx) {\n            trace!(\"Error caught in: {}\", id);\n            if this.borrow().has_listener_str(\"error\") {\n                let error_value = err.into_value(ctx)?;\n                C::emit_str(This(this), ctx, \"error\", vec![error_value], false)?;\n                return Ok(true);\n            }\n            return Err(err.throw(ctx));\n        }\n        Ok(false)\n    }\n}\n\npub trait Emitter<'js>\nwhere\n    Self: JsClass<'js> + Sized + 'js,\n{\n    fn get_event_list(&self) -> Arc<RwLock<EventList<'js>>>;\n\n    fn on_event_changed(&mut self, _event: EventKey<'js>, _added: bool) -> Result<()> {\n        Ok(())\n    }\n\n    fn add_event_emitter_prototype(ctx: &Ctx<'js>) -> Result<Object<'js>> {\n        let proto = Class::<Self>::prototype(ctx)?\n            .or_throw_msg(ctx, \"Prototype for EventEmitter not found\")?;\n\n        let on = Function::new(ctx.clone(), Self::on)?;\n        let off = Function::new(ctx.clone(), Self::remove_event_listener)?;\n\n        proto.set(\"once\", Func::from(Self::once))?;\n\n        proto.set(\"on\", on.clone())?;\n\n        proto.set(\"emit\", Func::from(Self::emit))?;\n\n        proto.set(\"prependListener\", Func::from(Self::prepend_listener))?;\n\n        proto.set(\n            \"prependOnceListener\",\n            Func::from(Self::prepend_once_listener),\n        )?;\n\n        proto.set(\"off\", off.clone())?;\n\n        proto.set(\"eventNames\", Func::from(Self::event_names))?;\n\n        proto.set(\"addListener\", on)?;\n\n        proto.set(\"removeListener\", off)?;\n\n        Ok(proto)\n    }\n\n    fn add_event_target_prototype(ctx: &Ctx<'js>) -> Result<Object<'js>> {\n        let proto = Class::<Self>::prototype(ctx)?\n            .or_throw_msg(ctx, \"Prototype for EventTarget not found\")?;\n\n        let on = Function::new(ctx.clone(), Self::evt_add_event_listener)?;\n        let off = Function::new(ctx.clone(), Self::remove_event_listener)?;\n\n        proto.set(\"dispatchEvent\", Func::from(Self::evt_dispatch_event))?;\n\n        proto.set(\"addEventListener\", on)?;\n\n        proto.set(\"removeEventListener\", off)?;\n\n        Ok(proto)\n    }\n\n    fn trace_event_emitter<'a>(&self, tracer: Tracer<'a, 'js>) {\n        let events = self.get_event_list();\n        let events = events.read().unwrap();\n        for (key, items) in events.iter() {\n            if let EventKey::Symbol(sym) = &key {\n                tracer.mark(sym);\n            }\n\n            for item in items {\n                tracer.mark(&item.callback);\n            }\n        }\n    }\n\n    fn remove_event_listener_str(\n        this: This<Class<'js, Self>>,\n        ctx: &Ctx<'js>,\n        event: &str,\n        listener: Function<'js>,\n    ) -> Result<Class<'js, Self>> {\n        let event = to_event(ctx, event)?;\n        Self::remove_event_listener(this, ctx.clone(), event, listener)\n    }\n\n    fn remove_event_listener(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        event: Value<'js>,\n        listener: Function<'js>,\n    ) -> Result<Class<'js, Self>> {\n        let events = this.clone().borrow().get_event_list();\n        let mut events = events.write().or_throw(&ctx)?;\n\n        let key = EventKey::from_value(&ctx, event)?;\n        if let Some(index) = events.iter_mut().position(|(k, _)| k == &key) {\n            let items = &mut events[index].1;\n            if let Some(pos) = items.iter().position(|item| item.callback == listener) {\n                items.remove(pos);\n                if items.is_empty() {\n                    events.remove(index);\n                }\n            }\n        };\n\n        Ok(this.0)\n    }\n\n    fn add_event_listener_str(\n        this: This<Class<'js, Self>>,\n        ctx: &Ctx<'js>,\n        event: &str,\n        listener: Function<'js>,\n        prepend: bool,\n        once: bool,\n    ) -> Result<Class<'js, Self>> {\n        let event = to_event(ctx, event)?;\n        Self::add_event_listener(this, ctx.clone(), event, listener, prepend, once)\n    }\n\n    fn once(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        event: Value<'js>,\n        listener: Function<'js>,\n    ) -> Result<Class<'js, Self>> {\n        Self::add_event_listener(this, ctx, event, listener, false, true)\n    }\n\n    fn on(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        event: Value<'js>,\n        listener: Function<'js>,\n    ) -> Result<Class<'js, Self>> {\n        Self::add_event_listener(this, ctx, event, listener, false, false)\n    }\n\n    fn prepend_listener(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        event: Value<'js>,\n        listener: Function<'js>,\n    ) -> Result<Class<'js, Self>> {\n        Self::add_event_listener(this, ctx, event, listener, true, false)\n    }\n\n    fn prepend_once_listener(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        event: Value<'js>,\n        listener: Function<'js>,\n    ) -> Result<Class<'js, Self>> {\n        Self::add_event_listener(this, ctx, event, listener, true, true)\n    }\n\n    fn evt_add_event_listener(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        event: Value<'js>,\n        listener: Function<'js>,\n        options: Opt<Object<'js>>,\n    ) -> Result<Class<'js, Self>> {\n        let mut once = false;\n        if let Some(opt) = options.0 {\n            if let Some(once_opt) = opt.get(\"once\")? {\n                once = once_opt;\n            }\n        }\n        Self::add_event_listener(this, ctx, event, listener, false, once)\n    }\n\n    fn add_event_listener(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        event: Value<'js>,\n        listener: Function<'js>,\n        prepend: bool,\n        once: bool,\n    ) -> Result<Class<'js, Self>> {\n        let this2 = this.clone();\n        let events = &this2.borrow().get_event_list();\n        let mut events = events.write().or_throw(&ctx)?;\n        let key = EventKey::from_value(&ctx, event)?;\n        let mut is_new = false;\n\n        let items = match events.iter_mut().find(|(k, _)| k == &key) {\n            Some((_, entry_items)) => entry_items,\n            None => {\n                let new_items = Vec::new();\n                is_new = true;\n                events.push((key.clone(), new_items));\n                &mut events.last_mut().unwrap().1\n            },\n        };\n\n        let item = EventItem {\n            callback: listener,\n            once,\n        };\n        if !prepend {\n            items.push(item);\n        } else {\n            items.insert(0, item);\n        }\n        if is_new {\n            this2.borrow_mut().on_event_changed(key, true)?\n        }\n        Ok(this.0)\n    }\n\n    fn has_listener_str(&self, event: &str) -> bool {\n        let key = EventKey::String(event.into());\n        has_key(self.get_event_list(), key)\n    }\n\n    #[allow(dead_code)]\n    fn has_listener(&self, ctx: Ctx<'js>, event: Value<'js>) -> Result<bool> {\n        let key = EventKey::from_value(&ctx, event)?;\n        Ok(has_key(self.get_event_list(), key))\n    }\n\n    #[allow(dead_code)]\n    fn get_listeners(&self, ctx: &Ctx<'js>, event: Value<'js>) -> Result<Vec<Function<'js>>> {\n        let key = EventKey::from_value(ctx, event)?;\n        Ok(find_all_listeners(self.get_event_list(), key))\n    }\n\n    fn get_listeners_str(&self, event: &str) -> Vec<Function<'js>> {\n        let key = EventKey::String(event.into());\n        find_all_listeners(self.get_event_list(), key)\n    }\n\n    fn do_emit(\n        event: Value<'js>,\n        this: This<Class<'js, Self>>,\n        ctx: &Ctx<'js>,\n        args: Rest<Value<'js>>,\n        defer: bool,\n    ) -> Result<()> {\n        let this2 = this.clone();\n        let events = &this2.borrow().get_event_list();\n        let mut events = events.write().or_throw(ctx)?;\n        let key = EventKey::from_value(ctx, event)?;\n\n        if let Some(index) = events.iter_mut().position(|(k, _)| k == &key) {\n            let items = &mut events[index].1;\n            let mut callbacks = Vec::with_capacity(items.len());\n            items.retain(|item: &EventItem<'_>| {\n                callbacks.push(item.callback.clone());\n                !item.once\n            });\n            if items.is_empty() {\n                events.remove(index);\n                this.borrow_mut().on_event_changed(key, false)?;\n            }\n            drop(events);\n            for callback in callbacks {\n                let args = args.iter().map(|arg| arg.to_owned()).collect();\n                let args = Rest(args);\n                let this = This(this.clone());\n                if defer {\n                    callback.defer((this, args))?;\n                } else {\n                    callback.call::<_, ()>((this, args))?;\n                }\n            }\n        }\n\n        Ok(())\n    }\n\n    fn emit_str(\n        this: This<Class<'js, Self>>,\n        ctx: &Ctx<'js>,\n        event: &str,\n        args: Vec<Value<'js>>,\n        defer: bool,\n    ) -> Result<()> {\n        let event = to_event(ctx, event)?;\n        Self::do_emit(event, this, ctx, args.into(), defer)\n    }\n\n    fn emit(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        event: Value<'js>,\n        args: Rest<Value<'js>>,\n    ) -> Result<()> {\n        Self::do_emit(event, this, &ctx, args, false)\n    }\n\n    fn evt_dispatch_event(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        event: Value<'js>,\n    ) -> Result<()> {\n        let event_type = event.get_optional(\"type\")?.unwrap();\n        Self::do_emit(event_type, this, &ctx, Rest(vec![event]), false)\n    }\n\n    fn event_names(this: This<OwnedBorrow<'js, Self>>, ctx: Ctx<'js>) -> Result<Vec<Value<'js>>> {\n        let events = this.get_event_list();\n        let events = events.read().or_throw(&ctx)?;\n\n        let mut names = Vec::with_capacity(events.len());\n        for (key, _entry) in events.iter() {\n            let value = match key {\n                EventKey::Symbol(symbol) => symbol.clone().into_value(),\n                EventKey::String(str) => JsString::from_str(ctx.clone(), str)?.into(),\n            };\n\n            names.push(value)\n        }\n\n        Ok(names)\n    }\n}\n\nfn find_all_listeners<'js>(\n    events: Arc<RwLock<EventList<'js>>>,\n    key: EventKey<'js>,\n) -> Vec<Function<'js>> {\n    let events = events.read().unwrap();\n    let items = events.iter().find(|(k, _)| k == &key);\n    if let Some((_, callbacks)) = items {\n        callbacks.iter().map(|item| item.callback.clone()).collect()\n    } else {\n        vec![]\n    }\n}\n\nfn has_key<'js>(event_list: Arc<RwLock<EventList<'js>>>, key: EventKey<'js>) -> bool {\n    event_list.read().unwrap().iter().any(|(k, _)| k == &key)\n}\n\nfn to_event<'js>(ctx: &Ctx<'js>, event: &str) -> Result<Value<'js>> {\n    let event = JsString::from_str(ctx.clone(), event)?;\n    Ok(event.into_value())\n}\n\npub struct EventsModule;\n\nimpl ModuleDef for EventsModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(stringify!(EventEmitter))?;\n        declare.declare(\"default\")?;\n\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        let ctor = Class::<EventEmitter>::create_constructor(ctx)?\n            .expect(\"Can't create EventEmitter constructor\");\n        ctor.set(stringify!(EventEmitter), ctor.clone())?;\n        exports.export(stringify!(EventEmitter), ctor.clone())?;\n        exports.export(\"default\", ctor)?;\n\n        EventEmitter::add_event_emitter_prototype(ctx)?;\n\n        Ok(())\n    }\n}\n\nimpl From<EventsModule> for ModuleInfo<EventsModule> {\n    fn from(val: EventsModule) -> Self {\n        ModuleInfo {\n            name: \"events\",\n            module: val,\n        }\n    }\n}\n\npub fn init(ctx: &Ctx<'_>) -> Result<()> {\n    let globals = ctx.globals();\n\n    Class::<EventTarget>::define(&globals)?;\n    Class::<CustomEvent>::define(&globals)?;\n    Class::<Event>::define(&globals)?;\n\n    EventTarget::add_event_target_prototype(ctx)?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "modules/llrt_exceptions/Cargo.toml",
    "content": "[package]\nname = \"llrt_exceptions\"\ndescription = \"LLRT Module exception\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[lib]\nname = \"llrt_exceptions\"\npath = \"src/lib.rs\"\n\n[dependencies]\nrquickjs = { version = \"0.11\", default-features = false }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\n"
  },
  {
    "path": "modules/llrt_exceptions/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_utils::{\n    option::Undefined,\n    primordials::{BasePrimordials, Primordial},\n};\nuse rquickjs::{\n    atom::PredefinedAtom,\n    class::JsClass,\n    function::{Constructor, Opt},\n    object::Property,\n    prelude::This,\n    Class, Coerced, Ctx, Exception, IntoJs, Object, Result, Value,\n};\n\n#[derive(rquickjs::class::Trace, rquickjs::JsLifetime)]\npub struct DOMException {\n    name: String,\n    message: String,\n    stack: String,\n    code: u8,\n}\n\nfn add_constants(obj: &Object<'_>) -> Result<()> {\n    const CONSTANTS: [(&str, u8); 25] = [\n        (\"INDEX_SIZE_ERR\", 1),\n        (\"DOMSTRING_SIZE_ERR\", 2),\n        (\"HIERARCHY_REQUEST_ERR\", 3),\n        (\"WRONG_DOCUMENT_ERR\", 4),\n        (\"INVALID_CHARACTER_ERR\", 5),\n        (\"NO_DATA_ALLOWED_ERR\", 6),\n        (\"NO_MODIFICATION_ALLOWED_ERR\", 7),\n        (\"NOT_FOUND_ERR\", 8),\n        (\"NOT_SUPPORTED_ERR\", 9),\n        (\"INUSE_ATTRIBUTE_ERR\", 10),\n        (\"INVALID_STATE_ERR\", 11),\n        (\"SYNTAX_ERR\", 12),\n        (\"INVALID_MODIFICATION_ERR\", 13),\n        (\"NAMESPACE_ERR\", 14),\n        (\"INVALID_ACCESS_ERR\", 15),\n        (\"VALIDATION_ERR\", 16),\n        (\"TYPE_MISMATCH_ERR\", 17),\n        (\"SECURITY_ERR\", 18),\n        (\"NETWORK_ERR\", 19),\n        (\"ABORT_ERR\", 20),\n        (\"URL_MISMATCH_ERR\", 21),\n        (\"QUOTA_EXCEEDED_ERR\", 22),\n        (\"TIMEOUT_ERR\", 23),\n        (\"INVALID_NODE_TYPE_ERR\", 24),\n        (\"DATA_CLONE_ERR\", 25),\n    ];\n\n    for (key, value) in CONSTANTS {\n        obj.prop(key, Property::from(value).enumerable())?;\n    }\n\n    Ok(())\n}\n\nimpl<'js> JsClass<'js> for DOMException {\n    const NAME: &'static str = \"DOMException\";\n    type Mutable = rquickjs::class::Writable;\n    fn prototype(ctx: &Ctx<'js>) -> rquickjs::Result<Option<Object<'js>>> {\n        use rquickjs::class::impl_::{MethodImpl, MethodImplementor};\n        let proto = Object::new(ctx.clone())?;\n        let implementor = MethodImpl::<Self>::new();\n        implementor.implement(&proto)?;\n        add_constants(&proto)?;\n\n        Ok(Some(proto))\n    }\n    fn constructor(ctx: &Ctx<'js>) -> Result<Option<Constructor<'js>>> {\n        use rquickjs::class::impl_::{ConstructorCreate, ConstructorCreator};\n        let implementor = ConstructorCreate::<Self>::new();\n        let constructor = implementor\n            .create_constructor(ctx)?\n            .expect(\"DOMException must have a constructor\");\n        add_constants(&constructor)?;\n\n        Ok(Some(constructor))\n    }\n}\n\nimpl<'js> IntoJs<'js> for DOMException {\n    fn into_js(self, ctx: &rquickjs::Ctx<'js>) -> Result<Value<'js>> {\n        let cls = Class::<Self>::instance(ctx.clone(), self)?;\n        rquickjs::IntoJs::into_js(cls, ctx)\n    }\n}\n\nimpl<'js> rquickjs::FromJs<'js> for DOMException\nwhere\n    for<'a> rquickjs::class::impl_::CloneWrapper<'a, Self>:\n        rquickjs::class::impl_::CloneTrait<Self>,\n{\n    fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        use rquickjs::class::impl_::{CloneTrait, CloneWrapper};\n        let value = Class::<Self>::from_js(ctx, value)?;\n        let borrow = value.try_borrow()?;\n        Ok(CloneWrapper(&*borrow).wrap_clone())\n    }\n}\n\n#[rquickjs::methods]\nimpl DOMException {\n    #[qjs(constructor)]\n    pub fn new(\n        ctx: Ctx<'_>,\n        this: This<Value<'_>>,\n        message: Opt<Undefined<Coerced<String>>>,\n        name: Opt<Undefined<Coerced<String>>>,\n    ) -> Result<Self> {\n        if this.0.is_undefined() {\n            return Err(Exception::throw_type(\n                &ctx,\n                \"Cannot call the DOMException constructor without 'new'\",\n            ));\n        }\n\n        let message = match message.0 {\n            Some(Undefined(Some(message))) => message.0,\n            _ => String::new(),\n        };\n\n        let name = match name.0 {\n            Some(Undefined(Some(message))) => DOMExceptionName::from(message.0),\n            _ => DOMExceptionName::Error,\n        };\n\n        Self::new_with_name(&ctx, name, message)\n    }\n\n    #[qjs(skip)]\n    pub fn new_with_name(ctx: &Ctx<'_>, name: DOMExceptionName, message: String) -> Result<Self> {\n        let primordials = BasePrimordials::get(ctx)?;\n\n        let new: Object = primordials\n            .constructor_error\n            .construct((message.clone(),))?;\n\n        Ok(Self {\n            name: name.as_str().to_string(),\n            code: name.code(),\n            message,\n            stack: new.get::<_, String>(PredefinedAtom::Stack)?,\n        })\n    }\n\n    #[qjs(get, enumerable, configurable)]\n    fn message(&self) -> &str {\n        self.message.as_str()\n    }\n\n    #[qjs(get, enumerable, configurable)]\n    pub fn name(&self) -> &str {\n        self.name.as_str()\n    }\n\n    #[qjs(get, enumerable, configurable)]\n    pub fn code(&self) -> u8 {\n        self.code\n    }\n\n    #[qjs(get)]\n    fn stack(&self) -> String {\n        self.stack.clone()\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    pub fn to_string_tag(&self) -> &str {\n        stringify!(DOMException)\n    }\n}\n\nmacro_rules! create_dom_exception {\n    ($name:ident, $($variant:ident),+ $(,)?) => {\n        #[derive(Debug)]\n        pub enum $name {\n            $(\n                $variant,\n            )+\n            Other(String),\n        }\n\n        impl $name {\n            pub fn as_str(&self) -> &str {\n                match self {\n                    $(\n                        Self::$variant => stringify!($variant),\n                    )+\n                    Self::Other(value) => value,\n                }\n            }\n        }\n\n        impl From<String> for $name {\n            fn from(value: String) -> Self {\n                match value.as_str() {\n                    $(\n                        stringify!($variant) => Self::$variant,\n                    )+\n                    _ => Self::Other(value),\n                }\n            }\n        }\n    };\n}\n\n// https://webidl.spec.whatwg.org/#dfn-error-names-table\ncreate_dom_exception!(\n    DOMExceptionName,\n    IndexSizeError,\n    HierarchyRequestError,\n    WrongDocumentError,\n    InvalidCharacterError,\n    NoModificationAllowedError,\n    NotFoundError,\n    NotSupportedError,\n    InUseAttributeError,\n    InvalidStateError,\n    SyntaxError,\n    InvalidModificationError,\n    NamespaceError,\n    InvalidAccessError,\n    TypeMismatchError,\n    SecurityError,\n    NetworkError,\n    AbortError,\n    URLMismatchError,\n    QuotaExceededError,\n    TimeoutError,\n    InvalidNodeTypeError,\n    DataCloneError,\n    EncodingError,\n    NotReadableError,\n    UnknownError,\n    ConstraintError,\n    DataError,\n    TransactionInactiveError,\n    ReadOnlyError,\n    VersionError,\n    OperationError,\n    NotAllowedError,\n    Error,\n);\n\nimpl DOMExceptionName {\n    fn code(&self) -> u8 {\n        match self {\n            DOMExceptionName::IndexSizeError => 1,\n            DOMExceptionName::HierarchyRequestError => 3,\n            DOMExceptionName::WrongDocumentError => 4,\n            DOMExceptionName::InvalidCharacterError => 5,\n            DOMExceptionName::NoModificationAllowedError => 7,\n            DOMExceptionName::NotFoundError => 8,\n            DOMExceptionName::NotSupportedError => 9,\n            DOMExceptionName::InUseAttributeError => 10,\n            DOMExceptionName::InvalidStateError => 11,\n            DOMExceptionName::SyntaxError => 12,\n            DOMExceptionName::InvalidModificationError => 13,\n            DOMExceptionName::NamespaceError => 14,\n            DOMExceptionName::InvalidAccessError => 15,\n            DOMExceptionName::TypeMismatchError => 17,\n            DOMExceptionName::SecurityError => 18,\n            DOMExceptionName::NetworkError => 19,\n            DOMExceptionName::AbortError => 20,\n            DOMExceptionName::URLMismatchError => 21,\n            DOMExceptionName::QuotaExceededError => 22,\n            DOMExceptionName::TimeoutError => 23,\n            DOMExceptionName::InvalidNodeTypeError => 24,\n            DOMExceptionName::DataCloneError => 25,\n            _ => 0,\n        }\n    }\n}\n\npub fn init(ctx: &Ctx<'_>) -> Result<()> {\n    let globals = ctx.globals();\n\n    BasePrimordials::init(ctx)?;\n\n    if let Some(constructor) = Class::<DOMException>::create_constructor(ctx)? {\n        // the wpt tests expect this particular property descriptor\n        globals.prop(\n            DOMException::NAME,\n            Property::from(constructor).writable().configurable(),\n        )?;\n    }\n\n    let dom_ex_proto = Class::<DOMException>::prototype(ctx)?.unwrap();\n    let error_prototype = &BasePrimordials::get(ctx)?.prototype_error;\n    dom_ex_proto.set_prototype(Some(error_prototype))?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "modules/llrt_fetch/Cargo.toml",
    "content": "[package]\nname = \"llrt_fetch\"\ndescription = \"LLRT Module fetch\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\nreadme = \"README.md\"\n\n[lib]\nname = \"llrt_fetch\"\npath = \"src/lib.rs\"\n\n[features]\ndefault = [\"http1\", \"http2\", \"compression-c\", \"webpki-roots\", \"tls-ring\"]\n\nhttp1 = [\"hyper/http1\", \"llrt_http/http1\"]\nhttp2 = [\"hyper/http2\", \"llrt_http/http2\"]\n\ncompression-c = [\"llrt_compression/all-c\"]\ncompression-rust = [\"llrt_compression/all-rust\"]\n\nwebpki-roots = [\"llrt_http/webpki-roots\"]\nnative-roots = [\"llrt_http/native-roots\"]\n\ntls-ring = [\"llrt_http/tls-ring\", \"llrt_test_tls/tls-ring\"]\ntls-aws-lc = [\"llrt_http/tls-aws-lc\", \"llrt_test_tls/tls-aws-lc\"]\ntls-graviola = [\"llrt_http/tls-graviola\", \"llrt_test_tls/tls-graviola\"]\ntls-openssl = [\"llrt_http/tls-openssl\", \"llrt_test_tls/tls-openssl\"]\n\n[dependencies]\nbytes = { version = \"1\", default-features = false }\neither = { version = \"1\", default-features = false }\nhttp-body-util = { version = \"0.1\", default-features = false }\nhyper = { version = \"1\", features = [\"client\"], default-features = false }\nitoa = { version = \"1\", default-features = false }\nllrt_abort = { version = \"0.8.1-beta\", path = \"../llrt_abort\" }\nllrt_buffer = { version = \"0.8.1-beta\", path = \"../llrt_buffer\" }\nllrt_compression = { version = \"0.8.1-beta\", path = \"../../libs/llrt_compression\", default-features = false }\nllrt_context = { version = \"0.8.1-beta\", path = \"../../libs/llrt_context\" }\nllrt_encoding = { version = \"0.8.1-beta\", path = \"../../libs/llrt_encoding\" }\nllrt_http = { version = \"0.8.1-beta\", default-features = false, path = \"../llrt_http\" }\nllrt_json = { version = \"0.8.1-beta\", path = \"../../libs/llrt_json\" }\nllrt_url = { version = \"0.8.1-beta\", path = \"../llrt_url\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nonce_cell = { version = \"1\", features = [\"std\"], default-features = false }\npin-project-lite = { version = \"0.2\", default-features = false }\npercent-encoding = { version = \"2\", features = [\n  \"std\",\n], default-features = false }\nrand = { version = \"0.10.0\", features = [\n  \"std\",\n  \"thread_rng\",\n], default-features = false }\nrquickjs = { version = \"0.11\", default-features = false }\ntokio = { version = \"1\", features = [\n  \"macros\",\n  \"sync\",\n], default-features = false }\ntracing = { version = \"0.1\", default-features = false }\n\n[dev-dependencies]\nllrt_compression = { version = \"0.8.1-beta\", path = \"../../libs/llrt_compression\" }\nllrt_test = { path = \"../../libs/llrt_test\" }\nllrt_test_tls = { path = \"../../libs/llrt_test_tls\", default-features = false }\nwiremock = { version = \"0.6\", default-features = false }\n"
  },
  {
    "path": "modules/llrt_fetch/src/body.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse http_body_util::BodyExt;\nuse hyper::{body::Incoming, Response};\nuse llrt_json::parse::json_parse;\nuse llrt_utils::{bytes::ObjectBytes, result::ResultExt};\nuse rquickjs::{\n    class::{Trace, Tracer},\n    ArrayBuffer, Class, Ctx, Exception, IntoJs, JsLifetime, Null, Result, TypedArray, Value,\n};\n\nuse crate::MIME_TYPE_OCTET_STREAM;\n\nuse super::{strip_bom, Blob, FormData};\n\n// WARN: We don't use that code since we don't have an implementation of ReadableStream.\n// We will revisit later.\n\nenum BodyVariant<'js> {\n    Incoming(Option<hyper::Response<Incoming>>),\n    Provided(Value<'js>),\n}\n\n#[rquickjs::class]\npub struct Body<'js> {\n    data: BodyVariant<'js>,\n    content_type: Option<String>,\n}\n\nunsafe impl<'js> JsLifetime<'js> for Body<'js> {\n    type Changed<'to> = Body<'to>;\n}\n\nimpl<'js> Trace<'js> for Body<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        if let BodyVariant::Provided(body) = &self.data {\n            body.trace(tracer)\n        }\n    }\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl<'js> Body<'js> {\n    pub async fn text(&mut self, ctx: Ctx<'js>) -> Result<String> {\n        let bytes = self.take_bytes(&ctx).await?;\n        Ok(String::from_utf8_lossy(&strip_bom(bytes)).to_string())\n    }\n\n    pub async fn json(&mut self, ctx: Ctx<'js>) -> Result<Value<'js>> {\n        let bytes = self.take_bytes(&ctx).await?;\n        json_parse(&ctx, strip_bom(bytes))\n    }\n\n    pub async fn array_buffer(&mut self, ctx: Ctx<'js>) -> Result<ArrayBuffer<'js>> {\n        let bytes = self.take_bytes(&ctx).await?;\n        ArrayBuffer::new(ctx, bytes)\n    }\n\n    pub async fn typed_array(&mut self, ctx: Ctx<'js>) -> Result<TypedArray<'js, u8>> {\n        let bytes = self.take_bytes(&ctx).await?;\n        TypedArray::<u8>::new(ctx, bytes)\n    }\n\n    pub async fn blob(&mut self, ctx: Ctx<'js>) -> Result<Blob> {\n        let bytes = self.take_bytes(&ctx).await?;\n        Ok(Blob::from_bytes(bytes, self.content_type.take())) //no need to copy, we can only take bytes once\n    }\n\n    async fn form_data(&mut self, ctx: Ctx<'js>) -> Result<FormData> {\n        let bytes = self.take_bytes(&ctx).await?;\n        let content_type = self\n            .content_type\n            .take()\n            .unwrap_or(MIME_TYPE_OCTET_STREAM.into());\n        FormData::from_multipart_bytes(&ctx, &content_type, bytes)\n    }\n\n    pub async fn bytes(&mut self, ctx: Ctx<'js>) -> Result<Value<'js>> {\n        let bytes = self.take_bytes(&ctx).await?;\n        TypedArray::new(ctx, bytes).map(|m| m.into_value())\n    }\n\n    pub fn is_used(&self) -> bool {\n        if let BodyVariant::Incoming(data) = &self.data {\n            return data.is_none();\n        }\n        false\n    }\n}\n\nimpl<'js> Body<'js> {\n    pub async fn get_text(ctx: Ctx<'js>, body: Option<&Class<'js, Self>>) -> Result<String> {\n        if let Some(body) = body {\n            return body.borrow_mut().text(ctx).await;\n        }\n        Ok(\"\".into())\n    }\n\n    pub async fn get_json(ctx: Ctx<'js>, body: Option<&Class<'js, Self>>) -> Result<Value<'js>> {\n        if let Some(body) = body {\n            return body.borrow_mut().json(ctx).await;\n        }\n        Err(Exception::throw_syntax(&ctx, \"JSON input is empty\"))\n    }\n\n    pub async fn get_array_buffer(\n        ctx: Ctx<'js>,\n        body: Option<&Class<'js, Self>>,\n    ) -> Result<ArrayBuffer<'js>> {\n        if let Some(body) = body {\n            return body.borrow_mut().array_buffer(ctx).await;\n        }\n        ArrayBuffer::new(ctx, Vec::<u8>::new())\n    }\n\n    pub async fn get_blob(ctx: Ctx<'js>, body: Option<&Class<'js, Self>>) -> Result<Blob> {\n        if let Some(body) = body {\n            return body.borrow_mut().blob(ctx).await;\n        }\n        Ok(Blob::from_bytes(Vec::<u8>::new(), None))\n    }\n\n    pub fn get_body(ctx: Ctx<'js>, body: Option<&Class<'js, Self>>) -> Result<Value<'js>> {\n        if let Some(body) = body {\n            return Ok(body.clone().into_value());\n        }\n        Null.into_js(&ctx)\n    }\n\n    pub fn from_value(\n        ctx: &Ctx<'js>,\n        body: Option<Value<'js>>,\n    ) -> Result<Option<Class<'js, Self>>> {\n        if let Some(body) = body {\n            if body.is_null() || body.is_undefined() {\n                return Ok(None);\n            }\n\n            return Ok(Some(Class::instance(\n                ctx.clone(),\n                Self {\n                    data: BodyVariant::Provided(body),\n                    content_type: None,\n                },\n            )?));\n        }\n        Ok(None)\n    }\n\n    pub fn from_incoming(\n        ctx: Ctx<'js>,\n        response: Response<Incoming>,\n        content_type: Option<String>,\n    ) -> Result<Class<'js, Self>> {\n        Class::instance(\n            ctx,\n            Self {\n                data: BodyVariant::Incoming(Some(response)),\n                content_type,\n            },\n        )\n    }\n\n    pub async fn take_bytes(&mut self, ctx: &Ctx<'js>) -> Result<Vec<u8>> {\n        let bytes = match &mut self.data {\n            BodyVariant::Incoming(incoming) => {\n                let mut body = incoming\n                    .take()\n                    .ok_or(Exception::throw_type(ctx, \"Already read\"))?;\n                let bytes = body.body_mut().collect().await.or_throw(ctx)?.to_bytes();\n                bytes.into()\n            },\n            BodyVariant::Provided(provided) => {\n                if let Some(blob) = provided.as_object().and_then(Class::<Blob>::from_object) {\n                    let blob = blob.borrow();\n                    blob.get_bytes()\n                } else {\n                    let bytes = ObjectBytes::from(ctx, provided)?;\n                    bytes.try_into().or_throw(ctx)?\n                }\n            },\n        };\n        Ok(bytes)\n    }\n}\n"
  },
  {
    "path": "modules/llrt_fetch/src/fetch.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{collections::HashSet, convert::Infallible, sync::Arc, time::Instant};\n\nuse bytes::Bytes;\nuse http_body_util::{combinators::BoxBody, Full};\nuse hyper::{header::HeaderName, Method, Request, Uri};\nuse llrt_abort::AbortSignal;\nuse llrt_encoding::bytes_from_b64;\nuse llrt_http::Agent;\nuse llrt_http::HyperClient;\nuse llrt_utils::{\n    bytes::{bytes_to_typed_array, ObjectBytes},\n    mc_oneshot,\n    result::ResultExt,\n    VERSION,\n};\nuse percent_encoding::percent_decode_str;\nuse rquickjs::{\n    atom::PredefinedAtom,\n    function::{Opt, This},\n    prelude::{Async, Func},\n    Class, Coerced, Ctx, Exception, FromJs, Function, IntoJs, Object, Result, Value,\n};\nuse tokio::{select, sync::Semaphore};\n\nuse super::{\n    headers::{Headers, HeadersGuard},\n    response::Response,\n    security::ensure_url_access,\n    Blob,\n};\n\n// https://fetch.spec.whatwg.org/#port-blocking\nconst BLOCKED_PORTS: [u16; 83] = [\n    0, 1, 7, 9, 11, 13, 15, 17, 19, 20, 21, 22, 23, 25, 37, 42, 43, 53, 69, 77, 79, 87, 95, 101,\n    102, 103, 104, 109, 110, 111, 113, 115, 117, 119, 123, 135, 137, 139, 143, 161, 179, 389, 427,\n    465, 512, 513, 514, 515, 526, 530, 531, 532, 540, 548, 554, 556, 563, 587, 601, 636, 989, 990,\n    993, 995, 1719, 1720, 1723, 2049, 3659, 4045, 4190, 5060, 5061, 6000, 6566, 6665, 6666, 6667,\n    6668, 6669, 6679, 6697, 10080,\n];\n\nconst MAX_REDIRECT_COUNT: u32 = 20;\n\npub fn init(global_client: HyperClient, globals: &Object) -> Result<()> {\n    let connections = Arc::new(Semaphore::new(500));\n\n    globals.set(\n        \"fetch\",\n        Func::from(Async(move |ctx, resource, args| {\n            let global_client = global_client.clone();\n            let connections = connections.clone();\n            let start = Instant::now();\n            let options = get_fetch_options(&ctx, resource, args);\n\n            async move {\n                let lock = connections.acquire().await;\n                let options = options?;\n\n                let client = options\n                    .agent\n                    .map(|agent| agent.borrow().client())\n                    .unwrap_or(global_client);\n\n                // https://fetch.spec.whatwg.org/#scheme-fetch\n                if let Some((scheme, fragment)) = options.url.split_once(':') {\n                    match scheme {\n                        \"http\" | \"https\" => {},\n                        \"data\" => return parse_data_url(&ctx, fragment, &options.method),\n                        \"about\" | \"blob\" | \"file\" => {\n                            return Err(Exception::throw_type(&ctx, \"Unsupported scheme\"));\n                        },\n                        _ => return Err(Exception::throw_type(&ctx, \"Invalid scheme\")),\n                    }\n                }\n\n                let mut uri = options.url.parse::<Uri>().map_err(|_| {\n                    Exception::throw_type(&ctx, &[\"Invalid URL :\", &options.url].concat())\n                })?;\n                let initial_uri: Uri = uri.clone();\n\n                let method_string = options.method.to_string();\n                let method = options.method;\n                let abort_receiver = options.abort_receiver;\n\n                ensure_url_access(&ctx, &uri)?;\n\n                let mut redirect_count = 0;\n                let mut response_status = 0;\n                let (res, guard) = loop {\n                    let (req, guard) = build_request(\n                        &ctx,\n                        &method,\n                        &uri,\n                        options.headers.as_ref(),\n                        options.body.as_ref(),\n                        &response_status,\n                        &initial_uri,\n                    )?;\n\n                    let res = if let Some(abort_receiver) = &abort_receiver {\n                        select! {\n                            res = client.request(req) => res.or_throw(&ctx)?,\n                            reason = abort_receiver.recv() => return Err(ctx.throw(reason))\n                        }\n                    } else {\n                        client.request(req).await.or_throw(&ctx)?\n                    };\n\n                    let status = res.status();\n                    if status.is_redirection() {\n                        match res.headers().get(HeaderName::from_static(\"location\")) {\n                            Some(location_headers) => {\n                                if let Ok(location_str) = location_headers.to_str() {\n                                    uri = location_str.parse().or_throw(&ctx)?;\n                                    ensure_url_access(&ctx, &uri)?;\n                                }\n                            },\n                            None => break (res, guard),\n                        };\n                    } else {\n                        break (res, guard);\n                    };\n\n                    if options.redirect == \"manual\" {\n                        break (res, guard);\n                    } else if options.redirect == \"error\" {\n                        return Err(Exception::throw_message(&ctx, \"Unexpected redirect\"));\n                    }\n\n                    redirect_count += 1;\n                    if redirect_count >= MAX_REDIRECT_COUNT {\n                        return Err(Exception::throw_message(&ctx, \"Max retries exceeded\"));\n                    }\n\n                    response_status = res.status().as_u16();\n                };\n\n                drop(lock);\n\n                Response::from_incoming(\n                    ctx,\n                    res,\n                    method_string,\n                    uri.to_string(),\n                    start,\n                    !matches!(redirect_count, 0),\n                    abort_receiver,\n                    guard,\n                )\n            }\n        })),\n    )?;\n    Ok(())\n}\n\nfn parse_data_url<'js>(ctx: &Ctx<'js>, data_url: &str, method: &Method) -> Result<Response<'js>> {\n    let (mime_type, data) = data_url\n        .split_once(',')\n        .ok_or_else(|| Exception::throw_type(ctx, \"Invalid data URL format\"))?;\n\n    let mut is_base64 = false;\n    let mut content_type = String::with_capacity(10);\n    for (i, part) in mime_type.split(';').enumerate() {\n        let part = part.trim();\n        if i == 1 || i == 2 {\n            if part == \"base64\" {\n                is_base64 = true;\n                break;\n            }\n            content_type.push(';');\n        }\n        content_type.push_str(part)\n    }\n\n    let content_type = if content_type.starts_with(';') {\n        [\"text/plain\", &content_type].concat()\n    } else if content_type.is_empty() {\n        \"text/plain;charset=US-ASCII\".to_string()\n    } else {\n        content_type\n    };\n\n    let body = if method == Method::HEAD {\n        vec![]\n    } else if is_base64 {\n        bytes_from_b64(data.as_bytes()).or_throw(ctx)?\n    } else {\n        let data = percent_decode_str(data).decode_utf8().or_throw(ctx)?;\n        data.as_bytes().into()\n    };\n\n    let blob = Blob::from_bytes(body, Some(content_type.clone())).into_js(ctx)?;\n\n    let headers = Object::new(ctx.clone())?;\n    headers.set(\"content-type\", content_type)?;\n\n    let options = Object::new(ctx.clone())?;\n    options.set(\"url\", data_url)?;\n    options.set(\"headers\", headers)?;\n\n    Response::new(ctx.clone(), Opt(Some(blob)), Opt(Some(options)))\n}\n\nfn build_request(\n    ctx: &Ctx<'_>,\n    method: &hyper::Method,\n    uri: &Uri,\n    headers: Option<&Headers>,\n    body: Option<&BodyBytes>,\n    prev_status: &u16,\n    initial_uri: &Uri,\n) -> Result<(Request<BoxBody<Bytes, Infallible>>, HeadersGuard)> {\n    if let Some(scheme) = uri.scheme_str() {\n        if !matches!(scheme, \"http\" | \"https\") {\n            return Err(Exception::throw_type(ctx, \"Invalid scheme in URL\"));\n        }\n\n        if let (\"http\", Some(port)) = (scheme, uri.authority().and_then(|a| a.port_u16())) {\n            if BLOCKED_PORTS.contains(&port) {\n                return Err(Exception::throw_type(ctx, \"Invalid port in URL\"));\n            }\n        }\n    }\n\n    let same_origin = is_same_origin(uri, initial_uri);\n    let guard = if same_origin {\n        HeadersGuard::Response\n    } else {\n        HeadersGuard::Immutable\n    };\n\n    let change_method = should_change_method(*prev_status, method);\n\n    let (method_to_use, body) = if change_method {\n        (Method::GET, None)\n    } else {\n        (method.clone(), body)\n    };\n\n    let mut req = Request::builder().method(method_to_use).uri(uri.clone());\n\n    let mut detected_headers = HashSet::new();\n\n    if let Some(headers) = headers {\n        for (header_name, value) in headers.iter() {\n            detected_headers.insert(header_name);\n            if change_method && is_request_body_header_name(header_name) {\n                continue;\n            }\n            if !same_origin && is_cors_non_wildcard_request_header_name(header_name) {\n                continue;\n            }\n            req = req.header(header_name, value)\n        }\n    }\n\n    if !detected_headers.contains(\"user-agent\") {\n        req = req.header(\"user-agent\", [\"llrt \", VERSION].concat());\n    }\n    if !detected_headers.contains(\"accept-encoding\") {\n        req = req.header(\"accept-encoding\", \"zstd, br, gzip, deflate\");\n    }\n    if !detected_headers.contains(\"accept-language\") {\n        req = req.header(\"accept-language\", \"*\");\n    }\n    if !detected_headers.contains(\"accept\") {\n        req = req.header(\"accept\", \"*/*\");\n    }\n    let body = req\n        .body(BoxBody::new(\n            body.map(|b| b.body.clone()).unwrap_or_default(),\n        ))\n        .or_throw(ctx)?;\n\n    Ok((body, guard))\n}\n\nfn is_same_origin(uri: &Uri, initial_uri: &Uri) -> bool {\n    is_same_scheme(uri, initial_uri)\n        && is_same_host(uri, initial_uri)\n        && is_same_port(uri, initial_uri)\n}\n\nfn is_same_scheme(uri: &Uri, initial_uri: &Uri) -> bool {\n    uri.scheme() == initial_uri.scheme()\n}\n\nfn is_same_host(uri: &Uri, initial_uri: &Uri) -> bool {\n    uri.host() == initial_uri.host()\n}\n\nfn is_same_port(uri: &Uri, initial_uri: &Uri) -> bool {\n    uri.authority().and_then(|a| a.port()) == initial_uri.authority().and_then(|a| a.port())\n}\n\nfn should_change_method(prev_status: u16, method: &Method) -> bool {\n    if matches!(prev_status, 301 | 302) {\n        return *method == Method::POST;\n    }\n\n    if prev_status == 303 {\n        return !matches!(*method, Method::GET | Method::HEAD);\n    }\n\n    false\n}\n\nfn is_request_body_header_name(key: &str) -> bool {\n    matches!(\n        key,\n        \"content-encoding\" | \"content-language\" | \"content-location\" | \"content-type\"\n    )\n}\n\nfn is_cors_non_wildcard_request_header_name(key: &str) -> bool {\n    matches!(key, \"authorization\")\n}\n\nstruct BodyBytes<'js> {\n    #[allow(dead_code)]\n    object_bytes: ObjectBytes<'js>,\n    body: Full<Bytes>,\n}\nimpl<'js> BodyBytes<'js> {\n    fn new(ctx: Ctx<'js>, object_bytes: ObjectBytes<'js>) -> Result<Self> {\n        //this is safe since we hold on to ObjectBytes\n        let raw_bytes: &'static [u8] = unsafe { std::mem::transmute(object_bytes.as_bytes(&ctx)?) };\n        let body = Full::from(Bytes::from_static(raw_bytes));\n        Ok(Self { object_bytes, body })\n    }\n}\n\nstruct FetchOptions<'js> {\n    method: hyper::Method,\n    url: String,\n    headers: Option<Headers>,\n    body: Option<BodyBytes<'js>>,\n    abort_receiver: Option<mc_oneshot::Receiver<Value<'js>>>,\n    redirect: String,\n    agent: Option<Class<'js, Agent>>,\n}\n\nfn get_fetch_options<'js>(\n    ctx: &Ctx<'js>,\n    resource: Value<'js>,\n    opts: Opt<Value<'js>>,\n) -> Result<FetchOptions<'js>> {\n    let mut url = None;\n    let mut resource_opts = None;\n    let mut arg_opts = None;\n    let mut headers = None;\n    let mut method = None;\n    let mut body = None;\n    let mut abort_receiver = None;\n    let mut redirect = String::from(\"\");\n    let mut agent = None;\n\n    if let Some(obj) = resource.as_object() {\n        let obj = obj.clone();\n        if obj.instance_of::<crate::Request>() {\n            resource_opts = Some(obj);\n        } else if let Some(to_string) = obj.get::<_, Option<Function>>(PredefinedAtom::ToString)? {\n            url = Some(to_string.call::<_, String>((This(obj),))?);\n        } else {\n            resource_opts = Some(obj);\n        }\n    } else {\n        url = Some(resource.get::<Coerced<String>>()?.to_string());\n    }\n\n    if let Some(options) = opts.0 {\n        arg_opts = options.into_object();\n    }\n\n    if resource_opts.is_some() || arg_opts.is_some() {\n        if let Some(method_opt) =\n            get_option::<String>(\"method\", arg_opts.as_ref(), resource_opts.as_ref())?\n        {\n            method = Some(match method_opt.as_str() {\n                \"GET\" => Ok(hyper::Method::GET),\n                \"POST\" => Ok(hyper::Method::POST),\n                \"PUT\" => Ok(hyper::Method::PUT),\n                \"CONNECT\" => Ok(hyper::Method::CONNECT),\n                \"HEAD\" => Ok(hyper::Method::HEAD),\n                \"PATCH\" => Ok(hyper::Method::PATCH),\n                \"DELETE\" => Ok(hyper::Method::DELETE),\n                _ => Err(Exception::throw_type(\n                    ctx,\n                    &[\"Invalid HTTP method: \", &method_opt].concat(),\n                )),\n            }?);\n        }\n\n        if let Some(body_opt) =\n            get_option::<Value>(\"body\", arg_opts.as_ref(), resource_opts.as_ref())?\n        {\n            let bytes = if let Ok(blob) = Class::<Blob>::from_value(&body_opt) {\n                let blob = blob.borrow();\n                let typed_array = bytes_to_typed_array(ctx.clone(), &blob.get_bytes())?;\n                ObjectBytes::from(ctx, &typed_array)?\n            } else {\n                ObjectBytes::from(ctx, &body_opt)?\n            };\n            body = Some(BodyBytes::new(ctx.clone(), bytes)?);\n        }\n\n        if let Some(url_opt) =\n            get_option::<String>(\"url\", arg_opts.as_ref(), resource_opts.as_ref())?\n        {\n            url = Some(url_opt);\n        }\n\n        if let Some(headers_op) =\n            get_option::<Value>(\"headers\", arg_opts.as_ref(), resource_opts.as_ref())?\n        {\n            headers = Some(Headers::from_value(ctx, headers_op, HeadersGuard::None)?);\n        }\n\n        if let Some(signal) =\n            get_option::<Class<AbortSignal>>(\"signal\", arg_opts.as_ref(), resource_opts.as_ref())?\n        {\n            abort_receiver = Some(signal.borrow().sender.subscribe());\n        }\n\n        if let Some(redirect_opt) =\n            get_option::<String>(\"redirect\", arg_opts.as_ref(), resource_opts.as_ref())?\n        {\n            let redirect_str = redirect_opt.as_str();\n            if !matches!(redirect_str, \"follow\" | \"manual\" | \"error\") {\n                return Err(Exception::throw_type(\n                    ctx,\n                    &[\"Invalid redirect option: \", redirect_str].concat(),\n                ));\n            }\n            redirect.push_str(redirect_str);\n        }\n\n        if let Some(agent_opt) =\n            get_option::<Class<'js, Agent>>(\"agent\", arg_opts.as_ref(), resource_opts.as_ref())?\n        {\n            agent = Some(agent_opt);\n        }\n    }\n\n    let url = match url {\n        Some(url) => url,\n        None => return Err(Exception::throw_reference(ctx, \"Missing required url\")),\n    };\n\n    Ok(FetchOptions {\n        method: method.unwrap_or_default(),\n        url,\n        headers,\n        body,\n        abort_receiver,\n        redirect,\n        agent,\n    })\n}\n\nfn get_option<'js, V: FromJs<'js> + Sized>(\n    arg: &str,\n    a: Option<&Object<'js>>,\n    b: Option<&Object<'js>>,\n) -> Result<Option<V>> {\n    if let Some(opt) = a {\n        if let Some(value) = opt.get::<_, Option<V>>(arg)? {\n            return Ok(Some(value));\n        }\n    }\n\n    if let Some(opt) = b {\n        if let Some(value) = opt.get::<_, Option<V>>(arg)? {\n            return Ok(Some(value));\n        }\n    }\n\n    Ok(None)\n}\n\n#[cfg(test)]\nmod tests {\n    use std::io::Read;\n\n    #[cfg(any(\n        feature = \"tls-ring\",\n        feature = \"tls-aws-lc\",\n        all(feature = \"tls-graviola\", target_arch = \"x86_64\")\n    ))]\n    use llrt_http::HttpsModule;\n    use llrt_test::test_async_with;\n    #[cfg(any(\n        feature = \"tls-ring\",\n        feature = \"tls-aws-lc\",\n        all(feature = \"tls-graviola\", target_arch = \"x86_64\")\n    ))]\n    use llrt_test::{call_test, ModuleEvaluator};\n    use rquickjs::{prelude::Promise, CatchResultExt};\n    use wiremock::{matchers, Mock, MockServer, ResponseTemplate};\n\n    use super::*;\n\n    #[test]\n    fn test_should_change_method() {\n        // Test cases for prev_status being 301 or 302\n        assert!(should_change_method(301, &Method::POST));\n        assert!(should_change_method(302, &Method::POST));\n\n        assert!(!should_change_method(301, &Method::GET));\n        assert!(!should_change_method(302, &Method::GET));\n        assert!(!should_change_method(301, &Method::HEAD));\n        assert!(!should_change_method(302, &Method::HEAD));\n\n        // Test cases for prev_status being 303\n        assert!(should_change_method(303, &Method::POST));\n\n        assert!(!should_change_method(303, &Method::GET));\n        assert!(!should_change_method(303, &Method::HEAD));\n\n        // Test case for other prev_status values\n        assert!(!should_change_method(200, &Method::POST));\n        assert!(!should_change_method(404, &Method::GET));\n    }\n\n    #[test]\n    fn test_is_request_body_header_name() {\n        assert!(is_request_body_header_name(\"content-encoding\"));\n        assert!(is_request_body_header_name(\"content-language\"));\n        assert!(is_request_body_header_name(\"content-location\"));\n        assert!(is_request_body_header_name(\"content-type\"));\n\n        assert!(!is_request_body_header_name(\"content-length\"));\n        assert!(!is_request_body_header_name(\"accept\"));\n    }\n\n    #[test]\n    fn test_is_same_origin() {\n        let uri1 = Uri::from_static(\"https://example.com:8080/path\");\n        let uri2 = Uri::from_static(\"https://example.com:8080/path\");\n\n        assert!(is_same_origin(&uri1, &uri2));\n\n        let uri3 = Uri::from_static(\"http://example.com/path\");\n        let uri4 = Uri::from_static(\"https://example.com/path\");\n\n        assert!(!is_same_origin(&uri3, &uri4));\n\n        let uri5 = Uri::from_static(\"https://example.com:8080/path\");\n        let uri6 = Uri::from_static(\"https://example.org:8080/path\");\n\n        assert!(!is_same_origin(&uri5, &uri6));\n\n        let uri7 = Uri::from_static(\"https://example.com:8080/path\");\n        let uri8 = Uri::from_static(\"https://example.com:8081/path\");\n\n        assert!(!is_same_origin(&uri7, &uri8));\n    }\n\n    #[test]\n    fn test_is_same_scheme() {\n        let uri1 = Uri::from_static(\"https://example.com\");\n        let uri2 = Uri::from_static(\"https://example.com\");\n\n        assert!(is_same_scheme(&uri1, &uri2));\n\n        let uri3 = Uri::from_static(\"http://example.com\");\n        let uri4 = Uri::from_static(\"https://example.com\");\n\n        assert!(!is_same_scheme(&uri3, &uri4));\n    }\n\n    #[test]\n    fn test_is_same_host() {\n        let uri1 = Uri::from_static(\"https://example.com\");\n        let uri2 = Uri::from_static(\"https://example.com\");\n\n        assert!(is_same_host(&uri1, &uri2));\n\n        let uri3 = Uri::from_static(\"https://example.com\");\n        let uri4 = Uri::from_static(\"https://example.org\");\n\n        assert!(!is_same_host(&uri3, &uri4));\n    }\n\n    #[test]\n    fn test_is_same_port() {\n        let uri1 = Uri::from_static(\"https://example.com:8080\");\n        let uri2 = Uri::from_static(\"https://example.com:8080\");\n\n        assert!(is_same_port(&uri1, &uri2));\n\n        let uri3 = Uri::from_static(\"https://example.com:8080\");\n        let uri4 = Uri::from_static(\"https://example.com:9090\");\n\n        assert!(!is_same_port(&uri3, &uri4));\n\n        let uri5 = Uri::from_static(\"https://example.com\");\n        let uri6 = Uri::from_static(\"https://example.com\");\n\n        assert!(is_same_port(&uri5, &uri6));\n\n        let uri7 = Uri::from_static(\"https://example.com:8080\");\n        let uri8 = Uri::from_static(\"https://example.com\");\n\n        assert!(!is_same_port(&uri7, &uri8));\n    }\n\n    #[tokio::test]\n    async fn test_fetch_function() {\n        let mock_server = MockServer::start().await;\n        let welcome_message = \"Hello, LLRT!\";\n\n        Mock::given(matchers::path(\"expect/200/\"))\n            .respond_with(\n                ResponseTemplate::new(200)\n                    .set_body_string(String::from_utf8(welcome_message.into()).unwrap()),\n            )\n            .mount(&mock_server)\n            .await;\n\n        Mock::given(matchers::path(\"expect/301/\"))\n            .respond_with(ResponseTemplate::new(301).insert_header(\n                \"location\",\n                format!(\"http://{}/{}\", mock_server.address(), \"expect/200/\"),\n            ))\n            .mount(&mock_server)\n            .await;\n\n        Mock::given(matchers::path(\"expect/302/\"))\n            .respond_with(ResponseTemplate::new(302).insert_header(\n                \"location\",\n                format!(\"http://{}/{}\", mock_server.address(), \"expect/200/\"),\n            ))\n            .mount(&mock_server)\n            .await;\n\n        Mock::given(matchers::path(\"expect/303/\"))\n            .respond_with(ResponseTemplate::new(303).insert_header(\n                \"location\",\n                format!(\"http://{}/{}\", mock_server.address(), \"expect/200/\"),\n            ))\n            .mount(&mock_server)\n            .await;\n\n        Mock::given(matchers::path(\"expect/304/\"))\n            .respond_with(ResponseTemplate::new(304).insert_header(\n                \"location\",\n                format!(\"http://{}/{}\", mock_server.address(), \"expect/200/\"),\n            ))\n            .mount(&mock_server)\n            .await;\n\n        Mock::given(matchers::path(\"expect/location/\"))\n            .respond_with(ResponseTemplate::new(200).insert_header(\n                \"location\",\n                format!(\"http://{}/{}\", mock_server.address(), \"expect/200/\"),\n            ))\n            .mount(&mock_server)\n            .await;\n\n        let mut data: Vec<u8> = Vec::new();\n        llrt_compression::zstd::encoder(welcome_message.as_bytes(), 3)\n            .unwrap()\n            .read_to_end(&mut data)\n            .unwrap();\n        Mock::given(matchers::path(\"content-encoding/zstd/\"))\n            .respond_with(\n                ResponseTemplate::new(200)\n                    .append_header(\"content-encoding\", \"zstd\")\n                    .set_body_raw(data.to_owned(), \"text/plain\"),\n            )\n            .mount(&mock_server)\n            .await;\n\n        let mut data: Vec<u8> = Vec::new();\n        llrt_compression::brotli::encoder(welcome_message.as_bytes())\n            .read_to_end(&mut data)\n            .unwrap();\n        Mock::given(matchers::path(\"content-encoding/br/\"))\n            .respond_with(\n                ResponseTemplate::new(200)\n                    .append_header(\"content-encoding\", \"br\")\n                    .set_body_raw(data.to_owned(), \"text/plain\"),\n            )\n            .mount(&mock_server)\n            .await;\n\n        let mut data: Vec<u8> = Vec::new();\n        llrt_compression::gz::encoder(\n            welcome_message.as_bytes(),\n            llrt_compression::gz::Compression::default(),\n        )\n        .read_to_end(&mut data)\n        .unwrap();\n        Mock::given(matchers::path(\"content-encoding/gzip/\"))\n            .respond_with(\n                ResponseTemplate::new(200)\n                    .append_header(\"content-encoding\", \"gzip\")\n                    .set_body_raw(data.to_owned(), \"text/plain\"),\n            )\n            .mount(&mock_server)\n            .await;\n\n        let mut data: Vec<u8> = Vec::new();\n        llrt_compression::zlib::encoder(\n            welcome_message.as_bytes(),\n            llrt_compression::zlib::Compression::default(),\n        )\n        .read_to_end(&mut data)\n        .unwrap();\n        Mock::given(matchers::path(\"content-encoding/deflate/\"))\n            .respond_with(\n                ResponseTemplate::new(200)\n                    .append_header(\"content-encoding\", \"deflate\")\n                    .set_body_raw(data.to_owned(), \"text/plain\"),\n            )\n            .mount(&mock_server)\n            .await;\n\n        // NOTE: A minimum redirect test pattern was created. Please add more as needed.\n        test_async_with(|ctx| {\n            crate::init(&ctx).unwrap();\n            Box::pin(async move {\n                let globals = ctx.globals();\n                let run = async {\n                    let fetch: Function = globals.get(\"fetch\")?;\n\n                    let headers = Object::new(ctx.clone())?;\n                    headers.set(\"content-encoding\", \"gzip\")?;\n                    headers.set(\"content-language\", \"en\")?;\n                    headers.set(\"content-location\", \"/documents/foo.txt\")?;\n                    headers.set(\"content-type\", \"text/plain\")?;\n                    headers.set(\"authorization\", \"Basic YWxhZGRpbjpvcGVuc2VzYW1l\")?;\n\n                    let options = Object::new(ctx.clone())?;\n                    options.set(\"redirect\", \"follow\")?;\n                    options.set(\"headers\", headers.clone())?;\n\n                    // Method: GET, Redirect Pattern: None\n                    options.set(\"method\", \"GET\")?;\n                    let url = format!(\"http://{}/expect/200/\", mock_server.address().clone());\n\n                    let response_promise: Promise = fetch.call((url, options.clone()))?;\n                    let response: Class<Response> = response_promise.into_future().await?;\n                    let response = response.borrow_mut();\n                    let response_text = response.text(ctx.clone()).await?;\n\n                    assert_eq!(response.status(), 200);\n                    assert_eq!(\n                        response.url(),\n                        format!(\"http://{}/expect/200/\", mock_server.address().clone())\n                    );\n                    assert!(!response.redirected());\n                    assert_eq!(response_text, welcome_message);\n\n                    // Method: GET, Redirect Pattern: 301 -> 200\n                    options.set(\"method\", \"GET\")?;\n                    let url = format!(\"http://{}/expect/301/\", mock_server.address().clone());\n\n                    let response_promise: Promise = fetch.call((url, options.clone()))?;\n                    let response: Class<Response> = response_promise.into_future().await?;\n                    let response = response.borrow();\n\n                    assert_eq!(response.status(), 200);\n                    assert_eq!(\n                        response.url(),\n                        format!(\"http://{}/expect/200/\", mock_server.address().clone())\n                    );\n                    assert!(response.redirected());\n\n                    // Method: GET, Redirect Pattern: 302 -> 200\n                    options.set(\"method\", \"GET\")?;\n                    let url = format!(\"http://{}/expect/302/\", mock_server.address().clone());\n\n                    let response_promise: Promise = fetch.call((url, options.clone()))?;\n                    let response: Class<Response> = response_promise.into_future().await?;\n                    let response = response.borrow();\n\n                    assert_eq!(response.status(), 200);\n                    assert_eq!(\n                        response.url(),\n                        format!(\"http://{}/expect/200/\", mock_server.address().clone())\n                    );\n                    assert!(response.redirected());\n\n                    // Method: GET, Redirect Pattern: 303 -> 200\n                    options.set(\"method\", \"GET\")?;\n                    let url = format!(\"http://{}/expect/303/\", mock_server.address().clone());\n\n                    let response_promise: Promise = fetch.call((url, options.clone()))?;\n                    let response: Class<Response> = response_promise.into_future().await?;\n                    let response = response.borrow();\n\n                    assert_eq!(response.status(), 200);\n                    assert_eq!(\n                        response.url(),\n                        format!(\"http://{}/expect/200/\", mock_server.address().clone())\n                    );\n                    assert!(response.redirected());\n\n                    // Method: GET, Non-redirect status with location header (304) - should NOT follow\n                    options.set(\"method\", \"GET\")?;\n                    let url = format!(\"http://{}/expect/location/\", mock_server.address().clone());\n\n                    let response_promise: Promise = fetch.call((url, options.clone()))?;\n                    let response: Class<Response> = response_promise.into_future().await?;\n                    let response = response.borrow();\n\n                    assert_eq!(response.status(), 200);\n                    assert_eq!(\n                        response.url(),\n                        format!(\"http://{}/expect/location/\", mock_server.address().clone())\n                    );\n                    assert!(!response.redirected());\n\n                    // Content-Encoding: zstd\n                    let url = format!(\n                        \"http://{}/content-encoding/zstd/\",\n                        mock_server.address().clone()\n                    );\n\n                    let response_promise: Promise = fetch.call((url, options.clone()))?;\n                    let response: Class<Response> = response_promise.into_future().await?;\n                    let response = response.borrow_mut();\n                    let response_text = response.text(ctx.clone()).await?;\n\n                    assert_eq!(response_text, welcome_message);\n\n                    // Content-Encoding: br\n                    let url = format!(\n                        \"http://{}/content-encoding/br/\",\n                        mock_server.address().clone()\n                    );\n\n                    let response_promise: Promise = fetch.call((url, options.clone()))?;\n                    let response: Class<Response> = response_promise.into_future().await?;\n                    let response = response.borrow_mut();\n                    let response_text = response.text(ctx.clone()).await?;\n\n                    assert_eq!(response_text, welcome_message);\n\n                    // Content-Encoding: gzip\n                    let url = format!(\n                        \"http://{}/content-encoding/gzip/\",\n                        mock_server.address().clone()\n                    );\n\n                    let response_promise: Promise = fetch.call((url, options.clone()))?;\n                    let response: Class<Response> = response_promise.into_future().await?;\n                    let response = response.borrow_mut();\n                    let response_text = response.text(ctx.clone()).await?;\n\n                    assert_eq!(response_text, welcome_message);\n\n                    // Content-Encoding: deflate\n                    let url = format!(\n                        \"http://{}/content-encoding/deflate/\",\n                        mock_server.address().clone()\n                    );\n\n                    let response_promise: Promise = fetch.call((url, options.clone()))?;\n                    let response: Class<Response> = response_promise.into_future().await?;\n                    let response = response.borrow_mut();\n                    let response_text = response.text(ctx.clone()).await?;\n\n                    assert_eq!(response_text, welcome_message);\n\n                    Ok(())\n                };\n                run.await.catch(&ctx).unwrap();\n            })\n        })\n        .await;\n    }\n\n    #[cfg(any(\n        feature = \"tls-ring\",\n        feature = \"tls-aws-lc\",\n        all(feature = \"tls-graviola\", target_arch = \"x86_64\")\n    ))]\n    #[tokio::test]\n    async fn test_fetch_tls() {\n        let mock_server = llrt_test_tls::MockServer::start().await.unwrap();\n        let addr = mock_server.address().to_string();\n        let ca = mock_server.ca().to_string();\n\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                crate::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<HttpsModule>(ctx.clone(), \"https\")\n                    .await\n                    .unwrap();\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { Agent } from 'https';\n\n                        export async function test(addr, ca) {\n                            const response = await fetch(`https://${addr}/echo`, {\n                                method: \"POST\",\n                                body: \"Hello, LLRT!\",\n                                agent: new Agent({\n                                    ca: ca\n                                }),\n                            });\n                            const text = await response.text();\n                            return text;\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n\n                let result = call_test::<String, _>(&ctx, &module, (addr, ca)).await;\n\n                assert_eq!(result, \"Hello, LLRT!\");\n            })\n        })\n        .await;\n    }\n\n    #[cfg(any(\n        feature = \"tls-ring\",\n        feature = \"tls-aws-lc\",\n        all(feature = \"tls-graviola\", target_arch = \"x86_64\")\n    ))]\n    #[tokio::test]\n    async fn test_fetch_ignore_certificate_errors() {\n        let mock_server = llrt_test_tls::MockServer::start().await.unwrap();\n        let addr = mock_server.address().to_string();\n\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                crate::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<HttpsModule>(ctx.clone(), \"https\")\n                    .await\n                    .unwrap();\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { Agent } from 'https';\n\n                        export async function test(addr) {\n                            const response = await fetch(`https://${addr}/echo`, {\n                                method: \"POST\",\n                                body: \"Hello, LLRT!\",\n                                agent: new Agent({\n                                    rejectUnauthorized: false,\n                                }),\n                            });\n                            const text = await response.text();\n                            return text;\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n\n                let result = call_test::<String, _>(&ctx, &module, (addr,)).await;\n\n                assert_eq!(result, \"Hello, LLRT!\");\n            })\n        })\n        .await;\n    }\n}\n"
  },
  {
    "path": "modules/llrt_fetch/src/form_data.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{\n    io::Write,\n    sync::{Arc, Mutex},\n};\n\nuse llrt_buffer::{Blob, File};\nuse llrt_utils::{class::IteratorDef, object::map_to_entries, result::ResultExt};\nuse rand::RngExt;\nuse rquickjs::{\n    atom::PredefinedAtom, class::Trace, prelude::Opt, Array, Class, Ctx, Exception, Function,\n    IntoJs, JsLifetime, Result, Value,\n};\n\n#[derive(Clone)]\nenum FormValue {\n    Text(String),\n    File(File),\n    Blob(Blob),\n}\n\nimpl<'js> IntoJs<'js> for FormValue {\n    fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {\n        match self {\n            FormValue::Text(s) => s.into_js(ctx),\n            FormValue::File(f) => f.clone().into_js(ctx),\n            FormValue::Blob(b) => b.clone().into_js(ctx),\n        }\n    }\n}\n\n#[derive(Clone, Trace, JsLifetime, Default)]\n#[rquickjs::class]\npub struct FormData {\n    #[qjs(skip_trace)]\n    entries: Arc<Mutex<Vec<(String, FormValue)>>>,\n}\n\nimpl<'js> IteratorDef<'js> for FormData {\n    fn js_entries(&self, ctx: Ctx<'js>) -> Result<Array<'js>> {\n        let entries = self.entries.lock().or_throw(&ctx)?;\n        map_to_entries(&ctx, entries.clone())\n    }\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl<'js> FormData {\n    #[qjs(constructor)]\n    pub fn new(_form: Opt<Value<'js>>, _submitter: Opt<Value<'js>>) -> Self {\n        Self {\n            entries: Arc::new(Mutex::new(Vec::new())),\n        }\n    }\n\n    pub fn append(&self, ctx: Ctx<'js>, name: String, value: Value<'js>) -> Result<()> {\n        let mut entries = self.entries.lock().or_throw(&ctx)?;\n\n        if let Some(obj) = value.clone().into_object() {\n            if let Some(f) = Class::<File>::from_object(&obj) {\n                let file = f.borrow().to_owned();\n                entries.push((name, FormValue::File(file)));\n                return Ok(());\n            }\n            if let Some(b) = Class::<Blob>::from_object(&obj) {\n                let blob = b.borrow().to_owned();\n                entries.push((name, FormValue::Blob(blob)));\n                return Ok(());\n            }\n        }\n\n        if let Some(s) = value.as_string() {\n            let str = s.to_string().or_throw(&ctx)?;\n            entries.push((name, FormValue::Text(str)));\n            return Ok(());\n        }\n\n        Err(Exception::throw_type(&ctx, \"Invalid FormData value type\"))\n    }\n\n    pub fn get(&self, ctx: Ctx<'js>, name: String) -> Result<Option<Value<'js>>> {\n        let entries = self.entries.lock().or_throw(&ctx)?;\n        for (k, v) in entries.iter().rev() {\n            if *k == name {\n                return Ok(v.clone().into_js(&ctx).ok());\n            }\n        }\n        Ok(None)\n    }\n\n    pub fn get_all(&self, ctx: Ctx<'js>, name: String) -> Result<Vec<Value<'js>>> {\n        let entries = self.entries.lock().or_throw(&ctx)?;\n\n        Ok(entries\n            .iter()\n            .filter(|(k, _)| *k == name)\n            .filter_map(|(_, v)| v.clone().into_js(&ctx).ok())\n            .collect())\n    }\n\n    pub fn has(&self, ctx: Ctx<'js>, name: String) -> Result<bool> {\n        let entries = self.entries.lock().or_throw(&ctx)?;\n\n        Ok(entries.iter().any(|(n, _)| n == &name))\n    }\n\n    pub fn set(&self, ctx: Ctx<'js>, name: String, value: Value<'js>) -> Result<()> {\n        let mut entries = self.entries.lock().or_throw(&ctx)?;\n        entries.retain(|(k, _)| *k != name);\n\n        if let Some(obj) = value.clone().into_object() {\n            if let Some(f) = Class::<File>::from_object(&obj) {\n                let file = f.borrow().to_owned();\n                entries.push((name, FormValue::File(file)));\n                return Ok(());\n            }\n            if let Some(b) = Class::<Blob>::from_object(&obj) {\n                let blob = b.borrow().to_owned();\n                entries.push((name, FormValue::Blob(blob)));\n                return Ok(());\n            }\n        }\n\n        if let Ok(s) = value.try_into_string() {\n            let string = s.to_string().or_throw(&ctx)?;\n            entries.push((name, FormValue::Text(string)));\n            return Ok(());\n        }\n\n        Err(Exception::throw_type(&ctx, \"Invalid FormData value type\"))\n    }\n\n    pub fn delete(&self, ctx: Ctx<'js>, name: String) -> Result<()> {\n        let mut entries = self.entries.lock().or_throw(&ctx)?;\n\n        entries.retain(|(k, _)| *k != name);\n        Ok(())\n    }\n\n    pub fn keys(&self, ctx: Ctx<'js>) -> Result<Vec<String>> {\n        let entries = self.entries.lock().or_throw(&ctx)?;\n\n        Ok(entries.iter().map(|(k, _)| k.clone()).collect())\n    }\n\n    pub fn values(&self, ctx: Ctx<'js>) -> Result<Vec<Value<'js>>> {\n        let ctx2 = ctx.clone();\n        let entries = self.entries.lock().or_throw(&ctx)?;\n\n        Ok(entries\n            .iter()\n            .filter_map(|(_, v)| v.clone().into_js(&ctx2).ok())\n            .collect())\n    }\n\n    pub fn entries(&self, ctx: Ctx<'js>) -> Result<Value<'js>> {\n        self.js_iterator(ctx)\n    }\n\n    #[qjs(rename = PredefinedAtom::SymbolIterator)]\n    pub fn iterator(&self, ctx: Ctx<'js>) -> Result<Value<'js>> {\n        self.js_iterator(ctx)\n    }\n\n    pub fn for_each(&self, ctx: Ctx<'js>, callback: Function<'js>) -> Result<()> {\n        let entries = self.entries.lock().or_throw(&ctx)?;\n\n        for (name, value) in entries.iter() {\n            let val = value.clone().into_js(&ctx)?;\n            () = callback.call((val, name.clone()))?;\n        }\n\n        Ok(())\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    pub fn to_string_tag(&self) -> &'static str {\n        stringify!(FormData)\n    }\n}\n\nimpl FormData {\n    #[allow(private_interfaces)]\n    pub fn iter<'js>(&self, ctx: &Ctx<'js>) -> Result<impl Iterator<Item = (String, FormValue)>> {\n        let entries = self.entries.lock().or_throw(ctx)?;\n        let entries = entries.clone();\n\n        Ok(entries.into_iter())\n    }\n\n    pub fn from_multipart_bytes<'js>(\n        ctx: &Ctx<'js>,\n        content_type: &str,\n        bytes: Vec<u8>,\n    ) -> Result<Self> {\n        if bytes.is_empty() {\n            return Ok(Self::default());\n        }\n\n        let Some(boundary) = extract_boundary(content_type) else {\n            return Ok(Self::default());\n        };\n        let boundary_marker = [\"--\", &boundary].concat().into_bytes();\n\n        let mut entries = Vec::new();\n        let parts = bytes.split(|b| *b == b'\\n').collect::<Vec<_>>();\n\n        let mut current_headers = Vec::new();\n        let mut current_data = Vec::new();\n        let mut in_headers = false;\n\n        let mut name: Option<String> = None;\n        let mut filename: Option<String> = None;\n        let mut mime_type: Option<String> = None;\n\n        for line in parts {\n            if line.starts_with(&boundary_marker) {\n                if !current_data.is_empty() && name.is_some() {\n                    let data = std::mem::take(&mut current_data);\n                    if let Some(filename) = filename.take() {\n                        let file = File::from_bytes(ctx, data, filename, mime_type)?;\n                        entries.push((name.take().or_throw(ctx)?, FormValue::File(file)));\n                    } else {\n                        let text = String::from_utf8_lossy(&data).into_owned();\n                        entries.push((name.take().or_throw(ctx)?, FormValue::Text(text)));\n                    }\n                }\n                current_headers.clear();\n                current_data.clear();\n                name = None;\n                filename = None;\n                mime_type = None;\n                in_headers = true;\n                continue;\n            }\n\n            if in_headers {\n                let line_str = String::from_utf8_lossy(line);\n                if line_str.trim().is_empty() {\n                    in_headers = false;\n                } else {\n                    current_headers.push(line_str.to_string());\n                    if line_str.to_lowercase().starts_with(\"content-disposition\") {\n                        for seg in line_str.split(';') {\n                            let seg = seg.trim();\n                            if let Some(n) = seg.strip_prefix(\"name=\") {\n                                name = Some(n.trim_matches('\"').into());\n                            } else if let Some(f) = seg.strip_prefix(\"filename=\") {\n                                filename = Some(f.trim_matches('\"').into());\n                            }\n                        }\n                    } else if line_str.to_lowercase().starts_with(\"content-type\") {\n                        if let Some(ct) = line_str.split(':').nth(1) {\n                            mime_type = Some(ct.trim().into());\n                        }\n                    }\n                }\n            } else {\n                current_data.extend_from_slice(line);\n                current_data.push(b'\\n');\n            }\n        }\n\n        Ok(Self {\n            entries: Arc::new(Mutex::new(entries)),\n        })\n    }\n\n    pub fn to_multipart_bytes<'js>(&self, ctx: &Ctx<'js>) -> Result<(Vec<u8>, String)> {\n        let boundary = generate_boundary();\n        let mut body = Vec::new();\n        let entries = self.entries.lock().or_throw(ctx)?;\n\n        for (name, value) in entries.iter() {\n            match value {\n                FormValue::Text(text) => {\n                    write!(\n                        body,\n                        \"--{boundary}\\r\\nContent-Disposition: form-data; name=\\\"{name}\\\"\\r\\n\\r\\n{text}\\r\\n\"\n                    )?;\n                },\n                FormValue::File(file) => {\n                    let filename = file.name().clone();\n                    let content_type = file.mime_type().clone();\n                    let bytes = file.get_blob().get_bytes();\n                    write!(\n                        body,\n                        \"--{boundary}\\r\\nContent-Disposition: form-data; name=\\\"{name}\\\"; filename=\\\"{filename}\\\"\\r\\nContent-Type: {content_type}\\r\\n\\r\\n\"\n                    )?;\n                    body.extend_from_slice(&bytes);\n                    body.extend_from_slice(b\"\\r\\n\");\n                },\n                FormValue::Blob(blob) => {\n                    let bytes = blob.get_bytes();\n                    let content_type = blob.mime_type();\n                    write!(\n                        body,\n                        \"--{boundary}\\r\\nContent-Disposition: form-data; name=\\\"{name}\\\"; filename=\\\"blob\\\"\\r\\nContent-Type: {content_type}\\r\\n\\r\\n\"\n                    )?;\n                    body.extend_from_slice(&bytes);\n                    body.extend_from_slice(b\"\\r\\n\");\n                },\n            }\n        }\n\n        write!(body, \"--{boundary}--\\r\\n\")?;\n\n        Ok((body, boundary))\n    }\n}\n\nfn extract_boundary(content_type: &str) -> Option<String> {\n    content_type.split(';').find_map(|part| {\n        let part = part.trim();\n        part.find(\"boundary=\").map(|idx| {\n            part[(idx + \"boundary=\".len())..]\n                .trim()\n                .trim_matches('\"')\n                .into()\n        })\n    })\n}\n\nfn generate_boundary() -> String {\n    let rand_string: String = rand::rng()\n        .sample_iter(&rand::distr::Alphanumeric)\n        .take(24)\n        .map(char::from)\n        .collect();\n\n    [\"----WebKitFormBoundary\", &rand_string].concat()\n}\n"
  },
  {
    "path": "modules/llrt_fetch/src/headers.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#![allow(clippy::uninlined_format_args)]\n\nuse std::{collections::BTreeMap, rc::Rc};\n\nuse hyper::HeaderMap;\nuse llrt_utils::{\n    class::{CustomInspect, IteratorDef},\n    object::map_to_entries,\n    primordials::{BasePrimordials, Primordial},\n    result::ResultExt,\n};\nuse rquickjs::{\n    atom::PredefinedAtom, class::Trace, methods, prelude::Opt, Array, Coerced, Ctx, Exception,\n    FromJs, Function, IntoJs, Iterable, JsLifetime, Null, Object, Result, Symbol, Value,\n};\n\nconst HEADERS_KEY_COOKIE: &str = \"cookie\";\nconst HEADERS_KEY_SET_COOKIE: &str = \"set-cookie\";\npub const HEADERS_KEY_CONTENT_TYPE: &str = \"content-type\";\n\ntype ImmutableString = Rc<str>;\n\n// https://fetch.spec.whatwg.org/#concept-headers-guard\n#[derive(Clone, Default, PartialEq)]\npub enum HeadersGuard {\n    #[default]\n    None,\n    Request,\n    RequestNoCors,\n    Response,\n    Immutable,\n}\n\n#[derive(Clone, Default, Trace, JsLifetime)]\n#[rquickjs::class]\npub struct Headers {\n    #[qjs(skip_trace)]\n    headers: Vec<(ImmutableString, ImmutableString)>,\n    #[qjs(skip_trace)]\n    guard: HeadersGuard,\n}\n\n#[methods(rename_all = \"camelCase\")]\nimpl Headers {\n    #[qjs(constructor)]\n    pub fn new<'js>(ctx: Ctx<'js>, init: Opt<Value<'js>>) -> Result<Self> {\n        if let Some(init) = init.into_inner() {\n            if init.is_null() || init.is_number() {\n                return Err(Exception::throw_type(&ctx, \"Invalid argument\"));\n            }\n            return Self::from_value(&ctx, init, HeadersGuard::None);\n        }\n\n        Ok(Self {\n            headers: Vec::new(),\n            guard: HeadersGuard::None,\n        })\n    }\n\n    pub fn append<'js>(&mut self, ctx: Ctx<'js>, key: String, value: Value<'js>) -> Result<()> {\n        let key: ImmutableString = key.to_lowercase().into();\n        if !is_http_header_name(&key) {\n            return Err(Exception::throw_type(&ctx, \"Invalid key\"));\n        }\n\n        let mut value = coerce_to_string(&ctx, value)?;\n        normalize_header_value_inplace(&ctx, &mut value)?;\n        if self.guard == HeadersGuard::RequestNoCors {\n            let val = value.split(',').next().unwrap_or(\"\").trim();\n            if !is_cors_safelisted_request_header(&key, val) {\n                return Ok(()); // silently ignore disallowed header\n            }\n            if self.headers.iter().any(|(k, _)| k == &key) {\n                return Ok(()); // silently ignore same header\n            }\n            value = val.into();\n        };\n        if !is_http_header_value(&value) {\n            return Err(Exception::throw_type(&ctx, \"Invalid value of key\"));\n        }\n\n        let str_key = key.as_ref();\n        if str_key == HEADERS_KEY_SET_COOKIE {\n            return {\n                self.headers.push((key, value.into()));\n                Ok(())\n            };\n        }\n        if let Some((_, existing_value)) = self.headers.iter_mut().find(|(k, _)| k == &key) {\n            let mut new_value = String::with_capacity(existing_value.len() + 2 + value.len());\n            new_value.push_str(existing_value);\n            match str_key {\n                HEADERS_KEY_COOKIE => new_value.push_str(\"; \"),\n                _ => new_value.push_str(\", \"),\n            }\n            new_value.push_str(&value);\n            *existing_value = new_value.into();\n        } else {\n            self.headers.push((key, value.into()));\n        }\n        Ok(())\n    }\n\n    pub fn get<'js>(&self, ctx: Ctx<'js>, key: String) -> Result<Value<'js>> {\n        let key: ImmutableString = key.to_lowercase().into();\n        if !is_http_header_name(&key) {\n            return Err(Exception::throw_type(&ctx, \"Invalid key\"));\n        }\n\n        if key.as_ref() == HEADERS_KEY_SET_COOKIE {\n            let result: Vec<&str> = self\n                .headers\n                .iter()\n                .filter_map(|(k, v)| if k == &key { Some(v.as_ref()) } else { None })\n                .collect();\n            return if result.is_empty() {\n                Null.into_js(&ctx)\n            } else {\n                result.join(\", \").into_js(&ctx)\n            };\n        }\n        self.headers\n            .iter()\n            .find(|(k, _)| *k == key)\n            .map(|(_, v)| v.as_ref().into_js(&ctx))\n            .unwrap_or_else(|| Null.into_js(&ctx))\n    }\n\n    pub fn get_set_cookie(&self) -> Vec<&str> {\n        self.headers\n            .iter()\n            .filter_map(|(k, v)| {\n                if k.as_ref() == HEADERS_KEY_SET_COOKIE {\n                    Some(v.as_ref())\n                } else {\n                    None\n                }\n            })\n            .collect()\n    }\n\n    pub fn has<'js>(&self, ctx: Ctx<'js>, key: String) -> Result<bool> {\n        let key: ImmutableString = key.to_lowercase().into();\n        if !is_http_header_name(&key) {\n            return Err(Exception::throw_type(&ctx, \"Invalid key\"));\n        }\n\n        Ok(self.headers.iter().any(|(k, _)| k == &key))\n    }\n\n    pub fn set<'js>(&mut self, ctx: Ctx<'js>, key: String, value: Value<'js>) -> Result<()> {\n        let key: ImmutableString = key.to_lowercase().into();\n        if !is_http_header_name(&key) {\n            return Err(Exception::throw_type(&ctx, \"Invalid key\"));\n        }\n\n        let mut value = coerce_to_string(&ctx, value)?;\n        normalize_header_value_inplace(&ctx, &mut value)?;\n        if self.guard == HeadersGuard::RequestNoCors {\n            let val = value.split(',').next().unwrap_or(\"\").trim();\n            if !is_cors_safelisted_request_header(&key, val) {\n                return Ok(()); // silently ignore disallowed header\n            }\n            value = val.into();\n        }\n        if !is_http_header_value(&value) {\n            return Err(Exception::throw_type(&ctx, \"Invalid value of key\"));\n        }\n\n        if key.as_ref() == HEADERS_KEY_SET_COOKIE {\n            self.headers.retain(|(k, _)| k != &key);\n            self.headers.push((key, value.into()));\n        } else {\n            match self.headers.iter_mut().find(|(k, _)| k == &key) {\n                Some((_, existing_value)) => *existing_value = value.into(),\n                None => self.headers.push((key, value.into())),\n            }\n        }\n        Ok(())\n    }\n\n    pub fn delete<'js>(&mut self, ctx: Ctx<'js>, key: String) -> Result<()> {\n        let key: ImmutableString = key.to_lowercase().into();\n        if !is_http_header_name(&key) {\n            return Err(Exception::throw_type(&ctx, \"Invalid key\"));\n        }\n\n        self.headers.retain(|(k, _)| k != &key);\n        Ok(())\n    }\n\n    pub fn keys<'js>(&self, ctx: Ctx<'js>) -> Result<Value<'js>> {\n        Iterable::from(\n            self.headers\n                .iter()\n                .map(|(k, _)| k.to_string())\n                .collect::<Vec<_>>(),\n        )\n        .into_js(&ctx)\n    }\n\n    pub fn values<'js>(&self, ctx: Ctx<'js>) -> Result<Value<'js>> {\n        Iterable::from(\n            self.headers\n                .iter()\n                .map(|(_, v)| v.to_string())\n                .collect::<Vec<_>>(),\n        )\n        .into_js(&ctx)\n    }\n\n    pub fn entries<'js>(&self, ctx: Ctx<'js>) -> Result<Value<'js>> {\n        self.js_iterator(ctx)\n    }\n\n    #[qjs(rename = PredefinedAtom::SymbolIterator)]\n    pub fn iterator<'js>(&self, ctx: Ctx<'js>) -> Result<Value<'js>> {\n        self.js_iterator(ctx)\n    }\n\n    pub fn for_each(&self, callback: Function<'_>) -> Result<()> {\n        for (k, v) in &self.headers {\n            () = callback.call((v.as_ref(), k.as_ref()))?;\n        }\n        Ok(())\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    pub fn to_string_tag(&self) -> &'static str {\n        stringify!(Headers)\n    }\n}\n\nimpl Headers {\n    pub fn iter(&self) -> impl Iterator<Item = (&str, &str)> {\n        self.headers.iter().map(|(k, v)| (k.as_ref(), v.as_ref()))\n    }\n\n    pub fn from_http_headers(header_map: &HeaderMap, guard: HeadersGuard) -> Result<Self> {\n        let mut headers = Vec::new();\n        for (n, v) in header_map.iter() {\n            headers.push((\n                n.as_str().into(),\n                String::from_utf8_lossy(v.as_bytes()).into(),\n            ));\n        }\n        Ok(Self { headers, guard })\n    }\n\n    pub fn from_value<'js>(ctx: &Ctx<'js>, value: Value<'js>, guard: HeadersGuard) -> Result<Self> {\n        if value.is_array() {\n            let array = unsafe { value.into_array().unwrap_unchecked() };\n            return Self::from_array(ctx, array, guard);\n        }\n\n        if let Some(obj) = value.as_object() {\n            if obj.contains_key(Symbol::iterator(ctx.clone()))? {\n                let array: Array = BasePrimordials::get(ctx)?\n                    .function_array_from\n                    .call((value,))?;\n                return Self::from_array(ctx, array, guard);\n            } else if obj.instance_of::<Headers>() {\n                return Headers::from_js(ctx, value);\n            } else {\n                let map: BTreeMap<String, Coerced<String>> = value.get().unwrap_or_default();\n                return Ok(Self::from_map(ctx, map, guard));\n            }\n        }\n\n        Ok(Self {\n            headers: vec![],\n            guard,\n        })\n    }\n\n    pub fn from_map(\n        ctx: &Ctx<'_>,\n        map: BTreeMap<String, Coerced<String>>,\n        guard: HeadersGuard,\n    ) -> Self {\n        let headers = map\n            .into_iter()\n            .filter_map(|(k, v)| {\n                if !is_http_header_name(&k) {\n                    return None;\n                }\n                let mut value = v.0;\n                let _ = normalize_header_value_inplace(ctx, &mut value);\n                Some((k.to_lowercase().into(), value.into()))\n            })\n            .collect::<Vec<(Rc<str>, Rc<str>)>>();\n\n        Self { headers, guard }\n    }\n\n    fn from_array<'js>(ctx: &Ctx<'js>, array: Array<'js>, guard: HeadersGuard) -> Result<Self> {\n        let mut headers: Vec<(ImmutableString, ImmutableString)> = Vec::new();\n\n        for entry in array.into_iter().flatten() {\n            if let Some(array_entry) = entry.as_array() {\n                if array_entry.len() % 2 != 0 {\n                    return Err(Exception::throw_type(ctx, \"Header arrays are not paired\"));\n                }\n\n                let raw_key = array_entry.get::<String>(0)?.to_lowercase();\n                let key: Rc<str> = ImmutableString::from(raw_key.clone());\n                if !is_http_header_name(&key) {\n                    return Err(Exception::throw_type(ctx, \"Invalid key\"));\n                }\n\n                let raw_value = array_entry.get::<Value>(1)?;\n                let value: ImmutableString = coerce_to_string(ctx, raw_value)?.into();\n                if !is_http_header_value(&value) {\n                    return Err(Exception::throw_type(ctx, \"Invalid value of key\"));\n                }\n\n                if raw_key == HEADERS_KEY_SET_COOKIE {\n                    headers.push((key, value));\n                    continue;\n                }\n\n                if let Some((_, existing_value)) = headers.iter_mut().find(|(k, _)| *k == key) {\n                    let mut new_value = existing_value.to_string();\n\n                    match raw_key.as_str() {\n                        HEADERS_KEY_COOKIE => new_value.push_str(\"; \"),\n                        _ => new_value.push_str(\", \"),\n                    }\n\n                    new_value.push_str(&value);\n                    *existing_value = ImmutableString::from(new_value);\n                } else {\n                    headers.push((key, value));\n                }\n            }\n        }\n\n        headers.sort_by(|a, b| a.0.cmp(&b.0));\n\n        Ok(Self { headers, guard })\n    }\n}\n\nimpl<'js> IteratorDef<'js> for Headers {\n    fn js_entries(&self, ctx: Ctx<'js>) -> Result<Array<'js>> {\n        map_to_entries(\n            &ctx,\n            self.headers.iter().map(|(k, v)| (k.as_ref(), v.as_ref())),\n        )\n    }\n}\n\nimpl<'js> CustomInspect<'js> for Headers {\n    fn custom_inspect(&self, ctx: Ctx<'js>) -> Result<Object<'js>> {\n        let obj = Object::new(ctx)?;\n        for (k, v) in self.headers.iter() {\n            obj.set(k.as_ref(), v.as_ref())?;\n        }\n\n        Ok(obj)\n    }\n}\n\nfn coerce_to_string<'js>(ctx: &Ctx<'js>, value: Value<'js>) -> Result<String> {\n    if value.is_null() {\n        Ok(\"null\".into())\n    } else if value.is_undefined() {\n        Ok(\"undefined\".into())\n    } else if let Some(v) = value.as_bool() {\n        Ok(v.to_string())\n    } else if let Some(v) = value.as_number() {\n        Ok(v.to_string())\n    } else if let Some(s) = value.as_string() {\n        s.to_string()\n    } else {\n        // fallback: try JSON.stringify or [object Object]\n        let base_primordials = BasePrimordials::get(ctx)?;\n        base_primordials.constructor_string.construct((value,))\n    }\n}\n\n// 3.2.6.  Field Value Components\n// https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6\nfn is_http_header_name(name: &str) -> bool {\n    if name.is_empty() {\n        return false;\n    }\n\n    name.bytes().all(|b| {\n        matches!(b,\n            b'!' | b'#' | b'$' | b'%' | b'&' | b'\\'' | b'*' | b'+' |\n            b'-' | b'.' | b'^' | b'_' | b'`' | b'|' | b'~' |\n            b'0'..=b'9' | b'A'..=b'Z' | b'a'..=b'z'\n        )\n    })\n}\n\nfn is_http_header_value(value: &str) -> bool {\n    value.chars().all(|c| {\n        c == '\\t'                // HTAB\n        || c == ' '              // SP\n        || (('\\u{21}'..='\\u{7E}').contains(&c)) // VCHAR range\n        || c == '\\u{0C}'         // Form Feed\n        || c == '\\u{00A0}' // NBSP\n    })\n}\n\nfn normalize_header_value_inplace(ctx: &Ctx<'_>, text: &mut String) -> Result<()> {\n    let mut input = std::mem::take(text).into_bytes();\n    let mut read_idx = 0;\n    let mut write_idx = 0;\n\n    // Skip leading SP or HTAB\n    while read_idx < input.len() && (input[read_idx] == b' ' || input[read_idx] == b'\\t') {\n        read_idx += 1;\n    }\n\n    // Store the last whitespace byte if any (space or tab)\n    let mut pending_whitespace: Option<u8> = None;\n\n    while read_idx < input.len() {\n        match input[read_idx] {\n            // obs-fold: CRLF followed by SP or HTAB\n            b'\\r'\n                if read_idx + 2 < input.len()\n                    && input[read_idx + 1] == b'\\n'\n                    && (input[read_idx + 2] == b' ' || input[read_idx + 2] == b'\\t') =>\n            {\n                pending_whitespace = Some(input[read_idx + 2]);\n                read_idx += 3;\n            },\n            b'\\r' | b'\\n' => {\n                // skip bare CR or LF\n                read_idx += 1;\n            },\n            b' ' | b'\\t' => {\n                // keep the last whitespace char to write later (collapse multiple)\n                pending_whitespace = Some(input[read_idx]);\n                read_idx += 1;\n            },\n            byte => {\n                // write pending whitespace if any\n                if let Some(ws) = pending_whitespace.take() {\n                    if write_idx > 0 {\n                        input[write_idx] = ws;\n                        write_idx += 1;\n                    }\n                }\n                input[write_idx] = byte;\n                write_idx += 1;\n                read_idx += 1;\n            },\n        }\n    }\n\n    // Trim trailing SP or HTAB\n    while write_idx > 0 && (input[write_idx - 1] == b' ' || input[write_idx - 1] == b'\\t') {\n        write_idx -= 1;\n    }\n\n    input.truncate(write_idx);\n    *text = String::from_utf8(input).or_throw(ctx)?;\n    Ok(())\n}\n\n// https://fetch.spec.whatwg.org/#cors-safelisted-request-header\npub fn is_cors_safelisted_request_header(key: &str, value: &str) -> bool {\n    if value.len() > 128 {\n        return false;\n    }\n\n    match key.to_ascii_lowercase().as_str() {\n        \"accept\" => !contains_cors_unsafe_request_header_byte(value),\n        \"accept-language\" | \"content-language\" => is_cors_safelisted_field_value(value),\n        \"content-type\" => {\n            if contains_cors_unsafe_request_header_byte(value) {\n                return false;\n            }\n            let mime_type = value.split(';').next().unwrap_or(\"\").trim();\n            matches!(\n                mime_type.to_ascii_lowercase().as_str(),\n                \"application/x-www-form-urlencoded\" | \"multipart/form-data\" | \"text/plain\" | \"\"\n            )\n        },\n        _ => false,\n    }\n}\n\n// https://fetch.spec.whatwg.org/#cors-unsafe-request-header-byte\npub fn contains_cors_unsafe_request_header_byte(value: &str) -> bool {\n    for byte in value.bytes() {\n        match byte {\n            // Control characters except for HT (0x09)\n            0x00..=0x08 | 0x0A..=0x1F => return true,\n\n            // byte is 0x22 (\"), 0x28 (left parenthesis), 0x29 (right parenthesis), 0x3A (:), 0x3C (<),\n            // 0x3E (>), 0x3F (?), 0x40 (@), 0x5B ([), 0x5C (\\), 0x5D (]), 0x7B ({), 0x7D (}), or 0x7F DEL.\n            0x22 | 0x28 | 0x29 | 0x3A | 0x3C | 0x3E | 0x3F | 0x40 | 0x5B | 0x5C | 0x5D | 0x7B\n            | 0x7F | 0x7D => return true,\n\n            _ => {}, // Allowed byte\n        }\n    }\n    false\n}\n\npub fn is_cors_safelisted_field_value(value: &str) -> bool {\n    value.bytes().all(|b| match b {\n        0x30..=0x39 | // 0-9\n        0x41..=0x5A | // A-Z\n        0x61..=0x7A | // a-z\n        0x20 | 0x2A | 0x2C | 0x2D | 0x2E | 0x3B | 0x3D => true, // allowed symbols\n        _ => false,\n    })\n}\n\n#[cfg(test)]\nmod tests {\n    use llrt_test::test_async_with;\n\n    use super::*;\n\n    #[tokio::test]\n    async fn test_get_header() {\n        test_async_with(|ctx| {\n            crate::init(&ctx).unwrap();\n            Box::pin(async move {\n                let mut headers = Headers::new(ctx.clone(), Opt(None)).unwrap();\n                headers\n                    .set(\n                        ctx.clone(),\n                        \"Content-Type\".into(),\n                        \"application/json\".into_js(&ctx).unwrap(),\n                    )\n                    .unwrap();\n\n                let append_headers = [\n                    (\"set-cookie\", \"cookie1=value1\"),\n                    (\"set-cookie\", \"cookie2=value2\"),\n                    (\"Accept-Encoding\", \"deflate\"),\n                    (\"Accept-Encoding\", \"gzip\"),\n                ];\n                for (key, value) in append_headers {\n                    headers\n                        .append(ctx.clone(), key.into(), value.into_js(&ctx).unwrap())\n                        .unwrap();\n                }\n\n                let get_headers = [\n                    (\"Content-Type\", \"application/json\"),\n                    (\"set-cookie\", \"cookie1=value1, cookie2=value2\"),\n                    (\"Accept-Encoding\", \"deflate, gzip\"),\n                ];\n                for (key, expected) in get_headers {\n                    assert_eq!(\n                        headers\n                            .get(ctx.clone(), key.into())\n                            .unwrap()\n                            .as_string()\n                            .unwrap()\n                            .to_string()\n                            .unwrap(),\n                        expected\n                    );\n                }\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_normalize_header_value_inplace() {\n        test_async_with(|ctx| {\n            crate::init(&ctx).unwrap();\n            Box::pin(async move {\n                // https://github.com/web-platform-tests/wpt/blob/master/fetch/api/headers/headers-normalize.any.js\n                let expectations = [\n                    (\" space \", \"space\"),\n                    (\"\\ttab\\t\", \"tab\"),\n                    (\" spaceAndTab\\t\", \"spaceAndTab\"),\n                    (\"\\r\\n newLine\", \"newLine\"),\n                    (\"newLine\\r\\n \", \"newLine\"),\n                    (\"\\r\\n\\tnewLine\", \"newLine\"),\n                    (\"\\t\\u{000C}\\tnewLine\\n\", \"\\u{000C}\\tnewLine\"), //  \\f = \\u{000C}\n                    (\"newLine\\u{00A0}\", \"newLine\\u{00A0}\"),   // \\u{00A0} = NBSP\n                ];\n                for (input, expected) in expectations {\n                    let mut value = input.to_string();\n                    super::normalize_header_value_inplace(&ctx, &mut value).unwrap();\n                    assert_eq!(\n                        value,\n                        expected,\n                        \"normalize_header_value_inplace failed: input = {:?}, expected = {:?}, got = {:?}\",\n                        input,\n                        expected,\n                        value\n                    );\n                }\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_headers_iterators() {\n        test_async_with(|ctx| {\n            crate::init(&ctx).unwrap();\n            Box::pin(async move {\n                let result: bool = ctx\n                    .eval(\n                        r#\"\n                        const h = new Headers([['x-first', '1'], ['x-second', '2']]);\n                        const iter = h.keys()[Symbol.iterator]();\n                        iter.next().value === 'x-first' &&\n                        iter.next().value === 'x-second' &&\n                        iter.next().done === true\n                        \"#,\n                    )\n                    .unwrap();\n                assert!(result, \"keys() iterator failed\");\n\n                let result: bool = ctx\n                    .eval(\n                        r#\"\n                        const h2 = new Headers([['x-first', '1'], ['x-second', '2']]);\n                        const iter2 = h2.values()[Symbol.iterator]();\n                        iter2.next().value === '1' &&\n                        iter2.next().value === '2' &&\n                        iter2.next().done === true\n                        \"#,\n                    )\n                    .unwrap();\n                assert!(result, \"values() iterator failed\");\n            })\n        })\n        .await;\n    }\n}\n"
  },
  {
    "path": "modules/llrt_fetch/src/incoming.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{\n    error::Error as StdError,\n    future::Future,\n    pin::Pin,\n    sync::Arc,\n    task::{ready, Context, Poll},\n};\n\nuse bytes::Bytes;\nuse http_body_util::BodyExt;\nuse hyper::{\n    body::{Body, Frame, Incoming, SizeHint},\n    HeaderMap,\n};\nuse llrt_utils::error_messages::ERROR_MSG_BROADCAST_LAGGED;\nuse pin_project_lite::pin_project;\nuse tokio::sync::{broadcast, watch};\n\npub fn channel(incoming: Incoming) -> (IncomingSender, IncomingReceiver) {\n    let (data_tx, data_rx) = broadcast::channel(16);\n    let (want_tx, want_rx) = watch::channel(());\n\n    let sender = IncomingSender {\n        inner: incoming,\n        want_rx,\n        data_tx,\n    };\n    let receiver = IncomingReceiver {\n        closed: false,\n        recv_fut: None,\n        want_tx,\n        data_rx,\n    };\n\n    (sender, receiver)\n}\n\n// The hyper frame is not `Clone`, so we need our own.\n// See: https://github.com/hyperium/hyper/discussions/3768\n#[derive(Clone)]\nenum ClonableFrame<T> {\n    Data(T),\n    Trailers(HeaderMap),\n}\n\nimpl<T> From<Frame<T>> for ClonableFrame<T> {\n    fn from(frame: Frame<T>) -> Self {\n        let frame = match frame.into_data() {\n            Ok(data) => return ClonableFrame::Data(data),\n            Err(frame) => frame,\n        };\n\n        match frame.into_trailers() {\n            Ok(trailers) => ClonableFrame::Trailers(trailers),\n            Err(_) => unreachable!(),\n        }\n    }\n}\n\nimpl<T> From<ClonableFrame<T>> for Frame<T> {\n    fn from(frame: ClonableFrame<T>) -> Self {\n        match frame {\n            ClonableFrame::Data(data) => Frame::data(data),\n            ClonableFrame::Trailers(trailers) => Frame::trailers(trailers),\n        }\n    }\n}\n\ntype RecvOutput =\n    Result<Result<ClonableFrame<Bytes>, Arc<hyper::Error>>, broadcast::error::RecvError>;\n\npub struct IncomingSender {\n    inner: Incoming,\n    want_rx: watch::Receiver<()>,\n    data_tx: broadcast::Sender<Result<ClonableFrame<Bytes>, Arc<hyper::Error>>>,\n}\n\nimpl IncomingSender {\n    pub async fn process(mut self) {\n        loop {\n            // Wait for the receiver to be ready\n            if self.want_rx.changed().await.is_err() {\n                tracing::trace!(\"All receivers are dead, closing sender\");\n                return;\n            }\n\n            // Check if the receiver is closed\n            if self.inner.is_end_stream() {\n                return;\n            }\n\n            // Get the next frame\n            let frame = match self.inner.frame().await {\n                Some(Ok(frame)) => frame,\n                Some(Err(err)) => {\n                    self.data_tx.send(Err(Arc::new(err))).ok();\n                    continue;\n                },\n                None => return,\n            };\n\n            // Send the frame\n            let clonable_frame = ClonableFrame::from(frame);\n            if self.data_tx.send(Ok(clonable_frame)).is_err() {\n                tracing::trace!(\"All receivers are dead, closing sender\");\n                return;\n            }\n        }\n    }\n}\n\npin_project! {\n    pub struct IncomingReceiver {\n        closed: bool,\n        #[pin]\n        recv_fut: Option<Pin<Box<dyn Future<Output = RecvOutput>>>>,\n        want_tx: watch::Sender<()>,\n        #[pin]\n        data_rx: broadcast::Receiver<Result<ClonableFrame<Bytes>, Arc<hyper::Error>>>,\n    }\n}\n\nimpl Clone for IncomingReceiver {\n    fn clone(&self) -> Self {\n        Self {\n            closed: self.closed,\n            recv_fut: None,\n            want_tx: self.want_tx.clone(),\n            data_rx: self.data_rx.resubscribe(),\n        }\n    }\n}\n\nimpl Body for IncomingReceiver {\n    type Data = Bytes;\n    type Error = Box<dyn StdError + Send + Sync>;\n\n    fn poll_frame(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {\n        let mut this = self.project();\n\n        // We already have a pending frame, poll it\n        if let Some(recv_fut) = this.recv_fut.as_mut().as_pin_mut() {\n            let recv_out = match ready!(recv_fut.poll(cx)) {\n                Ok(Ok(frame)) => Some(Ok(Frame::from(frame))),\n                Ok(Err(err)) => Some(Err(err.into())),\n                Err(broadcast::error::RecvError::Lagged(_)) => {\n                    Some(Err(ERROR_MSG_BROADCAST_LAGGED.into()))\n                },\n                Err(broadcast::error::RecvError::Closed) => {\n                    *this.closed = true;\n                    None\n                },\n            };\n            *this.recv_fut = None;\n            return Poll::Ready(recv_out);\n        }\n\n        // If the receiver is closed, we are done\n        if *this.closed {\n            return Poll::Ready(None);\n        }\n\n        // Check if there are frames available\n        match this.data_rx.try_recv() {\n            Ok(Ok(frame)) => return Poll::Ready(Some(Ok(Frame::from(frame)))),\n            Ok(Err(err)) => return Poll::Ready(Some(Err(err.into()))),\n            Err(broadcast::error::TryRecvError::Lagged(_)) => {\n                return Poll::Ready(Some(Err(ERROR_MSG_BROADCAST_LAGGED.into())));\n            },\n            Err(broadcast::error::TryRecvError::Empty) => (),\n            Err(broadcast::error::TryRecvError::Closed) => {\n                *this.closed = true;\n                return Poll::Ready(None);\n            },\n        }\n\n        // Signal the sender that we are ready to receive\n        if this.want_tx.send(()).is_err() {\n            *this.closed = true;\n            return Poll::Ready(None);\n        }\n\n        // Wait for the next frame\n        let recv_fut = Box::pin(this.data_rx.recv());\n        let recv_fut_static = erase_lifetime(recv_fut);\n        *this.recv_fut = Some(recv_fut_static);\n        Poll::Pending\n    }\n\n    fn is_end_stream(&self) -> bool {\n        self.closed\n    }\n\n    fn size_hint(&self) -> SizeHint {\n        // Since use a broadcast and a reader can miss frames, we can't know the exact size\n        SizeHint::default()\n    }\n}\n\nfn erase_lifetime<'a, T>(\n    fut: Pin<Box<dyn Future<Output = T> + Send + 'a>>,\n) -> Pin<Box<dyn Future<Output = T> + Send + 'static>> {\n    // SAFETY: This is safe since data_rx is pinned\n    unsafe { std::mem::transmute(fut) }\n}\n\n#[cfg(test)]\nmod tests {\n    use std::vec;\n\n    use llrt_test::{test_async_with_opts, TestOptions};\n    use rquickjs::{CatchResultExt, CaughtError, Class, Function, Object, Promise};\n    use wiremock::*;\n\n    use super::*;\n    use crate::*;\n\n    #[tokio::test]\n    async fn test_incoming() {\n        let mock_server = MockServer::start().await;\n        let welcome_message = \"Hello, LLRT!\";\n\n        Mock::given(matchers::path(\"some-path/\"))\n            .respond_with(ResponseTemplate::new(200).set_body_string(welcome_message.to_string()))\n            .mount(&mock_server)\n            .await;\n\n        test_async_with_opts(\n            |ctx| {\n                crate::init(&ctx).unwrap();\n                Box::pin(async move {\n                    let globals = ctx.globals();\n                    let run = async {\n                        let fetch: Function = globals.get(\"fetch\")?;\n\n                        let options = Object::new(ctx.clone())?;\n                        options.set(\"method\", \"GET\")?;\n\n                        let url = format!(\"http://{}/some-path/\", mock_server.address().clone());\n\n                        let response_promise: Promise = fetch.call((url, options.clone()))?;\n                        let response: Class<Response> = response_promise.into_future().await?;\n                        let response = response.borrow_mut();\n                        let response2 = response.clone(ctx.clone()).unwrap();\n\n                        let (response_res, response2_res) =\n                            tokio::join!(response.text(ctx.clone()), response2.text(ctx.clone()));\n                        let response_text = response_res.unwrap();\n                        assert_eq!(response.status(), 200);\n                        assert_eq!(response_text, welcome_message);\n\n                        let response2_text = response2_res.unwrap();\n                        assert_eq!(response2.status(), 200);\n                        assert_eq!(response2_text, welcome_message);\n\n                        Ok(())\n                    };\n                    run.await.catch(&ctx).unwrap();\n                })\n            },\n            TestOptions::new().no_pending_jobs(),\n        )\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_incoming_dropped() {\n        let mock_server = MockServer::start().await;\n        let welcome_message = \"Hello, LLRT!\";\n\n        Mock::given(matchers::path(\"some-path/\"))\n            .respond_with(ResponseTemplate::new(200).set_body_string(welcome_message.to_string()))\n            .mount(&mock_server)\n            .await;\n\n        test_async_with_opts(\n            |ctx| {\n                crate::init(&ctx).unwrap();\n                Box::pin(async move {\n                    let globals = ctx.globals();\n                    let run = async {\n                        let fetch: Function = globals.get(\"fetch\")?;\n\n                        let options = Object::new(ctx.clone())?;\n                        options.set(\"method\", \"GET\")?;\n\n                        let url = format!(\"http://{}/some-path/\", mock_server.address().clone());\n\n                        // The scope ensure we drop all responses\n                        {\n                            let response_promise: Promise = fetch.call((url, options.clone()))?;\n                            let response: Class<Response> = response_promise.into_future().await?;\n                            let response = response.borrow_mut();\n                            let _response2 = response.clone(ctx.clone()).unwrap();\n                        }\n\n                        tokio::task::yield_now().await;\n\n                        Ok(())\n                    };\n                    run.await.catch(&ctx).unwrap();\n                })\n            },\n            TestOptions::new().no_pending_jobs(),\n        )\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_incoming_lagged() {\n        let mock_server = MockServer::start().await;\n        let welcome_message = vec![b'x'; 1024 * 1024 * 50];\n\n        Mock::given(matchers::path(\"some-path/\"))\n            .respond_with(ResponseTemplate::new(200).set_body_bytes(welcome_message.clone()))\n            .mount(&mock_server)\n            .await;\n\n        test_async_with_opts(|ctx| {\n            crate::init(&ctx).unwrap();\n            Box::pin(async move {\n                let globals = ctx.globals();\n                let run = async {\n                    let fetch: Function = globals.get(\"fetch\")?;\n\n                    let options = Object::new(ctx.clone())?;\n                    options.set(\"method\", \"GET\")?;\n\n                    let url = format!(\"http://{}/some-path/\", mock_server.address().clone());\n\n                    let response_promise: Promise = fetch.call((url, options.clone()))?;\n                    let response: Class<Response> = response_promise.into_future().await?;\n                    let response = response.borrow_mut();\n                    let response2 = response.clone(ctx.clone()).unwrap();\n\n                    let response_text = response.text(ctx.clone()).await.unwrap();\n                    assert_eq!(response.status(), 200);\n                    assert_eq!(response_text.as_bytes(), welcome_message);\n\n                    let response2_err = response2.text(ctx.clone()).await.catch(&ctx).unwrap_err();\n                    assert_eq!(response2.status(), 200);\n                    assert!(matches!(response2_err, CaughtError::Exception(e) if e.message().unwrap() == ERROR_MSG_BROADCAST_LAGGED));\n\n                    Ok(())\n                };\n                run.await.catch(&ctx).unwrap();\n            })\n        }, TestOptions::new().no_pending_jobs())\n        .await;\n    }\n}\n"
  },
  {
    "path": "modules/llrt_fetch/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_buffer::Blob;\nuse llrt_http::HTTP_CLIENT;\nuse llrt_utils::{\n    class::CustomInspectExtension,\n    primordials::{BasePrimordials, Primordial},\n    result::ResultExt,\n};\nuse rquickjs::{Class, Ctx, Result};\nuse std::borrow::Cow;\n\npub use self::security::{get_allow_list, get_deny_list, set_allow_list, set_deny_list};\nuse self::{form_data::FormData, headers::Headers, request::Request, response::Response};\n\nmod body;\npub mod fetch;\npub mod form_data;\npub mod headers;\nmod incoming;\npub mod request;\npub mod response;\nmod security;\n\nconst MIME_TYPE_FORM_URLENCODED: &str = \"application/x-www-form-urlencoded;charset=UTF-8\";\nconst MIME_TYPE_TEXT: &str = \"text/plain;charset=UTF-8\";\nconst MIME_TYPE_JSON: &str = \"application/json;charset=UTF-8\";\nconst MIME_TYPE_FORM_DATA: &str = \"multipart/form-data; boundary=\";\nconst MIME_TYPE_OCTET_STREAM: &str = \"application/octet-stream\";\n\npub(crate) fn strip_bom<'a>(bytes: impl Into<Cow<'a, [u8]>>) -> Cow<'a, [u8]> {\n    let cow = bytes.into();\n    if cow.starts_with(&[0xEF, 0xBB, 0xBF]) {\n        match cow {\n            Cow::Borrowed(bytes) => Cow::Borrowed(&bytes[3..]),\n            Cow::Owned(mut bytes) => {\n                bytes.drain(0..3); //memmove instead of copy\n                Cow::Owned(bytes)\n            },\n        }\n    } else {\n        cow\n    }\n}\n\npub fn init(ctx: &Ctx) -> Result<()> {\n    let globals = ctx.globals();\n\n    BasePrimordials::init(ctx)?;\n\n    //init eagerly\n    fetch::init(HTTP_CLIENT.as_ref().or_throw(ctx)?.clone(), &globals)?;\n\n    Class::<FormData>::define(&globals)?;\n\n    Class::<Request>::define(&globals)?;\n    Class::<Response>::define(&globals)?;\n    Class::<Headers>::define_with_custom_inspect(&globals)?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "modules/llrt_fetch/src/request.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::sync::RwLock;\n\nuse llrt_abort::AbortSignal;\nuse llrt_http::Agent;\nuse llrt_json::parse::json_parse;\nuse llrt_url::{url_class::URL, url_search_params::URLSearchParams};\nuse llrt_utils::{bytes::ObjectBytes, object::ObjectExt, result::ResultExt};\nuse rquickjs::{\n    atom::PredefinedAtom, class::Trace, function::Opt, ArrayBuffer, Class, Ctx, Exception, FromJs,\n    IntoJs, Null, Object, Result, TypedArray, Value,\n};\n\nuse super::{\n    headers::{Headers, HeadersGuard, HEADERS_KEY_CONTENT_TYPE},\n    strip_bom, Blob, FormData, MIME_TYPE_FORM_DATA, MIME_TYPE_FORM_URLENCODED,\n    MIME_TYPE_OCTET_STREAM, MIME_TYPE_TEXT,\n};\n\n#[derive(Clone, Default, PartialEq)]\npub enum RequestMode {\n    #[default]\n    Cors,\n    NoCors,\n    SameOrigin,\n    Navigate,\n}\n\nimpl TryFrom<String> for RequestMode {\n    type Error = String;\n\n    fn try_from(s: String) -> std::result::Result<Self, Self::Error> {\n        Ok(match s.to_ascii_lowercase().as_str() {\n            \"cors\" => RequestMode::Cors,\n            \"no-cors\" => RequestMode::NoCors,\n            \"same-origin\" => RequestMode::SameOrigin,\n            \"navigate\" => RequestMode::Navigate,\n            _ => return Err([\"Invalid requrest mode: \", s.as_str()].concat()),\n        })\n    }\n}\n\nimpl RequestMode {\n    pub fn as_str(&self) -> &str {\n        match self {\n            Self::Cors => \"cors\",\n            Self::NoCors => \"no-cors\",\n            Self::SameOrigin => \"same-origin\",\n            Self::Navigate => \"navigate\",\n        }\n    }\n}\n\n#[allow(dead_code)]\n#[derive(rquickjs::JsLifetime)]\nenum BodyVariant<'js> {\n    Provided(Option<Value<'js>>),\n    Empty,\n}\n\n#[rquickjs::class]\n#[derive(rquickjs::JsLifetime)]\npub struct Request<'js> {\n    url: String,\n    method: String,\n    headers: Option<Class<'js, Headers>>,\n    body: RwLock<BodyVariant<'js>>,\n    signal: Option<Class<'js, AbortSignal<'js>>>,\n    mode: RequestMode,\n    keepalive: bool,\n    agent: Option<Class<'js, Agent>>,\n}\n\nimpl<'js> Trace<'js> for Request<'js> {\n    fn trace<'a>(&self, tracer: rquickjs::class::Tracer<'a, 'js>) {\n        if let Some(headers) = &self.headers {\n            headers.trace(tracer);\n        }\n        let body = self.body.read().unwrap();\n        let body = &*body;\n        if let BodyVariant::Provided(Some(body)) = body {\n            body.trace(tracer);\n        }\n    }\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl<'js> Request<'js> {\n    #[qjs(constructor)]\n    pub fn new(ctx: Ctx<'js>, input: Value<'js>, options: Opt<Value<'js>>) -> Result<Self> {\n        let mut request = Self {\n            url: \"\".into(),\n            method: \"GET\".into(),\n            headers: None,\n            body: RwLock::new(BodyVariant::Empty),\n            signal: None,\n            mode: RequestMode::Cors,\n            keepalive: false,\n            agent: None,\n        };\n\n        if input.is_string() {\n            request.url = input.get()?;\n        } else if let Ok(url) = URL::from_js(&ctx, input.clone()) {\n            request.url = url.to_string();\n        } else if input.is_object() {\n            assign_request(&mut request, ctx.clone(), unsafe {\n                input.as_object().unwrap_unchecked()\n            })?;\n        }\n        if let Some(options) = options.0 {\n            if let Some(obj) = options.as_object() {\n                assign_request(&mut request, ctx.clone(), obj)?;\n            }\n        }\n        if request.headers.is_none() {\n            let headers = Class::instance(ctx, Headers::default())?;\n            request.headers = Some(headers);\n        }\n\n        Ok(request)\n    }\n\n    #[qjs(get)]\n    fn url(&self) -> String {\n        self.url.clone()\n    }\n\n    #[qjs(get)]\n    fn method(&self) -> String {\n        self.method.clone()\n    }\n\n    #[qjs(get)]\n    fn headers(&self) -> Option<Class<'js, Headers>> {\n        self.headers.clone()\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    pub fn to_string_tag(&self) -> &'static str {\n        stringify!(Request)\n    }\n\n    //TODO should implement readable stream\n    #[qjs(get)]\n    fn body(&self, ctx: Ctx<'js>) -> Result<Value<'js>> {\n        let body = self.body.read().unwrap();\n        let body = &*body;\n        match body {\n            BodyVariant::Provided(value) => value.into_js(&ctx),\n            BodyVariant::Empty => Null.into_js(&ctx),\n        }\n    }\n\n    #[qjs(get)]\n    fn keepalive(&self) -> bool {\n        self.keepalive\n    }\n\n    #[qjs(get)]\n    fn signal(&self) -> Option<Class<'js, AbortSignal<'js>>> {\n        self.signal.clone()\n    }\n\n    #[qjs(get)]\n    fn body_used(&self) -> bool {\n        let body = self.body.read().unwrap();\n        let body = &*body;\n        match body {\n            BodyVariant::Provided(value) => value.is_none(),\n            BodyVariant::Empty => false,\n        }\n    }\n\n    #[qjs(get)]\n    fn mode(&self) -> &str {\n        self.mode.as_str()\n    }\n\n    #[qjs(get)]\n    fn cache(&self) -> &'static str {\n        \"no-store\"\n    }\n\n    #[qjs(get)]\n    fn agent(&self) -> Option<Class<'js, Agent>> {\n        self.agent.clone()\n    }\n\n    pub async fn text(&mut self, ctx: Ctx<'js>) -> Result<String> {\n        if let Some(bytes) = self.take_bytes(&ctx).await? {\n            return Ok(String::from_utf8_lossy(&strip_bom(bytes)).to_string());\n        }\n        Ok(\"\".into())\n    }\n\n    pub async fn json(&mut self, ctx: Ctx<'js>) -> Result<Value<'js>> {\n        if let Some(bytes) = self.take_bytes(&ctx).await? {\n            return json_parse(&ctx, strip_bom(bytes));\n        }\n        Err(Exception::throw_syntax(&ctx, \"JSON input is empty\"))\n    }\n\n    async fn array_buffer(&mut self, ctx: Ctx<'js>) -> Result<ArrayBuffer<'js>> {\n        if let Some(bytes) = self.take_bytes(&ctx).await? {\n            return ArrayBuffer::new(ctx, bytes);\n        }\n        ArrayBuffer::new(ctx, Vec::<u8>::new())\n    }\n\n    async fn bytes(&mut self, ctx: Ctx<'js>) -> Result<Value<'js>> {\n        if let Some(bytes) = self.take_bytes(&ctx).await? {\n            return TypedArray::new(ctx, bytes).map(|m| m.into_value());\n        }\n        TypedArray::new(ctx, Vec::<u8>::new()).map(|m| m.into_value())\n    }\n\n    async fn blob(&mut self, ctx: Ctx<'js>) -> Result<Blob> {\n        let mime_type = self.get_header_value(&ctx, HEADERS_KEY_CONTENT_TYPE)?;\n\n        if let Some(bytes) = self.take_bytes(&ctx).await? {\n            return Ok(Blob::from_bytes(bytes, mime_type));\n        }\n        Ok(Blob::from_bytes(Vec::<u8>::new(), mime_type))\n    }\n\n    async fn form_data(&self, ctx: Ctx<'js>) -> Result<FormData> {\n        let mime_type = self\n            .get_header_value(&ctx, HEADERS_KEY_CONTENT_TYPE)?\n            .unwrap_or(MIME_TYPE_OCTET_STREAM.into());\n\n        if let Some(bytes) = self.take_bytes(&ctx).await? {\n            let form_data = FormData::from_multipart_bytes(&ctx, &mime_type, bytes)?;\n            return Ok(form_data);\n        }\n        Ok(FormData::default())\n    }\n\n    fn clone(&mut self, ctx: Ctx<'js>) -> Result<Self> {\n        let headers = if let Some(headers) = &self.headers {\n            Some(Class::<Headers>::instance(\n                ctx.clone(),\n                headers.borrow().clone(),\n            )?)\n        } else {\n            None\n        };\n\n        //not async so should not block\n        let body = self.body.read().unwrap();\n        let body = &*body;\n        let body = match body {\n            BodyVariant::Provided(provided) => BodyVariant::Provided(provided.clone()),\n            BodyVariant::Empty => BodyVariant::Empty,\n        };\n\n        Ok(Self {\n            url: self.url.clone(),\n            method: self.url.clone(),\n            headers,\n            body: RwLock::new(body),\n            signal: self.signal.clone(),\n            mode: self.mode.clone(),\n            keepalive: self.keepalive,\n            agent: self.agent.clone(),\n        })\n    }\n}\n\nimpl<'js> Request<'js> {\n    #[allow(clippy::await_holding_lock)] //clippy complains about guard being held across await points but we drop the guard before awaiting\n    #[allow(clippy::readonly_write_lock)] //clippy complains about lock being read only but we mutate the value\n    async fn take_bytes(&self, ctx: &Ctx<'js>) -> Result<Option<Vec<u8>>> {\n        let mut body_guard = self.body.write().unwrap();\n        let body = &mut *body_guard;\n        let bytes = match body {\n            BodyVariant::Provided(provided) => {\n                let provided = provided\n                    .take()\n                    .ok_or(Exception::throw_message(ctx, \"Already read\"))?;\n                drop(body_guard);\n                if let Some(blob) = provided.as_object().and_then(Class::<Blob>::from_object) {\n                    let blob = blob.borrow();\n                    blob.get_bytes()\n                } else {\n                    let bytes = ObjectBytes::from(ctx, &provided)?;\n                    bytes.as_bytes(ctx)?.to_vec()\n                }\n            },\n            BodyVariant::Empty => return Ok(None),\n        };\n\n        Ok(Some(bytes))\n    }\n\n    fn get_headers(&self, ctx: &Ctx<'js>) -> Result<Option<Headers>> {\n        self.headers()\n            .map(|headers| Headers::from_js(ctx, headers.into_value()))\n            .transpose()\n            .or_throw(ctx)\n    }\n\n    fn get_header_value(&self, ctx: &Ctx<'js>, key: &str) -> Result<Option<String>> {\n        Ok(self.get_headers(ctx)?.and_then(|headers| {\n            headers\n                .iter()\n                .find_map(|(k, v)| (k == key).then(|| v.to_string()))\n        }))\n    }\n}\n\nfn assign_request<'js>(request: &mut Request<'js>, ctx: Ctx<'js>, obj: &Object<'js>) -> Result<()> {\n    if let Some(url) = obj.get_optional(\"url\")? {\n        request.url = url;\n    }\n    if let Some(method) = obj.get_optional::<_, String>(\"method\")? {\n        let method = method.to_ascii_uppercase();\n        if let \"CONNECT\" | \"TRACE\" | \"TRACK\" = method.as_str() {\n            return Err(Exception::throw_type(&ctx, \"This method is not allowed.\"));\n        }\n        request.method = method;\n    }\n    if let Some(mode) = obj.get_optional::<_, String>(\"mode\")? {\n        request.mode = mode.try_into().or_throw(&ctx)?;\n    }\n    if let Some(keepalive) = obj.get_optional::<_, Value>(\"keepalive\")? {\n        request.keepalive = if let Some(b) = keepalive.as_bool() {\n            b\n        } else if let Some(n) = keepalive.as_number() {\n            n != 0.0\n        } else {\n            false\n        }\n    }\n\n    if let Some(signal) = obj.get_optional::<_, Value>(\"signal\")? {\n        if !signal.is_undefined() && !signal.is_null() {\n            let signal = AbortSignal::from_js(&ctx, signal).map_err(|_| {\n                Exception::throw_type(\n                    &ctx,\n                    \"Failed to construct 'Request': 'signal' property is not an AbortSignal\",\n                )\n            })?;\n            request.signal = Some(Class::instance(ctx.clone(), signal)?);\n        }\n    }\n\n    let mut content_type: Option<String> = None;\n\n    if let Some(body) = obj.get_optional::<_, Value>(\"body\")? {\n        if !body.is_undefined() && !body.is_null() {\n            if let \"GET\" | \"HEAD\" = request.method.as_str() {\n                return Err(Exception::throw_type(\n                    &ctx,\n                    \"Failed to construct 'Request': Request with GET/HEAD method cannot have body.\",\n                ));\n            }\n\n            let body = if body.is_string() {\n                content_type = Some(MIME_TYPE_TEXT.into());\n                BodyVariant::Provided(Some(body))\n            } else if let Some(obj) = body.as_object() {\n                if let Some(blob) = Class::<Blob>::from_object(obj) {\n                    let blob = blob.borrow();\n                    if !blob.mime_type().is_empty() {\n                        content_type = Some(blob.mime_type());\n                    }\n                    BodyVariant::Provided(Some(body))\n                } else if let Some(fd) = Class::<FormData>::from_object(obj) {\n                    let fd = fd.borrow();\n                    let (multipart_body, boundary) = fd.to_multipart_bytes(&ctx)?;\n                    content_type = Some([MIME_TYPE_FORM_DATA, &boundary].concat());\n                    BodyVariant::Provided(Some(multipart_body.into_js(&ctx)?))\n                } else if obj.instance_of::<URLSearchParams>() {\n                    content_type = Some(MIME_TYPE_FORM_URLENCODED.into());\n                    BodyVariant::Provided(Some(body))\n                } else {\n                    BodyVariant::Provided(Some(body))\n                }\n            } else {\n                BodyVariant::Provided(Some(body))\n            };\n            request.body = RwLock::new(body);\n        }\n    }\n\n    let headers = {\n        let guard = if request.mode == RequestMode::NoCors {\n            HeadersGuard::RequestNoCors\n        } else {\n            HeadersGuard::Request\n        };\n        let mut headers = Headers::from_value(\n            &ctx,\n            obj.get_optional(\"headers\")?\n                .unwrap_or_else(|| Null.into_js(&ctx).unwrap()),\n            guard,\n        )?;\n        if !headers.has(ctx.clone(), HEADERS_KEY_CONTENT_TYPE.into())? {\n            if let Some(value) = content_type {\n                headers.set(\n                    ctx.clone(),\n                    HEADERS_KEY_CONTENT_TYPE.into(),\n                    value.into_js(&ctx)?,\n                )?;\n            }\n        }\n        Class::instance(ctx, headers)?\n    };\n    request.headers = Some(headers);\n\n    if let Some(agent_opt) = obj.get_optional(\"agent\")? {\n        request.agent = Some(agent_opt);\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "modules/llrt_fetch/src/response.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{\n    collections::{BTreeMap, HashMap},\n    io::Read,\n    sync::RwLock,\n    time::Instant,\n};\n\nuse either::Either;\nuse http_body_util::BodyExt;\nuse hyper::{\n    body::{Body, Incoming},\n    header::HeaderName,\n};\nuse llrt_abort::AbortSignal;\nuse llrt_context::CtxExtension;\nuse llrt_json::{parse::json_parse, stringify::json_stringify};\nuse llrt_url::{url_class::URL, url_search_params::URLSearchParams};\nuse llrt_utils::bytes::ObjectBytes;\nuse llrt_utils::{mc_oneshot, result::ResultExt};\nuse once_cell::sync::Lazy;\nuse rquickjs::{\n    atom::PredefinedAtom,\n    class::{Trace, Tracer},\n    function::Opt,\n    ArrayBuffer, Class, Coerced, Ctx, Exception, IntoJs, JsLifetime, Object, Result, TypedArray,\n    Undefined, Value,\n};\nuse tokio::select;\n\nuse super::{\n    headers::{Headers, HeadersGuard, HEADERS_KEY_CONTENT_TYPE},\n    incoming::{self, IncomingReceiver},\n    strip_bom, Blob, FormData, MIME_TYPE_FORM_DATA, MIME_TYPE_FORM_URLENCODED, MIME_TYPE_JSON,\n    MIME_TYPE_OCTET_STREAM, MIME_TYPE_TEXT,\n};\n\nstatic STATUS_TEXTS: Lazy<HashMap<u16, &'static str>> = Lazy::new(|| {\n    let mut map = HashMap::new();\n    map.insert(100, \"Continue\");\n    map.insert(101, \"Switching Protocols\");\n    map.insert(102, \"Processing\");\n    map.insert(103, \"Early Hints\");\n    map.insert(200, \"OK\");\n    map.insert(201, \"Created\");\n    map.insert(202, \"Accepted\");\n    map.insert(203, \"Non-Authoritative Information\");\n    map.insert(204, \"No Content\");\n    map.insert(205, \"Reset Content\");\n    map.insert(206, \"Partial Content\");\n    map.insert(207, \"Multi-Status\");\n    map.insert(208, \"Already Reported\");\n    map.insert(226, \"IM Used\");\n    map.insert(300, \"Multiple Choices\");\n    map.insert(301, \"Moved Permanently\");\n    map.insert(302, \"Found\");\n    map.insert(303, \"See Other\");\n    map.insert(304, \"Not Modified\");\n    map.insert(305, \"Use Proxy\");\n    map.insert(307, \"Temporary Redirect\");\n    map.insert(308, \"Permanent Redirect\");\n    map.insert(400, \"Bad Request\");\n    map.insert(401, \"Unauthorized\");\n    map.insert(402, \"Payment Required\");\n    map.insert(403, \"Forbidden\");\n    map.insert(404, \"Not Found\");\n    map.insert(405, \"Method Not Allowed\");\n    map.insert(406, \"Not Acceptable\");\n    map.insert(407, \"Proxy Authentication Required\");\n    map.insert(408, \"Request Timeout\");\n    map.insert(409, \"Conflict\");\n    map.insert(410, \"Gone\");\n    map.insert(411, \"Length Required\");\n    map.insert(412, \"Precondition Failed\");\n    map.insert(413, \"Payload Too Large\");\n    map.insert(414, \"URI Too Long\");\n    map.insert(415, \"Unsupported Media Type\");\n    map.insert(416, \"Range Not Satisfiable\");\n    map.insert(417, \"Expectation Failed\");\n    map.insert(418, \"I'm a teapot\");\n    map.insert(421, \"Misdirected Request\");\n    map.insert(422, \"Unprocessable Content\");\n    map.insert(423, \"Locked\");\n    map.insert(424, \"Failed Dependency\");\n    map.insert(425, \"Too Early\");\n    map.insert(426, \"Upgrade Required\");\n    map.insert(428, \"Precondition Required\");\n    map.insert(429, \"Too Many Requests\");\n    map.insert(431, \"Request Header Fields Too Large\");\n    map.insert(451, \"Unavailable For Legal Reasons\");\n    map.insert(500, \"Internal Server Error\");\n    map.insert(501, \"Not Implemented\");\n    map.insert(502, \"Bad Gateway\");\n    map.insert(503, \"Service Unavailable\");\n    map.insert(504, \"Gateway Timeout\");\n    map.insert(505, \"HTTP Version Not Supported\");\n    map.insert(506, \"Variant Also Negotiates\");\n    map.insert(507, \"Insufficient Storage\");\n    map.insert(508, \"Loop Detected\");\n    map.insert(510, \"Not Extended\");\n    map.insert(511, \"Network Authentication Required\");\n\n    map\n});\n\nenum BodyVariant<'js> {\n    Incoming(Option<hyper::Response<Incoming>>),\n    Cloned(Option<hyper::Response<IncomingReceiver>>),\n    Provided(Option<Value<'js>>),\n    Empty,\n}\n\n#[rquickjs::class]\npub struct Response<'js> {\n    body: RwLock<BodyVariant<'js>>,\n    content_encoding: Option<String>,\n    method: String,\n    url: String,\n    start: Instant,\n    status: u16,\n    status_text: Option<String>,\n    redirected: bool,\n    headers: Class<'js, Headers>,\n    abort_receiver: Option<mc_oneshot::Receiver<Value<'js>>>,\n}\n\nimpl<'js> Trace<'js> for Response<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.headers.trace(tracer);\n        let body = self.body.read().unwrap();\n        let body = &*body;\n        if let BodyVariant::Provided(Some(body)) = body {\n            body.trace(tracer);\n        }\n    }\n}\n\nunsafe impl<'js> JsLifetime<'js> for Response<'js> {\n    type Changed<'to> = Response<'to>;\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl<'js> Response<'js> {\n    #[qjs(constructor)]\n    pub fn new(ctx: Ctx<'js>, body: Opt<Value<'js>>, options: Opt<Object<'js>>) -> Result<Self> {\n        let mut url = \"\".into();\n        let mut status = 200;\n        let mut headers = None;\n        let mut status_text = None;\n        let mut abort_receiver = None;\n\n        if let Some(opt) = options.0 {\n            if let Some(url_opt) = opt.get(\"url\")? {\n                url = url_opt;\n            }\n            if let Some(status_opt) = opt.get(\"status\")? {\n                status = status_opt;\n            }\n            if let Some(headers_opt) = opt.get(\"headers\")? {\n                headers = Some(Headers::from_value(\n                    &ctx,\n                    headers_opt,\n                    HeadersGuard::Response,\n                )?);\n            }\n            if let Some(status_text_opt) = opt.get(\"statusText\")? {\n                status_text = Some(status_text_opt);\n            }\n\n            if let Some(signal) = opt.get::<_, Option<Class<AbortSignal>>>(\"signal\")? {\n                abort_receiver = Some(signal.borrow().sender.subscribe())\n            }\n        }\n\n        let mut content_type: Option<String> = None;\n\n        let body = body\n            .0\n            .and_then(|body| {\n                if body.is_null() || body.is_undefined() {\n                    None\n                } else if body.is_string() {\n                    content_type = Some(MIME_TYPE_TEXT.into());\n                    Some(BodyVariant::Provided(Some(body)))\n                } else if let Some(obj) = body.as_object() {\n                    if let Some(blob) = Class::<Blob>::from_object(obj) {\n                        let blob = blob.borrow();\n                        if !blob.mime_type().is_empty() {\n                            content_type = Some(blob.mime_type());\n                        }\n                        Some(BodyVariant::Provided(Some(body)))\n                    } else if let Some(fd) = Class::<FormData>::from_object(obj) {\n                        let fd = fd.borrow();\n                        let (multipart_body, boundary) = fd.to_multipart_bytes(&ctx).ok()?;\n                        content_type = Some([MIME_TYPE_FORM_DATA, &boundary].concat());\n                        Some(BodyVariant::Provided(Some(\n                            multipart_body.into_js(&ctx).ok()?,\n                        )))\n                    } else if obj.instance_of::<URLSearchParams>() {\n                        content_type = Some(MIME_TYPE_FORM_URLENCODED.into());\n                        Some(BodyVariant::Provided(Some(body)))\n                    } else {\n                        Some(BodyVariant::Provided(Some(body)))\n                    }\n                } else {\n                    Some(BodyVariant::Provided(Some(body)))\n                }\n            })\n            .unwrap_or_else(|| BodyVariant::Empty);\n\n        let mut headers = headers.unwrap_or_default();\n        if !headers.has(ctx.clone(), HEADERS_KEY_CONTENT_TYPE.into())? {\n            if let Some(value) = content_type {\n                headers.set(\n                    ctx.clone(),\n                    HEADERS_KEY_CONTENT_TYPE.into(),\n                    value.into_js(&ctx)?,\n                )?;\n            }\n        }\n        let headers = Class::instance(ctx.clone(), headers)?;\n\n        let content_encoding = headers.get(\"content-encoding\")?;\n\n        Ok(Self {\n            body: RwLock::new(body),\n            method: \"GET\".into(),\n            url,\n            start: Instant::now(),\n            status,\n            status_text,\n            redirected: false,\n            headers,\n            content_encoding,\n            abort_receiver,\n        })\n    }\n\n    #[qjs(get)]\n    pub fn status(&self) -> u64 {\n        self.status.into()\n    }\n\n    #[qjs(get)]\n    pub fn url(&self) -> String {\n        self.url.clone()\n    }\n\n    #[qjs(get)]\n    pub fn ok(&self) -> bool {\n        self.status > 199 && self.status < 300\n    }\n\n    #[qjs(get)]\n    pub fn redirected(&self) -> bool {\n        self.redirected\n    }\n\n    //FIXME return readable stream when implemented\n    #[qjs(get)]\n    pub fn body(&self) -> Undefined {\n        Undefined\n    }\n\n    #[qjs(get)]\n    fn headers(&self) -> Class<'js, Headers> {\n        self.headers.clone()\n    }\n\n    #[qjs(get, rename = \"type\")]\n    fn response_type(&self) -> &'js str {\n        match &self.status {\n            0 => \"error\",\n            _ => \"basic\",\n        }\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    pub fn to_string_tag(&self) -> &'static str {\n        stringify!(Response)\n    }\n\n    #[qjs(get)]\n    fn status_text(&self) -> String {\n        if let Some(text) = &self.status_text {\n            return text.to_string();\n        }\n        STATUS_TEXTS.get(&self.status).unwrap_or(&\"\").to_string()\n    }\n\n    #[qjs(get)]\n    fn body_used(&self) -> bool {\n        let body = self.body.read().unwrap();\n        let body = &*body;\n        match body {\n            BodyVariant::Incoming(response) => response.is_none(),\n            BodyVariant::Cloned(response) => response.is_none(),\n            BodyVariant::Provided(value) => value.is_none(),\n            BodyVariant::Empty => false,\n        }\n    }\n\n    pub(crate) async fn text(&self, ctx: Ctx<'js>) -> Result<String> {\n        if let Some(bytes) = self.take_bytes(&ctx).await? {\n            return Ok(String::from_utf8_lossy(&strip_bom(bytes)).to_string());\n        }\n        Ok(\"\".into())\n    }\n\n    pub(crate) async fn json(&self, ctx: Ctx<'js>) -> Result<Value<'js>> {\n        if let Some(bytes) = self.take_bytes(&ctx).await? {\n            return json_parse(&ctx, strip_bom(bytes));\n        }\n        Err(Exception::throw_syntax(&ctx, \"JSON input is empty\"))\n    }\n\n    async fn array_buffer(&self, ctx: Ctx<'js>) -> Result<ArrayBuffer<'js>> {\n        if let Some(bytes) = self.take_bytes(&ctx).await? {\n            return ArrayBuffer::new(ctx, bytes);\n        }\n        ArrayBuffer::new(ctx, Vec::<u8>::new())\n    }\n\n    async fn bytes(&self, ctx: Ctx<'js>) -> Result<Value<'js>> {\n        if let Some(bytes) = self.take_bytes(&ctx).await? {\n            return TypedArray::new(ctx, bytes).map(|m| m.into_value());\n        }\n        TypedArray::new(ctx, Vec::<u8>::new()).map(|m| m.into_value())\n    }\n\n    async fn blob(&self, ctx: Ctx<'js>) -> Result<Blob> {\n        let mime_type = self.get_header_value(&ctx, HEADERS_KEY_CONTENT_TYPE)?;\n\n        if let Some(bytes) = self.take_bytes(&ctx).await? {\n            return Ok(Blob::from_bytes(bytes, mime_type));\n        }\n        Ok(Blob::from_bytes(Vec::<u8>::new(), mime_type))\n    }\n\n    async fn form_data(&self, ctx: Ctx<'js>) -> Result<FormData> {\n        let mime_type = self\n            .get_header_value(&ctx, HEADERS_KEY_CONTENT_TYPE)?\n            .unwrap_or(MIME_TYPE_OCTET_STREAM.into());\n\n        if let Some(bytes) = self.take_bytes(&ctx).await? {\n            let form_data = FormData::from_multipart_bytes(&ctx, &mime_type, bytes)?;\n            return Ok(form_data);\n        }\n        Ok(FormData::default())\n    }\n\n    pub(crate) fn clone(&self, ctx: Ctx<'js>) -> Result<Self> {\n        //not async so should not block\n        let mut body = self.body.write().unwrap();\n        let body_mutex = &mut *body;\n        let body = match body_mutex {\n            BodyVariant::Incoming(incoming) => {\n                if let Some(response) = incoming.take() {\n                    let (head, incoming_response) = response.into_parts();\n                    let (sender, receiver) = incoming::channel(incoming_response);\n                    let response = hyper::Response::from_parts(head, receiver);\n\n                    *body_mutex = BodyVariant::Cloned(Some(response.clone()));\n\n                    ctx.spawn_exit_simple(async move {\n                        sender.process().await;\n                        Ok(())\n                    });\n                    BodyVariant::Cloned(Some(response))\n                } else {\n                    BodyVariant::Incoming(None)\n                }\n            },\n            BodyVariant::Cloned(incoming) => BodyVariant::Cloned(incoming.clone()),\n            BodyVariant::Provided(provided) => BodyVariant::Provided(provided.clone()),\n            BodyVariant::Empty => BodyVariant::Empty,\n        };\n\n        Ok(Self {\n            body: RwLock::new(body),\n            method: self.method.clone(),\n            url: self.url.clone(),\n            start: self.start,\n            status: self.status,\n            status_text: self.status_text.clone(),\n            redirected: self.redirected,\n            headers: Class::<Headers>::instance(ctx, self.headers.borrow().clone())?,\n            content_encoding: self.content_encoding.clone(),\n            abort_receiver: self.abort_receiver.clone(),\n        })\n    }\n\n    #[qjs(static)]\n    fn error(ctx: Ctx<'js>) -> Result<Self> {\n        Ok(Self {\n            body: RwLock::new(BodyVariant::Empty),\n            method: \"\".into(),\n            url: \"\".into(),\n            start: Instant::now(),\n            status: 0,\n            status_text: None,\n            redirected: false,\n            headers: Class::instance(ctx.clone(), Headers::default())?,\n            content_encoding: None,\n            abort_receiver: None,\n        })\n    }\n\n    #[qjs(static, rename = \"json\")]\n    fn json_static(ctx: Ctx<'js>, body: Value<'js>, options: Opt<Object<'js>>) -> Result<Self> {\n        let mut status = 200;\n        let mut status_text = None;\n\n        if let Some(ref opt) = options.0 {\n            if let Some(status_opt) = opt.get(\"status\")? {\n                status = status_opt;\n            }\n            if let Some(status_text_opt) = opt.get(\"statusText\")? {\n                status_text = Some(status_text_opt);\n            }\n        }\n\n        let mut headers = if let Some(ref opt) = options.0 {\n            let head = if let Some(headers_opt) = opt.get(\"headers\")? {\n                headers_opt\n            } else {\n                Value::new_null(ctx.clone())\n            };\n            Headers::from_value(&ctx, head, HeadersGuard::Response)?\n        } else {\n            Headers::from_value(&ctx, Value::new_null(ctx.clone()), HeadersGuard::Response)?\n        };\n\n        if !headers.has(ctx.clone(), \"content-type\".into())? {\n            headers.append(\n                ctx.clone(),\n                \"content-type\".into(),\n                MIME_TYPE_JSON.into_js(&ctx)?,\n            )?;\n        }\n\n        let headers = Class::instance(ctx.clone(), headers)?;\n        let content_encoding = headers.get(\"content-encoding\")?;\n\n        let body = if let Ok(Some(v)) = json_stringify(&ctx, body) {\n            BodyVariant::Provided(Some(v.into_js(&ctx)?))\n        } else {\n            return Err(Exception::throw_type(&ctx, \"Failed to convert JSON string\"));\n        };\n\n        Ok(Self {\n            body: RwLock::new(body),\n            method: \"\".into(),\n            url: \"\".into(),\n            start: Instant::now(),\n            status,\n            status_text,\n            redirected: false,\n            headers,\n            content_encoding,\n            abort_receiver: None,\n        })\n    }\n\n    #[qjs(static)]\n    fn redirect(\n        ctx: Ctx<'js>,\n        url: Either<URL<'js>, Coerced<String>>,\n        status: Opt<u16>,\n    ) -> Result<Self> {\n        let status = status.0.unwrap_or(302_u16);\n        let url = match url {\n            Either::Left(url) => url.to_string(),\n            Either::Right(url) => url.0,\n        };\n\n        let mut header = BTreeMap::new();\n        header.insert(\"location\".to_string(), Coerced(url));\n        let headers = Headers::from_map(&ctx, header, HeadersGuard::Response);\n        let headers = Class::instance(ctx.clone(), headers)?;\n\n        Ok(Self {\n            body: RwLock::new(BodyVariant::Empty),\n            method: \"\".into(),\n            url: \"\".into(),\n            start: Instant::now(),\n            status,\n            status_text: None,\n            redirected: false,\n            headers,\n            content_encoding: None,\n            abort_receiver: None,\n        })\n    }\n}\n\n#[allow(clippy::too_many_arguments)]\nimpl<'js> Response<'js> {\n    pub fn from_incoming(\n        ctx: Ctx<'js>,\n        response: hyper::Response<Incoming>,\n        method: String,\n        url: String,\n        start: Instant,\n        redirected: bool,\n        abort_receiver: Option<mc_oneshot::Receiver<Value<'js>>>,\n        guard: HeadersGuard,\n    ) -> Result<Self> {\n        let response_headers = response.headers();\n\n        let mut content_encoding = None;\n        if let Some(content_encoding_header) =\n            response_headers.get(HeaderName::from_static(\"content-encoding\"))\n        {\n            if let Ok(content_encoding_header) = content_encoding_header.to_str() {\n                content_encoding = Some(content_encoding_header.to_owned())\n            }\n        }\n\n        let headers = Headers::from_http_headers(response.headers(), guard)?;\n        let headers = Class::instance(ctx.clone(), headers)?;\n\n        let status = response.status();\n\n        Ok(Self {\n            body: RwLock::new(BodyVariant::Incoming(Some(response))),\n            content_encoding,\n            method,\n            url,\n            start,\n            status: status.as_u16(),\n            status_text: None,\n            redirected,\n            headers,\n            abort_receiver,\n        })\n    }\n\n    #[allow(clippy::await_holding_lock)] //clippy complains about guard being held across await points but we drop the guard before awaiting\n    #[allow(clippy::readonly_write_lock)] //clippy complains about lock being read only but we mutate the value\n    async fn take_bytes(&self, ctx: &Ctx<'js>) -> Result<Option<Vec<u8>>> {\n        let mut body_guard = self.body.write().unwrap();\n        let body = &mut *body_guard;\n        let bytes = match body {\n            BodyVariant::Incoming(ref mut incoming) => {\n                let response = incoming\n                    .take()\n                    .ok_or(Exception::throw_message(ctx, \"Already read\"))?;\n                drop(body_guard);\n\n                self.take_bytes_body(ctx, response.into_body()).await?\n            },\n            BodyVariant::Cloned(ref mut incoming) => {\n                let response = incoming\n                    .take()\n                    .ok_or(Exception::throw_message(ctx, \"Already read\"))?;\n                drop(body_guard);\n\n                self.take_bytes_body(ctx, response.into_body()).await?\n            },\n            BodyVariant::Provided(provided) => {\n                let provided = provided\n                    .take()\n                    .ok_or(Exception::throw_message(ctx, \"Already read\"))?;\n                drop(body_guard);\n                if let Some(blob) = provided.as_object().and_then(Class::<Blob>::from_object) {\n                    let blob = blob.borrow();\n                    blob.get_bytes()\n                } else {\n                    let bytes = ObjectBytes::from(ctx, &provided)?;\n                    bytes.as_bytes(ctx)?.to_vec()\n                }\n            },\n            BodyVariant::Empty => return Ok(None),\n        };\n\n        Ok(Some(bytes))\n    }\n\n    async fn take_bytes_body<T>(&self, ctx: &Ctx<'js>, body: T) -> Result<Vec<u8>>\n    where\n        T: Body,\n        T::Error: std::fmt::Display,\n    {\n        let bytes = if let Some(abort_signal) = self.abort_receiver.as_ref() {\n            select! {\n                err = abort_signal.recv() => return Err(ctx.throw(err)),\n                collected_body = body.collect() => collected_body.or_throw(ctx)?.to_bytes()\n            }\n        } else {\n            body.collect().await.or_throw(ctx)?.to_bytes()\n        };\n\n        if let Some(content_encoding) = self.content_encoding.as_deref() {\n            let mut data: Vec<u8> = Vec::with_capacity(bytes.len());\n            match content_encoding {\n                \"zstd\" => llrt_compression::zstd::decoder(&bytes[..])?.read_to_end(&mut data)?,\n                \"br\" => llrt_compression::brotli::decoder(&bytes[..]).read_to_end(&mut data)?,\n                \"gzip\" => llrt_compression::gz::decoder(&bytes[..]).read_to_end(&mut data)?,\n                \"deflate\" => llrt_compression::zlib::decoder(&bytes[..]).read_to_end(&mut data)?,\n                _ => return Err(Exception::throw_message(ctx, \"Unsupported encoding\")),\n            };\n            Ok(data)\n        } else {\n            Ok(bytes.to_vec())\n        }\n    }\n\n    fn get_headers(&self, ctx: &Ctx<'js>) -> Result<Headers> {\n        Headers::from_value(ctx, self.headers().as_value().clone(), HeadersGuard::None)\n    }\n\n    fn get_header_value(&self, ctx: &Ctx<'js>, key: &str) -> Result<Option<String>> {\n        Ok(self\n            .get_headers(ctx)?\n            .iter()\n            .find_map(|(k, v)| (k == key).then(|| v.to_string())))\n    }\n}\n"
  },
  {
    "path": "modules/llrt_fetch/src/security.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse hyper::Uri;\nuse rquickjs::{Ctx, Error, Exception, Result};\nuse std::sync::OnceLock;\n\nstatic HTTP_ALLOW_LIST: OnceLock<Vec<Uri>> = OnceLock::new();\n\nstatic HTTP_DENY_LIST: OnceLock<Vec<Uri>> = OnceLock::new();\n\npub fn set_allow_list(values: Vec<Uri>) {\n    _ = HTTP_ALLOW_LIST.set(values);\n}\n\npub fn get_allow_list() -> Option<&'static Vec<Uri>> {\n    HTTP_ALLOW_LIST.get()\n}\n\npub fn set_deny_list(values: Vec<Uri>) {\n    _ = HTTP_DENY_LIST.set(values);\n}\n\npub fn get_deny_list() -> Option<&'static Vec<Uri>> {\n    HTTP_DENY_LIST.get()\n}\n\npub fn ensure_url_access(ctx: &Ctx<'_>, uri: &Uri) -> Result<()> {\n    if let Some(allow_list) = HTTP_ALLOW_LIST.get() {\n        if !url_match(allow_list, uri) {\n            return Err(url_restricted_error(ctx, \"URL not allowed\", uri));\n        }\n    }\n\n    if let Some(deny_list) = HTTP_DENY_LIST.get() {\n        if url_match(deny_list, uri) {\n            return Err(url_restricted_error(ctx, \"URL denied\", uri));\n        }\n    }\n\n    Ok(())\n}\n\nfn url_restricted_error(ctx: &Ctx<'_>, message: &str, uri: &Uri) -> Error {\n    let uri_host = uri.host().unwrap_or_default();\n    let mut message_string = String::with_capacity(message.len() + 100);\n    message_string.push_str(message);\n    message_string.push_str(\": \");\n    message_string.push_str(uri_host);\n    if let Some(port) = uri.port_u16() {\n        message_string.push(':');\n        message_string.push_str(itoa::Buffer::new().format(port))\n    }\n\n    Exception::throw_message(ctx, &message_string)\n}\n\nfn url_match(list: &[Uri], uri: &Uri) -> bool {\n    let host = uri.host().unwrap_or_default();\n    let port = uri.port_u16().unwrap_or(80);\n    list.iter().any(|entry| {\n        host.ends_with(entry.host().unwrap_or_default()) && entry.port_u16().unwrap_or(80) == port\n    })\n}\n"
  },
  {
    "path": "modules/llrt_fs/Cargo.toml",
    "content": "[package]\nname = \"llrt_fs\"\ndescription = \"LLRT Module fs\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\nreadme = \"README.md\"\n\n[lib]\nname = \"llrt_fs\"\npath = \"src/lib.rs\"\n\n[dependencies]\neither = { version = \"1\", default-features = false }\nllrt_buffer = { version = \"0.8.1-beta\", path = \"../llrt_buffer\" }\nllrt_encoding = { version = \"0.8.1-beta\", path = \"../../libs/llrt_encoding\" }\nllrt_path = { version = \"0.8.1-beta\", path = \"../llrt_path\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", features = [\n  \"fs\",\n], default-features = false }\nrand = { version = \"0.10.0\", features = [\n  \"alloc\",\n  \"thread_rng\",\n], default-features = false }\nrquickjs = { version = \"0.11\", features = [\"either\"], default-features = false }\ntokio = { version = \"1\", features = [\n  \"fs\",\n  \"io-util\",\n  \"rt\",\n], default-features = false }\n\n[target.'cfg(windows)'.dependencies]\njunction = \"1\"\n\n[dev-dependencies]\nllrt_test = { path = \"../../libs/llrt_test\" }\n"
  },
  {
    "path": "modules/llrt_fs/src/access.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::fs::Metadata;\n\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{prelude::Opt, Ctx, Exception, Result};\nuse tokio::fs;\n\n#[allow(dead_code, unused_imports)]\nuse super::{CONSTANT_F_OK, CONSTANT_R_OK, CONSTANT_W_OK, CONSTANT_X_OK};\n\npub async fn access(ctx: Ctx<'_>, path: String, mode: Opt<u32>) -> Result<()> {\n    let metadata = fs::metadata(&path).await.or_throw_msg(\n        &ctx,\n        &[\"No such file or directory \\\"\", &path, \"\\\"\"].concat(),\n    )?;\n\n    verify_metadata(&ctx, mode, metadata)\n}\n\npub fn access_sync(ctx: Ctx<'_>, path: String, mode: Opt<u32>) -> Result<()> {\n    let metadata = std::fs::metadata(path.clone()).or_throw_msg(\n        &ctx,\n        &[\"No such file or directory \\\"\", &path, \"\\\"\"].concat(),\n    )?;\n\n    verify_metadata(&ctx, mode, metadata)\n}\n\nfn verify_metadata(ctx: &Ctx, mode: Opt<u32>, metadata: Metadata) -> Result<()> {\n    let permissions = metadata.permissions();\n\n    let mode = mode.unwrap_or(CONSTANT_F_OK);\n\n    if mode & CONSTANT_W_OK != 0 && permissions.readonly() {\n        return Err(Exception::throw_message(\n            ctx,\n            \"Permission denied. File not writable\",\n        ));\n    }\n\n    if mode & CONSTANT_X_OK != 0 {\n        #[cfg(unix)]\n        {\n            use std::os::unix::fs::PermissionsExt;\n            if permissions.mode() & 0o100 == 0 {\n                return Err(Exception::throw_message(\n                    ctx,\n                    \"Permission denied. File not executable\",\n                ));\n            }\n        }\n        // On Windows, X_OK behaves like F_OK (file exists check only)\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "modules/llrt_fs/src/chmod.rs",
    "content": "#[cfg(unix)]\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{Ctx, Result};\n#[cfg(unix)]\nuse std::os::unix::prelude::PermissionsExt;\n\n#[cfg(unix)]\npub(crate) fn chmod_error(path: &str) -> String {\n    [\"Can't set permissions of \\\"\", path, \"\\\"\"].concat()\n}\n\npub(crate) async fn set_mode(ctx: Ctx<'_>, path: &str, mode: u32) -> Result<()> {\n    #[cfg(unix)]\n    {\n        tokio::fs::set_permissions(path, PermissionsExt::from_mode(mode))\n            .await\n            .or_throw_msg(&ctx, &chmod_error(path))?;\n    }\n    #[cfg(not(unix))]\n    {\n        _ = ctx;\n        _ = path;\n        _ = mode;\n    }\n    Ok(())\n}\n\npub(crate) fn set_mode_sync(ctx: Ctx<'_>, path: &str, mode: u32) -> Result<()> {\n    #[cfg(unix)]\n    {\n        std::fs::set_permissions(path, PermissionsExt::from_mode(mode))\n            .or_throw_msg(&ctx, &chmod_error(path))?;\n    }\n    #[cfg(not(unix))]\n    {\n        _ = ctx;\n        _ = path;\n        _ = mode;\n    }\n    Ok(())\n}\n\npub async fn chmod(ctx: Ctx<'_>, path: String, mode: u32) -> Result<()> {\n    set_mode(ctx, &path, mode).await\n}\n\npub fn chmod_sync(ctx: Ctx<'_>, path: String, mode: u32) -> Result<()> {\n    set_mode_sync(ctx, &path, mode)\n}\n"
  },
  {
    "path": "modules/llrt_fs/src/file_handle.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#![allow(clippy::uninlined_format_args)]\n\nuse std::borrow::Cow;\nuse std::path::PathBuf;\n\nuse either::Either;\nuse llrt_buffer::{ArrayBufferView, Buffer};\nuse llrt_encoding::Encoder;\nuse llrt_utils::{\n    object::ObjectExt,\n    result::{OptionExt, ResultExt},\n};\nuse rquickjs::function::Opt;\nuse rquickjs::{Ctx, Error, Exception, FromJs, Null, Object, Result, Value};\nuse tokio::fs::File;\nuse tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt, SeekFrom};\n\nuse super::{read_file, Stats};\n\nconst DEFAULT_BUFFER_SIZE: usize = 16384;\nconst DEFAULT_ENCODING: &str = \"utf8\";\n\n#[allow(dead_code)]\n#[rquickjs::class]\n#[derive(rquickjs::class::Trace, rquickjs::JsLifetime)]\npub struct FileHandle {\n    #[qjs(skip_trace)]\n    file: Option<File>,\n    #[qjs(skip_trace)]\n    path: PathBuf,\n}\n\nimpl FileHandle {\n    pub fn new(file: File, path: PathBuf) -> Self {\n        Self {\n            file: Some(file),\n            path,\n        }\n    }\n\n    fn file(&self, ctx: &Ctx<'_>) -> Result<&File> {\n        self.file.as_ref().or_throw_msg(ctx, \"FileHandle is closed\")\n    }\n\n    fn file_mut(&mut self, ctx: &Ctx<'_>) -> Result<&mut File> {\n        self.file.as_mut().or_throw_msg(ctx, \"FileHandle is closed\")\n    }\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl FileHandle {\n    #[allow(unused_variables)]\n    async fn chmod(&self, ctx: Ctx<'_>, mode: u32) -> Result<()> {\n        #[cfg(unix)]\n        {\n            use std::os::unix::fs::PermissionsExt;\n            let perm = std::fs::Permissions::from_mode(mode);\n            self.file(&ctx)?\n                .set_permissions(perm)\n                .await\n                .or_throw_msg(&ctx, \"Can't modify file permissions\")?;\n        }\n        Ok(())\n    }\n\n    #[allow(unused_variables)]\n    async fn chown(&self, ctx: Ctx<'_>, uid: u32, gid: u32) -> Result<()> {\n        #[cfg(unix)]\n        {\n            let path = self.path.clone();\n            tokio::task::spawn_blocking(move || {\n                std::os::unix::fs::chown(&path, Some(uid), Some(gid))\n            })\n            .await\n            .or_throw(&ctx)?\n            .or_throw_msg(&ctx, \"Can't modify file owner\")?;\n        }\n        Ok(())\n    }\n\n    async fn close(&mut self) {\n        if let Some(file) = self.file.take() {\n            drop(file.into_std().await);\n        }\n    }\n\n    async fn datasync(&self, ctx: Ctx<'_>) -> Result<()> {\n        self.file(&ctx)?\n            .sync_data()\n            .await\n            .or_throw_msg(&ctx, \"Can't sync file data\")?;\n        Ok(())\n    }\n\n    #[qjs(get)]\n    async fn fd(&self, ctx: Ctx<'_>) -> Result<i32> {\n        #[cfg(unix)]\n        {\n            use std::os::fd::AsRawFd;\n            Ok(self.file(&ctx)?.as_raw_fd())\n        }\n        #[cfg(windows)]\n        {\n            use std::os::windows::io::AsRawHandle;\n            let handle = self.file(&ctx)?.as_raw_handle();\n            Ok(handle as i32)\n        }\n        #[cfg(not(any(unix, windows)))]\n        {\n            Ok(0)\n        }\n    }\n\n    async fn read<'js>(\n        &mut self,\n        ctx: Ctx<'js>,\n        buffer_or_options: Opt<Either<ArrayBufferView<'js>, ReadOptions<'js>>>,\n        options_or_offset: Opt<Either<ReadOptions<'js>, usize>>,\n        length: Opt<usize>,\n        position: Opt<Option<u64>>, // -1 is not supported\n    ) -> Result<Object<'js>> {\n        let options_1 = match buffer_or_options.0 {\n            Some(Either::Left(buffer)) => ReadOptions {\n                buffer: Some(buffer),\n                ..Default::default()\n            },\n            Some(Either::Right(options)) => options,\n            None => ReadOptions::default(),\n        };\n        let options_2 = match options_or_offset.0 {\n            Some(Either::Left(options)) => options,\n            Some(Either::Right(offset)) => ReadOptions {\n                offset: Some(offset),\n                ..Default::default()\n            },\n            None => ReadOptions::default(),\n        };\n\n        let mut buffer = options_1\n            .buffer\n            .or(options_2.buffer)\n            .unwrap_or_else_ok(|| {\n                ArrayBufferView::from_buffer(&ctx, Buffer::alloc(DEFAULT_BUFFER_SIZE))\n            })?;\n        let offset = options_1.offset.or(options_2.offset).unwrap_or(0);\n        let length = options_1\n            .length\n            .or(options_2.length)\n            .or(length.0)\n            .unwrap_or_else(|| buffer.len() - offset);\n        let position = options_1\n            .position\n            .or(options_2.position)\n            .or(position.0.flatten());\n        validate_length_offset(&ctx, length, offset, buffer.len())?;\n\n        // It is not safe to pass the buffer from `ArrayBufferView` to `File::read`\n        // since the read is done in a different thread and we cannot garantee\n        // that multiple read calls are not done with the same buffer.\n        // Ideally, we should make our own version of `BufReader` to reuse the buffer\n        // instead of doing an allocation on each read.\n        let mut buf = vec![0u8; length];\n        let file = self.file_mut(&ctx)?;\n\n        // Tokio doesn't offer an API for positional reads. This means we have\n        // to seek to the position, read the file, and then seek back to the original\n        // position. See https://github.com/tokio-rs/tokio/issues/699\n        let mut cursor = None;\n        if let Some(position) = position {\n            cursor = Some(\n                file.seek(SeekFrom::Current(0))\n                    .await\n                    .or_throw_msg(&ctx, \"Can't get cursor\")?,\n            );\n            file.seek(SeekFrom::Start(position))\n                .await\n                .or_throw_msg(&ctx, \"Can't seek file\")?;\n        }\n\n        let bytes_read = file\n            .read(&mut buf)\n            .await\n            .or_throw_msg(&ctx, \"Failed to read file\")?;\n\n        // Reset the file at the original position. If there is an error while\n        // resetting the cursor, we close the file pre-emptively since future\n        // reads would be invalid.\n        if let Some(cursor) = cursor {\n            if let Err(err) = file\n                .seek(SeekFrom::Start(cursor))\n                .await\n                .or_throw_msg(&ctx, \"Failed to reset cursor\")\n            {\n                self.close().await;\n                return Err(err);\n            }\n        }\n\n        let dst_buf = buffer\n            .as_bytes_mut()\n            .or_throw_msg(&ctx, \"Buffer is detached\")?;\n        dst_buf[offset..].copy_from_slice(&buf);\n\n        let result = Object::new(ctx)?;\n        result.set(\"bytesRead\", bytes_read)?;\n        result.set(\"buffer\", buffer)?;\n        Ok(result)\n    }\n\n    async fn read_file<'js>(\n        &mut self,\n        ctx: Ctx<'js>,\n        options: Opt<Either<String, read_file::ReadFileOptions>>,\n    ) -> Result<Value<'js>> {\n        let size = self\n            .file(&ctx)?\n            .metadata()\n            .await\n            .map(|m| m.len() as usize)\n            .ok();\n        let mut bytes = Vec::new();\n        bytes\n            .try_reserve_exact(size.unwrap_or(0))\n            .or_throw_msg(&ctx, \"Out of memory\")?;\n\n        self.file_mut(&ctx)?\n            .read_to_end(&mut bytes)\n            .await\n            .or_throw_msg(&ctx, \"Failed to read file\")?;\n        read_file::handle_read_file_bytes(&ctx, options, bytes)\n    }\n\n    async fn stat(&self, ctx: Ctx<'_>) -> Result<Stats> {\n        let metadata = self\n            .file(&ctx)?\n            .metadata()\n            .await\n            .or_throw_msg(&ctx, \"Can't stat file\")?;\n        Ok(Stats::new(metadata))\n    }\n\n    async fn sync(&self, ctx: Ctx<'_>) -> Result<()> {\n        self.file(&ctx)?\n            .sync_all()\n            .await\n            .or_throw_msg(&ctx, \"Can't sync file\")\n    }\n\n    async fn truncate(&mut self, ctx: Ctx<'_>, len: Opt<u64>) -> Result<()> {\n        let len = len.0.unwrap_or(0);\n        self.file_mut(&ctx)?\n            .set_len(len)\n            .await\n            .or_throw_msg(&ctx, \"Can't truncate file\")\n    }\n\n    // Setting times not supported in tokio\n    // See https://github.com/tokio-rs/tokio/issues/6368\n    // async fn utimes(&mut self,  ctx: Ctx<'_>, atime: Value<'_>, mtime: Value<'_>) -> Result<()>\n\n    async fn write<'js>(\n        &mut self,\n        ctx: Ctx<'js>,\n        buffer_or_string: Either<ArrayBufferView<'js>, String>,\n        offset_or_options_or_position: Opt<Either<Either<usize, Null>, WriteOptions>>,\n        length_or_encoding: Opt<Either<usize, String>>,\n        position: Opt<Option<u64>>,\n    ) -> Result<Object<'js>> {\n        let mut options = match offset_or_options_or_position.0 {\n            Some(Either::Left(Either::Left(offset_or_position))) => {\n                if buffer_or_string.is_left() {\n                    WriteOptions {\n                        offset: Some(offset_or_position),\n                        ..Default::default()\n                    }\n                } else {\n                    WriteOptions::default()\n                }\n            },\n            Some(Either::Right(options)) => options,\n            _ => WriteOptions::default(),\n        };\n        if let Some(Either::Left(length)) = length_or_encoding.0 {\n            options.length = Some(length);\n        }\n\n        let buffer = match &buffer_or_string {\n            Either::Left(buffer) => {\n                let buffer = buffer.as_bytes().or_throw_msg(&ctx, \"Buffer is detached\")?;\n                Cow::Borrowed(buffer)\n            },\n            Either::Right(string) => {\n                let encoding = length_or_encoding\n                    .0\n                    .and_then(|e| e.right())\n                    .unwrap_or_else(|| DEFAULT_ENCODING.to_string());\n                let buffer = Encoder::from_str(&encoding)\n                    .and_then(|enc| enc.decode_from_string(string.clone()))\n                    .or_throw(&ctx)?;\n                Cow::Owned(buffer)\n            },\n        };\n\n        let offset = options.offset.unwrap_or(0);\n        let length = options.length.unwrap_or(buffer.len() - offset);\n        let position = options.position.or(position.0.flatten());\n        validate_length_offset(&ctx, length, offset, buffer.len())?;\n\n        let file = self.file_mut(&ctx)?;\n\n        // Tokio doesn't offer an API for positional writes. This means we have\n        // to seek to the position, write to the file, and then seek back to the original\n        // position. See https://github.com/tokio-rs/tokio/issues/699\n        let mut cursor = None;\n        if let Some(position) = position {\n            cursor = Some(\n                file.seek(SeekFrom::Current(0))\n                    .await\n                    .or_throw_msg(&ctx, \"Can't get cursor\")?,\n            );\n            file.seek(SeekFrom::Start(position))\n                .await\n                .or_throw_msg(&ctx, \"Can't seek file\")?;\n        }\n\n        file.write_all(&buffer[offset..length])\n            .await\n            .or_throw_msg(&ctx, \"Failed to write to file\")?;\n\n        // Reset the file at the original position. If there is an error while\n        // resetting the cursor, we close the file pre-emptively since future\n        // writes would be invalid.\n        if let Some(cursor) = cursor {\n            if let Err(err) = file\n                .seek(SeekFrom::Start(cursor))\n                .await\n                .or_throw_msg(&ctx, \"Failed to reset cursor\")\n            {\n                self.close().await;\n                return Err(err);\n            }\n        }\n\n        let result = Object::new(ctx)?;\n        result.set(\"bytesWritten\", length)?;\n        result.set(\"buffer\", buffer_or_string)?;\n        Ok(result)\n    }\n\n    async fn write_file<'js>(\n        &mut self,\n        ctx: Ctx<'js>,\n        data: Either<ArrayBufferView<'js>, String>,\n        options_or_encoding: Opt<Either<WriteFileOptions, String>>,\n    ) -> Result<()> {\n        let file = self.file_mut(&ctx)?;\n\n        // Always overwrite the whole file\n        file.set_len(0)\n            .await\n            .or_throw_msg(&ctx, \"Failed to truncate file\")?;\n\n        let encoding = match options_or_encoding.0 {\n            Some(Either::Left(options)) => options.encoding,\n            Some(Either::Right(encoding)) => Some(encoding),\n            _ => None,\n        }\n        .unwrap_or_else(|| DEFAULT_ENCODING.to_string());\n\n        let buffer = match &data {\n            Either::Left(buffer) => {\n                let buffer = buffer.as_bytes().or_throw_msg(&ctx, \"Buffer is detached\")?;\n                Cow::Borrowed(buffer)\n            },\n            Either::Right(string) => {\n                let buffer = Encoder::from_str(&encoding)\n                    .and_then(|enc| enc.decode_from_string(string.clone()))\n                    .or_throw(&ctx)?;\n                Cow::Owned(buffer)\n            },\n        };\n\n        file.write_all(&buffer)\n            .await\n            .or_throw_msg(&ctx, \"Failed to write to file\")?;\n        Ok(())\n    }\n}\n\nfn validate_length_offset(\n    ctx: &Ctx<'_>,\n    length: usize,\n    offset: usize,\n    buffer_length: usize,\n) -> Result<()> {\n    if offset > buffer_length {\n        return Err(Exception::throw_range(\n            ctx,\n            &format!(\"offset ({}) <= {}\", offset, buffer_length),\n        ));\n    }\n    if length > buffer_length - offset {\n        return Err(Exception::throw_range(\n            ctx,\n            &format!(\"length ({}) <= {}\", length, buffer_length - offset),\n        ));\n    }\n    Ok(())\n}\n\n#[derive(Default)]\nstruct ReadOptions<'js> {\n    buffer: Option<ArrayBufferView<'js>>,\n    offset: Option<usize>,\n    length: Option<usize>,\n    position: Option<u64>,\n}\n\nimpl<'js> FromJs<'js> for ReadOptions<'js> {\n    fn from_js(_ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        let ty_name = value.type_name();\n        let obj = value\n            .as_object()\n            .ok_or(Error::new_from_js(ty_name, \"Object\"))?;\n\n        let buffer = obj.get_optional::<_, ArrayBufferView<'js>>(\"buffer\")?;\n        let offset = obj.get_optional::<_, usize>(\"offset\")?;\n        let length = obj.get_optional::<_, usize>(\"length\")?;\n        let position = obj.get_optional::<_, u64>(\"position\")?;\n\n        Ok(Self {\n            buffer,\n            offset,\n            length,\n            position,\n        })\n    }\n}\n\n#[derive(Default)]\nstruct WriteOptions {\n    offset: Option<usize>,\n    length: Option<usize>,\n    position: Option<u64>,\n}\n\nimpl<'js> FromJs<'js> for WriteOptions {\n    fn from_js(_ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        let ty_name = value.type_name();\n        let obj = value\n            .as_object()\n            .ok_or(Error::new_from_js(ty_name, \"Object\"))?;\n\n        let offset = obj.get_optional::<_, usize>(\"offset\")?;\n        let length = obj.get_optional::<_, usize>(\"length\")?;\n        let position = obj.get_optional::<_, u64>(\"position\")?;\n\n        Ok(Self {\n            offset,\n            length,\n            position,\n        })\n    }\n}\n\n#[derive(Default)]\nstruct WriteFileOptions {\n    encoding: Option<String>,\n}\n\nimpl<'js> FromJs<'js> for WriteFileOptions {\n    fn from_js(_ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        let ty_name = value.type_name();\n        let obj = value\n            .as_object()\n            .ok_or(Error::new_from_js(ty_name, \"Object\"))?;\n\n        let encoding = obj.get_optional::<_, String>(\"encoding\")?;\n\n        Ok(Self { encoding })\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use llrt_buffer as buffer;\n    use llrt_test::{call_test, call_test_err, test_async_with, ModuleEvaluator};\n    use rquickjs::{CatchResultExt, CaughtError};\n    use tokio::fs::OpenOptions;\n\n    use super::*;\n\n    async fn given_file(content: &str, options: &mut OpenOptions) -> (File, PathBuf) {\n        // Create file\n        let path = llrt_test::given_file(content).await;\n\n        // Open in right mode\n        let file = options.open(&path).await.unwrap();\n        (file, path)\n    }\n\n    #[tokio::test]\n    async fn test_file_handle_read() {\n        let (file, path) = given_file(\"Hello World\", OpenOptions::new().read(true)).await;\n        let path_1 = path.clone();\n\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        export async function test(filehandle) {\n                            const buffer = new ArrayBuffer(4096);\n                            const view = new Uint8Array(buffer);\n                            const read = await filehandle.read(view);\n                            return Array.from(view);\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n\n                let result =\n                    call_test::<Vec<u8>, _>(&ctx, &module, (FileHandle::new(file, path_1),)).await;\n\n                assert!(result.starts_with(b\"Hello World\"));\n            })\n        })\n        .await;\n\n        tokio::fs::remove_file(&path).await.unwrap();\n    }\n\n    #[tokio::test]\n    async fn test_file_handle_read_concurrent() {\n        let (file_a, path_a) = given_file(&\"a\".repeat(20000), OpenOptions::new().read(true)).await;\n        let (file_b, path_b) = given_file(&\"b\".repeat(20000), OpenOptions::new().read(true)).await;\n        let path_a_1 = path_a.clone();\n        let path_b_1 = path_b.clone();\n\n        test_async_with(|ctx| {\n            Box::pin(async move {\n\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        export async function test(filehandleA, filehandleB) {\n                            const buffer = new ArrayBuffer(10000);\n                            const view = new Uint8Array(buffer);\n                            const read = await Promise.all([filehandleA.read(view), filehandleB.read(view)]);\n                            return Array.from(view);\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n\n                let result =\n                    call_test::<Vec<u8>, _>(&ctx, &module, (FileHandle::new(file_a, path_a_1), FileHandle::new(file_b, path_b_1))).await;\n\n                assert_eq!(result.len(), 10000);\n                if result.iter().all(|&b| b == b'a') {\n                    println!(\"All a\");\n                } else if result.iter().all(|&b| b == b'b') {\n                    println!(\"All b\");\n                } else {\n                    println!(\"Mixed\");\n                }\n            })\n        })\n        .await;\n\n        tokio::fs::remove_file(&path_a).await.unwrap();\n        tokio::fs::remove_file(&path_b).await.unwrap();\n    }\n\n    #[tokio::test]\n    async fn test_file_handle_read_position() {\n        let (file, path) = given_file(\"Hello World\", OpenOptions::new().read(true)).await;\n        let path_1 = path.clone();\n\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        export async function test(filehandle) {\n                            const buffer = new ArrayBuffer(4096);\n                            const view = new Uint8Array(buffer);\n                            await filehandle.read(view, { position: 6 });\n                            await filehandle.read(view, { offset: 5 });\n                            return Array.from(view);\n                        }\n                    \"#,\n                )\n                .await\n                .catch(&ctx)\n                .unwrap();\n\n                let result =\n                    call_test::<Vec<u8>, _>(&ctx, &module, (FileHandle::new(file, path_1),)).await;\n\n                assert!(result.starts_with(b\"WorldHello World\"));\n            })\n        })\n        .await;\n\n        tokio::fs::remove_file(&path).await.unwrap();\n    }\n\n    #[tokio::test]\n    async fn test_file_handle_read_subarray() {\n        let (file, path) = given_file(\"Hello World\", OpenOptions::new().read(true)).await;\n        let path_1 = path.clone();\n\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        export async function test(filehandle) {\n                            const buffer = new ArrayBuffer(4096);\n                            const view = new Uint8Array(buffer);\n                            const subarray = view.subarray(3, 8);\n                            const read = await filehandle.read(subarray);\n                            return Array.from(view);\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n\n                let result =\n                    call_test::<Vec<u8>, _>(&ctx, &module, (FileHandle::new(file, path_1),)).await;\n\n                assert!(result.starts_with(b\"\\x00\\x00\\x00Hello\\x00\"));\n            })\n        })\n        .await;\n\n        tokio::fs::remove_file(&path).await.unwrap();\n    }\n\n    #[tokio::test]\n    async fn test_file_handle_read_buffer() {\n        let (file, path) = given_file(\"Hello World\", OpenOptions::new().read(true)).await;\n        let path_1 = path.clone();\n\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                buffer::init(&ctx).unwrap();\n\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        export async function test(filehandle) {\n                            const buffer = new ArrayBuffer(4096);\n                            const view = new Uint8Array(buffer);\n                            await filehandle.read(view, { length: 2000, offset: 3000 });\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n\n                let error = call_test_err::<(), _>(&ctx, &module, (FileHandle::new(file, path_1),))\n                    .await\n                    .unwrap_err();\n\n                let CaughtError::Exception(exception) = error else {\n                    panic!(\"Expected exception\");\n                };\n\n                assert_eq!(exception.message().unwrap(), \"length (2000) <= 1096\");\n            })\n        })\n        .await;\n\n        tokio::fs::remove_file(&path).await.unwrap();\n    }\n\n    #[tokio::test]\n    async fn test_file_handle_read_out_of_range() {\n        let (file, path) = given_file(\"Hello World\", OpenOptions::new().read(true)).await;\n        let path_1 = path.clone();\n\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                buffer::init(&ctx).unwrap();\n\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        export async function test(filehandle) {\n                            const buffer = Buffer.alloc(4096);\n                            const read = await filehandle.read(buffer);\n                            return Array.from(buffer);\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n\n                let result =\n                    call_test::<Vec<u8>, _>(&ctx, &module, (FileHandle::new(file, path_1),)).await;\n\n                assert!(result.starts_with(b\"Hello World\"));\n            })\n        })\n        .await;\n\n        tokio::fs::remove_file(&path).await.unwrap();\n    }\n\n    #[tokio::test]\n    async fn test_file_handle_read_file() {\n        let (file, path) = given_file(\"Hello World\", OpenOptions::new().read(true)).await;\n        let path_1 = path.clone();\n\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        export async function test(filehandle) {\n                            const data = await filehandle.readFile(\"utf8\");\n                            return data;\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n\n                let result =\n                    call_test::<String, _>(&ctx, &module, (FileHandle::new(file, path_1),)).await;\n\n                assert_eq!(result, \"Hello World\");\n            })\n        })\n        .await;\n\n        tokio::fs::remove_file(&path).await.unwrap();\n    }\n\n    #[tokio::test]\n    async fn test_file_handle_write() {\n        let (file, path) = given_file(\"\", OpenOptions::new().write(true)).await;\n        let path_1 = path.clone();\n\n        test_async_with(|ctx| {\n            Box::pin(async move {\n\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        export async function test(filehandle) {\n                            const { bytesWritten } = await filehandle.write(\"Hello World\", null, \"utf8\");\n                            await filehandle.sync();\n                            return bytesWritten;\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n\n                let result =\n                    call_test::<u32, _>(&ctx, &module, (FileHandle::new(file, path_1),)).await;\n\n                assert_eq!(result, 11);\n            })\n        })\n        .await;\n\n        let file_content = tokio::fs::read(&path).await.unwrap();\n        tokio::fs::remove_file(&path).await.unwrap();\n        assert_eq!(file_content, b\"Hello World\");\n    }\n\n    #[tokio::test]\n    async fn test_file_handle_write_position() {\n        let (file, path) = given_file(\"\", OpenOptions::new().write(true)).await;\n        let path_1 = path.clone();\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        export async function test(filehandle) {\n                            const { bytesWritten } = await filehandle.write(\"Hello World\", null, \"utf8\", 4);\n                            await filehandle.write(\"a\", null, \"utf8\");\n                            await filehandle.sync();\n                            return bytesWritten;\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n\n                let result =\n                    call_test::<u32, _>(&ctx, &module, (FileHandle::new(file, path_1),)).await;\n\n                assert_eq!(result, 11);\n            })\n        })\n        .await;\n\n        let file_content = tokio::fs::read(&path).await.unwrap();\n        tokio::fs::remove_file(&path).await.unwrap();\n        assert_eq!(file_content, b\"a\\x00\\x00\\x00Hello World\");\n    }\n\n    #[tokio::test]\n    async fn test_file_handle_write_out_of_range() {\n        let (file, path) = given_file(\"\", OpenOptions::new().write(true)).await;\n        let path_1 = path.clone();\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        export async function test(filehandle) {\n                            await filehandle.write(\"Hello World\", { offset: 5, length: 20 });\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n\n                let error = call_test_err::<(), _>(&ctx, &module, (FileHandle::new(file, path_1),))\n                    .await\n                    .unwrap_err();\n\n                let CaughtError::Exception(exception) = error else {\n                    panic!(\"Expected exception\");\n                };\n\n                assert_eq!(exception.message().unwrap(), \"length (20) <= 6\");\n            })\n        })\n        .await;\n\n        let file_content = tokio::fs::read(&path).await.unwrap();\n        tokio::fs::remove_file(&path).await.unwrap();\n        assert_eq!(file_content, b\"\");\n    }\n\n    #[tokio::test]\n    async fn test_file_handle_write_file() {\n        let (file, path) = given_file(\n            \"Other very very very very long Data\",\n            OpenOptions::new().write(true),\n        )\n        .await;\n        let path_1 = path.clone();\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        export async function test(filehandle) {\n                            await filehandle.writeFile(\"Hello World\", \"utf8\");\n                            await filehandle.sync();\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n\n                call_test::<(), _>(&ctx, &module, (FileHandle::new(file, path_1),)).await;\n            })\n        })\n        .await;\n\n        let file_content = tokio::fs::read(&path).await.unwrap();\n        tokio::fs::remove_file(&path).await.unwrap();\n        assert_eq!(file_content, b\"Hello World\");\n    }\n\n    #[tokio::test]\n    async fn test_file_handle_fd() {\n        let (file, path) = given_file(\"\", OpenOptions::new().read(true)).await;\n        let path_1 = path.clone();\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        export async function test(filehandle) {\n                            return filehandle.fd;\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n\n                let result =\n                    call_test::<i32, _>(&ctx, &module, (FileHandle::new(file, path_1),)).await;\n\n                assert!(result > 0);\n            })\n        })\n        .await;\n\n        tokio::fs::remove_file(&path).await.unwrap();\n    }\n}\n"
  },
  {
    "path": "modules/llrt_fs/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nmod access;\nmod chmod;\nmod file_handle;\nmod mkdir;\nmod open;\nmod read_dir;\nmod read_file;\nmod rename;\nmod rm;\nmod stats;\nmod symlink;\nmod write_file;\n\nuse llrt_utils::module::{export_default, ModuleInfo};\nuse rquickjs::{\n    module::{Declarations, Exports, ModuleDef},\n    prelude::{Async, Func},\n};\nuse rquickjs::{Class, Ctx, Object, Result};\n\nuse self::access::{access, access_sync};\nuse self::chmod::{chmod, chmod_sync};\nuse self::file_handle::FileHandle;\nuse self::mkdir::{mkdir, mkdir_sync, mkdtemp, mkdtemp_sync};\nuse self::open::open;\nuse self::read_dir::{read_dir, read_dir_sync, Dirent};\nuse self::read_file::{read_file, read_file_sync};\nuse self::rename::{rename, rename_sync};\nuse self::rm::{rmdir, rmdir_sync, rmfile, rmfile_sync};\nuse self::stats::{lstat_fn, lstat_fn_sync, stat_fn, stat_fn_sync, Stats};\nuse self::symlink::{symlink, symlink_sync};\nuse self::write_file::{write_file, write_file_sync};\n\npub const CONSTANT_F_OK: u32 = 0;\npub const CONSTANT_R_OK: u32 = 4;\npub const CONSTANT_W_OK: u32 = 2;\npub const CONSTANT_X_OK: u32 = 1;\n\npub struct FsPromisesModule;\n\nimpl ModuleDef for FsPromisesModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(\"access\")?;\n        declare.declare(\"open\")?;\n        declare.declare(\"readFile\")?;\n        declare.declare(\"writeFile\")?;\n        declare.declare(\"rename\")?;\n        declare.declare(\"readdir\")?;\n        declare.declare(\"mkdir\")?;\n        declare.declare(\"mkdtemp\")?;\n        declare.declare(\"rm\")?;\n        declare.declare(\"rmdir\")?;\n        declare.declare(\"stat\")?;\n        declare.declare(\"lstat\")?;\n        declare.declare(\"constants\")?;\n        declare.declare(\"chmod\")?;\n        declare.declare(\"symlink\")?;\n\n        declare.declare(\"default\")?;\n\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        let globals = ctx.globals();\n\n        Class::<Dirent>::define(&globals)?;\n        Class::<FileHandle>::define(&globals)?;\n        Class::<Stats>::define(&globals)?;\n\n        export_default(ctx, exports, |default| {\n            export_promises(ctx, default)?;\n\n            Ok(())\n        })\n    }\n}\n\nimpl From<FsPromisesModule> for ModuleInfo<FsPromisesModule> {\n    fn from(val: FsPromisesModule) -> Self {\n        ModuleInfo {\n            name: \"fs/promises\",\n            module: val,\n        }\n    }\n}\n\npub struct FsModule;\n\nimpl ModuleDef for FsModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(\"promises\")?;\n        declare.declare(\"accessSync\")?;\n        declare.declare(\"mkdirSync\")?;\n        declare.declare(\"mkdtempSync\")?;\n        declare.declare(\"readdirSync\")?;\n        declare.declare(\"readFileSync\")?;\n        declare.declare(\"rmdirSync\")?;\n        declare.declare(\"rmSync\")?;\n        declare.declare(\"statSync\")?;\n        declare.declare(\"lstatSync\")?;\n        declare.declare(\"writeFileSync\")?;\n        declare.declare(\"constants\")?;\n        declare.declare(\"chmodSync\")?;\n        declare.declare(\"renameSync\")?;\n        declare.declare(\"symlinkSync\")?;\n\n        declare.declare(\"default\")?;\n\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        let globals = ctx.globals();\n\n        Class::<Dirent>::define(&globals)?;\n        Class::<FileHandle>::define(&globals)?;\n        Class::<Stats>::define(&globals)?;\n\n        export_default(ctx, exports, |default| {\n            let promises = Object::new(ctx.clone())?;\n            export_promises(ctx, &promises)?;\n            export_constants(ctx, default)?;\n\n            default.set(\"promises\", promises)?;\n            default.set(\"accessSync\", Func::from(access_sync))?;\n            default.set(\"mkdirSync\", Func::from(mkdir_sync))?;\n            default.set(\"mkdtempSync\", Func::from(mkdtemp_sync))?;\n            default.set(\"readdirSync\", Func::from(read_dir_sync))?;\n            default.set(\"readFileSync\", Func::from(read_file_sync))?;\n            default.set(\"rmdirSync\", Func::from(rmdir_sync))?;\n            default.set(\"rmSync\", Func::from(rmfile_sync))?;\n            default.set(\"statSync\", Func::from(stat_fn_sync))?;\n            default.set(\"lstatSync\", Func::from(lstat_fn_sync))?;\n            default.set(\"writeFileSync\", Func::from(write_file_sync))?;\n            default.set(\"chmodSync\", Func::from(chmod_sync))?;\n            default.set(\"renameSync\", Func::from(rename_sync))?;\n            default.set(\"symlinkSync\", Func::from(symlink_sync))?;\n\n            Ok(())\n        })\n    }\n}\n\nfn export_promises<'js>(ctx: &Ctx<'js>, exports: &Object<'js>) -> Result<()> {\n    export_constants(ctx, exports)?;\n\n    exports.set(\"access\", Func::from(Async(access)))?;\n    exports.set(\"open\", Func::from(Async(open)))?;\n    exports.set(\"readFile\", Func::from(Async(read_file)))?;\n    exports.set(\"writeFile\", Func::from(Async(write_file)))?;\n    exports.set(\"rename\", Func::from(Async(rename)))?;\n    exports.set(\"readdir\", Func::from(Async(read_dir)))?;\n    exports.set(\"mkdir\", Func::from(Async(mkdir)))?;\n    exports.set(\"mkdtemp\", Func::from(Async(mkdtemp)))?;\n    exports.set(\"rm\", Func::from(Async(rmfile)))?;\n    exports.set(\"rmdir\", Func::from(Async(rmdir)))?;\n    exports.set(\"stat\", Func::from(Async(stat_fn)))?;\n    exports.set(\"lstat\", Func::from(Async(lstat_fn)))?;\n    exports.set(\"chmod\", Func::from(Async(chmod)))?;\n    exports.set(\"symlink\", Func::from(Async(symlink)))?;\n\n    Ok(())\n}\n\nfn export_constants<'js>(ctx: &Ctx<'js>, exports: &Object<'js>) -> Result<()> {\n    let constants = Object::new(ctx.clone())?;\n    constants.set(\"F_OK\", CONSTANT_F_OK)?;\n    constants.set(\"R_OK\", CONSTANT_R_OK)?;\n    constants.set(\"W_OK\", CONSTANT_W_OK)?;\n    constants.set(\"X_OK\", CONSTANT_X_OK)?;\n\n    exports.set(\"constants\", constants)?;\n\n    Ok(())\n}\n\nimpl From<FsModule> for ModuleInfo<FsModule> {\n    fn from(val: FsModule) -> Self {\n        ModuleInfo {\n            name: \"fs\",\n            module: val,\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_fs/src/mkdir.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse crate::chmod::{set_mode, set_mode_sync};\n\nuse llrt_path::resolve_path;\nuse llrt_utils::result::ResultExt;\nuse rand::RngExt;\nuse rquickjs::{function::Opt, Ctx, Object, Result};\nuse tokio::fs;\n\npub async fn mkdir<'js>(ctx: Ctx<'js>, path: String, options: Opt<Object<'js>>) -> Result<String> {\n    let (recursive, mode, path) = get_params(&path, options)?;\n\n    if recursive {\n        fs::create_dir_all(&path).await\n    } else {\n        fs::create_dir(&path).await\n    }\n    .or_throw_msg(&ctx, &[\"Can't create dir \\\"\", &path, \"\\\"\"].concat())?;\n\n    set_mode(ctx, &path, mode).await?;\n\n    Ok(path)\n}\n\npub fn mkdir_sync<'js>(ctx: Ctx<'js>, path: String, options: Opt<Object<'js>>) -> Result<String> {\n    let (recursive, mode, path) = get_params(&path, options)?;\n\n    if recursive {\n        std::fs::create_dir_all(&path)\n    } else {\n        std::fs::create_dir(&path)\n    }\n    .or_throw_msg(&ctx, &[\"Can't create dir \\\"\", &path, \"\\\"\"].concat())?;\n\n    set_mode_sync(ctx, &path, mode)?;\n\n    Ok(path)\n}\n\nfn get_params(path: &str, options: Opt<Object>) -> Result<(bool, u32, String)> {\n    let mut recursive = false;\n    let mut mode = 0o777;\n\n    if let Some(options) = options.0 {\n        recursive = options.get(\"recursive\").unwrap_or_default();\n        mode = options.get(\"mode\").unwrap_or(0o777);\n    }\n    let path = resolve_path([path])?;\n    Ok((recursive, mode, path))\n}\n\nconst CHARS: &[u8] = b\"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\";\n\nfn random_chars(len: usize) -> String {\n    let mut bytes = vec![0u8; len];\n    rand::rng().fill(&mut bytes);\n    bytes\n        .iter()\n        .map(|&byte| {\n            let idx = (byte as usize) % CHARS.len();\n            CHARS[idx] as char\n        })\n        .collect::<String>()\n}\n\npub async fn mkdtemp(ctx: Ctx<'_>, prefix: String) -> Result<String> {\n    let path = [prefix.as_str(), random_chars(6).as_str()].join(\",\");\n    fs::create_dir_all(&path)\n        .await\n        .or_throw_msg(&ctx, &[\"Can't create dir \\\"\", &path, \"\\\"\"].concat())?;\n    Ok(path)\n}\n\npub fn mkdtemp_sync(ctx: Ctx<'_>, prefix: String) -> Result<String> {\n    let path = [prefix.as_str(), random_chars(6).as_str()].join(\",\");\n    std::fs::create_dir_all(&path)\n        .or_throw_msg(&ctx, &[\"Can't create dir \\\"\", &path, \"\\\"\"].concat())?;\n    Ok(path)\n}\n"
  },
  {
    "path": "modules/llrt_fs/src/open.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::path::PathBuf;\n\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{function::Opt, Ctx, Exception, Result};\nuse tokio::fs::OpenOptions;\n\nuse super::file_handle::FileHandle;\n\npub async fn open(\n    ctx: Ctx<'_>,\n    path: String,\n    flags: Opt<String>,\n    mode: Opt<u32>,\n) -> Result<FileHandle> {\n    let mut options = OpenOptions::new();\n    match flags.0.as_deref().unwrap_or(\"r\") {\n        // We are not supporting the sync modes\n        \"a\" => options.append(true).create(true),\n        \"ax\" => options.append(true).create_new(true),\n        \"a+\" => options.append(true).read(true),\n        \"r\" => options.read(true),\n        \"r+\" => options.read(true).write(true),\n        \"w\" => options.write(true).create(true).truncate(true),\n        \"wx\" => options.write(true).create_new(true),\n        \"w+\" => options.write(true).read(true).create(true).truncate(true),\n        \"wx+\" => options.write(true).read(true).create_new(true),\n        flags => {\n            return Err(Exception::throw_message(\n                &ctx,\n                &[\"Invalid flags '\", flags, \"'\"].concat(),\n            ))\n        },\n    };\n    #[cfg(unix)]\n    {\n        let mode = mode.0.unwrap_or(0o666);\n        options.mode(mode);\n    }\n    #[cfg(not(unix))]\n    {\n        _ = mode;\n    }\n\n    let path = PathBuf::from(path);\n    let file = options\n        .open(&path)\n        .await\n        .or_throw_msg(&ctx, \"Cannot open file\")?;\n\n    Ok(FileHandle::new(file, path))\n}\n\n#[cfg(test)]\nmod tests {\n    use llrt_buffer as buffer;\n    use llrt_test::{call_test, given_file, test_async_with, ModuleEvaluator};\n\n    use crate::FsPromisesModule;\n\n    #[tokio::test]\n    async fn test_file_handle_read() {\n        let path = given_file(\"Hello World\")\n            .await\n            .to_string_lossy()\n            .to_string();\n        let path_1 = path.clone();\n\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                buffer::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<FsPromisesModule>(ctx.clone(), \"fs/promises\")\n                    .await\n                    .unwrap();\n\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { open } from 'fs/promises';\n\n                        export async function test(path) {\n                            let filehandle = null;\n                            try {\n                                filehandle = await open(path, 'r+');\n                                let { buffer } = await filehandle.read();\n                                return Array.from(buffer);\n                            } finally {\n                                await filehandle?.close();\n                            }\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n\n                let result = call_test::<Vec<u8>, _>(&ctx, &module, (path_1,)).await;\n\n                assert!(result.starts_with(b\"Hello World\"));\n            })\n        })\n        .await;\n\n        tokio::fs::remove_file(path).await.unwrap();\n    }\n}\n"
  },
  {
    "path": "modules/llrt_fs/src/read_dir.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#[cfg(unix)]\nuse std::os::unix::fs::FileTypeExt;\nuse std::{fs::Metadata, path::PathBuf};\n\nuse llrt_path::{ends_with_sep, CURRENT_DIR_STR};\nuse llrt_utils::fs::DirectoryWalker;\nuse rquickjs::{\n    atom::PredefinedAtom, prelude::Opt, Array, Class, Ctx, IntoJs, Object, Result, Value,\n};\n\n#[derive(rquickjs::class::Trace, rquickjs::JsLifetime)]\n#[rquickjs::class]\npub struct Dirent {\n    #[qjs(skip_trace)]\n    metadata: Metadata,\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl Dirent {\n    pub fn is_file(&self) -> bool {\n        self.metadata.is_file()\n    }\n    pub fn is_directory(&self) -> bool {\n        self.metadata.is_dir()\n    }\n\n    pub fn is_symbolic_link(&self) -> bool {\n        self.metadata.is_symlink()\n    }\n\n    #[qjs(rename = \"isFIFO\")]\n    pub fn is_fifo(&self) -> bool {\n        #[cfg(unix)]\n        {\n            self.metadata.file_type().is_fifo()\n        }\n        #[cfg(not(unix))]\n        {\n            false\n        }\n    }\n\n    pub fn is_block_device(&self) -> bool {\n        #[cfg(unix)]\n        {\n            self.metadata.file_type().is_block_device()\n        }\n        #[cfg(not(unix))]\n        {\n            false\n        }\n    }\n\n    pub fn is_character_device(&self) -> bool {\n        #[cfg(unix)]\n        {\n            self.metadata.file_type().is_char_device()\n        }\n        #[cfg(not(unix))]\n        {\n            false\n        }\n    }\n\n    pub fn is_socket(&self) -> bool {\n        #[cfg(unix)]\n        {\n            self.metadata.file_type().is_socket()\n        }\n        #[cfg(not(unix))]\n        {\n            false\n        }\n    }\n}\n\nstruct ReadDirItem {\n    name: String,\n    metadata: Option<Metadata>,\n}\n\npub struct ReadDir {\n    items: Vec<ReadDirItem>,\n    root: String,\n}\n\nimpl<'js> IntoJs<'js> for ReadDir {\n    fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {\n        let arr = Array::new(ctx.clone())?;\n        for (index, item) in self.items.into_iter().enumerate() {\n            if let Some(metadata) = item.metadata {\n                let dirent = Dirent { metadata };\n\n                let dirent = Class::instance(ctx.clone(), dirent)?;\n                dirent.set(PredefinedAtom::Name, item.name)?;\n                dirent.set(\"parentPath\", &self.root)?;\n                arr.set(index, dirent)?;\n            } else {\n                arr.set(index, item.name)?;\n            }\n        }\n        arr.into_js(ctx)\n    }\n}\n\npub async fn read_dir(mut path: String, options: Opt<Object<'_>>) -> Result<ReadDir> {\n    let (with_file_types, skip_root_pos, mut directory_walker) =\n        process_options_and_create_directory_walker(&mut path, options);\n\n    let mut items = Vec::with_capacity(64);\n\n    while let Some((child, metadata)) = directory_walker.walk().await? {\n        append_directory_and_metadata_to_vec(\n            with_file_types,\n            skip_root_pos,\n            &mut items,\n            child,\n            metadata,\n        );\n    }\n\n    items.sort_by(|a, b| a.name.partial_cmp(&b.name).unwrap());\n\n    Ok(ReadDir { items, root: path })\n}\n\npub fn read_dir_sync(mut path: String, options: Opt<Object<'_>>) -> Result<ReadDir> {\n    let (with_file_types, skip_root_pos, mut directory_walker) =\n        process_options_and_create_directory_walker(&mut path, options);\n\n    let mut items = Vec::with_capacity(64);\n    while let Some((child, metadata)) = directory_walker.walk_sync()? {\n        append_directory_and_metadata_to_vec(\n            with_file_types,\n            skip_root_pos,\n            &mut items,\n            child,\n            metadata,\n        );\n    }\n\n    items.sort_by(|a, b| a.name.partial_cmp(&b.name).unwrap());\n\n    Ok(ReadDir { items, root: path })\n}\n\ntype OptionsAndDirectoryWalker = (bool, usize, DirectoryWalker<fn(&str) -> bool>);\n\nfn process_options_and_create_directory_walker(\n    path: &mut String,\n    options: Opt<Object>,\n) -> OptionsAndDirectoryWalker {\n    let mut with_file_types = false;\n    let mut is_recursive = false;\n\n    if let Some(options) = options.0 {\n        with_file_types = options\n            .get(\"withFileTypes\")\n            .ok()\n            .and_then(|file_types: Value| file_types.as_bool())\n            .unwrap_or_default();\n\n        is_recursive = options\n            .get(\"recursive\")\n            .ok()\n            .and_then(|recursive: Value| recursive.as_bool())\n            .unwrap_or_default();\n    };\n\n    if ends_with_sep(path) {\n        path.pop();\n    }\n\n    let skip_root_pos = {\n        match path.as_str() {\n            // . | ./\n            \".\" | CURRENT_DIR_STR => path.len(),\n            // path\n            _ => path.len() + 1,\n        }\n    };\n\n    let mut directory_walker: DirectoryWalker<fn(&str) -> bool> =\n        DirectoryWalker::new(PathBuf::from(&path), |_| true);\n\n    if is_recursive {\n        directory_walker.set_recursive(true);\n    }\n    (with_file_types, skip_root_pos, directory_walker)\n}\n\nfn append_directory_and_metadata_to_vec(\n    with_file_types: bool,\n    skip_root_pos: usize,\n    items: &mut Vec<ReadDirItem>,\n    child: PathBuf,\n    metadata: Metadata,\n) {\n    let metadata = if with_file_types {\n        Some(metadata)\n    } else {\n        None\n    };\n\n    let name = child.into_os_string().to_string_lossy()[skip_root_pos..].to_string();\n\n    items.push(ReadDirItem { name, metadata })\n}\n"
  },
  {
    "path": "modules/llrt_fs/src/read_file.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse either::Either;\nuse llrt_buffer::Buffer;\nuse llrt_utils::{object::ObjectExt, result::ResultExt};\nuse rquickjs::{function::Opt, Ctx, Error, FromJs, IntoJs, Result, Value};\nuse tokio::fs;\n\npub async fn read_file(\n    ctx: Ctx<'_>,\n    path: String,\n    options: Opt<Either<String, ReadFileOptions>>,\n) -> Result<Value<'_>> {\n    let bytes = fs::read(&path)\n        .await\n        .or_throw_msg(&ctx, &[\"Can't read \\\"\", &path, \"\\\"\"].concat())?;\n\n    handle_read_file_bytes(&ctx, options, bytes)\n}\n\npub fn read_file_sync(\n    ctx: Ctx<'_>,\n    path: String,\n    options: Opt<Either<String, ReadFileOptions>>,\n) -> Result<Value<'_>> {\n    let bytes =\n        std::fs::read(&path).or_throw_msg(&ctx, &[\"Can't read \\\"\", &path, \"\\\"\"].concat())?;\n\n    handle_read_file_bytes(&ctx, options, bytes)\n}\n\npub(crate) fn handle_read_file_bytes<'a>(\n    ctx: &Ctx<'a>,\n    options: Opt<Either<String, ReadFileOptions>>,\n    bytes: Vec<u8>,\n) -> Result<Value<'a>> {\n    let buffer = Buffer(bytes);\n\n    if let Some(options) = options.0 {\n        let encoding = match options {\n            Either::Left(encoding) => Some(encoding),\n            Either::Right(options) => options.encoding,\n        };\n\n        if let Some(encoding) = encoding {\n            return buffer\n                .to_string(ctx, &encoding)\n                .and_then(|s| s.into_js(ctx));\n        }\n    }\n\n    buffer.into_js(ctx)\n}\n\npub(crate) struct ReadFileOptions {\n    pub encoding: Option<String>,\n}\n\nimpl<'js> FromJs<'js> for ReadFileOptions {\n    fn from_js(_ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        let ty_name = value.type_name();\n        let obj = value\n            .as_object()\n            .ok_or(Error::new_from_js(ty_name, \"Object\"))?;\n\n        let encoding = obj.get_optional::<_, String>(\"encoding\")?;\n\n        Ok(Self { encoding })\n    }\n}\n"
  },
  {
    "path": "modules/llrt_fs/src/rename.rs",
    "content": "use llrt_utils::result::ResultExt;\nuse rquickjs::{Ctx, Result};\n\npub(crate) fn rename_error(from: &str, to: &str) -> String {\n    [\n        \"Can't rename file/folder from \\\"\",\n        from,\n        \"\\\" to \\\"\",\n        to,\n        \"\\\"\",\n    ]\n    .concat()\n}\n\npub async fn rename(ctx: Ctx<'_>, old_path: String, new_path: String) -> Result<()> {\n    tokio::fs::rename(&old_path, &new_path)\n        .await\n        .or_throw_msg(&ctx, &rename_error(&old_path, &new_path))?;\n    Ok(())\n}\n\npub fn rename_sync(ctx: Ctx<'_>, old_path: String, new_path: String) -> Result<()> {\n    std::fs::rename(&old_path, &new_path)\n        .or_throw_msg(&ctx, &rename_error(&old_path, &new_path))?;\n    Ok(())\n}\n"
  },
  {
    "path": "modules/llrt_fs/src/rm.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{function::Opt, Ctx, Object, Result};\nuse tokio::fs;\n\n#[allow(clippy::manual_async_fn)]\npub async fn rmdir<'js>(ctx: Ctx<'js>, path: String, options: Opt<Object<'js>>) -> Result<()> {\n    let recursive = get_params_rm_dir(options);\n\n    if recursive {\n        fs::remove_dir_all(&path).await\n    } else {\n        fs::remove_dir(&path).await\n    }\n    .or_throw_msg(&ctx, &[\"Can't remove dir \\\"\", &path, \"\\\"\"].concat())?;\n\n    Ok(())\n}\n\n#[allow(clippy::manual_async_fn)]\npub fn rmdir_sync<'js>(ctx: Ctx<'js>, path: String, options: Opt<Object<'js>>) -> Result<()> {\n    let recursive = get_params_rm_dir(options);\n\n    if recursive {\n        std::fs::remove_dir_all(&path)\n    } else {\n        std::fs::remove_dir(&path)\n    }\n    .or_throw_msg(&ctx, &[\"Can't remove dir \\\"\", &path, \"\\\"\"].concat())?;\n\n    Ok(())\n}\n\npub async fn rmfile<'js>(ctx: Ctx<'js>, path: String, options: Opt<Object<'js>>) -> Result<()> {\n    let (recursive, force) = get_params_rm(options);\n\n    let res = async move {\n        let is_dir = fs::metadata(&path)\n            .await\n            .map(|metadata| metadata.is_dir())\n            .or_throw(&ctx)?;\n\n        (if is_dir && recursive {\n            fs::remove_dir_all(&path).await\n        } else if is_dir && !recursive {\n            fs::remove_dir(&path).await\n        } else {\n            fs::remove_file(&path).await\n        })\n        .or_throw_msg(&ctx, &[\"Can't remove file \\\"\", &path, \"\\\"\"].concat())?;\n\n        Ok(())\n    }\n    .await;\n\n    if !force {\n        return res;\n    }\n\n    Ok(())\n}\n\npub fn rmfile_sync(path: String, options: Opt<Object<'_>>) -> Result<()> {\n    let (recursive, force) = get_params_rm(options);\n\n    let res = (|| -> Result<()> {\n        let is_dir = std::fs::metadata(&path).map(|metadata| metadata.is_dir())?;\n\n        (if is_dir && recursive {\n            std::fs::remove_dir_all(&path)\n        } else if is_dir && !recursive {\n            std::fs::remove_dir(&path)\n        } else {\n            std::fs::remove_file(&path)\n        })?;\n\n        Ok(())\n    })();\n\n    if !force {\n        return res;\n    }\n\n    Ok(())\n}\n\nfn get_params_rm_dir(options: Opt<Object>) -> bool {\n    let mut recursive = false;\n\n    if let Some(options) = options.0 {\n        recursive = options.get(\"recursive\").unwrap_or_default();\n    }\n    recursive\n}\n\nfn get_params_rm(options: Opt<Object>) -> (bool, bool) {\n    let mut recursive = false;\n    let mut force = false;\n\n    if let Some(options) = options.0 {\n        recursive = options.get(\"recursive\").unwrap_or_default();\n        force = options.get(\"force\").unwrap_or_default();\n    }\n    (recursive, force)\n}\n"
  },
  {
    "path": "modules/llrt_fs/src/stats.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#[cfg(unix)]\nuse std::os::unix::fs::FileTypeExt;\n#[cfg(unix)]\nuse std::os::unix::fs::MetadataExt;\n#[cfg(windows)]\nuse std::os::windows::fs::MetadataExt;\n#[allow(unused_imports)]\nuse std::{\n    fs::Metadata,\n    time::{Duration, SystemTime},\n};\n\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{Ctx, Result};\nuse tokio::fs;\n\n// The Stats implementation is very much based on Unix. The Windows implementation\n// tries its best to mimic the implementation of libuv since it is the standard.\n// See: https://github.com/libuv/libuv/blob/90648ea3e55125a5a819b32106da6462da310da6/src/win/fs.c\n//\n// By comparison, the Deno implementation is very basic and doesn't even try much.\n// See: https://github.com/denoland/deno/blob/c9da27e147d0681724dd647593abbaa46417feb7/ext/io/fs.rs#L114-L182\n//\n// This implementation doesn't handle files created before UNIX_EPOCH.\n\n#[rquickjs::class]\n#[derive(rquickjs::class::Trace, rquickjs::JsLifetime)]\npub struct Stats {\n    #[qjs(skip_trace)]\n    metadata: Metadata,\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl Stats {\n    #[qjs(skip)]\n    pub fn new(metadata: Metadata) -> Self {\n        Self { metadata }\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn dev(&self) -> u64 {\n        #[cfg(unix)]\n        {\n            self.metadata.dev()\n        }\n        #[cfg(not(unix))]\n        {\n            // Unstable feature, see https://github.com/rust-lang/rust/issues/63010\n            0\n        }\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn ino(&self) -> u64 {\n        #[cfg(unix)]\n        {\n            self.metadata.ino()\n        }\n        #[cfg(not(unix))]\n        {\n            // Unstable feature, see https://github.com/rust-lang/rust/issues/63010\n            0\n        }\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn mode(&self) -> u32 {\n        #[cfg(unix)]\n        {\n            self.metadata.mode()\n        }\n        #[cfg(not(unix))]\n        {\n            0o666\n        }\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn nlink(&self) -> u64 {\n        #[cfg(unix)]\n        {\n            self.metadata.nlink()\n        }\n        #[cfg(not(unix))]\n        {\n            // Unstable feature, see https://github.com/rust-lang/rust/issues/63010\n            1\n        }\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn uid(&self) -> u32 {\n        #[cfg(unix)]\n        {\n            self.metadata.uid()\n        }\n        #[cfg(not(unix))]\n        {\n            0\n        }\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn gid(&self) -> u32 {\n        #[cfg(unix)]\n        {\n            self.metadata.gid()\n        }\n        #[cfg(not(unix))]\n        {\n            0\n        }\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn rdev(&self) -> u64 {\n        #[cfg(unix)]\n        {\n            self.metadata.rdev()\n        }\n        #[cfg(not(unix))]\n        {\n            0\n        }\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn size(&self) -> u64 {\n        #[cfg(unix)]\n        {\n            self.metadata.size()\n        }\n        #[cfg(windows)]\n        {\n            if self.metadata.is_dir() {\n                0\n            } else {\n                self.metadata.file_size()\n            }\n        }\n        #[cfg(not(any(unix, windows)))]\n        {\n            0\n        }\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn blksize(&self) -> u64 {\n        #[cfg(unix)]\n        {\n            self.metadata.blksize()\n        }\n        #[cfg(not(unix))]\n        {\n            4096\n        }\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn blocks(&self) -> u64 {\n        #[cfg(unix)]\n        {\n            self.metadata.blocks()\n        }\n        #[cfg(not(unix))]\n        {\n            0\n        }\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn atime_ms(&self, ctx: Ctx<'_>) -> Result<u64> {\n        #[cfg(unix)]\n        {\n            _ = ctx;\n            Ok(self.metadata.atime_nsec() as u64 / 1e6 as u64)\n        }\n        #[cfg(not(unix))]\n        {\n            self.metadata.accessed().map(to_msec).or_throw(&ctx)\n        }\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn mtime_ms(&self, ctx: Ctx<'_>) -> Result<u64> {\n        #[cfg(unix)]\n        {\n            _ = ctx;\n            Ok(self.metadata.mtime_nsec() as u64 / 1e6 as u64)\n        }\n        #[cfg(not(unix))]\n        {\n            self.metadata.modified().map(to_msec).or_throw(&ctx)\n        }\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn ctime_ms(&self, ctx: Ctx<'_>) -> Result<u64> {\n        #[cfg(unix)]\n        {\n            _ = ctx;\n            Ok(self.metadata.ctime_nsec() as u64 / 1e6 as u64)\n        }\n        #[cfg(not(unix))]\n        {\n            self.metadata.modified().map(to_msec).or_throw(&ctx)\n        }\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn birthtime_ms(&self, ctx: Ctx<'_>) -> Result<u64> {\n        self.metadata\n            .created()\n            .or_throw(&ctx)\n            .and_then(|c| c.elapsed().or_throw(&ctx))\n            .map(|d| d.as_millis() as u64)\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn atime(&self, ctx: Ctx<'_>) -> Result<SystemTime> {\n        self.metadata.accessed().or_throw(&ctx)\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn mtime(&self, ctx: Ctx<'_>) -> Result<SystemTime> {\n        self.metadata.modified().or_throw(&ctx)\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn ctime(&self, ctx: Ctx<'_>) -> Result<SystemTime> {\n        #[cfg(unix)]\n        {\n            _ = ctx;\n            Ok(SystemTime::UNIX_EPOCH + Duration::from_nanos(self.metadata.ctime_nsec() as u64))\n        }\n        #[cfg(not(unix))]\n        {\n            self.metadata.modified().or_throw(&ctx)\n        }\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn birthtime(&self, ctx: Ctx<'_>) -> Result<SystemTime> {\n        self.metadata.created().or_throw(&ctx)\n    }\n\n    pub fn is_file(&self) -> bool {\n        self.metadata.is_file()\n    }\n\n    /// @deprecated Use `is_directory` instead\n    pub fn is_dir(&self) -> bool {\n        self.metadata.is_dir()\n    }\n\n    pub fn is_directory(&self) -> bool {\n        self.metadata.is_dir()\n    }\n\n    /// @deprecated Use `is_symbolic_link` instead\n    pub fn is_symlink(&self) -> bool {\n        self.metadata.is_symlink()\n    }\n\n    pub fn is_symbolic_link(&self) -> bool {\n        self.metadata.is_symlink()\n    }\n\n    #[qjs(rename = \"isFIFO\")]\n    pub fn is_fifo(&self) -> bool {\n        #[cfg(unix)]\n        {\n            self.metadata.file_type().is_fifo()\n        }\n        #[cfg(not(unix))]\n        {\n            false\n        }\n    }\n\n    pub fn is_block_device(&self) -> bool {\n        #[cfg(unix)]\n        {\n            self.metadata.file_type().is_block_device()\n        }\n        #[cfg(not(unix))]\n        {\n            false\n        }\n    }\n\n    pub fn is_character_device(&self) -> bool {\n        #[cfg(unix)]\n        {\n            self.metadata.file_type().is_char_device()\n        }\n        #[cfg(not(unix))]\n        {\n            false\n        }\n    }\n\n    pub fn is_socket(&self) -> bool {\n        #[cfg(unix)]\n        {\n            self.metadata.file_type().is_socket()\n        }\n        #[cfg(not(unix))]\n        {\n            false\n        }\n    }\n}\n\npub async fn stat_fn(ctx: Ctx<'_>, path: String) -> Result<Stats> {\n    let metadata = fs::metadata(&path)\n        .await\n        .or_throw_msg(&ctx, &[\"Can't stat \\\"\", &path, \"\\\"\"].concat())?;\n\n    let stats = Stats::new(metadata);\n\n    Ok(stats)\n}\n\npub fn stat_fn_sync(ctx: Ctx<'_>, path: String) -> Result<Stats> {\n    let metadata =\n        std::fs::metadata(&path).or_throw_msg(&ctx, &[\"Can't stat \\\"\", &path, \"\\\"\"].concat())?;\n\n    let stats = Stats::new(metadata);\n\n    Ok(stats)\n}\n\npub async fn lstat_fn(ctx: Ctx<'_>, path: String) -> Result<Stats> {\n    let metadata = fs::symlink_metadata(&path)\n        .await\n        .or_throw_msg(&ctx, &[\"Can't lstat \\\"\", &path, \"\\\"\"].concat())?;\n\n    let stats = Stats::new(metadata);\n\n    Ok(stats)\n}\n\npub fn lstat_fn_sync(ctx: Ctx<'_>, path: String) -> Result<Stats> {\n    let metadata = std::fs::symlink_metadata(&path)\n        .or_throw_msg(&ctx, &[\"Can't lstat \\\"\", &path, \"\\\"\"].concat())?;\n\n    let stats = Stats::new(metadata);\n\n    Ok(stats)\n}\n\n#[allow(dead_code)]\n#[inline(always)]\nfn to_msec(time: SystemTime) -> u64 {\n    time.duration_since(SystemTime::UNIX_EPOCH)\n        .map(|t| t.as_millis() as u64)\n        .unwrap_or_else(|err| err.duration().as_millis() as u64)\n}\n"
  },
  {
    "path": "modules/llrt_fs/src/symlink.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nuse std::io;\n\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{function::Opt, Ctx, Result};\n\nfn symlink_blocking(target: &str, path: &str, type_value: Option<String>) -> io::Result<()> {\n    #[cfg(unix)]\n    {\n        _ = type_value;\n        std::os::unix::fs::symlink(target, path)\n    }\n    #[cfg(windows)]\n    {\n        let type_str = match type_value.as_deref() {\n            Some(t @ (\"file\" | \"dir\" | \"junction\")) => t,\n            _ => {\n                if std::fs::metadata(target)\n                    .map(|m| m.is_dir())\n                    .unwrap_or(false)\n                {\n                    \"dir\"\n                } else {\n                    \"file\"\n                }\n            },\n        };\n        match type_str {\n            \"junction\" => junction::create(target, path),\n            \"dir\" => std::os::windows::fs::symlink_dir(target, path),\n            _ => std::os::windows::fs::symlink_file(target, path),\n        }\n    }\n}\n\npub async fn symlink<'js>(\n    ctx: Ctx<'js>,\n    target: String,\n    path: String,\n    type_value: Opt<String>,\n) -> Result<()> {\n    let path_clone = path.clone();\n\n    tokio::task::spawn_blocking(move || symlink_blocking(&target, &path_clone, type_value.0))\n        .await\n        .map_err(io::Error::other)?\n        .or_throw_msg(&ctx, &[\"Can't create symlink \\\"\", &path, \"\\\"\"].concat())\n}\n\npub fn symlink_sync<'js>(\n    ctx: Ctx<'js>,\n    target: String,\n    path: String,\n    type_value: Opt<String>,\n) -> Result<()> {\n    symlink_blocking(&target, &path, type_value.0)\n        .or_throw_msg(&ctx, &[\"Can't create symlink \\\"\", &path, \"\\\"\"].concat())\n}\n"
  },
  {
    "path": "modules/llrt_fs/src/write_file.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nuse either::Either;\nuse llrt_utils::{bytes::ObjectBytes, object::ObjectExt, result::ResultExt};\nuse rquickjs::{function::Opt, Ctx, Error, FromJs, Result, Value};\nuse tokio::fs;\nuse tokio::io::AsyncWriteExt;\n\npub async fn write_file<'js>(\n    ctx: Ctx<'js>,\n    path: String,\n    data: Value<'js>,\n    options: Opt<Either<String, WriteFileOptions>>,\n) -> Result<()> {\n    let write_error_message = &[\"Can't write file \\\"\", &path, \"\\\"\"].concat();\n\n    let mut file = fs::File::create(&path)\n        .await\n        .or_throw_msg(&ctx, write_error_message)?;\n\n    #[cfg(unix)]\n    if let Some(Either::Right(opts)) = options.0 {\n        use std::os::unix::fs::PermissionsExt;\n\n        let perm = PermissionsExt::from_mode(opts.mode.unwrap_or(0o666));\n        file.set_permissions(perm)\n            .await\n            .or_throw_msg(&ctx, write_error_message)?;\n    }\n    #[cfg(not(unix))]\n    {\n        _ = options;\n        if let Some(Either::Right(opts)) = options.0 {\n            _ = opts.mode;\n        }\n    }\n\n    let bytes = ObjectBytes::from(&ctx, &data)?;\n    file.write_all(bytes.as_bytes(&ctx)?)\n        .await\n        .or_throw_msg(&ctx, write_error_message)?;\n    file.flush().await.or_throw_msg(&ctx, write_error_message)?;\n\n    Ok(())\n}\n\npub fn write_file_sync<'js>(\n    ctx: Ctx<'js>,\n    path: String,\n    bytes: ObjectBytes<'js>,\n    options: Opt<Either<String, WriteFileOptions>>,\n) -> Result<()> {\n    let write_error_message = &[\"Can't write file \\\"\", &path, \"\\\"\"].concat();\n    std::fs::write(&path, bytes.as_bytes(&ctx)?).or_throw_msg(&ctx, write_error_message)?;\n\n    #[cfg(unix)]\n    {\n        if let Some(Either::Right(opts)) = options.0 {\n            use std::os::unix::fs::PermissionsExt;\n\n            std::fs::set_permissions(path, PermissionsExt::from_mode(opts.mode.unwrap_or(0o666)))\n                .or_throw_msg(&ctx, write_error_message)?;\n        }\n    }\n    #[cfg(not(unix))]\n    {\n        _ = options;\n        if let Some(Either::Right(opts)) = options.0 {\n            _ = opts.mode;\n        }\n    }\n\n    Ok(())\n}\n\npub(crate) struct WriteFileOptions {\n    pub mode: Option<u32>,\n}\n\nimpl<'js> FromJs<'js> for WriteFileOptions {\n    fn from_js(_ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        let ty_name = value.type_name();\n        let obj = value\n            .as_object()\n            .ok_or(Error::new_from_js(ty_name, \"Object\"))?;\n\n        let mode = obj.get_optional::<_, u32>(\"mode\")?;\n\n        Ok(Self { mode })\n    }\n}\n"
  },
  {
    "path": "modules/llrt_http/Cargo.toml",
    "content": "[package]\nname = \"llrt_http\"\ndescription = \"LLRT Module http & https\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\nreadme = \"README.md\"\n\n[lib]\nname = \"llrt_http\"\npath = \"src/lib.rs\"\n\n[features]\ndefault = [\"http1\", \"http2\", \"webpki-roots\", \"tls-ring\"]\n\nhttp1 = [\"hyper/http1\", \"hyper-rustls?/http1\", \"hyper-util/http1\"]\nhttp2 = [\"hyper/http2\", \"hyper-rustls?/http2\", \"hyper-util/http2\"]\n\nwebpki-roots = [\"llrt_tls/webpki-roots\"]\nnative-roots = [\"llrt_tls/native-roots\"]\n\n# TLS crypto backend features (rustls-based)\ntls-ring = [\n  \"http1\",\n  \"llrt_tls/tls-ring\",\n  \"dep:hyper-rustls\",\n  \"hyper-rustls/ring\",\n  \"dep:rustls\",\n]\ntls-aws-lc = [\n  \"http1\",\n  \"llrt_tls/tls-aws-lc\",\n  \"dep:hyper-rustls\",\n  \"hyper-rustls/aws-lc-rs\",\n  \"dep:rustls\",\n]\ntls-graviola = [\n  \"http1\",\n  \"llrt_tls/tls-graviola\",\n  \"dep:hyper-rustls\",\n  \"dep:rustls\",\n]\n\n# OpenSSL TLS backend\ntls-openssl = [\n  \"http1\",\n  \"llrt_tls/tls-openssl\",\n  \"dep:hyper-openssl\",\n  \"dep:openssl\",\n]\n\n[dependencies]\nbytes = { version = \"1\", default-features = false }\nhttp-body-util = { version = \"0.1\", default-features = false }\nhyper = { version = \"1\", features = [\"client\"], default-features = false }\nhyper-util = { version = \"0.1\", features = [\n  \"client-legacy\",\n  \"tokio\",\n], default-features = false }\nhyper-rustls = { version = \"0.27\", default-features = false, optional = true }\nhyper-openssl = { version = \"0.10\", features = [\n  \"client-legacy\",\n], optional = true }\nopenssl = { version = \"0.10\", optional = true }\nllrt_dns_cache = { version = \"0.8.1-beta\", path = \"../../libs/llrt_dns_cache\" }\nllrt_tls = { version = \"0.8.1-beta\", default-features = false, path = \"../llrt_tls\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nonce_cell = { version = \"1\", features = [\"std\"], default-features = false }\nrquickjs = { version = \"0.11\", features = [\n  \"either\",\n  \"std\",\n], default-features = false }\nrustls = { version = \"0.23\", features = [\n  \"tls12\",\n], default-features = false, optional = true }\n\n[dev-dependencies]\n"
  },
  {
    "path": "modules/llrt_http/src/agent.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_utils::result::ResultExt;\nuse llrt_utils::{any_of::AnyOf4, bytes::ObjectBytes, object::ObjectExt};\nuse rquickjs::{prelude::Opt, Ctx, Error, FromJs, Result, Value};\n\nuse crate::HyperClient;\n\n#[rquickjs::class]\n#[derive(rquickjs::JsLifetime, rquickjs::class::Trace)]\npub struct Agent {\n    #[qjs(skip_trace)]\n    client: HyperClient,\n}\n\nimpl Agent {\n    pub fn client(&self) -> HyperClient {\n        self.client.clone()\n    }\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl Agent {\n    #[qjs(constructor)]\n    pub fn new<'js>(ctx: Ctx<'js>, options: Opt<AgentOptions>) -> Result<Self> {\n        let mut reject_unauthorized = true;\n        let mut ca = None;\n\n        if let Some(options) = options.0 {\n            if let Some(opt_reject_unauthorized) = options.reject_unauthorized {\n                reject_unauthorized = opt_reject_unauthorized;\n            }\n            if let Some(opt_ca) = options.ca {\n                ca = Some(opt_ca);\n            }\n        }\n\n        let config = llrt_tls::build_client_config(llrt_tls::BuildClientConfigOptions {\n            reject_unauthorized,\n            ca,\n        })\n        .or_throw_msg(&ctx, \"Failed to build TLS config\")?;\n        let client =\n            crate::build_client(Some(config)).or_throw_msg(&ctx, \"Failed to build HTTP client\")?;\n\n        Ok(Self { client })\n    }\n}\n\npub struct AgentOptions {\n    reject_unauthorized: Option<bool>,\n    ca: Option<Vec<Vec<u8>>>,\n}\n\nimpl<'js> FromJs<'js> for AgentOptions {\n    fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        let ty_name = value.type_name();\n        let obj = value\n            .as_object()\n            .ok_or(Error::new_from_js(ty_name, \"Object\"))?;\n\n        let reject_unauthorized = obj.get_optional::<_, bool>(\"rejectUnauthorized\")?;\n        let ca = obj\n            .get_optional::<_, AnyOf4<String, Vec<String>, ObjectBytes, Vec<ObjectBytes>>>(\"ca\")?\n            .map(|ca| {\n                let ca = match ca {\n                    AnyOf4::A(ca) => vec![ca.into_bytes()],\n                    AnyOf4::B(ca) => ca.into_iter().map(|ca| ca.into_bytes()).collect(),\n                    AnyOf4::C(ca) => vec![ca.into_bytes(ctx)?],\n                    AnyOf4::D(ca) => ca\n                        .into_iter()\n                        .map(|ca| ca.into_bytes(ctx))\n                        .collect::<Result<Vec<_>>>()?,\n                };\n                Ok::<_, Error>(ca)\n            })\n            .transpose()?;\n\n        Ok(Self {\n            reject_unauthorized,\n            ca,\n        })\n    }\n}\n"
  },
  {
    "path": "modules/llrt_http/src/client.rs",
    "content": "use std::convert::Infallible;\n\nuse bytes::Bytes;\nuse http_body_util::combinators::BoxBody;\nuse hyper_util::{\n    client::legacy::{connect::HttpConnector, Client},\n    rt::{TokioExecutor, TokioTimer},\n};\nuse llrt_dns_cache::CachedDnsResolver;\nuse once_cell::sync::Lazy;\n\nuse crate::get_pool_idle_timeout;\n\n#[cfg(any(feature = \"tls-ring\", feature = \"tls-aws-lc\", feature = \"tls-graviola\"))]\nuse crate::get_http_version;\n\n// Rustls-based TLS backends\n#[cfg(any(feature = \"tls-ring\", feature = \"tls-aws-lc\", feature = \"tls-graviola\"))]\nmod rustls_client {\n    use super::*;\n    use hyper_rustls::HttpsConnector;\n    use llrt_tls::TLS_CONFIG;\n    use rustls::ClientConfig;\n\n    #[cfg(feature = \"http2\")]\n    use crate::HttpVersion;\n\n    pub type HyperClient =\n        Client<HttpsConnector<HttpConnector<CachedDnsResolver>>, BoxBody<Bytes, Infallible>>;\n\n    pub static HTTP_CLIENT: Lazy<Result<HyperClient, Box<dyn std::error::Error + Send + Sync>>> =\n        Lazy::new(|| build_client(None));\n\n    pub fn build_client(\n        tls_config: Option<ClientConfig>,\n    ) -> Result<HyperClient, Box<dyn std::error::Error + Send + Sync>> {\n        let pool_idle_timeout = get_pool_idle_timeout();\n\n        let config = if let Some(tls_config) = tls_config {\n            tls_config\n        } else {\n            match &*TLS_CONFIG {\n                Ok(tls_config) => tls_config.clone(),\n                Err(e) => return Err(e.to_string().into()),\n            }\n        };\n\n        let builder = hyper_rustls::HttpsConnectorBuilder::new()\n            .with_tls_config(config)\n            .https_or_http();\n\n        let mut cache_dns_connector = CachedDnsResolver::new().into_http_connector();\n        cache_dns_connector.enforce_http(false);\n\n        let https = match get_http_version() {\n            #[cfg(feature = \"http2\")]\n            HttpVersion::Http2 => builder\n                .enable_all_versions()\n                .wrap_connector(cache_dns_connector),\n            _ => builder.enable_http1().wrap_connector(cache_dns_connector),\n        };\n\n        Ok(Client::builder(TokioExecutor::new())\n            .pool_idle_timeout(pool_idle_timeout)\n            .pool_timer(TokioTimer::new())\n            .build(https))\n    }\n}\n\n// OpenSSL TLS backend\n#[cfg(feature = \"tls-openssl\")]\nmod openssl_client {\n    use super::*;\n    use hyper_openssl::client::legacy::HttpsConnector;\n    use llrt_tls::TLS_CONFIG;\n    use openssl::ssl::SslConnectorBuilder;\n\n    pub type HyperClient =\n        Client<HttpsConnector<HttpConnector<CachedDnsResolver>>, BoxBody<Bytes, Infallible>>;\n\n    pub static HTTP_CLIENT: Lazy<Result<HyperClient, Box<dyn std::error::Error + Send + Sync>>> =\n        Lazy::new(|| build_client(None));\n\n    pub fn build_client(\n        tls_config: Option<SslConnectorBuilder>,\n    ) -> Result<HyperClient, Box<dyn std::error::Error + Send + Sync>> {\n        let pool_idle_timeout = get_pool_idle_timeout();\n\n        let connector = if let Some(tls_config) = tls_config {\n            tls_config\n        } else {\n            match TLS_CONFIG.as_ref() {\n                Ok(_builder) => {\n                    // Clone the builder by creating a new one with same settings\n                    llrt_tls::build_client_config(llrt_tls::BuildClientConfigOptions {\n                        reject_unauthorized: true,\n                        ca: None,\n                    })?\n                },\n                Err(e) => return Err(e.to_string().into()),\n            }\n        };\n\n        let mut cache_dns_connector = CachedDnsResolver::new().into_http_connector();\n        cache_dns_connector.enforce_http(false);\n\n        let mut https = HttpsConnector::with_connector(cache_dns_connector, connector)?;\n        https.set_callback(|ssl, _| {\n            #[cfg(feature = \"http2\")]\n            ssl.set_alpn_protos(b\"\\x02h2\\x08http/1.1\")?;\n            #[cfg(not(feature = \"http2\"))]\n            ssl.set_alpn_protos(b\"\\x08http/1.1\")?;\n            Ok(())\n        });\n\n        Ok(Client::builder(TokioExecutor::new())\n            .pool_idle_timeout(pool_idle_timeout)\n            .pool_timer(TokioTimer::new())\n            .build(https))\n    }\n}\n\n// Re-export based on feature\n#[cfg(any(feature = \"tls-ring\", feature = \"tls-aws-lc\", feature = \"tls-graviola\"))]\npub use rustls_client::*;\n\n#[cfg(feature = \"tls-openssl\")]\npub use openssl_client::*;\n"
  },
  {
    "path": "modules/llrt_http/src/config.rs",
    "content": "use std::{\n    sync::{\n        atomic::{AtomicU64, Ordering},\n        OnceLock,\n    },\n    time::Duration,\n};\n\nstatic CONNECTION_POOL_IDLE_TIMEOUT: AtomicU64 = AtomicU64::new(15);\n\npub fn set_pool_idle_timeout_seconds(seconds: u64) {\n    CONNECTION_POOL_IDLE_TIMEOUT.store(seconds, Ordering::Relaxed);\n}\n\npub fn get_pool_idle_timeout() -> Duration {\n    Duration::from_secs(CONNECTION_POOL_IDLE_TIMEOUT.load(Ordering::Relaxed))\n}\n\n#[derive(Debug, Clone, Copy)]\npub enum HttpVersion {\n    Http1_1,\n    Http2,\n}\n\nstatic HTTP_VERSION: OnceLock<HttpVersion> = OnceLock::new();\n\npub fn set_http_version(version: HttpVersion) {\n    _ = HTTP_VERSION.set(version);\n}\n\npub fn get_http_version() -> HttpVersion {\n    *HTTP_VERSION.get_or_init(|| {\n        #[cfg(all(feature = \"http2\", feature = \"http1\"))]\n        {\n            HttpVersion::Http1_1\n        }\n        #[cfg(all(not(feature = \"http1\"), feature = \"http2\"))]\n        {\n            HttpVersion::Http2\n        }\n        #[cfg(all(not(feature = \"http2\"), feature = \"http1\"))]\n        {\n            HttpVersion::Http1_1\n        }\n        #[cfg(all(not(feature = \"http2\"), not(feature = \"http1\")))]\n        {\n            compile_error!(\"Either the `http1` or `http2` feature must be enabled\")\n        }\n    })\n}\n"
  },
  {
    "path": "modules/llrt_http/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_utils::module::{export_default, ModuleInfo};\nuse rquickjs::{\n    module::{Declarations, Exports, ModuleDef},\n    Ctx, Result,\n};\n\npub use self::config::*;\n\n#[cfg(any(\n    feature = \"tls-ring\",\n    feature = \"tls-aws-lc\",\n    feature = \"tls-graviola\",\n    feature = \"tls-openssl\"\n))]\nmod client;\nmod config;\n\n#[cfg(any(\n    feature = \"tls-ring\",\n    feature = \"tls-aws-lc\",\n    feature = \"tls-graviola\",\n    feature = \"tls-openssl\"\n))]\nmod agent;\n\n#[cfg(any(\n    feature = \"tls-ring\",\n    feature = \"tls-aws-lc\",\n    feature = \"tls-graviola\",\n    feature = \"tls-openssl\"\n))]\npub use self::{agent::Agent, client::*};\n\npub struct HttpsModule;\n\nimpl ModuleDef for HttpsModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        #[cfg(any(\n            feature = \"tls-ring\",\n            feature = \"tls-aws-lc\",\n            feature = \"tls-graviola\",\n            feature = \"tls-openssl\"\n        ))]\n        declare.declare(stringify!(Agent))?;\n        declare.declare(\"default\")?;\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        export_default(ctx, exports, |default| {\n            #[cfg(any(\n                feature = \"tls-ring\",\n                feature = \"tls-aws-lc\",\n                feature = \"tls-graviola\",\n                feature = \"tls-openssl\"\n            ))]\n            rquickjs::Class::<Agent>::define(default)?;\n\n            let _ = default;\n            Ok(())\n        })\n    }\n}\n\nimpl From<HttpsModule> for ModuleInfo<HttpsModule> {\n    fn from(val: HttpsModule) -> Self {\n        ModuleInfo {\n            name: \"https\",\n            module: val,\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_intl/Cargo.toml",
    "content": "[package]\nname = \"llrt_intl\"\ndescription = \"LLRT Intl module - minimal internationalization support\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\nreadme = \"README.md\"\n\n[lib]\nname = \"llrt_intl\"\npath = \"src/lib.rs\"\n\n[dependencies]\nitoa = \"1.0\"\njiff = { version = \"0.2\" }\nrquickjs = { version = \"0.11\", default-features = false }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\" }\n"
  },
  {
    "path": "modules/llrt_intl/README.md",
    "content": "# llrt_intl\n\nMinimal internationalization support for LLRT. Provides a subset of `Intl` functionality focused on timezone support.\n\n## Features\n\n- **Intl.DateTimeFormat** - Minimal implementation supporting `format()`, `formatToParts()`, and `resolvedOptions()`\n- **Date.prototype.toLocaleString** - Enhanced to support the `timeZone` option\n- **dayjs compatibility** - Enables the dayjs timezone plugin without polyfills\n\n## API\n\n### `Intl.DateTimeFormat`\n\nMinimal implementation for timezone-aware date formatting.\n\n### `Date.prototype.toLocaleString`\n\nEnhanced to support the `timeZone` option for timezone conversion.\n\n## Examples\n\n### Intl.DateTimeFormat\n\n```javascript\nconst formatter = new Intl.DateTimeFormat(\"en-US\", {\n  timeZone: \"America/Denver\",\n  hour12: false,\n  year: \"numeric\",\n  month: \"2-digit\",\n  day: \"2-digit\",\n  hour: \"2-digit\",\n  minute: \"2-digit\",\n  second: \"2-digit\",\n});\n\nconst date = new Date(\"2022-03-02T15:45:34Z\");\nconsole.log(formatter.format(date)); // \"03/02/2022, 08:45:34\"\n```\n\n### Using with dayjs\n\n```javascript\nconst dayjs = require(\"dayjs\");\nconst utc = require(\"dayjs/plugin/utc\");\nconst timezone = require(\"dayjs/plugin/timezone\");\n\ndayjs.extend(utc);\ndayjs.extend(timezone);\n\nconst date = dayjs(\"2022-03-02T15:45:34Z\");\nconsole.log(date.tz(\"America/Denver\").format()); // \"2022-03-02T08:45:34-07:00\"\nconsole.log(date.tz(\"Asia/Tokyo\").format()); // \"2022-03-03T00:45:34+09:00\"\n```\n"
  },
  {
    "path": "modules/llrt_intl/src/cldr_data.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\n//! Baked CLDR locale data for date/time formatting.\n//!\n//! This module contains pre-extracted patterns from the Unicode CLDR project\n//! for a subset of common locales, enabling locale-aware date/time formatting\n//! without requiring the full ICU library.\n//!\n//! Data sourced from: https://github.com/unicode-org/cldr-json\n\n/// Locale-specific date/time formatting data\n#[derive(Debug, Clone)]\npub struct LocaleData {\n    /// Date format patterns (full, long, medium, short)\n    pub date_formats: DateFormats,\n    /// Time format patterns (full, long, medium, short)\n    pub time_formats: TimeFormats,\n    /// Pattern for combining date and time (e.g., \"{1}, {0}\")\n    pub datetime_pattern: &'static str,\n    /// Month names (wide format, 1-indexed internally but stored 0-indexed)\n    pub months_wide: [&'static str; 12],\n    /// Month names (abbreviated format)\n    pub months_abbr: [&'static str; 12],\n    /// Weekday names (wide format, 0=Sunday)\n    pub days_wide: [&'static str; 7],\n    /// Weekday names (abbreviated format)\n    pub days_abbr: [&'static str; 7],\n    /// AM marker\n    pub am: &'static str,\n    /// PM marker\n    pub pm: &'static str,\n    /// Whether this locale uses 12-hour time by default\n    pub hour12_default: bool,\n}\n\n/// Date format patterns for different styles\n#[derive(Debug, Clone)]\npub struct DateFormats {\n    pub full: &'static str,\n    pub long: &'static str,\n    pub medium: &'static str,\n    pub short: &'static str,\n}\n\n/// Time format patterns for different styles\n#[derive(Debug, Clone)]\npub struct TimeFormats {\n    pub full: &'static str,\n    pub long: &'static str,\n    pub medium: &'static str,\n    pub short: &'static str,\n}\n\n/// Get locale data for a given locale string.\n/// Falls back to en-US for unknown locales.\npub fn get_locale_data(locale: &str) -> &'static LocaleData {\n    // Normalize locale: lowercase, handle both - and _\n    let locale_lower = locale.to_lowercase().replace('_', \"-\");\n\n    // Try exact match first, then language-only fallback\n    match locale_lower.as_str() {\n        \"en-us\" | \"en\" => &EN_US,\n        \"en-gb\" | \"en-au\" | \"en-nz\" | \"en-ie\" => &EN_GB,\n        \"de\" | \"de-de\" | \"de-at\" | \"de-ch\" => &DE,\n        \"fr\" | \"fr-fr\" | \"fr-ca\" | \"fr-be\" | \"fr-ch\" => &FR,\n        \"es\" | \"es-es\" | \"es-mx\" | \"es-ar\" => &ES,\n        \"it\" | \"it-it\" => &IT,\n        \"pt\" | \"pt-pt\" | \"pt-br\" => &PT,\n        \"nl\" | \"nl-nl\" | \"nl-be\" => &NL,\n        \"ru\" | \"ru-ru\" => &RU,\n        \"ja\" | \"ja-jp\" => &JA,\n        \"ko\" | \"ko-kr\" => &KO,\n        \"zh\" | \"zh-cn\" | \"zh-hans\" => &ZH,\n        \"zh-tw\" | \"zh-hant\" | \"zh-hk\" => &ZH_TW,\n        \"ar\" | \"ar-sa\" | \"ar-eg\" => &AR,\n        // High priority locales\n        \"hi\" | \"hi-in\" => &HI,\n        \"bn\" | \"bn-bd\" | \"bn-in\" => &BN,\n        \"vi\" | \"vi-vn\" => &VI,\n        \"th\" | \"th-th\" => &TH,\n        \"id\" | \"id-id\" => &ID,\n        \"tr\" | \"tr-tr\" => &TR,\n        \"pl\" | \"pl-pl\" => &PL,\n        \"uk\" | \"uk-ua\" => &UK,\n        // Medium priority locales\n        \"sv\" | \"sv-se\" => &SV,\n        \"da\" | \"da-dk\" => &DA,\n        \"nb\" | \"nb-no\" | \"no\" | \"nn\" | \"nn-no\" => &NB,\n        \"fi\" | \"fi-fi\" => &FI,\n        \"cs\" | \"cs-cz\" => &CS,\n        \"el\" | \"el-gr\" => &EL,\n        \"he\" | \"he-il\" | \"iw\" => &HE,\n        \"hu\" | \"hu-hu\" => &HU,\n        \"ro\" | \"ro-ro\" => &RO,\n        // Fallback to en-US\n        _ => {\n            // Try to match just the language part\n            if let Some(lang) = locale_lower.split('-').next() {\n                match lang {\n                    \"en\" => &EN_US,\n                    \"de\" => &DE,\n                    \"fr\" => &FR,\n                    \"es\" => &ES,\n                    \"it\" => &IT,\n                    \"pt\" => &PT,\n                    \"nl\" => &NL,\n                    \"ru\" => &RU,\n                    \"ja\" => &JA,\n                    \"ko\" => &KO,\n                    \"zh\" => &ZH,\n                    \"ar\" => &AR,\n                    \"hi\" => &HI,\n                    \"bn\" => &BN,\n                    \"vi\" => &VI,\n                    \"th\" => &TH,\n                    \"id\" => &ID,\n                    \"tr\" => &TR,\n                    \"pl\" => &PL,\n                    \"uk\" => &UK,\n                    \"sv\" => &SV,\n                    \"da\" => &DA,\n                    \"nb\" | \"no\" | \"nn\" => &NB,\n                    \"fi\" => &FI,\n                    \"cs\" => &CS,\n                    \"el\" => &EL,\n                    \"he\" | \"iw\" => &HE,\n                    \"hu\" => &HU,\n                    \"ro\" => &RO,\n                    _ => &EN_US,\n                }\n            } else {\n                &EN_US\n            }\n        },\n    }\n}\n\n// English (US) - en-US\nstatic EN_US: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE, MMMM d, y\",\n        long: \"MMMM d, y\",\n        medium: \"MMM d, y\",\n        short: \"M/d/yy\",\n    },\n    time_formats: TimeFormats {\n        full: \"h:mm:ss a zzzz\",\n        long: \"h:mm:ss a z\",\n        medium: \"h:mm:ss a\",\n        short: \"h:mm a\",\n    },\n    datetime_pattern: \"{1}, {0}\",\n    months_wide: [\n        \"January\",\n        \"February\",\n        \"March\",\n        \"April\",\n        \"May\",\n        \"June\",\n        \"July\",\n        \"August\",\n        \"September\",\n        \"October\",\n        \"November\",\n        \"December\",\n    ],\n    months_abbr: [\n        \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\",\n    ],\n    days_wide: [\n        \"Sunday\",\n        \"Monday\",\n        \"Tuesday\",\n        \"Wednesday\",\n        \"Thursday\",\n        \"Friday\",\n        \"Saturday\",\n    ],\n    days_abbr: [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"],\n    am: \"AM\",\n    pm: \"PM\",\n    hour12_default: true,\n};\n\n// English (GB) - en-GB\nstatic EN_GB: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE, d MMMM y\",\n        long: \"d MMMM y\",\n        medium: \"d MMM y\",\n        short: \"dd/MM/y\",\n    },\n    time_formats: TimeFormats {\n        full: \"HH:mm:ss zzzz\",\n        long: \"HH:mm:ss z\",\n        medium: \"HH:mm:ss\",\n        short: \"HH:mm\",\n    },\n    datetime_pattern: \"{1}, {0}\",\n    months_wide: [\n        \"January\",\n        \"February\",\n        \"March\",\n        \"April\",\n        \"May\",\n        \"June\",\n        \"July\",\n        \"August\",\n        \"September\",\n        \"October\",\n        \"November\",\n        \"December\",\n    ],\n    months_abbr: [\n        \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\",\n    ],\n    days_wide: [\n        \"Sunday\",\n        \"Monday\",\n        \"Tuesday\",\n        \"Wednesday\",\n        \"Thursday\",\n        \"Friday\",\n        \"Saturday\",\n    ],\n    days_abbr: [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"],\n    am: \"am\",\n    pm: \"pm\",\n    hour12_default: false,\n};\n\n// German - de\nstatic DE: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE, d. MMMM y\",\n        long: \"d. MMMM y\",\n        medium: \"dd.MM.y\",\n        short: \"dd.MM.yy\",\n    },\n    time_formats: TimeFormats {\n        full: \"HH:mm:ss zzzz\",\n        long: \"HH:mm:ss z\",\n        medium: \"HH:mm:ss\",\n        short: \"HH:mm\",\n    },\n    datetime_pattern: \"{1}, {0}\",\n    months_wide: [\n        \"Januar\",\n        \"Februar\",\n        \"März\",\n        \"April\",\n        \"Mai\",\n        \"Juni\",\n        \"Juli\",\n        \"August\",\n        \"September\",\n        \"Oktober\",\n        \"November\",\n        \"Dezember\",\n    ],\n    months_abbr: [\n        \"Jan.\", \"Feb.\", \"März\", \"Apr.\", \"Mai\", \"Juni\", \"Juli\", \"Aug.\", \"Sep.\", \"Okt.\", \"Nov.\",\n        \"Dez.\",\n    ],\n    days_wide: [\n        \"Sonntag\",\n        \"Montag\",\n        \"Dienstag\",\n        \"Mittwoch\",\n        \"Donnerstag\",\n        \"Freitag\",\n        \"Samstag\",\n    ],\n    days_abbr: [\"So.\", \"Mo.\", \"Di.\", \"Mi.\", \"Do.\", \"Fr.\", \"Sa.\"],\n    am: \"AM\",\n    pm: \"PM\",\n    hour12_default: false,\n};\n\n// French - fr\nstatic FR: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE d MMMM y\",\n        long: \"d MMMM y\",\n        medium: \"d MMM y\",\n        short: \"dd/MM/y\",\n    },\n    time_formats: TimeFormats {\n        full: \"HH:mm:ss zzzz\",\n        long: \"HH:mm:ss z\",\n        medium: \"HH:mm:ss\",\n        short: \"HH:mm\",\n    },\n    datetime_pattern: \"{1}, {0}\",\n    months_wide: [\n        \"janvier\",\n        \"février\",\n        \"mars\",\n        \"avril\",\n        \"mai\",\n        \"juin\",\n        \"juillet\",\n        \"août\",\n        \"septembre\",\n        \"octobre\",\n        \"novembre\",\n        \"décembre\",\n    ],\n    months_abbr: [\n        \"janv.\", \"févr.\", \"mars\", \"avr.\", \"mai\", \"juin\", \"juil.\", \"août\", \"sept.\", \"oct.\", \"nov.\",\n        \"déc.\",\n    ],\n    days_wide: [\n        \"dimanche\", \"lundi\", \"mardi\", \"mercredi\", \"jeudi\", \"vendredi\", \"samedi\",\n    ],\n    days_abbr: [\"dim.\", \"lun.\", \"mar.\", \"mer.\", \"jeu.\", \"ven.\", \"sam.\"],\n    am: \"AM\",\n    pm: \"PM\",\n    hour12_default: false,\n};\n\n// Spanish - es\nstatic ES: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE, d 'de' MMMM 'de' y\",\n        long: \"d 'de' MMMM 'de' y\",\n        medium: \"d MMM y\",\n        short: \"d/M/yy\",\n    },\n    time_formats: TimeFormats {\n        full: \"H:mm:ss zzzz\",\n        long: \"H:mm:ss z\",\n        medium: \"H:mm:ss\",\n        short: \"H:mm\",\n    },\n    datetime_pattern: \"{1}, {0}\",\n    months_wide: [\n        \"enero\",\n        \"febrero\",\n        \"marzo\",\n        \"abril\",\n        \"mayo\",\n        \"junio\",\n        \"julio\",\n        \"agosto\",\n        \"septiembre\",\n        \"octubre\",\n        \"noviembre\",\n        \"diciembre\",\n    ],\n    months_abbr: [\n        \"ene\", \"feb\", \"mar\", \"abr\", \"may\", \"jun\", \"jul\", \"ago\", \"sept\", \"oct\", \"nov\", \"dic\",\n    ],\n    days_wide: [\n        \"domingo\",\n        \"lunes\",\n        \"martes\",\n        \"miércoles\",\n        \"jueves\",\n        \"viernes\",\n        \"sábado\",\n    ],\n    days_abbr: [\"dom\", \"lun\", \"mar\", \"mié\", \"jue\", \"vie\", \"sáb\"],\n    am: \"a.\\u{a0}m.\",\n    pm: \"p.\\u{a0}m.\",\n    hour12_default: false,\n};\n\n// Italian - it\nstatic IT: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE d MMMM y\",\n        long: \"d MMMM y\",\n        medium: \"d MMM y\",\n        short: \"dd/MM/yy\",\n    },\n    time_formats: TimeFormats {\n        full: \"HH:mm:ss zzzz\",\n        long: \"HH:mm:ss z\",\n        medium: \"HH:mm:ss\",\n        short: \"HH:mm\",\n    },\n    datetime_pattern: \"{1}, {0}\",\n    months_wide: [\n        \"gennaio\",\n        \"febbraio\",\n        \"marzo\",\n        \"aprile\",\n        \"maggio\",\n        \"giugno\",\n        \"luglio\",\n        \"agosto\",\n        \"settembre\",\n        \"ottobre\",\n        \"novembre\",\n        \"dicembre\",\n    ],\n    months_abbr: [\n        \"gen\", \"feb\", \"mar\", \"apr\", \"mag\", \"giu\", \"lug\", \"ago\", \"set\", \"ott\", \"nov\", \"dic\",\n    ],\n    days_wide: [\n        \"domenica\",\n        \"lunedì\",\n        \"martedì\",\n        \"mercoledì\",\n        \"giovedì\",\n        \"venerdì\",\n        \"sabato\",\n    ],\n    days_abbr: [\"dom\", \"lun\", \"mar\", \"mer\", \"gio\", \"ven\", \"sab\"],\n    am: \"AM\",\n    pm: \"PM\",\n    hour12_default: false,\n};\n\n// Portuguese - pt\nstatic PT: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE, d 'de' MMMM 'de' y\",\n        long: \"d 'de' MMMM 'de' y\",\n        medium: \"d 'de' MMM 'de' y\",\n        short: \"dd/MM/y\",\n    },\n    time_formats: TimeFormats {\n        full: \"HH:mm:ss zzzz\",\n        long: \"HH:mm:ss z\",\n        medium: \"HH:mm:ss\",\n        short: \"HH:mm\",\n    },\n    datetime_pattern: \"{1}, {0}\",\n    months_wide: [\n        \"janeiro\",\n        \"fevereiro\",\n        \"março\",\n        \"abril\",\n        \"maio\",\n        \"junho\",\n        \"julho\",\n        \"agosto\",\n        \"setembro\",\n        \"outubro\",\n        \"novembro\",\n        \"dezembro\",\n    ],\n    months_abbr: [\n        \"jan\", \"fev\", \"mar\", \"abr\", \"mai\", \"jun\", \"jul\", \"ago\", \"set\", \"out\", \"nov\", \"dez\",\n    ],\n    days_wide: [\n        \"domingo\",\n        \"segunda-feira\",\n        \"terça-feira\",\n        \"quarta-feira\",\n        \"quinta-feira\",\n        \"sexta-feira\",\n        \"sábado\",\n    ],\n    days_abbr: [\"dom\", \"seg\", \"ter\", \"qua\", \"qui\", \"sex\", \"sáb\"],\n    am: \"AM\",\n    pm: \"PM\",\n    hour12_default: false,\n};\n\n// Dutch - nl\nstatic NL: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE d MMMM y\",\n        long: \"d MMMM y\",\n        medium: \"d MMM y\",\n        short: \"dd-MM-y\",\n    },\n    time_formats: TimeFormats {\n        full: \"HH:mm:ss zzzz\",\n        long: \"HH:mm:ss z\",\n        medium: \"HH:mm:ss\",\n        short: \"HH:mm\",\n    },\n    datetime_pattern: \"{1}, {0}\",\n    months_wide: [\n        \"januari\",\n        \"februari\",\n        \"maart\",\n        \"april\",\n        \"mei\",\n        \"juni\",\n        \"juli\",\n        \"augustus\",\n        \"september\",\n        \"oktober\",\n        \"november\",\n        \"december\",\n    ],\n    months_abbr: [\n        \"jan\", \"feb\", \"mrt\", \"apr\", \"mei\", \"jun\", \"jul\", \"aug\", \"sep\", \"okt\", \"nov\", \"dec\",\n    ],\n    days_wide: [\n        \"zondag\",\n        \"maandag\",\n        \"dinsdag\",\n        \"woensdag\",\n        \"donderdag\",\n        \"vrijdag\",\n        \"zaterdag\",\n    ],\n    days_abbr: [\"zo\", \"ma\", \"di\", \"wo\", \"do\", \"vr\", \"za\"],\n    am: \"a.m.\",\n    pm: \"p.m.\",\n    hour12_default: false,\n};\n\n// Russian - ru\nstatic RU: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE, d MMMM y 'г'.\",\n        long: \"d MMMM y 'г'.\",\n        medium: \"d MMM y 'г'.\",\n        short: \"dd.MM.y\",\n    },\n    time_formats: TimeFormats {\n        full: \"HH:mm:ss zzzz\",\n        long: \"HH:mm:ss z\",\n        medium: \"HH:mm:ss\",\n        short: \"HH:mm\",\n    },\n    datetime_pattern: \"{1}, {0}\",\n    months_wide: [\n        \"января\",\n        \"февраля\",\n        \"марта\",\n        \"апреля\",\n        \"мая\",\n        \"июня\",\n        \"июля\",\n        \"августа\",\n        \"сентября\",\n        \"октября\",\n        \"ноября\",\n        \"декабря\",\n    ],\n    months_abbr: [\n        \"янв.\",\n        \"февр.\",\n        \"мар.\",\n        \"апр.\",\n        \"мая\",\n        \"июн.\",\n        \"июл.\",\n        \"авг.\",\n        \"сент.\",\n        \"окт.\",\n        \"нояб.\",\n        \"дек.\",\n    ],\n    days_wide: [\n        \"воскресенье\",\n        \"понедельник\",\n        \"вторник\",\n        \"среда\",\n        \"четверг\",\n        \"пятница\",\n        \"суббота\",\n    ],\n    days_abbr: [\"вс\", \"пн\", \"вт\", \"ср\", \"чт\", \"пт\", \"сб\"],\n    am: \"AM\",\n    pm: \"PM\",\n    hour12_default: false,\n};\n\n// Japanese - ja\nstatic JA: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"y年M月d日EEEE\",\n        long: \"y年M月d日\",\n        medium: \"y/MM/dd\",\n        short: \"y/MM/dd\",\n    },\n    time_formats: TimeFormats {\n        full: \"H時mm分ss秒 zzzz\",\n        long: \"H:mm:ss z\",\n        medium: \"H:mm:ss\",\n        short: \"H:mm\",\n    },\n    datetime_pattern: \"{1} {0}\",\n    months_wide: [\n        \"1月\", \"2月\", \"3月\", \"4月\", \"5月\", \"6月\", \"7月\", \"8月\", \"9月\", \"10月\", \"11月\", \"12月\",\n    ],\n    months_abbr: [\n        \"1月\", \"2月\", \"3月\", \"4月\", \"5月\", \"6月\", \"7月\", \"8月\", \"9月\", \"10月\", \"11月\", \"12月\",\n    ],\n    days_wide: [\n        \"日曜日\",\n        \"月曜日\",\n        \"火曜日\",\n        \"水曜日\",\n        \"木曜日\",\n        \"金曜日\",\n        \"土曜日\",\n    ],\n    days_abbr: [\"日\", \"月\", \"火\", \"水\", \"木\", \"金\", \"土\"],\n    am: \"午前\",\n    pm: \"午後\",\n    hour12_default: false,\n};\n\n// Korean - ko\nstatic KO: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"y년 MMMM d일 EEEE\",\n        long: \"y년 MMMM d일\",\n        medium: \"y. M. d.\",\n        short: \"yy. M. d.\",\n    },\n    time_formats: TimeFormats {\n        full: \"a h시 m분 s초 zzzz\",\n        long: \"a h시 m분 s초 z\",\n        medium: \"a h:mm:ss\",\n        short: \"a h:mm\",\n    },\n    datetime_pattern: \"{1} {0}\",\n    months_wide: [\n        \"1월\", \"2월\", \"3월\", \"4월\", \"5월\", \"6월\", \"7월\", \"8월\", \"9월\", \"10월\", \"11월\", \"12월\",\n    ],\n    months_abbr: [\n        \"1월\", \"2월\", \"3월\", \"4월\", \"5월\", \"6월\", \"7월\", \"8월\", \"9월\", \"10월\", \"11월\", \"12월\",\n    ],\n    days_wide: [\n        \"일요일\",\n        \"월요일\",\n        \"화요일\",\n        \"수요일\",\n        \"목요일\",\n        \"금요일\",\n        \"토요일\",\n    ],\n    days_abbr: [\"일\", \"월\", \"화\", \"수\", \"목\", \"금\", \"토\"],\n    am: \"오전\",\n    pm: \"오후\",\n    hour12_default: true,\n};\n\n// Chinese (Simplified) - zh\nstatic ZH: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"y年M月d日EEEE\",\n        long: \"y年M月d日\",\n        medium: \"y年M月d日\",\n        short: \"y/M/d\",\n    },\n    time_formats: TimeFormats {\n        full: \"zzzz HH:mm:ss\",\n        long: \"z HH:mm:ss\",\n        medium: \"HH:mm:ss\",\n        short: \"HH:mm\",\n    },\n    datetime_pattern: \"{1} {0}\",\n    months_wide: [\n        \"一月\",\n        \"二月\",\n        \"三月\",\n        \"四月\",\n        \"五月\",\n        \"六月\",\n        \"七月\",\n        \"八月\",\n        \"九月\",\n        \"十月\",\n        \"十一月\",\n        \"十二月\",\n    ],\n    months_abbr: [\n        \"1月\", \"2月\", \"3月\", \"4月\", \"5月\", \"6月\", \"7月\", \"8月\", \"9月\", \"10月\", \"11月\", \"12月\",\n    ],\n    days_wide: [\n        \"星期日\",\n        \"星期一\",\n        \"星期二\",\n        \"星期三\",\n        \"星期四\",\n        \"星期五\",\n        \"星期六\",\n    ],\n    days_abbr: [\"周日\", \"周一\", \"周二\", \"周三\", \"周四\", \"周五\", \"周六\"],\n    am: \"上午\",\n    pm: \"下午\",\n    hour12_default: false,\n};\n\n// Chinese (Traditional) - zh-TW\nstatic ZH_TW: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"y年M月d日 EEEE\",\n        long: \"y年M月d日\",\n        medium: \"y年M月d日\",\n        short: \"y/M/d\",\n    },\n    time_formats: TimeFormats {\n        full: \"ah:mm:ss [zzzz]\",\n        long: \"ah:mm:ss [z]\",\n        medium: \"ah:mm:ss\",\n        short: \"ah:mm\",\n    },\n    datetime_pattern: \"{1} {0}\",\n    months_wide: [\n        \"1月\", \"2月\", \"3月\", \"4月\", \"5月\", \"6月\", \"7月\", \"8月\", \"9月\", \"10月\", \"11月\", \"12月\",\n    ],\n    months_abbr: [\n        \"1月\", \"2月\", \"3月\", \"4月\", \"5月\", \"6月\", \"7月\", \"8月\", \"9月\", \"10月\", \"11月\", \"12月\",\n    ],\n    days_wide: [\n        \"星期日\",\n        \"星期一\",\n        \"星期二\",\n        \"星期三\",\n        \"星期四\",\n        \"星期五\",\n        \"星期六\",\n    ],\n    days_abbr: [\"週日\", \"週一\", \"週二\", \"週三\", \"週四\", \"週五\", \"週六\"],\n    am: \"上午\",\n    pm: \"下午\",\n    hour12_default: true,\n};\n\n// Arabic - ar\nstatic AR: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE، d MMMM y\",\n        long: \"d MMMM y\",\n        medium: \"dd/MM/y\",\n        short: \"d/M/y\",\n    },\n    time_formats: TimeFormats {\n        full: \"h:mm:ss a zzzz\",\n        long: \"h:mm:ss a z\",\n        medium: \"h:mm:ss a\",\n        short: \"h:mm a\",\n    },\n    datetime_pattern: \"{1}, {0}\",\n    months_wide: [\n        \"يناير\",\n        \"فبراير\",\n        \"مارس\",\n        \"أبريل\",\n        \"مايو\",\n        \"يونيو\",\n        \"يوليو\",\n        \"أغسطس\",\n        \"سبتمبر\",\n        \"أكتوبر\",\n        \"نوفمبر\",\n        \"ديسمبر\",\n    ],\n    months_abbr: [\n        \"يناير\",\n        \"فبراير\",\n        \"مارس\",\n        \"أبريل\",\n        \"مايو\",\n        \"يونيو\",\n        \"يوليو\",\n        \"أغسطس\",\n        \"سبتمبر\",\n        \"أكتوبر\",\n        \"نوفمبر\",\n        \"ديسمبر\",\n    ],\n    days_wide: [\n        \"الأحد\",\n        \"الاثنين\",\n        \"الثلاثاء\",\n        \"الأربعاء\",\n        \"الخميس\",\n        \"الجمعة\",\n        \"السبت\",\n    ],\n    days_abbr: [\n        \"الأحد\",\n        \"الاثنين\",\n        \"الثلاثاء\",\n        \"الأربعاء\",\n        \"الخميس\",\n        \"الجمعة\",\n        \"السبت\",\n    ],\n    am: \"ص\",\n    pm: \"م\",\n    hour12_default: true,\n};\n\n// Hindi - hi\nstatic HI: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE, d MMMM y\",\n        long: \"d MMMM y\",\n        medium: \"d MMM y\",\n        short: \"d/M/yy\",\n    },\n    time_formats: TimeFormats {\n        full: \"h:mm:ss a zzzz\",\n        long: \"h:mm:ss a z\",\n        medium: \"h:mm:ss a\",\n        short: \"h:mm a\",\n    },\n    datetime_pattern: \"{1}, {0}\",\n    months_wide: [\n        \"जनवरी\",\n        \"फ़रवरी\",\n        \"मार्च\",\n        \"अप्रैल\",\n        \"मई\",\n        \"जून\",\n        \"जुलाई\",\n        \"अगस्त\",\n        \"सितंबर\",\n        \"अक्तूबर\",\n        \"नवंबर\",\n        \"दिसंबर\",\n    ],\n    months_abbr: [\n        \"जन॰\",\n        \"फ़र॰\",\n        \"मार्च\",\n        \"अप्रैल\",\n        \"मई\",\n        \"जून\",\n        \"जुल॰\",\n        \"अग॰\",\n        \"सित॰\",\n        \"अक्तू॰\",\n        \"नव॰\",\n        \"दिस॰\",\n    ],\n    days_wide: [\n        \"रविवार\",\n        \"सोमवार\",\n        \"मंगलवार\",\n        \"बुधवार\",\n        \"गुरुवार\",\n        \"शुक्रवार\",\n        \"शनिवार\",\n    ],\n    days_abbr: [\"रवि\", \"सोम\", \"मंगल\", \"बुध\", \"गुरु\", \"शुक्र\", \"शनि\"],\n    am: \"am\",\n    pm: \"pm\",\n    hour12_default: true,\n};\n\n// Bengali - bn\nstatic BN: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE, d MMMM, y\",\n        long: \"d MMMM, y\",\n        medium: \"d MMM, y\",\n        short: \"d/M/yy\",\n    },\n    time_formats: TimeFormats {\n        full: \"h:mm:ss a zzzz\",\n        long: \"h:mm:ss a z\",\n        medium: \"h:mm:ss a\",\n        short: \"h:mm a\",\n    },\n    datetime_pattern: \"{1}, {0}\",\n    months_wide: [\n        \"জানুয়ারী\",\n        \"ফেব্রুয়ারী\",\n        \"মার্চ\",\n        \"এপ্রিল\",\n        \"মে\",\n        \"জুন\",\n        \"জুলাই\",\n        \"আগস্ট\",\n        \"সেপ্টেম্বর\",\n        \"অক্টোবর\",\n        \"নভেম্বর\",\n        \"ডিসেম্বর\",\n    ],\n    months_abbr: [\n        \"জানু\",\n        \"ফেব\",\n        \"মার্চ\",\n        \"এপ্রি\",\n        \"মে\",\n        \"জুন\",\n        \"জুলাই\",\n        \"আগ\",\n        \"সেপ\",\n        \"অক্টো\",\n        \"নভে\",\n        \"ডিসে\",\n    ],\n    days_wide: [\n        \"রবিবার\",\n        \"সোমবার\",\n        \"মঙ্গলবার\",\n        \"বুধবার\",\n        \"বৃহস্পতিবার\",\n        \"শুক্রবার\",\n        \"শনিবার\",\n    ],\n    days_abbr: [\"রবি\", \"সোম\", \"মঙ্গল\", \"বুধ\", \"বৃহস্পতি\", \"শুক্র\", \"শনি\"],\n    am: \"AM\",\n    pm: \"PM\",\n    hour12_default: true,\n};\n\n// Vietnamese - vi\nstatic VI: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE, d MMMM, y\",\n        long: \"d MMMM, y\",\n        medium: \"d MMM, y\",\n        short: \"dd/MM/y\",\n    },\n    time_formats: TimeFormats {\n        full: \"HH:mm:ss zzzz\",\n        long: \"HH:mm:ss z\",\n        medium: \"HH:mm:ss\",\n        short: \"HH:mm\",\n    },\n    datetime_pattern: \"{1}, {0}\",\n    months_wide: [\n        \"tháng 1\",\n        \"tháng 2\",\n        \"tháng 3\",\n        \"tháng 4\",\n        \"tháng 5\",\n        \"tháng 6\",\n        \"tháng 7\",\n        \"tháng 8\",\n        \"tháng 9\",\n        \"tháng 10\",\n        \"tháng 11\",\n        \"tháng 12\",\n    ],\n    months_abbr: [\n        \"thg 1\", \"thg 2\", \"thg 3\", \"thg 4\", \"thg 5\", \"thg 6\", \"thg 7\", \"thg 8\", \"thg 9\", \"thg 10\",\n        \"thg 11\", \"thg 12\",\n    ],\n    days_wide: [\n        \"Chủ Nhật\",\n        \"Thứ Hai\",\n        \"Thứ Ba\",\n        \"Thứ Tư\",\n        \"Thứ Năm\",\n        \"Thứ Sáu\",\n        \"Thứ Bảy\",\n    ],\n    days_abbr: [\"CN\", \"Th 2\", \"Th 3\", \"Th 4\", \"Th 5\", \"Th 6\", \"Th 7\"],\n    am: \"SA\",\n    pm: \"CH\",\n    hour12_default: false,\n};\n\n// Thai - th\nstatic TH: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEEที่ d MMMM G y\",\n        long: \"d MMMM G y\",\n        medium: \"d MMM y\",\n        short: \"d/M/yy\",\n    },\n    time_formats: TimeFormats {\n        full: \"H นาฬิกา mm นาที ss วินาที zzzz\",\n        long: \"H นาฬิกา mm นาที ss วินาที z\",\n        medium: \"HH:mm:ss\",\n        short: \"HH:mm\",\n    },\n    datetime_pattern: \"{1} {0}\",\n    months_wide: [\n        \"มกราคม\",\n        \"กุมภาพันธ์\",\n        \"มีนาคม\",\n        \"เมษายน\",\n        \"พฤษภาคม\",\n        \"มิถุนายน\",\n        \"กรกฎาคม\",\n        \"สิงหาคม\",\n        \"กันยายน\",\n        \"ตุลาคม\",\n        \"พฤศจิกายน\",\n        \"ธันวาคม\",\n    ],\n    months_abbr: [\n        \"ม.ค.\",\n        \"ก.พ.\",\n        \"มี.ค.\",\n        \"เม.ย.\",\n        \"พ.ค.\",\n        \"มิ.ย.\",\n        \"ก.ค.\",\n        \"ส.ค.\",\n        \"ก.ย.\",\n        \"ต.ค.\",\n        \"พ.ย.\",\n        \"ธ.ค.\",\n    ],\n    days_wide: [\n        \"วันอาทิตย์\",\n        \"วันจันทร์\",\n        \"วันอังคาร\",\n        \"วันพุธ\",\n        \"วันพฤหัสบดี\",\n        \"วันศุกร์\",\n        \"วันเสาร์\",\n    ],\n    days_abbr: [\"อา.\", \"จ.\", \"อ.\", \"พ.\", \"พฤ.\", \"ศ.\", \"ส.\"],\n    am: \"ก่อนเที่ยง\",\n    pm: \"หลังเที่ยง\",\n    hour12_default: false,\n};\n\n// Indonesian - id\nstatic ID: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE, dd MMMM y\",\n        long: \"d MMMM y\",\n        medium: \"d MMM y\",\n        short: \"dd/MM/yy\",\n    },\n    time_formats: TimeFormats {\n        full: \"HH.mm.ss zzzz\",\n        long: \"HH.mm.ss z\",\n        medium: \"HH.mm.ss\",\n        short: \"HH.mm\",\n    },\n    datetime_pattern: \"{1} {0}\",\n    months_wide: [\n        \"Januari\",\n        \"Februari\",\n        \"Maret\",\n        \"April\",\n        \"Mei\",\n        \"Juni\",\n        \"Juli\",\n        \"Agustus\",\n        \"September\",\n        \"Oktober\",\n        \"November\",\n        \"Desember\",\n    ],\n    months_abbr: [\n        \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"Mei\", \"Jun\", \"Jul\", \"Agu\", \"Sep\", \"Okt\", \"Nov\", \"Des\",\n    ],\n    days_wide: [\n        \"Minggu\", \"Senin\", \"Selasa\", \"Rabu\", \"Kamis\", \"Jumat\", \"Sabtu\",\n    ],\n    days_abbr: [\"Min\", \"Sen\", \"Sel\", \"Rab\", \"Kam\", \"Jum\", \"Sab\"],\n    am: \"AM\",\n    pm: \"PM\",\n    hour12_default: false,\n};\n\n// Turkish - tr\nstatic TR: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"d MMMM y EEEE\",\n        long: \"d MMMM y\",\n        medium: \"d MMM y\",\n        short: \"d.MM.y\",\n    },\n    time_formats: TimeFormats {\n        full: \"HH:mm:ss zzzz\",\n        long: \"HH:mm:ss z\",\n        medium: \"HH:mm:ss\",\n        short: \"HH:mm\",\n    },\n    datetime_pattern: \"{1} {0}\",\n    months_wide: [\n        \"Ocak\", \"Şubat\", \"Mart\", \"Nisan\", \"Mayıs\", \"Haziran\", \"Temmuz\", \"Ağustos\", \"Eylül\", \"Ekim\",\n        \"Kasım\", \"Aralık\",\n    ],\n    months_abbr: [\n        \"Oca\", \"Şub\", \"Mar\", \"Nis\", \"May\", \"Haz\", \"Tem\", \"Ağu\", \"Eyl\", \"Eki\", \"Kas\", \"Ara\",\n    ],\n    days_wide: [\n        \"Pazar\",\n        \"Pazartesi\",\n        \"Salı\",\n        \"Çarşamba\",\n        \"Perşembe\",\n        \"Cuma\",\n        \"Cumartesi\",\n    ],\n    days_abbr: [\"Paz\", \"Pzt\", \"Sal\", \"Çar\", \"Per\", \"Cum\", \"Cmt\"],\n    am: \"ÖÖ\",\n    pm: \"ÖS\",\n    hour12_default: false,\n};\n\n// Polish - pl\nstatic PL: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE, d MMMM y\",\n        long: \"d MMMM y\",\n        medium: \"d MMM y\",\n        short: \"dd.MM.y\",\n    },\n    time_formats: TimeFormats {\n        full: \"HH:mm:ss zzzz\",\n        long: \"HH:mm:ss z\",\n        medium: \"HH:mm:ss\",\n        short: \"HH:mm\",\n    },\n    datetime_pattern: \"{1}, {0}\",\n    months_wide: [\n        \"stycznia\",\n        \"lutego\",\n        \"marca\",\n        \"kwietnia\",\n        \"maja\",\n        \"czerwca\",\n        \"lipca\",\n        \"sierpnia\",\n        \"września\",\n        \"października\",\n        \"listopada\",\n        \"grudnia\",\n    ],\n    months_abbr: [\n        \"sty\", \"lut\", \"mar\", \"kwi\", \"maj\", \"cze\", \"lip\", \"sie\", \"wrz\", \"paź\", \"lis\", \"gru\",\n    ],\n    days_wide: [\n        \"niedziela\",\n        \"poniedziałek\",\n        \"wtorek\",\n        \"środa\",\n        \"czwartek\",\n        \"piątek\",\n        \"sobota\",\n    ],\n    days_abbr: [\"niedz.\", \"pon.\", \"wt.\", \"śr.\", \"czw.\", \"pt.\", \"sob.\"],\n    am: \"AM\",\n    pm: \"PM\",\n    hour12_default: false,\n};\n\n// Ukrainian - uk\nstatic UK: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE, d MMMM y 'р'.\",\n        long: \"d MMMM y 'р'.\",\n        medium: \"d MMM y 'р'.\",\n        short: \"dd.MM.yy\",\n    },\n    time_formats: TimeFormats {\n        full: \"HH:mm:ss zzzz\",\n        long: \"HH:mm:ss z\",\n        medium: \"HH:mm:ss\",\n        short: \"HH:mm\",\n    },\n    datetime_pattern: \"{1}, {0}\",\n    months_wide: [\n        \"січня\",\n        \"лютого\",\n        \"березня\",\n        \"квітня\",\n        \"травня\",\n        \"червня\",\n        \"липня\",\n        \"серпня\",\n        \"вересня\",\n        \"жовтня\",\n        \"листопада\",\n        \"грудня\",\n    ],\n    months_abbr: [\n        \"січ.\",\n        \"лют.\",\n        \"бер.\",\n        \"квіт.\",\n        \"трав.\",\n        \"черв.\",\n        \"лип.\",\n        \"серп.\",\n        \"вер.\",\n        \"жовт.\",\n        \"лист.\",\n        \"груд.\",\n    ],\n    days_wide: [\n        \"неділя\",\n        \"понеділок\",\n        \"вівторок\",\n        \"середа\",\n        \"четвер\",\n        \"пʼятниця\",\n        \"субота\",\n    ],\n    days_abbr: [\"нд\", \"пн\", \"вт\", \"ср\", \"чт\", \"пт\", \"сб\"],\n    am: \"дп\",\n    pm: \"пп\",\n    hour12_default: false,\n};\n\n// Swedish - sv\nstatic SV: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE d MMMM y\",\n        long: \"d MMMM y\",\n        medium: \"d MMM y\",\n        short: \"y-MM-dd\",\n    },\n    time_formats: TimeFormats {\n        full: \"HH:mm:ss zzzz\",\n        long: \"HH:mm:ss z\",\n        medium: \"HH:mm:ss\",\n        short: \"HH:mm\",\n    },\n    datetime_pattern: \"{1} {0}\",\n    months_wide: [\n        \"januari\",\n        \"februari\",\n        \"mars\",\n        \"april\",\n        \"maj\",\n        \"juni\",\n        \"juli\",\n        \"augusti\",\n        \"september\",\n        \"oktober\",\n        \"november\",\n        \"december\",\n    ],\n    months_abbr: [\n        \"jan.\", \"feb.\", \"mars\", \"apr.\", \"maj\", \"juni\", \"juli\", \"aug.\", \"sep.\", \"okt.\", \"nov.\",\n        \"dec.\",\n    ],\n    days_wide: [\n        \"söndag\", \"måndag\", \"tisdag\", \"onsdag\", \"torsdag\", \"fredag\", \"lördag\",\n    ],\n    days_abbr: [\"sön\", \"mån\", \"tis\", \"ons\", \"tors\", \"fre\", \"lör\"],\n    am: \"fm\",\n    pm: \"em\",\n    hour12_default: false,\n};\n\n// Danish - da\nstatic DA: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE 'den' d. MMMM y\",\n        long: \"d. MMMM y\",\n        medium: \"d. MMM y\",\n        short: \"dd.MM.y\",\n    },\n    time_formats: TimeFormats {\n        full: \"HH.mm.ss zzzz\",\n        long: \"HH.mm.ss z\",\n        medium: \"HH.mm.ss\",\n        short: \"HH.mm\",\n    },\n    datetime_pattern: \"{1} 'kl'. {0}\",\n    months_wide: [\n        \"januar\",\n        \"februar\",\n        \"marts\",\n        \"april\",\n        \"maj\",\n        \"juni\",\n        \"juli\",\n        \"august\",\n        \"september\",\n        \"oktober\",\n        \"november\",\n        \"december\",\n    ],\n    months_abbr: [\n        \"jan.\", \"feb.\", \"mar.\", \"apr.\", \"maj\", \"jun.\", \"jul.\", \"aug.\", \"sep.\", \"okt.\", \"nov.\",\n        \"dec.\",\n    ],\n    days_wide: [\n        \"søndag\", \"mandag\", \"tirsdag\", \"onsdag\", \"torsdag\", \"fredag\", \"lørdag\",\n    ],\n    days_abbr: [\"søn.\", \"man.\", \"tir.\", \"ons.\", \"tor.\", \"fre.\", \"lør.\"],\n    am: \"AM\",\n    pm: \"PM\",\n    hour12_default: false,\n};\n\n// Norwegian Bokmål - nb\nstatic NB: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE d. MMMM y\",\n        long: \"d. MMMM y\",\n        medium: \"d. MMM y\",\n        short: \"dd.MM.y\",\n    },\n    time_formats: TimeFormats {\n        full: \"HH:mm:ss zzzz\",\n        long: \"HH:mm:ss z\",\n        medium: \"HH:mm:ss\",\n        short: \"HH:mm\",\n    },\n    datetime_pattern: \"{1}, {0}\",\n    months_wide: [\n        \"januar\",\n        \"februar\",\n        \"mars\",\n        \"april\",\n        \"mai\",\n        \"juni\",\n        \"juli\",\n        \"august\",\n        \"september\",\n        \"oktober\",\n        \"november\",\n        \"desember\",\n    ],\n    months_abbr: [\n        \"jan.\", \"feb.\", \"mar.\", \"apr.\", \"mai\", \"jun.\", \"jul.\", \"aug.\", \"sep.\", \"okt.\", \"nov.\",\n        \"des.\",\n    ],\n    days_wide: [\n        \"søndag\", \"mandag\", \"tirsdag\", \"onsdag\", \"torsdag\", \"fredag\", \"lørdag\",\n    ],\n    days_abbr: [\"søn.\", \"man.\", \"tir.\", \"ons.\", \"tor.\", \"fre.\", \"lør.\"],\n    am: \"a.m.\",\n    pm: \"p.m.\",\n    hour12_default: false,\n};\n\n// Finnish - fi\nstatic FI: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"cccc d. MMMM y\",\n        long: \"d. MMMM y\",\n        medium: \"d.M.y\",\n        short: \"d.M.y\",\n    },\n    time_formats: TimeFormats {\n        full: \"H.mm.ss zzzz\",\n        long: \"H.mm.ss z\",\n        medium: \"H.mm.ss\",\n        short: \"H.mm\",\n    },\n    datetime_pattern: \"{1} 'klo' {0}\",\n    months_wide: [\n        \"tammikuuta\",\n        \"helmikuuta\",\n        \"maaliskuuta\",\n        \"huhtikuuta\",\n        \"toukokuuta\",\n        \"kesäkuuta\",\n        \"heinäkuuta\",\n        \"elokuuta\",\n        \"syyskuuta\",\n        \"lokakuuta\",\n        \"marraskuuta\",\n        \"joulukuuta\",\n    ],\n    months_abbr: [\n        \"tammik.\", \"helmik.\", \"maalisk.\", \"huhtik.\", \"toukok.\", \"kesäk.\", \"heinäk.\", \"elok.\",\n        \"syysk.\", \"lokak.\", \"marrask.\", \"jouluk.\",\n    ],\n    days_wide: [\n        \"sunnuntaina\",\n        \"maanantaina\",\n        \"tiistaina\",\n        \"keskiviikkona\",\n        \"torstaina\",\n        \"perjantaina\",\n        \"lauantaina\",\n    ],\n    days_abbr: [\"su\", \"ma\", \"ti\", \"ke\", \"to\", \"pe\", \"la\"],\n    am: \"ap.\",\n    pm: \"ip.\",\n    hour12_default: false,\n};\n\n// Czech - cs\nstatic CS: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE d. MMMM y\",\n        long: \"d. MMMM y\",\n        medium: \"d. M. y\",\n        short: \"dd.MM.yy\",\n    },\n    time_formats: TimeFormats {\n        full: \"H:mm:ss zzzz\",\n        long: \"H:mm:ss z\",\n        medium: \"H:mm:ss\",\n        short: \"H:mm\",\n    },\n    datetime_pattern: \"{1} {0}\",\n    months_wide: [\n        \"ledna\",\n        \"února\",\n        \"března\",\n        \"dubna\",\n        \"května\",\n        \"června\",\n        \"července\",\n        \"srpna\",\n        \"září\",\n        \"října\",\n        \"listopadu\",\n        \"prosince\",\n    ],\n    months_abbr: [\n        \"led\", \"úno\", \"bře\", \"dub\", \"kvě\", \"čvn\", \"čvc\", \"srp\", \"zář\", \"říj\", \"lis\", \"pro\",\n    ],\n    days_wide: [\n        \"neděle\",\n        \"pondělí\",\n        \"úterý\",\n        \"středa\",\n        \"čtvrtek\",\n        \"pátek\",\n        \"sobota\",\n    ],\n    days_abbr: [\"ne\", \"po\", \"út\", \"st\", \"čt\", \"pá\", \"so\"],\n    am: \"dop.\",\n    pm: \"odp.\",\n    hour12_default: false,\n};\n\n// Greek - el\nstatic EL: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE d MMMM y\",\n        long: \"d MMMM y\",\n        medium: \"d MMM y\",\n        short: \"d/M/yy\",\n    },\n    time_formats: TimeFormats {\n        full: \"h:mm:ss a zzzz\",\n        long: \"h:mm:ss a z\",\n        medium: \"h:mm:ss a\",\n        short: \"h:mm a\",\n    },\n    datetime_pattern: \"{1}, {0}\",\n    months_wide: [\n        \"Ιανουαρίου\",\n        \"Φεβρουαρίου\",\n        \"Μαρτίου\",\n        \"Απριλίου\",\n        \"Μαΐου\",\n        \"Ιουνίου\",\n        \"Ιουλίου\",\n        \"Αυγούστου\",\n        \"Σεπτεμβρίου\",\n        \"Οκτωβρίου\",\n        \"Νοεμβρίου\",\n        \"Δεκεμβρίου\",\n    ],\n    months_abbr: [\n        \"Ιαν\", \"Φεβ\", \"Μαρ\", \"Απρ\", \"Μαΐ\", \"Ιουν\", \"Ιουλ\", \"Αυγ\", \"Σεπ\", \"Οκτ\", \"Νοε\", \"Δεκ\",\n    ],\n    days_wide: [\n        \"Κυριακή\",\n        \"Δευτέρα\",\n        \"Τρίτη\",\n        \"Τετάρτη\",\n        \"Πέμπτη\",\n        \"Παρασκευή\",\n        \"Σάββατο\",\n    ],\n    days_abbr: [\"Κυρ\", \"Δευ\", \"Τρί\", \"Τετ\", \"Πέμ\", \"Παρ\", \"Σάβ\"],\n    am: \"π.μ.\",\n    pm: \"μ.μ.\",\n    hour12_default: true,\n};\n\n// Hebrew - he\nstatic HE: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE, d בMMMM y\",\n        long: \"d בMMMM y\",\n        medium: \"d בMMM y\",\n        short: \"d.M.y\",\n    },\n    time_formats: TimeFormats {\n        full: \"H:mm:ss zzzz\",\n        long: \"H:mm:ss z\",\n        medium: \"H:mm:ss\",\n        short: \"H:mm\",\n    },\n    datetime_pattern: \"{1}, {0}\",\n    months_wide: [\n        \"ינואר\",\n        \"פברואר\",\n        \"מרץ\",\n        \"אפריל\",\n        \"מאי\",\n        \"יוני\",\n        \"יולי\",\n        \"אוגוסט\",\n        \"ספטמבר\",\n        \"אוקטובר\",\n        \"נובמבר\",\n        \"דצמבר\",\n    ],\n    months_abbr: [\n        \"ינו׳\", \"פבר׳\", \"מרץ\", \"אפר׳\", \"מאי\", \"יוני\", \"יולי\", \"אוג׳\", \"ספט׳\", \"אוק׳\", \"נוב׳\",\n        \"דצמ׳\",\n    ],\n    days_wide: [\n        \"יום ראשון\",\n        \"יום שני\",\n        \"יום שלישי\",\n        \"יום רביעי\",\n        \"יום חמישי\",\n        \"יום שישי\",\n        \"יום שבת\",\n    ],\n    days_abbr: [\n        \"יום א׳\",\n        \"יום ב׳\",\n        \"יום ג׳\",\n        \"יום ד׳\",\n        \"יום ה׳\",\n        \"יום ו׳\",\n        \"שבת\",\n    ],\n    am: \"לפנה״צ\",\n    pm: \"אחה״צ\",\n    hour12_default: false,\n};\n\n// Hungarian - hu\nstatic HU: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"y. MMMM d., EEEE\",\n        long: \"y. MMMM d.\",\n        medium: \"y. MMM d.\",\n        short: \"y. MM. dd.\",\n    },\n    time_formats: TimeFormats {\n        full: \"H:mm:ss zzzz\",\n        long: \"H:mm:ss z\",\n        medium: \"H:mm:ss\",\n        short: \"H:mm\",\n    },\n    datetime_pattern: \"{1} {0}\",\n    months_wide: [\n        \"január\",\n        \"február\",\n        \"március\",\n        \"április\",\n        \"május\",\n        \"június\",\n        \"július\",\n        \"augusztus\",\n        \"szeptember\",\n        \"október\",\n        \"november\",\n        \"december\",\n    ],\n    months_abbr: [\n        \"jan.\", \"febr.\", \"márc.\", \"ápr.\", \"máj.\", \"jún.\", \"júl.\", \"aug.\", \"szept.\", \"okt.\", \"nov.\",\n        \"dec.\",\n    ],\n    days_wide: [\n        \"vasárnap\",\n        \"hétfő\",\n        \"kedd\",\n        \"szerda\",\n        \"csütörtök\",\n        \"péntek\",\n        \"szombat\",\n    ],\n    days_abbr: [\"V\", \"H\", \"K\", \"Sze\", \"Cs\", \"P\", \"Szo\"],\n    am: \"de.\",\n    pm: \"du.\",\n    hour12_default: false,\n};\n\n// Romanian - ro\nstatic RO: LocaleData = LocaleData {\n    date_formats: DateFormats {\n        full: \"EEEE, d MMMM y\",\n        long: \"d MMMM y\",\n        medium: \"d MMM y\",\n        short: \"dd.MM.y\",\n    },\n    time_formats: TimeFormats {\n        full: \"HH:mm:ss zzzz\",\n        long: \"HH:mm:ss z\",\n        medium: \"HH:mm:ss\",\n        short: \"HH:mm\",\n    },\n    datetime_pattern: \"{1}, {0}\",\n    months_wide: [\n        \"ianuarie\",\n        \"februarie\",\n        \"martie\",\n        \"aprilie\",\n        \"mai\",\n        \"iunie\",\n        \"iulie\",\n        \"august\",\n        \"septembrie\",\n        \"octombrie\",\n        \"noiembrie\",\n        \"decembrie\",\n    ],\n    months_abbr: [\n        \"ian.\", \"feb.\", \"mar.\", \"apr.\", \"mai\", \"iun.\", \"iul.\", \"aug.\", \"sept.\", \"oct.\", \"nov.\",\n        \"dec.\",\n    ],\n    days_wide: [\n        \"duminică\",\n        \"luni\",\n        \"marți\",\n        \"miercuri\",\n        \"joi\",\n        \"vineri\",\n        \"sâmbătă\",\n    ],\n    days_abbr: [\"dum.\", \"lun.\", \"mar.\", \"mie.\", \"joi\", \"vin.\", \"sâm.\"],\n    am: \"a.m.\",\n    pm: \"p.m.\",\n    hour12_default: false,\n};\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_get_locale_data_exact_match() {\n        let data = get_locale_data(\"en-US\");\n        assert_eq!(data.date_formats.short, \"M/d/yy\");\n        assert!(data.hour12_default);\n\n        let data = get_locale_data(\"de-DE\");\n        assert_eq!(data.date_formats.short, \"dd.MM.yy\");\n        assert!(!data.hour12_default);\n    }\n\n    #[test]\n    fn test_get_locale_data_language_fallback() {\n        let data = get_locale_data(\"de\");\n        assert_eq!(data.date_formats.short, \"dd.MM.yy\");\n\n        let data = get_locale_data(\"fr\");\n        assert_eq!(data.date_formats.short, \"dd/MM/y\");\n    }\n\n    #[test]\n    fn test_get_locale_data_unknown_fallback() {\n        let data = get_locale_data(\"xx-YY\");\n        // Should fall back to en-US\n        assert_eq!(data.date_formats.short, \"M/d/yy\");\n    }\n\n    #[test]\n    fn test_get_locale_data_case_insensitive() {\n        let data1 = get_locale_data(\"en-US\");\n        let data2 = get_locale_data(\"EN-US\");\n        let data3 = get_locale_data(\"En-Us\");\n        assert_eq!(data1.date_formats.short, data2.date_formats.short);\n        assert_eq!(data2.date_formats.short, data3.date_formats.short);\n    }\n\n    #[test]\n    fn test_get_locale_data_underscore() {\n        let data = get_locale_data(\"en_US\");\n        assert_eq!(data.date_formats.short, \"M/d/yy\");\n    }\n\n    #[test]\n    fn test_months_count() {\n        let data = get_locale_data(\"en-US\");\n        assert_eq!(data.months_wide.len(), 12);\n        assert_eq!(data.months_abbr.len(), 12);\n    }\n\n    #[test]\n    fn test_days_count() {\n        let data = get_locale_data(\"en-US\");\n        assert_eq!(data.days_wide.len(), 7);\n        assert_eq!(data.days_abbr.len(), 7);\n    }\n}\n"
  },
  {
    "path": "modules/llrt_intl/src/date_time_format.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\n//! Minimal Intl.DateTimeFormat implementation for timezone support.\n//! This provides just enough functionality to support dayjs and similar libraries.\n\nuse jiff::{tz::TimeZone, Timestamp, Zoned};\nuse rquickjs::{\n    atom::PredefinedAtom, prelude::Opt, Array, Coerced, Ctx, Exception, Object, Result, Value,\n};\n\n/// Stores the resolved options for a DateTimeFormat instance\n#[derive(Clone, Debug)]\npub struct DateTimeFormatOptions {\n    pub locale: String,\n    pub timezone: TimeZone,\n    pub hour12: bool,\n    pub year: Option<String>,\n    pub month: Option<String>,\n    pub day: Option<String>,\n    pub hour: Option<String>,\n    pub minute: Option<String>,\n    pub second: Option<String>,\n    pub weekday: Option<String>,\n    pub timezone_name: Option<String>,\n    pub fractional_second_digits: Option<u8>,\n}\n\nimpl Default for DateTimeFormatOptions {\n    fn default() -> Self {\n        Self {\n            locale: \"en-US\".to_string(),\n            timezone: TimeZone::UTC,\n            hour12: false,\n            year: None,\n            month: None,\n            day: None,\n            hour: None,\n            minute: None,\n            second: None,\n            weekday: None,\n            timezone_name: None,\n            fractional_second_digits: None,\n        }\n    }\n}\n\n/// A formatted part with type and value\n#[derive(Debug, Clone)]\npub struct FormatPart {\n    pub part_type: &'static str,\n    pub value: String,\n}\n\nimpl FormatPart {\n    #[inline]\n    fn new(part_type: &'static str, value: String) -> Self {\n        Self { part_type, value }\n    }\n\n    #[inline]\n    fn literal(value: &'static str) -> Self {\n        Self {\n            part_type: \"literal\",\n            value: value.to_string(),\n        }\n    }\n}\n\n/// Format a number with optional zero-padding\n#[inline]\nfn format_number(value: i16, two_digit: bool) -> String {\n    let mut buf = itoa::Buffer::new();\n    if two_digit && value < 10 {\n        let mut result = String::with_capacity(2);\n        result.push('0');\n        result.push_str(buf.format(value));\n        result\n    } else {\n        buf.format(value).to_string()\n    }\n}\n\n/// Format a number component based on option style\n#[inline]\nfn format_component(value: i16, style: Option<&str>) -> String {\n    let two_digit = matches!(style, Some(\"2-digit\"));\n    format_number(value, two_digit)\n}\n\n/// Build format parts from a Zoned datetime in pure Rust\nfn build_format_parts(local_dt: &Zoned, options: &DateTimeFormatOptions) -> Vec<FormatPart> {\n    let mut parts = Vec::with_capacity(16);\n\n    // Month\n    if let Some(ref month_opt) = options.month {\n        parts.push(FormatPart::new(\n            \"month\",\n            format_component(local_dt.month().into(), Some(month_opt)),\n        ));\n        parts.push(FormatPart::literal(\"/\"));\n    }\n\n    // Day\n    if let Some(ref day_opt) = options.day {\n        parts.push(FormatPart::new(\n            \"day\",\n            format_component(local_dt.day().into(), Some(day_opt)),\n        ));\n        parts.push(FormatPart::literal(\"/\"));\n    }\n\n    // Year\n    if let Some(ref year_opt) = options.year {\n        let year_val = if year_opt == \"2-digit\" {\n            format_number(local_dt.year() % 100, true)\n        } else {\n            let mut buf = itoa::Buffer::new();\n            buf.format(local_dt.year()).to_string()\n        };\n        parts.push(FormatPart::new(\"year\", year_val));\n    }\n\n    // Add separator between date and time if we have both\n    let has_date = options.year.is_some() || options.month.is_some() || options.day.is_some();\n    let has_time = options.hour.is_some() || options.minute.is_some() || options.second.is_some();\n\n    if has_date && has_time {\n        parts.push(FormatPart::literal(\", \"));\n    }\n\n    // Hour\n    if options.hour.is_some() {\n        let hour = local_dt.hour();\n        let hour_val = if options.hour12 {\n            match hour {\n                0 => 12,\n                13..=23 => hour - 12,\n                _ => hour,\n            }\n        } else {\n            hour\n        };\n\n        parts.push(FormatPart::new(\n            \"hour\",\n            format_component(hour_val.into(), options.hour.as_deref()),\n        ));\n\n        if options.minute.is_some() || options.second.is_some() {\n            parts.push(FormatPart::literal(\":\"));\n        }\n    }\n\n    // Minute\n    if options.minute.is_some() {\n        parts.push(FormatPart::new(\n            \"minute\",\n            format_component(local_dt.minute().into(), options.minute.as_deref()),\n        ));\n\n        if options.second.is_some() {\n            parts.push(FormatPart::literal(\":\"));\n        }\n    }\n\n    // Second\n    if options.second.is_some() {\n        parts.push(FormatPart::new(\n            \"second\",\n            format_component(local_dt.second().into(), options.second.as_deref()),\n        ));\n    }\n\n    // dayPeriod for 12-hour format\n    if options.hour12 && options.hour.is_some() {\n        let hour = local_dt.hour();\n        parts.push(FormatPart::literal(\" \"));\n        parts.push(FormatPart::new(\n            \"dayPeriod\",\n            if hour >= 12 { \"PM\" } else { \"AM\" }.to_string(),\n        ));\n    }\n\n    // Timezone name\n    if let Some(ref tz_name_opt) = options.timezone_name {\n        parts.push(FormatPart::literal(\" \"));\n        let tz_str = format_timezone_name(local_dt, &options.timezone, tz_name_opt);\n        parts.push(FormatPart::new(\"timeZoneName\", tz_str));\n    }\n\n    parts\n}\n\n/// Format timezone name based on style option\nfn format_timezone_name(local_dt: &Zoned, timezone: &TimeZone, style: &str) -> String {\n    match style {\n        \"short\" | \"shortOffset\" => {\n            let offset = local_dt.offset();\n            let total_secs = offset.seconds();\n            let hours = total_secs / 3600;\n            let mins = (total_secs % 3600).abs() / 60;\n\n            let mut result = String::with_capacity(10);\n            result.push_str(\"GMT\");\n\n            if hours >= 0 {\n                result.push('+');\n            }\n\n            let mut buf = itoa::Buffer::new();\n            result.push_str(buf.format(hours));\n\n            if mins != 0 && style == \"shortOffset\" {\n                result.push(':');\n                if mins < 10 {\n                    result.push('0');\n                }\n                result.push_str(buf.format(mins));\n            }\n\n            result\n        },\n        \"long\" => timezone.iana_name().unwrap_or_default().into(),\n        _ => timezone.iana_name().unwrap_or_default().into(),\n    }\n}\n\n/// Convert format parts Vec to JS Array\nfn parts_to_js_array<'js>(ctx: &Ctx<'js>, parts: Vec<FormatPart>) -> Result<Array<'js>> {\n    let array = Array::new(ctx.clone())?;\n    for (idx, part) in parts.into_iter().enumerate() {\n        let obj = Object::new(ctx.clone())?;\n        obj.set(\"type\", part.part_type)?;\n        obj.set(\"value\", part.value)?;\n        array.set(idx, obj)?;\n    }\n    Ok(array)\n}\n\n/// Join format parts into a single string\nfn parts_to_string(parts: &[FormatPart]) -> String {\n    let total_len: usize = parts.iter().map(|p| p.value.len()).sum();\n    let mut result = String::with_capacity(total_len);\n    for part in parts {\n        result.push_str(&part.value);\n    }\n    result\n}\n\n/// Parse epoch milliseconds from a Date value\nfn parse_epoch_ms<'js>(ctx: &Ctx<'js>, date: Opt<Value<'js>>) -> Result<f64> {\n    if let Some(date_val) = date.into_inner() {\n        if date_val.is_undefined() {\n            Ok(Timestamp::now().as_millisecond() as f64)\n        } else if let Some(num) = date_val.as_number() {\n            Ok(num)\n        } else {\n            date_val\n                .get::<Coerced<f64>>()\n                .map(|c| c.0)\n                .map_err(|_| Exception::throw_type(ctx, \"Invalid date\"))\n        }\n    } else {\n        Ok(Timestamp::now().as_millisecond() as f64)\n    }\n}\n\n/// Convert epoch milliseconds to Zoned datetime in the specified timezone\nfn epoch_to_datetime(ctx: &Ctx<'_>, epoch_ms: f64, timezone: &TimeZone) -> Result<Zoned> {\n    let utc_dt = Timestamp::from_millisecond(epoch_ms as i64)\n        .map_err(|_| Exception::throw_range(ctx, \"Invalid timestamp\"))?;\n    Ok(utc_dt.to_zoned(timezone.clone()))\n}\n\n/// Minimal Intl.DateTimeFormat implementation\n#[derive(Clone, rquickjs::class::Trace, rquickjs::JsLifetime)]\n#[rquickjs::class]\npub struct DateTimeFormat {\n    #[qjs(skip_trace)]\n    options: DateTimeFormatOptions,\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl DateTimeFormat {\n    #[qjs(constructor)]\n    pub fn new(ctx: Ctx<'_>, locales: Opt<Value<'_>>, options: Opt<Object<'_>>) -> Result<Self> {\n        let mut opts = DateTimeFormatOptions::default();\n\n        // Parse locale (we only care about extracting the language tag)\n        if let Some(locale_val) = locales.into_inner() {\n            if let Some(s) = locale_val.as_string() {\n                opts.locale = s.to_string()?;\n            } else if let Some(arr) = locale_val.as_array() {\n                if let Ok(first) = arr.get::<Value>(0) {\n                    if let Some(s) = first.as_string() {\n                        opts.locale = s.to_string()?;\n                    }\n                }\n            }\n        }\n\n        // Parse options\n        if let Some(options_obj) = options.into_inner() {\n            // timeZone\n            if let Ok(tz_val) = options_obj.get::<_, String>(\"timeZone\") {\n                opts.timezone = TimeZone::get(&tz_val).map_err(|_| {\n                    Exception::throw_range(&ctx, &[\"Invalid time zone: \", &tz_val].concat())\n                })?;\n            }\n\n            // hour12\n            if let Ok(h12) = options_obj.get::<_, bool>(\"hour12\") {\n                opts.hour12 = h12;\n            }\n\n            // Date/time components\n            if let Ok(v) = options_obj.get::<_, String>(\"year\") {\n                opts.year = Some(v);\n            }\n            if let Ok(v) = options_obj.get::<_, String>(\"month\") {\n                opts.month = Some(v);\n            }\n            if let Ok(v) = options_obj.get::<_, String>(\"day\") {\n                opts.day = Some(v);\n            }\n            if let Ok(v) = options_obj.get::<_, String>(\"hour\") {\n                opts.hour = Some(v);\n            }\n            if let Ok(v) = options_obj.get::<_, String>(\"minute\") {\n                opts.minute = Some(v);\n            }\n            if let Ok(v) = options_obj.get::<_, String>(\"second\") {\n                opts.second = Some(v);\n            }\n            if let Ok(v) = options_obj.get::<_, String>(\"weekday\") {\n                opts.weekday = Some(v);\n            }\n            if let Ok(v) = options_obj.get::<_, String>(\"timeZoneName\") {\n                opts.timezone_name = Some(v);\n            }\n            if let Ok(v) = options_obj.get::<_, u8>(\"fractionalSecondDigits\") {\n                opts.fractional_second_digits = Some(v);\n            }\n        }\n\n        Ok(Self { options: opts })\n    }\n\n    /// Format a date according to the locale and options\n    pub fn format<'js>(&self, ctx: Ctx<'js>, date: Opt<Value<'js>>) -> Result<String> {\n        let epoch_ms = parse_epoch_ms(&ctx, date)?;\n        let local_dt = epoch_to_datetime(&ctx, epoch_ms, &self.options.timezone)?;\n        let parts = build_format_parts(&local_dt, &self.options);\n        Ok(parts_to_string(&parts))\n    }\n\n    /// Format a date to parts\n    #[qjs(rename = \"formatToParts\")]\n    pub fn format_to_parts<'js>(&self, ctx: Ctx<'js>, date: Opt<Value<'js>>) -> Result<Array<'js>> {\n        let epoch_ms = parse_epoch_ms(&ctx, date)?;\n        let local_dt = epoch_to_datetime(&ctx, epoch_ms, &self.options.timezone)?;\n        let parts = build_format_parts(&local_dt, &self.options);\n        parts_to_js_array(&ctx, parts)\n    }\n\n    /// Return resolved options\n    #[qjs(rename = \"resolvedOptions\")]\n    pub fn resolved_options<'js>(&self, ctx: Ctx<'js>) -> Result<Object<'js>> {\n        let obj = Object::new(ctx.clone())?;\n\n        obj.set(\"locale\", self.options.locale.as_str())?;\n        obj.set(\"calendar\", \"gregory\")?;\n        obj.set(\"numberingSystem\", \"latn\")?;\n        obj.set(\n            \"timeZone\",\n            self.options.timezone.iana_name().unwrap_or_default(),\n        )?;\n\n        if self.options.hour.is_some() {\n            obj.set(\"hour12\", self.options.hour12)?;\n            obj.set(\"hourCycle\", if self.options.hour12 { \"h12\" } else { \"h23\" })?;\n        }\n\n        if let Some(ref v) = self.options.year {\n            obj.set(\"year\", v.as_str())?;\n        }\n        if let Some(ref v) = self.options.month {\n            obj.set(\"month\", v.as_str())?;\n        }\n        if let Some(ref v) = self.options.day {\n            obj.set(\"day\", v.as_str())?;\n        }\n        if let Some(ref v) = self.options.hour {\n            obj.set(\"hour\", v.as_str())?;\n        }\n        if let Some(ref v) = self.options.minute {\n            obj.set(\"minute\", v.as_str())?;\n        }\n        if let Some(ref v) = self.options.second {\n            obj.set(\"second\", v.as_str())?;\n        }\n        if let Some(ref v) = self.options.weekday {\n            obj.set(\"weekday\", v.as_str())?;\n        }\n        if let Some(ref v) = self.options.timezone_name {\n            obj.set(\"timeZoneName\", v.as_str())?;\n        }\n\n        Ok(obj)\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    pub fn to_string_tag(&self) -> &'static str {\n        \"Intl.DateTimeFormat\"\n    }\n}\n\n/// Format a date in the specified timezone using locale options.\n/// This is used to implement Date.prototype.toLocaleString with timezone support.\npub fn format_date_in_timezone(\n    epoch_ms: f64,\n    timezone: &TimeZone,\n    options: &ToLocaleStringOptions,\n) -> String {\n    let utc_dt = Timestamp::from_millisecond(epoch_ms as i64).unwrap();\n    let local_dt = utc_dt.to_zoned(timezone.clone());\n\n    // Format as MM/DD/YYYY, HH:MM:SS AM/PM (en-US style)\n    let month = local_dt.month();\n    let day = local_dt.day();\n    let year = local_dt.year();\n    let hour = local_dt.hour();\n    let minute = local_dt.minute();\n    let second = local_dt.second();\n\n    let mut buf = itoa::Buffer::new();\n    let mut result = String::with_capacity(24);\n\n    // Month (zero-padded)\n    if month < 10 {\n        result.push('0');\n    }\n    result.push_str(buf.format(month));\n    result.push('/');\n\n    // Day (zero-padded)\n    if day < 10 {\n        result.push('0');\n    }\n    result.push_str(buf.format(day));\n    result.push('/');\n\n    // Year\n    result.push_str(buf.format(year));\n    result.push_str(\", \");\n\n    if options.hour12 {\n        let (hour12, period) = match hour {\n            0 => (12, \"AM\"),\n            1..=11 => (hour, \"AM\"),\n            12 => (12, \"PM\"),\n            _ => (hour - 12, \"PM\"),\n        };\n\n        // Hour (no padding for 12-hour format)\n        result.push_str(buf.format(hour12));\n        result.push(':');\n\n        // Minute (zero-padded)\n        if minute < 10 {\n            result.push('0');\n        }\n        result.push_str(buf.format(minute));\n        result.push(':');\n\n        // Second (zero-padded)\n        if second < 10 {\n            result.push('0');\n        }\n        result.push_str(buf.format(second));\n\n        result.push(' ');\n        result.push_str(period);\n    } else {\n        // Hour (zero-padded)\n        if hour < 10 {\n            result.push('0');\n        }\n        result.push_str(buf.format(hour));\n        result.push(':');\n\n        // Minute (zero-padded)\n        if minute < 10 {\n            result.push('0');\n        }\n        result.push_str(buf.format(minute));\n        result.push(':');\n\n        // Second (zero-padded)\n        if second < 10 {\n            result.push('0');\n        }\n        result.push_str(buf.format(second));\n    }\n\n    result\n}\n\n/// Options for toLocaleString\n#[derive(Default)]\npub struct ToLocaleStringOptions {\n    pub hour12: bool,\n    pub hour12_set: bool,\n    pub date_style: Option<String>,\n    pub time_style: Option<String>,\n}\n\n/// Parse toLocaleString options from a JavaScript object\npub fn parse_to_locale_string_options<'js>(\n    ctx: &Ctx<'js>,\n    options: Option<Object<'js>>,\n) -> Result<(Option<TimeZone>, ToLocaleStringOptions)> {\n    let mut tz: Option<TimeZone> = None;\n    let mut opts = ToLocaleStringOptions::default();\n\n    if let Some(options_obj) = options {\n        // Parse timeZone\n        if let Ok(tz_val) = options_obj.get::<_, String>(\"timeZone\") {\n            tz = Some(TimeZone::get(&tz_val).map_err(|_| {\n                Exception::throw_range(ctx, &[\"Invalid time zone: \", &tz_val].concat())\n            })?);\n        }\n\n        // Parse hour12\n        if let Ok(h12) = options_obj.get::<_, bool>(\"hour12\") {\n            opts.hour12 = h12;\n            opts.hour12_set = true;\n        }\n\n        // Parse dateStyle\n        if let Ok(ds) = options_obj.get::<_, String>(\"dateStyle\") {\n            opts.date_style = Some(ds);\n        }\n\n        // Parse timeStyle\n        if let Ok(ts) = options_obj.get::<_, String>(\"timeStyle\") {\n            opts.time_style = Some(ts);\n        }\n    }\n\n    Ok((tz, opts))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use jiff::tz::TimeZone;\n\n    #[test]\n    fn test_format_number() {\n        assert_eq!(format_number(5, false), \"5\");\n        assert_eq!(format_number(5, true), \"05\");\n        assert_eq!(format_number(12, true), \"12\");\n        assert_eq!(format_number(0, true), \"00\");\n    }\n\n    #[test]\n    fn test_format_component() {\n        assert_eq!(format_component(5, Some(\"2-digit\")), \"05\");\n        assert_eq!(format_component(5, Some(\"numeric\")), \"5\");\n        assert_eq!(format_component(12, Some(\"2-digit\")), \"12\");\n        assert_eq!(format_component(12, None), \"12\");\n    }\n\n    #[test]\n    fn test_build_format_parts_date_only() {\n        let tz = TimeZone::get(\"UTC\").unwrap();\n        // 2024-03-15 10:30:45 UTC\n        let epoch_ms = 1710499845000.0;\n        let utc_dt = Timestamp::from_millisecond(epoch_ms as i64).unwrap();\n        let local_dt = utc_dt.to_zoned(tz);\n\n        let options = DateTimeFormatOptions {\n            year: Some(\"numeric\".to_string()),\n            month: Some(\"2-digit\".to_string()),\n            day: Some(\"2-digit\".to_string()),\n            ..Default::default()\n        };\n\n        let parts = build_format_parts(&local_dt, &options);\n\n        assert_eq!(parts.len(), 5); // month, /, day, /, year\n        assert_eq!(parts[0].part_type, \"month\");\n        assert_eq!(parts[0].value, \"03\");\n        assert_eq!(parts[1].part_type, \"literal\");\n        assert_eq!(parts[1].value, \"/\");\n        assert_eq!(parts[2].part_type, \"day\");\n        assert_eq!(parts[2].value, \"15\");\n        assert_eq!(parts[4].part_type, \"year\");\n        assert_eq!(parts[4].value, \"2024\");\n    }\n\n    #[test]\n    fn test_build_format_parts_time_only() {\n        let tz = TimeZone::get(\"UTC\").unwrap();\n        // 2024-03-15 10:30:45 UTC\n        let epoch_ms = 1710498645000.0;\n        let utc_dt = Timestamp::from_millisecond(epoch_ms as i64).unwrap();\n        let local_dt = utc_dt.to_zoned(tz);\n\n        let options = DateTimeFormatOptions {\n            hour: Some(\"2-digit\".to_string()),\n            minute: Some(\"2-digit\".to_string()),\n            second: Some(\"2-digit\".to_string()),\n            ..Default::default()\n        };\n\n        let parts = build_format_parts(&local_dt, &options);\n\n        assert_eq!(parts[0].part_type, \"hour\");\n        assert_eq!(parts[0].value, \"10\");\n        assert_eq!(parts[2].part_type, \"minute\");\n        assert_eq!(parts[2].value, \"30\");\n        assert_eq!(parts[4].part_type, \"second\");\n        assert_eq!(parts[4].value, \"45\");\n    }\n\n    #[test]\n    fn test_build_format_parts_12hour() {\n        let tz = TimeZone::get(\"UTC\").unwrap();\n        // 2024-03-15 14:30:00 UTC (2 PM)\n        let epoch_ms = 1710514200000.0;\n        let utc_dt = Timestamp::from_millisecond(epoch_ms as i64).unwrap();\n        let local_dt = utc_dt.to_zoned(tz);\n\n        let options = DateTimeFormatOptions {\n            hour: Some(\"numeric\".to_string()),\n            hour12: true,\n            ..Default::default()\n        };\n\n        let parts = build_format_parts(&local_dt, &options);\n\n        assert_eq!(parts[0].part_type, \"hour\");\n        assert_eq!(parts[0].value, \"2\"); // 14:00 -> 2 PM\n        assert_eq!(parts[2].part_type, \"dayPeriod\");\n        assert_eq!(parts[2].value, \"PM\");\n    }\n\n    #[test]\n    fn test_build_format_parts_midnight_12hour() {\n        let tz = TimeZone::get(\"UTC\").unwrap();\n        // 2024-03-15 00:30:00 UTC (12:30 AM)\n        let epoch_ms = 1710463800000.0;\n        let utc_dt = Timestamp::from_millisecond(epoch_ms as i64).unwrap();\n        let local_dt = utc_dt.to_zoned(tz);\n\n        let options = DateTimeFormatOptions {\n            hour: Some(\"numeric\".to_string()),\n            hour12: true,\n            ..Default::default()\n        };\n\n        let parts = build_format_parts(&local_dt, &options);\n\n        assert_eq!(parts[0].part_type, \"hour\");\n        assert_eq!(parts[0].value, \"12\"); // 00:00 -> 12 AM\n        assert_eq!(parts[2].part_type, \"dayPeriod\");\n        assert_eq!(parts[2].value, \"AM\");\n    }\n\n    #[test]\n    fn test_format_timezone_name_short() {\n        let tz = TimeZone::get(\"America/New_York\").unwrap();\n        // Summer time (EDT = UTC-4)\n        let epoch_ms = 1720000000000.0; // July 2024\n        let utc_dt = Timestamp::from_millisecond(epoch_ms as i64).unwrap();\n        let local_dt = utc_dt.to_zoned(tz.clone());\n\n        let result = format_timezone_name(&local_dt, &tz, \"short\");\n        assert_eq!(result, \"GMT-4\");\n    }\n\n    #[test]\n    fn test_format_timezone_name_long() {\n        let tz = TimeZone::get(\"America/New_York\").unwrap();\n        let epoch_ms = 1720000000000.0;\n        let utc_dt = Timestamp::from_millisecond(epoch_ms as i64).unwrap();\n        let local_dt = utc_dt.to_zoned(tz.clone());\n\n        let result = format_timezone_name(&local_dt, &tz, \"long\");\n        assert_eq!(result, \"America/New_York\");\n    }\n\n    #[test]\n    fn test_parts_to_string() {\n        let parts = vec![\n            FormatPart::new(\"month\", \"03\".to_string()),\n            FormatPart::literal(\"/\"),\n            FormatPart::new(\"day\", \"15\".to_string()),\n            FormatPart::literal(\"/\"),\n            FormatPart::new(\"year\", \"2024\".to_string()),\n        ];\n\n        assert_eq!(parts_to_string(&parts), \"03/15/2024\");\n    }\n\n    #[test]\n    fn test_format_date_in_timezone() {\n        // 2024-03-15 14:30:45 UTC\n        let epoch_ms = 1710513045000.0;\n        let tz = TimeZone::get(\"UTC\").unwrap();\n\n        let opts = ToLocaleStringOptions {\n            hour12: true,\n            ..Default::default()\n        };\n        let result = format_date_in_timezone(epoch_ms, &tz, &opts);\n        assert_eq!(result, \"03/15/2024, 2:30:45 PM\");\n\n        let opts = ToLocaleStringOptions {\n            hour12: false,\n            ..Default::default()\n        };\n        let result = format_date_in_timezone(epoch_ms, &tz, &opts);\n        assert_eq!(result, \"03/15/2024, 14:30:45\");\n    }\n\n    #[test]\n    fn test_format_date_in_timezone_with_tz() {\n        // 2024-03-15 14:30:45 UTC -> 10:30:45 AM EDT (UTC-4)\n        let epoch_ms = 1710513045000.0;\n        let tz = TimeZone::get(\"America/New_York\").unwrap();\n\n        let opts = ToLocaleStringOptions {\n            hour12: true,\n            ..Default::default()\n        };\n        let result = format_date_in_timezone(epoch_ms, &tz, &opts);\n        assert_eq!(result, \"03/15/2024, 10:30:45 AM\");\n    }\n\n    #[test]\n    fn test_format_date_midnight() {\n        // 2024-03-15 00:00:00 UTC\n        let epoch_ms = 1710460800000.0;\n        let tz = TimeZone::get(\"UTC\").unwrap();\n\n        let opts = ToLocaleStringOptions {\n            hour12: true,\n            ..Default::default()\n        };\n        let result = format_date_in_timezone(epoch_ms, &tz, &opts);\n        assert_eq!(result, \"03/15/2024, 12:00:00 AM\");\n\n        let opts = ToLocaleStringOptions {\n            hour12: false,\n            ..Default::default()\n        };\n        let result = format_date_in_timezone(epoch_ms, &tz, &opts);\n        assert_eq!(result, \"03/15/2024, 00:00:00\");\n    }\n\n    #[test]\n    fn test_format_date_noon() {\n        // 2024-03-15 12:00:00 UTC\n        let epoch_ms = 1710504000000.0;\n        let tz = TimeZone::get(\"UTC\").unwrap();\n\n        let opts = ToLocaleStringOptions {\n            hour12: true,\n            ..Default::default()\n        };\n        let result = format_date_in_timezone(epoch_ms, &tz, &opts);\n        assert_eq!(result, \"03/15/2024, 12:00:00 PM\");\n    }\n}\n"
  },
  {
    "path": "modules/llrt_intl/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\n//! Minimal Intl module for LLRT.\n//!\n//! Provides a subset of the `Intl` API focused on timezone support,\n//! enabling compatibility with libraries like dayjs.\n\nmod cldr_data;\nmod date_time_format;\nmod pattern_formatter;\n\npub use date_time_format::{\n    format_date_in_timezone, parse_to_locale_string_options, DateTimeFormat, DateTimeFormatOptions,\n    ToLocaleStringOptions,\n};\n\nuse cldr_data::get_locale_data;\nuse jiff::{\n    tz::{TimeZone, TimeZoneDatabase},\n    Timestamp,\n};\nuse pattern_formatter::{combine_datetime, format_with_pattern};\nuse rquickjs::{\n    function::{Constructor, Opt, This},\n    prelude::Func,\n    Array, Class, Coerced, Ctx, Exception, Object, Result, Value,\n};\n\n/// Initialize the Intl global object with DateTimeFormat\npub fn init(ctx: &Ctx<'_>) -> Result<()> {\n    let globals = ctx.globals();\n\n    // Create Intl object\n    let intl = Object::new(ctx.clone())?;\n    intl.set(\"supportedValuesOf\", Func::from(supported_values_of))?;\n\n    // Add DateTimeFormat constructor\n    Class::<DateTimeFormat>::define(&intl)?;\n\n    // Set Intl global\n    globals.set(\"Intl\", intl)?;\n\n    // Patch Date.prototype.toLocaleString to support timeZone option\n    patch_date_to_locale_string(ctx)?;\n\n    Ok(())\n}\n\n/// Patch Date.prototype.toLocaleString to support the timeZone option\nfn patch_date_to_locale_string(ctx: &Ctx<'_>) -> Result<()> {\n    let globals = ctx.globals();\n    let date_ctor: Constructor = globals.get(\"Date\")?;\n    let date_proto: Object = date_ctor.get(\"prototype\")?;\n\n    // Replace toLocaleString with our implementation\n    date_proto.set(\"toLocaleString\", Func::from(date_to_locale_string))?;\n\n    Ok(())\n}\n\n/// Custom Date.prototype.toLocaleString implementation with timezone and locale support\nfn date_to_locale_string<'js>(\n    ctx: Ctx<'js>,\n    this: This<Value<'js>>,\n    locale: Opt<Value<'js>>,\n    options: Opt<Object<'js>>,\n) -> Result<String> {\n    // Coerce Date to number (uses valueOf internally, same as getTime)\n    let epoch_ms = this\n        .0\n        .get::<Coerced<f64>>()\n        .map(|c| c.0)\n        .map_err(|_| Exception::throw_type(&ctx, \"this is not a Date object\"))?;\n\n    // Check for NaN (Invalid Date)\n    if epoch_ms.is_nan() {\n        return Ok(\"Invalid Date\".to_string());\n    }\n\n    // Parse locale\n    let locale_str = parse_locale_arg(locale)?;\n    let locale_data = get_locale_data(&locale_str);\n\n    // Parse options\n    let (tz, opts) = parse_to_locale_string_options(&ctx, options.0)?;\n\n    let timezone = tz.unwrap_or(TimeZone::system());\n\n    // Convert epoch to DateTime\n    let utc_dt = Timestamp::from_millisecond(epoch_ms as i64)\n        .map_err(|_| Exception::throw_range(&ctx, \"Invalid timestamp\"))?;\n    let local_dt = utc_dt.to_zoned(timezone);\n\n    // Determine hour12 setting - use locale default if not explicitly set\n    let hour12 = if opts.hour12_set {\n        Some(opts.hour12)\n    } else {\n        Some(locale_data.hour12_default)\n    };\n\n    // Format using CLDR patterns based on dateStyle/timeStyle\n    let (date_style, time_style) = (opts.date_style.as_deref(), opts.time_style.as_deref());\n\n    match (date_style, time_style) {\n        (Some(ds), Some(ts)) => {\n            // Both date and time\n            let date_pattern = get_date_pattern(ds, locale_data);\n            let time_pattern = get_time_pattern(ts, locale_data);\n            let date_str = format_with_pattern(&local_dt, date_pattern, locale_data, hour12);\n            let time_str = format_with_pattern(&local_dt, time_pattern, locale_data, hour12);\n            Ok(combine_datetime(\n                &date_str,\n                &time_str,\n                locale_data.datetime_pattern,\n            ))\n        },\n        (Some(ds), None) => {\n            // Date only\n            let date_pattern = get_date_pattern(ds, locale_data);\n            Ok(format_with_pattern(\n                &local_dt,\n                date_pattern,\n                locale_data,\n                hour12,\n            ))\n        },\n        (None, Some(ts)) => {\n            // Time only\n            let time_pattern = get_time_pattern(ts, locale_data);\n            Ok(format_with_pattern(\n                &local_dt,\n                time_pattern,\n                locale_data,\n                hour12,\n            ))\n        },\n        (None, None) => {\n            // Default: short date and medium time (matching browser behavior)\n            let date_str = format_with_pattern(\n                &local_dt,\n                locale_data.date_formats.short,\n                locale_data,\n                hour12,\n            );\n            let time_str = format_with_pattern(\n                &local_dt,\n                locale_data.time_formats.medium,\n                locale_data,\n                hour12,\n            );\n            Ok(combine_datetime(\n                &date_str,\n                &time_str,\n                locale_data.datetime_pattern,\n            ))\n        },\n    }\n}\n\n/// Parse locale argument from JavaScript\nfn parse_locale_arg(locale: Opt<Value<'_>>) -> Result<String> {\n    if let Some(val) = locale.into_inner() {\n        if val.is_undefined() || val.is_null() {\n            return Ok(\"en-US\".to_string());\n        }\n        if let Some(s) = val.as_string() {\n            return s.to_string();\n        }\n        if let Some(arr) = val.as_array() {\n            if let Ok(first) = arr.get::<Value>(0) {\n                if let Some(s) = first.as_string() {\n                    return s.to_string();\n                }\n            }\n        }\n    }\n    Ok(\"en-US\".to_string())\n}\n\n/// Get date pattern for a given style\nfn get_date_pattern<'a>(style: &str, locale_data: &'a cldr_data::LocaleData) -> &'a str {\n    match style {\n        \"full\" => locale_data.date_formats.full,\n        \"long\" => locale_data.date_formats.long,\n        \"medium\" => locale_data.date_formats.medium,\n        \"short\" => locale_data.date_formats.short,\n        _ => locale_data.date_formats.medium,\n    }\n}\n\n/// Get time pattern for a given style\nfn get_time_pattern<'a>(style: &str, locale_data: &'a cldr_data::LocaleData) -> &'a str {\n    match style {\n        \"full\" => locale_data.time_formats.full,\n        \"long\" => locale_data.time_formats.long,\n        \"medium\" => locale_data.time_formats.medium,\n        \"short\" => locale_data.time_formats.short,\n        _ => locale_data.time_formats.medium,\n    }\n}\n\nfn supported_values_of<'js>(ctx: Ctx<'js>, key: String) -> Result<Array<'js>> {\n    let array = Array::new(ctx.clone())?;\n    match key.as_ref() {\n        \"timeZone\" => {\n            let timezones = TimeZoneDatabase::from_env();\n\n            for (i, tz) in timezones.available().enumerate() {\n                array.set(i, tz.as_str())?;\n            }\n        },\n        _ => {\n            return Err(Exception::throw_range(\n                &ctx,\n                \"Unknown key for Intl.supportedValuesOf\",\n            ))\n        },\n    }\n\n    Ok(array)\n}\n"
  },
  {
    "path": "modules/llrt_intl/src/pattern_formatter.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\n//! CLDR pattern parser and formatter.\n//!\n//! Parses Unicode CLDR date/time patterns and formats dates accordingly.\n//! Pattern syntax follows Unicode Technical Standard #35:\n//! https://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table\n\nuse crate::cldr_data::LocaleData;\nuse jiff::Zoned;\n\n/// Format a Zoned datetime using a CLDR pattern string\npub fn format_with_pattern(\n    dt: &Zoned,\n    pattern: &str,\n    locale_data: &LocaleData,\n    hour12_override: Option<bool>,\n) -> String {\n    let mut result = String::with_capacity(pattern.len() * 2);\n    let mut chars = pattern.chars().peekable();\n\n    while let Some(ch) = chars.next() {\n        match ch {\n            // Quoted literal text\n            '\\'' => {\n                // Check for escaped quote ('')\n                if chars.peek() == Some(&'\\'') {\n                    chars.next();\n                    result.push('\\'');\n                } else {\n                    // Collect until closing quote\n                    for c in chars.by_ref() {\n                        if c == '\\'' {\n                            break;\n                        }\n                        result.push(c);\n                    }\n                }\n            },\n            // Pattern letters\n            'y' | 'Y' => {\n                let count = 1 + consume_same(&mut chars, ch);\n                format_year(&mut result, dt.year(), count);\n            },\n            'M' | 'L' => {\n                let count = 1 + consume_same(&mut chars, ch);\n                format_month(&mut result, dt.month(), count, locale_data);\n            },\n            'd' => {\n                let count = 1 + consume_same(&mut chars, ch);\n                format_number(&mut result, dt.day(), count);\n            },\n            'E' | 'e' | 'c' => {\n                let count = 1 + consume_same(&mut chars, ch);\n                format_weekday(\n                    &mut result,\n                    dt.weekday().to_sunday_zero_offset() as usize,\n                    count,\n                    locale_data,\n                );\n            },\n            'a' => {\n                consume_same(&mut chars, ch);\n                // Only show AM/PM if we're using 12-hour format\n                let use_12h = hour12_override.unwrap_or(true);\n                if use_12h {\n                    let hour = dt.hour();\n                    if hour < 12 {\n                        result.push_str(locale_data.am);\n                    } else {\n                        result.push_str(locale_data.pm);\n                    }\n                }\n            },\n            'h' => {\n                let count = 1 + consume_same(&mut chars, ch);\n                let hour = dt.hour();\n                // If hour12 is explicitly false, use 24-hour format instead\n                let use_12h = hour12_override.unwrap_or(true);\n                if use_12h {\n                    // 12-hour format (1-12)\n                    let hour12 = match hour {\n                        0 => 12,\n                        1..=12 => hour,\n                        _ => hour - 12,\n                    };\n                    format_number(&mut result, hour12, count);\n                } else {\n                    // 24-hour format (0-23)\n                    format_number(&mut result, hour, count);\n                }\n            },\n            'H' => {\n                let count = 1 + consume_same(&mut chars, ch);\n                let hour = dt.hour();\n                // If hour12 is explicitly true, use 12-hour format instead\n                let use_12h = hour12_override.unwrap_or(false);\n                if use_12h {\n                    let hour12 = match hour {\n                        0 => 12,\n                        1..=12 => hour,\n                        _ => hour - 12,\n                    };\n                    format_number(&mut result, hour12, count);\n                } else {\n                    // 24-hour format (0-23)\n                    format_number(&mut result, hour, count);\n                }\n            },\n            'm' => {\n                let count = 1 + consume_same(&mut chars, ch);\n                format_number(&mut result, dt.minute(), count);\n            },\n            's' => {\n                let count = 1 + consume_same(&mut chars, ch);\n                format_number(&mut result, dt.second(), count);\n            },\n            'z' => {\n                let count = 1 + consume_same(&mut chars, ch);\n                format_timezone(&mut result, dt, count);\n            },\n            'Z' | 'O' | 'v' | 'V' | 'X' | 'x' => {\n                let count = 1 + consume_same(&mut chars, ch);\n                format_timezone(&mut result, dt, count);\n            },\n            // Skip these pattern letters (not commonly needed)\n            'G' | 'q' | 'Q' | 'w' | 'W' | 'D' | 'F' | 'g' | 'A' | 'S' => {\n                consume_same(&mut chars, ch);\n            },\n            // Pass through literal characters\n            _ => {\n                result.push(ch);\n            },\n        }\n    }\n\n    // If hour12=true and pattern originally used 24h format (H) without AM/PM marker,\n    // we need to append AM/PM since we converted to 12h format\n    if let Some(true) = hour12_override {\n        if !pattern.contains('a') && pattern.contains('H') {\n            result.push(' ');\n            if dt.hour() < 12 {\n                result.push_str(locale_data.am);\n            } else {\n                result.push_str(locale_data.pm);\n            }\n        }\n    }\n\n    result\n}\n\n/// Consume consecutive identical characters, returning count of additional chars\nfn consume_same(chars: &mut std::iter::Peekable<std::str::Chars>, ch: char) -> usize {\n    let mut count = 0;\n    while chars.peek() == Some(&ch) {\n        chars.next();\n        count += 1;\n    }\n    count\n}\n\n/// Format year based on pattern width\nfn format_year(result: &mut String, year: i16, width: usize) {\n    let mut buf = itoa::Buffer::new();\n    if width == 2 {\n        // 2-digit year\n        let short_year = (year % 100).unsigned_abs();\n        if short_year < 10 {\n            result.push('0');\n        }\n        result.push_str(buf.format(short_year));\n    } else {\n        result.push_str(buf.format(year));\n    }\n}\n\n/// Format month based on pattern width\nfn format_month(result: &mut String, month: i8, width: usize, locale_data: &LocaleData) {\n    match width {\n        1 => {\n            // Numeric, no padding\n            let mut buf = itoa::Buffer::new();\n            result.push_str(buf.format(month));\n        },\n        2 => {\n            // Numeric, zero-padded\n            let mut buf = itoa::Buffer::new();\n            if month < 10 {\n                result.push('0');\n            }\n            result.push_str(buf.format(month));\n        },\n        3 => {\n            // Abbreviated\n            if (1..=12).contains(&month) {\n                result.push_str(locale_data.months_abbr[month as usize - 1]);\n            }\n        },\n        _ => {\n            // Wide (4+)\n            if (1..=12).contains(&month) {\n                result.push_str(locale_data.months_wide[month as usize - 1]);\n            }\n        },\n    }\n}\n\n/// Format weekday based on pattern width\nfn format_weekday(result: &mut String, weekday: usize, width: usize, locale_data: &LocaleData) {\n    match width {\n        1..=3 => {\n            // Abbreviated\n            result.push_str(locale_data.days_abbr[weekday]);\n        },\n        _ => {\n            // Wide (4+)\n            result.push_str(locale_data.days_wide[weekday]);\n        },\n    }\n}\n\n/// Format a number with optional zero-padding\nfn format_number(result: &mut String, value: i8, min_width: usize) {\n    let mut buf = itoa::Buffer::new();\n    let s = buf.format(value);\n    if min_width >= 2 && s.len() < min_width {\n        for _ in 0..(min_width - s.len()) {\n            result.push('0');\n        }\n    }\n    result.push_str(s);\n}\n\n/// Format timezone\nfn format_timezone(result: &mut String, dt: &Zoned, width: usize) {\n    let total_secs = dt.offset().seconds();\n    let hours = total_secs / 3600;\n    let mins = (total_secs % 3600).abs() / 60;\n\n    if width >= 4 {\n        // Long form: timezone name\n        result.push_str(dt.time_zone().iana_name().unwrap_or_default());\n    } else {\n        // Short form: GMT offset\n        result.push_str(\"GMT\");\n        if hours >= 0 {\n            result.push('+');\n        }\n        let mut buf = itoa::Buffer::new();\n        result.push_str(buf.format(hours));\n        if mins != 0 {\n            result.push(':');\n            if mins < 10 {\n                result.push('0');\n            }\n            result.push_str(buf.format(mins));\n        }\n    }\n}\n\n/// Combine date and time strings using a datetime pattern\npub fn combine_datetime(date: &str, time: &str, pattern: &str) -> String {\n    pattern.replace(\"{1}\", date).replace(\"{0}\", time)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::cldr_data::get_locale_data;\n    use jiff::{civil, tz::TimeZone, Zoned};\n\n    fn make_dt(year: i16, month: i8, day: i8, hour: i8, min: i8, sec: i8) -> Zoned {\n        civil::date(year, month, day)\n            .at(hour, min, sec, 0)\n            .to_zoned(TimeZone::UTC)\n            .unwrap()\n    }\n\n    #[test]\n    fn test_format_year() {\n        let dt = make_dt(2024, 3, 15, 10, 30, 45);\n        let locale = get_locale_data(\"en-US\");\n\n        assert!(format_with_pattern(&dt, \"y\", locale, None).contains(\"2024\"));\n        assert!(format_with_pattern(&dt, \"yy\", locale, None).contains(\"24\"));\n        assert!(format_with_pattern(&dt, \"yyyy\", locale, None).contains(\"2024\"));\n    }\n\n    #[test]\n    fn test_format_month() {\n        let dt = make_dt(2024, 3, 15, 10, 30, 45);\n        let locale = get_locale_data(\"en-US\");\n\n        assert_eq!(format_with_pattern(&dt, \"M\", locale, None), \"3\");\n        assert_eq!(format_with_pattern(&dt, \"MM\", locale, None), \"03\");\n        assert_eq!(format_with_pattern(&dt, \"MMM\", locale, None), \"Mar\");\n        assert_eq!(format_with_pattern(&dt, \"MMMM\", locale, None), \"March\");\n    }\n\n    #[test]\n    fn test_format_day() {\n        let dt = make_dt(2024, 3, 5, 10, 30, 45);\n        let locale = get_locale_data(\"en-US\");\n\n        assert_eq!(format_with_pattern(&dt, \"d\", locale, None), \"5\");\n        assert_eq!(format_with_pattern(&dt, \"dd\", locale, None), \"05\");\n    }\n\n    #[test]\n    fn test_format_weekday() {\n        // March 15, 2024 is a Friday\n        let dt = make_dt(2024, 3, 15, 10, 30, 45);\n        let locale = get_locale_data(\"en-US\");\n\n        assert_eq!(format_with_pattern(&dt, \"E\", locale, None), \"Fri\");\n        assert_eq!(format_with_pattern(&dt, \"EEEE\", locale, None), \"Friday\");\n    }\n\n    #[test]\n    fn test_format_hour_12() {\n        let dt = make_dt(2024, 3, 15, 14, 30, 45);\n        let locale = get_locale_data(\"en-US\");\n\n        assert_eq!(format_with_pattern(&dt, \"h\", locale, None), \"2\");\n        assert_eq!(format_with_pattern(&dt, \"hh\", locale, None), \"02\");\n    }\n\n    #[test]\n    fn test_format_hour_24() {\n        let dt = make_dt(2024, 3, 15, 14, 30, 45);\n        let locale = get_locale_data(\"en-US\");\n\n        assert_eq!(format_with_pattern(&dt, \"H\", locale, None), \"14\");\n        assert_eq!(format_with_pattern(&dt, \"HH\", locale, None), \"14\");\n    }\n\n    #[test]\n    fn test_format_minute_second() {\n        let dt = make_dt(2024, 3, 15, 14, 5, 9);\n        let locale = get_locale_data(\"en-US\");\n\n        assert_eq!(format_with_pattern(&dt, \"m\", locale, None), \"5\");\n        assert_eq!(format_with_pattern(&dt, \"mm\", locale, None), \"05\");\n        assert_eq!(format_with_pattern(&dt, \"s\", locale, None), \"9\");\n        assert_eq!(format_with_pattern(&dt, \"ss\", locale, None), \"09\");\n    }\n\n    #[test]\n    fn test_format_am_pm() {\n        let locale = get_locale_data(\"en-US\");\n\n        let dt_am = make_dt(2024, 3, 15, 10, 30, 45);\n        assert_eq!(format_with_pattern(&dt_am, \"a\", locale, None), \"AM\");\n\n        let dt_pm = make_dt(2024, 3, 15, 14, 30, 45);\n        assert_eq!(format_with_pattern(&dt_pm, \"a\", locale, None), \"PM\");\n    }\n\n    #[test]\n    fn test_format_quoted_literal() {\n        let dt = make_dt(2024, 3, 15, 10, 30, 45);\n        let locale = get_locale_data(\"en-US\");\n\n        assert_eq!(\n            format_with_pattern(&dt, \"d 'de' MMMM\", locale, None),\n            \"15 de March\"\n        );\n    }\n\n    #[test]\n    fn test_format_full_date_en_us() {\n        let dt = make_dt(2024, 3, 15, 14, 30, 45);\n        let locale = get_locale_data(\"en-US\");\n\n        let result = format_with_pattern(&dt, locale.date_formats.full, locale, None);\n        assert_eq!(result, \"Friday, March 15, 2024\");\n    }\n\n    #[test]\n    fn test_format_full_date_de() {\n        let dt = make_dt(2024, 3, 15, 14, 30, 45);\n        let locale = get_locale_data(\"de-DE\");\n\n        let result = format_with_pattern(&dt, locale.date_formats.full, locale, None);\n        assert_eq!(result, \"Freitag, 15. März 2024\");\n    }\n\n    #[test]\n    fn test_format_short_date_en_us() {\n        let dt = make_dt(2024, 3, 15, 14, 30, 45);\n        let locale = get_locale_data(\"en-US\");\n\n        let result = format_with_pattern(&dt, locale.date_formats.short, locale, None);\n        assert_eq!(result, \"3/15/24\");\n    }\n\n    #[test]\n    fn test_format_short_date_de() {\n        let dt = make_dt(2024, 3, 15, 14, 30, 45);\n        let locale = get_locale_data(\"de-DE\");\n\n        let result = format_with_pattern(&dt, locale.date_formats.short, locale, None);\n        assert_eq!(result, \"15.03.24\");\n    }\n\n    #[test]\n    fn test_format_short_time_en_us() {\n        let dt = make_dt(2024, 3, 15, 14, 30, 45);\n        let locale = get_locale_data(\"en-US\");\n\n        let result = format_with_pattern(&dt, locale.time_formats.short, locale, None);\n        assert_eq!(result, \"2:30 PM\");\n    }\n\n    #[test]\n    fn test_format_short_time_de() {\n        let dt = make_dt(2024, 3, 15, 14, 30, 45);\n        let locale = get_locale_data(\"de-DE\");\n\n        let result = format_with_pattern(&dt, locale.time_formats.short, locale, None);\n        assert_eq!(result, \"14:30\");\n    }\n\n    #[test]\n    fn test_combine_datetime() {\n        assert_eq!(\n            combine_datetime(\"3/15/24\", \"2:30 PM\", \"{1}, {0}\"),\n            \"3/15/24, 2:30 PM\"\n        );\n        assert_eq!(\n            combine_datetime(\"15.03.24\", \"14:30\", \"{1} {0}\"),\n            \"15.03.24 14:30\"\n        );\n    }\n\n    #[test]\n    fn test_midnight_12h() {\n        let dt = make_dt(2024, 3, 15, 0, 0, 0);\n        let locale = get_locale_data(\"en-US\");\n\n        let result = format_with_pattern(&dt, \"h:mm a\", locale, None);\n        assert_eq!(result, \"12:00 AM\");\n    }\n\n    #[test]\n    fn test_noon_12h() {\n        let dt = make_dt(2024, 3, 15, 12, 0, 0);\n        let locale = get_locale_data(\"en-US\");\n\n        let result = format_with_pattern(&dt, \"h:mm a\", locale, None);\n        assert_eq!(result, \"12:00 PM\");\n    }\n\n    #[test]\n    fn test_japanese_locale() {\n        let dt = make_dt(2024, 3, 15, 14, 30, 45);\n        let locale = get_locale_data(\"ja-JP\");\n\n        let result = format_with_pattern(&dt, locale.date_formats.long, locale, None);\n        assert_eq!(result, \"2024年3月15日\");\n    }\n\n    #[test]\n    fn test_korean_locale() {\n        let dt = make_dt(2024, 3, 15, 14, 30, 45);\n        let locale = get_locale_data(\"ko-KR\");\n\n        let result = format_with_pattern(&dt, locale.date_formats.medium, locale, None);\n        assert_eq!(result, \"2024. 3. 15.\");\n    }\n}\n"
  },
  {
    "path": "modules/llrt_navigator/Cargo.toml",
    "content": "[package]\nname = \"llrt_navigator\"\ndescription = \"LLRT Module navigator\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\nreadme = \"README.md\"\n\n[lib]\nname = \"llrt_navigator\"\npath = \"src/lib.rs\"\n\n[dependencies]\nrquickjs = { version = \"0.11\", default-features = false }\n"
  },
  {
    "path": "modules/llrt_navigator/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse rquickjs::{Ctx, Object, Result};\n\nfn get_user_agent() -> &'static str {\n    concat!(\"llrt \", env!(\"CARGO_PKG_VERSION\"))\n}\n\npub fn init(ctx: &Ctx<'_>) -> Result<()> {\n    let globals = ctx.globals();\n\n    let navigator = Object::new(ctx.clone())?;\n\n    navigator.set(\"userAgent\", get_user_agent())?;\n\n    globals.set(\"navigator\", navigator)?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "modules/llrt_net/Cargo.toml",
    "content": "[package]\nname = \"llrt_net\"\ndescription = \"LLRT Module net\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\nreadme = \"README.md\"\n\n[lib]\nname = \"llrt_net\"\npath = \"src/lib.rs\"\n\n[dependencies]\nitoa = { version = \"1\", default-features = false }\nllrt_buffer = { version = \"0.8.1-beta\", path = \"../llrt_buffer\" }\nllrt_context = { version = \"0.8.1-beta\", path = \"../../libs/llrt_context\" }\nllrt_events = { version = \"0.8.1-beta\", path = \"../llrt_events\" }\nllrt_stream = { version = \"0.8.1-beta\", path = \"../llrt_stream\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", default-features = false }\ntokio = { version = \"1\", features = [\"net\"], default-features = false }\ntracing = { version = \"0.1\", default-features = false }\n\n[dev-dependencies]\nllrt_test = { path = \"../../libs/llrt_test\" }\nrand = { version = \"0.10.0\", features = [\"alloc\"], default-features = false }\n"
  },
  {
    "path": "modules/llrt_net/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{net::SocketAddr, result::Result as StdResult};\n\nuse llrt_events::Emitter;\nuse llrt_utils::{\n    module::{export_default, ModuleInfo},\n    result::ResultExt,\n};\nuse rquickjs::{\n    module::{Declarations, Exports, ModuleDef},\n    prelude::{Func, This},\n    Class, Ctx, IntoJs, Result,\n};\n#[cfg(unix)]\nuse tokio::net::{UnixListener, UnixStream};\nuse tokio::{\n    net::{TcpListener, TcpStream},\n    sync::oneshot::Receiver,\n};\n\nuse self::security::ensure_access;\npub use self::security::{get_allow_list, get_deny_list, set_allow_list, set_deny_list};\n\nmod security;\nmod server;\nmod socket;\n\nuse self::{server::Server, socket::Socket};\n\nconst LOCALHOST: &str = \"localhost\";\n\n#[allow(dead_code)]\nenum ReadyState {\n    Opening,\n    Open,\n    Closed,\n    ReadOnly,\n    WriteOnly,\n}\n\nimpl ReadyState {\n    #[allow(clippy::inherent_to_string)]\n    pub fn to_string(&self) -> String {\n        String::from(match self {\n            ReadyState::Opening => \"opening\",\n            ReadyState::Open => \"open\",\n            ReadyState::Closed => \"closed\",\n            ReadyState::ReadOnly => \"readOnly\",\n            ReadyState::WriteOnly => \"writeOnly\",\n        })\n    }\n}\n\nenum NetStream {\n    Tcp((TcpStream, SocketAddr)),\n    #[cfg(unix)]\n    Unix((UnixStream, tokio::net::unix::SocketAddr)),\n}\n\nimpl NetStream {\n    async fn process<'js>(\n        self,\n        socket: &Class<'js, Socket<'js>>,\n        ctx: &Ctx<'js>,\n        allow_half_open: bool,\n    ) -> Result<bool> {\n        let (readable_done, writable_done) = match self {\n            NetStream::Tcp((stream, _)) => {\n                Socket::process_tcp_stream(socket, ctx, stream, allow_half_open)\n            },\n            #[cfg(unix)]\n            NetStream::Unix((stream, _)) => {\n                Socket::process_unix_stream(socket, ctx, stream, allow_half_open)\n            },\n        }?;\n        let had_error = rw_join(ctx, readable_done, writable_done).await?;\n        Ok(had_error)\n    }\n}\n\nenum Listener {\n    Tcp(TcpListener),\n    #[cfg(unix)]\n    Unix(UnixListener),\n}\n\nimpl Listener {\n    async fn accept(&self, ctx: &Ctx<'_>) -> Result<NetStream> {\n        match self {\n            Listener::Tcp(tcp) => tcp\n                .accept()\n                .await\n                .map(|(stream, addr)| NetStream::Tcp((stream, addr)))\n                .or_throw(ctx),\n            #[cfg(unix)]\n            Listener::Unix(unix) => unix\n                .accept()\n                .await\n                .map(|(stream, addr)| NetStream::Unix((stream, addr)))\n                .or_throw(ctx),\n        }\n    }\n}\n\nfn get_hostname(host: &str, port: u16) -> String {\n    [host, itoa::Buffer::new().format(port)].join(\":\")\n}\n\nfn get_address_parts(\n    ctx: &Ctx,\n    addr: StdResult<SocketAddr, std::io::Error>,\n) -> Result<(String, u16, String)> {\n    let addr = addr.or_throw(ctx)?;\n    Ok((\n        addr.ip().to_string(),\n        addr.port(),\n        String::from(if addr.is_ipv4() { \"IPv4\" } else { \"IPv6\" }),\n    ))\n}\n\nasync fn rw_join(\n    ctx: &Ctx<'_>,\n    readable_done: Receiver<bool>,\n    writable_done: Receiver<bool>,\n) -> Result<bool> {\n    let (readable_res, writable_res) = tokio::join!(readable_done, writable_done);\n    let had_error = readable_res.or_throw_msg(ctx, \"Readable sender dropped\")?\n        || writable_res.or_throw_msg(ctx, \"Writable sender dropped\")?;\n    Ok(had_error)\n}\n\npub struct NetModule;\n\nimpl ModuleDef for NetModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(\"createConnection\")?;\n        declare.declare(\"connect\")?;\n        declare.declare(\"createServer\")?;\n        declare.declare(stringify!(Socket))?;\n        declare.declare(stringify!(Server))?;\n        declare.declare(\"default\")?;\n\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        export_default(ctx, exports, |default| {\n            Class::<Socket>::define(default)?;\n            Class::<Server>::define(default)?;\n\n            Socket::add_event_emitter_prototype(ctx)?;\n            Server::add_event_emitter_prototype(ctx)?;\n\n            let connect = Func::from(|ctx, args| {\n                struct Args<'js>(Ctx<'js>);\n                let Args(ctx) = Args(ctx);\n                let this = Socket::new(ctx.clone(), false)?;\n                Socket::connect(This(this), ctx.clone(), args)\n            })\n            .into_js(ctx)?;\n\n            default.set(\"createConnection\", connect.clone())?;\n            default.set(\"connect\", connect)?;\n            default.set(\n                \"createServer\",\n                Func::from(|ctx, args| {\n                    struct Args<'js>(Ctx<'js>);\n                    let Args(ctx) = Args(ctx);\n                    Server::new(ctx.clone(), args)\n                }),\n            )\n        })?;\n        Ok(())\n    }\n}\n\nimpl From<NetModule> for ModuleInfo<NetModule> {\n    fn from(val: NetModule) -> Self {\n        ModuleInfo {\n            name: \"net\",\n            module: val,\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_net/src/security.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::sync::OnceLock;\n\nuse rquickjs::{Ctx, Exception, Result};\n\nstatic NET_ALLOW_LIST: OnceLock<Vec<String>> = OnceLock::new();\n\nstatic NET_DENY_LIST: OnceLock<Vec<String>> = OnceLock::new();\n\npub fn set_allow_list(values: Vec<String>) {\n    _ = NET_ALLOW_LIST.set(values);\n}\n\npub fn get_allow_list() -> Option<&'static Vec<String>> {\n    NET_ALLOW_LIST.get()\n}\n\npub fn set_deny_list(values: Vec<String>) {\n    _ = NET_DENY_LIST.set(values);\n}\n\npub fn get_deny_list() -> Option<&'static Vec<String>> {\n    NET_DENY_LIST.get()\n}\n\npub fn ensure_access(ctx: &Ctx<'_>, resource: &String) -> Result<()> {\n    if let Some(allow_list) = NET_ALLOW_LIST.get() {\n        if !allow_list.contains(resource) {\n            return Err(Exception::throw_message(\n                ctx,\n                &[\"Network address not allowed: \", resource].concat(),\n            ));\n        }\n    }\n\n    if let Some(deny_list) = NET_DENY_LIST.get() {\n        if deny_list.contains(resource) {\n            return Err(Exception::throw_message(\n                ctx,\n                &[\"Network address denied: \", resource].concat(),\n            ));\n        }\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "modules/llrt_net/src/server.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#![allow(clippy::uninlined_format_args)]\n\nuse std::sync::{\n    atomic::{AtomicBool, Ordering},\n    Arc, RwLock,\n};\n\nuse llrt_context::CtxExtension;\nuse llrt_events::{EmitError, Emitter, EventEmitter, EventList};\nuse llrt_stream::{impl_stream_events, SteamEvents};\nuse llrt_utils::{object::ObjectExt, result::ResultExt, reuse_list::ReuseList};\n#[cfg(unix)]\nuse rquickjs::IntoJs;\nuse rquickjs::{\n    class::Trace,\n    prelude::{Opt, Rest, This},\n    Class, Ctx, Exception, Function, JsLifetime, Object, Result, Undefined, Value,\n};\n#[cfg(unix)]\nuse tokio::net::UnixListener;\nuse tokio::{\n    net::TcpListener,\n    select,\n    sync::{\n        broadcast::{self, Sender},\n        Notify,\n    },\n};\nuse tracing::trace;\n\nuse super::{get_address_parts, get_hostname, socket::Socket, Listener, NetStream};\n\nimpl_stream_events!(Server);\n\n#[rquickjs::class]\npub struct Server<'js> {\n    emitter: EventEmitter<'js>,\n    address: Value<'js>,\n    close_tx: Sender<()>,\n    allow_half_open: bool,\n    already_listen: Arc<AtomicBool>,\n    sockets: ReuseList<Class<'js, Socket<'js>>>,\n    should_close: Arc<AtomicBool>,\n}\n\nimpl<'js> Trace<'js> for Server<'js> {\n    fn trace<'a>(&self, tracer: rquickjs::class::Tracer<'a, 'js>) {\n        self.emitter.trace(tracer);\n        self.address.trace(tracer);\n        for socket_ref in self.sockets.iter() {\n            socket_ref.trace(tracer);\n        }\n    }\n}\n\nunsafe impl<'js> JsLifetime<'js> for Server<'js> {\n    type Changed<'to> = Server<'to>;\n}\n\nimpl<'js> Emitter<'js> for Server<'js> {\n    fn get_event_list(&self) -> Arc<RwLock<EventList<'js>>> {\n        self.emitter.get_event_list()\n    }\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl<'js> Server<'js> {\n    #[qjs(constructor)]\n    pub fn new(ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<Class<'js, Self>> {\n        let mut args_iter = args.0.into_iter();\n\n        let mut connection_listener = None;\n        let mut allow_half_open = false;\n\n        if let Some(first) = args_iter.next() {\n            if let Some(connection_listener_arg) = first.as_function() {\n                connection_listener = Some(connection_listener_arg.clone());\n            }\n            if let Some(opts_arg) = first.as_object() {\n                allow_half_open = opts_arg.get_optional(\"allowHalfOpen\")?.unwrap_or_default();\n            }\n        }\n        if let Some(next) = args_iter.next() {\n            connection_listener = next.into_function();\n        }\n\n        let emitter = EventEmitter::new();\n        let (close_tx, _) = broadcast::channel::<()>(1);\n\n        let instance = Class::instance(\n            ctx.clone(),\n            Self {\n                emitter,\n                address: Undefined.into_value(ctx.clone()),\n                close_tx,\n                allow_half_open,\n                already_listen: Arc::new(AtomicBool::new(false)),\n                sockets: ReuseList::with_capacity(8),\n                should_close: Arc::new(AtomicBool::new(false)),\n            },\n        )?;\n\n        if let Some(connection_listener) = connection_listener {\n            Self::add_event_listener_str(\n                This(instance.clone()),\n                &ctx,\n                \"connection\",\n                connection_listener,\n                false,\n                false,\n            )?;\n        }\n\n        Ok(instance)\n    }\n\n    pub fn address(&self) -> Value<'js> {\n        self.address.clone()\n    }\n\n    pub fn get_connections(&self, cb: Opt<Function<'js>>) -> Result<()> {\n        if let Some(cb) = cb.0 {\n            cb.call::<_, ()>((Undefined, self.sockets.len()))?;\n        }\n        Ok(())\n    }\n\n    #[allow(unused_assignments)]\n    ///TODO add backlog support\n    pub fn listen(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        args: Rest<Value<'js>>,\n    ) -> Result<()> {\n        let mut args_iter = args.0.into_iter();\n        let mut port = None;\n        let mut path = None;\n        let mut host = None;\n        #[allow(unused_variables)] //TODO add backlog support\n        let mut backlog = None;\n        let mut callback = None;\n\n        let borrow = this.borrow();\n        let mut close_rx = borrow.close_tx.subscribe();\n        let allow_half_open = borrow.allow_half_open;\n        let already_running = borrow.already_listen.clone();\n        let should_close = borrow.should_close.clone();\n        drop(borrow);\n\n        if already_running.load(Ordering::Relaxed) {\n            return Err(Exception::throw_message(&ctx, \"ERR_SERVER_ALREADY_LISTEN\"));\n        }\n\n        if let Some(first) = args_iter.next() {\n            if let Some(callback_arg) = first.as_function() {\n                callback = Some(callback_arg.clone());\n            } else {\n                if let Some(port_arg) = first.as_int() {\n                    if port_arg > 0xFFFF {\n                        return Err(Exception::throw_range(\n                            &ctx,\n                            \"port should be between 0 and 65535\",\n                        ));\n                    }\n                    port = Some(port_arg);\n                }\n                if let Some(path_arg) = first.as_string() {\n                    path = Some(path_arg.to_string()?);\n                }\n                if let Some(opts_arg) = first.as_object() {\n                    port = opts_arg.get_optional(\"port\")?;\n                    path = opts_arg.get_optional(\"path\")?;\n                    host = opts_arg.get_optional(\"host\")?;\n                    backlog = opts_arg.get_optional(\"backlog\")?;\n                }\n\n                let path = first.into_string();\n\n                if let Some(second) = args_iter.next() {\n                    if let Some(callback_arg) = second.as_function() {\n                        callback = Some(callback_arg.clone());\n                    }\n                    if let Some(host_arg) = second.as_string() {\n                        host = Some(host_arg.to_string()?);\n                    }\n                    if path.is_some() {\n                        if let Some(backlog_arg) = second.as_int() {\n                            backlog = Some(backlog_arg);\n                        }\n                    }\n                    if let Some(third) = args_iter.next() {\n                        if let Some(callback_arg) = third.as_function() {\n                            callback = Some(callback_arg.clone());\n                        }\n                        if port.is_some() {\n                            if let Some(backlog_arg) = third.as_int() {\n                                backlog = Some(backlog_arg);\n\n                                callback = args_iter.next().and_then(|v| v.into_function());\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        if let Some(callback) = callback {\n            Self::add_event_listener_str(\n                This(this.clone()),\n                &ctx,\n                \"listening\",\n                callback,\n                true,\n                true,\n            )?;\n        }\n\n        let ctx2 = ctx.clone();\n\n        if port.is_none() && path.is_none() {\n            port = Some(0)\n        }\n\n        ctx.spawn_exit(async move {\n            already_running.store(true, Ordering::Relaxed);\n            let listener = match Self::bind(this.clone(), ctx2.clone(), port, host, path).await {\n                Ok(listener) => listener,\n                Err(e) => {\n                    already_running.store(false, Ordering::Relaxed);\n                    Err::<(), _>(e).emit_error(\"listen\", &ctx2, this.clone())?;\n                    return Ok(()); // Don't stop the VM if failed to bind\n                },\n            };\n\n            Self::emit_str(This(this.clone()), &ctx2, \"listening\", vec![], false)?;\n\n            let notify = Arc::new(Notify::new());\n            let close_notify = notify.notified();\n\n            loop {\n                let ctx3 = ctx2.clone();\n                let this2 = this.clone();\n\n                select! {\n                    socket = listener.accept(&ctx3) => {\n                        Self::handle_socket_connection(\n                            this2.clone(),\n                            ctx3.clone(),\n                            socket,\n                            notify.clone(),\n                            allow_half_open,\n                        ).emit_error(\"handle_socket_connection\",&ctx3, this2)?;\n                    },\n                    _ = close_rx.recv() => {\n                        break;\n                    }\n                }\n            }\n\n            if !this.borrow().sockets.is_empty() {\n                trace!(\"Waiting for sockets to finish\");\n                close_notify.await;\n                trace!(\"Sockets finished\");\n            } else {\n                trace!(\"No sockets to wait for, closing\");\n            }\n\n            already_running.store(false, Ordering::Relaxed);\n            should_close.store(false, Ordering::Relaxed);\n\n            Self::emit_str(this, &ctx2, \"close\", vec![], false)?;\n\n            Ok(())\n        })?;\n\n        Ok(())\n    }\n\n    fn close(this: This<Class<'js, Self>>, ctx: Ctx<'js>, cb: Opt<Function<'js>>) -> Result<()> {\n        trace!(\"Closing server\");\n        if let Some(cb) = cb.0 {\n            Self::add_event_listener_str(This(this.clone()), &ctx, \"close\", cb, true, true)?;\n        }\n        let borrow = this.borrow_mut();\n        borrow.should_close.store(true, Ordering::Relaxed);\n        let _ = borrow.close_tx.send(());\n        Ok(())\n    }\n}\n\nimpl<'js> Server<'js> {\n    async fn bind(\n        this: Class<'js, Self>,\n        ctx: Ctx<'js>,\n        port: Option<i32>,\n        host: Option<String>,\n        path: Option<String>,\n    ) -> Result<Listener> {\n        let listener = if let Some(port) = port {\n            let listener = TcpListener::bind(get_hostname(\n                &host.unwrap_or_else(|| String::from(\"0.0.0.0\")),\n                port as u16,\n            ))\n            .await\n            .or_throw(&ctx)?;\n\n            let address_object = Object::new(ctx.clone())?;\n\n            let (address, port, family) = get_address_parts(&ctx, listener.local_addr())?;\n            address_object.set(\"address\", address)?;\n            address_object.set(\"port\", port)?;\n            address_object.set(\"family\", family)?;\n\n            this.borrow_mut().address = address_object.into_value();\n\n            Listener::Tcp(listener)\n        } else if let Some(path) = path {\n            #[cfg(unix)]\n            {\n                let listener: UnixListener = UnixListener::bind(&path).or_throw(&ctx)?;\n                this.borrow_mut().address = path.into_js(&ctx)?;\n                Listener::Unix(listener)\n            }\n            #[cfg(not(unix))]\n            {\n                _ = path;\n                return Err(Exception::throw_type(\n                    &ctx,\n                    \"Unix domain sockets are not supported on this platform\",\n                ));\n            }\n        } else {\n            panic!(\"unreachable\")\n        };\n        Ok(listener)\n    }\n\n    fn handle_socket_connection(\n        this: Class<'js, Self>,\n        ctx: Ctx<'js>,\n        stream_result: Result<NetStream>,\n        notify_close: Arc<Notify>,\n        allow_half_open: bool,\n    ) -> Result<()> {\n        let net_stream = stream_result.or_throw(&ctx)?;\n\n        ctx.clone().spawn_exit(async move {\n            let socket_instance = Socket::new(ctx.clone(), allow_half_open)?;\n            let socket_index;\n            {\n                let mut sever_borrow = this.borrow_mut();\n                socket_index = sever_borrow.sockets.append(socket_instance.clone());\n            }\n\n            let socket_instance2 = socket_instance.clone().into_value();\n            Self::emit_str(\n                This(this.clone()),\n                &ctx,\n                \"connection\",\n                vec![socket_instance2],\n                false,\n            )?;\n\n            let had_error = net_stream\n                .process(&socket_instance, &ctx, allow_half_open)\n                .await?;\n\n            Socket::emit_close(socket_instance, &ctx, had_error)?;\n            {\n                let mut sever_borrow = this.borrow_mut();\n                sever_borrow.sockets.remove(socket_index);\n\n                if sever_borrow.sockets.is_empty()\n                    && sever_borrow.should_close.load(Ordering::Relaxed)\n                {\n                    trace!(\"Sockets empty, notify close\");\n                    notify_close.notify_one();\n                }\n            }\n\n            Ok(())\n        })?;\n\n        Ok(())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use std::time::Duration;\n\n    use llrt_buffer as buffer;\n    use llrt_test::{call_test, test_async_with, ModuleEvaluator};\n    use tokio::{\n        io::{AsyncReadExt, AsyncWriteExt},\n        net::TcpStream,\n    };\n\n    use crate::NetModule;\n\n    async fn call_tcp(port: u16) {\n        // Connect to server\n        tokio::time::sleep(Duration::from_millis(100)).await;\n        let mut stream = TcpStream::connect(format!(\"127.0.0.1:{}\", port))\n            .await\n            .unwrap();\n        stream.set_nodelay(true).unwrap();\n\n        // Write\n        let msg = b\"Hello, world!\";\n        stream.write_all(msg).await.unwrap();\n        stream.flush().await.unwrap();\n\n        // Read\n        let mut buf = vec![0; 1024];\n        let n = stream.read(&mut buf).await.unwrap();\n\n        assert_eq!(&buf[..n], msg);\n    }\n\n    #[tokio::test]\n    async fn test_server_echo() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                buffer::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<NetModule>(ctx.clone(), \"net\")\n                    .await\n                    .unwrap();\n\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { createServer } from 'net';\n\n                        export async function test() {\n                            const server = createServer(socket => {\n                                socket.on('data', data => {\n                                    socket.write(data, () => server.close());\n                                });\n                            });\n\n                            // Use port 0 to let the OS assign an available port\n                            server.listen(0, '127.0.0.1');\n\n                            return new Promise((resolve, reject) => {\n                                server.on('listening', () => {\n                                    const port = server.address().port;\n                                    resolve(port);\n                                });\n                                server.on('error', (err) => reject(err));\n                            });\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n\n                // Get the OS-assigned port from the server\n                let port: u16 = call_test(&ctx, &module, ()).await;\n\n                // Now connect to the server and run the echo test\n                call_tcp(port).await;\n            })\n        })\n        .await;\n    }\n}\n"
  },
  {
    "path": "modules/llrt_net/src/socket.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::sync::{Arc, RwLock};\n\nuse llrt_context::CtxExtension;\nuse llrt_events::{EmitError, Emitter, EventEmitter, EventKey, EventList};\nuse llrt_stream::{\n    impl_stream_events,\n    readable::{ReadableStream, ReadableStreamInner},\n    writable::{WritableStream, WritableStreamInner},\n    SteamEvents,\n};\nuse llrt_utils::{object::ObjectExt, result::ResultExt};\nuse rquickjs::{\n    class::{Trace, Tracer},\n    prelude::{Opt, Rest, This},\n    Class, Ctx, Error, Exception, Function, JsLifetime, Object, Result, Value,\n};\n#[cfg(unix)]\nuse tokio::net::UnixStream;\nuse tokio::{\n    io::{AsyncRead, AsyncWrite},\n    net::TcpStream,\n    sync::oneshot::Receiver,\n};\nuse tracing::trace;\n\nuse super::{ensure_access, get_address_parts, get_hostname, rw_join, ReadyState, LOCALHOST};\n\nimpl_stream_events!(Socket);\n\n#[rquickjs::class]\n#[allow(dead_code)]\npub struct Socket<'js> {\n    emitter: EventEmitter<'js>,\n    readable_stream_inner: ReadableStreamInner<'js>,\n    writable_stream_inner: WritableStreamInner<'js>,\n    connecting: bool,\n    destroyed: bool,\n    pending: bool,\n    local_address: Option<String>,\n    local_family: Option<String>,\n    local_port: Option<u16>,\n    remote_address: Option<String>,\n    remote_family: Option<String>,\n    remote_port: Option<u16>,\n    ready_state: ReadyState,\n    allow_half_open: bool,\n}\n\nunsafe impl<'js> JsLifetime<'js> for Socket<'js> {\n    type Changed<'to> = Socket<'to>;\n}\n\nimpl<'js> Trace<'js> for Socket<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.emitter.trace(tracer);\n    }\n}\n\nimpl<'js> Emitter<'js> for Socket<'js> {\n    fn get_event_list(&self) -> Arc<RwLock<EventList<'js>>> {\n        self.emitter.get_event_list()\n    }\n\n    fn on_event_changed(&mut self, event: EventKey<'js>, added: bool) -> Result<()> {\n        self.readable_stream_inner.on_event_changed(event, added)\n    }\n}\n\nimpl<'js> ReadableStream<'js> for Socket<'js> {\n    fn inner_mut(&mut self) -> &mut ReadableStreamInner<'js> {\n        &mut self.readable_stream_inner\n    }\n\n    fn inner(&self) -> &ReadableStreamInner<'js> {\n        &self.readable_stream_inner\n    }\n}\n\nimpl<'js> WritableStream<'js> for Socket<'js> {\n    fn inner_mut(&mut self) -> &mut WritableStreamInner<'js> {\n        &mut self.writable_stream_inner\n    }\n\n    fn inner(&self) -> &WritableStreamInner<'js> {\n        &self.writable_stream_inner\n    }\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl<'js> Socket<'js> {\n    #[qjs(constructor)]\n    pub fn ctor(ctx: Ctx<'js>, opts: Opt<Object<'js>>) -> Result<Class<'js, Self>> {\n        let mut allow_half_open = false;\n        if let Some(opts) = opts.0 {\n            if let Some(opt_allow_half_open) = opts.get_optional(\"allowHalfOpen\")? {\n                allow_half_open = opt_allow_half_open;\n            }\n        }\n\n        Self::new(ctx, allow_half_open)\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn connecting(&self) -> bool {\n        self.connecting\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn pending(&self) -> bool {\n        self.pending\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn remote_address(&self) -> Option<String> {\n        self.remote_address.clone()\n    }\n\n    pub fn write(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        value: Value<'js>,\n        cb: Opt<Function<'js>>,\n    ) -> Result<()> {\n        WritableStream::write_flushed(this, ctx.clone(), value, cb)?;\n        Ok(())\n    }\n\n    pub fn end(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        callback: Opt<Function<'js>>,\n    ) -> Result<()> {\n        if let Some(cb) = callback.0 {\n            Self::add_event_listener_str(This(this.clone()), &ctx, \"end\", cb, true, true)?;\n        }\n\n        //ReadableStream::destroy(This(this.clone()), ctx.clone())?;\n        WritableStream::end(this);\n\n        Ok(())\n    }\n\n    pub fn destroy(this: This<Class<'js, Self>>, error: Opt<Value<'js>>) -> Class<'js, Self> {\n        this.borrow_mut().destroyed = true;\n        ReadableStream::destroy(This(this.clone()), Opt(None));\n        WritableStream::destroy(This(this.clone()), error);\n        this.0\n    }\n\n    pub fn read(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        size: Opt<usize>,\n    ) -> Result<Value<'js>> {\n        ReadableStream::read(this, ctx, size)\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn local_address(&self) -> Option<String> {\n        self.local_address.clone()\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn remote_family(&self) -> Option<String> {\n        self.remote_family.clone()\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn local_family(&self) -> Option<String> {\n        self.local_family.clone()\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn remote_port(&self) -> Option<u16> {\n        self.remote_port\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn local_port(&self) -> Option<u16> {\n        self.local_port\n    }\n\n    #[qjs(get, enumerable)]\n    pub fn ready_state(&self) -> String {\n        self.ready_state.to_string()\n    }\n\n    pub fn connect(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        args: Rest<Value<'js>>,\n    ) -> Result<Class<'js, Self>> {\n        let args = args.0;\n\n        let borrow = this.borrow();\n        let allow_half_open = borrow.allow_half_open;\n        if borrow.destroyed {\n            return Err(Exception::throw_message(&ctx, \"Socket destroyed\"));\n        }\n        drop(borrow);\n\n        let mut port = None;\n        let mut host = String::from(LOCALHOST);\n        let mut path = None;\n        let mut listener = None;\n        let mut last = None;\n        let mut addr = None;\n\n        let mut args = args.into_iter();\n\n        if let Some(first) = args.next() {\n            if let Some(opts) = first.as_object() {\n                port = opts.get_optional(\"port\")?;\n                path = opts.get_optional(\"path\")?;\n                if let Some(host_arg) = opts.get_optional(\"host\")? {\n                    host = host_arg\n                }\n            } else if let Some(path_arg) = first.as_string() {\n                path = Some(path_arg.to_string()?);\n            } else if let Some(port_arg) = first.as_int() {\n                port = Some(port_arg as u16);\n                if let Some(next) = args.next() {\n                    if let Some(host_arg) = next.as_string() {\n                        host = host_arg.to_string()?;\n                    } else {\n                        last = Some(next)\n                    }\n                }\n            }\n        }\n\n        if let Some(last) = last.or_else(|| args.next()) {\n            if let Some(cb) = last.as_function() {\n                listener = Some(cb.to_owned());\n            }\n        }\n\n        if path.is_none() && port.is_none() {\n            return Err(Exception::throw_type(&ctx, \"port or path are required\"));\n        }\n\n        if let Some(path) = path.clone() {\n            ensure_access(&ctx, &path)?;\n        }\n        if let Some(port) = port {\n            let hostname = get_hostname(&host, port);\n            ensure_access(&ctx, &hostname)?;\n            addr = Some(hostname);\n        }\n\n        let this = this.0;\n\n        let this2 = this.clone();\n\n        if let Some(listener) = listener {\n            Socket::add_event_listener_str(\n                This(this.clone()),\n                &ctx,\n                \"connect\",\n                listener,\n                false,\n                true,\n            )?;\n        }\n\n        ctx.clone().spawn_exit(async move {\n            let ctx2 = ctx.clone();\n            let ctx3 = ctx.clone();\n            let this3 = this2.clone();\n            if this3.borrow().destroyed {\n                Socket::emit_close(this3.clone(), &ctx3, false)?;\n                return Ok(());\n            }\n            let connect = async move {\n                let (readable_done, writable_done) = if let Some(path) = path {\n                    #[cfg(unix)]\n                    {\n                        let stream = UnixStream::connect(path).await.or_throw(&ctx3)?;\n                        Self::process_unix_stream(&this2, &ctx3, stream, allow_half_open)\n                    }\n                    #[cfg(not(unix))]\n                    {\n                        _ = path;\n                        return Err(Exception::throw_type(\n                            &ctx3,\n                            \"Unix domain sockets are not supported on this platform\",\n                        ));\n                    }\n                } else if let Some(addr) = addr {\n                    let stream = TcpStream::connect(addr).await.or_throw(&ctx3)?;\n                    Self::process_tcp_stream(&this2, &ctx3, stream, allow_half_open)\n                } else {\n                    unreachable!()\n                }?;\n\n                Socket::emit_str(This(this2.clone()), &ctx3, \"connect\", vec![], false)?;\n\n                let had_error = rw_join(&ctx3, readable_done, writable_done).await?;\n\n                Socket::emit_close(this2, &ctx3, had_error)?;\n\n                Ok::<_, Error>(())\n            }\n            .await;\n\n            connect.emit_error(\"connect\", &ctx2, this3)?;\n            Ok(())\n        })?;\n\n        Ok(this)\n    }\n}\n\nimpl<'js> Socket<'js> {\n    pub fn new(ctx: Ctx<'js>, allow_half_open: bool) -> Result<Class<'js, Self>> {\n        let emitter = EventEmitter::new();\n\n        let readable_stream_inner = ReadableStreamInner::new(emitter.clone(), false);\n        let writable_stream_inner = WritableStreamInner::new(emitter.clone(), false);\n\n        let instance = Class::instance(\n            ctx,\n            Self {\n                emitter,\n                connecting: false,\n                destroyed: false,\n                pending: true,\n                ready_state: ReadyState::Closed,\n                local_address: None,\n                local_family: None,\n                local_port: None,\n                remote_address: None,\n                remote_family: None,\n                remote_port: None,\n                readable_stream_inner,\n                writable_stream_inner,\n                allow_half_open,\n            },\n        )?;\n        Ok(instance)\n    }\n\n    pub fn process_tcp_stream(\n        this: &Class<'js, Self>,\n        ctx: &Ctx<'js>,\n        stream: TcpStream,\n        allow_half_open: bool,\n    ) -> Result<(Receiver<bool>, Receiver<bool>)> {\n        Self::set_addresses(this, ctx, &stream)?;\n\n        let (reader, writer) = stream.into_split();\n        Self::process_stream(this, ctx, reader, writer, allow_half_open)\n    }\n\n    #[cfg(unix)]\n    pub fn process_unix_stream(\n        this: &Class<'js, Self>,\n        ctx: &Ctx<'js>,\n        stream: UnixStream,\n        allow_half_open: bool,\n    ) -> Result<(Receiver<bool>, Receiver<bool>)> {\n        let (reader, writer) = stream.into_split();\n        Self::process_stream(this, ctx, reader, writer, allow_half_open)\n    }\n\n    fn process_stream<R: AsyncRead + 'js + Unpin, W: AsyncWrite + 'js + Unpin>(\n        this: &Class<'js, Self>,\n        ctx: &Ctx<'js>,\n        reader: R,\n        writer: W,\n        allow_half_open: bool,\n    ) -> Result<(Receiver<bool>, Receiver<bool>)> {\n        let this2 = this.clone();\n        let readable_done =\n            ReadableStream::process_callback(this.clone(), ctx, reader, move || {\n                if !allow_half_open {\n                    WritableStream::end(This(this2));\n                }\n            })?;\n        let writable_done = WritableStream::process(this.clone(), ctx, writer)?;\n\n        trace!(\"Connected to stream\");\n        let mut borrow = this.borrow_mut();\n        borrow.connecting = false;\n        borrow.pending = false;\n        borrow.ready_state = ReadyState::Open;\n        drop(borrow);\n\n        Ok((readable_done, writable_done))\n    }\n\n    pub fn set_addresses<'a>(\n        this: &'a Class<'js, Self>,\n        ctx: &Ctx<'js>,\n        stream: &TcpStream,\n    ) -> Result<()> {\n        let mut borrow = this.borrow_mut();\n\n        let (remote_address, remote_port, remote_family) =\n            get_address_parts(ctx, stream.peer_addr())?;\n        borrow.remote_address = Some(remote_address);\n        borrow.remote_port = Some(remote_port);\n        borrow.remote_family = Some(remote_family);\n\n        let (local_address, local_port, local_family) =\n            get_address_parts(ctx, stream.local_addr())?;\n        borrow.local_address = Some(local_address);\n        borrow.local_port = Some(local_port);\n        borrow.local_family = Some(local_family);\n\n        drop(borrow);\n        Ok(())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use std::time::Duration;\n\n    use llrt_buffer as buffer;\n    use llrt_test::{call_test, test_async_with, ModuleEvaluator};\n    use rquickjs::{function::IntoArgs, module::Evaluated, Ctx, FromJs, Module};\n    use tokio::{\n        io::{AsyncReadExt, AsyncWriteExt},\n        net::TcpListener,\n    };\n\n    use crate::NetModule;\n\n    async fn server() -> u16 {\n        // Use port 0 to let the OS assign an available port\n        let listener = TcpListener::bind((\"127.0.0.1\", 0)).await.unwrap();\n        let port = listener.local_addr().unwrap().port();\n\n        // Spawn the accept loop so we can return the port immediately\n        tokio::spawn(async move {\n            let (mut stream, _) = listener.accept().await.unwrap();\n            stream.set_nodelay(true).unwrap();\n\n            // Read\n            let mut buf = vec![0; 1024];\n            let n = stream.read(&mut buf).await.unwrap();\n\n            // Write\n            stream.write_all(&buf[..n]).await.unwrap();\n            stream.flush().await.unwrap();\n        });\n\n        port\n    }\n\n    async fn call_test_delay<'js, T, A>(\n        ctx: &Ctx<'js>,\n        module: &Module<'js, Evaluated>,\n        args: A,\n    ) -> T\n    where\n        T: FromJs<'js>,\n        A: IntoArgs<'js>,\n    {\n        tokio::time::sleep(Duration::from_millis(100)).await;\n        call_test::<T, _>(ctx, module, args).await\n    }\n\n    #[tokio::test]\n    async fn test_server_echo() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                buffer::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<NetModule>(ctx.clone(), \"net\")\n                    .await\n                    .unwrap();\n\n                // Start server and get OS-assigned port\n                let port = server().await;\n\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { connect } from 'net';\n\n                        export async function test(port) {\n                            const socket = connect({ port });\n                            const txData = \"Hello World\";\n                            return new Promise((resolve, reject) => {\n                                socket.on('connect', () => {\n                                    socket.write(txData, (err) => {\n                                        if (err) {\n                                            reject(err);\n                                        }\n                                    });\n                                });\n                                socket.on('data', (rxData) => {\n                                    resolve(rxData.toString() === txData);\n                                });\n                            });\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n\n                let ok: bool = call_test_delay(&ctx, &module, (port,)).await;\n                assert!(ok)\n            })\n        })\n        .await;\n    }\n}\n"
  },
  {
    "path": "modules/llrt_os/Cargo.toml",
    "content": "[package]\nname = \"llrt_os\"\ndescription = \"LLRT Module OS\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\nreadme = \"README.md\"\n\n[features]\ndefault = [\"network\", \"statistics\", \"system\"]\n\nnetwork = [\"sysinfo/network\", \"system\"]\nstatistics = [\"system\"]\nsystem = [\"sysinfo/system\"]\n\n[dependencies]\nhome = { version = \"0.5\", default-features = false }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nnum_cpus = { version = \"1\", default-features = false }\nonce_cell = { version = \"1\", features = [\"std\"], default-features = false }\nrquickjs = { version = \"0.11\", features = [\"std\"], default-features = false }\n\n# Optional\nsysinfo = { version = \"0.38\", default-features = false, optional = true }\n\n[target.'cfg(unix)'.dependencies]\nlibc = { version = \"0.2\", default-features = false }\nusers = { version = \"0.11\", features = [\"cache\"], default-features = false }\n\n[target.'cfg(windows)'.dependencies]\nwhoami = { version = \"2\", default-features = false }\nwindows-registry = { version = \"0.6\", features = [\n  \"std\",\n], default-features = false }\nwindows-result = { version = \"0.4\", features = [\n  \"std\",\n], default-features = false }\nwindows-version = { version = \"0.1\", default-features = false }\n\n[dev-dependencies]\nllrt_test = { path = \"../../libs/llrt_test\" }\ntokio = { version = \"1\", features = [\"test-util\"], default-features = false }\n"
  },
  {
    "path": "modules/llrt_os/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#![allow(clippy::uninlined_format_args)]\n\nuse std::env;\n\nuse llrt_utils::{\n    module::{export_default, ModuleInfo},\n    sysinfo::{ARCH, PLATFORM},\n};\nuse rquickjs::{\n    module::{Declarations, Exports, ModuleDef},\n    prelude::Func,\n    Ctx, Exception, Result,\n};\n\n#[cfg(feature = \"system\")]\nuse sysinfo::System;\n\n#[cfg(unix)]\nuse self::unix::{\n    get_priority, get_release, get_type, get_user_info, get_version, set_priority, DEV_NULL, EOL,\n};\n#[cfg(windows)]\nuse self::windows::{\n    get_priority, get_release, get_type, get_user_info, get_version, set_priority, DEV_NULL, EOL,\n};\n\n#[cfg(unix)]\nmod unix;\n#[cfg(windows)]\nmod windows;\n\n#[cfg(feature = \"network\")]\nuse self::network::get_network_interfaces;\n#[cfg(feature = \"statistics\")]\nuse self::statistics::{get_cpus, get_free_mem, get_total_mem};\n\n#[cfg(feature = \"network\")]\nmod network;\n#[cfg(feature = \"statistics\")]\nmod statistics;\n\nfn get_available_parallelism() -> usize {\n    num_cpus::get()\n}\n\nfn get_endianness() -> &'static str {\n    #[cfg(target_endian = \"little\")]\n    {\n        \"LE\"\n    }\n    #[cfg(target_endian = \"big\")]\n    {\n        \"BE\"\n    }\n}\n\nfn get_home_dir(ctx: Ctx<'_>) -> Result<String> {\n    home::home_dir()\n        .map(|val| val.to_string_lossy().into_owned())\n        .ok_or_else(|| Exception::throw_message(&ctx, \"Could not determine home directory\"))\n}\n\n#[cfg(feature = \"system\")]\nfn get_host_name(ctx: Ctx<'_>) -> Result<String> {\n    System::host_name().ok_or_else(|| Exception::throw_reference(&ctx, \"System::host_name\"))\n}\n\n#[cfg(feature = \"system\")]\nfn get_load_avg() -> Vec<f64> {\n    let load_avg = System::load_average();\n\n    vec![load_avg.one, load_avg.five, load_avg.fifteen]\n}\n\n#[cfg(feature = \"system\")]\nfn get_machine() -> String {\n    System::cpu_arch()\n}\n\nfn get_tmp_dir() -> String {\n    env::temp_dir().to_string_lossy().to_string()\n}\n\n#[cfg(feature = \"system\")]\nfn get_uptime() -> u64 {\n    System::uptime()\n}\n\npub struct OsModule;\n\nimpl ModuleDef for OsModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(\"arch\")?;\n        declare.declare(\"availableParallelism\")?;\n        declare.declare(\"devNull\")?;\n        declare.declare(\"endianness\")?;\n        declare.declare(\"EOL\")?;\n        declare.declare(\"getPriority\")?;\n        declare.declare(\"homedir\")?;\n        declare.declare(\"platform\")?;\n        declare.declare(\"release\")?;\n        declare.declare(\"setPriority\")?;\n        declare.declare(\"tmpdir\")?;\n        declare.declare(\"type\")?;\n        declare.declare(\"userInfo\")?;\n        declare.declare(\"version\")?;\n\n        #[cfg(feature = \"network\")]\n        {\n            declare.declare(\"networkInterfaces\")?;\n        }\n\n        #[cfg(feature = \"statistics\")]\n        {\n            declare.declare(\"cpus\")?;\n            declare.declare(\"freemem\")?;\n            declare.declare(\"totalmem\")?;\n        }\n        #[cfg(feature = \"system\")]\n        {\n            declare.declare(\"hostname\")?;\n            declare.declare(\"loadavg\")?;\n            declare.declare(\"machine\")?;\n            declare.declare(\"uptime\")?;\n        }\n        declare.declare(\"default\")?;\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        export_default(ctx, exports, |default| {\n            default.set(\"arch\", Func::from(|| ARCH))?;\n            default.set(\n                \"availableParallelism\",\n                Func::from(get_available_parallelism),\n            )?;\n            default.set(\"devNull\", DEV_NULL)?;\n            default.set(\"endianness\", Func::from(get_endianness))?;\n            default.set(\"EOL\", EOL)?;\n            default.set(\"getPriority\", Func::from(get_priority))?;\n            default.set(\"homedir\", Func::from(get_home_dir))?;\n            default.set(\"platform\", Func::from(|| PLATFORM))?;\n            default.set(\"release\", Func::from(get_release))?;\n            default.set(\"setPriority\", Func::from(set_priority))?;\n            default.set(\"tmpdir\", Func::from(get_tmp_dir))?;\n            default.set(\"type\", Func::from(get_type))?;\n            default.set(\"userInfo\", Func::from(get_user_info))?;\n            default.set(\"version\", Func::from(get_version))?;\n            #[cfg(feature = \"network\")]\n            {\n                default.set(\"networkInterfaces\", Func::from(get_network_interfaces))?;\n            }\n\n            #[cfg(feature = \"statistics\")]\n            {\n                default.set(\"cpus\", Func::from(get_cpus))?;\n                default.set(\"freemem\", Func::from(get_free_mem))?;\n                default.set(\"totalmem\", Func::from(get_total_mem))?;\n            }\n            #[cfg(feature = \"system\")]\n            {\n                default.set(\"hostname\", Func::from(get_host_name))?;\n                default.set(\"loadavg\", Func::from(get_load_avg))?;\n                default.set(\"machine\", Func::from(get_machine))?;\n                default.set(\"uptime\", Func::from(get_uptime))?;\n            }\n            Ok(())\n        })\n    }\n}\n\nimpl From<OsModule> for ModuleInfo<OsModule> {\n    fn from(val: OsModule) -> Self {\n        ModuleInfo {\n            name: \"os\",\n            module: val,\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use llrt_test::{call_test, test_async_with, ModuleEvaluator};\n    use rquickjs::{Ctx, Value};\n\n    use super::*;\n\n    async fn run_test_return_string(\n        ctx: &Ctx<'_>,\n        name: &str,\n        is_function: bool,\n        expected_assertion: impl Fn(String),\n    ) {\n        ModuleEvaluator::eval_rust::<OsModule>(ctx.clone(), \"os\")\n            .await\n            .unwrap();\n\n        let brackets = if is_function { \"()\" } else { \"\" };\n        let module = ModuleEvaluator::eval_js(\n            ctx.clone(),\n            \"test\",\n            &format!(\n                r#\"\n                    import {{ {} }} from 'os';\n\n                    export async function test() {{\n                        return {}{}\n                    }}\n                \"#,\n                name, name, brackets\n            ),\n        )\n        .await\n        .unwrap();\n\n        let result = call_test::<String, _>(ctx, &module, ()).await;\n        expected_assertion(result);\n    }\n\n    async fn run_test_return_number(ctx: &Ctx<'_>, name: &str, expected_assertion: impl Fn(Value)) {\n        ModuleEvaluator::eval_rust::<OsModule>(ctx.clone(), \"os\")\n            .await\n            .unwrap();\n\n        let module = ModuleEvaluator::eval_js(\n            ctx.clone(),\n            \"test\",\n            &format!(\n                r#\"\n                    import {{ {} }} from 'os';\n\n                    export async function test() {{\n                        return {}()\n                    }}\n                \"#,\n                name, name\n            ),\n        )\n        .await\n        .unwrap();\n\n        let result = call_test::<Value, _>(ctx, &module, ()).await;\n        expected_assertion(result);\n    }\n\n    #[tokio::test]\n    async fn test_available_parallelism() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                run_test_return_number(&ctx, \"availableParallelism\", |result| {\n                    assert!(result.is_number()); // platform dependant\n                })\n                .await;\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_arch() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                run_test_return_string(&ctx, \"type\", true, |result| {\n                    assert!(!result.is_empty()); // platform dependant\n                })\n                .await;\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_devnull() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                run_test_return_string(&ctx, \"devNull\", false, |result| {\n                    assert_eq!(result, DEV_NULL);\n                })\n                .await;\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_endianness() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                run_test_return_string(&ctx, \"endianness\", true, |result| {\n                    let endianness = if cfg!(target_endian = \"little\") {\n                        \"LE\".to_string()\n                    } else {\n                        \"BE\".to_string()\n                    };\n                    assert_eq!(result, endianness);\n                })\n                .await;\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_eol() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                run_test_return_string(&ctx, \"EOL\", false, |result| {\n                    assert_eq!(result, EOL);\n                })\n                .await;\n            })\n        })\n        .await;\n    }\n\n    #[cfg(feature = \"statistics\")]\n    #[tokio::test]\n    async fn test_freemem() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                run_test_return_number(&ctx, \"freemem\", |result| {\n                    assert!(result.is_number()); // platform dependant\n                })\n                .await;\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_homedir() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                run_test_return_string(&ctx, \"homedir\", true, |result| {\n                    assert!(!result.is_empty()); // platform dependant\n                })\n                .await;\n            })\n        })\n        .await;\n    }\n\n    #[cfg(feature = \"system\")]\n    #[tokio::test]\n    async fn test_hostname() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                run_test_return_string(&ctx, \"hostname\", true, |result| {\n                    assert!(!result.is_empty()); // platform dependant\n                })\n                .await;\n            })\n        })\n        .await;\n    }\n\n    #[cfg(feature = \"system\")]\n    #[tokio::test]\n    async fn test_machine() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                run_test_return_string(&ctx, \"machine\", true, |result| {\n                    assert!(!result.is_empty()); // platform dependant\n                })\n                .await;\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_platform() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                run_test_return_string(&ctx, \"platform\", true, |result| {\n                    assert!(!result.is_empty()); // platform dependant\n                })\n                .await;\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_release() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                run_test_return_string(&ctx, \"release\", true, |result| {\n                    assert!(!result.is_empty()); // platform dependant\n                })\n                .await;\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_tmpdir() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                run_test_return_string(&ctx, \"tmpdir\", true, |result| {\n                    assert!(!result.is_empty()); // platform dependant\n                })\n                .await;\n            })\n        })\n        .await;\n    }\n\n    #[cfg(feature = \"statistics\")]\n    #[tokio::test]\n    async fn test_totalmem() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                run_test_return_number(&ctx, \"totalmem\", |result| {\n                    assert!(result.is_number()); // platform dependant\n                })\n                .await;\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_type() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                run_test_return_string(&ctx, \"type\", true, |result| {\n                    assert!(result == \"Linux\" || result == \"Windows_NT\" || result == \"Darwin\");\n                })\n                .await;\n            })\n        })\n        .await;\n    }\n\n    #[cfg(feature = \"system\")]\n    #[tokio::test]\n    async fn test_uptime() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                run_test_return_number(&ctx, \"uptime\", |result| {\n                    assert!(result.is_number()); // platform dependant\n                })\n                .await;\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_version() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                run_test_return_string(&ctx, \"version\", true, |result| {\n                    assert!(!result.is_empty()); // platform dependant\n                })\n                .await;\n            })\n        })\n        .await;\n    }\n}\n"
  },
  {
    "path": "modules/llrt_os/src/network.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{\n    collections::HashMap,\n    net::{Ipv4Addr, Ipv6Addr},\n    sync::{Arc, Mutex},\n};\n\nuse llrt_utils::result::ResultExt;\nuse once_cell::sync::Lazy;\nuse rquickjs::{Ctx, Object, Result};\nuse sysinfo::Networks;\n\nstatic NETWORKS: Lazy<Arc<Mutex<Networks>>> =\n    Lazy::new(|| Arc::new(Mutex::new(Networks::new_with_refreshed_list())));\n\npub fn get_network_interfaces(ctx: Ctx<'_>) -> Result<HashMap<String, Vec<Object<'_>>>> {\n    let mut map: HashMap<String, Vec<Object>> = HashMap::new();\n    let networks = NETWORKS.lock().unwrap();\n\n    for (interface_name, network_data) in networks.iter() {\n        let mut ifs = Vec::new();\n\n        for ip_network in network_data.ip_networks() {\n            let addr = &ip_network.addr.to_string();\n            let is_ipv4 = addr.contains(\".\");\n            let (is_internal, scope_id) = if is_ipv4 {\n                get_attribute_ipv4(&ctx, addr)?\n            } else {\n                get_attribute_ipv6(&ctx, addr)?\n            };\n\n            let obj = Object::new(ctx.clone())?;\n            obj.set(\"address\", addr)?;\n            obj.set(\n                \"netmask\",\n                if is_ipv4 {\n                    prefix_to_netmask_ipv4(ip_network.prefix)\n                } else {\n                    prefix_to_netmask_ipv6(ip_network.prefix)\n                }\n                .to_string(),\n            )?;\n            obj.set(\"family\", if is_ipv4 { \"IPv4\" } else { \"IPv6\" })?;\n            obj.set(\"mac\", network_data.mac_address().to_string())?;\n            obj.set(\"internal\", is_internal)?;\n            obj.set(\"cidr\", [addr, \"/\", &ip_network.prefix.to_string()].concat())?;\n            if !is_ipv4 {\n                obj.set(\"scopeid\", scope_id)?;\n            }\n\n            ifs.push(obj);\n        }\n        if !ifs.is_empty() {\n            map.insert(interface_name.to_string(), ifs);\n        }\n    }\n    Ok(map)\n}\n\nfn prefix_to_netmask_ipv4(prefix: u8) -> Box<str> {\n    let mut prefix = prefix;\n\n    if prefix > 32 {\n        return Box::from(\"\");\n    }\n\n    let mut mask = [0u8; 4];\n\n    #[allow(clippy::needless_range_loop)]\n    for i in 0..4 {\n        if prefix >= 8 {\n            mask[i] = 255;\n            prefix -= 8;\n        } else if prefix > 0 {\n            mask[i] = 255 << (8 - prefix);\n            break;\n        }\n    }\n    Box::from(Ipv4Addr::new(mask[0], mask[1], mask[2], mask[3]).to_string())\n}\n\nfn prefix_to_netmask_ipv6(prefix: u8) -> Box<str> {\n    let mut prefix = prefix;\n\n    if prefix > 128 {\n        return Box::from(\"\");\n    }\n\n    let mut mask = [0u16; 8];\n\n    #[allow(clippy::needless_range_loop)]\n    for i in 0..8 {\n        if prefix >= 16 {\n            mask[i] = 0xFFFF;\n            prefix -= 16;\n        } else if prefix > 0 {\n            mask[i] = 0xFFFF << (16 - prefix);\n            break;\n        }\n    }\n    Box::from(\n        Ipv6Addr::new(\n            mask[0], mask[1], mask[2], mask[3], mask[4], mask[5], mask[6], mask[7],\n        )\n        .to_string(),\n    )\n}\n\nfn get_attribute_ipv4(ctx: &Ctx<'_>, addr: &str) -> Result<(bool, u8)> {\n    let addr = addr.parse::<Ipv4Addr>().or_throw(ctx)?;\n    let is_internal = addr.is_broadcast()\n        || addr.is_documentation()\n        || addr.is_link_local()\n        || addr.is_loopback()\n        || addr.is_multicast()\n        || addr.is_unspecified();\n    let scope_id = 0; // For IPv4, ScopeID is a dummy value.\n\n    Ok((is_internal, scope_id))\n}\n\nfn get_attribute_ipv6(ctx: &Ctx<'_>, addr: &str) -> Result<(bool, u8)> {\n    let addr = addr.parse::<Ipv6Addr>().or_throw(ctx)?;\n    let is_internal = addr.is_loopback() || addr.is_multicast() || addr.is_unspecified();\n    let scope_id = 0; // ScopeID is not supported at this time.\n\n    Ok((is_internal, scope_id))\n}\n"
  },
  {
    "path": "modules/llrt_os/src/statistics.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::sync::{Arc, Mutex};\n\nuse once_cell::sync::Lazy;\nuse rquickjs::{Ctx, Object, Result};\nuse sysinfo::{CpuRefreshKind, MemoryRefreshKind, RefreshKind, System};\n\nstatic SYSTEM: Lazy<Arc<Mutex<System>>> = Lazy::new(|| {\n    Arc::new(Mutex::new(System::new_with_specifics(\n        RefreshKind::nothing()\n            .with_cpu(CpuRefreshKind::nothing().with_cpu_usage().with_frequency())\n            .with_memory(MemoryRefreshKind::nothing().with_ram()),\n    )))\n});\n\npub fn get_cpus(ctx: Ctx<'_>) -> Result<Vec<Object<'_>>> {\n    let mut vec: Vec<Object> = Vec::new();\n    let system = SYSTEM.lock().unwrap();\n\n    for cpu in system.cpus() {\n        let obj = Object::new(ctx.clone())?;\n        obj.set(\"model\", cpu.brand())?;\n        obj.set(\"speed\", cpu.frequency())?;\n\n        // The number of milliseconds spent by the CPU in each mode cannot be obtained at this time.\n        let times = Object::new(ctx.clone())?;\n        times.set(\"user\", 0)?;\n        times.set(\"nice\", 0)?;\n        times.set(\"sys\", 0)?;\n        times.set(\"idle\", 0)?;\n        times.set(\"irq\", 0)?;\n        obj.set(\"times\", times)?;\n\n        vec.push(obj);\n    }\n    Ok(vec)\n}\n\npub fn get_free_mem() -> u64 {\n    let mut system = SYSTEM.lock().unwrap();\n\n    system.refresh_memory_specifics(MemoryRefreshKind::nothing().with_ram());\n    system.free_memory()\n}\n\npub fn get_total_mem() -> u64 {\n    let mut system = SYSTEM.lock().unwrap();\n\n    system.refresh_memory_specifics(MemoryRefreshKind::nothing().with_ram());\n    system.total_memory()\n}\n"
  },
  {
    "path": "modules/llrt_os/src/unix.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{\n    ffi::CStr,\n    sync::{Arc, Mutex},\n};\n\nuse libc::{getpriority, setpriority, PRIO_PROCESS};\nuse once_cell::sync::Lazy;\nuse rquickjs::{\n    prelude::{Opt, Rest},\n    Ctx, Exception, IntoJs, Null, Object, Result, Value,\n};\nuse users::{os::unix::UserExt, Groups, Users, UsersCache};\n\nuse crate::get_home_dir;\n\nstatic USER_CACHE: Lazy<Arc<Mutex<UsersCache>>> =\n    Lazy::new(|| Arc::new(Mutex::new(UsersCache::new())));\n\nstatic OS_INFO: Lazy<(String, String, String)> = Lazy::new(uname);\npub static EOL: &str = \"\\n\";\npub static DEV_NULL: &str = \"/dev/null\";\n\npub fn get_priority(who: Opt<u32>) -> i32 {\n    let who = who.0.unwrap_or(0);\n\n    unsafe { getpriority(PRIO_PROCESS, who) }\n}\n\npub fn set_priority(ctx: Ctx<'_>, args: Rest<Value>) -> Result<()> {\n    let mut args_iter = args.0.into_iter().rev();\n    let prio: i32 = args_iter\n        .next()\n        .and_then(|v| v.as_number())\n        .ok_or_else(|| {\n            Exception::throw_type(&ctx, \"The `priority` argument must be of type number.\")\n        })? as i32;\n    let who: u32 = args_iter.next().and_then(|v| v.as_number()).unwrap_or(0f64) as u32;\n\n    if !(-20..=19).contains(&prio) {\n        return Err(Exception::throw_range(\n            &ctx,\n            \"The value of `priority` is out of range. It must be >= -20 && <= 19.\",\n        ));\n    }\n\n    unsafe {\n        setpriority(PRIO_PROCESS, who, prio);\n    }\n    Ok(())\n}\n\npub fn get_type() -> &'static str {\n    &OS_INFO.0\n}\n\npub fn get_user_info<'js>(ctx: Ctx<'js>, _options: Opt<Value>) -> Result<Object<'js>> {\n    let cache = USER_CACHE.lock().unwrap();\n\n    let obj = Object::new(ctx.clone())?;\n\n    let uid = cache.get_current_uid();\n    obj.set(\"uid\", uid)?;\n    obj.set(\"gid\", cache.get_current_gid())?;\n\n    let (username, shell) = if let Some(user) = cache.get_user_by_uid(uid) {\n        (\n            user.name().to_str().into_js(&ctx)?,\n            user.shell().to_str().into_js(&ctx)?,\n        )\n    } else {\n        (Null.into_js(&ctx)?, Null.into_js(&ctx)?)\n    };\n    obj.set(\"username\", username)?;\n    obj.set(\"homedir\", get_home_dir(ctx.clone()))?;\n    obj.set(\"shell\", shell)?;\n    Ok(obj)\n}\n\npub fn get_release() -> &'static str {\n    &OS_INFO.1\n}\n\npub fn get_version() -> &'static str {\n    &OS_INFO.2\n}\n\nfn uname() -> (String, String, String) {\n    let mut info = std::mem::MaybeUninit::uninit();\n    // SAFETY: `info` is a valid pointer to a `libc::utsname` struct.\n    let res = unsafe { libc::uname(info.as_mut_ptr()) };\n    if res != 0 {\n        return (String::new(), String::new(), String::new());\n    }\n    // SAFETY: `uname` returns 0 on success and info is initialized.\n    let info = unsafe { info.assume_init() };\n    (\n        // SAFETY: `info.sysname` is a valid NUL-terminated pointer.\n        unsafe {\n            CStr::from_ptr(info.sysname.as_ptr())\n                .to_string_lossy()\n                .into_owned()\n        },\n        // SAFETY: `info.release` is a valid NUL-terminated pointer.\n        unsafe {\n            CStr::from_ptr(info.release.as_ptr())\n                .to_string_lossy()\n                .into_owned()\n        },\n        // SAFETY: `info.version` is a valid NUL-terminated pointer.\n        unsafe {\n            CStr::from_ptr(info.version.as_ptr())\n                .to_string_lossy()\n                .into_owned()\n        },\n    )\n}\n"
  },
  {
    "path": "modules/llrt_os/src/windows.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_utils::result::ResultExt;\nuse once_cell::sync::Lazy;\nuse rquickjs::{\n    prelude::{Opt, Rest},\n    Ctx, Exception, IntoJs, Null, Object,\n};\n\nuse windows_registry::LOCAL_MACHINE;\nuse windows_result::Result;\nuse windows_version::OsVersion;\n\nuse crate::get_home_dir;\n\nstatic OS_RELEASE: Lazy<String> = Lazy::new(release);\nstatic OS_VERSION: Lazy<String> = Lazy::new(|| version().unwrap_or_default());\npub static EOL: &str = \"\\r\\n\";\npub static DEV_NULL: &str = \"\\\\.\\nul\";\n\npub fn get_priority(_who: Opt<u32>) -> i32 {\n    0\n}\n\npub fn set_priority(ctx: Ctx<'_>, _args: Rest<rquickjs::Value>) -> rquickjs::Result<()> {\n    Err(Exception::throw_syntax(\n        &ctx,\n        \"setPriority is not implemented.\",\n    ))\n}\n\npub fn get_type() -> &'static str {\n    // In theory there are more types linx MinGW but in practice this is good enough\n    \"Windows_NT\"\n}\n\npub fn get_release() -> &'static str {\n    &OS_RELEASE\n}\n\npub fn get_version() -> &'static str {\n    &OS_VERSION\n}\n\nfn release() -> String {\n    let version = OsVersion::current();\n    format!(\"{}.{}.{}\", version.major, version.minor, version.build)\n}\n\npub fn get_user_info<'js>(\n    ctx: Ctx<'js>,\n    _options: Opt<rquickjs::Value>,\n) -> rquickjs::Result<Object<'js>> {\n    let obj = Object::new(ctx.clone())?;\n\n    obj.set(\"uid\", -1)?;\n    obj.set(\"gid\", -1)?;\n    obj.set(\"username\", whoami::username().or_throw(&ctx)?)?;\n    obj.set(\"homedir\", get_home_dir(ctx.clone()))?;\n    obj.set(\"shell\", Null.into_js(&ctx)?)?;\n    Ok(obj)\n}\n\nfn version() -> Result<String> {\n    let version = OsVersion::current();\n\n    let registry_key = LOCAL_MACHINE\n        .open(\"SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\")\n        .map_err(std::io::Error::from)?;\n    let mut value = registry_key\n        .get_string(\"ProductName\")\n        .map_err(std::io::Error::from)?;\n    // Windows 11 shares dwMajorVersion with Windows 10\n    // this workaround tries to disambiguate that by checking\n    // if the dwBuildNumber is from Windows 11 releases (>= 22000).\n    if version.major == 10 && version.build >= 22000 && value.starts_with(\"Windows 10\") {\n        value.replace_range(9..10, \"1\");\n    }\n\n    Ok(value)\n}\n"
  },
  {
    "path": "modules/llrt_path/Cargo.toml",
    "content": "[package]\nname = \"llrt_path\"\ndescription = \"LLRT Module path\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[lib]\nname = \"llrt_path\"\npath = \"src/lib.rs\"\n\n[dependencies]\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", features = [\"std\"], default-features = false }\n\n[target.'cfg(windows)'.dependencies]\nmemchr = { version = \"2\", default-features = false }\n\n[dev-dependencies]\ncriterion = { version = \"0.8\", default-features = false }\nonce_cell = { version = \"1\", features = [\"std\"], default-features = false }\nrand = { version = \"0.10.0\", features = [\n  \"alloc\",\n  \"thread_rng\",\n], default-features = false }\n\n[[bench]]\nname = \"slash_replacement\"\nharness = false\n"
  },
  {
    "path": "modules/llrt_path/benches/slash_replacement.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#![allow(clippy::uninlined_format_args)]\n\nuse criterion::{criterion_group, criterion_main, Criterion};\nuse llrt_path::replace_backslash;\nuse rand::prelude::*;\nuse std::path::{Path, PathBuf};\n\nconst MAX_DEPTH: usize = 10;\nconst PATH_STYLE_PROB: f64 = 0.5;\n\nconst WORD_LIST: &[&str] = &[\n    \"home\",\n    \"user\",\n    \"admin\",\n    \"documents\",\n    \"downloads\",\n    \"music\",\n    \"videos\",\n    \"projects\",\n    \"notes\",\n    \"desktop\",\n    \"workspace\",\n    \"archive\",\n    \"backup\",\n    \"code\",\n    \"scripts\",\n    \"logs\",\n    \"build\",\n    \"bin\",\n    \"src\",\n    \"include\",\n    \"lib\",\n    \"temp\",\n    \"cache\",\n    \"system\",\n    \"private\",\n    \"shared\",\n    \"public\",\n    \"common\",\n    \"vacation\",\n    \"pictures\",\n    \"gallery\",\n    \"photos\",\n    \"library\",\n    \"data\",\n    \"storage\",\n    \"cloud\",\n    \"tasks\",\n    \"files\",\n    \"records\",\n    \"history\",\n    \"samples\",\n    \"assets\",\n    \"media\",\n    \"config\",\n    \"setup\",\n    \"exports\",\n    \"imports\",\n    \"local\",\n    \"global\",\n    \"network\",\n    \"remote\",\n    \"main\",\n    \"backup\",\n    \"security\",\n    \"mainframe\",\n    \"tools\",\n    \"resources\",\n    \"info\",\n    \"settings\",\n    \"profile\",\n    \"account\",\n    \"group\",\n    \"modules\",\n    \"scripts\",\n    \"test\",\n    \"dist\",\n    \"coverage\",\n    \"docs\",\n    \"models\",\n    \"services\",\n    \"components\",\n    \"assets\",\n    \"functions\",\n    \"tests\",\n    \"data\",\n    \"results\",\n    \"index\",\n    \"source\",\n    \"runtime\",\n    \"example\",\n    \"template\",\n    \"styles\",\n    \"layout\",\n    \"config\",\n    \"docs\",\n    \"dependencies\",\n    \"log\",\n    \"controller\",\n    \"service\",\n    \"client\",\n    \"server\",\n    \"draft\",\n    \"final\",\n    \"old\",\n    \"new\",\n    \"review\",\n    \"complete\",\n    \"inprogress\",\n    \"template\",\n    \"empty\",\n    \"readme\",\n    \"license\",\n    \"notes\",\n    \"reference\",\n    \"guide\",\n    \"outline\",\n    \"summary\",\n];\n\nfn generate_random_path() -> String {\n    let mut rng = ThreadRng::default();\n    let mut path = PathBuf::new();\n    let depth = rng.random_range(1..=MAX_DEPTH);\n\n    for _ in 0..depth {\n        let name = WORD_LIST.choose(&mut rng).unwrap();\n        if rng.random_bool(PATH_STYLE_PROB) {\n            path.push(format!(\"{}\\\\\", name));\n        } else {\n            path.push(name);\n        }\n    }\n    path.to_string_lossy().to_string()\n}\n\nfn replace_with_string_replace(path: String) -> String {\n    path.replace('\\\\', \"/\")\n}\n\nfn benchmark(c: &mut Criterion) {\n    c.bench_function(\"String Replace\", |b| {\n        b.iter(|| {\n            let path = generate_random_path();\n            replace_with_string_replace(path);\n        })\n    });\n\n    c.bench_function(\"Memchr Replace\", |b| {\n        b.iter(|| {\n            let path = generate_random_path();\n            replace_backslash(path);\n        })\n    });\n\n    c.bench_function(\"File slash replace\", |b| {\n        b.iter(|| {\n            let path = generate_random_path();\n            replace_filename(path);\n        })\n    });\n\n    c.bench_function(\"File components replace\", |b| {\n        b.iter(|| {\n            let path = generate_random_path();\n            replace_components(path);\n        })\n    });\n}\n\nfn replace_components(path: String) -> String {\n    let length = path.len();\n    let path = Path::new(&path);\n    let components = path.components();\n    let mut new_path = String::with_capacity(length);\n\n    for component in components {\n        new_path.push_str(&component.as_os_str().to_string_lossy());\n        new_path.push('/');\n    }\n    new_path.truncate(length);\n\n    new_path\n}\n\nfn replace_filename(path: String) -> String {\n    Path::new(&path)\n        .to_string_lossy()\n        .to_string()\n        .replace('\\\\', \"/\")\n}\n\ncriterion_group!(benches, benchmark);\ncriterion_main!(benches);\n"
  },
  {
    "path": "modules/llrt_path/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{\n    borrow::Cow,\n    path::{Component, Path, PathBuf, MAIN_SEPARATOR, MAIN_SEPARATOR_STR},\n};\n\nuse llrt_utils::module::{export_default, ModuleInfo};\nuse rquickjs::{\n    function::Opt,\n    module::{Declarations, Exports, ModuleDef},\n    prelude::{Func, Rest},\n    Ctx, Object, Result,\n};\n\npub struct PathModule;\n\n#[cfg(windows)]\nconst DELIMITER: char = ';';\n#[cfg(not(windows))]\nconst DELIMITER: char = ':';\n\n#[cfg(windows)]\npub const CURRENT_DIR_STR: &str = \".\\\\\";\n\n#[cfg(windows)]\nconst FORWARD_SLASH_STR: &str = \"/\";\n\n#[cfg(not(windows))]\npub const CURRENT_DIR_STR: &str = \"./\";\n\n#[cfg(windows)]\nuse memchr::{memchr, memchr2, memchr2_iter};\n\n#[cfg(windows)]\npub fn replace_backslash(path: impl Into<String>) -> String {\n    let mut path = path.into();\n    let bytes = unsafe { path.as_bytes_mut() };\n\n    let mut start = 0;\n    while let Some(pos) = memchr(b'\\\\', &bytes[start..]) {\n        bytes[start + pos] = b'/';\n        start += pos + 1;\n    }\n    path\n}\n\n#[cfg(not(windows))]\npub fn replace_backslash(path: impl Into<String>) -> String {\n    path.into().replace('\\\\', \"/\")\n}\n\n#[cfg(windows)]\nfn find_next_separator(s: &str) -> Option<usize> {\n    memchr2(b'\\\\', b'/', s.as_bytes())\n}\n\n#[cfg(not(windows))]\nfn find_next_separator(s: &str) -> Option<usize> {\n    s.find(MAIN_SEPARATOR)\n}\n\n#[cfg(windows)]\nfn find_last_sep(path: &str) -> Option<usize> {\n    memchr2_iter(b'\\\\', b'/', path.as_bytes()).next_back()\n}\n\n#[cfg(not(windows))]\nfn find_last_sep(path: &str) -> Option<usize> {\n    path.rfind(MAIN_SEPARATOR)\n}\n\npub fn dirname<'a, P: Into<Cow<'a, str>>>(path: P) -> String {\n    let path = path.into();\n    let len = path.len();\n\n    if len == 0 {\n        return \".\".into();\n    }\n\n    let bytes = path.as_bytes();\n\n    #[cfg(windows)]\n    {\n        if len == 1 {\n            return if is_sep(bytes[0]) {\n                path.into_owned()\n            } else {\n                \".\".to_string()\n            };\n        }\n\n        // Determine root end and search offset\n        let (root_end, offset) = if is_sep(bytes[0]) {\n            if is_sep(bytes[1]) {\n                // UNC path: \\\\server\\share\n                parse_unc_root(bytes, len).unwrap_or((1, 1))\n            } else {\n                (1, 1)\n            }\n        } else if bytes.len() > 1 && is_drive_letter(bytes[0]) && bytes[1] == b':' {\n            let r = if len > 2 && is_sep(bytes[2]) { 3 } else { 2 };\n            (r, r)\n        } else {\n            (0, 0)\n        };\n\n        // Find last separator (skipping trailing separators)\n        let end = find_dirname_end(bytes, offset);\n\n        match end {\n            Some(e) => &path[..e],\n            None if root_end > 0 => &path[..root_end],\n            None => \".\",\n        }\n        .into()\n    }\n\n    #[cfg(not(windows))]\n    {\n        if len == 1 {\n            return if bytes[0] == b'/' {\n                path.into_owned()\n            } else {\n                \".\".into()\n            };\n        }\n\n        let has_root = bytes[0] == b'/';\n        let end = find_dirname_end(bytes, 1);\n\n        match end {\n            Some(e) if has_root && e == 1 => \"//\",\n            Some(e) => &path[..e],\n            None if has_root => \"/\",\n            None => \".\",\n        }\n        .into()\n    }\n}\n\n#[cfg(windows)]\nfn is_sep(c: u8) -> bool {\n    c == b'/' || c == b'\\\\'\n}\n\n#[cfg(windows)]\nfn is_drive_letter(c: u8) -> bool {\n    c.is_ascii_alphabetic()\n}\n\n#[cfg(windows)]\nfn parse_unc_root(bytes: &[u8], len: usize) -> Option<(usize, usize)> {\n    let mut j = 2;\n    // Skip server name\n    while j < len && !is_sep(bytes[j]) {\n        j += 1;\n    }\n    if j >= len || j == 2 {\n        return None;\n    }\n    // Skip separators\n    while j < len && is_sep(bytes[j]) {\n        j += 1;\n    }\n    if j >= len {\n        return None;\n    }\n    let share_start = j;\n    // Skip share name\n    while j < len && !is_sep(bytes[j]) {\n        j += 1;\n    }\n    if j == share_start {\n        return None;\n    }\n    if j == len {\n        return None;\n    } // UNC root only - caller handles this\n    Some((j + 1, j + 1))\n}\n\nfn find_dirname_end(bytes: &[u8], offset: usize) -> Option<usize> {\n    let mut matched_slash = true;\n    for i in (offset..bytes.len()).rev() {\n        #[cfg(windows)]\n        let is_separator = is_sep(bytes[i]);\n        #[cfg(not(windows))]\n        let is_separator = bytes[i] == b'/';\n\n        if is_separator {\n            if !matched_slash {\n                return Some(i);\n            }\n        } else {\n            matched_slash = false;\n        }\n    }\n    None\n}\n\npub fn name_extname(path: &str) -> (&str, &str) {\n    let path = strip_last_sep(path);\n    let sep_pos = find_last_sep(path);\n\n    let path = match sep_pos {\n        Some(idx) => &path[idx + 1..],\n        None => path,\n    };\n    if path.starts_with('.') {\n        return (path, \"\");\n    }\n    match path.rfind('.') {\n        Some(idx) => path.split_at(idx),\n        None => (path, \"\"),\n    }\n}\n\nfn strip_last_sep(path: &str) -> &str {\n    if ends_with_sep(path) {\n        &path[..path.len() - 1]\n    } else {\n        path\n    }\n}\n\npub fn basename(path: String, suffix: Opt<String>) -> String {\n    #[cfg(windows)]\n    {\n        if path.is_empty() || path == MAIN_SEPARATOR_STR || path == FORWARD_SLASH_STR {\n            return String::from(\"\");\n        }\n    }\n    #[cfg(not(windows))]\n    {\n        if path.is_empty() || path == MAIN_SEPARATOR_STR {\n            return String::from(\"\");\n        }\n    }\n\n    let (base, ext) = name_extname(&path);\n    let mut name = [base, ext].concat();\n    if let Some(suffix) = suffix.0 {\n        if let Some(location) = name.rfind(&suffix) {\n            name.truncate(location);\n            return name;\n        }\n    }\n    name\n}\n\nfn extname(path: String) -> String {\n    let (_, ext) = name_extname(&path);\n    ext.to_string()\n}\n\nfn format(obj: Object) -> String {\n    let dir: String = obj.get(\"dir\").unwrap_or_default();\n    let root: String = obj.get(\"root\").unwrap_or_default();\n    let base: String = obj.get(\"base\").unwrap_or_default();\n    let name: String = obj.get(\"name\").unwrap_or_default();\n    let ext: String = obj.get(\"ext\").unwrap_or_default();\n\n    let mut path = String::new();\n    if !dir.is_empty() {\n        path.push_str(&dir);\n        if !ends_with_sep(&dir) {\n            path.push(MAIN_SEPARATOR);\n        }\n    } else if !root.is_empty() {\n        path.push_str(&root);\n        if !ends_with_sep(&root) {\n            path.push(MAIN_SEPARATOR);\n        }\n    }\n    if !base.is_empty() {\n        path.push_str(&base);\n    } else {\n        path.push_str(&name);\n        if !ext.is_empty() {\n            if !ext.starts_with('.') {\n                path.push('.');\n            }\n            path.push_str(&ext);\n        }\n    }\n    path\n}\n\nfn parse(ctx: Ctx, path_str: String) -> Result<Object> {\n    let obj = Object::new(ctx)?;\n    let path = Path::new(&path_str);\n    let parent = path\n        .parent()\n        .map(|p| p.to_str().unwrap())\n        .unwrap_or_default();\n    let filename = path\n        .file_name()\n        .map(|n| n.to_str().unwrap())\n        .unwrap_or_default();\n\n    let (name, extension) = name_extname(filename);\n\n    let root = path\n        .components()\n        .next()\n        .and_then(|c| match c {\n            Component::Prefix(prefix) => prefix.as_os_str().to_str(),\n            Component::RootDir => c.as_os_str().to_str(),\n            _ => Some(\"\"),\n        })\n        .unwrap_or_default();\n\n    obj.set(\"root\", root)?;\n    obj.set(\"dir\", parent)?;\n    obj.set(\"base\", [name, extension].concat())?;\n    obj.set(\"ext\", extension)?;\n    obj.set(\"name\", name)?;\n\n    Ok(obj)\n}\n\nfn join(parts: Rest<String>) -> String {\n    join_path(parts.0.iter())\n}\n\npub fn join_path<S, I>(parts: I) -> String\nwhere\n    S: AsRef<str>,\n    I: IntoIterator<Item = S>,\n{\n    join_path_with_separator(parts, false)\n}\n\npub fn join_path_with_separator<S, I>(parts: I, force_posix_sep: bool) -> String\nwhere\n    S: AsRef<str>,\n    I: IntoIterator<Item = S>,\n{\n    //fine because we're either moving or storing references\n    let parts_vec: Vec<S> = parts.into_iter().collect();\n    //add one slash plus drive letter\n    //max is probably parts+size\n    let likely_max_size = parts_vec\n        .iter()\n        .map(|p| p.as_ref().len() + 1)\n        .sum::<usize>()\n        + 10;\n    let result = String::with_capacity(likely_max_size);\n    join_resolve_path(parts_vec, false, result, PathBuf::new(), force_posix_sep)\n}\n\npub fn resolve_path<S, I>(parts: I) -> Result<String>\nwhere\n    S: AsRef<str>,\n    I: IntoIterator<Item = S>,\n{\n    resolve_path_with_separator(parts, false)\n}\n\npub fn resolve_path_with_separator<S, I>(parts: I, force_posix_sep: bool) -> Result<String>\nwhere\n    S: AsRef<str>,\n    I: IntoIterator<Item = S>,\n{\n    let cwd = std::env::current_dir()?;\n\n    let mut result = cwd.clone().into_os_string().into_string().unwrap();\n    //add MAIN_SEPARATOR if we're not on already MAIN_SEPARATOR\n    if !result.ends_with(MAIN_SEPARATOR) {\n        result.push(MAIN_SEPARATOR);\n    }\n    #[cfg(windows)]\n    {\n        if force_posix_sep {\n            result = result.replace(MAIN_SEPARATOR, FORWARD_SLASH_STR);\n        }\n    }\n    Ok(join_resolve_path(parts, true, result, cwd, force_posix_sep))\n}\n\npub fn relative<F, T>(from: F, to: T) -> Result<String>\nwhere\n    F: AsRef<str>,\n    T: AsRef<str>,\n{\n    let from_ref = from.as_ref();\n    let to_ref = to.as_ref();\n    if from_ref == to_ref {\n        return Ok(\"\".into());\n    }\n\n    let mut abs_from = None;\n\n    if !is_absolute(from_ref) {\n        abs_from = Some(\n            std::env::current_dir()?.to_string_lossy().to_string() + MAIN_SEPARATOR_STR + from_ref,\n        );\n    }\n\n    let mut abs_to = None;\n\n    if !is_absolute(to_ref) {\n        abs_to = Some(\n            std::env::current_dir()?.to_string_lossy().to_string() + MAIN_SEPARATOR_STR + to_ref,\n        );\n    }\n\n    let from_ref = abs_from.as_deref().unwrap_or(from_ref);\n    let to_ref = abs_to.as_deref().unwrap_or(to_ref);\n\n    let mut from_index = 0;\n    let mut to_index = 0;\n    // skip common prefix\n    while from_index < from_ref.len() && to_index < to_ref.len() {\n        let from_next = find_next_separator(&from_ref[from_index..])\n            .unwrap_or(from_ref.len() - from_index)\n            + from_index;\n        let to_next =\n            find_next_separator(&to_ref[to_index..]).unwrap_or(to_ref.len() - to_index) + to_index;\n        if from_ref[from_index..from_next] != to_ref[to_index..to_next] {\n            break;\n        }\n        from_index = from_next + 1; //move past the separator\n        to_index = to_next + 1; //move past the separator\n    }\n    let mut relative = String::new();\n    // add \"..\" for each remaining component in 'from'\n    while from_index < from_ref.len() {\n        let from_next = find_next_separator(&from_ref[from_index..])\n            .unwrap_or(from_ref.len() - from_index)\n            + from_index;\n        if !relative.is_empty() {\n            relative.push(MAIN_SEPARATOR);\n        }\n        relative.push_str(\"..\");\n        from_index = from_next + 1; // Move past the separator\n    }\n    // add the remaining components from 'to'\n    while to_index < to_ref.len() {\n        let to_next =\n            find_next_separator(&to_ref[to_index..]).unwrap_or(to_ref.len() - to_index) + to_index;\n        if !relative.is_empty() {\n            relative.push(MAIN_SEPARATOR);\n        }\n        let component = &to_ref[to_index..to_next];\n        if component != \".\" {\n            relative.push_str(component);\n        }\n        to_index = to_next + 1; // Move past the separator\n    }\n    Ok(if relative.is_empty() {\n        \".\".into()\n    } else {\n        relative\n    })\n}\n\nfn join_resolve_path<S, I>(\n    parts: I,\n    resolve: bool,\n    mut result: String,\n    cwd: PathBuf,\n    force_posix_sep: bool,\n) -> String\nwhere\n    S: AsRef<str>,\n    I: IntoIterator<Item = S>,\n{\n    let (sep, sep_str) = if force_posix_sep {\n        ('/', \"/\")\n    } else {\n        (MAIN_SEPARATOR, MAIN_SEPARATOR_STR)\n    };\n\n    let mut resolve_cow: Cow<str>;\n    let mut empty = true;\n    let mut prefix_len = 0;\n\n    let mut index_stack = Vec::with_capacity(16);\n\n    // Remove the trailing sep: /a/b// -> /a/b\n    if ends_with_sep(&result) && result.len() > 1 {\n        result.truncate(result.len() - 1);\n    }\n\n    for part in parts {\n        let mut part_ref: &str = part.as_ref();\n        let mut start = 0;\n        if resolve {\n            if cfg!(not(windows)) {\n                if part_ref.starts_with(MAIN_SEPARATOR) {\n                    empty = false;\n                    result = MAIN_SEPARATOR.into();\n                    start = 1;\n                }\n            } else {\n                let starts_with_sep = starts_with_sep(part_ref);\n                if starts_with_sep {\n                    let (prefix, _) = get_path_prefix(&cwd);\n                    prefix_len = prefix.len();\n                    result = prefix;\n                    empty = false;\n                    result.push(sep);\n                } else {\n                    let path_buf: PathBuf = PathBuf::from(part_ref);\n                    if path_buf.is_absolute() {\n                        empty = false;\n                        let (prefix, mut components) = get_path_prefix(&path_buf);\n                        if !prefix.is_empty() {\n                            components.next(); //consume prefix\n                        }\n                        prefix_len = prefix.len();\n                        result = prefix;\n                        result.push(sep);\n                        resolve_cow = components\n                            .map(|comp| comp.as_os_str().to_str().unwrap_or_default()) // Convert each component to &str\n                            .collect::<Vec<&str>>() // Collect into a vector of &str\n                            .join(sep_str)\n                            .into();\n                        part_ref = resolve_cow.as_ref();\n                    }\n                }\n            }\n        } else if starts_with_sep(part_ref) && empty {\n            empty = false;\n            result.push(sep);\n            start = 1;\n        }\n\n        while start < part_ref.len() {\n            let end = find_next_separator(&part_ref[start..]).map_or(part_ref.len(), |i| i + start);\n            match &part_ref[start..end] {\n                \"..\" => {\n                    if let Some(last_index) = index_stack.pop() {\n                        result.truncate(last_index);\n                    } else if empty {\n                        if let Some(last_index) = find_last_sep(&result) {\n                            result.truncate(last_index);\n                        }\n                    }\n                },\n                \"\" | \".\" => {\n                    //ignore\n                },\n                sub_part => {\n                    let len = result.len();\n                    if !result.ends_with(sep) && !result.is_empty() {\n                        result.push(sep);\n                    }\n                    result.push_str(sub_part);\n                    result.push(sep);\n                    index_stack.push(len);\n                },\n            }\n            start = end + 1;\n        }\n    }\n\n    if result.len() > prefix_len + 1 && ends_with_sep(&result) {\n        result.truncate(result.len() - 1);\n    }\n\n    result\n}\n\npub fn resolve(path: Rest<String>) -> Result<String> {\n    resolve_path(path.iter())\n}\n\nfn get_path_prefix(cwd: &Path) -> (String, std::iter::Peekable<std::path::Components<'_>>) {\n    let mut components = cwd.components().peekable();\n\n    let prefix = if let Some(Component::Prefix(prefix)) = components.peek() {\n        prefix.as_os_str().to_str().unwrap().to_string()\n    } else {\n        \"\".into()\n    };\n\n    (prefix, components)\n}\n\npub fn normalize<P: AsRef<str>>(path: P) -> String {\n    join_path([path].iter())\n}\n\n#[allow(dead_code)] //used by windows\nfn starts_with_sep(path: &str) -> bool {\n    matches!(path.as_bytes().first().unwrap_or(&0), b'/' | b'\\\\')\n}\n\n#[cfg(windows)]\npub fn ends_with_sep(path: &str) -> bool {\n    matches!(path.as_bytes().last().unwrap_or(&0), b'/' | b'\\\\')\n}\n\n#[cfg(not(windows))]\npub fn ends_with_sep(path: &str) -> bool {\n    path.ends_with(MAIN_SEPARATOR)\n}\n\n#[cfg(windows)]\npub fn is_absolute(path: &str) -> bool {\n    starts_with_sep(path) || PathBuf::from(path).is_absolute()\n}\n\n#[cfg(not(windows))]\npub fn is_absolute(path: &str) -> bool {\n    path.starts_with(MAIN_SEPARATOR)\n}\n\nimpl ModuleDef for PathModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(\"basename\")?;\n        declare.declare(\"dirname\")?;\n        declare.declare(\"extname\")?;\n        declare.declare(\"format\")?;\n        declare.declare(\"parse\")?;\n        declare.declare(\"join\")?;\n        declare.declare(\"resolve\")?;\n        declare.declare(\"relative\")?;\n        declare.declare(\"normalize\")?;\n        declare.declare(\"isAbsolute\")?;\n        declare.declare(\"delimiter\")?;\n        declare.declare(\"sep\")?;\n\n        declare.declare(\"default\")?;\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        export_default(ctx, exports, |default| {\n            default.set(\"dirname\", Func::from(dirname::<String>))?;\n            default.set(\"basename\", Func::from(basename))?;\n            default.set(\"extname\", Func::from(extname))?;\n            default.set(\"format\", Func::from(format))?;\n            default.set(\"parse\", Func::from(parse))?;\n            default.set(\"join\", Func::from(join))?;\n            default.set(\"relative\", Func::from(relative::<String, String>))?;\n            default.set(\"resolve\", Func::from(resolve))?;\n            default.set(\"normalize\", Func::from(normalize::<String>))?;\n            default.set(\"isAbsolute\", Func::from(|s: String| is_absolute(&s)))?;\n            default.prop(\"delimiter\", DELIMITER.to_string())?;\n            default.prop(\"sep\", MAIN_SEPARATOR.to_string())?;\n            Ok(())\n        })\n    }\n}\n\nimpl From<PathModule> for ModuleInfo<PathModule> {\n    fn from(val: PathModule) -> Self {\n        ModuleInfo {\n            name: \"path\",\n            module: val,\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use std::{env::set_current_dir, sync::Mutex};\n\n    static THREAD_LOCK: Lazy<Mutex<()>> = Lazy::new(Mutex::default);\n\n    use once_cell::sync::Lazy;\n\n    use super::*;\n\n    #[test]\n    fn test_relative() {\n        let _shared = THREAD_LOCK.lock().unwrap();\n        let cwd = std::env::current_dir().expect(\"unable to get current working directory\");\n        set_current_dir(\"/\").expect(\"unable to set working directory to /\");\n\n        assert_eq!(\n            relative(\"a/b/c\", \"b/c\").unwrap(),\n            \"../../../b/c\".replace('/', MAIN_SEPARATOR_STR)\n        );\n        assert_eq!(\n            relative(\"/data/orandea/test/aaa\", \"/data/orandea/impl/bbb\").unwrap(),\n            \"../../impl/bbb\".replace('/', MAIN_SEPARATOR_STR)\n        );\n        assert_eq!(\n            relative(\"/a/b/c\", \"/a/d\").unwrap(),\n            \"../../d\".replace('/', MAIN_SEPARATOR_STR)\n        );\n        assert_eq!(relative(\"/a/b/c\", \"/a/b/c/d\").unwrap(), \"d\");\n        assert_eq!(relative(\"/a/b/c\", \"/a/b/c\").unwrap(), \"\");\n\n        assert_eq!(\n            relative(\"a/b\", \"a/b/c/d\").unwrap(),\n            \"c/d\".replace('/', MAIN_SEPARATOR_STR)\n        );\n        assert_eq!(\n            relative(\"a/b/c\", \"b/c\").unwrap(),\n            \"../../../b/c\".replace('/', MAIN_SEPARATOR_STR)\n        );\n\n        set_current_dir(cwd).expect(\"unable to set working directory back\");\n    }\n\n    #[test]\n    fn test_dirname() {\n        assert_eq!(dirname(\"/usr/local/bin\".to_string()), \"/usr/local\");\n        assert_eq!(dirname(\"/usr/local/\".to_string()), \"/usr\");\n        assert_eq!(dirname(\"usr/local/bin\".to_string()), \"usr/local\");\n        assert_eq!(dirname(\"/\".to_string()), \"/\");\n        assert_eq!(dirname(\"\".to_string()), \".\");\n    }\n\n    #[test]\n    fn test_basename() {\n        assert_eq!(basename(\"/usr/local/bin\".to_string(), Opt(None)), \"bin\");\n        assert_eq!(\n            basename(\"/usr/local/bin.txt\".to_string(), Opt(None)),\n            \"bin.txt\"\n        );\n        assert_eq!(\n            basename(\n                \"/usr/local/bin.txt\".to_string(),\n                Opt(Some(\".txt\".to_string()))\n            ),\n            \"bin\"\n        );\n        assert_eq!(basename(\"\".to_string(), Opt(None)), \"\");\n        assert_eq!(basename(\"/\".to_string(), Opt(None)), \"\");\n    }\n\n    #[test]\n    fn test_extname() {\n        assert_eq!(extname(\"/usr/local/bin.txt\".to_string()), \".txt\");\n        assert_eq!(extname(\"/usr/local/bin\".to_string()), \"\");\n        assert_eq!(extname(\"file.tar.gz\".to_string()), \".gz\");\n        assert_eq!(extname(\".bashrc\".to_string()), \"\");\n        assert_eq!(extname(\"\".to_string()), \"\");\n    }\n\n    #[test]\n    fn test_join() {\n        // Standard cases\n        assert_eq!(\n            join_path([\"/usr\", \"local\", \"bin\"].iter()),\n            \"/usr/local/bin\".replace('/', MAIN_SEPARATOR_STR)\n        );\n        assert_eq!(\n            join_path([\"/usr\", \"/local\", \"bin\"].iter()),\n            \"/usr/local/bin\".replace('/', MAIN_SEPARATOR_STR)\n        );\n        assert_eq!(\n            join_path([\"usr\", \"local\", \"bin\"].iter()),\n            \"usr/local/bin\".replace('/', MAIN_SEPARATOR_STR)\n        );\n        assert_eq!(join_path([\"\", \"bin\"].iter()), \"bin\");\n\n        // Complex cases\n        assert_eq!(\n            join_path([\"/usr\", \"..\", \"local\", \"bin\"].iter()),\n            \"/local/bin\".replace('/', MAIN_SEPARATOR_STR)\n        ); // Parent dir\n        assert_eq!(\n            join_path([\".\", \"usr\", \"local\"]),\n            \"usr/local\".replace('/', MAIN_SEPARATOR_STR)\n        ); // Current dir\n        assert_eq!(\n            join_path([\"/usr\", \".\", \"bin\"].iter()),\n            \"/usr/bin\".replace('/', MAIN_SEPARATOR_STR)\n        ); // Current dir in middle\n        assert_eq!(\n            join_path([\"usr\", \"local\", \"bin\", \"..\"].iter()),\n            \"usr/local\".replace('/', MAIN_SEPARATOR_STR)\n        ); // Ending with parent dir\n        assert_eq!(\n            join_path([\"/usr\", \"local\", \"\", \"bin\"].iter()),\n            \"/usr/local/bin\".replace('/', MAIN_SEPARATOR_STR)\n        ); // Empty component in path\n        assert_eq!(\n            join_path([\"/usr\", \"local\", \".hidden\"].iter()),\n            \"/usr/local/.hidden\".replace('/', MAIN_SEPARATOR_STR)\n        ); // Hidden file\n    }\n\n    #[test]\n    fn test_resolve_path() {\n        let _shared = THREAD_LOCK.lock().unwrap();\n        let prefix = if cfg!(windows) {\n            if let Some(Component::Prefix(prefix)) =\n                std::env::current_dir().unwrap().components().next()\n            {\n                prefix.as_os_str().to_str().unwrap().to_string()\n            } else {\n                \"\".into()\n            }\n        } else {\n            \"\".into()\n        };\n\n        assert_eq!(\n            resolve_path([\"\", \"foo/bar\"].iter()).unwrap(),\n            std::env::current_dir()\n                .unwrap()\n                .join(\"foo/bar\".replace('/', MAIN_SEPARATOR_STR))\n                .to_string_lossy()\n                .to_string()\n        );\n\n        // Standard cases\n        assert_eq!(\n            resolve_path([\"/\"].iter()).unwrap(),\n            prefix.clone() + MAIN_SEPARATOR_STR\n        );\n\n        // Standard cases\n        assert_eq!(\n            resolve_path([\"/foo/bar\", \"../baz\"].iter()).unwrap(),\n            prefix.clone() + &\"/foo/baz\".replace('/', MAIN_SEPARATOR_STR)\n        );\n        assert_eq!(\n            resolve_path([\"/foo/bar\", \"./baz\"].iter()).unwrap(),\n            prefix.clone() + &\"/foo/bar/baz\".replace('/', MAIN_SEPARATOR_STR)\n        );\n        assert_eq!(\n            resolve_path([\"foo/bar\", \"/baz\"].iter()).unwrap(),\n            prefix.clone() + &\"/baz\".replace('/', MAIN_SEPARATOR_STR)\n        );\n\n        // Complex cases\n        assert_eq!(\n            resolve_path([\"/foo\", \"bar\", \".\", \"baz\"].iter()).unwrap(),\n            prefix.clone() + &\"/foo/bar/baz\".replace('/', MAIN_SEPARATOR_STR)\n        ); // Current dir in middle\n        assert_eq!(\n            resolve_path([\"/foo\", \"bar\", \"..\", \"baz\"].iter()).unwrap(),\n            prefix.clone() + &\"/foo/baz\".replace('/', MAIN_SEPARATOR_STR)\n        ); // Parent dir in middle\n        assert_eq!(\n            resolve_path([\"/foo\", \"bar\", \"../..\", \"baz\"].iter()).unwrap(),\n            prefix.clone() + &\"/baz\".replace('/', MAIN_SEPARATOR_STR)\n        ); // Double parent dir\n        assert_eq!(\n            resolve_path([\"/foo\", \"bar\", \".hidden\"].iter()).unwrap(),\n            prefix.clone() + &\"/foo/bar/.hidden\".replace('/', MAIN_SEPARATOR_STR)\n        ); // Hidden file\n        assert_eq!(\n            resolve_path([\"/foo\", \".\", \"bar\", \".\"].iter()).unwrap(),\n            prefix.clone() + &\"/foo/bar\".replace('/', MAIN_SEPARATOR_STR)\n        ); // Multiple current dirs\n        assert_eq!(\n            resolve_path([\"/foo\", \"..\", \"..\", \"bar\"].iter()).unwrap(),\n            prefix.clone() + &\"/bar\".replace('/', MAIN_SEPARATOR_STR)\n        ); // Multiple parent dirs\n        assert_eq!(\n            resolve_path([\"/foo/bar\", \"/..\", \"baz\"].iter()).unwrap(),\n            prefix.clone() + &\"/baz\".replace('/', MAIN_SEPARATOR_STR)\n        ); // Parent dir with absolute path\n\n        assert_eq!(\n            resolve_path([\"../foo\"].iter()).unwrap(),\n            std::env::current_dir()\n                .unwrap()\n                .parent()\n                .unwrap()\n                .join(\"foo\".replace('/', MAIN_SEPARATOR_STR))\n                .to_string_lossy()\n                .to_string()\n        ); // Start with ..\n\n        assert_eq!(\n            resolve_path([\"../\".repeat(32)].iter()).unwrap(),\n            prefix.clone()\n        ); // Many ..\n    }\n\n    #[test]\n    fn test_normalize() {\n        assert_eq!(\n            normalize(\"/foo//bar//baz\"),\n            \"/foo/bar/baz\".replace('/', MAIN_SEPARATOR_STR)\n        );\n        assert_eq!(\n            normalize(\"/foo/./bar/../baz\"),\n            \"/foo/baz\".replace('/', MAIN_SEPARATOR_STR)\n        );\n        assert_eq!(\n            normalize(\"foo/bar/\"),\n            \"foo/bar\".replace('/', MAIN_SEPARATOR_STR)\n        );\n        assert_eq!(normalize(\"./foo\"), \"foo\");\n    }\n\n    #[test]\n    fn test_is_absolute() {\n        assert!(is_absolute(\"/usr/local/bin\"));\n        assert!(!is_absolute(\"usr/local/bin\"));\n        #[cfg(windows)]\n        assert!(is_absolute(\"C:\\\\Program Files\")); // for Windows systems\n        assert!(!is_absolute(\"./local/bin\"));\n    }\n\n    #[test]\n    fn test_replace_backslash() {\n        assert_eq!(replace_backslash(\"C:\\\\Program Files\"), \"C:/Program Files\");\n        assert_eq!(replace_backslash(\"/usr/local/bin\"), \"/usr/local/bin\");\n        assert_eq!(replace_backslash(\"C:\\\\Users\\\\User\\\\\"), \"C:/Users/User/\");\n    }\n}\n"
  },
  {
    "path": "modules/llrt_perf_hooks/Cargo.toml",
    "content": "[package]\nname = \"llrt_perf_hooks\"\ndescription = \"LLRT Module perf_hooks\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\nreadme = \"README.md\"\n\n[lib]\nname = \"llrt_perf_hooks\"\npath = \"src/lib.rs\"\n\n[dependencies]\nllrt_events = { version = \"0.8.1-beta\", path = \"../llrt_events\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", default-features = false }\n\n[dev-dependencies]\nllrt_test = { path = \"../../libs/llrt_test\" }\n"
  },
  {
    "path": "modules/llrt_perf_hooks/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_events::Emitter;\nuse llrt_utils::module::{export_default, ModuleInfo};\nuse rquickjs::{\n    module::{Declarations, Exports, ModuleDef},\n    Class, Ctx, Object, Result,\n};\n\nuse crate::performance::Performance;\n\nmod performance;\n\npub struct PerfHooksModule;\n\nimpl ModuleDef for PerfHooksModule {\n    fn declare(declare: &Declarations<'_>) -> Result<()> {\n        declare.declare(\"performance\")?;\n        declare.declare(\"default\")?;\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        export_default(ctx, exports, |default| {\n            let globals = ctx.globals();\n\n            let performance: Object = globals.get(\"performance\")?;\n            default.set(\"performance\", performance)?;\n\n            Ok(())\n        })\n    }\n}\n\nimpl From<PerfHooksModule> for ModuleInfo<PerfHooksModule> {\n    fn from(val: PerfHooksModule) -> Self {\n        ModuleInfo {\n            name: \"perf_hooks\",\n            module: val,\n        }\n    }\n}\n\npub fn init(ctx: &Ctx<'_>) -> Result<()> {\n    let globals = ctx.globals();\n\n    let instance = Class::instance(ctx.clone(), Performance::new())?;\n    Performance::add_event_target_prototype(ctx)?;\n\n    globals.set(\"performance\", instance)?;\n    Ok(())\n}\n\n// #[cfg(test)]\n// mod tests {\n//     use llrt_test::{call_test, test_async_with, ModuleEvaluator};\n//     use rquickjs::CatchResultExt;\n\n//     use super::*;\n\n//     #[tokio::test]\n//     async fn test_now() {\n//         time::init();\n//         test_async_with(|ctx| {\n//             Box::pin(async move {\n//                 ModuleEvaluator::eval_rust::<PerfHooksModule>(ctx.clone(), \"perf_hooks\")\n//                     .await\n//                     .catch(&ctx)\n//                     .unwrap();\n\n//                 let module = ModuleEvaluator::eval_js(\n//                     ctx.clone(),\n//                     \"test\",\n//                     r#\"\n//                         import { performance } from 'perf_hooks';\n\n//                         export async function test() {\n//                             const now = performance.now()\n//                             // TODO: Delaying with setTimeout\n//                             for(let i=0; i < (1<<20); i++){}\n\n//                             return performance.now() - now\n//                         }\n//                     \"#,\n//                 )\n//                 .await\n//                 .unwrap();\n//                 let result = call_test::<u32, _>(&ctx, &module, ()).await;\n//                 assert!(result > 0)\n//             })\n//         })\n//         .await;\n//     }\n\n//     #[tokio::test]\n//     async fn test_time_origin() {\n//         time::init();\n//         test_async_with(|ctx| {\n//             Box::pin(async move {\n//                 ModuleEvaluator::eval_rust::<PerfHooksModule>(ctx.clone(), \"perf_hooks\")\n//                     .await\n//                     .catch(&ctx)\n//                     .unwrap();\n\n//                 let module = ModuleEvaluator::eval_js(\n//                     ctx.clone(),\n//                     \"test\",\n//                     r#\"\n//                         import { performance } from 'perf_hooks';\n\n//                         export async function test() {\n//                             return performance.timeOrigin\n//                         }\n//                     \"#,\n//                 )\n//                 .await\n//                 .catch(&ctx)\n//                 .unwrap();\n//                 let result = call_test::<f64, _>(&ctx, &module, ()).await;\n//                 assert!(result > 0.0);\n//             })\n//         })\n//         .await;\n//     }\n\n//     #[tokio::test]\n//     async fn test_to_json() {\n//         time::init();\n//         test_async_with(|ctx| {\n//             Box::pin(async move {\n//                 ModuleEvaluator::eval_rust::<PerfHooksModule>(ctx.clone(), \"perf_hooks\")\n//                     .await\n//                     .unwrap();\n\n//                 let module = ModuleEvaluator::eval_js(\n//                     ctx.clone(),\n//                     \"test\",\n//                     r#\"\n//                         import { performance } from 'perf_hooks';\n\n//                         export async function test() {\n//                             return performance.toJSON()\n//                         }\n//                     \"#,\n//                 )\n//                 .await\n//                 .unwrap();\n//                 let result = call_test::<Object, _>(&ctx, &module, ()).await;\n//                 let time_origin = result.get::<_, f64>(\"timeOrigin\").unwrap();\n//                 assert!(time_origin > 0.);\n//             })\n//         })\n//         .await;\n//     }\n// }\n"
  },
  {
    "path": "modules/llrt_perf_hooks/src/performance.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::sync::{Arc, RwLock};\n\nuse llrt_events::{Emitter, EventList, Events};\nuse llrt_utils::time;\nuse rquickjs::{\n    atom::PredefinedAtom,\n    class::{Trace, Tracer},\n    Ctx, JsLifetime, Object, Result,\n};\n\n#[rquickjs::class]\n#[derive(Clone)]\npub struct Performance<'js> {\n    pub events: Events<'js>,\n}\n\nunsafe impl<'js> JsLifetime<'js> for Performance<'js> {\n    type Changed<'to> = Performance<'to>;\n}\n\nimpl<'js> Emitter<'js> for Performance<'js> {\n    fn get_event_list(&self) -> Arc<RwLock<EventList<'js>>> {\n        self.events.clone()\n    }\n}\n\nimpl<'js> Trace<'js> for Performance<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.trace_event_emitter(tracer);\n    }\n}\n\nimpl<'js> Default for Performance<'js> {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl<'js> Performance<'js> {\n    #[qjs(constructor)]\n    pub fn new() -> Self {\n        Self {\n            #[allow(clippy::arc_with_non_send_sync)]\n            events: Arc::new(RwLock::new(Vec::new())),\n        }\n    }\n\n    #[qjs(get)]\n    fn time_origin() -> f64 {\n        let time_origin = time::origin_nanos() as f64;\n\n        time_origin / 1e6\n    }\n\n    fn now() -> f64 {\n        let now = time::now_nanos();\n        let started = time::origin_nanos();\n        let elapsed = now.saturating_sub(started);\n\n        (elapsed as f64) / 1e6\n    }\n\n    #[qjs(rename = PredefinedAtom::ToJSON)]\n    fn to_json(ctx: Ctx<'_>) -> Result<Object<'_>> {\n        let obj = Object::new(ctx.clone())?;\n        obj.set(\"timeOrigin\", Self::time_origin())?;\n\n        Ok(obj)\n    }\n}\n"
  },
  {
    "path": "modules/llrt_process/Cargo.toml",
    "content": "[package]\nname = \"llrt_process\"\ndescription = \"LLRT Module process\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[lib]\nname = \"llrt_process\"\npath = \"src/lib.rs\"\n\n[dependencies]\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", features = [\"std\"], default-features = false }\n\n[target.'cfg(unix)'.dependencies]\nlibc = { version = \"0.2\", default-features = false }\n\n[dev-dependencies]\nllrt_test = { path = \"../../libs/llrt_test\" }\ntokio = { version = \"1\", features = [\"test-util\"], default-features = false }\n"
  },
  {
    "path": "modules/llrt_process/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::collections::HashMap;\nuse std::env;\nuse std::sync::atomic::{AtomicU8, Ordering};\n\nuse llrt_utils::signals;\n\nuse llrt_utils::primordials::{BasePrimordials, Primordial};\npub use llrt_utils::sysinfo;\nuse llrt_utils::{\n    module::{export_default, ModuleInfo},\n    object::Proxy,\n    result::ResultExt,\n    sysinfo::{ARCH, PLATFORM},\n    time, VERSION,\n};\nuse rquickjs::Exception;\nuse rquickjs::{\n    convert::Coerced,\n    module::{Declarations, Exports, ModuleDef},\n    object::{Accessor, Property},\n    prelude::Func,\n    Array, BigInt, Ctx, Error, Function, IntoJs, Object, Result, Value,\n};\n\npub static EXIT_CODE: AtomicU8 = AtomicU8::new(0);\n\nfn cwd(ctx: Ctx<'_>) -> Result<String> {\n    env::current_dir()\n        .or_throw(&ctx)\n        .map(|path| path.to_string_lossy().to_string())\n}\n\nfn hr_time_big_int(ctx: Ctx<'_>) -> Result<BigInt<'_>> {\n    let now = time::now_nanos();\n    let started = time::origin_nanos();\n\n    let elapsed = now.saturating_sub(started);\n\n    BigInt::from_u64(ctx, elapsed)\n}\n\nfn hr_time(ctx: Ctx<'_>) -> Result<Array<'_>> {\n    let now = time::now_nanos();\n    let started = time::origin_nanos();\n    let elapsed = now.saturating_sub(started);\n\n    let seconds = elapsed / 1_000_000_000;\n    let remaining_nanos = elapsed % 1_000_000_000;\n\n    let array = Array::new(ctx)?;\n\n    array.set(0, seconds)?;\n    array.set(1, remaining_nanos)?;\n\n    Ok(array)\n}\n\nfn to_exit_code(ctx: &Ctx<'_>, code: &Value<'_>) -> Result<Option<u8>> {\n    if let Ok(code) = code.get::<Coerced<f64>>() {\n        let code = code.0;\n        let code: u8 = if code.fract() != 0.0 {\n            return Err(Exception::throw_range(\n                ctx,\n                \"The value of 'code' must be an integer\",\n            ));\n        } else {\n            (code as i32).rem_euclid(256) as u8\n        };\n        return Ok(Some(code));\n    }\n    Ok(None)\n}\n\nfn exit(ctx: Ctx<'_>, code: Value<'_>) -> Result<()> {\n    let code = match to_exit_code(&ctx, &code)? {\n        Some(code) => code,\n        None => EXIT_CODE.load(Ordering::Relaxed),\n    };\n    std::process::exit(code.into())\n}\n\nfn env_proxy_setter<'js>(\n    target: Object<'js>,\n    prop: Value<'js>,\n    value: Coerced<String>,\n) -> Result<bool> {\n    target.set(prop, value.to_string())?;\n    Ok(true)\n}\n\n#[cfg(unix)]\nfn getuid() -> u32 {\n    unsafe { libc::getuid() }\n}\n\n#[cfg(unix)]\nfn getgid() -> u32 {\n    unsafe { libc::getgid() }\n}\n\n#[cfg(unix)]\nfn geteuid() -> u32 {\n    unsafe { libc::geteuid() }\n}\n\n#[cfg(unix)]\nfn getegid() -> u32 {\n    unsafe { libc::getegid() }\n}\n\n#[cfg(unix)]\nfn setuid(id: u32) -> i32 {\n    unsafe { libc::setuid(id) }\n}\n\n#[cfg(unix)]\nfn setgid(id: u32) -> i32 {\n    unsafe { libc::setgid(id) }\n}\n\n#[cfg(unix)]\nfn seteuid(id: u32) -> i32 {\n    unsafe { libc::seteuid(id) }\n}\n\n#[cfg(unix)]\nfn setegid(id: u32) -> i32 {\n    unsafe { libc::setegid(id) }\n}\n\npub fn init(ctx: &Ctx<'_>) -> Result<()> {\n    let globals = ctx.globals();\n    BasePrimordials::init(ctx)?;\n    let process = Object::new(ctx.clone())?;\n    let process_versions = Object::new(ctx.clone())?;\n    process_versions.set(\"llrt\", VERSION)?;\n    // Node.js version - Set for compatibility with some Node.js packages (e.g. cls-hooked).\n    process_versions.set(\"node\", \"0.0.0\")?;\n\n    let hr_time = Function::new(ctx.clone(), hr_time)?;\n    hr_time.set(\"bigint\", Func::from(hr_time_big_int))?;\n\n    let release = Object::new(ctx.clone())?;\n    release.prop(\"name\", Property::from(\"llrt\").enumerable())?;\n\n    let env_map: HashMap<String, String> = env::vars().collect();\n    let mut args: Vec<String> = env::args().collect();\n\n    if let Some(arg) = args.get(1) {\n        if arg == \"-e\" || arg == \"--eval\" {\n            args.remove(1);\n            args.remove(1);\n        }\n    }\n\n    let env_obj = env_map.into_js(ctx)?;\n\n    let env_proxy = Proxy::with_target(ctx.clone(), env_obj)?;\n    env_proxy.setter(Func::from(env_proxy_setter))?;\n\n    process.set(\"env\", env_proxy)?;\n    process.set(\"cwd\", Func::from(cwd))?;\n    process.set(\"argv0\", args.clone().first().cloned().unwrap_or_default())?;\n    process.set(\"id\", std::process::id())?;\n    process.set(\"argv\", args)?;\n    process.set(\"platform\", PLATFORM)?;\n    process.set(\"arch\", ARCH)?;\n    process.set(\"hrtime\", hr_time)?;\n    process.set(\"release\", release)?;\n    process.set(\"version\", VERSION)?;\n    process.set(\"versions\", process_versions)?;\n\n    process.prop(\n        \"exitCode\",\n        Accessor::new(\n            |ctx| {\n                struct Args<'js>(Ctx<'js>);\n                let Args(ctx) = Args(ctx);\n                ctx.globals().get::<_, Value>(\"__exitCode\")\n            },\n            |ctx, code| {\n                struct Args<'js>(Ctx<'js>, Value<'js>);\n                let Args(ctx, code) = Args(ctx, code);\n                if let Some(code) = to_exit_code(&ctx, &code)? {\n                    EXIT_CODE.store(code, Ordering::Relaxed);\n                }\n                ctx.globals().set(\"__exitCode\", code)?;\n                Ok::<_, Error>(())\n            },\n        )\n        .configurable()\n        .enumerable(),\n    )?;\n    process.set(\"exit\", Func::from(exit))?;\n    process.set(\n        \"kill\",\n        Func::from(|ctx, pid, signal| signals::kill(&ctx, pid, signal)),\n    )?;\n\n    #[cfg(unix)]\n    {\n        process.set(\"getuid\", Func::from(getuid))?;\n        process.set(\"getgid\", Func::from(getgid))?;\n        process.set(\"geteuid\", Func::from(geteuid))?;\n        process.set(\"getegid\", Func::from(getegid))?;\n        process.set(\"setuid\", Func::from(setuid))?;\n        process.set(\"setgid\", Func::from(setgid))?;\n        process.set(\"seteuid\", Func::from(seteuid))?;\n        process.set(\"setegid\", Func::from(setegid))?;\n    }\n\n    globals.set(\"process\", process)?;\n\n    Ok(())\n}\n\npub struct ProcessModule;\n\nimpl ModuleDef for ProcessModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(\"env\")?;\n        declare.declare(\"cwd\")?;\n        declare.declare(\"argv0\")?;\n        declare.declare(\"id\")?;\n        declare.declare(\"argv\")?;\n        declare.declare(\"platform\")?;\n        declare.declare(\"arch\")?;\n        declare.declare(\"hrtime\")?;\n        declare.declare(\"release\")?;\n        declare.declare(\"version\")?;\n        declare.declare(\"versions\")?;\n        declare.declare(\"exitCode\")?;\n        declare.declare(\"exit\")?;\n        declare.declare(\"kill\")?;\n\n        #[cfg(unix)]\n        {\n            declare.declare(\"getuid\")?;\n            declare.declare(\"getgid\")?;\n            declare.declare(\"geteuid\")?;\n            declare.declare(\"getegid\")?;\n            declare.declare(\"setuid\")?;\n            declare.declare(\"setgid\")?;\n            declare.declare(\"seteuid\")?;\n            declare.declare(\"setegid\")?;\n        }\n\n        declare.declare(\"default\")?;\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        let globals = ctx.globals();\n        let process: Object = globals.get(\"process\")?;\n\n        export_default(ctx, exports, |default| {\n            for name in process.keys::<String>() {\n                let name = name?;\n                let value: Value = process.get(&name)?;\n                default.set(name, value)?;\n            }\n\n            Ok(())\n        })?;\n\n        Ok(())\n    }\n}\n\nimpl From<ProcessModule> for ModuleInfo<ProcessModule> {\n    fn from(val: ProcessModule) -> Self {\n        ModuleInfo {\n            name: \"process\",\n            module: val,\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use llrt_test::{call_test, test_async_with, ModuleEvaluator};\n\n    use super::*;\n\n    #[tokio::test]\n    async fn test_hr_time() {\n        time::init();\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<ProcessModule>(ctx.clone(), \"process\")\n                    .await\n                    .unwrap();\n\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { hrtime } from 'process';\n\n                        export async function test() {\n                            // TODO: Delaying with setTimeout\n                            for(let i=0; i < (1<<20); i++){}\n                            return hrtime()\n\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<Vec<u32>, _>(&ctx, &module, ()).await;\n                assert_eq!(result.len(), 2);\n                assert_eq!(result[0], 0);\n                assert!(result[1] > 0);\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_hr_time_bigint() {\n        time::init();\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<ProcessModule>(ctx.clone(), \"process\")\n                    .await\n                    .unwrap();\n\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { hrtime } from 'process';\n\n                        export async function test() {\n                            // TODO: Delaying with setTimeout\n                            for(let i=0; i < (1<<20); i++){}\n                            return hrtime.bigint()\n\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<Coerced<i64>, _>(&ctx, &module, ()).await;\n                assert!(result.0 > 0);\n            })\n        })\n        .await;\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream/Cargo.toml",
    "content": "[package]\nname = \"llrt_stream\"\ndescription = \"LLRT Module stream\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[lib]\nname = \"llrt_stream\"\npath = \"src/lib.rs\"\n\n[dependencies]\nllrt_buffer = { version = \"0.8.1-beta\", path = \"../llrt_buffer\" }\nllrt_context = { version = \"0.8.1-beta\", path = \"../../libs/llrt_context\" }\nllrt_events = { version = \"0.8.1-beta\", path = \"../llrt_events\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", features = [\n  \"bytearray-buffer\",\n], default-features = false }\nrquickjs = { version = \"0.11\", features = [\"std\"], default-features = false }\ntokio = { version = \"1\", features = [\n  \"macros\",\n  \"io-util\",\n], default-features = false }\n"
  },
  {
    "path": "modules/llrt_stream/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::result::Result as StdResult;\n\nuse llrt_events::Emitter;\nuse rquickjs::{prelude::This, Class, Ctx, IntoJs, Result, Value};\nuse tokio::sync::broadcast::error::RecvError;\n\npub mod readable;\npub mod writable;\n\npub fn set_destroyed_and_error<'js>(\n    is_destroyed: &mut bool,\n    error_value: &mut Option<Value<'js>>,\n    error: StdResult<Option<Value<'js>>, RecvError>,\n) {\n    *is_destroyed = true;\n    if let Ok(error) = error {\n        *error_value = error\n    }\n}\nconst DEFAULT_BUFFER_SIZE: usize = 1024 * 16;\n\npub trait SteamEvents<'js>\nwhere\n    Self: Emitter<'js>,\n{\n    fn emit_close(this: Class<'js, Self>, ctx: &Ctx<'js>, had_error: bool) -> Result<()> {\n        Self::emit_str(\n            This(this),\n            ctx,\n            \"close\",\n            vec![had_error.into_js(ctx)?],\n            false,\n        )\n    }\n\n    #[allow(dead_code)]\n    fn emit_end(this: Class<'js, Self>, ctx: &Ctx<'js>) -> Result<()> {\n        Self::emit_str(This(this), ctx, \"end\", vec![], false)\n    }\n}\n\n#[macro_export]\nmacro_rules! impl_stream_events {\n\n    ($($struct:ident),*) => {\n        $(\n            impl<'js> $crate::SteamEvents<'js> for $struct<'js> {}\n        )*\n    };\n}\n"
  },
  {
    "path": "modules/llrt_stream/src/readable.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::sync::{atomic::AtomicUsize, Arc, RwLock};\n\nuse llrt_buffer::Buffer;\nuse llrt_context::CtxExtension;\nuse llrt_events::{EmitError, Emitter, EventEmitter, EventKey, EventList};\nuse llrt_utils::{bytearray_buffer::BytearrayBuffer, result::ResultExt};\nuse rquickjs::{\n    class::{Trace, Tracer},\n    prelude::{Func, Opt, This},\n    Class, Ctx, Error, IntoJs, JsLifetime, Null, Result, Value,\n};\nuse tokio::{\n    io::{AsyncRead, AsyncReadExt, BufReader},\n    sync::{\n        broadcast::{self, Sender},\n        oneshot::Receiver,\n    },\n};\n\nuse super::{impl_stream_events, set_destroyed_and_error, SteamEvents, DEFAULT_BUFFER_SIZE};\n\n#[derive(PartialEq, Clone, Debug)]\npub enum ReadableState {\n    Init,\n    Flowing,\n    Paused,\n}\n\n#[allow(dead_code)]\npub struct ReadableStreamInner<'js> {\n    emitter: EventEmitter<'js>,\n    destroy_tx: Sender<Option<Value<'js>>>,\n    is_ended: bool,\n    is_destroyed: bool,\n    errored: bool,\n    buffer: BytearrayBuffer,\n    emit_close: bool,\n    state: ReadableState,\n    high_water_mark: AtomicUsize,\n    listener: Option<&'static str>,\n    data_listener_attached_tx: Sender<()>,\n}\n\nimpl<'js> Trace<'js> for ReadableStreamInner<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.emitter.trace(tracer);\n    }\n}\n\nimpl<'js> ReadableStreamInner<'js> {\n    pub fn on_event_changed(&mut self, event: EventKey<'js>, added: bool) -> Result<()> {\n        if let EventKey::String(event) = event {\n            match event.as_ref() {\n                \"data\" => {\n                    if added {\n                        if self.state == ReadableState::Paused {\n                            let _ = self.data_listener_attached_tx.send(());\n                        }\n                        self.state = ReadableState::Flowing;\n                        self.listener = Some(\"data\");\n                    } else {\n                        self.listener = None;\n                    }\n                },\n                \"readable\" => {\n                    if added {\n                        self.state = ReadableState::Paused;\n                        self.listener = Some(\"readable\");\n                    } else {\n                        self.listener = None;\n                    }\n                },\n                _ => {},\n            }\n        }\n        Ok(())\n    }\n\n    pub fn new(emitter: EventEmitter<'js>, emit_close: bool) -> Self {\n        let (destroy_tx, _) = broadcast::channel::<Option<Value<'js>>>(1);\n        let (listener_attached_tx, _) = broadcast::channel::<()>(1);\n        Self {\n            emitter,\n            destroy_tx,\n            is_ended: false,\n            data_listener_attached_tx: listener_attached_tx,\n            buffer: BytearrayBuffer::new(DEFAULT_BUFFER_SIZE),\n            state: ReadableState::Init,\n            high_water_mark: DEFAULT_BUFFER_SIZE.into(),\n            listener: None,\n            is_destroyed: false,\n            emit_close,\n            errored: false,\n        }\n    }\n}\n\n#[rquickjs::class]\n#[derive(rquickjs::class::Trace)]\npub struct DefaultReadableStream<'js> {\n    inner: ReadableStreamInner<'js>,\n}\n\nunsafe impl<'js> JsLifetime<'js> for DefaultReadableStream<'js> {\n    type Changed<'to> = DefaultReadableStream<'to>;\n}\n\nimpl<'js> DefaultReadableStream<'js> {\n    fn with_emitter(ctx: Ctx<'js>, emitter: EventEmitter<'js>) -> Result<Class<'js, Self>> {\n        Class::instance(\n            ctx,\n            Self {\n                inner: ReadableStreamInner::new(emitter, true),\n            },\n        )\n    }\n\n    pub fn new(ctx: Ctx<'js>) -> Result<Class<'js, Self>> {\n        Self::with_emitter(ctx, EventEmitter::new())\n    }\n}\n\nimpl_stream_events!(DefaultReadableStream);\nimpl<'js> Emitter<'js> for DefaultReadableStream<'js> {\n    fn get_event_list(&self) -> Arc<RwLock<EventList<'js>>> {\n        self.inner.emitter.get_event_list()\n    }\n\n    fn on_event_changed(&mut self, event: EventKey<'js>, added: bool) -> Result<()> {\n        self.inner.on_event_changed(event, added)\n    }\n}\nimpl<'js> ReadableStream<'js> for DefaultReadableStream<'js> {\n    fn inner_mut(&mut self) -> &mut ReadableStreamInner<'js> {\n        &mut self.inner\n    }\n\n    fn inner(&self) -> &ReadableStreamInner<'js> {\n        &self.inner\n    }\n}\n\npub trait ReadableStream<'js>\nwhere\n    Self: Emitter<'js> + SteamEvents<'js>,\n{\n    fn inner_mut(&mut self) -> &mut ReadableStreamInner<'js>;\n\n    fn inner(&self) -> &ReadableStreamInner<'js>;\n\n    fn add_readable_stream_prototype(ctx: &Ctx<'js>) -> Result<()> {\n        let proto = Class::<Self>::prototype(ctx)?\n            .or_throw_msg(ctx, &[\"Prototype for \", Self::NAME, \" not found\"].concat())?;\n\n        proto.set(\"read\", Func::from(Self::read))?;\n\n        proto.set(\"destroy\", Func::from(Self::destroy))?;\n\n        Ok(())\n    }\n\n    fn destroy(this: This<Class<'js, Self>>, error: Opt<Value<'js>>) -> Class<'js, Self> {\n        let mut borrow = this.borrow_mut();\n        let inner = borrow.inner_mut();\n        inner.is_destroyed = true;\n        let _ = inner.destroy_tx.send(error.0);\n        drop(borrow);\n        this.0\n    }\n\n    fn read(this: This<Class<'js, Self>>, ctx: Ctx<'js>, size: Opt<usize>) -> Result<Value<'js>> {\n        if let Some(data) = this.borrow().inner().buffer.read(size.0) {\n            return Buffer(data).into_js(&ctx);\n        }\n\n        Ok(Null.into_value(ctx))\n    }\n\n    fn drain(this: Class<'js, Self>, ctx: &Ctx<'js>) -> Result<()> {\n        let this2 = this.clone();\n        let borrow = this2.borrow();\n        let inner = borrow.inner();\n        let listener = inner.listener;\n\n        if let Some(listener) = listener {\n            let ba_buffer = inner.buffer.clone();\n            if !ba_buffer.is_empty() {\n                drop(borrow);\n                let args = match listener {\n                    \"data\" => {\n                        let buffer = ba_buffer.read(None).unwrap_or_default();\n                        if buffer.is_empty() {\n                            return Ok(());\n                        }\n                        vec![Buffer(buffer).into_js(ctx)?]\n                    },\n                    \"readable\" => {\n                        vec![]\n                    },\n                    _ => {\n                        vec![]\n                    },\n                };\n                Self::emit_str(This(this), ctx, listener, args, false)?;\n            }\n        }\n        Ok(())\n    }\n\n    fn process<T: AsyncRead + 'js + Unpin>(\n        this: Class<'js, Self>,\n        ctx: &Ctx<'js>,\n        readable: T,\n    ) -> Result<Receiver<bool>> {\n        Self::do_process(this, ctx, readable, || {})\n    }\n\n    fn process_callback<T: AsyncRead + 'js + Unpin, C: FnOnce() + Sized + 'js>(\n        this: Class<'js, Self>,\n        ctx: &Ctx<'js>,\n        readable: T,\n        on_end: C,\n    ) -> Result<Receiver<bool>> {\n        Self::do_process(this, ctx, readable, on_end)\n    }\n\n    fn do_process<T: AsyncRead + 'js + Unpin, C: FnOnce() + Sized + 'js>(\n        this: Class<'js, Self>,\n        ctx: &Ctx<'js>,\n        readable: T,\n        on_end: C,\n    ) -> Result<Receiver<bool>> {\n        let ctx2 = ctx.clone();\n        ctx.spawn_exit(async move {\n            let this2 = this.clone();\n            let ctx3 = ctx2.clone();\n\n            let borrow = this2.borrow();\n            let inner = borrow.inner();\n            let mut destroy_rx = inner.destroy_tx.subscribe();\n            let is_ended = inner.is_ended;\n            let mut is_destroyed = inner.is_destroyed;\n            let emit_close = inner.emit_close;\n\n            let mut listener_attached_tx = inner.data_listener_attached_tx.subscribe();\n            let ba_buffer = inner.buffer.clone();\n            let mut has_data = false;\n            drop(borrow);\n\n            let read_function = async move {\n                let mut reader: BufReader<T> = BufReader::new(readable);\n                let mut buffer = Vec::<u8>::with_capacity(DEFAULT_BUFFER_SIZE);\n                let mut last_state = ReadableState::Init;\n                let mut error_value = None;\n\n                if !is_ended && !is_destroyed {\n                    loop {\n                        tokio::select! {\n                            result = reader.read_buf(&mut buffer) => {\n                                let bytes_read = result.or_throw(&ctx3)?;\n\n                                let mut state = this2.borrow().inner().state.clone();\n                                if !has_data && state == ReadableState::Init {\n                                    this2.borrow_mut().inner_mut().state = ReadableState::Paused;\n                                    state =  ReadableState::Paused;\n                                    has_data = true;\n                                }\n\n                                match state {\n                                    ReadableState::Flowing => {\n                                        if last_state == ReadableState::Paused {\n                                            if let Some(empty_buffer) = ba_buffer.read(None) {\n                                                buffer.extend(empty_buffer);\n                                            }\n                                        }\n\n                                        if buffer.is_empty() {\n                                            break;\n                                        }\n\n                                        Self::emit_str(\n                                            This(this2.clone()),\n                                            &ctx3,\n                                            \"data\",\n                                            vec![Buffer(buffer.clone()).into_js(&ctx3)?],\n                                            false\n                                        )?;\n                                        buffer.clear();\n                                    },\n                                    ReadableState::Paused => {\n\n                                        if bytes_read == 0 {\n                                            break;\n                                        }\n\n                                        let write_buffer_future = ba_buffer.write(&mut buffer);\n                                        Self::emit_str(\n                                            This(this2.clone()),\n                                            &ctx3,\n                                            \"readable\",\n                                            vec![],\n                                            false\n                                        )?;\n                                        tokio::select!{\n                                            capacity = write_buffer_future => {\n                                                buffer.clear();\n                                                //increase buffer capacity if bytearray buffer has more capacity to reduce read syscalls\n                                                buffer.reserve(buffer.capacity()-capacity);\n                                            }\n                                            error = destroy_rx.recv()  => {\n                                                set_destroyed_and_error(&mut is_destroyed,  &mut error_value, error);\n                                                break;\n                                            }\n                                            _ = listener_attached_tx.recv() => {\n                                                ba_buffer.clear().await\n                                                //don't clear buffer\n                                            }\n                                        }\n                                    },\n                                    _ => {\n                                        //should not happen\n                                    }\n                                }\n\n                                last_state = state;\n\n\n                            }\n                            error = destroy_rx.recv()  => {\n                                set_destroyed_and_error(&mut is_destroyed,  &mut error_value, error);\n                                break;\n                            },\n                        }\n                    }\n                }\n\n                let mut borrow = this2.borrow_mut();\n                let inner = borrow.inner_mut();\n                inner.buffer.close().await;\n                if is_destroyed {\n                    inner.is_destroyed = true;\n                } else {\n                    inner.is_ended = true;\n                }\n\n                drop(borrow);\n                drop(reader);\n\n                if !is_destroyed {\n                    on_end();\n                    Self::emit_str(This(this2), &ctx3, \"end\", vec![], false)?;\n                }\n\n                if let Some(error_value) = error_value{\n                    return Err(ctx3.throw(error_value));\n                }\n\n                Ok::<_, Error>(())\n            }\n            .await;\n\n            let had_error = read_function.emit_error(\"readable\",&ctx2, this.clone())?;\n\n            if emit_close {\n                Self::emit_close(this,&ctx2,had_error)?;\n            }\n\n            Ok::<_, Error>(had_error)\n        })\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream/src/writable.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::sync::{Arc, RwLock};\n\nuse llrt_context::CtxExtension;\nuse llrt_events::{EmitError, Emitter, EventEmitter, EventList};\nuse llrt_utils::{bytes::ObjectBytes, error::ErrorExtensions, result::ResultExt};\nuse rquickjs::{\n    class::{Trace, Tracer},\n    prelude::{Func, Opt, This},\n    Class, Ctx, Error, Exception, Function, JsLifetime, Result, Value,\n};\nuse tokio::{\n    io::{AsyncWrite, AsyncWriteExt, BufWriter},\n    sync::{\n        broadcast::{self, Sender},\n        mpsc::{self, UnboundedReceiver, UnboundedSender},\n        oneshot::Receiver,\n    },\n};\n\nuse super::{impl_stream_events, set_destroyed_and_error, SteamEvents};\n\npub struct WritableStreamInner<'js> {\n    emitter: EventEmitter<'js>,\n    command_tx: UnboundedSender<WriteCommand<'js>>,\n    command_rx: Option<UnboundedReceiver<WriteCommand<'js>>>,\n    is_finished: bool,\n    #[allow(dead_code)]\n    errored: bool,\n    emit_close: bool,\n    is_destroyed: bool,\n    destroy_tx: Sender<Option<Value<'js>>>,\n}\n\nimpl<'js> Trace<'js> for WritableStreamInner<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.emitter.trace(tracer);\n    }\n}\n\nimpl<'js> WritableStreamInner<'js> {\n    pub fn new(emitter: EventEmitter<'js>, emit_close: bool) -> Self {\n        let (tx, rx) = mpsc::unbounded_channel();\n\n        let (destroy_tx, _) = broadcast::channel::<Option<Value<'js>>>(1);\n\n        Self {\n            command_tx: tx,\n            command_rx: Some(rx),\n            emitter,\n            is_finished: false,\n            is_destroyed: false,\n            destroy_tx,\n            emit_close,\n            errored: false,\n        }\n    }\n}\n\n#[derive(Debug)]\n#[allow(dead_code)]\npub enum WriteCommand<'js> {\n    End,\n    Write(Value<'js>, Option<Function<'js>>, bool),\n    Flush,\n}\n\n#[rquickjs::class]\n#[derive(rquickjs::class::Trace)]\npub struct DefaultWritableStream<'js> {\n    inner: WritableStreamInner<'js>,\n}\n\nunsafe impl<'js> JsLifetime<'js> for DefaultWritableStream<'js> {\n    type Changed<'to> = DefaultWritableStream<'to>;\n}\n\nimpl<'js> DefaultWritableStream<'js> {\n    fn with_emitter(ctx: Ctx<'js>, emitter: EventEmitter<'js>) -> Result<Class<'js, Self>> {\n        Class::instance(\n            ctx,\n            Self {\n                inner: WritableStreamInner::new(emitter, true),\n            },\n        )\n    }\n\n    pub fn new(ctx: Ctx<'js>) -> Result<Class<'js, Self>> {\n        Self::with_emitter(ctx, EventEmitter::new())\n    }\n}\n\nimpl_stream_events!(DefaultWritableStream);\nimpl<'js> Emitter<'js> for DefaultWritableStream<'js> {\n    fn get_event_list(&self) -> Arc<RwLock<EventList<'js>>> {\n        self.inner.emitter.get_event_list()\n    }\n}\n\nimpl<'js> WritableStream<'js> for DefaultWritableStream<'js> {\n    fn inner_mut(&mut self) -> &mut WritableStreamInner<'js> {\n        &mut self.inner\n    }\n\n    fn inner(&self) -> &WritableStreamInner<'js> {\n        &self.inner\n    }\n}\n\npub trait WritableStream<'js>\nwhere\n    Self: Emitter<'js> + SteamEvents<'js>,\n{\n    fn inner_mut(&mut self) -> &mut WritableStreamInner<'js>;\n\n    fn inner(&self) -> &WritableStreamInner<'js>;\n\n    fn add_writable_stream_prototype(ctx: &Ctx<'js>) -> Result<()> {\n        let proto = Class::<Self>::prototype(ctx)?\n            .or_throw_msg(ctx, &[\"Prototype for \", Self::NAME, \" not found\"].concat())?;\n\n        proto.set(\"write\", Func::from(Self::write))?;\n\n        proto.set(\"end\", Func::from(Self::end))?;\n\n        Ok(())\n    }\n\n    fn destroy(this: This<Class<'js, Self>>, error: Opt<Value<'js>>) -> Class<'js, Self> {\n        if !this.borrow().inner().is_finished {\n            let mut borrow = this.borrow_mut();\n            let inner = borrow.inner_mut();\n            inner.is_finished = true;\n            inner.is_destroyed = true;\n            let tx = inner.destroy_tx.clone();\n            drop(borrow);\n            //it doesn't matter if channel is closed because then writable is already closed\n            let _ = tx.send(error.0);\n        }\n        this.0\n    }\n\n    fn end(this: This<Class<'js, Self>>) -> Class<'js, Self> {\n        if !this.borrow().inner().is_finished {\n            let mut borrow = this.borrow_mut();\n            let inner = borrow.inner_mut();\n            inner.is_finished = true;\n            let tx = inner.command_tx.clone();\n            drop(borrow);\n            //it doesn't matter if channel is closed because then writable is already closed\n            let _ = tx.send(WriteCommand::End);\n        }\n        this.0\n    }\n\n    #[allow(dead_code)]\n    fn flush(this: Class<'js, Self>, ctx: &Ctx<'js>) -> Result<()> {\n        let _ = this\n            .borrow()\n            .inner()\n            .command_tx\n            .send(WriteCommand::Flush)\n            .or_throw(ctx);\n        Ok(())\n    }\n\n    fn write_flushed(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        value: Value<'js>,\n        cb: Opt<Function<'js>>,\n    ) -> Result<()> {\n        Self::do_write(this, ctx, value, cb, true)\n    }\n\n    fn write(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        value: Value<'js>,\n        cb: Opt<Function<'js>>,\n    ) -> Result<()> {\n        Self::do_write(this, ctx, value, cb, false)\n    }\n\n    fn do_write(\n        this: This<Class<'js, Self>>,\n        ctx: Ctx<'js>,\n        value: Value<'js>,\n        cb: Opt<Function<'js>>,\n        flush: bool,\n    ) -> Result<()> {\n        let callback = cb.0;\n\n        if this\n            .borrow()\n            .inner()\n            .command_tx\n            .send(WriteCommand::Write(value, callback.clone(), flush))\n            .is_err()\n        {\n            if let Some(cb) = callback {\n                let err = Exception::throw_message(&ctx, \"This stream has been ended\")\n                    .into_value(&ctx)?;\n\n                () = cb.call((err,))?;\n            }\n        }\n\n        Ok(())\n    }\n\n    fn process<T: AsyncWrite + 'js + Unpin>(\n        this: Class<'js, Self>,\n        ctx: &Ctx<'js>,\n        writable: T,\n    ) -> Result<Receiver<bool>> {\n        let mut borrow = this.borrow_mut();\n        let inner = borrow.inner_mut();\n        let is_ended = inner.is_finished;\n        let mut is_destroyed = inner.is_destroyed;\n        let emit_close = inner.emit_close;\n        let mut command_rx = inner\n            .command_rx\n            .take()\n            .expect(\"rx from writable process already taken!\");\n        let mut destroy_rx = inner.destroy_tx.subscribe();\n        let mut error_value = None;\n\n        drop(borrow);\n        let ctx2 = ctx.clone();\n\n        ctx.spawn_exit(async move {\n            let ctx3 = ctx2.clone();\n            let ctx4 = ctx2.clone();\n            let this2 = this.clone();\n            let write_function = async move {\n                let mut writer = BufWriter::new(writable);\n\n                if !is_ended && !is_destroyed {\n                    loop {\n                        tokio::select! {\n                            command = command_rx.recv() => {\n                                 match command {\n                                    Some(WriteCommand::Write(value, cb, flush)) => {\n                                        let bytes = ObjectBytes::from(&ctx3, &value)?;\n                                        let data = bytes.as_bytes(&ctx4)?;\n                                        let result = async {\n                                            writer.write_all(data).await?;\n                                            if flush {\n                                                writer.flush().await.or_throw(&ctx3)?;\n                                            }\n                                            Ok::<_, Error>(())\n                                        }.await;\n\n                                        match result {\n                                            Ok(_) => {\n                                                if let Some(cb) = cb {\n                                                    () = cb.call(())?;\n                                                }\n                                            },\n                                            Err(err) => {\n                                                let err2 = Exception::throw_message(&ctx3, &err.to_string());\n                                                if let Some(cb) = cb {\n                                                    let err = err.into_value(&ctx3)?;\n                                                    () = cb.call((err,))?;\n                                                }\n                                                return Err(err2);\n                                            }\n                                        }\n                                    },\n                                    Some(WriteCommand::End) => {\n                                        writer.shutdown().await.or_throw(&ctx3)?;\n                                        break;\n                                    },\n                                    Some(WriteCommand::Flush) => writer.flush().await.or_throw(&ctx3)?,\n                                    None => break,\n                                }\n                            },\n                            error = destroy_rx.recv() => {\n                                set_destroyed_and_error(&mut is_destroyed,  &mut error_value, error);\n                                break;\n                            }\n                        }\n                    }\n                }\n\n                drop(writer);\n\n                if !is_destroyed {\n                    Self::emit_str(This(this2), &ctx3, \"finish\", vec![], false)?;\n                }\n\n                if let Some(error_value) = error_value{\n                    return Err(ctx3.throw(error_value));\n                }\n\n                Ok::<_, Error>(())\n            }\n            .await;\n\n            let had_error = write_function.emit_error(\"writable\", &ctx2, this.clone())?;\n\n            if emit_close {\n                Self::emit_close(this,&ctx2,had_error)?;\n            }\n\n            Ok::<_, Error>(had_error)\n        })\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/Cargo.toml",
    "content": "[package]\nname = \"llrt_stream_web\"\ndescription = \"LLRT Module stream/web\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[lib]\nname = \"llrt_stream_web\"\npath = \"src/lib.rs\"\n\n[dependencies]\nllrt_abort = { version = \"0.8.1-beta\", path = \"../llrt_abort\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", default-features = false }\n\n[dev-dependencies]\nllrt_test = { path = \"../../libs/llrt_test\" }\ntokio = { version = \"1\", features = [\"test-util\"], default-features = false }\n"
  },
  {
    "path": "modules/llrt_stream_web/src/lib.rs",
    "content": "use llrt_utils::{\n    module::{export_default, ModuleInfo},\n    primordials::{BasePrimordials, Primordial},\n};\nuse queuing_strategy::{ByteLengthQueuingStrategy, CountQueuingStrategy};\nuse readable::{\n    ReadableByteStreamController, ReadableStream, ReadableStreamBYOBReader,\n    ReadableStreamBYOBRequest, ReadableStreamDefaultController, ReadableStreamDefaultReader,\n};\nuse rquickjs::{\n    module::{Declarations, Exports, ModuleDef},\n    Class, Ctx, Result,\n};\nuse writable::{WritableStream, WritableStreamDefaultController, WritableStreamDefaultWriter};\n\nuse crate::{\n    readable::{ArrayConstructorPrimordials, IteratorPrimordials},\n    utils::promise::PromisePrimordials,\n    writable::WritableStreamDefaultControllerPrimordials,\n};\n\nmod queuing_strategy;\nmod readable;\nmod readable_writable_pair;\nmod utils;\nmod writable;\n\n/// Defines web streams, which are exposed through the \"stream/web\" Node import, but also at the global scope\n/// Web streams consist of Readable, Writable, and Transform streams. Transform is currently unimplemented.\n///\n/// https://developer.mozilla.org/en-US/docs/Web/API/Streams_API\n///\n/// # ReadableStream\n/// ReadableStream knows how to 'pull' objects or bytes from an underlying source, generally a user-defined function or an [async] iterator.\n/// A source enqueues data to the stream via a controller, either ReadableStreamDefaultController or a ReadableByteStreamController optionally for byte data.\n/// The controller is created at stream initialisation and cannot change.\n///\n/// Data is read from the stream using a reader, which is obtained using stream.getReader(). A reader 'locks' the stream for reading, preventing\n/// other readers from being created. When a reader is released with `reader.releaseLock()`, the stream goes back to having no reader and a new one can be created.\n/// In the case of ReadableByteStreamController, a special reader ReadableStreamBYOBReader may be used, which allows users to provide their own\n/// buffer to fill bytes into when reading. Otherwise, ReadableStreamDefaultReader is used by default, and this may also be used with byte streams.\n///\n/// A ReadableStream can be 'tee'd', which splits it into two readable streams which both read the same underlying data, potentially at different\n/// paces. This is an area of substantial complexity for the implementation, particularly in the case of byte streams as the alternative reader types\n/// must be handled correctly.\n///\n/// # WritableStream\n/// WritableStream knows how to 'push' objects into an underlying sink, generally a user-defined function. It has no special casing for bytes, and so\n/// only has one type of controller, WritableStreamDefaultController, and only one type of writer WritableStreamDefaultWriter. The controller is only needed for\n/// error handling because writes are signalled via a function call to a user-defined 'write' method which receives the chunk directly.\n///\n/// Data is written to the stream using a WritableStreamDefaultWriter, which is obtained using stream.getWriter(). A writer 'locks' the stream for writing,\n/// preventing other writers from being created. When a writer is released with `writer.releaseLock()`, the stream goes back to having no writer and a new one can be created.\npub struct StreamWebModule;\n\n// https://nodejs.org/api/webstreams.html\nimpl ModuleDef for StreamWebModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(stringify!(ReadableStream))?;\n        declare.declare(stringify!(ReadableStreamDefaultReader))?;\n        declare.declare(stringify!(ReadableStreamBYOBReader))?;\n        declare.declare(stringify!(ReadableStreamDefaultController))?;\n        declare.declare(stringify!(ReadableByteStreamController))?;\n        declare.declare(stringify!(ReadableStreamBYOBRequest))?;\n\n        declare.declare(stringify!(WritableStream))?;\n        declare.declare(stringify!(WritableStreamDefaultWriter))?;\n        declare.declare(stringify!(WritableStreamDefaultController))?;\n\n        declare.declare(stringify!(ByteLengthQueuingStrategy))?;\n        declare.declare(stringify!(CountQueuingStrategy))?;\n\n        declare.declare(\"default\")?;\n        Ok(())\n    }\n\n    #[inline]\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        export_default(ctx, exports, |default| {\n            Class::<ReadableStream>::define(default)?;\n            Class::<ReadableStreamDefaultReader>::define(default)?;\n            Class::<ReadableStreamBYOBReader>::define(default)?;\n            Class::<ReadableStreamDefaultController>::define(default)?;\n            Class::<ReadableByteStreamController>::define(default)?;\n            Class::<ReadableStreamBYOBRequest>::define(default)?;\n\n            Class::<WritableStream>::define(default)?;\n            Class::<WritableStreamDefaultWriter>::define(default)?;\n            Class::<WritableStreamDefaultController>::define(default)?;\n\n            Class::<ByteLengthQueuingStrategy>::define(default)?;\n            Class::<CountQueuingStrategy>::define(default)?;\n\n            Ok(())\n        })?;\n\n        Ok(())\n    }\n}\n\nimpl From<StreamWebModule> for ModuleInfo<StreamWebModule> {\n    fn from(val: StreamWebModule) -> Self {\n        ModuleInfo {\n            name: \"stream/web\",\n            module: val,\n        }\n    }\n}\n\npub fn init(ctx: &Ctx) -> Result<()> {\n    let globals = &ctx.globals();\n\n    BasePrimordials::init(ctx)?;\n    PromisePrimordials::init(ctx)?;\n    ArrayConstructorPrimordials::init(ctx)?;\n    WritableStreamDefaultControllerPrimordials::init(ctx)?;\n    IteratorPrimordials::init(ctx)?;\n\n    // https://min-common-api.proposal.wintertc.org/#api-index\n    Class::<ByteLengthQueuingStrategy>::define(globals)?;\n    Class::<CountQueuingStrategy>::define(globals)?;\n\n    Class::<ReadableByteStreamController>::define(globals)?;\n    Class::<ReadableStream>::define(globals)?;\n    Class::<ReadableStreamBYOBReader>::define(globals)?;\n    Class::<ReadableStreamBYOBRequest>::define(globals)?;\n    Class::<ReadableStreamDefaultController>::define(globals)?;\n    Class::<ReadableStreamDefaultReader>::define(globals)?;\n\n    Class::<WritableStream>::define(globals)?;\n    Class::<WritableStreamDefaultController>::define(globals)?;\n\n    // This is exposed globally by Node even though its not in the min-common-api\n    Class::<WritableStreamDefaultWriter>::define(globals)?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/queuing_strategy/byte_length.rs",
    "content": "use rquickjs::{class::Trace, methods, Class, Ctx, JsLifetime, Result};\n\nuse super::{NativeSizeFunction, QueueingStrategyInit};\n\n#[derive(JsLifetime, Trace)]\n#[rquickjs::class]\npub(crate) struct ByteLengthQueuingStrategy<'js> {\n    high_water_mark: f64,\n    size: Class<'js, NativeSizeFunction>,\n}\n\n#[methods(rename_all = \"camelCase\")]\nimpl<'js> ByteLengthQueuingStrategy<'js> {\n    #[qjs(constructor)]\n    pub(crate) fn new(ctx: Ctx<'js>, init: QueueingStrategyInit) -> Result<Self> {\n        // Set this.[[highWaterMark]] to init[\"highWaterMark\"].\n        Ok(Self {\n            high_water_mark: init.high_water_mark,\n            size: Class::instance(ctx, NativeSizeFunction::ByteLength)?,\n        })\n    }\n\n    // readonly attribute Function size;\n    // size is an attribute, not a method, so this function is not itself the size function, but instead returns one\n    #[qjs(get)]\n    pub(crate) fn size(&self) -> Class<'js, NativeSizeFunction> {\n        self.size.clone()\n    }\n\n    // readonly attribute unrestricted double highWaterMark;\n    #[qjs(get)]\n    pub(crate) fn high_water_mark(&self) -> f64 {\n        self.high_water_mark\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/queuing_strategy/count.rs",
    "content": "use rquickjs::{class::Trace, methods, Class, Ctx, JsLifetime, Result};\n\nuse super::{NativeSizeFunction, QueueingStrategyInit};\n\n#[derive(JsLifetime, Trace)]\n#[rquickjs::class]\npub(crate) struct CountQueuingStrategy<'js> {\n    high_water_mark: f64,\n    size: Class<'js, NativeSizeFunction>,\n}\n\n#[methods(rename_all = \"camelCase\")]\nimpl<'js> CountQueuingStrategy<'js> {\n    #[qjs(constructor)]\n    pub(crate) fn new(ctx: Ctx<'js>, init: QueueingStrategyInit) -> Result<Self> {\n        // Set this.[[highWaterMark]] to init[\"highWaterMark\"].\n        Ok(Self {\n            high_water_mark: init.high_water_mark,\n            size: Class::instance(ctx, NativeSizeFunction::Count)?,\n        })\n    }\n\n    // readonly attribute Function size;\n    // size is an attribute, not a method, so this function is not itself the size function, but instead returns one\n    #[qjs(get)]\n    pub(crate) fn size(&self) -> Class<'js, NativeSizeFunction> {\n        self.size.clone()\n    }\n\n    // readonly attribute unrestricted double highWaterMark;\n    #[qjs(get)]\n    pub(crate) fn high_water_mark(&self) -> f64 {\n        self.high_water_mark\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/queuing_strategy/mod.rs",
    "content": "use rquickjs::{\n    class::{JsCell, JsClass, Readable, Trace},\n    function::{Constructor, Params},\n    Class, Ctx, Error, Exception, FromJs, Function, JsLifetime, Object, Result, Value,\n};\n\npub(crate) use byte_length::ByteLengthQueuingStrategy;\npub(crate) use count::CountQueuingStrategy;\n\nuse crate::utils::ValueOrUndefined;\n\nmod byte_length;\nmod count;\n\n/// QueuingStrategy is the structure of a user-provided object describing how backpressure should be signalled.\n/// https://streams.spec.whatwg.org/#qs-api\npub(super) struct QueuingStrategy<'js> {\n    // unrestricted double highWaterMark;\n    high_water_mark: Option<Value<'js>>,\n    // callback QueuingStrategySize = unrestricted double (any chunk);\n    pub(super) size: Option<SizeFunction<'js>>,\n}\n\nimpl<'js> FromJs<'js> for QueuingStrategy<'js> {\n    fn from_js(_ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        let ty_name = value.type_name();\n        let obj = value\n            .as_object()\n            .ok_or_else(|| Error::new_from_js(ty_name, \"Object\"))?;\n\n        let high_water_mark = obj.get_value_or_undefined::<_, Value>(\"highWaterMark\")?;\n        let size = obj.get_value_or_undefined::<_, _>(\"size\")?;\n\n        Ok(Self {\n            high_water_mark,\n            size,\n        })\n    }\n}\n\nimpl<'js> QueuingStrategy<'js> {\n    // https://streams.spec.whatwg.org/#validate-and-normalize-high-water-mark\n    pub(super) fn extract_high_water_mark(\n        ctx: &Ctx<'js>,\n        this: Option<Self>,\n        default_hwm: f64,\n    ) -> Result<f64> {\n        match this {\n            // If strategy[\"highWaterMark\"] does not exist, return defaultHWM.\n            None => Ok(default_hwm),\n            // Let highWaterMark be strategy[\"highWaterMark\"].\n            Some(Self {\n                high_water_mark: Some(high_water_mark),\n                ..\n            }) => {\n                let high_water_mark = high_water_mark.as_number().unwrap_or(f64::NAN);\n                // If highWaterMark is NaN or highWaterMark < 0, throw a RangeError exception.\n                if high_water_mark.is_nan() || high_water_mark < 0.0 {\n                    Err(Exception::throw_range(ctx, \"Invalid highWaterMark\"))\n                } else {\n                    // Return highWaterMark.\n                    Ok(high_water_mark)\n                }\n            },\n\n            // If strategy[\"highWaterMark\"] does not exist, return defaultHWM.\n            _ => Ok(default_hwm),\n        }\n    }\n\n    // https://streams.spec.whatwg.org/#make-size-algorithm-from-size-function\n    pub(super) fn extract_size_algorithm(this: Option<&Self>) -> SizeAlgorithm<'js> {\n        // If strategy[\"size\"] does not exist, return an algorithm that returns 1.\n        match this.as_ref().and_then(|t| t.size.as_ref()) {\n            None => SizeAlgorithm::AlwaysOne,\n            Some(size) => SizeAlgorithm::SizeFunction(size.clone()),\n        }\n    }\n}\n\n/// SizeAlgorithm represents the two ways we might generate sizes - by calling a function or by simply returning 1.0 (the default)\n#[derive(JsLifetime, Trace, Clone)]\npub(super) enum SizeAlgorithm<'js> {\n    AlwaysOne,\n    SizeFunction(SizeFunction<'js>),\n}\n\nimpl<'js> SizeAlgorithm<'js> {\n    pub(super) fn call(&self, ctx: Ctx<'js>, chunk: Value<'js>) -> Result<SizeValue<'js>> {\n        match self {\n            Self::AlwaysOne\n            | Self::SizeFunction(SizeFunction::Native(NativeSizeFunction::Count)) => {\n                Ok(SizeValue::Native(1.0))\n            },\n            Self::SizeFunction(SizeFunction::Js(ref f)) => f.call((chunk.clone(),)),\n            Self::SizeFunction(SizeFunction::Native(NativeSizeFunction::ByteLength)) => {\n                let size = byte_length_queueing_strategy_size_function(&ctx, &chunk)?;\n                SizeValue::from_js(&ctx, size)\n            },\n        }\n    }\n}\n\n/// SizeValue abstracts over the sources of size values - they can either come from user-provided size functions, in which case they might\n/// be any Value, or (more often) they come from a NativeSizeFunction or the default AlwaysOne algorithm and we can pass around a native Rust type.\npub(super) enum SizeValue<'js> {\n    Value(Value<'js>),\n    Native(f64),\n}\n\nimpl SizeValue<'_> {\n    pub(super) fn as_number(&self) -> Option<f64> {\n        match self {\n            Self::Value(value) => value.as_number(),\n            Self::Native(size) => Some(*size),\n        }\n    }\n}\n\nimpl<'js> FromJs<'js> for SizeValue<'js> {\n    fn from_js(_: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        if let Some(size) = value.as_number() {\n            return Ok(Self::Native(size));\n        }\n\n        Ok(Self::Value(value))\n    }\n}\n\n/// SizeFunction abstracts over user-provided size functions (from their own queuing strategy implementations) and ones provided by us.\n/// We want to be able to recognise the ones that we have provided so we can short-circuit expensive JS calls\n#[derive(JsLifetime, Trace, Clone)]\npub(super) enum SizeFunction<'js> {\n    Js(Function<'js>),\n    Native(NativeSizeFunction),\n}\n\nimpl<'js> FromJs<'js> for SizeFunction<'js> {\n    fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        if let Ok(nsf) = Class::<NativeSizeFunction>::from_value(&value) {\n            return Ok(SizeFunction::Native(*nsf.borrow()));\n        }\n\n        Ok(SizeFunction::Js(Function::from_js(ctx, value)?))\n    }\n}\n\n/// QueueingStrategyInit is the dictionary of input parameters for both native queuing strategies\n/// https://streams.spec.whatwg.org/#dictdef-queuingstrategyinit\npub(crate) struct QueueingStrategyInit {\n    high_water_mark: f64,\n}\n\nimpl<'js> FromJs<'js> for QueueingStrategyInit {\n    fn from_js(_ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        let ty_name = value.type_name();\n        let obj = value\n            .as_object()\n            .ok_or_else(|| Error::new_from_js(ty_name, \"Object\"))?;\n\n        let high_water_mark = obj\n            .get_value_or_undefined(\"highWaterMark\")?\n            .ok_or_else(|| Error::new_from_js(ty_name, \"QueueingStrategyInit\"))?;\n\n        Ok(Self { high_water_mark })\n    }\n}\n\n/// NativeSizeFunction is a callable class which allows us to keep track that these size functions are not user provided, but\n/// in fact represent the native size functions. This allows us to avoid JS calls by noticing that a size function is this class.\n#[derive(JsLifetime, Trace, Clone, Copy)]\npub(super) enum NativeSizeFunction {\n    ByteLength,\n    Count,\n}\n\nimpl<'js> JsClass<'js> for NativeSizeFunction {\n    const NAME: &'static str = \"NativeSizeFunction\";\n\n    const CALLABLE: bool = true;\n\n    type Mutable = Readable;\n\n    fn prototype(ctx: &Ctx<'js>) -> Result<Option<Object<'js>>> {\n        Ok(Some(Function::prototype(ctx.clone())))\n    }\n\n    fn constructor(_ctx: &Ctx<'js>) -> Result<Option<Constructor<'js>>> {\n        Ok(None)\n    }\n\n    fn call<'a>(this: &JsCell<'js, Self>, params: Params<'a, 'js>) -> Result<Value<'js>> {\n        match &*this.borrow() {\n            NativeSizeFunction::Count => Ok(Value::new_int(params.ctx().clone(), 1)),\n            NativeSizeFunction::ByteLength => {\n                let Some(chunk) = params.arg(0) else {\n                    return Err(Exception::throw_type(\n                        params.ctx(),\n                        \"ByteLengthQueuingStrategy expects an argument 'chunk'\",\n                    ));\n                };\n\n                byte_length_queueing_strategy_size_function(params.ctx(), &chunk)\n            },\n        }\n    }\n}\n\nfn byte_length_queueing_strategy_size_function<'js>(\n    ctx: &Ctx<'js>,\n    chunk: &Value<'js>,\n) -> Result<Value<'js>> {\n    if let Some(chunk) = chunk.as_object() {\n        chunk.get(\"byteLength\")\n    } else {\n        Err(Exception::throw_type(\n            ctx,\n            \"ByteLengthQueuingStrategy argument 'chunk' must be an object\",\n        ))\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/readable/byob_reader.rs",
    "content": "use std::collections::VecDeque;\n\nuse llrt_utils::{bytes::ObjectBytes, primordials::Primordial};\nuse rquickjs::{\n    atom::PredefinedAtom,\n    class::{JsClass, OwnedBorrowMut, Trace, Tracer},\n    function::Constructor,\n    methods,\n    prelude::{Opt, This},\n    ArrayBuffer, Class, Ctx, Error, Exception, FromJs, Function, IntoJs, JsLifetime, Object,\n    Promise, Result, Value,\n};\n\nuse crate::{\n    readable::{\n        byte_controller::ReadableByteStreamController,\n        controller::{ReadableStreamController, ReadableStreamControllerClass},\n        default_reader::{ReadableStreamDefaultReaderOwned, ReadableStreamReadResult},\n        objects::{ReadableStreamBYOBObjects, ReadableStreamObjects},\n        reader::{ReadableStreamGenericReader, ReadableStreamReader, ReadableStreamReaderOwned},\n        stream::{ReadableStreamOwned, ReadableStreamState},\n    },\n    utils::{\n        promise::{promise_rejected_with_constructor, with_promise_result, ResolveablePromise},\n        UnwrapOrUndefined, ValueOrUndefined,\n    },\n};\n\n#[derive(Trace)]\n#[rquickjs::class]\npub(crate) struct ReadableStreamBYOBReader<'js> {\n    pub(super) generic: ReadableStreamGenericReader<'js>,\n    pub(super) read_into_requests: VecDeque<Box<dyn ReadableStreamReadIntoRequest<'js> + 'js>>,\n}\n\npub(crate) type ReadableStreamBYOBReaderClass<'js> = Class<'js, ReadableStreamBYOBReader<'js>>;\npub(crate) type ReadableStreamBYOBReaderOwned<'js> =\n    OwnedBorrowMut<'js, ReadableStreamBYOBReader<'js>>;\n\nunsafe impl<'js> JsLifetime<'js> for ReadableStreamBYOBReader<'js> {\n    type Changed<'to> = ReadableStreamBYOBReader<'to>;\n}\n\nimpl<'js> ReadableStreamBYOBReader<'js> {\n    pub(super) fn readable_stream_byob_reader_error_read_into_requests(\n        mut objects: ReadableStreamBYOBObjects<'js>,\n        e: Value<'js>,\n    ) -> Result<ReadableStreamBYOBObjects<'js>> {\n        // Let readIntoRequests be reader.[[readIntoRequests]].\n        let read_into_requests = &mut objects.reader.read_into_requests;\n\n        // Set reader.[[readIntoRequests]] to a new empty list.\n        let read_into_requests = read_into_requests.split_off(0);\n        // For each readIntoRequest of readIntoRequests,\n        for read_into_request in read_into_requests {\n            // Perform readIntoRequest’s error steps, given e.\n            objects = read_into_request.error_steps(objects, e.clone())?;\n        }\n\n        Ok(objects)\n    }\n\n    pub(super) fn set_up_readable_stream_byob_reader(\n        ctx: Ctx<'js>,\n        stream: ReadableStreamOwned<'js>,\n    ) -> Result<(ReadableStreamOwned<'js>, Class<'js, Self>)> {\n        // If ! IsReadableStreamLocked(stream) is true, throw a TypeError exception.\n        if stream.is_readable_stream_locked() {\n            return Err(Exception::throw_type(\n                &ctx,\n                \"This stream has already been locked for exclusive reading by another reader\",\n            ));\n        }\n\n        // If stream.[[controller]] does not implement ReadableByteStreamController, throw a TypeError exception.\n        match stream.controller {\n            ReadableStreamControllerClass::ReadableStreamByteController(_) => {},\n            _ => {\n                return Err(Exception::throw_type(\n                    &ctx,\n                    \"Cannot construct a ReadableStreamBYOBReader for a stream not constructed with a byte source\",\n                ));\n            },\n        };\n\n        // Perform ! ReadableStreamReaderGenericInitialize(reader, stream).\n        let generic =\n            ReadableStreamGenericReader::readable_stream_reader_generic_initialize(&ctx, stream)?;\n\n        let mut stream = OwnedBorrowMut::from_class(generic.stream.clone().unwrap());\n\n        let reader = Class::instance(\n            ctx.clone(),\n            Self {\n                generic,\n                // Set reader.[[readIntoRequests]] to a new empty list.\n                read_into_requests: VecDeque::new(),\n            },\n        )?;\n\n        stream.reader = Some(reader.clone().into());\n\n        Ok((stream, reader))\n    }\n\n    pub(super) fn readable_stream_byob_reader_release(\n        mut objects: ReadableStreamBYOBObjects<'js>,\n    ) -> Result<ReadableStreamBYOBObjects<'js>> {\n        // Perform ! ReadableStreamReaderGenericRelease(reader).\n        objects\n            .reader\n            .generic\n            .readable_stream_reader_generic_release(&mut objects.stream, || {\n                objects.controller.release_steps()\n            })?;\n\n        // Let e be a new TypeError exception.\n        let e: Value = objects\n            .stream\n            .constructor_type_error\n            .call((\"Reader was released\",))?;\n        // Perform ! ReadableStreamBYOBReaderErrorReadIntoRequests(reader, e).\n        Self::readable_stream_byob_reader_error_read_into_requests(objects, e)\n    }\n\n    pub(super) fn readable_stream_byob_reader_read(\n        ctx: &Ctx<'js>,\n        // Let stream be reader.[[stream]].\n        mut objects: ReadableStreamBYOBObjects<'js>,\n        view: ViewBytes<'js>,\n        min: u64,\n        read_into_request: impl ReadableStreamReadIntoRequest<'js> + 'js,\n    ) -> Result<ReadableStreamBYOBObjects<'js>> {\n        // Set stream.[[disturbed]] to true.\n        objects.stream.disturbed = true;\n\n        // If stream.[[state]] is \"errored\", perform readIntoRequest’s error steps given stream.[[storedError]].\n        if let ReadableStreamState::Errored(ref stored_error) = objects.stream.state {\n            let stored_error = stored_error.clone();\n            read_into_request.error_steps(objects, stored_error)\n        } else {\n            // Otherwise, perform ! ReadableByteStreamControllerPullInto(stream.[[controller]], view, min, readIntoRequest).\n            ReadableByteStreamController::readable_byte_stream_controller_pull_into(\n                ctx,\n                objects,\n                view,\n                min,\n                read_into_request,\n            )\n        }\n    }\n}\n\n#[methods(rename_all = \"camelCase\")]\nimpl<'js> ReadableStreamBYOBReader<'js> {\n    // this is required by web platform tests\n    #[qjs(get)]\n    pub fn constructor(ctx: Ctx<'js>) -> Result<Option<Constructor<'js>>> {\n        <ReadableStreamBYOBReader as JsClass>::constructor(&ctx)\n    }\n\n    #[qjs(constructor)]\n    pub fn new(ctx: Ctx<'js>, stream: ReadableStreamOwned<'js>) -> Result<Class<'js, Self>> {\n        // Perform ? SetUpReadableStreamBYOBReader(this, stream).\n        let (_, reader) = Self::set_up_readable_stream_byob_reader(ctx, stream)?;\n        Ok(reader)\n    }\n\n    fn read(\n        ctx: Ctx<'js>,\n        reader: This<OwnedBorrowMut<'js, Self>>,\n        view: Opt<Value<'js>>,\n        options: Opt<Value<'js>>,\n    ) -> Result<Promise<'js>> {\n        with_promise_result(&ctx, || {\n            let options = match options.0 {\n                None => ReadableStreamBYOBReaderReadOptions { min: 1 },\n                Some(value) => ReadableStreamBYOBReaderReadOptions::from_js(&ctx, value)?,\n            };\n\n            let view = ViewBytes::from_value(\n                &ctx,\n                &reader.generic.function_array_buffer_is_view,\n                view.0.as_ref(),\n            )?;\n\n            let (buffer, byte_length, _) = view.get_array_buffer()?;\n\n            // If view.[[ByteLength]] is 0, return a promise rejected with a TypeError exception.\n            if byte_length == 0 {\n                return promise_rejected_with_constructor(\n                    &reader.generic.constructor_type_error,\n                    &reader.generic.promise_primordials,\n                    \"view must have non-zero byteLength\",\n                );\n            }\n\n            // If view.[[ViewedArrayBuffer]].[[ArrayBufferByteLength]] is 0, return a promise rejected with a TypeError exception.\n            if buffer.is_empty() {\n                return promise_rejected_with_constructor(\n                    &reader.generic.constructor_type_error,\n                    &reader.generic.promise_primordials,\n                    \"view's buffer must have non-zero byteLength\",\n                );\n            }\n\n            // If ! IsDetachedBuffer(view.[[ViewedArrayBuffer]]) is true, return a promise rejected with a TypeError exception.\n            if buffer.as_bytes().is_none() {\n                return promise_rejected_with_constructor(\n                    &reader.generic.constructor_type_error,\n                    &reader.generic.promise_primordials,\n                    \"view's buffer has been detached\",\n                );\n            }\n\n            // If options[\"min\"] is 0, return a promise rejected with a TypeError exception.\n            if options.min == 0 {\n                return promise_rejected_with_constructor(\n                    &reader.generic.constructor_type_error,\n                    &reader.generic.promise_primordials,\n                    \"options.min must be greater than 0\",\n                );\n            }\n\n            // If view has a [[TypedArrayName]] internal slot,\n            let typed_array_len = match &view.0 {\n                ObjectBytes::U8Array(a) => Some(a.len()),\n                ObjectBytes::I8Array(a) => Some(a.len()),\n                ObjectBytes::U16Array(a) => Some(a.len()),\n                ObjectBytes::I16Array(a) => Some(a.len()),\n                ObjectBytes::U32Array(a) => Some(a.len()),\n                ObjectBytes::I32Array(a) => Some(a.len()),\n                ObjectBytes::U64Array(a) => Some(a.len()),\n                ObjectBytes::I64Array(a) => Some(a.len()),\n                ObjectBytes::F32Array(a) => Some(a.len()),\n                ObjectBytes::F64Array(a) => Some(a.len()),\n                _ => None,\n            };\n            if let Some(typed_array_len) = typed_array_len {\n                // If options[\"min\"] > view.[[ArrayLength]], return a promise rejected with a RangeError exception.\n                if options.min > typed_array_len as u64 {\n                    return promise_rejected_with_constructor(\n                        &reader.generic.constructor_range_error,\n                        &reader.generic.promise_primordials,\n                        \"options.min must be less than or equal to views length\",\n                    );\n                }\n            } else {\n                // Otherwise (i.e., it is a DataView),\n                // If options[\"min\"] > view.[[ByteLength]], return a promise rejected with a RangeError exception.\n                if options.min > byte_length as u64 {\n                    return promise_rejected_with_constructor(\n                        &reader.generic.constructor_range_error,\n                        &reader.generic.promise_primordials,\n                        \"options.min must be less than or equal to views byteLength\",\n                    );\n                }\n            }\n\n            // If this.[[stream]] is undefined, return a promise rejected with a TypeError exception.\n            if reader.generic.stream.is_none() {\n                return promise_rejected_with_constructor(\n                    &reader.generic.constructor_type_error,\n                    &reader.generic.promise_primordials,\n                    \"Cannot read a stream using a released reader\",\n                );\n            }\n\n            // Let promise be a new promise.\n            let promise = ResolveablePromise::new(&ctx)?;\n            // Let readIntoRequest be a new read-into request with the following items:\n            #[derive(Trace)]\n            struct ReadIntoRequest<'js> {\n                promise: ResolveablePromise<'js>,\n            }\n\n            impl<'js> ReadableStreamReadIntoRequest<'js> for ReadIntoRequest<'js> {\n                // chunk steps, given chunk\n                // Resolve promise with «[ \"value\" → chunk, \"done\" → false ]».\n                fn chunk_steps(\n                    &self,\n                    objects: ReadableStreamBYOBObjects<'js>,\n                    chunk: Value<'js>,\n                ) -> Result<ReadableStreamBYOBObjects<'js>> {\n                    self.promise.resolve(ReadableStreamReadResult {\n                        value: Some(chunk),\n                        done: false,\n                    })?;\n                    Ok(objects)\n                }\n\n                // close steps, given chunk\n                // Resolve promise with «[ \"value\" → chunk, \"done\" → true ]».\n                fn close_steps(\n                    &self,\n                    objects: ReadableStreamBYOBObjects<'js>,\n                    chunk: Value<'js>,\n                ) -> Result<ReadableStreamBYOBObjects<'js>> {\n                    self.promise.resolve(ReadableStreamReadResult {\n                        value: Some(chunk),\n                        done: true,\n                    })?;\n                    Ok(objects)\n                }\n\n                // error steps, given e\n                // Reject promise with e.\n                fn error_steps(\n                    &self,\n                    objects: ReadableStreamBYOBObjects<'js>,\n                    reason: Value<'js>,\n                ) -> Result<ReadableStreamBYOBObjects<'js>> {\n                    self.promise.reject(reason)?;\n                    Ok(objects)\n                }\n            }\n\n            let objects = ReadableStreamObjects::from_byob_reader(reader.0);\n\n            // Perform ! ReadableStreamBYOBReaderRead(this, view, options[\"min\"], readIntoRequest).\n            Self::readable_stream_byob_reader_read(\n                &ctx,\n                objects,\n                view,\n                options.min,\n                ReadIntoRequest {\n                    promise: promise.clone(),\n                },\n            )?;\n\n            // Return promise.\n            Ok(promise.promise)\n        })\n    }\n\n    fn release_lock(reader: This<OwnedBorrowMut<'js, Self>>) -> Result<()> {\n        // If this.[[stream]] is undefined, return.\n        if reader.generic.stream.is_none() {\n            return Ok(());\n        };\n\n        let objects = ReadableStreamObjects::from_byob_reader(reader.0);\n\n        // Perform ! ReadableStreamBYOBReaderRelease(this).\n        Self::readable_stream_byob_reader_release(objects)?;\n\n        Ok(())\n    }\n\n    #[qjs(get)]\n    fn closed(&self) -> Promise<'js> {\n        self.generic.closed_promise.promise.clone()\n    }\n\n    fn cancel(\n        ctx: Ctx<'js>,\n        reader: This<OwnedBorrowMut<'js, Self>>,\n        reason: Opt<Value<'js>>,\n    ) -> Result<Promise<'js>> {\n        if reader.generic.stream.is_none() {\n            // If this.[[stream]] is undefined, return a promise rejected with a TypeError exception.\n            return promise_rejected_with_constructor(\n                &reader.generic.constructor_type_error,\n                &reader.generic.promise_primordials,\n                \"Cannot cancel a stream using a released reader\",\n            );\n        }\n\n        let objects = ReadableStreamObjects::from_byob_reader(reader.0);\n\n        // Return ! ReadableStreamReaderGenericCancel(this, reason).\n        let (promise, _) = ReadableStreamGenericReader::readable_stream_reader_generic_cancel(\n            ctx.clone(),\n            objects,\n            reason.0.unwrap_or_undefined(&ctx),\n        )?;\n        Ok(promise)\n    }\n}\n\nstruct ReadableStreamBYOBReaderReadOptions {\n    min: u64,\n}\n\nimpl<'js> FromJs<'js> for ReadableStreamBYOBReaderReadOptions {\n    fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        let ty_name = value.type_name();\n        let obj = value\n            .as_object()\n            .ok_or(Error::new_from_js(ty_name, \"Object\"))?;\n\n        let min = obj.get_value_or_undefined::<_, f64>(\"min\")?.unwrap_or(1.0);\n        if min < u64::MIN as f64 || min > u64::MAX as f64 {\n            return Err(Exception::throw_type(\n                ctx,\n                \"min on ReadableStreamBYOBReaderReadOptions must fit into unsigned long long\",\n            ));\n        };\n\n        Ok(Self { min: min as u64 })\n    }\n}\n\npub(super) trait ReadableStreamReadIntoRequest<'js>: Trace<'js> {\n    fn chunk_steps(\n        &self,\n        objects: ReadableStreamBYOBObjects<'js>,\n        chunk: Value<'js>,\n    ) -> Result<ReadableStreamBYOBObjects<'js>>;\n\n    fn close_steps(\n        &self,\n        objects: ReadableStreamBYOBObjects<'js>,\n        chunk: Value<'js>,\n    ) -> Result<ReadableStreamBYOBObjects<'js>>;\n\n    fn error_steps(\n        &self,\n        objects: ReadableStreamBYOBObjects<'js>,\n        reason: Value<'js>,\n    ) -> Result<ReadableStreamBYOBObjects<'js>>;\n}\n\nimpl<'js> Trace<'js> for Box<dyn ReadableStreamReadIntoRequest<'js> + 'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.as_ref().trace(tracer);\n    }\n}\n\n#[derive(JsLifetime, Clone)]\npub(super) struct ViewBytes<'js>(ObjectBytes<'js>);\n\nimpl<'js> ViewBytes<'js> {\n    pub(super) fn from_object(\n        ctx: &Ctx<'js>,\n        function_array_buffer_is_view: &Function<'js>,\n        object: &Object<'js>,\n    ) -> Result<Self> {\n        if function_array_buffer_is_view.call::<_, bool>((object.clone(),))? {\n            if let Some(view) = ObjectBytes::from_array_buffer(object)? {\n                return Ok(Self(view));\n            }\n        }\n\n        Err(Exception::throw_type(\n            ctx,\n            \"view must be an ArrayBufferView\",\n        ))\n    }\n\n    pub(super) fn from_value(\n        ctx: &Ctx<'js>,\n        function_array_buffer_is_view: &Function<'js>,\n        value: Option<&Value<'js>>,\n    ) -> Result<Self> {\n        match value.and_then(Value::as_object) {\n            None => {\n                Err(Exception::throw_type(\n                    ctx,\n                    \"view must be typed DataView, Buffer, ArrayBuffer, or Uint8Array, but is not an object\",\n                ))\n            },\n            Some(object) => Self::from_object(ctx, function_array_buffer_is_view, object),\n        }\n    }\n\n    pub(super) fn get_array_buffer(&self) -> Result<(ArrayBuffer<'js>, usize, usize)> {\n        Ok(self\n            .0\n            .get_array_buffer()?\n            .expect(\"invariant broken; ViewBytes may not contain ObjectBytes::Vec\"))\n    }\n\n    pub(super) fn element_size(&self) -> usize {\n        match self.0 {\n            ObjectBytes::U8Array(_) => 1,\n            ObjectBytes::I8Array(_) => 1,\n            ObjectBytes::U16Array(_) => 2,\n            ObjectBytes::I16Array(_) => 2,\n            ObjectBytes::U32Array(_) => 4,\n            ObjectBytes::I32Array(_) => 4,\n            ObjectBytes::U64Array(_) => 8,\n            ObjectBytes::I64Array(_) => 8,\n            ObjectBytes::F32Array(_) => 4,\n            ObjectBytes::F64Array(_) => 8,\n            ObjectBytes::DataView(_) => 1,\n            ObjectBytes::Vec(_) => {\n                panic!(\"invariant broken; ViewBytes may not contain ObjectBytes::Vec\")\n            },\n        }\n    }\n}\n\n#[derive(Clone, JsLifetime)]\npub(crate) struct ArrayConstructorPrimordials<'js> {\n    pub(super) constructor_uint8array: Constructor<'js>,\n    constructor_int8array: Constructor<'js>,\n    constructor_uint16array: Constructor<'js>,\n    constructor_int16array: Constructor<'js>,\n    constructor_uint32array: Constructor<'js>,\n    constructor_int32array: Constructor<'js>,\n    constructor_uint64array: Constructor<'js>,\n    constructor_int64array: Constructor<'js>,\n    constructor_f32array: Constructor<'js>,\n    constructor_f64array: Constructor<'js>,\n    constructor_data_view: Constructor<'js>,\n}\n\nimpl<'js> Trace<'js> for ArrayConstructorPrimordials<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.constructor_uint8array.trace(tracer);\n        self.constructor_int8array.trace(tracer);\n        self.constructor_uint16array.trace(tracer);\n        self.constructor_int16array.trace(tracer);\n        self.constructor_uint32array.trace(tracer);\n        self.constructor_int32array.trace(tracer);\n        self.constructor_uint64array.trace(tracer);\n        self.constructor_int64array.trace(tracer);\n        self.constructor_f32array.trace(tracer);\n        self.constructor_f64array.trace(tracer);\n        self.constructor_data_view.trace(tracer);\n    }\n}\n\nimpl<'js> Primordial<'js> for ArrayConstructorPrimordials<'js> {\n    fn new(ctx: &Ctx<'js>) -> Result<Self>\n    where\n        Self: Sized,\n    {\n        let globals = ctx.globals();\n        Ok(Self {\n            constructor_uint8array: globals.get(PredefinedAtom::Uint8Array)?,\n            constructor_int8array: globals.get(PredefinedAtom::Int8Array)?,\n            constructor_uint16array: globals.get(PredefinedAtom::Uint16Array)?,\n            constructor_int16array: globals.get(PredefinedAtom::Int16Array)?,\n            constructor_uint32array: globals.get(PredefinedAtom::Uint32Array)?,\n            constructor_int32array: globals.get(PredefinedAtom::Int32Array)?,\n            constructor_uint64array: globals.get(PredefinedAtom::BigUint64Array)?,\n            constructor_int64array: globals.get(PredefinedAtom::BigInt64Array)?,\n            constructor_f32array: globals.get(PredefinedAtom::Float32Array)?,\n            constructor_f64array: globals.get(PredefinedAtom::Float64Array)?,\n            constructor_data_view: globals.get(PredefinedAtom::DataView)?,\n        })\n    }\n}\n\nimpl<'js> ArrayConstructorPrimordials<'js> {\n    pub(super) fn for_view_bytes(&self, v: &ViewBytes<'js>) -> Constructor<'js> {\n        match v.0 {\n            ObjectBytes::U8Array(_) => self.constructor_uint8array.clone(),\n            ObjectBytes::I8Array(_) => self.constructor_int8array.clone(),\n            ObjectBytes::U16Array(_) => self.constructor_uint16array.clone(),\n            ObjectBytes::I16Array(_) => self.constructor_int16array.clone(),\n            ObjectBytes::U32Array(_) => self.constructor_uint32array.clone(),\n            ObjectBytes::I32Array(_) => self.constructor_int32array.clone(),\n            ObjectBytes::U64Array(_) => self.constructor_uint64array.clone(),\n            ObjectBytes::I64Array(_) => self.constructor_int64array.clone(),\n            ObjectBytes::F32Array(_) => self.constructor_f32array.clone(),\n            ObjectBytes::F64Array(_) => self.constructor_f64array.clone(),\n            ObjectBytes::DataView(_) => self.constructor_data_view.clone(),\n            ObjectBytes::Vec(_) => {\n                panic!(\"invariant broken; ViewBytes may not contain ObjectBytes::Vec\")\n            },\n        }\n    }\n}\n\nimpl<'js> Trace<'js> for ViewBytes<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.0.trace(tracer);\n    }\n}\n\nimpl<'js> IntoJs<'js> for ViewBytes<'js> {\n    fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {\n        self.0.into_js(ctx)\n    }\n}\n\nimpl<'js> ReadableStreamReader<'js> for ReadableStreamBYOBReaderOwned<'js> {\n    type Class = ReadableStreamBYOBReaderClass<'js>;\n\n    fn with_reader<C>(\n        self,\n        ctx: C,\n        _: impl FnOnce(\n            C,\n            ReadableStreamDefaultReaderOwned<'js>,\n        ) -> Result<(C, ReadableStreamDefaultReaderOwned<'js>)>,\n        byob: impl FnOnce(\n            C,\n            ReadableStreamBYOBReaderOwned<'js>,\n        ) -> Result<(C, ReadableStreamBYOBReaderOwned<'js>)>,\n        _: impl FnOnce(C) -> Result<C>,\n    ) -> Result<(C, Self)> {\n        byob(ctx, self)\n    }\n\n    fn into_inner(self) -> Self::Class {\n        self.into_inner()\n    }\n\n    fn from_class(class: Self::Class) -> Self {\n        OwnedBorrowMut::from_class(class)\n    }\n\n    fn try_from_erased(erased: Option<ReadableStreamReaderOwned<'js>>) -> Option<Self> {\n        match erased {\n            Some(ReadableStreamReaderOwned::ReadableStreamBYOBReader(r)) => Some(r),\n            _ => None,\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/readable/byte_controller.rs",
    "content": "use std::collections::VecDeque;\n\nuse llrt_utils::{\n    error_messages::ERROR_MSG_ARRAY_BUFFER_DETACHED,\n    option::{Null, Undefined},\n    primordials::{BasePrimordials, Primordial},\n    result::ResultExt,\n};\nuse rquickjs::{\n    class::{OwnedBorrow, OwnedBorrowMut, Trace, Tracer},\n    function::Constructor,\n    methods,\n    prelude::{Opt, This},\n    ArrayBuffer, Class, Ctx, Error, Exception, Function, IntoJs, JsLifetime, Object, Promise,\n    Result, TypedArray, Value,\n};\n\nuse crate::{\n    readable::{\n        byob_reader::{ArrayConstructorPrimordials, ReadableStreamReadIntoRequest, ViewBytes},\n        controller::{\n            ReadableStreamController, ReadableStreamControllerClass, ReadableStreamControllerOwned,\n        },\n        default_controller::ReadableStreamDefaultControllerOwned,\n        default_reader::ReadableStreamReadRequest,\n        objects::{\n            ReadableByteStreamObjects, ReadableStreamBYOBObjects, ReadableStreamClassObjects,\n            ReadableStreamDefaultReaderObjects, ReadableStreamObjects,\n        },\n        reader::ReadableStreamReader,\n        stream::{\n            algorithms::{CancelAlgorithm, PullAlgorithm, StartAlgorithm},\n            source::UnderlyingSource,\n            ReadableStream, ReadableStreamClass, ReadableStreamOwned, ReadableStreamState,\n        },\n    },\n    utils::{\n        class_from_owned_borrow_mut,\n        promise::{promise_resolved_with, upon_promise},\n        UnwrapOrUndefined,\n    },\n};\n\n#[derive(JsLifetime)]\n#[rquickjs::class]\npub(crate) struct ReadableByteStreamController<'js> {\n    auto_allocate_chunk_size: Option<usize>,\n    #[qjs(get)]\n    byob_request: Option<Class<'js, ReadableStreamBYOBRequest<'js>>>,\n    cancel_algorithm: Option<CancelAlgorithm<'js>>,\n    close_requested: bool,\n    pull_again: bool,\n    pull_algorithm: Option<PullAlgorithm<'js>>,\n    pulling: bool,\n    pub(super) pending_pull_intos: VecDeque<PullIntoDescriptor<'js>>,\n    queue: VecDeque<ReadableByteStreamQueueEntry<'js>>,\n    queue_total_size: usize,\n    started: bool,\n    strategy_hwm: f64,\n    pub(super) stream: ReadableStreamClass<'js>,\n\n    pub(super) array_constructor_primordials: ArrayConstructorPrimordials<'js>,\n    constructor_array_buffer: Constructor<'js>,\n    pub(super) function_array_buffer_is_view: Function<'js>,\n}\n\nimpl<'js> Trace<'js> for ReadableByteStreamController<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.auto_allocate_chunk_size.trace(tracer);\n        self.byob_request.trace(tracer);\n        self.cancel_algorithm.trace(tracer);\n        self.pull_algorithm.trace(tracer);\n        self.pending_pull_intos.trace(tracer);\n        self.queue.trace(tracer);\n        self.queue_total_size.trace(tracer);\n        self.started.trace(tracer);\n        self.strategy_hwm.trace(tracer);\n        self.stream.trace(tracer);\n        self.array_constructor_primordials.trace(tracer);\n        self.constructor_array_buffer.trace(tracer);\n        self.function_array_buffer_is_view.trace(tracer);\n    }\n}\n\npub(crate) type ReadableByteStreamControllerClass<'js> =\n    Class<'js, ReadableByteStreamController<'js>>;\npub(crate) type ReadableByteStreamControllerOwned<'js> =\n    OwnedBorrowMut<'js, ReadableByteStreamController<'js>>;\n\nimpl<'js> ReadableByteStreamController<'js> {\n    // SetUpReadableByteStreamControllerFromUnderlyingSource\n    pub(super) fn set_up_readable_byte_stream_controller_from_underlying_source(\n        ctx: &Ctx<'js>,\n        stream: ReadableStreamOwned<'js>,\n        underlying_source: Null<Undefined<Object<'js>>>,\n        underlying_source_dict: UnderlyingSource<'js>,\n        high_water_mark: f64,\n    ) -> Result<()> {\n        let (start_algorithm, pull_algorithm, cancel_algorithm, auto_allocate_chunk_size) = (\n            // If underlyingSourceDict[\"start\"] exists, then set startAlgorithm to an algorithm which returns the result of invoking underlyingSourceDict[\"start\"] with argument list\n            // « controller » and callback this value underlyingSource.\n            underlying_source_dict\n                .start\n                .map(|f| StartAlgorithm::Function {\n                    f,\n                    underlying_source: underlying_source.clone(),\n                })\n                .unwrap_or(StartAlgorithm::ReturnUndefined),\n            // If underlyingSourceDict[\"pull\"] exists, then set pullAlgorithm to an algorithm which returns the result of invoking underlyingSourceDict[\"pull\"] with argument list\n            // « controller » and callback this value underlyingSource.\n            underlying_source_dict\n                .pull\n                .map(|f| PullAlgorithm::Function {\n                    f,\n                    underlying_source: underlying_source.clone(),\n                })\n                .unwrap_or(PullAlgorithm::ReturnPromiseUndefined),\n            // If underlyingSourceDict[\"cancel\"] exists, then set cancelAlgorithm to an algorithm which takes an argument reason and returns the result of invoking underlyingSourceDict[\"cancel\"] with argument list\n            // « reason » and callback this value underlyingSource.\n            underlying_source_dict\n                .cancel\n                .map(|f| CancelAlgorithm::Function {\n                    f,\n                    underlying_source,\n                })\n                .unwrap_or(CancelAlgorithm::ReturnPromiseUndefined),\n            // Let autoAllocateChunkSize be underlyingSourceDict[\"autoAllocateChunkSize\"], if it exists, or undefined otherwise.\n            underlying_source_dict.auto_allocate_chunk_size,\n        );\n\n        // If autoAllocateChunkSize is 0, then throw a TypeError exception.\n        if auto_allocate_chunk_size == Some(0) {\n            return Err(Exception::throw_type(\n                ctx,\n                \"autoAllocateChunkSize must be greater than 0\",\n            ));\n        }\n\n        Self::set_up_readable_byte_stream_controller(\n            ctx.clone(),\n            stream,\n            start_algorithm,\n            pull_algorithm,\n            cancel_algorithm,\n            high_water_mark,\n            auto_allocate_chunk_size,\n        )?;\n\n        Ok(())\n    }\n\n    pub(super) fn set_up_readable_byte_stream_controller(\n        ctx: Ctx<'js>,\n        stream: ReadableStreamOwned<'js>,\n        start_algorithm: StartAlgorithm<'js>,\n        pull_algorithm: PullAlgorithm<'js>,\n        cancel_algorithm: CancelAlgorithm<'js>,\n        high_water_mark: f64,\n        auto_allocate_chunk_size: Option<usize>,\n    ) -> Result<Class<'js, Self>> {\n        let (stream_class, mut stream) = class_from_owned_borrow_mut(stream);\n\n        let array_constructor_primordials = ArrayConstructorPrimordials::get(&ctx)?.clone();\n        let BasePrimordials {\n            constructor_array_buffer,\n            function_array_buffer_is_view,\n            ..\n        } = &*BasePrimordials::get(&ctx)?;\n\n        let controller = Self {\n            // Set controller.[[stream]] to stream.\n            stream: stream_class,\n\n            // Set controller.[[pullAgain]] and controller.[[pulling]] to false.\n            pull_again: false,\n            pulling: false,\n\n            // Set controller.[[byobRequest]] to null.\n            byob_request: None,\n\n            // Perform ! ResetQueue(controller).\n            queue: VecDeque::new(),\n            queue_total_size: 0,\n\n            // Set controller.[[closeRequested]] and controller.[[started]] to false.\n            close_requested: false,\n            started: false,\n\n            // Set controller.[[strategyHWM]] to highWaterMark.\n            strategy_hwm: high_water_mark,\n\n            // Set controller.[[pullAlgorithm]] to pullAlgorithm.\n            pull_algorithm: Some(pull_algorithm),\n            cancel_algorithm: Some(cancel_algorithm),\n\n            // Set controller.[[autoAllocateChunkSize]] to autoAllocateChunkSize.\n            auto_allocate_chunk_size,\n\n            pending_pull_intos: VecDeque::new(),\n\n            array_constructor_primordials,\n            constructor_array_buffer: constructor_array_buffer.clone(),\n            function_array_buffer_is_view: function_array_buffer_is_view.clone(),\n        };\n\n        let controller_class = Class::instance(ctx.clone(), controller)?;\n\n        // Set stream.[[controller]] to controller.\n        stream.controller =\n            ReadableStreamControllerClass::ReadableStreamByteController(controller_class.clone());\n\n        let objects =\n            ReadableStreamObjects::new_byte(stream, OwnedBorrowMut::from_class(controller_class))\n                .refresh_reader();\n\n        let promise_primordials = objects.stream.promise_primordials.clone();\n\n        // Let startResult be the result of performing startAlgorithm.\n        let (start_result, objects_class) =\n            Self::start_algorithm(ctx.clone(), objects, start_algorithm)?;\n\n        // Let startPromise be a promise resolved with startResult.\n        let start_promise = promise_resolved_with(&ctx, &promise_primordials, Ok(start_result))?;\n\n        let _ = upon_promise::<Value<'js>, _>(ctx.clone(), start_promise, {\n            let objects_class = objects_class.clone();\n            move |ctx, result| {\n                let mut objects =\n                    ReadableStreamObjects::from_class_no_reader(objects_class).refresh_reader();\n                match result {\n                    // Upon fulfillment of startPromise,\n                    Ok(_) => {\n                        // Set controller.[[started]] to true.\n                        objects.controller.started = true;\n                        // Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).\n                        Self::readable_byte_stream_controller_call_pull_if_needed(ctx, objects)?;\n                        Ok(())\n                    },\n                    // Upon rejection of startPromise with reason r,\n                    Err(r) => {\n                        // Perform ! ReadableByteStreamControllerError(controller, r).\n                        Self::readable_byte_stream_controller_error(objects, r)?;\n                        Ok(())\n                    },\n                }\n            }\n        })?;\n\n        Ok(objects_class.controller)\n    }\n\n    fn readable_byte_stream_controller_call_pull_if_needed<R: ReadableStreamReader<'js>>(\n        ctx: Ctx<'js>,\n        objects: ReadableByteStreamObjects<'js, R>,\n    ) -> Result<ReadableByteStreamObjects<'js, R>> {\n        // Let shouldPull be ! ReadableByteStreamControllerShouldCallPull(controller).\n        let (should_pull, mut objects) =\n            Self::readable_byte_stream_controller_should_call_pull(objects);\n\n        // If shouldPull is false, return.\n        if !should_pull {\n            return Ok(objects);\n        }\n\n        // If controller.[[pulling]] is true,\n        if objects.controller.pulling {\n            // Set controller.[[pullAgain]] to true.\n            objects.controller.pull_again = true;\n\n            // Return.\n            return Ok(objects);\n        }\n\n        // Set controller.[[pulling]] to true.\n        objects.controller.pulling = true;\n\n        // Let pullPromise be the result of performing controller.[[pullAlgorithm]].\n        let (pull_promise, objects_class) = Self::pull_algorithm(ctx.clone(), objects)?;\n\n        upon_promise::<Value<'js>, ()>(ctx, pull_promise, {\n            let objects_class = objects_class.clone();\n            move |ctx, result| {\n                let mut objects =\n                    ReadableStreamObjects::from_class_no_reader(objects_class).refresh_reader();\n                match result {\n                    // Upon fulfillment of pullPromise,\n                    Ok(_) => {\n                        // Set controller.[[pulling]] to false.\n                        objects.controller.pulling = false;\n                        // If controller.[[pullAgain]] is true,\n                        if objects.controller.pull_again {\n                            // Set controller.[[pullAgain]] to false.\n                            objects.controller.pull_again = false;\n                            // Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).\n                            Self::readable_byte_stream_controller_call_pull_if_needed(\n                                ctx, objects,\n                            )?;\n                        };\n                        Ok(())\n                    },\n                    // Upon rejection of pullPromise with reason e,\n                    Err(e) => {\n                        // Perform ! ReadableByteStreamControllerError(controller, e).\n                        Self::readable_byte_stream_controller_error(objects, e)?;\n                        Ok(())\n                    },\n                }\n            }\n        })?;\n\n        Ok(ReadableStreamObjects::from_class(objects_class))\n    }\n\n    fn readable_byte_stream_controller_should_call_pull<R: ReadableStreamReader<'js>>(\n        mut objects: ReadableByteStreamObjects<'js, R>,\n    ) -> (bool, ReadableByteStreamObjects<'js, R>) {\n        // Let stream be controller.[[stream]].\n        match objects.stream.state {\n            ReadableStreamState::Readable => {},\n            // If stream.[[state]] is not \"readable\", return false.\n            _ => return (false, objects),\n        }\n\n        // If controller.[[closeRequested]] is true, return false.\n        if objects.controller.close_requested {\n            return (false, objects);\n        }\n\n        // If controller.[[started]] is false, return false.\n        if !objects.controller.started {\n            return (false, objects);\n        }\n\n        let (mut has_read_requests, mut has_read_into_requests) = (false, false);\n        objects = objects\n            .with_reader(\n                |objects| {\n                    // If ! ReadableStreamHasDefaultReader(stream) is true and ! ReadableStreamGetNumReadRequests(stream) > 0, return true.\n                    if ReadableStream::readable_stream_get_num_read_requests(&objects.reader) > 0 {\n                        has_read_requests = true;\n                    }\n                    Ok(objects)\n                },\n                |objects| {\n                    // If ! ReadableStreamHasBYOBReader(stream) is true and ! ReadableStreamGetNumReadIntoRequests(stream) > 0, return true.\n                    if ReadableStream::readable_stream_get_num_read_into_requests(&objects.reader)\n                        > 0\n                    {\n                        has_read_into_requests = true;\n                    }\n                    Ok(objects)\n                },\n                Ok,\n            )\n            .unwrap();\n\n        if has_read_requests || has_read_into_requests {\n            return (true, objects);\n        }\n\n        // Let desiredSize be ! ReadableByteStreamControllerGetDesiredSize(controller).\n        let desired_size = objects\n            .controller\n            .readable_byte_stream_controller_get_desired_size(&objects.stream);\n\n        // Assert: desiredSize is not null.\n        if desired_size.0.expect(\"desired_size must not be null\") > 0.0 {\n            // If desiredSize > 0, return true.\n            return (true, objects);\n        }\n\n        // Return false.\n        (false, objects)\n    }\n\n    pub(super) fn readable_byte_stream_controller_error<R: ReadableStreamReader<'js>>(\n        // Let stream be controller.[[stream]].\n        mut objects: ReadableByteStreamObjects<'js, R>,\n        e: Value<'js>,\n    ) -> Result<ReadableByteStreamObjects<'js, R>> {\n        // If stream.[[state]] is not \"readable\", return.\n        if !matches!(objects.stream.state, ReadableStreamState::Readable) {\n            return Ok(objects);\n        };\n\n        // Perform ! ReadableByteStreamControllerClearPendingPullIntos(controller).\n        objects\n            .controller\n            .readable_byte_stream_controller_clear_pending_pull_intos();\n\n        // Perform ! ResetQueue(controller).\n        objects.controller.reset_queue();\n\n        // Perform ! ReadableByteStreamControllerClearAlgorithms(controller).\n        objects\n            .controller\n            .readable_byte_stream_controller_clear_algorithms();\n\n        // Perform ! ReadableStreamError(stream, e).\n        ReadableStream::readable_stream_error(objects, e)\n    }\n\n    fn readable_byte_stream_controller_clear_pending_pull_intos(&mut self) {\n        // Perform ! ReadableByteStreamControllerInvalidateBYOBRequest(controller).\n        self.readable_byte_stream_controller_invalidate_byob_request();\n\n        // Set controller.[[pendingPullIntos]] to a new empty list.\n        self.pending_pull_intos.clear();\n    }\n\n    fn readable_byte_stream_controller_invalidate_byob_request(&mut self) {\n        let byob_request = match self.byob_request {\n            // If controller.[[byobRequest]] is null, return.\n            None => return,\n            Some(ref byob_request) => byob_request.clone(),\n        };\n        let mut byob_request = OwnedBorrowMut::from_class(byob_request);\n        byob_request.controller = None;\n        byob_request.view = None;\n\n        self.byob_request = None;\n    }\n\n    fn readable_byte_stream_controller_clear_algorithms(&mut self) {\n        self.pull_algorithm = None;\n        self.cancel_algorithm = None;\n    }\n\n    pub(super) fn readable_byte_stream_controller_get_byob_request(\n        ctx: Ctx<'js>,\n        controller: OwnedBorrowMut<'js, Self>,\n    ) -> Result<(\n        Null<Class<'js, ReadableStreamBYOBRequest<'js>>>,\n        OwnedBorrowMut<'js, Self>,\n    )> {\n        // If controller.[[byobRequest]] is null and controller.[[pendingPullIntos]] is not empty,\n        if controller.byob_request.is_none() && !controller.pending_pull_intos.is_empty() {\n            // Let firstDescriptor be controller.[[pendingPullIntos]][0].\n            let first_descriptor = &controller.pending_pull_intos[0];\n\n            // Let view be ! Construct(%Uint8Array%, « firstDescriptor’s buffer, firstDescriptor’s byte offset + firstDescriptor’s bytes filled, firstDescriptor’s byte length − firstDescriptor’s bytes filled »).\n            let view = ViewBytes::from_value(\n                &ctx,\n                &controller.function_array_buffer_is_view,\n                Some(\n                    &controller\n                        .array_constructor_primordials\n                        .constructor_uint8array\n                        .construct((\n                            first_descriptor.buffer.clone(),\n                            first_descriptor.byte_offset + first_descriptor.bytes_filled,\n                            first_descriptor.byte_length - first_descriptor.bytes_filled,\n                        ))?,\n                ),\n            )?;\n\n            let (controller_class, mut controller) = class_from_owned_borrow_mut(controller);\n\n            // Let byobRequest be a new ReadableStreamBYOBRequest.\n            let byob_request = ReadableStreamBYOBRequest {\n                // Set byobRequest.[[controller]] to controller.\n                controller: Some(controller_class),\n                // Set byobRequest.[[view]] to view.\n                view: Some(view),\n            };\n\n            // Set controller.[[byobRequest]] to byobRequest.\n            controller.byob_request = Some(Class::instance(ctx, byob_request)?);\n\n            Ok((Null(controller.byob_request.clone()), controller))\n        } else {\n            // Return controller.[[byobRequest]].\n            Ok((Null(controller.byob_request.clone()), controller))\n        }\n    }\n\n    fn readable_byte_stream_controller_get_desired_size(\n        &self,\n        stream: &ReadableStream<'js>,\n    ) -> Null<f64> {\n        // Let state be controller.[[stream]].[[state]].\n        match stream.state {\n            // If state is \"errored\", return null.\n            ReadableStreamState::Errored(_) => Null(None),\n            // If state is \"closed\", return 0.\n            ReadableStreamState::Closed => Null(Some(0.0)),\n            // Return controller.[[strategyHWM]] − controller.[[queueTotalSize]].\n            _ => Null(Some(self.strategy_hwm - self.queue_total_size as f64)),\n        }\n    }\n\n    fn reset_queue(&mut self) {\n        // Set container.[[queue]] to a new empty list.\n        self.queue.clear();\n        // Set container.[[queueTotalSize]] to 0.\n        self.queue_total_size = 0;\n    }\n\n    pub(super) fn readable_byte_stream_controller_close<R: ReadableStreamReader<'js>>(\n        ctx: Ctx<'js>,\n        // Let stream be controller.[[stream]].\n        mut objects: ReadableByteStreamObjects<'js, R>,\n    ) -> Result<ReadableByteStreamObjects<'js, R>> {\n        // If controller.[[closeRequested]] is true or stream.[[state]] is not \"readable\", return.\n        if objects.controller.close_requested\n            || !matches!(objects.stream.state, ReadableStreamState::Readable)\n        {\n            return Ok(objects);\n        }\n\n        // If controller.[[queueTotalSize]] > 0,\n        if objects.controller.queue_total_size > 0 {\n            // Set controller.[[closeRequested]] to true.\n            objects.controller.close_requested = true;\n            // Return.\n            return Ok(objects);\n        }\n\n        // If controller.[[pendingPullIntos]] is not empty,\n        // Let firstPendingPullInto be controller.[[pendingPullIntos]][0].\n        if let Some(first_pending_pull_into) = objects.controller.pending_pull_intos.front() {\n            // If the remainder after dividing firstPendingPullInto’s bytes filled by firstPendingPullInto’s element size is not 0,\n            if first_pending_pull_into.bytes_filled % first_pending_pull_into.element_size != 0 {\n                // Let e be a new TypeError exception.\n                let e: Value = objects\n                    .stream\n                    .constructor_type_error\n                    .call((\"Insufficient bytes to fill elements in the given buffer\",))?;\n                Self::readable_byte_stream_controller_error(objects, e.clone())?;\n                return Err(ctx.throw(e));\n            }\n        }\n\n        // Perform ! ReadableByteStreamControllerClearAlgorithms(controller).\n        objects\n            .controller\n            .readable_byte_stream_controller_clear_algorithms();\n\n        // Perform ! ReadableStreamClose(stream).\n        ReadableStream::readable_stream_close(ctx, objects)\n    }\n\n    pub(super) fn readable_byte_stream_controller_enqueue<R: ReadableStreamReader<'js>>(\n        ctx: &Ctx<'js>,\n        // Let stream be controller.[[stream]].\n        mut objects: ReadableByteStreamObjects<'js, R>,\n        chunk: ViewBytes<'js>,\n    ) -> Result<ReadableByteStreamObjects<'js, R>> {\n        // If controller.[[closeRequested]] is true or stream.[[state]] is not \"readable\", return.\n        if objects.controller.close_requested\n            || !matches!(objects.stream.state, ReadableStreamState::Readable)\n        {\n            return Ok(objects);\n        };\n\n        // Let buffer be chunk.[[ViewedArrayBuffer]].\n        // Let byteOffset be chunk.[[ByteOffset]].\n        // Let byteLength be chunk.[[ByteLength]].\n        let (buffer, byte_length, byte_offset) = chunk.get_array_buffer()?;\n\n        // If ! IsDetachedBuffer(buffer) is true, throw a TypeError exception.\n        buffer.as_raw().ok_or(Exception::throw_type(\n            ctx,\n            \"chunk's buffer is detached and so cannot be enqueued\",\n        ))?;\n\n        // Let transferredBuffer be ? TransferArrayBuffer(buffer).\n        let transferred_buffer = transfer_array_buffer(buffer)?;\n\n        // If controller.[[pendingPullIntos]] is not empty,\n        // Let firstPendingPullInto be controller.[[pendingPullIntos]][0].\n        if !objects.controller.pending_pull_intos.is_empty() {\n            // If ! IsDetachedBuffer(firstPendingPullInto’s buffer) is true, throw a TypeError exception.\n            objects.controller.pending_pull_intos[0]\n                    .buffer\n                    .as_raw()\n                    .or_throw_type(\n                        ctx,\n                        \"The BYOB request's buffer has been detached and so cannot be filled with an enqueued chunk\",\n                    )?;\n\n            // Perform ! ReadableByteStreamControllerInvalidateBYOBRequest(controller).\n            objects\n                .controller\n                .readable_byte_stream_controller_invalidate_byob_request();\n\n            // Set firstPendingPullInto’s buffer to ! TransferArrayBuffer(firstPendingPullInto’s buffer).\n            objects.controller.pending_pull_intos[0].buffer =\n                transfer_array_buffer(objects.controller.pending_pull_intos[0].buffer.clone())?;\n\n            // If firstPendingPullInto’s reader type is \"none\", perform ? ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(controller, firstPendingPullInto).\n            if let PullIntoDescriptorReaderType::None =\n                objects.controller.pending_pull_intos[0].reader_type\n            {\n                objects = Self::readable_byte_stream_enqueue_detached_pull_into_to_queue(\n                    ctx.clone(),\n                    objects,\n                    0,\n                )?;\n            }\n        }\n\n        objects = objects.with_reader(\n            // If ! ReadableStreamHasDefaultReader(stream) is true,\n            |mut objects| {\n                // Perform ! ReadableByteStreamControllerProcessReadRequestsUsingQueue(controller).\n                objects = Self::readable_byte_stream_controller_process_read_requests_using_queue(\n                    objects, ctx,\n                )?;\n\n                // If ! ReadableStreamGetNumReadRequests(stream) is 0,\n                if ReadableStream::readable_stream_get_num_read_requests(&objects.reader) == 0 {\n                    // Perform ! ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength).\n                    objects\n                        .controller\n                        .readable_byte_stream_controller_enqueue_chunk_to_queue(\n                            transferred_buffer.clone(),\n                            byte_offset,\n                            byte_length,\n                        )\n                } else {\n                    // Otherwise,\n                    // If controller.[[pendingPullIntos]] is not empty,\n                    if !objects.controller.pending_pull_intos.is_empty() {\n                        // Perform ! ReadableByteStreamControllerShiftPendingPullInto(controller).\n                        objects\n                            .controller\n                            .readable_byte_stream_controller_shift_pending_pull_into();\n                    }\n\n                    // Let transferredView be ! Construct(%Uint8Array%, « transferredBuffer, byteOffset, byteLength »).\n                    let transferred_view = ViewBytes::from_value(\n                        ctx,\n                        &objects.controller.function_array_buffer_is_view,\n                        Some(\n                            &objects\n                                .controller\n                                .array_constructor_primordials\n                                .constructor_uint8array\n                                .construct((\n                                    transferred_buffer.clone(),\n                                    byte_offset,\n                                    byte_length,\n                                ))?,\n                        ),\n                    );\n\n                    // Perform ! ReadableStreamFulfillReadRequest(stream, transferredView, false).\n                    objects = ReadableStream::readable_stream_fulfill_read_request(\n                        ctx,\n                        objects,\n                        transferred_view.into_js(ctx)?,\n                        false,\n                    )?;\n                }\n\n                Ok(objects)\n            },\n            |mut objects| {\n                // Otherwise, if ! ReadableStreamHasBYOBReader(stream) is true,\n                // Perform ! ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength).\n                objects\n                    .controller\n                    .readable_byte_stream_controller_enqueue_chunk_to_queue(\n                        transferred_buffer.clone(),\n                        byte_offset,\n                        byte_length,\n                    );\n                // Perform ! ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).\n\n                Self::readable_byte_stream_controller_process_pull_into_descriptors_using_queue(\n                    ctx, objects,\n                )\n            },\n            |mut objects| {\n                // Otherwise,\n                // Perform ! ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength).\n                objects\n                    .controller\n                    .readable_byte_stream_controller_enqueue_chunk_to_queue(\n                        transferred_buffer.clone(),\n                        byte_offset,\n                        byte_length,\n                    );\n\n                Ok(objects)\n            },\n        )?;\n\n        // Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).\n        Self::readable_byte_stream_controller_call_pull_if_needed(ctx.clone(), objects)\n    }\n\n    fn readable_byte_stream_enqueue_detached_pull_into_to_queue<R: ReadableStreamReader<'js>>(\n        ctx: Ctx<'js>,\n        mut objects: ReadableByteStreamObjects<'js, R>,\n        pull_into_descriptor_index: usize,\n    ) -> Result<ReadableByteStreamObjects<'js, R>> {\n        let pull_into_descriptor =\n            &objects.controller.pending_pull_intos[pull_into_descriptor_index];\n        // If pullIntoDescriptor’s bytes filled > 0, perform ? ReadableByteStreamControllerEnqueueClonedChunkToQueue(controller, pullIntoDescriptor’s buffer, pullIntoDescriptor’s byte offset, pullIntoDescriptor’s bytes filled).\n        if pull_into_descriptor.bytes_filled > 0 {\n            let buffer = pull_into_descriptor.buffer.clone();\n            let byte_offset = pull_into_descriptor.byte_offset;\n            let bytes_filled = pull_into_descriptor.bytes_filled;\n            objects = Self::readable_byte_stream_controller_enqueue_cloned_chunk_to_queue(\n                ctx,\n                objects,\n                &buffer,\n                byte_offset,\n                bytes_filled,\n            )?;\n        }\n\n        // Perform ! ReadableByteStreamControllerShiftPendingPullInto(controller).\n        objects\n            .controller\n            .readable_byte_stream_controller_shift_pending_pull_into();\n\n        Ok(objects)\n    }\n\n    fn readable_byte_stream_controller_process_read_requests_using_queue(\n        mut objects: ReadableStreamDefaultReaderObjects<'js, OwnedBorrowMut<'js, Self>>,\n        ctx: &Ctx<'js>,\n    ) -> Result<ReadableStreamDefaultReaderObjects<'js, OwnedBorrowMut<'js, Self>>> {\n        // While reader.[[readRequests]] is not empty,\n        while !objects.reader.read_requests.is_empty() {\n            // If controller.[[queueTotalSize]] is 0, return.\n            if objects.controller.queue_total_size == 0 {\n                return Ok(objects);\n            }\n\n            // Let readRequest be reader.[[readRequests]][0].\n            // Remove readRequest from reader.[[readRequests]].\n            let read_request = objects.reader.read_requests.pop_front().unwrap();\n            // Perform ! ReadableByteStreamControllerFillReadRequestFromQueue(controller, readRequest).\n            objects = Self::readable_byte_stream_controller_fill_read_request_from_queue(\n                ctx,\n                objects,\n                read_request,\n            )?;\n        }\n\n        Ok(objects)\n    }\n\n    fn readable_byte_stream_controller_shift_pending_pull_into(\n        &mut self,\n    ) -> PullIntoDescriptor<'js> {\n        // Let descriptor be controller.[[pendingPullIntos]][0].\n        // Remove descriptor from controller.[[pendingPullIntos]].\n        // Return descriptor.\n        self.pending_pull_intos.pop_front().expect(\n            \"ReadableByteStreamControllerShiftPendingPullInto called on empty pendingPullIntos\",\n        )\n    }\n\n    fn readable_byte_stream_controller_enqueue_chunk_to_queue(\n        &mut self,\n        buffer: ArrayBuffer<'js>,\n        byte_offset: usize,\n        byte_length: usize,\n    ) {\n        let len = buffer.len();\n        // Append a new readable byte stream queue entry with buffer buffer, byte offset byteOffset, and byte length byteLength to controller.[[queue]].\n        self.queue.push_back(ReadableByteStreamQueueEntry {\n            buffer,\n            byte_offset,\n            byte_length,\n        });\n\n        // Set controller.[[queueTotalSize]] to controller.[[queueTotalSize]] + byteLength.\n        self.queue_total_size += len;\n    }\n\n    fn readable_byte_stream_controller_process_pull_into_descriptors_using_queue<\n        R: ReadableStreamReader<'js>,\n    >(\n        ctx: &Ctx<'js>,\n        mut objects: ReadableByteStreamObjects<'js, R>,\n    ) -> Result<ReadableByteStreamObjects<'js, R>> {\n        // While controller.[[pendingPullIntos]] is not empty,\n        while !objects.controller.pending_pull_intos.is_empty() {\n            // If controller.[[queueTotalSize]] is 0, return.\n            if objects.controller.queue_total_size == 0 {\n                return Ok(objects);\n            }\n\n            // Let pullIntoDescriptor be controller.[[pendingPullIntos]][0].\n            let mut pull_into_descriptor_ref = PullIntoDescriptorRefMut::Index(0);\n\n            // If ! ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) is true,\n            if objects\n                .controller\n                .readable_byte_stream_controller_fill_pull_into_descriptor_from_queue(\n                    ctx,\n                    &mut pull_into_descriptor_ref,\n                )?\n            {\n                // Perform ! ReadableByteStreamControllerShiftPendingPullInto(controller).\n                let pull_into_descriptor = objects\n                    .controller\n                    .readable_byte_stream_controller_shift_pending_pull_into();\n\n                // Perform ! ReadableByteStreamControllerCommitPullIntoDescriptor(controller.[[stream]], pullIntoDescriptor).\n                objects = Self::readable_byte_stream_controller_commit_pull_into_descriptor(\n                    ctx.clone(),\n                    objects,\n                    pull_into_descriptor,\n                )?;\n            }\n        }\n        Ok(objects)\n    }\n\n    fn readable_byte_stream_controller_enqueue_cloned_chunk_to_queue<\n        R: ReadableStreamReader<'js>,\n    >(\n        ctx: Ctx<'js>,\n        mut objects: ReadableByteStreamObjects<'js, R>,\n        buffer: &ArrayBuffer<'js>,\n        byte_offset: usize,\n        byte_length: usize,\n    ) -> Result<ReadableByteStreamObjects<'js, R>> {\n        // Let cloneResult be CloneArrayBuffer(buffer, byteOffset, byteLength, %ArrayBuffer%).\n        let clone_result = match ArrayBuffer::new_copy(\n            ctx.clone(),\n            &buffer.as_bytes().expect(\n                \"ReadableByteStreamControllerEnqueueClonedChunkToQueue called on detached buffer\",\n            )[byte_offset..byte_offset + byte_length],\n        ) {\n            Ok(clone_result) => clone_result,\n            Err(Error::Exception) => {\n                let err = ctx.catch();\n                Self::readable_byte_stream_controller_error(objects, err.clone())?;\n                return Err(ctx.throw(err));\n            },\n            Err(err) => return Err(err),\n        };\n\n        // Perform ! ReadableByteStreamControllerEnqueueChunkToQueue(controller, cloneResult.[[Value]], 0, byteLength).\n        objects\n            .controller\n            .readable_byte_stream_controller_enqueue_chunk_to_queue(clone_result, 0, byte_length);\n\n        Ok(objects)\n    }\n\n    fn readable_byte_stream_controller_fill_read_request_from_queue(\n        ctx: &Ctx<'js>,\n        mut objects: ReadableStreamDefaultReaderObjects<'js, OwnedBorrowMut<'js, Self>>,\n        read_request: impl ReadableStreamReadRequest<'js>,\n    ) -> Result<ReadableStreamDefaultReaderObjects<'js, OwnedBorrowMut<'js, Self>>> {\n        let entry = {\n            // Assert: controller.[[queueTotalSize]] > 0.\n            // Let entry be controller.[[queue]][0].\n            // Remove entry from controller.[[queue]].\n            let entry = objects.controller.queue.pop_front().expect(\n                \"ReadableByteStreamControllerFillReadRequestFromQueue called with empty queue\",\n            );\n\n            // Set controller.[[queueTotalSize]] to controller.[[queueTotalSize]] − entry’s byte length.\n            objects.controller.queue_total_size -= entry.byte_length;\n\n            entry\n        };\n\n        // Perform ! ReadableByteStreamControllerHandleQueueDrain(controller).\n        objects = Self::readable_byte_stream_controller_handle_queue_drain(ctx.clone(), objects)?;\n\n        // Let view be ! Construct(%Uint8Array%, « entry’s buffer, entry’s byte offset, entry’s byte length »).\n        let view: TypedArray<u8> = objects\n            .controller\n            .array_constructor_primordials\n            .constructor_uint8array\n            .construct((entry.buffer, entry.byte_offset, entry.byte_length))?;\n\n        // Perform readRequest’s chunk steps, given view.\n        read_request.chunk_steps_typed(objects, view.into_value())\n    }\n\n    fn readable_byte_stream_controller_fill_pull_into_descriptor_from_queue<'a>(\n        &'a mut self,\n        ctx: &Ctx<'js>,\n        pull_into_descriptor_ref: &mut PullIntoDescriptorRefMut<'js, 'a>,\n    ) -> Result<bool> {\n        let (mut total_bytes_to_copy_remaining, ready) = {\n            let pull_into_descriptor = match pull_into_descriptor_ref {\n                PullIntoDescriptorRefMut::Index(i) => &mut self.pending_pull_intos[*i],\n                PullIntoDescriptorRefMut::Owned(r) => r,\n            };\n            // Let maxBytesToCopy be min(controller.[[queueTotalSize]], pullIntoDescriptor’s byte length − pullIntoDescriptor’s bytes filled).\n            let max_bytes_to_copy: usize = std::cmp::min(\n                self.queue_total_size,\n                pull_into_descriptor.byte_length - pull_into_descriptor.bytes_filled,\n            );\n\n            // Let maxBytesFilled be pullIntoDescriptor’s bytes filled + maxBytesToCopy.\n            let max_bytes_filled = pull_into_descriptor.bytes_filled + max_bytes_to_copy;\n\n            // Let totalBytesToCopyRemaining be maxBytesToCopy.\n            let mut total_bytes_to_copy_remaining = max_bytes_to_copy;\n\n            // Let ready be false.\n            let mut ready = false;\n\n            // Let remainderBytes be the remainder after dividing maxBytesFilled by pullIntoDescriptor’s element size.\n            let remainder_bytes = max_bytes_filled % pull_into_descriptor.element_size;\n\n            // Let maxAlignedBytes be maxBytesFilled − remainderBytes.\n            let max_aligned_bytes = max_bytes_filled - remainder_bytes;\n\n            // If maxAlignedBytes ≥ pullIntoDescriptor’s minimum fill,\n            if max_aligned_bytes >= pull_into_descriptor.minimum_fill {\n                // Set totalBytesToCopyRemaining to maxAlignedBytes − pullIntoDescriptor’s bytes filled.\n                total_bytes_to_copy_remaining =\n                    max_aligned_bytes - pull_into_descriptor.bytes_filled;\n                // Set ready to true.\n                ready = true\n            }\n\n            (total_bytes_to_copy_remaining, ready)\n        };\n\n        // Let queue be controller.[[queue]].\n        // While totalBytesToCopyRemaining > 0,\n        while total_bytes_to_copy_remaining > 0 {\n            let bytes_to_copy = {\n                let pull_into_descriptor = match pull_into_descriptor_ref {\n                    PullIntoDescriptorRefMut::Index(i) => &mut self.pending_pull_intos[*i],\n                    PullIntoDescriptorRefMut::Owned(r) => r,\n                };\n\n                // Let headOfQueue be queue[0].\n                let head_of_queue = self\n                    .queue\n                    .front_mut()\n                    .expect(\"empty queue with bytes to copy\");\n                // Let bytesToCopy be min(totalBytesToCopyRemaining, headOfQueue’s byte length).\n                let bytes_to_copy: usize =\n                    std::cmp::min(total_bytes_to_copy_remaining, head_of_queue.byte_length);\n                // Let destStart be pullIntoDescriptor’s byte offset + pullIntoDescriptor’s bytes filled.\n                let dest_start: usize =\n                    pull_into_descriptor.byte_offset + pull_into_descriptor.bytes_filled;\n                // Perform ! CopyDataBlockBytes(pullIntoDescriptor’s buffer.[[ArrayBufferData]], destStart, headOfQueue’s buffer.[[ArrayBufferData]], headOfQueue’s byte offset, bytesToCopy).\n                copy_data_block_bytes(\n                    ctx,\n                    &pull_into_descriptor.buffer,\n                    dest_start,\n                    &head_of_queue.buffer,\n                    head_of_queue.byte_offset,\n                    bytes_to_copy,\n                )?;\n                if head_of_queue.byte_length == bytes_to_copy {\n                    // If headOfQueue’s byte length is bytesToCopy,\n                    // Remove queue[0].\n                    self.queue.pop_front();\n                } else {\n                    // Otherwise,\n                    // Set headOfQueue’s byte offset to headOfQueue’s byte offset + bytesToCopy.\n                    head_of_queue.byte_offset += bytes_to_copy;\n                    // Set headOfQueue’s byte length to headOfQueue’s byte length − bytesToCopy.\n                    head_of_queue.byte_length -= bytes_to_copy\n                }\n\n                // Set controller.[[queueTotalSize]] to controller.[[queueTotalSize]] − bytesToCopy.\n                self.queue_total_size -= bytes_to_copy;\n\n                bytes_to_copy\n            };\n\n            // Perform ! ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesToCopy, pullIntoDescriptor).\n            self.readable_byte_stream_controller_fill_head_pull_into_descriptor(\n                bytes_to_copy,\n                pull_into_descriptor_ref,\n            );\n\n            // Set totalBytesToCopyRemaining to totalBytesToCopyRemaining − bytesToCopy.\n            total_bytes_to_copy_remaining -= bytes_to_copy\n        }\n\n        Ok(ready)\n    }\n\n    fn readable_byte_stream_controller_commit_pull_into_descriptor<R: ReadableStreamReader<'js>>(\n        ctx: Ctx<'js>,\n        objects: ReadableByteStreamObjects<'js, R>,\n        pull_into_descriptor: PullIntoDescriptor<'js>,\n    ) -> Result<ReadableByteStreamObjects<'js, R>> {\n        // Let done be false.\n        let mut done = false;\n        // If stream.[[state]] is \"closed\",\n        if matches!(objects.stream.state, ReadableStreamState::Closed) {\n            // Set done to true.\n            done = true\n        }\n\n        let reader_type = pull_into_descriptor.reader_type;\n\n        // Let filledView be ! ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor).\n        let filled_view = Self::readable_byte_stream_controller_convert_pull_into_descriptor(\n            ctx.clone(),\n            &objects.stream.function_array_buffer_is_view,\n            pull_into_descriptor,\n        )?;\n\n        if let PullIntoDescriptorReaderType::Default = reader_type {\n            // If pullIntoDescriptor’s reader type is \"default\",\n            objects.with_assert_default_reader(|objects| {\n                // Perform ! ReadableStreamFulfillReadRequest(stream, filledView, done).\n                ReadableStream::readable_stream_fulfill_read_request(\n                    &ctx,\n                    objects,\n                    filled_view.into_js(&ctx)?,\n                    done,\n                )\n            })\n        } else {\n            // Otherwise,\n            objects.with_assert_byob_reader(|objects| {\n                // Perform ! ReadableStreamFulfillReadIntoRequest(stream, filledView, done).\n                ReadableStream::readable_stream_fulfill_read_into_request(\n                    &ctx,\n                    objects,\n                    filled_view,\n                    done,\n                )\n            })\n        }\n    }\n\n    fn readable_byte_stream_controller_handle_queue_drain<R: ReadableStreamReader<'js>>(\n        ctx: Ctx<'js>,\n        mut objects: ReadableByteStreamObjects<'js, R>,\n    ) -> Result<ReadableByteStreamObjects<'js, R>> {\n        // If controller.[[queueTotalSize]] is 0 and controller.[[closeRequested]] is true,\n        if objects.controller.queue_total_size == 0 && objects.controller.close_requested {\n            // Perform ! ReadableByteStreamControllerClearAlgorithms(controller).\n            objects\n                .controller\n                .readable_byte_stream_controller_clear_algorithms();\n            // Perform ! ReadableStreamClose(controller.[[stream]]).\n            ReadableStream::readable_stream_close(ctx, objects)\n        } else {\n            // Otherwise,\n            // Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).\n            Self::readable_byte_stream_controller_call_pull_if_needed(ctx.clone(), objects)\n        }\n    }\n\n    fn readable_byte_stream_controller_convert_pull_into_descriptor(\n        ctx: Ctx<'js>,\n        function_array_buffer_is_view: &Function<'js>,\n        pull_into_descriptor: PullIntoDescriptor<'js>,\n    ) -> Result<ViewBytes<'js>> {\n        let PullIntoDescriptor {\n            // Let bytesFilled be pullIntoDescriptor’s bytes filled.\n            bytes_filled,\n            // Let elementSize be pullIntoDescriptor’s element size.\n            element_size,\n            byte_offset,\n            buffer,\n            ..\n        } = pull_into_descriptor;\n        // Let buffer be ! TransferArrayBuffer(pullIntoDescriptor’s buffer).\n        let buffer = transfer_array_buffer(buffer);\n        // Return ! Construct(pullIntoDescriptor’s view constructor, « buffer, pullIntoDescriptor’s byte offset, bytesFilled ÷ elementSize »).\n        let view: Object = pull_into_descriptor.view_constructor.construct((\n            buffer,\n            byte_offset,\n            bytes_filled / element_size,\n        ))?;\n        ViewBytes::from_object(&ctx, function_array_buffer_is_view, &view)\n    }\n\n    pub(super) fn readable_byte_stream_controller_pull_into(\n        ctx: &Ctx<'js>,\n        // Let stream be controller.[[stream]].\n        mut objects: ReadableStreamBYOBObjects<'js>,\n        view: ViewBytes<'js>,\n        min: u64,\n        read_into_request: impl ReadableStreamReadIntoRequest<'js> + 'js,\n    ) -> Result<ReadableStreamBYOBObjects<'js>> {\n        // Set elementSize to the element size specified in the typed array constructors table for view.[[TypedArrayName]].\n        // Set ctor to the constructor specified in the typed array constructors table for view.[[TypedArrayName]].\n        let (element_size, ctor) = (\n            view.element_size(),\n            objects\n                .controller\n                .array_constructor_primordials\n                .for_view_bytes(&view),\n        );\n\n        // Let minimumFill be min × elementSize.\n        let minimum_fill: usize = (min as usize) * element_size;\n\n        // Let byteOffset be view.[[ByteOffset]].\n        // Let byteLength be view.[[ByteLength]].\n        let (buffer, byte_length, byte_offset) = view.get_array_buffer()?;\n\n        // Let bufferResult be TransferArrayBuffer(view.[[ViewedArrayBuffer]]).\n        let buffer_result = transfer_array_buffer(buffer);\n        let buffer = match buffer_result {\n            // If bufferResult is an abrupt completion,\n            Err(Error::Exception) => {\n                // Perform readIntoRequest’s error steps, given bufferResult.[[Value]].\n                objects = read_into_request.error_steps(objects, ctx.catch())?;\n                // Return.\n                return Ok(objects);\n            },\n            Err(err) => return Err(err),\n            // Let buffer be bufferResult.[[Value]].\n            Ok(buffer) => buffer,\n        };\n\n        let buffer_byte_length = buffer.len();\n        // Let pullIntoDescriptor be a new pull-into descriptor with\n        let mut pull_into_descriptor = PullIntoDescriptor {\n            buffer,\n            buffer_byte_length,\n            byte_offset,\n            byte_length,\n            bytes_filled: 0,\n            minimum_fill,\n            element_size,\n            view_constructor: ctor.clone(),\n            reader_type: PullIntoDescriptorReaderType::Byob,\n        };\n\n        // If controller.[[pendingPullIntos]] is not empty,\n        if !objects.controller.pending_pull_intos.is_empty() {\n            // Append pullIntoDescriptor to controller.[[pendingPullIntos]].\n            objects\n                .controller\n                .pending_pull_intos\n                .push_back(pull_into_descriptor);\n\n            // Perform ! ReadableStreamAddReadIntoRequest(stream, readIntoRequest).\n            ReadableStream::readable_stream_add_read_into_request(\n                &mut objects.reader,\n                read_into_request,\n            );\n\n            // Return.\n            return Ok(objects);\n        }\n\n        // If stream.[[state]] is \"closed\",\n        if matches!(objects.stream.state, ReadableStreamState::Closed) {\n            // Let emptyView be ! Construct(ctor, « pullIntoDescriptor’s buffer, pullIntoDescriptor’s byte offset, 0 »).\n            let empty_view: Value<'js> = ctor.construct((\n                pull_into_descriptor.buffer,\n                pull_into_descriptor.byte_offset,\n                0,\n            ))?;\n\n            // Perform readIntoRequest’s close steps, given emptyView.\n            objects = read_into_request.close_steps(objects, empty_view)?;\n\n            // Return.\n            return Ok(objects);\n        }\n\n        // If controller.[[queueTotalSize]] > 0,\n        if objects.controller.queue_total_size > 0 {\n            // If ! ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) is true,\n            if objects\n                .controller\n                .readable_byte_stream_controller_fill_pull_into_descriptor_from_queue(\n                    ctx,\n                    &mut PullIntoDescriptorRefMut::Owned(&mut pull_into_descriptor),\n                )?\n            {\n                // Let filledView be ! ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor).\n                let filled_view = objects\n                    .controller\n                    .readable_byte_steam_controller_convert_pull_into_descriptor(\n                        pull_into_descriptor,\n                    )?;\n\n                // Perform ! ReadableByteStreamControllerHandleQueueDrain(controller).\n                objects =\n                    Self::readable_byte_stream_controller_handle_queue_drain(ctx.clone(), objects)?;\n\n                // Perform readIntoRequest’s chunk steps, given filledView.\n                // Return.\n                return read_into_request.chunk_steps(objects, filled_view);\n            }\n\n            // If controller.[[closeRequested]] is true,\n            if objects.controller.close_requested {\n                // Let e be a TypeError exception.\n                let e: Value = objects\n                    .stream\n                    .constructor_type_error\n                    .call((\"Insufficient bytes to fill elements in the given buffer\",))?;\n\n                // Perform ! ReadableByteStreamControllerError(controller, e).\n                objects = Self::readable_byte_stream_controller_error(objects, e.clone())?;\n\n                // Perform readIntoRequest’s error steps, given e.\n                // Return.\n                return read_into_request.error_steps(objects, e);\n            }\n        }\n\n        // Append pullIntoDescriptor to controller.[[pendingPullIntos]].\n        objects\n            .controller\n            .pending_pull_intos\n            .push_back(pull_into_descriptor);\n\n        // Perform ! ReadableStreamAddReadIntoRequest(stream, readIntoRequest).\n        ReadableStream::readable_stream_add_read_into_request(\n            &mut objects.reader,\n            read_into_request,\n        );\n\n        // Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).\n        Self::readable_byte_stream_controller_call_pull_if_needed(ctx.clone(), objects)\n    }\n\n    fn readable_byte_steam_controller_convert_pull_into_descriptor(\n        &mut self,\n        pull_into_descriptor: PullIntoDescriptor<'js>,\n    ) -> Result<Value<'js>> {\n        // Let bytesFilled be pullIntoDescriptor’s bytes filled.\n        let bytes_filled = pull_into_descriptor.bytes_filled;\n\n        // Let elementSize be pullIntoDescriptor’s element size.\n        let element_size = pull_into_descriptor.element_size;\n\n        // Let buffer be ! TransferArrayBuffer(pullIntoDescriptor’s buffer).\n        let buffer = transfer_array_buffer(pull_into_descriptor.buffer)?;\n\n        // Return ! Construct(pullIntoDescriptor’s view constructor, « buffer, pullIntoDescriptor’s byte offset, bytesFilled ÷ elementSize »).\n        pull_into_descriptor.view_constructor.construct((\n            buffer,\n            pull_into_descriptor.byte_offset,\n            bytes_filled / element_size,\n        ))\n    }\n\n    pub(super) fn readable_byte_stream_controller_respond<R: ReadableStreamReader<'js>>(\n        ctx: Ctx<'js>,\n        mut objects: ReadableByteStreamObjects<'js, R>,\n        bytes_written: usize,\n    ) -> Result<()> {\n        // Let firstDescriptor be controller.[[pendingPullIntos]][0].\n        let first_descriptor = &mut objects.controller.pending_pull_intos[0];\n\n        // Let state be controller.[[stream]].[[state]].\n        match objects.stream.state {\n            // If state is \"closed\",\n            ReadableStreamState::Closed => {\n                // If bytesWritten is not 0, throw a TypeError exception.\n                if bytes_written != 0 {\n                    return Err(Exception::throw_type(\n                        &ctx,\n                        \"bytesWritten must be 0 when calling respond() on a closed stream\",\n                    ));\n                }\n            },\n            // Otherwise,\n            _ => {\n                // If bytesWritten is 0, throw a TypeError exception.\n                if bytes_written == 0 {\n                    return Err(Exception::throw_type(\n                        &ctx,\n                        \"bytesWritten must be greater than 0 when calling respond() on a readable stream\",\n                    ));\n                }\n\n                // If firstDescriptor’s bytes filled + bytesWritten > firstDescriptor’s byte length, throw a RangeError exception.\n                if first_descriptor.bytes_filled + bytes_written > first_descriptor.byte_length {\n                    return Err(Exception::throw_range(&ctx, \"bytesWritten out of range'\"));\n                }\n            },\n        };\n\n        // Set firstDescriptor’s buffer to ! TransferArrayBuffer(firstDescriptor’s buffer).\n        first_descriptor.buffer = transfer_array_buffer(first_descriptor.buffer.clone())?;\n\n        // Perform ? ReadableByteStreamControllerRespondInternal(controller, bytesWritten).\n        Self::readable_byte_stream_controller_respond_internal(ctx, objects, bytes_written)\n    }\n\n    fn readable_byte_stream_controller_respond_internal<R: ReadableStreamReader<'js>>(\n        ctx: Ctx<'js>,\n        mut objects: ReadableByteStreamObjects<'js, R>,\n        bytes_written: usize,\n    ) -> Result<()> {\n        // Let firstDescriptor be controller.[[pendingPullIntos]][0].\n        let first_descriptor_index = 0;\n\n        // Perform ! ReadableByteStreamControllerInvalidateBYOBRequest(controller).\n        objects\n            .controller\n            .readable_byte_stream_controller_invalidate_byob_request();\n\n        // Let state be controller.[[stream]].[[state]].\n        match objects.stream.state {\n            // If state is \"closed\",\n            ReadableStreamState::Closed => {\n                // Perform ! ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor).\n                objects = Self::readable_byte_stream_controller_respond_in_closed_state(\n                    ctx.clone(),\n                    objects,\n                    first_descriptor_index,\n                )?;\n            },\n            // Otherwise\n            _ => {\n                // Perform ? ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, firstDescriptor).\n                objects = Self::readable_byte_stream_controller_respond_in_readable_state(\n                    ctx.clone(),\n                    objects,\n                    bytes_written,\n                    first_descriptor_index,\n                )?\n            },\n        };\n\n        _ = Self::readable_byte_stream_controller_call_pull_if_needed(ctx, objects)?;\n        Ok(())\n    }\n\n    fn readable_byte_stream_controller_respond_in_closed_state<R: ReadableStreamReader<'js>>(\n        ctx: Ctx<'js>,\n        // Let stream be controller.[[stream]].\n        mut objects: ReadableByteStreamObjects<'js, R>,\n        first_descriptor_index: usize,\n    ) -> Result<ReadableByteStreamObjects<'js, R>> {\n        // If firstDescriptor’s reader type is \"none\", perform ! ReadableByteStreamControllerShiftPendingPullInto(controller).\n        if let PullIntoDescriptorReaderType::None =\n            objects.controller.pending_pull_intos[first_descriptor_index].reader_type\n        {\n            objects\n                .controller\n                .readable_byte_stream_controller_shift_pending_pull_into();\n        }\n\n        // If ! ReadableStreamHasBYOBReader(stream) is true,\n        objects.with_reader(\n            Ok,\n            |mut objects| {\n                // While ! ReadableStreamGetNumReadIntoRequests(stream) > 0,\n                while ReadableStream::readable_stream_get_num_read_into_requests(&objects.reader)\n                    > 0\n                {\n                    // Let pullIntoDescriptor be ! ReadableByteStreamControllerShiftPendingPullInto(controller).\n                    let pull_into_descriptor = objects\n                        .controller\n                        .readable_byte_stream_controller_shift_pending_pull_into();\n\n                    // Perform ! ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDescriptor).\n                    objects = Self::readable_byte_stream_controller_commit_pull_into_descriptor(\n                        ctx.clone(),\n                        objects,\n                        pull_into_descriptor,\n                    )?;\n                }\n\n                Ok(objects)\n            },\n            Ok,\n        )\n    }\n\n    fn readable_byte_stream_controller_respond_in_readable_state<R: ReadableStreamReader<'js>>(\n        ctx: Ctx<'js>,\n        // Let stream be controller.[[stream]].\n        mut objects: ReadableByteStreamObjects<'js, R>,\n        bytes_written: usize,\n        pull_into_descriptor_index: usize,\n    ) -> Result<ReadableByteStreamObjects<'js, R>> {\n        // Perform ! ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesWritten, pullIntoDescriptor).\n        objects\n            .controller\n            .readable_byte_stream_controller_fill_head_pull_into_descriptor(\n                bytes_written,\n                &mut PullIntoDescriptorRefMut::Index(pull_into_descriptor_index),\n            );\n\n        // If pullIntoDescriptor’s reader type is \"none\",\n        if let PullIntoDescriptorReaderType::None =\n            objects.controller.pending_pull_intos[pull_into_descriptor_index].reader_type\n        {\n            // Perform ? ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(controller, pullIntoDescriptor).\n            objects = Self::readable_byte_stream_enqueue_detached_pull_into_to_queue(\n                ctx.clone(),\n                objects,\n                pull_into_descriptor_index,\n            )?;\n            // Perform ! ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).\n            // Return.\n            return Self::readable_byte_stream_controller_process_pull_into_descriptors_using_queue(\n                &ctx, objects,\n            );\n        }\n\n        // If pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s minimum fill, return.\n        if objects.controller.pending_pull_intos[pull_into_descriptor_index].bytes_filled\n            < objects.controller.pending_pull_intos[pull_into_descriptor_index].minimum_fill\n        {\n            return Ok(objects);\n        }\n\n        // Perform ! ReadableByteStreamControllerShiftPendingPullInto(controller).\n        let mut pull_into_descriptor = objects\n            .controller\n            .readable_byte_stream_controller_shift_pending_pull_into();\n\n        // Let remainderSize be the remainder after dividing pullIntoDescriptor’s bytes filled by pullIntoDescriptor’s element size.\n        let remainder_size = pull_into_descriptor.bytes_filled % pull_into_descriptor.element_size;\n\n        // If remainderSize > 0,\n        if remainder_size > 0 {\n            // Let end be pullIntoDescriptor’s byte offset + pullIntoDescriptor’s bytes filled.\n            let end = pull_into_descriptor.byte_offset + pull_into_descriptor.bytes_filled;\n\n            let buffer = pull_into_descriptor.buffer.clone();\n\n            // Perform ? ReadableByteStreamControllerEnqueueClonedChunkToQueue(controller, pullIntoDescriptor’s buffer, end − remainderSize, remainderSize).\n            objects = Self::readable_byte_stream_controller_enqueue_cloned_chunk_to_queue(\n                ctx.clone(),\n                objects,\n                &buffer,\n                end - remainder_size,\n                remainder_size,\n            )?;\n        }\n\n        // Set pullIntoDescriptor’s bytes filled to pullIntoDescriptor’s bytes filled − remainderSize.\n        pull_into_descriptor.bytes_filled -= remainder_size;\n\n        // Perform ! ReadableByteStreamControllerCommitPullIntoDescriptor(controller.[[stream]], pullIntoDescriptor).\n        objects = Self::readable_byte_stream_controller_commit_pull_into_descriptor(\n            ctx.clone(),\n            objects,\n            pull_into_descriptor,\n        )?;\n\n        // Perform ! ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).\n        Self::readable_byte_stream_controller_process_pull_into_descriptors_using_queue(\n            &ctx, objects,\n        )\n    }\n\n    pub(super) fn readable_byte_stream_controller_respond_with_new_view<\n        R: ReadableStreamReader<'js>,\n    >(\n        ctx: Ctx<'js>,\n        mut objects: ReadableByteStreamObjects<'js, R>,\n        view: ViewBytes<'js>,\n    ) -> Result<()> {\n        // Let firstDescriptor be controller.[[pendingPullIntos]][0].\n        let first_descriptor_index = 0;\n\n        let (buffer, byte_length, byte_offset) = view.get_array_buffer()?;\n\n        // Let state be controller.[[stream]].[[state]].\n        match objects.stream.state {\n            // If state is \"closed\",\n            ReadableStreamState::Closed => {\n                // If view.[[ByteLength]] is not 0, throw a TypeError exception.\n                if byte_length != 0 {\n                    return Err(Exception::throw_type(&ctx, \"The view's length must be 0 when calling respondWithNewView() on a closed stream\"));\n                }\n            },\n            // Otherwise\n            _ => {\n                // If view.[[ByteLength]] is 0, throw a TypeError exception.\n                if byte_length == 0 {\n                    return Err(Exception::throw_type(&ctx, \"The view's length must be greater than 0 when calling respondWithNewView() on a readable stream\"));\n                }\n            },\n        };\n\n        {\n            let first_descriptor =\n                &mut objects.controller.pending_pull_intos[first_descriptor_index];\n\n            // If firstDescriptor’s byte offset + firstDescriptor’ bytes filled is not view.[[ByteOffset]], throw a RangeError exception.\n            if first_descriptor.byte_offset + first_descriptor.bytes_filled != byte_offset {\n                return Err(Exception::throw_range(\n                    &ctx,\n                    \"The region specified by view does not match byobRequest\",\n                ));\n            };\n\n            // If firstDescriptor’s buffer byte length is not view.[[ViewedArrayBuffer]].[[ByteLength]], throw a RangeError exception.\n            if first_descriptor.buffer_byte_length != buffer.len() {\n                return Err(Exception::throw_range(\n                    &ctx,\n                    \"The buffer of view has different capacity than byobRequest\",\n                ));\n            };\n\n            // If firstDescriptor’s bytes filled + view.[[ByteLength]] > firstDescriptor’s byte length, throw a RangeError exception.\n            if first_descriptor.bytes_filled + byte_length > first_descriptor.byte_length {\n                return Err(Exception::throw_range(\n                    &ctx,\n                    \"The region specified by view is larger than byobRequest\",\n                ));\n            }\n\n            // Set firstDescriptor’s buffer to ? TransferArrayBuffer(view.[[ViewedArrayBuffer]]).\n            first_descriptor.buffer = transfer_array_buffer(buffer)?;\n        }\n\n        // Perform ? ReadableByteStreamControllerRespondInternal(controller, viewByteLength).\n        Self::readable_byte_stream_controller_respond_internal(ctx, objects, byte_length)\n    }\n\n    fn readable_byte_stream_controller_fill_head_pull_into_descriptor<'a>(\n        &mut self,\n        size: usize,\n        pull_into_descriptor_ref: &mut PullIntoDescriptorRefMut<'js, 'a>,\n    ) {\n        let pull_into_descriptor = match pull_into_descriptor_ref {\n            PullIntoDescriptorRefMut::Index(i) => &mut self.pending_pull_intos[*i],\n            PullIntoDescriptorRefMut::Owned(r) => *r,\n        };\n\n        // Set pullIntoDescriptor’s bytes filled to bytes filled + size.\n        pull_into_descriptor.bytes_filled += size;\n    }\n\n    fn start_algorithm<R: ReadableStreamReader<'js>>(\n        ctx: Ctx<'js>,\n        objects: ReadableByteStreamObjects<'js, R>,\n        start_algorithm: StartAlgorithm<'js>,\n    ) -> Result<(\n        Value<'js>,\n        ReadableStreamClassObjects<'js, OwnedBorrowMut<'js, Self>, R>,\n    )> {\n        let objects_class = objects.into_inner();\n\n        Ok((\n            start_algorithm.call(\n                ctx,\n                ReadableStreamControllerClass::ReadableStreamByteController(\n                    objects_class.controller.clone(),\n                ),\n            )?,\n            objects_class,\n        ))\n    }\n\n    fn pull_algorithm<R: ReadableStreamReader<'js>>(\n        ctx: Ctx<'js>,\n        objects: ReadableByteStreamObjects<'js, R>,\n    ) -> Result<(\n        Promise<'js>,\n        ReadableStreamClassObjects<'js, OwnedBorrowMut<'js, Self>, R>,\n    )> {\n        let pull_algorithm = objects\n            .controller\n            .pull_algorithm\n            .clone()\n            .expect(\"pull algorithm used after ReadableStreamDefaultControllerClearAlgorithms\");\n        let promise_primordials = objects.stream.promise_primordials.clone();\n        let objects_class = objects.into_inner();\n\n        Ok((\n            pull_algorithm.call(\n                ctx,\n                &promise_primordials,\n                ReadableStreamControllerClass::ReadableStreamByteController(\n                    objects_class.controller.clone(),\n                ),\n            )?,\n            objects_class,\n        ))\n    }\n\n    fn cancel_algorithm<R: ReadableStreamReader<'js>>(\n        ctx: Ctx<'js>,\n        objects: ReadableByteStreamObjects<'js, R>,\n        reason: Value<'js>,\n    ) -> Result<(\n        Promise<'js>,\n        ReadableStreamClassObjects<'js, OwnedBorrowMut<'js, Self>, R>,\n    )> {\n        let cancel_algorithm =\n            objects.controller.cancel_algorithm.clone().expect(\n                \"cancel algorithm used after ReadableStreamDefaultControllerClearAlgorithms\",\n            );\n        let promise_primordials = objects.stream.promise_primordials.clone();\n        let objects_class = objects.into_inner();\n\n        Ok((\n            cancel_algorithm.call(ctx, &promise_primordials, reason)?,\n            objects_class,\n        ))\n    }\n}\n\n#[methods(rename_all = \"camelCase\")]\nimpl<'js> ReadableByteStreamController<'js> {\n    #[qjs(constructor)]\n    fn new(ctx: Ctx<'js>) -> Result<Class<'js, Self>> {\n        Err(Exception::throw_type(&ctx, \"Illegal constructor\"))\n    }\n\n    // readonly attribute unrestricted double? desiredSize;\n    #[qjs(get)]\n    fn byob_request(\n        ctx: Ctx<'js>,\n        controller: This<OwnedBorrowMut<'js, Self>>,\n    ) -> Result<Null<Class<'js, ReadableStreamBYOBRequest<'js>>>> {\n        let (request, _) =\n            Self::readable_byte_stream_controller_get_byob_request(ctx, controller.0)?;\n        Ok(request)\n    }\n\n    // readonly attribute unrestricted double? desiredSize;\n    #[qjs(get)]\n    fn desired_size(&self) -> Null<f64> {\n        let stream = OwnedBorrow::from_class(self.stream.clone());\n        self.readable_byte_stream_controller_get_desired_size(&stream)\n    }\n\n    // undefined close();\n    fn close(ctx: Ctx<'js>, controller: This<OwnedBorrowMut<'js, Self>>) -> Result<()> {\n        // If this.[[closeRequested]] is true, throw a TypeError exception.\n        if controller.close_requested {\n            return Err(Exception::throw_type(&ctx, \"close() called more than once\"));\n        }\n\n        let objects = ReadableStreamObjects::from_byte_controller(controller.0).refresh_reader();\n\n        if !matches!(objects.stream.state, ReadableStreamState::Readable) {\n            return Err(Exception::throw_type(\n                &ctx,\n                \"close() called when stream is not readable\",\n            ));\n        };\n\n        // Perform ? ReadableByteStreamControllerClose(this).\n        Self::readable_byte_stream_controller_close(ctx, objects)?;\n        Ok(())\n    }\n\n    // undefined enqueue(ArrayBufferView chunk);\n    fn enqueue(\n        this: This<OwnedBorrowMut<'js, Self>>,\n        ctx: Ctx<'js>,\n        chunk: Value<'js>,\n    ) -> Result<()> {\n        let chunk = ViewBytes::from_value(&ctx, &this.function_array_buffer_is_view, Some(&chunk))?;\n\n        let (array_buffer, byte_length, _) = chunk.get_array_buffer()?;\n\n        // If chunk.[[ByteLength]] is 0, throw a TypeError exception.\n        if byte_length == 0 {\n            return Err(Exception::throw_type(\n                &ctx,\n                \"chunk must have non-zero byteLength\",\n            ));\n        }\n\n        // If chunk.[[ViewedArrayBuffer]].[[ArrayBufferByteLength]] is 0, throw a TypeError exception.\n        if array_buffer.is_empty() {\n            return Err(Exception::throw_type(\n                &ctx,\n                \"chunk must have non-zero buffer byteLength\",\n            ));\n        }\n\n        // If this.[[closeRequested]] is true, throw a TypeError exception.\n        if this.close_requested {\n            return Err(Exception::throw_type(&ctx, \"stream is closed or draining\"));\n        }\n\n        let objects = ReadableStreamObjects::from_byte_controller(this.0).refresh_reader();\n\n        // If this.[[stream]].[[state]] is not \"readable\", throw a TypeError exception.\n        if !matches!(objects.stream.state, ReadableStreamState::Readable) {\n            return Err(Exception::throw_type(\n                &ctx,\n                \"The stream is not in the readable state and cannot be enqueued to\",\n            ));\n        };\n\n        // Return ? ReadableByteStreamControllerEnqueue(this, chunk).\n        Self::readable_byte_stream_controller_enqueue(&ctx, objects, chunk)?;\n        Ok(())\n    }\n\n    // undefined error(optional any e);\n    fn error(\n        ctx: Ctx<'js>,\n        controller: This<OwnedBorrowMut<'js, Self>>,\n        e: Opt<Value<'js>>,\n    ) -> Result<()> {\n        let objects = ReadableStreamObjects::from_byte_controller(controller.0).refresh_reader();\n\n        // Perform ! ReadableByteStreamControllerError(this, e).\n        Self::readable_byte_stream_controller_error(objects, e.0.unwrap_or_undefined(&ctx))?;\n        Ok(())\n    }\n}\n\nimpl<'js> ReadableStreamController<'js> for ReadableByteStreamControllerOwned<'js> {\n    type Class = ReadableByteStreamControllerClass<'js>;\n\n    fn with_controller<C, O>(\n        self,\n        ctx: C,\n        _: impl FnOnce(\n            C,\n            ReadableStreamDefaultControllerOwned<'js>,\n        ) -> Result<(O, ReadableStreamDefaultControllerOwned<'js>)>,\n        byte: impl FnOnce(\n            C,\n            ReadableByteStreamControllerOwned<'js>,\n        ) -> Result<(O, ReadableByteStreamControllerOwned<'js>)>,\n    ) -> Result<(O, Self)> {\n        let (ctx, reader) = byte(ctx, self)?;\n        Ok((ctx, reader))\n    }\n\n    fn into_inner(self) -> Self::Class {\n        OwnedBorrowMut::into_inner(self)\n    }\n\n    fn from_class(class: Self::Class) -> Self {\n        OwnedBorrowMut::from_class(class)\n    }\n\n    fn into_erased(self) -> ReadableStreamControllerOwned<'js> {\n        ReadableStreamControllerOwned::ReadableStreamByteController(self)\n    }\n\n    fn try_from_erased(erased: ReadableStreamControllerOwned<'js>) -> Option<Self> {\n        match erased {\n            ReadableStreamControllerOwned::ReadableStreamDefaultController(_) => None,\n            ReadableStreamControllerOwned::ReadableStreamByteController(r) => Some(r),\n        }\n    }\n\n    fn pull_steps(\n        ctx: &Ctx<'js>,\n        mut objects: ReadableStreamDefaultReaderObjects<'js, Self>,\n        read_request: impl ReadableStreamReadRequest<'js> + 'js,\n    ) -> Result<ReadableStreamDefaultReaderObjects<'js, Self>> {\n        // If this.[[queueTotalSize]] > 0,\n        if objects.controller.queue_total_size > 0 {\n            // Perform ! ReadableByteStreamControllerFillReadRequestFromQueue(this, readRequest).\n            // Return.\n            return ReadableByteStreamController::readable_byte_stream_controller_fill_read_request_from_queue(\n                ctx,\n                objects,\n                read_request,\n            );\n        }\n\n        // Let autoAllocateChunkSize be this.[[autoAllocateChunkSize]].\n        let auto_allocate_chunk_size = objects.controller.auto_allocate_chunk_size;\n\n        // If autoAllocateChunkSize is not undefined,\n        if let Some(auto_allocate_chunk_size) = auto_allocate_chunk_size {\n            // Let buffer be Construct(%ArrayBuffer%, « autoAllocateChunkSize »).\n            let buffer: ArrayBuffer = match objects\n                .controller\n                .constructor_array_buffer\n                .construct((auto_allocate_chunk_size,))\n            {\n                // If buffer is an abrupt completion,\n                Err(Error::Exception) => {\n                    // Perform readRequest’s error steps, given buffer.[[Value]].\n                    return read_request.error_steps_typed(objects, ctx.catch());\n                },\n                Err(err) => return Err(err),\n                Ok(buffer) => buffer,\n            };\n\n            // Let pullIntoDescriptor be a new pull-into descriptor with...\n            let pull_into_descriptor = PullIntoDescriptor {\n                buffer,\n                buffer_byte_length: auto_allocate_chunk_size,\n                byte_offset: 0,\n                byte_length: auto_allocate_chunk_size,\n                bytes_filled: 0,\n                minimum_fill: 1,\n                element_size: 1,\n                view_constructor: objects\n                    .controller\n                    .array_constructor_primordials\n                    .constructor_uint8array\n                    .clone(),\n                reader_type: PullIntoDescriptorReaderType::Default,\n            };\n\n            // Append pullIntoDescriptor to this.[[pendingPullIntos]].\n            objects\n                .controller\n                .pending_pull_intos\n                .push_back(pull_into_descriptor);\n        }\n\n        // Perform ! ReadableStreamAddReadRequest(stream, readRequest).\n        objects\n            .stream\n            .readable_stream_add_read_request(&mut objects.reader, read_request);\n\n        // Perform ! ReadableByteStreamControllerCallPullIfNeeded(this).\n        ReadableByteStreamController::readable_byte_stream_controller_call_pull_if_needed(\n            ctx.clone(),\n            objects,\n        )\n    }\n\n    fn cancel_steps<R: ReadableStreamReader<'js>>(\n        ctx: &Ctx<'js>,\n        mut objects: ReadableStreamObjects<'js, Self, R>,\n        reason: Value<'js>,\n    ) -> Result<(Promise<'js>, ReadableStreamObjects<'js, Self, R>)> {\n        // Perform ! ReadableByteStreamControllerClearPendingPullIntos(this).\n        objects\n            .controller\n            .readable_byte_stream_controller_clear_pending_pull_intos();\n\n        // Perform ! ResetQueue(this).\n        objects.controller.reset_queue();\n\n        // Let result be the result of performing this.[[cancelAlgorithm]], passing in reason.\n        let (result, objects_class) =\n            ReadableByteStreamController::cancel_algorithm(ctx.clone(), objects, reason)?;\n\n        objects = ReadableStreamObjects::from_class(objects_class);\n\n        // Perform ! ReadableByteStreamControllerClearAlgorithms(this).\n        objects\n            .controller\n            .readable_byte_stream_controller_clear_algorithms();\n\n        // Return result.\n        Ok((result, objects))\n    }\n\n    fn release_steps(&mut self) {\n        // If this.[[pendingPullIntos]] is not empty,\n        if !self.pending_pull_intos.is_empty() {\n            // Let firstPendingPullInto be this.[[pendingPullIntos]][0].\n            let first_pending_pull_into = &mut self.pending_pull_intos[0];\n\n            // Set firstPendingPullInto’s reader type to \"none\".\n            first_pending_pull_into.reader_type = PullIntoDescriptorReaderType::None;\n\n            // Set this.[[pendingPullIntos]] to the list « firstPendingPullInto ».\n            _ = self.pending_pull_intos.split_off(1);\n        }\n    }\n}\n\n#[derive(JsLifetime, Trace, Clone)]\n#[rquickjs::class]\npub(crate) struct ReadableStreamBYOBRequest<'js> {\n    pub(super) view: Option<ViewBytes<'js>>,\n    controller: Option<ReadableByteStreamControllerClass<'js>>,\n}\n\n#[methods(rename_all = \"camelCase\")]\nimpl<'js> ReadableStreamBYOBRequest<'js> {\n    #[qjs(constructor)]\n    fn new(ctx: Ctx<'js>) -> Result<Class<'js, Self>> {\n        Err(Exception::throw_type(&ctx, \"Illegal constructor\"))\n    }\n\n    #[qjs(get)]\n    fn view(&self) -> Null<ViewBytes<'js>> {\n        Null(self.view.clone())\n    }\n\n    fn respond(\n        ctx: Ctx<'js>,\n        byob_request: This<OwnedBorrowMut<'js, Self>>,\n        bytes_written: usize,\n    ) -> Result<()> {\n        // If this.[[controller]] is undefined, throw a TypeError exception.\n        let (controller, view) = match (&byob_request.controller, &byob_request.view) {\n            (Some(controller), Some(view)) => (controller.clone(), view),\n            _ => {\n                return Err(Exception::throw_type(\n                    &ctx,\n                    \"This BYOB request has been invalidated\",\n                ));\n            },\n        };\n        let (buffer, _, _) = view.get_array_buffer()?;\n        drop(byob_request);\n\n        // If ! IsDetachedBuffer(this.[[view]].[[ArrayBuffer]]) is true, throw a TypeError exception.\n        if buffer.as_bytes().is_none() {\n            return Err(Exception::throw_type(\n                &ctx,\n                \"The BYOB request's buffer has been detached and so cannot be used as a response\",\n            ));\n        }\n\n        let objects =\n            ReadableStreamObjects::from_byte_controller(OwnedBorrowMut::from_class(controller))\n                .refresh_reader();\n\n        // Perform ? ReadableByteStreamControllerRespond(this.[[controller]], bytesWritten).\n        ReadableByteStreamController::readable_byte_stream_controller_respond(\n            ctx,\n            objects,\n            bytes_written,\n        )\n    }\n\n    fn respond_with_new_view(\n        ctx: Ctx<'js>,\n        byob_request: This<OwnedBorrowMut<'js, Self>>,\n        view: Opt<Value<'js>>,\n    ) -> Result<()> {\n        // If this.[[controller]] is undefined, throw a TypeError exception.\n        let controller = match &byob_request.controller {\n            Some(controller) => controller.clone(),\n            _ => {\n                return Err(Exception::throw_type(\n                    &ctx,\n                    \"This BYOB request has been invalidated\",\n                ));\n            },\n        };\n        drop(byob_request);\n\n        let controller = OwnedBorrowMut::from_class(controller);\n\n        let view = ViewBytes::from_value(\n            &ctx,\n            &controller.function_array_buffer_is_view,\n            view.0.as_ref(),\n        )?;\n\n        let (buffer, _, _) = view.get_array_buffer()?;\n\n        // If ! IsDetachedBuffer(view.[[ViewedArrayBuffer]]) is true, throw a TypeError exception.\n        if buffer.as_bytes().is_none() {\n            return Err(Exception::throw_type(\n                &ctx,\n                \"The given view's buffer has been detached and so cannot be used as a response\",\n            ));\n        }\n\n        let objects = ReadableStreamObjects::from_byte_controller(controller).refresh_reader();\n\n        // Return ? ReadableByteStreamControllerRespondWithNewView(this.[[controller]], view).\n        ReadableByteStreamController::readable_byte_stream_controller_respond_with_new_view(\n            ctx, objects, view,\n        )\n    }\n}\n\n#[derive(JsLifetime)]\npub(super) struct PullIntoDescriptor<'js> {\n    buffer: ArrayBuffer<'js>,\n    buffer_byte_length: usize,\n    byte_offset: usize,\n    byte_length: usize,\n    bytes_filled: usize,\n    minimum_fill: usize,\n    element_size: usize,\n    view_constructor: Constructor<'js>,\n    reader_type: PullIntoDescriptorReaderType,\n}\n\nimpl<'js> Trace<'js> for PullIntoDescriptor<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.buffer.trace(tracer);\n        self.buffer_byte_length.trace(tracer);\n        self.byte_offset.trace(tracer);\n        self.byte_length.trace(tracer);\n        self.bytes_filled.trace(tracer);\n        self.minimum_fill.trace(tracer);\n        self.element_size.trace(tracer);\n        self.view_constructor.trace(tracer);\n        self.reader_type.trace(tracer);\n    }\n}\n\nenum PullIntoDescriptorRefMut<'js, 'a> {\n    Index(usize),\n    Owned(&'a mut PullIntoDescriptor<'js>),\n}\n\n#[derive(Trace, Clone, Copy)]\nenum PullIntoDescriptorReaderType {\n    Default,\n    Byob,\n    None,\n}\n\n#[derive(JsLifetime)]\nstruct ReadableByteStreamQueueEntry<'js> {\n    buffer: ArrayBuffer<'js>,\n    byte_offset: usize,\n    byte_length: usize,\n}\n\nimpl<'js> Trace<'js> for ReadableByteStreamQueueEntry<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.buffer.trace(tracer);\n        self.byte_offset.trace(tracer);\n        self.byte_length.trace(tracer)\n    }\n}\n\nfn transfer_array_buffer(buffer: ArrayBuffer<'_>) -> Result<ArrayBuffer<'_>> {\n    buffer.get::<_, Function>(\"transfer\")?.call((This(buffer),))\n}\n\nfn copy_data_block_bytes(\n    ctx: &Ctx<'_>,\n    to_block: &ArrayBuffer,\n    to_index: usize,\n    from_block: &ArrayBuffer,\n    from_index: usize,\n    count: usize,\n) -> Result<()> {\n    let to_raw = to_block\n        .as_raw()\n        .ok_or(ERROR_MSG_ARRAY_BUFFER_DETACHED)\n        .or_throw(ctx)?;\n    let to_slice = unsafe { std::slice::from_raw_parts_mut(to_raw.ptr.as_ptr(), to_raw.len) };\n    let from_raw = from_block\n        .as_raw()\n        .ok_or(ERROR_MSG_ARRAY_BUFFER_DETACHED)\n        .or_throw(ctx)?;\n    let from_slice = unsafe { std::slice::from_raw_parts(from_raw.ptr.as_ptr(), from_raw.len) };\n\n    to_slice[to_index..to_index + count]\n        .copy_from_slice(&from_slice[from_index..from_index + count]);\n    Ok(())\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/readable/controller.rs",
    "content": "use rquickjs::{\n    class::{OwnedBorrowMut, Trace},\n    Ctx, IntoJs, JsLifetime, Promise, Result, Value,\n};\n\nuse crate::readable::{\n    byte_controller::{ReadableByteStreamControllerClass, ReadableByteStreamControllerOwned},\n    default_controller::{\n        ReadableStreamDefaultControllerClass, ReadableStreamDefaultControllerOwned,\n    },\n    default_reader::ReadableStreamReadRequest,\n    objects::{ReadableStreamDefaultReaderObjects, ReadableStreamObjects},\n    reader::ReadableStreamReader,\n};\n\npub(super) trait ReadableStreamController<'js>: Sized {\n    type Class: Clone + Trace<'js>;\n\n    fn with_controller<C, O>(\n        self,\n        ctx: C,\n        default: impl FnOnce(\n            C,\n            ReadableStreamDefaultControllerOwned<'js>,\n        ) -> Result<(O, ReadableStreamDefaultControllerOwned<'js>)>,\n        byte: impl FnOnce(\n            C,\n            ReadableByteStreamControllerOwned<'js>,\n        ) -> Result<(O, ReadableByteStreamControllerOwned<'js>)>,\n    ) -> Result<(O, Self)>;\n\n    fn into_inner(self) -> Self::Class;\n    fn from_class(class: Self::Class) -> Self;\n\n    fn into_erased(self) -> ReadableStreamControllerOwned<'js>;\n    fn try_from_erased(erased: ReadableStreamControllerOwned<'js>) -> Option<Self>;\n\n    fn pull_steps(\n        ctx: &Ctx<'js>,\n        objects: ReadableStreamDefaultReaderObjects<'js, Self>,\n        read_request: impl ReadableStreamReadRequest<'js> + 'js,\n    ) -> Result<ReadableStreamDefaultReaderObjects<'js, Self>>;\n\n    fn cancel_steps<R: ReadableStreamReader<'js>>(\n        ctx: &Ctx<'js>,\n        objects: ReadableStreamObjects<'js, Self, R>,\n        reason: Value<'js>,\n    ) -> Result<(Promise<'js>, ReadableStreamObjects<'js, Self, R>)>;\n\n    fn release_steps(&mut self);\n}\n\n#[derive(JsLifetime, Trace, Clone)]\npub enum ReadableStreamControllerClass<'js> {\n    ReadableStreamDefaultController(ReadableStreamDefaultControllerClass<'js>),\n    ReadableStreamByteController(ReadableByteStreamControllerClass<'js>),\n    Uninitialised, // Only for use when initialising a Stream - should never be present later on\n}\n\nimpl<'js> IntoJs<'js> for ReadableStreamControllerClass<'js> {\n    fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {\n        match self {\n            Self::ReadableStreamDefaultController(c) => c.into_js(ctx),\n            Self::ReadableStreamByteController(c) => c.into_js(ctx),\n            Self::Uninitialised => {\n                panic!(\"Tried to convert an uninitialised controller class to JS\")\n            },\n        }\n    }\n}\n\npub(super) enum ReadableStreamControllerOwned<'js> {\n    ReadableStreamDefaultController(ReadableStreamDefaultControllerOwned<'js>),\n    ReadableStreamByteController(ReadableByteStreamControllerOwned<'js>),\n}\n\nimpl<'js> ReadableStreamController<'js> for ReadableStreamControllerOwned<'js> {\n    type Class = ReadableStreamControllerClass<'js>;\n\n    fn with_controller<C, O>(\n        self,\n        ctx: C,\n        default: impl FnOnce(\n            C,\n            ReadableStreamDefaultControllerOwned<'js>,\n        ) -> Result<(O, ReadableStreamDefaultControllerOwned<'js>)>,\n        byob: impl FnOnce(\n            C,\n            ReadableByteStreamControllerOwned<'js>,\n        ) -> Result<(O, ReadableByteStreamControllerOwned<'js>)>,\n    ) -> Result<(O, Self)> {\n        match self {\n            ReadableStreamControllerOwned::ReadableStreamDefaultController(r) => {\n                let (ctx, r) = default(ctx, r)?;\n                Ok((ctx, Self::ReadableStreamDefaultController(r)))\n            },\n            ReadableStreamControllerOwned::ReadableStreamByteController(r) => {\n                let (ctx, r) = byob(ctx, r)?;\n                Ok((ctx, Self::ReadableStreamByteController(r)))\n            },\n        }\n    }\n\n    fn into_inner(self) -> Self::Class {\n        match self {\n            ReadableStreamControllerOwned::ReadableStreamDefaultController(c) => {\n                ReadableStreamControllerClass::ReadableStreamDefaultController(c.into_inner())\n            },\n            ReadableStreamControllerOwned::ReadableStreamByteController(c) => {\n                ReadableStreamControllerClass::ReadableStreamByteController(c.into_inner())\n            },\n        }\n    }\n\n    fn from_class(class: Self::Class) -> Self {\n        match class {\n            ReadableStreamControllerClass::ReadableStreamDefaultController(class) => {\n                ReadableStreamControllerOwned::ReadableStreamDefaultController(\n                    OwnedBorrowMut::from_class(class),\n                )\n            },\n            ReadableStreamControllerClass::ReadableStreamByteController(class) => {\n                ReadableStreamControllerOwned::ReadableStreamByteController(\n                    OwnedBorrowMut::from_class(class),\n                )\n            },\n            ReadableStreamControllerClass::Uninitialised => {\n                panic!(\"Tried to borrow an uninitialised controller class\")\n            },\n        }\n    }\n\n    fn into_erased(self) -> ReadableStreamControllerOwned<'js> {\n        self\n    }\n\n    fn try_from_erased(erased: ReadableStreamControllerOwned<'js>) -> Option<Self> {\n        Some(erased)\n    }\n\n    fn pull_steps(\n        ctx: &Ctx<'js>,\n        objects: ReadableStreamDefaultReaderObjects<'js, Self>,\n        read_request: impl ReadableStreamReadRequest<'js> + 'js,\n    ) -> Result<ReadableStreamDefaultReaderObjects<'js, Self>> {\n        objects\n            .with_controller(\n                read_request,\n                |read_request, objects| {\n                    ReadableStreamDefaultControllerOwned::<'js>::pull_steps(\n                        ctx,\n                        objects,\n                        read_request,\n                    )\n                    .map(|objects| ((), objects))\n                },\n                |read_request, objects| {\n                    ReadableByteStreamControllerOwned::<'js>::pull_steps(ctx, objects, read_request)\n                        .map(|objects| ((), objects))\n                },\n            )\n            .map(|((), objects)| objects)\n    }\n\n    fn cancel_steps<R: ReadableStreamReader<'js>>(\n        ctx: &Ctx<'js>,\n        objects: ReadableStreamObjects<'js, Self, R>,\n        reason: Value<'js>,\n    ) -> Result<(Promise<'js>, ReadableStreamObjects<'js, Self, R>)> {\n        objects.with_controller(\n            reason,\n            |reason, objects| {\n                ReadableStreamDefaultControllerOwned::<'js>::cancel_steps(ctx, objects, reason)\n            },\n            |reason, objects| {\n                ReadableByteStreamControllerOwned::<'js>::cancel_steps(ctx, objects, reason)\n            },\n        )\n    }\n\n    fn release_steps(&mut self) {\n        match self {\n            ReadableStreamControllerOwned::ReadableStreamDefaultController(c) => c.release_steps(),\n            ReadableStreamControllerOwned::ReadableStreamByteController(c) => c.release_steps(),\n        }\n    }\n}\n\nimpl<'js> From<ReadableStreamDefaultControllerOwned<'js>> for ReadableStreamControllerOwned<'js> {\n    fn from(value: ReadableStreamDefaultControllerOwned<'js>) -> Self {\n        Self::ReadableStreamDefaultController(value)\n    }\n}\n\nimpl<'js> From<ReadableByteStreamControllerOwned<'js>> for ReadableStreamControllerOwned<'js> {\n    fn from(value: ReadableByteStreamControllerOwned<'js>) -> Self {\n        Self::ReadableStreamByteController(value)\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/readable/default_controller.rs",
    "content": "use llrt_utils::option::{Null, Undefined};\nuse rquickjs::{\n    class::{OwnedBorrow, OwnedBorrowMut, Trace},\n    methods,\n    prelude::{Opt, This},\n    Class, Ctx, Error, Exception, JsLifetime, Object, Promise, Result, Value,\n};\n\nuse crate::{\n    queuing_strategy::{SizeAlgorithm, SizeValue},\n    readable::{\n        byte_controller::ReadableByteStreamControllerOwned,\n        controller::{\n            ReadableStreamController, ReadableStreamControllerClass, ReadableStreamControllerOwned,\n        },\n        default_reader::{ReadableStreamDefaultReaderOrUndefined, ReadableStreamReadRequest},\n        objects::{\n            ReadableStreamClassObjects, ReadableStreamDefaultControllerObjects,\n            ReadableStreamDefaultReaderObjects, ReadableStreamObjects,\n        },\n        reader::ReadableStreamReader,\n        stream::{\n            algorithms::{CancelAlgorithm, PullAlgorithm, StartAlgorithm},\n            source::UnderlyingSource,\n            ReadableStream, ReadableStreamClass, ReadableStreamOwned, ReadableStreamState,\n        },\n    },\n    utils::{\n        class_from_owned_borrow_mut,\n        promise::{promise_resolved_with, upon_promise},\n        queue::QueueWithSizes,\n        UnwrapOrUndefined,\n    },\n};\n\n#[derive(JsLifetime, Trace)]\n#[rquickjs::class]\npub(crate) struct ReadableStreamDefaultController<'js> {\n    cancel_algorithm: Option<CancelAlgorithm<'js>>,\n    close_requested: bool,\n    pull_again: bool,\n    pull_algorithm: Option<PullAlgorithm<'js>>,\n    pulling: bool,\n    container: QueueWithSizes<'js>,\n    started: bool,\n    strategy_hwm: f64,\n    strategy_size_algorithm: Option<SizeAlgorithm<'js>>,\n    pub(super) stream: ReadableStreamClass<'js>,\n}\n\npub(super) type ReadableStreamDefaultControllerClass<'js> =\n    Class<'js, ReadableStreamDefaultController<'js>>;\npub(super) type ReadableStreamDefaultControllerOwned<'js> =\n    OwnedBorrowMut<'js, ReadableStreamDefaultController<'js>>;\n\nimpl<'js> ReadableStreamDefaultController<'js> {\n    pub(super) fn set_up_readable_stream_default_controller_from_underlying_source(\n        ctx: Ctx<'js>,\n        stream: ReadableStreamOwned<'js>,\n        underlying_source: Null<Undefined<Object<'js>>>,\n        underlying_source_dict: UnderlyingSource<'js>,\n        high_water_mark: f64,\n        size_algorithm: SizeAlgorithm<'js>,\n    ) -> Result<()> {\n        let (start_algorithm, pull_algorithm, cancel_algorithm) = (\n            // If underlyingSourceDict[\"start\"] exists, then set startAlgorithm to an algorithm which returns the result of invoking underlyingSourceDict[\"start\"] with argument list\n            // « controller » and callback this value underlyingSource.\n            underlying_source_dict\n                .start\n                .map(|f| StartAlgorithm::Function {\n                    f,\n                    underlying_source: underlying_source.clone(),\n                })\n                .unwrap_or(StartAlgorithm::ReturnUndefined),\n            // If underlyingSourceDict[\"pull\"] exists, then set pullAlgorithm to an algorithm which returns the result of invoking underlyingSourceDict[\"pull\"] with argument list\n            // « controller » and callback this value underlyingSource.\n            underlying_source_dict\n                .pull\n                .map(|f| PullAlgorithm::Function {\n                    f,\n                    underlying_source: underlying_source.clone(),\n                })\n                .unwrap_or(PullAlgorithm::ReturnPromiseUndefined),\n            // If underlyingSourceDict[\"cancel\"] exists, then set cancelAlgorithm to an algorithm which takes an argument reason and returns the result of invoking underlyingSourceDict[\"cancel\"] with argument list\n            // « reason » and callback this value underlyingSource.\n            underlying_source_dict\n                .cancel\n                .map(|f| CancelAlgorithm::Function {\n                    f,\n                    underlying_source,\n                })\n                .unwrap_or(CancelAlgorithm::ReturnPromiseUndefined),\n        );\n\n        // Perform ? SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm).\n        Self::set_up_readable_stream_default_controller(\n            ctx.clone(),\n            stream,\n            start_algorithm,\n            pull_algorithm,\n            cancel_algorithm,\n            high_water_mark,\n            size_algorithm,\n        )?;\n\n        Ok(())\n    }\n\n    pub(super) fn set_up_readable_stream_default_controller(\n        ctx: Ctx<'js>,\n        stream: ReadableStreamOwned<'js>,\n        start_algorithm: StartAlgorithm<'js>,\n        pull_algorithm: PullAlgorithm<'js>,\n        cancel_algorithm: CancelAlgorithm<'js>,\n        high_water_mark: f64,\n        size_algorithm: SizeAlgorithm<'js>,\n    ) -> Result<Class<'js, Self>> {\n        let (stream_class, mut stream) = class_from_owned_borrow_mut(stream);\n\n        let controller = ReadableStreamDefaultController {\n            // Set controller.[[stream]] to stream.\n            stream: stream_class.clone(),\n\n            // Perform ! ResetQueue(controller).\n            container: QueueWithSizes::new(),\n\n            // Set controller.[[started]], controller.[[closeRequested]], controller.[[pullAgain]], and controller.[[pulling]] to false.\n            started: false,\n            close_requested: false,\n            pull_again: false,\n            pulling: false,\n\n            // Set controller.[[strategySizeAlgorithm]] to sizeAlgorithm and controller.[[strategyHWM]] to highWaterMark.\n            strategy_size_algorithm: Some(size_algorithm),\n            strategy_hwm: high_water_mark,\n\n            // Set controller.[[pullAlgorithm]] to pullAlgorithm.\n            pull_algorithm: Some(pull_algorithm),\n            // Set controller.[[cancelAlgorithm]] to cancelAlgorithm.\n            cancel_algorithm: Some(cancel_algorithm),\n        };\n\n        let controller_class = Class::instance(ctx.clone(), controller)?;\n\n        // Set stream.[[controller]] to controller.\n        stream.controller = ReadableStreamControllerClass::ReadableStreamDefaultController(\n            controller_class.clone(),\n        );\n\n        let objects = ReadableStreamObjects::new_default(\n            stream,\n            OwnedBorrowMut::from_class(controller_class),\n        );\n\n        let promise_primordials = objects.stream.promise_primordials.clone();\n\n        // Let startResult be the result of performing startAlgorithm. (This might throw an exception.)\n        let (start_result, objects_class) =\n            Self::start_algorithm(ctx.clone(), objects, start_algorithm)?;\n\n        // Let startPromise be a promise resolved with startResult.\n        let start_promise = promise_resolved_with(&ctx, &promise_primordials, Ok(start_result))?;\n\n        let _ = upon_promise::<Value<'js>, _>(ctx.clone(), start_promise, {\n            let objects_class = objects_class.clone();\n            move |ctx, result| {\n                let mut objects =\n                    ReadableStreamObjects::from_class_no_reader(objects_class).refresh_reader();\n\n                match result {\n                    // Upon fulfillment of startPromise,\n                    Ok(_) => {\n                        // Set controller.[[started]] to true.\n                        objects.controller.started = true;\n                        // Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).\n                        Self::readable_stream_default_controller_call_pull_if_needed(ctx, objects)?;\n                    },\n                    // Upon rejection of startPromise with reason r,\n                    Err(r) => {\n                        // Perform ! ReadableByteStreamControllerError(controller, r).\n                        Self::readable_stream_default_controller_error(objects, r)?;\n                    },\n                }\n                Ok(())\n            }\n        })?;\n\n        Ok(objects_class.controller)\n    }\n\n    fn readable_stream_default_controller_call_pull_if_needed<\n        R: ReadableStreamDefaultReaderOrUndefined<'js>,\n    >(\n        ctx: Ctx<'js>,\n        objects: ReadableStreamDefaultControllerObjects<'js, R>,\n    ) -> Result<ReadableStreamDefaultControllerObjects<'js, R>> {\n        // Let shouldPull be ! ReadableStreamDefaultControllerShouldCallPull(controller).\n\n        let (should_pull, mut objects) =\n            ReadableStreamDefaultController::readable_stream_default_controller_should_call_pull(\n                objects,\n            );\n\n        // If shouldPull is false, return.\n        if !should_pull {\n            return Ok(objects);\n        }\n\n        // If controller.[[pulling]] is true,\n        if objects.controller.pulling {\n            // Set controller.[[pullAgain]] to true.\n            objects.controller.pull_again = true;\n\n            // Return.\n            return Ok(objects);\n        }\n\n        // Set controller.[[pulling]] to true.\n        objects.controller.pulling = true;\n\n        // Let pullPromise be the result of performing controller.[[pullAlgorithm]].\n        let (pull_promise, objects_class) = Self::pull_algorithm(ctx.clone(), objects)?;\n\n        upon_promise::<Value<'js>, _>(ctx.clone(), pull_promise, {\n            let objects_class = objects_class.clone();\n            move |ctx, result| {\n                let mut objects =\n                    ReadableStreamObjects::from_class_no_reader(objects_class).refresh_reader();\n                match result {\n                    // Upon fulfillment of pullPromise,\n                    Ok(_) => {\n                        // Set controller.[[pulling]] to false.\n                        objects.controller.pulling = false;\n                        // If controller.[[pullAgain]] is true,\n                        if objects.controller.pull_again {\n                            // Set controller.[[pullAgain]] to false.\n                            objects.controller.pull_again = false;\n                            // Perform ! ReadableStreamDefaultControllerCallPullIfNeeded(controller).\n                            Self::readable_stream_default_controller_call_pull_if_needed(\n                                ctx, objects,\n                            )?;\n                        };\n                        Ok(())\n                    },\n                    // Upon rejection of pullPromise with reason e,\n                    Err(e) => {\n                        // Perform ! ReadableStreamDefaultControllerError(controller, e).\n                        Self::readable_stream_default_controller_error(objects, e)?;\n                        Ok(())\n                    },\n                }\n            }\n        })?;\n\n        Ok(ReadableStreamObjects::from_class(objects_class))\n    }\n\n    pub(super) fn readable_stream_default_controller_error<R: ReadableStreamReader<'js>>(\n        // Let stream be controller.[[stream]].\n        mut objects: ReadableStreamDefaultControllerObjects<'js, R>,\n        e: Value<'js>,\n    ) -> Result<ReadableStreamDefaultControllerObjects<'js, R>> {\n        // If stream.[[state]] is not \"readable\", return.\n        if !matches!(objects.stream.state, ReadableStreamState::Readable) {\n            return Ok(objects);\n        };\n\n        // Perform ! ResetQueue(controller).\n        objects.controller.container.reset_queue();\n\n        // Perform ! ReadableStreamDefaultControllerClearAlgorithms(controller).\n        objects\n            .controller\n            .readable_stream_default_controller_clear_algorithms();\n\n        // Perform ! ReadableStreamError(stream, e).\n        ReadableStream::readable_stream_error(objects, e)\n    }\n\n    fn readable_stream_default_controller_should_call_pull<\n        R: ReadableStreamDefaultReaderOrUndefined<'js>,\n    >(\n        mut objects: ReadableStreamDefaultControllerObjects<'js, R>,\n    ) -> (bool, ReadableStreamDefaultControllerObjects<'js, R>) {\n        // Let stream be controller.[[stream]].\n        // If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(controller) is false, return false.\n        if !objects\n            .controller\n            .readable_stream_default_controller_can_close_or_enqueue(&objects.stream)\n        {\n            return (false, objects);\n        }\n\n        // If controller.[[started]] is false, return false.\n        if !objects.controller.started {\n            return (false, objects);\n        }\n\n        {\n            let mut ret = false;\n            // If ! IsReadableStreamLocked(stream) is true and ! ReadableStreamGetNumReadRequests(stream) > 0, return true.\n            objects = objects\n                .with_some_reader(\n                    |objects| {\n                        if ReadableStream::readable_stream_get_num_read_requests(&objects.reader)\n                            > 0\n                        {\n                            ret = true\n                        }\n                        Ok(objects)\n                    },\n                    Ok,\n                )\n                .unwrap();\n            if ret {\n                return (true, objects);\n            }\n        }\n\n        // Let desiredSize be ! ReadableStreamDefaultControllerGetDesiredSize(controller).\n        let desired_size = objects.controller\n            .readable_stream_default_controller_get_desired_size(&objects.stream)\n            .0\n            .expect(\n            \"desiredSize should not be null during ReadableStreamDefaultControllerShouldCallPull\",\n        );\n        // If desiredSize > 0, return true.\n        if desired_size > 0.0 {\n            return (true, objects);\n        }\n\n        // Return false.\n        (false, objects)\n    }\n\n    fn readable_stream_default_controller_clear_algorithms(&mut self) {\n        self.pull_algorithm = None;\n        self.cancel_algorithm = None;\n        self.strategy_size_algorithm = None;\n    }\n\n    fn readable_stream_default_controller_can_close_or_enqueue(\n        &self,\n        stream: &ReadableStream<'js>,\n    ) -> bool {\n        // Let state be controller.[[stream]].[[state]].\n        match stream.state {\n            // If controller.[[closeRequested]] is false and state is \"readable\", return true.\n            ReadableStreamState::Readable if !self.close_requested => true,\n            // Otherwise, return false.\n            _ => false,\n        }\n    }\n\n    fn readable_stream_default_controller_get_desired_size(\n        &self,\n        stream: &ReadableStream<'js>,\n    ) -> Null<f64> {\n        // Let state be controller.[[stream]].[[state]].\n        match stream.state {\n            // If state is \"errored\", return null.\n            ReadableStreamState::Errored(_) => Null(None),\n            // If state is \"closed\", return 0.\n            ReadableStreamState::Closed => Null(Some(0.0)),\n            // Return controller.[[strategyHWM]] − controller.[[queueTotalSize]].\n            ReadableStreamState::Readable => {\n                Null(Some(self.strategy_hwm - self.container.queue_total_size))\n            },\n        }\n    }\n\n    pub(super) fn readable_stream_default_controller_close<R: ReadableStreamReader<'js>>(\n        ctx: Ctx<'js>,\n        // Let stream be controller.[[stream]].\n        mut objects: ReadableStreamDefaultControllerObjects<'js, R>,\n    ) -> Result<ReadableStreamDefaultControllerObjects<'js, R>> {\n        // If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(controller) is false, return.\n        if !objects\n            .controller\n            .readable_stream_default_controller_can_close_or_enqueue(&objects.stream)\n        {\n            return Ok(objects);\n        }\n\n        // Set controller.[[closeRequested]] to true.\n        objects.controller.close_requested = true;\n\n        // If controller.[[queue]] is empty,\n        if objects.controller.container.queue.is_empty() {\n            // Perform ! ReadableStreamDefaultControllerClearAlgorithms(controller).\n            objects\n                .controller\n                .readable_stream_default_controller_clear_algorithms();\n            // Perform ! ReadableStreamClose(stream).\n            objects = ReadableStream::readable_stream_close(ctx, objects)?;\n        }\n\n        Ok(objects)\n    }\n\n    pub(super) fn readable_stream_default_controller_enqueue<\n        R: ReadableStreamDefaultReaderOrUndefined<'js>,\n    >(\n        ctx: Ctx<'js>,\n        // Let stream be controller.[[stream]].\n        mut objects: ReadableStreamDefaultControllerObjects<'js, R>,\n        chunk: Value<'js>,\n    ) -> Result<ReadableStreamDefaultControllerObjects<'js, R>> {\n        // If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(controller) is false, return.\n        if !objects\n            .controller\n            .readable_stream_default_controller_can_close_or_enqueue(&objects.stream)\n        {\n            return Ok(objects);\n        }\n\n        let mut els = true;\n        // If ! IsReadableStreamLocked(stream) is true and ! ReadableStreamGetNumReadRequests(stream) > 0, perform ! ReadableStreamFulfillReadRequest(stream, chunk, false).\n        objects = objects.with_some_reader(\n            |objects| {\n                if ReadableStream::readable_stream_get_num_read_requests(&objects.reader) > 0 {\n                    els = false;\n                    ReadableStream::readable_stream_fulfill_read_request(\n                        &ctx,\n                        objects,\n                        chunk.clone(),\n                        false,\n                    )\n                } else {\n                    Ok(objects)\n                }\n            },\n            Ok,\n        )?;\n\n        if els {\n            // Let result be the result of performing controller.[[strategySizeAlgorithm]], passing in chunk, and interpreting the result as a completion record.\n            let (result, objects_class) =\n                Self::strategy_size_algorithm(ctx.clone(), objects, chunk.clone());\n\n            objects = ReadableStreamObjects::from_class(objects_class);\n\n            match result {\n                // If result is an abrupt completion,\n                Err(Error::Exception) => {\n                    let err = ctx.catch();\n                    // Perform ! ReadableStreamDefaultControllerError(controller, result.[[Value]]).\n                    Self::readable_stream_default_controller_error(objects, err.clone())?;\n\n                    return Err(ctx.throw(err));\n                },\n                // Let chunkSize be result.[[Value]].\n                Ok(chunk_size) => {\n                    // Let enqueueResult be EnqueueValueWithSize(controller, chunk, chunkSize).\n                    let enqueue_result = objects\n                        .controller\n                        .container\n                        .enqueue_value_with_size(&ctx, chunk, chunk_size);\n\n                    match enqueue_result {\n                        // If enqueueResult is an abrupt completion,\n                        Err(Error::Exception) => {\n                            let err = ctx.catch();\n                            // Perform ! ReadableStreamDefaultControllerError(controller, enqueueResult.[[Value]]).\n                            Self::readable_stream_default_controller_error(objects, err.clone())?;\n                            return Err(ctx.throw(err));\n                        },\n                        Err(err) => return Err(err),\n                        Ok(()) => {},\n                    }\n                },\n                Err(err) => return Err(err),\n            }\n        }\n\n        // Perform ! ReadableStreamDefaultControllerCallPullIfNeeded(controller).\n        Self::readable_stream_default_controller_call_pull_if_needed(ctx, objects)\n    }\n\n    fn start_algorithm<R: ReadableStreamReader<'js>>(\n        ctx: Ctx<'js>,\n        objects: ReadableStreamDefaultControllerObjects<'js, R>,\n        start_algorithm: StartAlgorithm<'js>,\n    ) -> Result<(\n        Value<'js>,\n        ReadableStreamClassObjects<'js, OwnedBorrowMut<'js, Self>, R>,\n    )> {\n        let objects_class = objects.into_inner();\n\n        Ok((\n            start_algorithm.call(\n                ctx,\n                ReadableStreamControllerClass::ReadableStreamDefaultController(\n                    objects_class.controller.clone(),\n                ),\n            )?,\n            objects_class,\n        ))\n    }\n\n    fn pull_algorithm<R: ReadableStreamReader<'js>>(\n        ctx: Ctx<'js>,\n        objects: ReadableStreamDefaultControllerObjects<'js, R>,\n    ) -> Result<(\n        Promise<'js>,\n        ReadableStreamClassObjects<'js, OwnedBorrowMut<'js, Self>, R>,\n    )> {\n        let pull_algorithm = objects\n            .controller\n            .pull_algorithm\n            .clone()\n            .expect(\"pull algorithm used after ReadableStreamDefaultControllerClearAlgorithms\");\n        let promise_primordials = objects.stream.promise_primordials.clone();\n        let objects_class = objects.into_inner();\n\n        Ok((\n            pull_algorithm.call(\n                ctx,\n                &promise_primordials,\n                ReadableStreamControllerClass::ReadableStreamDefaultController(\n                    objects_class.controller.clone(),\n                ),\n            )?,\n            objects_class,\n        ))\n    }\n\n    fn strategy_size_algorithm<R: ReadableStreamReader<'js>>(\n        ctx: Ctx<'js>,\n        objects: ReadableStreamDefaultControllerObjects<'js, R>,\n        chunk: Value<'js>,\n    ) -> (\n        Result<SizeValue<'js>>,\n        ReadableStreamClassObjects<'js, OwnedBorrowMut<'js, Self>, R>,\n    ) {\n        let strategy_size_algorithm = objects\n            .controller\n            .strategy_size_algorithm\n            .clone()\n            .expect(\"size algorithm used after ReadableStreamDefaultControllerClearAlgorithms\");\n        let objects_class = objects.into_inner();\n\n        (strategy_size_algorithm.call(ctx, chunk), objects_class)\n    }\n\n    pub(super) fn cancel_algorithm<R: ReadableStreamReader<'js>>(\n        ctx: Ctx<'js>,\n        objects: ReadableStreamDefaultControllerObjects<'js, R>,\n        reason: Value<'js>,\n    ) -> Result<(\n        Promise<'js>,\n        ReadableStreamClassObjects<'js, OwnedBorrowMut<'js, Self>, R>,\n    )> {\n        let cancel_algorithm =\n            objects.controller.cancel_algorithm.clone().expect(\n                \"cancel algorithm used after ReadableStreamDefaultControllerClearAlgorithms\",\n            );\n        let promise_primordials = objects.stream.promise_primordials.clone();\n        let objects_class = objects.into_inner();\n\n        Ok((\n            cancel_algorithm.call(ctx, &promise_primordials, reason)?,\n            objects_class,\n        ))\n    }\n}\n\n#[methods(rename_all = \"camelCase\")]\nimpl<'js> ReadableStreamDefaultController<'js> {\n    // this is required by web platform tests for unclear reasons\n    fn constructor() -> Self {\n        unimplemented!()\n    }\n\n    #[qjs(constructor)]\n    fn new(ctx: Ctx<'js>) -> Result<Class<'js, Self>> {\n        Err(Exception::throw_type(&ctx, \"Illegal constructor\"))\n    }\n\n    // readonly attribute unrestricted double? desiredSize;\n    #[qjs(get)]\n    fn desired_size(&self) -> Null<f64> {\n        let stream = OwnedBorrow::from_class(self.stream.clone());\n        self.readable_stream_default_controller_get_desired_size(&stream)\n    }\n\n    // undefined close();\n    fn close(ctx: Ctx<'js>, controller: This<OwnedBorrowMut<'js, Self>>) -> Result<()> {\n        let objects = ReadableStreamObjects::from_default_controller(controller.0);\n\n        // If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(this) is false, throw a TypeError exception.\n        if !objects\n            .controller\n            .readable_stream_default_controller_can_close_or_enqueue(&objects.stream)\n        {\n            return Err(Exception::throw_type(\n                &ctx,\n                \"The stream is not in a state that permits close\",\n            ));\n        }\n\n        // Perform ! ReadableStreamDefaultControllerClose(this).\n        Self::readable_stream_default_controller_close(ctx, objects)?;\n        Ok(())\n    }\n\n    // undefined enqueue(optional any chunk);\n    fn enqueue(\n        ctx: Ctx<'js>,\n        controller: This<OwnedBorrowMut<'js, Self>>,\n        chunk: Opt<Value<'js>>,\n    ) -> Result<()> {\n        let objects = ReadableStreamObjects::from_default_controller(controller.0);\n\n        // If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(this) is false, throw a TypeError exception.\n        if !objects\n            .controller\n            .readable_stream_default_controller_can_close_or_enqueue(&objects.stream)\n        {\n            return Err(Exception::throw_type(\n                &ctx,\n                \"The stream is not in a state that permits enqueue\",\n            ));\n        }\n\n        objects.with_reader(\n            |objects| {\n                // Perform ? ReadableStreamDefaultControllerEnqueue(this, chunk).\n                Self::readable_stream_default_controller_enqueue(\n                    ctx.clone(),\n                    objects,\n                    chunk.0.clone().unwrap_or_undefined(&ctx),\n                )\n            },\n            |_| panic!(\"Default controller must not have byob reader\"),\n            |objects| {\n                // Perform ? ReadableStreamDefaultControllerEnqueue(this, chunk).\n                Self::readable_stream_default_controller_enqueue(\n                    ctx.clone(),\n                    objects,\n                    chunk.0.clone().unwrap_or_undefined(&ctx),\n                )\n            },\n        )?;\n\n        Ok(())\n    }\n\n    // undefined error(optional any e);\n    fn error(\n        ctx: Ctx<'js>,\n        controller: This<OwnedBorrowMut<'js, Self>>,\n        e: Opt<Value<'js>>,\n    ) -> Result<()> {\n        let objects = ReadableStreamObjects::from_default_controller(controller.0);\n\n        // Perform ! ReadableStreamDefaultControllerError(this, e).\n        Self::readable_stream_default_controller_error(objects, e.0.unwrap_or_undefined(&ctx))?;\n        Ok(())\n    }\n}\n\nimpl<'js> ReadableStreamController<'js> for ReadableStreamDefaultControllerOwned<'js> {\n    type Class = ReadableStreamDefaultControllerClass<'js>;\n\n    fn with_controller<C, O>(\n        self,\n        ctx: C,\n        default: impl FnOnce(\n            C,\n            ReadableStreamDefaultControllerOwned<'js>,\n        ) -> Result<(O, ReadableStreamDefaultControllerOwned<'js>)>,\n        _: impl FnOnce(\n            C,\n            ReadableByteStreamControllerOwned<'js>,\n        ) -> Result<(O, ReadableByteStreamControllerOwned<'js>)>,\n    ) -> Result<(O, Self)> {\n        let (ctx, reader) = default(ctx, self)?;\n        Ok((ctx, reader))\n    }\n\n    fn into_inner(self) -> Self::Class {\n        OwnedBorrowMut::into_inner(self)\n    }\n\n    fn from_class(class: Self::Class) -> Self {\n        OwnedBorrowMut::from_class(class)\n    }\n\n    fn into_erased(self) -> ReadableStreamControllerOwned<'js> {\n        ReadableStreamControllerOwned::ReadableStreamDefaultController(self)\n    }\n\n    fn try_from_erased(erased: ReadableStreamControllerOwned<'js>) -> Option<Self> {\n        match erased {\n            ReadableStreamControllerOwned::ReadableStreamDefaultController(r) => Some(r),\n            ReadableStreamControllerOwned::ReadableStreamByteController(_) => None,\n        }\n    }\n\n    fn pull_steps(\n        ctx: &Ctx<'js>,\n        mut objects: ReadableStreamDefaultReaderObjects<'js, Self>,\n        read_request: impl ReadableStreamReadRequest<'js> + 'js,\n    ) -> Result<ReadableStreamDefaultReaderObjects<'js, Self>> {\n        // If this.[[queue]] is not empty,\n        if !objects.controller.container.queue.is_empty() {\n            // Let chunk be ! DequeueValue(this).\n            let chunk = objects.controller.container.dequeue_value();\n            // If this.[[closeRequested]] is true and this.[[queue]] is empty,\n            if objects.controller.close_requested && objects.controller.container.queue.is_empty() {\n                // Perform ! ReadableStreamDefaultControllerClearAlgorithms(this).\n                objects\n                    .controller\n                    .readable_stream_default_controller_clear_algorithms();\n                // Perform ! ReadableStreamClose(stream).\n                objects = ReadableStream::readable_stream_close(ctx.clone(), objects)?;\n            } else {\n                // Otherwise, perform ! ReadableStreamDefaultControllerCallPullIfNeeded(this).\n                objects =\n                    ReadableStreamDefaultController::readable_stream_default_controller_call_pull_if_needed(\n                        ctx.clone(),\n                        objects,\n                    )?;\n            }\n\n            // Perform readRequest’s chunk steps, given chunk.\n            read_request.chunk_steps_typed(objects, chunk)\n        } else {\n            // Otherwise,\n            // Perform ! ReadableStreamAddReadRequest(stream, readRequest).\n            objects\n                .stream\n                .readable_stream_add_read_request(&mut objects.reader, read_request);\n            // Perform ! ReadableStreamDefaultControllerCallPullIfNeeded(this).\n\n            ReadableStreamDefaultController::readable_stream_default_controller_call_pull_if_needed(\n                ctx.clone(),\n                objects,\n            )\n        }\n    }\n\n    fn cancel_steps<R: ReadableStreamReader<'js>>(\n        ctx: &Ctx<'js>,\n        mut objects: ReadableStreamObjects<'js, Self, R>,\n        reason: Value<'js>,\n    ) -> Result<(Promise<'js>, ReadableStreamObjects<'js, Self, R>)> {\n        // Perform ! ResetQueue(this).\n        objects.controller.container.reset_queue();\n\n        // Let result be the result of performing this.[[cancelAlgorithm]], passing reason.\n        let (result, objects_class) =\n            ReadableStreamDefaultController::cancel_algorithm(ctx.clone(), objects, reason)?;\n\n        objects = ReadableStreamObjects::from_class(objects_class);\n        // Perform ! ReadableStreamDefaultControllerClearAlgorithms(this).\n        objects\n            .controller\n            .readable_stream_default_controller_clear_algorithms();\n\n        // Return result.\n        Ok((result, objects))\n    }\n\n    fn release_steps(&mut self) {}\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/readable/default_reader.rs",
    "content": "use std::collections::VecDeque;\n\nuse rquickjs::class::Tracer;\nuse rquickjs::prelude::This;\nuse rquickjs::{\n    class::{OwnedBorrowMut, Trace},\n    methods,\n    prelude::Opt,\n    Class, Ctx, Exception, Promise, Result, Value,\n};\nuse rquickjs::{IntoJs, JsLifetime, Object};\n\nuse crate::{\n    readable::{\n        byob_reader::ReadableStreamBYOBReaderOwned,\n        controller::ReadableStreamController,\n        objects::{ReadableStreamDefaultReaderObjects, ReadableStreamObjects},\n        reader::{\n            ReadableStreamGenericReader, ReadableStreamReader, ReadableStreamReaderOwned,\n            UndefinedReader,\n        },\n        stream::{ReadableStreamOwned, ReadableStreamState},\n    },\n    utils::{\n        promise::{promise_rejected_with_constructor, ResolveablePromise},\n        UnwrapOrUndefined,\n    },\n};\n\n#[derive(Trace)]\n#[rquickjs::class]\npub(crate) struct ReadableStreamDefaultReader<'js> {\n    pub(super) generic: ReadableStreamGenericReader<'js>,\n    pub(super) read_requests: VecDeque<Box<dyn ReadableStreamReadRequest<'js> + 'js>>,\n}\n\npub(crate) type ReadableStreamDefaultReaderClass<'js> =\n    Class<'js, ReadableStreamDefaultReader<'js>>;\npub(crate) type ReadableStreamDefaultReaderOwned<'js> =\n    OwnedBorrowMut<'js, ReadableStreamDefaultReader<'js>>;\n\nunsafe impl<'js> JsLifetime<'js> for ReadableStreamDefaultReader<'js> {\n    type Changed<'to> = ReadableStreamDefaultReader<'to>;\n}\n\nimpl<'js> ReadableStreamDefaultReader<'js> {\n    pub(super) fn readable_stream_default_reader_error_read_requests<\n        C: ReadableStreamController<'js>,\n    >(\n        mut objects: ReadableStreamDefaultReaderObjects<'js, C>,\n        e: Value<'js>,\n    ) -> Result<ReadableStreamDefaultReaderObjects<'js, C>> {\n        // Let readRequests be reader.[[readRequests]].\n        let read_requests = &mut objects.reader.read_requests;\n\n        // Set reader.[[readRequests]] to a new empty list.\n        let read_requests = read_requests.split_off(0);\n\n        // For each readRequest of readRequests,\n        for read_request in read_requests {\n            // Perform readRequest’s error steps, given e.\n            objects = read_request.error_steps_typed(objects, e.clone())?;\n        }\n\n        Ok(objects)\n    }\n\n    pub(super) fn readable_stream_default_reader_read<\n        'closure,\n        C: ReadableStreamController<'js>,\n    >(\n        ctx: &Ctx<'js>,\n        // Let stream be reader.[[stream]].\n        mut objects: ReadableStreamDefaultReaderObjects<'js, C>,\n        read_request: impl ReadableStreamReadRequest<'js> + 'js,\n    ) -> Result<ReadableStreamDefaultReaderObjects<'js, C>> {\n        // Set stream.[[disturbed]] to true.\n        objects.stream.disturbed = true;\n        match objects.stream.state {\n            // If stream.[[state]] is \"closed\", perform readRequest’s close steps.\n            ReadableStreamState::Closed => read_request.close_steps_typed(ctx, objects),\n            // Otherwise, if stream.[[state]] is \"errored\", perform readRequest’s error steps given stream.[[storedError]].\n            ReadableStreamState::Errored(ref stored_error) => {\n                let stored_error = stored_error.clone();\n                read_request.error_steps_typed(objects, stored_error)\n            },\n            // Otherwise,\n            _ => {\n                // Perform ! stream.[[controller]].[[PullSteps]](readRequest).\n                C::pull_steps(ctx, objects, read_request)\n            },\n        }\n    }\n\n    pub(super) fn set_up_readable_stream_default_reader(\n        ctx: &Ctx<'js>,\n        stream: ReadableStreamOwned<'js>,\n    ) -> Result<(ReadableStreamOwned<'js>, Class<'js, Self>)> {\n        // If ! IsReadableStreamLocked(stream) is true, throw a TypeError exception.\n        if stream.is_readable_stream_locked() {\n            return Err(Exception::throw_type(\n                ctx,\n                \"This stream has already been locked for exclusive reading by another reader\",\n            ));\n        }\n\n        // Perform ! ReadableStreamReaderGenericInitialize(reader, stream).\n        let generic =\n            ReadableStreamGenericReader::readable_stream_reader_generic_initialize(ctx, stream)?;\n        let mut stream = OwnedBorrowMut::from_class(generic.stream.clone().unwrap());\n\n        let reader = Class::instance(\n            ctx.clone(),\n            Self {\n                generic,\n                // Set reader.[[readRequests]] to a new empty list.\n                read_requests: VecDeque::new(),\n            },\n        )?;\n\n        stream.reader = Some(reader.clone().into());\n\n        Ok((stream, reader))\n    }\n\n    pub(super) fn readable_stream_default_reader_release<C: ReadableStreamController<'js>>(\n        mut objects: ReadableStreamDefaultReaderObjects<'js, C>,\n    ) -> Result<ReadableStreamDefaultReaderObjects<'js, C>> {\n        // Perform ! ReadableStreamReaderGenericRelease(reader).\n        objects\n            .reader\n            .generic\n            .readable_stream_reader_generic_release(&mut objects.stream, || {\n                objects.controller.release_steps()\n            })?;\n\n        // Let e be a new TypeError exception.\n        let e: Value = objects\n            .stream\n            .constructor_type_error\n            .call((\"Reader was released\",))?;\n\n        // Perform ! ReadableStreamDefaultReaderErrorReadRequests(reader, e).\n        Self::readable_stream_default_reader_error_read_requests(objects, e)\n    }\n}\n\n#[methods(rename_all = \"camelCase\")]\nimpl<'js> ReadableStreamDefaultReader<'js> {\n    #[qjs(constructor)]\n    pub fn new(ctx: Ctx<'js>, stream: ReadableStreamOwned<'js>) -> Result<Class<'js, Self>> {\n        // Perform ? SetUpReadableStreamDefaultReader(this, stream).\n        let (_, reader) = Self::set_up_readable_stream_default_reader(&ctx, stream)?;\n        Ok(reader)\n    }\n\n    fn read(ctx: Ctx<'js>, reader: This<OwnedBorrowMut<'js, Self>>) -> Result<Promise<'js>> {\n        if reader.generic.stream.is_none() {\n            // If this.[[stream]] is undefined, return a promise rejected with a TypeError exception.\n            return promise_rejected_with_constructor(\n                &reader.generic.constructor_type_error,\n                &reader.generic.promise_primordials,\n                \"Cannot read from a stream using a released reader\",\n            );\n        }\n\n        let objects = ReadableStreamObjects::from_default_reader(reader.0);\n\n        // Let promise be a new promise.\n        let promise = ResolveablePromise::new(&ctx)?;\n\n        // Let readRequest be a new read request with the following items:\n        #[derive(Trace)]\n        struct ReadRequest<'js> {\n            promise: ResolveablePromise<'js>,\n        }\n\n        impl<'js> ReadableStreamReadRequest<'js> for ReadRequest<'js> {\n            // chunk steps, given chunk\n            // Resolve promise with «[ \"value\" → chunk, \"done\" → false ]».\n            fn chunk_steps(\n                &self,\n                objects: ReadableStreamDefaultReaderObjects<'js>,\n                chunk: Value<'js>,\n            ) -> Result<ReadableStreamDefaultReaderObjects<'js>> {\n                self.promise.resolve(ReadableStreamReadResult {\n                    value: Some(chunk),\n                    done: false,\n                })?;\n\n                Ok(objects)\n            }\n\n            // close steps\n            // Resolve promise with «[ \"value\" → undefined, \"done\" → true ]».\n            fn close_steps(\n                &self,\n                _: &Ctx<'js>,\n                objects: ReadableStreamDefaultReaderObjects<'js>,\n            ) -> Result<ReadableStreamDefaultReaderObjects<'js>> {\n                self.promise.resolve(ReadableStreamReadResult {\n                    value: None,\n                    done: true,\n                })?;\n                Ok(objects)\n            }\n\n            fn error_steps(\n                &self,\n                objects: ReadableStreamDefaultReaderObjects<'js>,\n                e: Value<'js>,\n            ) -> Result<ReadableStreamDefaultReaderObjects<'js>> {\n                self.promise.reject(e)?;\n                Ok(objects)\n            }\n        }\n\n        // Perform ! ReadableStreamDefaultReaderRead(this, readRequest).\n        Self::readable_stream_default_reader_read(\n            &ctx,\n            objects,\n            ReadRequest {\n                promise: promise.clone(),\n            },\n        )?;\n\n        // Return promise.\n        Ok(promise.promise)\n    }\n\n    fn release_lock(reader: This<OwnedBorrowMut<'js, Self>>) -> Result<()> {\n        if reader.generic.stream.is_none() {\n            // If this.[[stream]] is undefined, return.\n            return Ok(());\n        }\n\n        let objects = ReadableStreamObjects::from_default_reader(reader.0);\n\n        // Perform ! ReadableStreamDefaultReaderRelease(this).\n        Self::readable_stream_default_reader_release(objects)?;\n        Ok(())\n    }\n\n    #[qjs(get)]\n    fn closed(&self) -> Promise<'js> {\n        self.generic.closed_promise.promise.clone()\n    }\n\n    fn cancel(\n        ctx: Ctx<'js>,\n        reader: This<OwnedBorrowMut<'js, Self>>,\n        reason: Opt<Value<'js>>,\n    ) -> Result<Promise<'js>> {\n        if reader.generic.stream.is_none() {\n            // If this.[[stream]] is undefined, return a promise rejected with a TypeError exception.\n            return promise_rejected_with_constructor(\n                &reader.generic.constructor_type_error,\n                &reader.generic.promise_primordials,\n                \"Cannot cancel a stream using a released reader\",\n            );\n        };\n\n        let objects = ReadableStreamObjects::from_default_reader(reader.0);\n\n        // Return ! ReadableStreamReaderGenericCancel(this, reason).\n        let (promise, _) = ReadableStreamGenericReader::readable_stream_reader_generic_cancel(\n            ctx.clone(),\n            objects,\n            reason.0.unwrap_or_undefined(&ctx),\n        )?;\n        Ok(promise)\n    }\n}\n\nimpl<'js> ReadableStreamReader<'js> for ReadableStreamDefaultReaderOwned<'js> {\n    type Class = ReadableStreamDefaultReaderClass<'js>;\n\n    fn with_reader<C>(\n        self,\n        ctx: C,\n        default: impl FnOnce(\n            C,\n            ReadableStreamDefaultReaderOwned<'js>,\n        ) -> Result<(C, ReadableStreamDefaultReaderOwned<'js>)>,\n        _: impl FnOnce(\n            C,\n            ReadableStreamBYOBReaderOwned<'js>,\n        ) -> Result<(C, ReadableStreamBYOBReaderOwned<'js>)>,\n        _: impl FnOnce(C) -> Result<C>,\n    ) -> Result<(C, Self)> {\n        default(ctx, self)\n    }\n\n    fn into_inner(self) -> Self::Class {\n        self.into_inner()\n    }\n\n    fn from_class(class: Self::Class) -> Self {\n        OwnedBorrowMut::from_class(class)\n    }\n\n    fn try_from_erased(erased: Option<ReadableStreamReaderOwned<'js>>) -> Option<Self> {\n        match erased {\n            Some(ReadableStreamReaderOwned::ReadableStreamDefaultReader(r)) => Some(r),\n            _ => None,\n        }\n    }\n}\n\npub(super) trait ReadableStreamDefaultReaderOrUndefined<'js>:\n    ReadableStreamReader<'js>\n{\n}\n\nimpl<'js> ReadableStreamDefaultReaderOrUndefined<'js> for ReadableStreamDefaultReaderOwned<'js> {}\n\nimpl<'js> ReadableStreamDefaultReaderOrUndefined<'js>\n    for Option<ReadableStreamDefaultReaderOwned<'js>>\n{\n}\n\nimpl ReadableStreamDefaultReaderOrUndefined<'_> for UndefinedReader {}\n\npub(super) trait ReadableStreamReadRequest<'js>: Trace<'js> {\n    fn chunk_steps_typed<C: ReadableStreamController<'js>>(\n        &self,\n        objects: ReadableStreamDefaultReaderObjects<'js, C>,\n        chunk: Value<'js>,\n    ) -> Result<ReadableStreamDefaultReaderObjects<'js, C>>\n    where\n        Self: Sized,\n    {\n        let mut erased = ReadableStreamObjects {\n            stream: objects.stream,\n            controller: objects.controller.into_erased(),\n            reader: objects.reader,\n        };\n\n        erased = self.chunk_steps(erased, chunk)?;\n\n        Ok(ReadableStreamObjects {\n            stream: erased.stream,\n            controller: C::try_from_erased(erased.controller)\n                .expect(\"chunk steps must not change type of controller\"),\n            reader: erased.reader,\n        })\n    }\n\n    fn chunk_steps(\n        &self,\n        objects: ReadableStreamDefaultReaderObjects<'js>,\n        chunk: Value<'js>,\n    ) -> Result<ReadableStreamDefaultReaderObjects<'js>>;\n\n    fn close_steps_typed<C: ReadableStreamController<'js>>(\n        &self,\n        ctx: &Ctx<'js>,\n        objects: ReadableStreamDefaultReaderObjects<'js, C>,\n    ) -> Result<ReadableStreamDefaultReaderObjects<'js, C>>\n    where\n        Self: Sized,\n    {\n        let mut erased = ReadableStreamObjects {\n            stream: objects.stream,\n            controller: objects.controller.into_erased(),\n            reader: objects.reader,\n        };\n\n        erased = self.close_steps(ctx, erased)?;\n\n        Ok(ReadableStreamObjects {\n            stream: erased.stream,\n            controller: C::try_from_erased(erased.controller)\n                .expect(\"close steps must not change type of controller\"),\n            reader: erased.reader,\n        })\n    }\n\n    fn close_steps(\n        &self,\n        ctx: &Ctx<'js>,\n        objects: ReadableStreamDefaultReaderObjects<'js>,\n    ) -> Result<ReadableStreamDefaultReaderObjects<'js>>;\n\n    fn error_steps_typed<C: ReadableStreamController<'js>>(\n        &self,\n        objects: ReadableStreamDefaultReaderObjects<'js, C>,\n        reason: Value<'js>,\n    ) -> Result<ReadableStreamDefaultReaderObjects<'js, C>>\n    where\n        Self: Sized,\n    {\n        let mut erased = ReadableStreamObjects {\n            stream: objects.stream,\n            controller: objects.controller.into_erased(),\n            reader: objects.reader,\n        };\n\n        erased = self.error_steps(erased, reason)?;\n\n        Ok(ReadableStreamObjects {\n            stream: erased.stream,\n            controller: C::try_from_erased(erased.controller)\n                .expect(\"error steps must not change type of controller\"),\n            reader: erased.reader,\n        })\n    }\n\n    fn error_steps(\n        &self,\n        objects: ReadableStreamDefaultReaderObjects<'js>,\n        reason: Value<'js>,\n    ) -> Result<ReadableStreamDefaultReaderObjects<'js>>;\n}\n\nimpl<'js> Trace<'js> for Box<dyn ReadableStreamReadRequest<'js> + 'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.as_ref().trace(tracer);\n    }\n}\n\nimpl<'js> ReadableStreamReadRequest<'js> for Box<dyn ReadableStreamReadRequest<'js> + 'js> {\n    fn chunk_steps(\n        &self,\n        objects: ReadableStreamDefaultReaderObjects<'js>,\n        chunk: Value<'js>,\n    ) -> Result<ReadableStreamDefaultReaderObjects<'js>> {\n        self.as_ref().chunk_steps(objects, chunk)\n    }\n\n    fn close_steps(\n        &self,\n        ctx: &Ctx<'js>,\n        objects: ReadableStreamDefaultReaderObjects<'js>,\n    ) -> Result<ReadableStreamDefaultReaderObjects<'js>> {\n        self.as_ref().close_steps(ctx, objects)\n    }\n\n    fn error_steps(\n        &self,\n        objects: ReadableStreamDefaultReaderObjects<'js>,\n        reason: Value<'js>,\n    ) -> Result<ReadableStreamDefaultReaderObjects<'js>> {\n        self.as_ref().error_steps(objects, reason)\n    }\n}\n\npub(super) struct ReadableStreamReadResult<'js> {\n    pub(super) value: Option<Value<'js>>,\n    pub(super) done: bool,\n}\n\nimpl<'js> IntoJs<'js> for ReadableStreamReadResult<'js> {\n    fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {\n        let obj = Object::new(ctx.clone())?;\n        obj.set(\"value\", self.value)?;\n        obj.set(\"done\", self.done)?;\n        Ok(obj.into_value())\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/readable/iterator.rs",
    "content": "use std::{\n    rc::Rc,\n    sync::atomic::{AtomicBool, Ordering},\n};\n\nuse llrt_utils::{\n    object::CreateSymbol,\n    primordials::{BasePrimordials, Primordial},\n};\nuse rquickjs::{\n    atom::PredefinedAtom,\n    class::{JsClass, OwnedBorrow, OwnedBorrowMut, Trace, Tracer},\n    function::Constructor,\n    methods,\n    prelude::{Opt, This},\n    Class, Coerced, Ctx, Error, Exception, FromJs, Function, IntoAtom, IntoJs, JsLifetime, Object,\n    Promise, Result, Symbol, Type, Value,\n};\n\nuse crate::{\n    readable::{\n        controller::ReadableStreamControllerOwned,\n        default_reader::{\n            ReadableStreamDefaultReader, ReadableStreamDefaultReaderOwned,\n            ReadableStreamReadRequest, ReadableStreamReadResult,\n        },\n        objects::{\n            ReadableStreamClassObjects, ReadableStreamDefaultReaderObjects, ReadableStreamObjects,\n        },\n        reader::ReadableStreamGenericReader,\n    },\n    utils::{\n        class_from_owned_borrow_mut,\n        promise::{promise_resolved_with, PromisePrimordials},\n        promise::{upon_promise, upon_promise_fulfilment, ResolveablePromise},\n        UnwrapOrUndefined,\n    },\n};\n\npub(super) enum IteratorKind {\n    Async,\n}\n\npub(super) struct IteratorRecord<'js> {\n    pub(super) iterator: Object<'js>,\n    next_method: Function<'js>,\n    done: AtomicBool,\n\n    sync_to_async_iterator: Function<'js>,\n}\n\nimpl<'js> IteratorRecord<'js> {\n    pub(super) fn get_iterator(\n        ctx: &Ctx<'js>,\n        obj: Value<'js>,\n        kind: IteratorKind,\n    ) -> Result<Self> {\n        let method: Option<Function<'js>> = match kind {\n            // If kind is async, then\n            IteratorKind::Async => {\n                // Let method be ? GetMethod(obj, %Symbol.asyncIterator%).\n                let method = get_method(ctx, obj.clone(), Symbol::async_iterator(ctx.clone()))?;\n                // If method is undefined, then\n                if method.is_none() {\n                    // Let syncMethod be ? GetMethod(obj, %Symbol.iterator%).\n                    let sync_method = get_method(ctx, obj.clone(), Symbol::iterator(ctx.clone()))?;\n\n                    // If syncMethod is undefined, throw a TypeError exception.\n                    let sync_method = match sync_method {\n                        None => {\n                            return Err(Exception::throw_type(ctx, \"Object is not an iterator\"));\n                        },\n                        Some(sync_method) => sync_method,\n                    };\n\n                    // Let syncIteratorRecord be ? GetIteratorFromMethod(obj, syncMethod).\n                    let sync_iterator_record =\n                        Self::get_iterator_from_method(ctx, &obj, sync_method)?;\n\n                    // Return CreateAsyncFromSyncIterator(syncIteratorRecord).\n                    return sync_iterator_record.create_async_from_sync_iterator(ctx);\n                }\n\n                method\n            },\n        };\n\n        // If method is undefined, throw a TypeError exception.\n        match method {\n            None => Err(Exception::throw_type(ctx, \"Object is not an iterator\")),\n            Some(method) => {\n                // Return ? GetIteratorFromMethod(obj, method).\n                Self::get_iterator_from_method(ctx, &obj, method)\n            },\n        }\n    }\n\n    fn get_iterator_from_method(\n        ctx: &Ctx<'js>,\n        obj: &Value<'js>,\n        method: Function<'js>,\n    ) -> Result<Self> {\n        // Let iterator be ? Call(method, obj).\n        let iterator: Value<'js> = method.call((This(obj),))?;\n        let iterator = match iterator.into_object() {\n            Some(iterator) => iterator,\n            None => {\n                return Err(Exception::throw_type(\n                    ctx,\n                    \"The iterator method must return an object\",\n                ));\n            },\n        };\n        // Let nextMethod be ? Get(iterator, \"next\").\n        let next_method = iterator.get(PredefinedAtom::Next)?;\n        // Let iteratorRecord be the Iterator Record { [[Iterator]]: iterator, [[NextMethod]]: nextMethod, [[Done]]: false }.\n        // Return iteratorRecord.\n        Ok(Self {\n            iterator,\n            next_method,\n            done: AtomicBool::new(false),\n            sync_to_async_iterator: IteratorPrimordials::get(ctx)?\n                .sync_to_async_iterator\n                .clone(),\n        })\n    }\n\n    fn create_async_from_sync_iterator(self, ctx: &Ctx<'js>) -> Result<Self> {\n        let sync_iterable = Object::new(ctx.clone())?;\n        sync_iterable.set(\n            Symbol::iterator(ctx.clone()),\n            Function::new(ctx.clone(), {\n                let iterator = self.iterator.clone();\n                move || iterator.clone()\n            }),\n        )?;\n\n        let async_iterator: Object<'js> = self.sync_to_async_iterator.call((sync_iterable,))?;\n\n        let next_method = async_iterator.get(PredefinedAtom::Next)?;\n\n        Ok(Self {\n            iterator: async_iterator,\n            next_method,\n            done: AtomicBool::new(false),\n            sync_to_async_iterator: self.sync_to_async_iterator,\n        })\n    }\n\n    pub(super) fn iterator_next(\n        &self,\n        ctx: &Ctx<'js>,\n        value: Option<Value<'js>>,\n    ) -> Result<Object<'js>> {\n        let result: Result<Value<'js>> = match value {\n            // If value is not present, then\n            None => {\n                // Let result be Completion(Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]])).\n\n                self.next_method.call((This(self.iterator.clone()),))\n            },\n            // Else,\n            Some(value) => {\n                // Let result be Completion(Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]], « value »)).\n                self.next_method.call((This(self.iterator.clone()), value))\n            },\n        };\n\n        let result = match result {\n            // If result is a throw completion, then\n            Err(Error::Exception) => {\n                // Set iteratorRecord.[[Done]] to true.\n                self.done.store(true, Ordering::Release);\n                // Return ? result.\n                return Err(Error::Exception);\n            },\n            Err(err) => return Err(err),\n            // Set result to ! result.\n            Ok(result) => result,\n        };\n\n        let result = match result.into_object() {\n            // If result is not an Object, then\n            None => {\n                // Set iteratorRecord.[[Done]] to true.\n                self.done.store(true, Ordering::Release);\n                return Err(Exception::throw_type(\n                    ctx,\n                    \"The iterator.next() method must return an object\",\n                ));\n            },\n            Some(result) => result,\n        };\n        // Return result.\n        Ok(result)\n    }\n\n    pub(super) fn iterator_complete(iterator_result: &Object<'js>) -> Result<bool> {\n        let done: Coerced<bool> = iterator_result.get(PredefinedAtom::Done)?;\n        Ok(done.0)\n    }\n\n    pub(super) fn iterator_value(iterator_result: &Object<'js>) -> Result<Value<'js>> {\n        iterator_result.get(PredefinedAtom::Value)\n    }\n}\n\npub(super) struct ReadableStreamAsyncIterator<'js> {\n    objects: ReadableStreamClassObjects<\n        'js,\n        ReadableStreamControllerOwned<'js>,\n        ReadableStreamDefaultReaderOwned<'js>,\n    >,\n    prevent_cancel: bool,\n    is_finished: Rc<AtomicBool>,\n    ongoing_promise: Option<Promise<'js>>,\n\n    promise_primordials: PromisePrimordials<'js>,\n    end_of_iteration: Symbol<'js>,\n}\n\nimpl<'js> Trace<'js> for ReadableStreamAsyncIterator<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        Trace::<'js>::trace(&self.objects, tracer);\n        if let Some(ongoing_promise) = &self.ongoing_promise {\n            ongoing_promise.trace(tracer);\n        }\n        Trace::<'js>::trace(&self.end_of_iteration, tracer);\n    }\n}\n\nunsafe impl<'js> JsLifetime<'js> for ReadableStreamAsyncIterator<'js> {\n    type Changed<'to> = ReadableStreamAsyncIterator<'to>;\n}\n\nimpl<'js> ReadableStreamAsyncIterator<'js> {\n    pub(super) fn new(\n        ctx: Ctx<'js>,\n        objects: ReadableStreamClassObjects<\n            'js,\n            ReadableStreamControllerOwned<'js>,\n            ReadableStreamDefaultReaderOwned<'js>,\n        >,\n        promise_primordials: PromisePrimordials<'js>,\n        prevent_cancel: bool,\n    ) -> Result<Class<'js, Self>> {\n        let end_of_iteration = IteratorPrimordials::get(&ctx)?.end_of_iteration.clone();\n\n        Class::instance(\n            ctx,\n            Self {\n                objects,\n                prevent_cancel,\n                is_finished: Rc::new(AtomicBool::new(false)),\n                ongoing_promise: None,\n                promise_primordials,\n                end_of_iteration,\n            },\n        )\n    }\n}\n\n// Custom JsClass implementation needed until prototype, function names and function lengths can be influenced in the class derivation macro\nimpl<'js> JsClass<'js> for ReadableStreamAsyncIterator<'js> {\n    const NAME: &'static str = \"ReadableStreamAsyncIterator\";\n    type Mutable = rquickjs::class::Writable;\n    fn prototype(ctx: &Ctx<'js>) -> Result<Option<Object<'js>>> {\n        use rquickjs::class::impl_::MethodImplementor;\n        let proto = Object::new(ctx.clone())?;\n        let primordial = IteratorPrimordials::get(ctx)?;\n        proto.set_prototype(Some(&primordial.async_iterator_prototype))?;\n        let implementor = rquickjs::class::impl_::MethodImpl::<Self>::new();\n        implementor.implement(&proto)?;\n        let next_fn: Function<'js> = proto.get(\"next\")?;\n        // yup, the wpt tests really do check these.\n        next_fn.set_name(\"next\")?;\n        let return_fn: Function<'js> = proto.get(\"return\")?;\n        return_fn.set_name(\"return\")?;\n        return_fn.set_length(1)?;\n        Ok(Some(proto))\n    }\n    fn constructor(ctx: &Ctx<'js>) -> Result<Option<Constructor<'js>>> {\n        use rquickjs::class::impl_::ConstructorCreator;\n        let implementor = rquickjs::class::impl_::ConstructorCreate::<Self>::new();\n        (&implementor).create_constructor(ctx)\n    }\n}\nimpl<'js> IntoJs<'js> for ReadableStreamAsyncIterator<'js> {\n    fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {\n        let cls = Class::<Self>::instance(ctx.clone(), self)?;\n        rquickjs::IntoJs::into_js(cls, ctx)\n    }\n}\n\nimpl<'js> FromJs<'js> for ReadableStreamAsyncIterator<'js>\nwhere\n    for<'a> rquickjs::class::impl_::CloneWrapper<'a, Self>:\n        rquickjs::class::impl_::CloneTrait<Self>,\n{\n    fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        use rquickjs::class::impl_::CloneTrait;\n        let value = Class::<Self>::from_js(ctx, value)?;\n        let borrow = value.try_borrow()?;\n        Ok(rquickjs::class::impl_::CloneWrapper(&*borrow).wrap_clone())\n    }\n}\n\n#[methods]\nimpl<'js> ReadableStreamAsyncIterator<'js> {\n    fn next(ctx: Ctx<'js>, iterator: This<OwnedBorrowMut<'js, Self>>) -> Result<Promise<'js>> {\n        let is_finished = iterator.is_finished.clone();\n\n        let next_steps = move |ctx: Ctx<'js>, iterator: &Self, iterator_class: Class<'js, Self>| {\n            if is_finished.load(Ordering::Acquire) {\n                return promise_resolved_with(\n                    &ctx,\n                    &iterator.promise_primordials,\n                    Ok(ReadableStreamReadResult {\n                        value: None,\n                        done: true,\n                    }\n                    .into_js(&ctx)?),\n                );\n            }\n\n            let next_promise = Self::next_steps(&ctx, iterator)?;\n\n            upon_promise(\n                ctx,\n                next_promise,\n                move |ctx, result: std::result::Result<Value<'js>, _>| {\n                    let mut iterator = OwnedBorrowMut::from_class(iterator_class);\n                    match result {\n                        Ok(next) => {\n                            iterator.ongoing_promise = None;\n                            if next.as_symbol() == Some(&iterator.end_of_iteration) {\n                                iterator.is_finished.store(true, Ordering::Release);\n                                Ok(ReadableStreamReadResult {\n                                    value: None,\n                                    done: true,\n                                })\n                            } else {\n                                Ok(ReadableStreamReadResult {\n                                    value: Some(next),\n                                    done: false,\n                                })\n                            }\n                        },\n                        Err(reason) => {\n                            iterator.ongoing_promise = None;\n                            iterator.is_finished.store(true, Ordering::Release);\n                            Err(ctx.throw(reason))\n                        },\n                    }\n                },\n            )\n        };\n\n        let (iterator_class, mut iterator) = class_from_owned_borrow_mut(iterator.0);\n        let ongoing_promise = iterator.ongoing_promise.take();\n\n        let ongoing_promise = match ongoing_promise {\n            Some(ongoing_promise) => upon_promise(\n                ctx,\n                ongoing_promise,\n                move |ctx, _: std::result::Result<Value<'js>, _>| {\n                    let iterator = OwnedBorrow::from_class(iterator_class.clone());\n                    next_steps(ctx, &iterator, iterator_class)\n                },\n            )?,\n            None => next_steps(ctx, &iterator, iterator_class)?,\n        };\n\n        Ok(iterator.ongoing_promise.insert(ongoing_promise).clone())\n    }\n\n    #[qjs(rename = \"return\")]\n    fn r#return(\n        ctx: Ctx<'js>,\n        iterator: This<OwnedBorrowMut<'js, Self>>,\n        value: Opt<Value<'js>>,\n    ) -> Result<Promise<'js>> {\n        let is_finished = iterator.is_finished.clone();\n        let value = value.0.unwrap_or_undefined(&ctx);\n\n        let return_steps = {\n            let value = value.clone();\n            move |ctx: Ctx<'js>, iterator: &Self| {\n                if is_finished.swap(true, Ordering::AcqRel) {\n                    return promise_resolved_with(\n                        &ctx,\n                        &iterator.promise_primordials,\n                        Ok(ReadableStreamReadResult {\n                            value: Some(value),\n                            done: true,\n                        }\n                        .into_js(&ctx)?),\n                    );\n                }\n\n                Self::return_steps(ctx.clone(), iterator, value)\n            }\n        };\n\n        let (iterator_class, mut iterator) = class_from_owned_borrow_mut(iterator.0);\n        let ongoing_promise = iterator.ongoing_promise.take();\n\n        let ongoing_promise = match ongoing_promise {\n            Some(ongoing_promise) => upon_promise(\n                ctx.clone(),\n                ongoing_promise,\n                move |ctx, _: std::result::Result<Value<'js>, _>| {\n                    let iterator = OwnedBorrow::from_class(iterator_class.clone());\n                    return_steps(ctx, &iterator)\n                },\n            )?,\n            None => return_steps(ctx.clone(), &iterator)?,\n        };\n\n        iterator.ongoing_promise = Some(ongoing_promise.clone());\n\n        upon_promise_fulfilment(ctx, ongoing_promise, move |_, ()| {\n            Ok(ReadableStreamReadResult {\n                value: Some(value),\n                done: true,\n            })\n        })\n    }\n}\n\nimpl<'js> ReadableStreamAsyncIterator<'js> {\n    // The get the next iteration result steps for a ReadableStream, given stream and iterator, are:\n    fn next_steps(ctx: &Ctx<'js>, iterator: &Self) -> Result<Promise<'js>> {\n        // Let reader be iterator’s reader.\n        let objects = iterator.objects.clone();\n\n        // Let promise be a new promise.\n        let promise = ResolveablePromise::new(ctx)?;\n\n        // Let readRequest be a new read request with the following items:\n        #[derive(Trace)]\n        struct ReadRequest<'js> {\n            promise: ResolveablePromise<'js>,\n            end_of_iteration: Symbol<'js>,\n        }\n\n        impl<'js> ReadableStreamReadRequest<'js> for ReadRequest<'js> {\n            fn chunk_steps(\n                &self,\n                objects: ReadableStreamDefaultReaderObjects<'js>,\n                chunk: Value<'js>,\n            ) -> Result<ReadableStreamDefaultReaderObjects<'js>> {\n                // Resolve promise with chunk.\n                self.promise.resolve(chunk)?;\n                Ok(objects)\n            }\n\n            fn close_steps(\n                &self,\n                _ctx: &Ctx<'js>,\n                mut objects: ReadableStreamDefaultReaderObjects<'js>,\n            ) -> Result<ReadableStreamDefaultReaderObjects<'js>> {\n                // Perform ! ReadableStreamDefaultReaderRelease(reader).\n                objects =\n                    ReadableStreamDefaultReader::readable_stream_default_reader_release(objects)?;\n\n                // Resolve promise with end of iteration.\n                self.promise.resolve(self.end_of_iteration.clone())?;\n                Ok(objects)\n            }\n\n            fn error_steps(\n                &self,\n                mut objects: ReadableStreamDefaultReaderObjects<'js>,\n                reason: Value<'js>,\n            ) -> Result<ReadableStreamDefaultReaderObjects<'js>> {\n                // Perform ! ReadableStreamDefaultReaderRelease(reader).\n                objects =\n                    ReadableStreamDefaultReader::readable_stream_default_reader_release(objects)?;\n\n                // Reject promise with e.\n                self.promise.reject(reason)?;\n                Ok(objects)\n            }\n        }\n\n        let objects = ReadableStreamObjects::from_class(objects);\n\n        // Perform ! ReadableStreamDefaultReaderRead(this, readRequest).\n        ReadableStreamDefaultReader::readable_stream_default_reader_read(\n            ctx,\n            objects,\n            ReadRequest {\n                promise: promise.clone(),\n                end_of_iteration: iterator.end_of_iteration.clone(),\n            },\n        )?;\n\n        // Return promise.\n        Ok(promise.promise)\n    }\n\n    // The asynchronous iterator return steps for a ReadableStream, given stream, iterator, and arg, are:\n    fn return_steps(ctx: Ctx<'js>, iterator: &Self, arg: Value<'js>) -> Result<Promise<'js>> {\n        // Let reader be iterator’s reader.\n        let objects = ReadableStreamObjects::from_class(iterator.objects.clone());\n\n        // If iterator’s prevent cancel is false:\n        if !iterator.prevent_cancel {\n            // Let result be ! ReadableStreamReaderGenericCancel(reader, arg).\n            let (result, objects) =\n                ReadableStreamGenericReader::readable_stream_reader_generic_cancel(\n                    ctx.clone(),\n                    objects,\n                    arg,\n                )?;\n\n            // Perform ! ReadableStreamDefaultReaderRelease(reader).\n            ReadableStreamDefaultReader::readable_stream_default_reader_release(objects)?;\n\n            // Return result.\n            return Ok(result);\n        }\n\n        // Perform ! ReadableStreamDefaultReaderRelease(reader).\n        ReadableStreamDefaultReader::readable_stream_default_reader_release(objects)?;\n\n        // Return a promise resolved with undefined.\n        Ok(iterator\n            .promise_primordials\n            .promise_resolved_with_undefined\n            .clone())\n    }\n}\n\n#[derive(Clone, JsLifetime, Trace)]\npub(crate) struct IteratorPrimordials<'js> {\n    end_of_iteration: Symbol<'js>,\n    sync_to_async_iterator: Function<'js>,\n    async_iterator_prototype: Object<'js>,\n}\n\nimpl<'js> Primordial<'js> for IteratorPrimordials<'js> {\n    fn new(ctx: &Ctx<'js>) -> Result<Self>\n    where\n        Self: Sized,\n    {\n        let sync_to_async_iterator = ctx.eval::<Function<'js>, _>(\n            r#\"\n            (syncIterable) => (async function* () {\n              return yield* syncIterable;\n            })()\n        \"#,\n        )?;\n\n        // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncIterator\n        // ```js\n        // const AsyncIteratorPrototype = Object.getPrototypeOf(\n        //   Object.getPrototypeOf(Object.getPrototypeOf((async function* () {})())),\n        // );\n        // ```\n        let async_iterator_prototype = ctx\n            .eval::<Object<'js>, _>(\"(async function* () {})()\")?\n            .get_prototype()\n            .as_ref()\n            .and_then(Object::get_prototype)\n            .as_ref()\n            .and_then(Object::get_prototype)\n            .expect(\"async iterator prototype not found\");\n\n        Ok(Self {\n            end_of_iteration: Symbol::for_description(ctx, \"async iterator end of iteration\")?,\n            sync_to_async_iterator,\n            async_iterator_prototype,\n        })\n    }\n}\n\n// https://tc39.es/ecma262/multipage/abstract-operations.html#sec-getmethod\nfn get_method<'js>(\n    ctx: &Ctx<'js>,\n    value: Value<'js>,\n    property: impl IntoAtom<'js>,\n) -> Result<Option<Function<'js>>> {\n    // 1. Let func be ? GetV(V, P).\n    let func = get_v(ctx, value, property)?;\n\n    // 2. If func is either undefined or null, return undefined.\n    if func.is_undefined() || func.is_null() {\n        return Ok(None);\n    }\n\n    match func.into_function() {\n        // 3. If IsCallable(func) is false, throw a TypeError exception.\n        None => Err(Exception::throw_type(ctx, \"not a function\")),\n        // 4. Return func.\n        Some(func) => Ok(Some(func)),\n    }\n}\n\n// https://tc39.es/ecma262/multipage/abstract-operations.html#sec-getv\nfn get_v<'js>(\n    ctx: &Ctx<'js>,\n    value: Value<'js>,\n    property: impl IntoAtom<'js>,\n) -> Result<Value<'js>> {\n    // 1. Let O be ? ToObject(V).\n    let o: Object<'js> = to_object(ctx, value)?;\n\n    // 2. Return ? O.[[Get]](P, V).\n    o.get(property)\n}\n\n// https://tc39.es/ecma262/multipage/abstract-operations.html#sec-toobject\nfn to_object<'js>(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Object<'js>> {\n    let base_primordials = BasePrimordials::get(ctx)?;\n\n    match value.type_of() {\n        // Return a new Boolean object whose [[BooleanData]] internal slot is set to argument\n        Type::Bool => base_primordials.constructor_bool.construct((value,))?,\n        // Return a new Number object whose [[NumberData]] internal slot is set to argument\n        Type::Int | Type::Float => base_primordials.constructor_number.construct((value,))?,\n        // Return a new String object whose [[StringData]] internal slot is set to argument\n        Type::String => base_primordials.constructor_string.construct((value,))?,\n        // Return a new Symbol object whose [[SymbolData]] internal slot is set to argument\n        // `new Symbol` is invalid but we can use `Object(symbol)\n        Type::Symbol => base_primordials.constructor_object.call((value,))?,\n        // Return a new BigInt object whose [[BigIntData]] internal slot is set to argument\n        // `new BigInt` is invalid but we can use `Object(bigInt)\n        Type::BigInt => base_primordials.constructor_object.call((value,))?,\n        // Return argument\n        typ if typ.interpretable_as(Type::Object) => Ok(value.into_object().unwrap()),\n        // Throw a TypeError exception.\n        typ => Err(Exception::throw_type(\n            ctx,\n            &format!(\"{typ} cannot be converted to an object\"),\n        )),\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use llrt_test::test_sync_with;\n    use rquickjs::BigInt;\n\n    #[tokio::test]\n    async fn test_to_object() {\n        test_sync_with(|ctx| {\n            BasePrimordials::init(&ctx)?;\n            let good_values: [Value; 7] = [\n                Value::new_bool(ctx.clone(), false),\n                Value::new_int(ctx.clone(), 123),\n                Value::new_float(ctx.clone(), 1.5),\n                rquickjs::String::from_str(ctx.clone(), \"abc\")?.into_value(),\n                Symbol::for_description(&ctx, \"def\")?.into_value(),\n                BigInt::from_i64(ctx.clone(), 123456)?.into_value(),\n                Object::new(ctx.clone())?.into_value(),\n            ];\n\n            for value in good_values {\n                to_object(&ctx, value)?;\n            }\n\n            let bad_values: [Value; 3] = [\n                Value::new_uninitialized(ctx.clone()),\n                Value::new_undefined(ctx.clone()),\n                Value::new_null(ctx.clone()),\n            ];\n\n            for value in bad_values {\n                let ty = value.type_of();\n                if to_object(&ctx, value).is_ok() {\n                    panic!(\"Values of type {ty} should not be convertible to object\")\n                }\n            }\n\n            Ok(())\n        })\n        .await;\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/readable/mod.rs",
    "content": "mod byob_reader;\nmod byte_controller;\nmod controller;\nmod default_controller;\nmod default_reader;\nmod iterator;\nmod objects;\nmod reader;\nmod stream;\n\npub(crate) use byob_reader::{ArrayConstructorPrimordials, ReadableStreamBYOBReader};\npub(crate) use byte_controller::{ReadableByteStreamController, ReadableStreamBYOBRequest};\npub(crate) use default_controller::ReadableStreamDefaultController;\npub(crate) use default_reader::ReadableStreamDefaultReader;\npub(crate) use iterator::IteratorPrimordials;\npub(crate) use stream::{ReadableStream, ReadableStreamClass};\n"
  },
  {
    "path": "modules/llrt_stream_web/src/readable/objects.rs",
    "content": "use rquickjs::{\n    class::{OwnedBorrowMut, Trace, Tracer},\n    Result,\n};\n\nuse crate::readable::{\n    byob_reader::ReadableStreamBYOBReaderOwned,\n    byte_controller::ReadableByteStreamControllerOwned,\n    controller::{\n        ReadableStreamController, ReadableStreamControllerClass, ReadableStreamControllerOwned,\n    },\n    default_controller::ReadableStreamDefaultControllerOwned,\n    default_reader::{ReadableStreamDefaultReaderOrUndefined, ReadableStreamDefaultReaderOwned},\n    reader::{ReadableStreamReader, ReadableStreamReaderOwned, UndefinedReader},\n    stream::{ReadableStream, ReadableStreamClass, ReadableStreamOwned},\n};\n\npub(super) struct ReadableStreamObjects<'js, C, R> {\n    pub(super) stream: ReadableStreamOwned<'js>,\n    pub(super) controller: C,\n    pub(super) reader: R,\n}\n\npub(super) type ReadableStreamDefaultControllerObjects<'js, R> =\n    ReadableStreamObjects<'js, ReadableStreamDefaultControllerOwned<'js>, R>;\npub(super) type ReadableStreamDefaultReaderObjects<'js, C = ReadableStreamControllerOwned<'js>> =\n    ReadableStreamObjects<'js, C, ReadableStreamDefaultReaderOwned<'js>>;\npub(super) type ReadableByteStreamObjects<'js, R> =\n    ReadableStreamObjects<'js, ReadableByteStreamControllerOwned<'js>, R>;\npub(super) type ReadableStreamBYOBObjects<'js> = ReadableStreamObjects<\n    'js,\n    ReadableByteStreamControllerOwned<'js>,\n    ReadableStreamBYOBReaderOwned<'js>,\n>;\n\npub(super) struct ReadableStreamClassObjects<\n    'js,\n    C: ReadableStreamController<'js>,\n    R: ReadableStreamReader<'js>,\n> {\n    pub(super) stream: ReadableStreamClass<'js>,\n    pub(super) controller: C::Class,\n    pub(super) reader: R::Class,\n}\n\n// derive(Clone) isn't clever enough to figure out that C and R don't need to implement Clone, but only C::Class and R::Class.\nimpl<'js, C: ReadableStreamController<'js>, R: ReadableStreamReader<'js>> Clone\n    for ReadableStreamClassObjects<'js, C, R>\n{\n    fn clone(&self) -> Self {\n        Self {\n            stream: self.stream.clone(),\n            controller: self.controller.clone(),\n            reader: self.reader.clone(),\n        }\n    }\n}\n\n// derive(Trace) isn't clever enough to figure out that C and R don't need to implement Trace, but only C::Class and R::Class.\nimpl<'js, C: ReadableStreamController<'js>, R: ReadableStreamReader<'js>> Trace<'js>\n    for ReadableStreamClassObjects<'js, C, R>\n{\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.stream.trace(tracer);\n        self.controller.trace(tracer);\n        self.reader.trace(tracer);\n    }\n}\n\nimpl<'js, C: ReadableStreamController<'js>, R: ReadableStreamReader<'js>>\n    ReadableStreamClassObjects<'js, C, R>\n{\n    pub(super) fn set_reader<RNext: ReadableStreamReader<'js>>(\n        self,\n        reader: RNext::Class,\n    ) -> ReadableStreamClassObjects<'js, C, RNext> {\n        drop(self.reader);\n        ReadableStreamClassObjects {\n            stream: self.stream,\n            controller: self.controller,\n            reader,\n        }\n    }\n}\n\nimpl<'js, C: ReadableStreamController<'js>, R: ReadableStreamReader<'js>>\n    ReadableStreamObjects<'js, C, R>\n{\n    pub(super) fn with_assert_default_controller(\n        mut self,\n        f: impl FnOnce(\n            ReadableStreamDefaultControllerObjects<'js, R>,\n        ) -> Result<ReadableStreamDefaultControllerObjects<'js, R>>,\n    ) -> Result<Self> {\n        ((), self) = self.with_controller(\n            (),\n            |(), controller| Ok(((), f(controller)?)),\n            |_, _| panic!(\"expected default controller, found byte controller\"),\n        )?;\n        Ok(self)\n    }\n\n    pub(super) fn with_assert_byte_controller(\n        mut self,\n        f: impl FnOnce(ReadableByteStreamObjects<'js, R>) -> Result<ReadableByteStreamObjects<'js, R>>,\n    ) -> Result<Self> {\n        ((), self) = self.with_controller(\n            (),\n            |_, _| panic!(\"expected byte controller, found default controller\"),\n            |(), controller| Ok(((), f(controller)?)),\n        )?;\n        Ok(self)\n    }\n\n    pub(super) fn with_controller<Ctx, O>(\n        self,\n        ctx: Ctx,\n        default: impl FnOnce(\n            Ctx,\n            ReadableStreamDefaultControllerObjects<'js, R>,\n        ) -> Result<(O, ReadableStreamDefaultControllerObjects<'js, R>)>,\n        byte: impl FnOnce(\n            Ctx,\n            ReadableByteStreamObjects<'js, R>,\n        ) -> Result<(O, ReadableByteStreamObjects<'js, R>)>,\n    ) -> Result<(O, Self)> {\n        let ((out, stream, reader), controller) = self.controller.with_controller(\n            (ctx, self.stream, self.reader),\n            |(ctx, stream, reader), controller| {\n                let (out, objects) = default(\n                    ctx,\n                    ReadableStreamObjects {\n                        stream,\n                        controller,\n                        reader,\n                    },\n                )?;\n\n                Ok(((out, objects.stream, objects.reader), objects.controller))\n            },\n            |(ctx, stream, reader), controller| {\n                let (out, objects) = byte(\n                    ctx,\n                    ReadableStreamObjects {\n                        stream,\n                        controller,\n                        reader,\n                    },\n                )?;\n\n                Ok(((out, objects.stream, objects.reader), objects.controller))\n            },\n        )?;\n\n        Ok((\n            out,\n            Self {\n                stream,\n                controller,\n                reader,\n            },\n        ))\n    }\n\n    pub(super) fn with_assert_byob_reader(\n        self,\n        f: impl FnOnce(ReadableStreamBYOBObjects<'js>) -> Result<ReadableStreamBYOBObjects<'js>>,\n    ) -> Result<Self> {\n        self.with_reader(\n            |_| panic!(\"expected byob reader, found default reader\"),\n            f,\n            |_| panic!(\"expected byob reader, found no reader\"),\n        )\n    }\n\n    pub(super) fn with_assert_default_reader(\n        self,\n        f: impl FnOnce(\n            ReadableStreamDefaultReaderObjects<'js, C>,\n        ) -> Result<ReadableStreamDefaultReaderObjects<'js, C>>,\n    ) -> Result<Self> {\n        self.with_reader(\n            f,\n            |_| panic!(\"expected default reader, found byob reader\"),\n            |_| panic!(\"expected default reader, found no reader\"),\n        )\n    }\n\n    pub(super) fn with_reader(\n        mut self,\n        default: impl FnOnce(\n            ReadableStreamDefaultReaderObjects<'js, C>,\n        ) -> Result<ReadableStreamDefaultReaderObjects<'js, C>>,\n        byob: impl FnOnce(ReadableStreamBYOBObjects<'js>) -> Result<ReadableStreamBYOBObjects<'js>>,\n        none: impl FnOnce(\n            ReadableStreamObjects<'js, C, UndefinedReader>,\n        ) -> Result<ReadableStreamObjects<'js, C, UndefinedReader>>,\n    ) -> Result<Self> {\n        ((self.stream, self.controller), self.reader) = self.reader.with_reader(\n            (self.stream, self.controller),\n            |(stream, controller), reader| {\n                let objects = default(ReadableStreamObjects {\n                    stream,\n                    controller,\n                    reader,\n                })?;\n\n                Ok(((objects.stream, objects.controller), objects.reader))\n            },\n            |(mut stream, mut controller), mut reader| {\n                ((stream, reader), controller) = controller.with_controller(\n                    (stream, reader),\n                    |_, _| panic!(\"byob reader must have a byte controller\"),\n                    |(stream, reader), controller| {\n                        let objects = byob(ReadableStreamObjects {\n                            stream,\n                            controller,\n                            reader,\n                        })?;\n\n                        Ok(((objects.stream, objects.reader), objects.controller))\n                    },\n                )?;\n\n                Ok(((stream, controller), reader))\n            },\n            |(stream, controller)| {\n                let objects = none(ReadableStreamObjects {\n                    stream,\n                    controller,\n                    reader: UndefinedReader,\n                })?;\n\n                Ok((objects.stream, objects.controller))\n            },\n        )?;\n\n        Ok(self)\n    }\n\n    pub(super) fn into_inner(self) -> ReadableStreamClassObjects<'js, C, R> {\n        ReadableStreamClassObjects {\n            stream: self.stream.into_inner(),\n            controller: self.controller.into_inner(),\n            reader: self.reader.into_inner(),\n        }\n    }\n\n    pub(super) fn from_class(objects_class: ReadableStreamClassObjects<'js, C, R>) -> Self {\n        Self {\n            stream: OwnedBorrowMut::from_class(objects_class.stream),\n            controller: C::from_class(objects_class.controller),\n            reader: R::from_class(objects_class.reader),\n        }\n    }\n\n    pub(super) fn from_class_no_reader(\n        objects_class: ReadableStreamClassObjects<'js, C, R>,\n    ) -> ReadableStreamObjects<'js, C, UndefinedReader> {\n        ReadableStreamObjects {\n            stream: OwnedBorrowMut::from_class(objects_class.stream),\n            controller: C::from_class(objects_class.controller),\n            reader: UndefinedReader,\n        }\n    }\n\n    pub(super) fn clear_reader(self) -> ReadableStreamObjects<'js, C, UndefinedReader> {\n        drop(self.reader);\n        ReadableStreamObjects {\n            stream: self.stream,\n            controller: self.controller,\n            reader: UndefinedReader,\n        }\n    }\n}\n\nimpl<'js>\n    ReadableStreamDefaultControllerObjects<'js, Option<ReadableStreamDefaultReaderOwned<'js>>>\n{\n    pub(super) fn from_default_controller(\n        controller: ReadableStreamDefaultControllerOwned<'js>,\n    ) -> Self {\n        Self::new_default(\n            OwnedBorrowMut::from_class(controller.stream.clone()),\n            controller,\n        )\n    }\n\n    pub(super) fn new_default(\n        stream: ReadableStreamOwned<'js>,\n        controller: ReadableStreamDefaultControllerOwned<'js>,\n    ) -> Self {\n        ReadableStreamObjects {\n            stream,\n            controller,\n            reader: UndefinedReader,\n        }\n        .refresh_reader()\n    }\n}\n\nimpl<'js, R: ReadableStreamReader<'js>> ReadableStreamDefaultControllerObjects<'js, R> {\n    pub(super) fn refresh_reader(\n        mut self,\n    ) -> ReadableStreamDefaultControllerObjects<'js, Option<ReadableStreamDefaultReaderOwned<'js>>>\n    {\n        drop(self.reader);\n        let reader = self.stream.reader_mut();\n        ReadableStreamObjects {\n            stream: self.stream,\n            controller: self.controller,\n            reader: ReadableStreamReader::try_from_erased(reader)\n                .expect(\"default controller must have default reader or no reader\"),\n        }\n    }\n}\n\nimpl<'js> ReadableByteStreamObjects<'js, UndefinedReader> {\n    pub(super) fn from_byte_controller(controller: ReadableByteStreamControllerOwned<'js>) -> Self {\n        Self::new_byte(\n            OwnedBorrowMut::from_class(controller.stream.clone()),\n            controller,\n        )\n    }\n\n    pub(super) fn new_byte(\n        stream: ReadableStreamOwned<'js>,\n        controller: ReadableByteStreamControllerOwned<'js>,\n    ) -> Self {\n        ReadableStreamObjects {\n            stream,\n            controller,\n            reader: UndefinedReader,\n        }\n    }\n\n    pub(super) fn set_reader<RNext: ReadableStreamReader<'js>>(\n        self,\n        reader: RNext,\n    ) -> ReadableByteStreamObjects<'js, RNext> {\n        ReadableStreamObjects {\n            stream: self.stream,\n            controller: self.controller,\n            reader,\n        }\n    }\n}\n\nimpl<'js> ReadableStreamBYOBObjects<'js> {\n    pub(super) fn from_byob_reader(reader: ReadableStreamBYOBReaderOwned<'js>) -> Self {\n        let stream = OwnedBorrowMut::from_class(\n            reader\n                .generic\n                .stream\n                .clone()\n                .expect(\"ReadableStreamBYOBReader must have a stream\"),\n        );\n        let controller = match &stream.controller {\n            ReadableStreamControllerClass::ReadableStreamByteController(c) => c.clone(),\n            _ => panic!(\"ReadableStreamBYOBReader stream must have byte controller\"),\n        };\n        Self {\n            stream,\n            controller: OwnedBorrowMut::from_class(controller),\n            reader,\n        }\n    }\n}\n\nimpl<'js, R: ReadableStreamReader<'js>> ReadableByteStreamObjects<'js, R> {\n    pub(super) fn refresh_reader(\n        mut self,\n    ) -> ReadableByteStreamObjects<'js, Option<ReadableStreamReaderOwned<'js>>> {\n        drop(self.reader);\n        let reader = self.stream.reader_mut();\n        ReadableStreamObjects {\n            stream: self.stream,\n            controller: self.controller,\n            reader,\n        }\n    }\n}\n\nimpl<'js, C: ReadableStreamController<'js>, R: ReadableStreamDefaultReaderOrUndefined<'js>>\n    ReadableStreamObjects<'js, C, R>\n{\n    pub(super) fn with_some_reader(\n        self,\n        default: impl FnOnce(\n            ReadableStreamDefaultReaderObjects<'js, C>,\n        ) -> Result<ReadableStreamDefaultReaderObjects<'js, C>>,\n        none: impl FnOnce(\n            ReadableStreamObjects<'js, C, UndefinedReader>,\n        ) -> Result<ReadableStreamObjects<'js, C, UndefinedReader>>,\n    ) -> Result<Self> {\n        self.with_reader(\n            default,\n            |_| panic!(\"byob reader cannot implement DefaultReaderOrUndefined\"),\n            none,\n        )\n    }\n}\n\nimpl<'js> ReadableStreamObjects<'js, ReadableStreamControllerOwned<'js>, UndefinedReader> {\n    pub(super) fn from_stream(stream: ReadableStreamOwned<'js>) -> Self {\n        let controller = ReadableStreamControllerOwned::from_class(stream.controller.clone());\n        Self::new(stream, controller)\n    }\n\n    fn new(\n        stream: OwnedBorrowMut<'js, ReadableStream<'js>>,\n        controller: ReadableStreamControllerOwned<'js>,\n    ) -> Self {\n        ReadableStreamObjects {\n            stream,\n            controller,\n            reader: UndefinedReader,\n        }\n    }\n}\n\nimpl<'js, R: ReadableStreamReader<'js>>\n    ReadableStreamObjects<'js, ReadableStreamControllerOwned<'js>, R>\n{\n    pub(super) fn refresh_reader(\n        mut self,\n    ) -> ReadableStreamObjects<\n        'js,\n        ReadableStreamControllerOwned<'js>,\n        Option<ReadableStreamReaderOwned<'js>>,\n    > {\n        drop(self.reader);\n        let reader = self.stream.reader_mut();\n        ReadableStreamObjects {\n            stream: self.stream,\n            controller: self.controller,\n            reader,\n        }\n    }\n}\n\nimpl<'js> ReadableStreamDefaultReaderObjects<'js> {\n    pub(super) fn from_default_reader(reader: ReadableStreamDefaultReaderOwned<'js>) -> Self {\n        let stream = OwnedBorrowMut::from_class(\n            reader\n                .generic\n                .stream\n                .clone()\n                .expect(\"ReadableStreamDefaultReader must have a stream\"),\n        );\n        let controller = ReadableStreamControllerOwned::from_class(stream.controller.clone());\n        Self {\n            stream,\n            controller,\n            reader,\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/readable/reader.rs",
    "content": "use rquickjs::{\n    class::{OwnedBorrowMut, Trace, Tracer},\n    function::Constructor,\n    Ctx, Error, FromJs, Function, IntoJs, JsLifetime, Promise, Result, Value,\n};\n\nuse crate::{\n    readable::{\n        byob_reader::ReadableStreamBYOBReader,\n        byob_reader::{ReadableStreamBYOBReaderClass, ReadableStreamBYOBReaderOwned},\n        controller::ReadableStreamController,\n        default_reader::{\n            ReadableStreamDefaultReader, ReadableStreamDefaultReaderClass,\n            ReadableStreamDefaultReaderOwned,\n        },\n        objects::ReadableStreamObjects,\n        stream::{ReadableStream, ReadableStreamClass, ReadableStreamOwned, ReadableStreamState},\n    },\n    utils::promise::{PromisePrimordials, ResolveablePromise},\n};\n\npub(super) trait ReadableStreamReader<'js>: Sized + 'js {\n    type Class: Clone + Trace<'js>;\n\n    fn with_reader<C>(\n        self,\n        ctx: C,\n        default: impl FnOnce(\n            C,\n            ReadableStreamDefaultReaderOwned<'js>,\n        ) -> Result<(C, ReadableStreamDefaultReaderOwned<'js>)>,\n        byob: impl FnOnce(\n            C,\n            ReadableStreamBYOBReaderOwned<'js>,\n        ) -> Result<(C, ReadableStreamBYOBReaderOwned<'js>)>,\n        none: impl FnOnce(C) -> Result<C>,\n    ) -> Result<(C, Self)>;\n\n    fn into_inner(self) -> Self::Class;\n\n    fn from_class(class: Self::Class) -> Self;\n\n    fn try_from_erased(erased: Option<ReadableStreamReaderOwned<'js>>) -> Option<Self>;\n}\n\n// typedef (ReadableStreamDefaultController or ReadableByteStreamController) ReadableStreamController;\n#[derive(JsLifetime, Clone, PartialEq, Eq)]\npub enum ReadableStreamReaderClass<'js> {\n    ReadableStreamDefaultReader(ReadableStreamDefaultReaderClass<'js>),\n    ReadableStreamBYOBReader(ReadableStreamBYOBReaderClass<'js>),\n}\n\nimpl<'js> ReadableStreamReaderClass<'js> {\n    pub(super) fn closed_promise(&self) -> Promise<'js> {\n        match self {\n            Self::ReadableStreamDefaultReader(r) => {\n                r.borrow().generic.closed_promise.promise.clone()\n            },\n            Self::ReadableStreamBYOBReader(r) => r.borrow().generic.closed_promise.promise.clone(),\n        }\n    }\n}\n\nimpl<'js> From<ReadableStreamDefaultReaderClass<'js>> for ReadableStreamReaderClass<'js> {\n    fn from(value: ReadableStreamDefaultReaderClass<'js>) -> Self {\n        Self::ReadableStreamDefaultReader(value)\n    }\n}\n\nimpl<'js> From<ReadableStreamBYOBReaderClass<'js>> for ReadableStreamReaderClass<'js> {\n    fn from(value: ReadableStreamBYOBReaderClass<'js>) -> Self {\n        Self::ReadableStreamBYOBReader(value)\n    }\n}\n\npub(super) enum ReadableStreamReaderOwned<'js> {\n    ReadableStreamDefaultReader(ReadableStreamDefaultReaderOwned<'js>),\n    ReadableStreamBYOBReader(ReadableStreamBYOBReaderOwned<'js>),\n}\n\nimpl<'js> ReadableStreamReader<'js> for ReadableStreamReaderOwned<'js> {\n    type Class = ReadableStreamReaderClass<'js>;\n\n    fn with_reader<C>(\n        self,\n        ctx: C,\n        default: impl FnOnce(\n            C,\n            ReadableStreamDefaultReaderOwned<'js>,\n        ) -> Result<(C, ReadableStreamDefaultReaderOwned<'js>)>,\n        byob: impl FnOnce(\n            C,\n            ReadableStreamBYOBReaderOwned<'js>,\n        ) -> Result<(C, ReadableStreamBYOBReaderOwned<'js>)>,\n        _: impl FnOnce(C) -> Result<C>,\n    ) -> Result<(C, Self)> {\n        match self {\n            Self::ReadableStreamDefaultReader(r) => {\n                let (ctx, r) = default(ctx, r)?;\n                Ok((ctx, Self::ReadableStreamDefaultReader(r)))\n            },\n            Self::ReadableStreamBYOBReader(r) => {\n                let (ctx, r) = byob(ctx, r)?;\n                Ok((ctx, Self::ReadableStreamBYOBReader(r)))\n            },\n        }\n    }\n\n    fn into_inner(self) -> Self::Class {\n        match self {\n            ReadableStreamReaderOwned::ReadableStreamDefaultReader(r) => {\n                ReadableStreamReaderClass::ReadableStreamDefaultReader(r.into_inner())\n            },\n            ReadableStreamReaderOwned::ReadableStreamBYOBReader(r) => {\n                ReadableStreamReaderClass::ReadableStreamBYOBReader(r.into_inner())\n            },\n        }\n    }\n\n    fn from_class(class: Self::Class) -> Self {\n        match class {\n            ReadableStreamReaderClass::ReadableStreamDefaultReader(r) => {\n                Self::ReadableStreamDefaultReader(OwnedBorrowMut::from_class(r))\n            },\n            ReadableStreamReaderClass::ReadableStreamBYOBReader(r) => {\n                Self::ReadableStreamBYOBReader(OwnedBorrowMut::from_class(r))\n            },\n        }\n    }\n\n    fn try_from_erased(erased: Option<ReadableStreamReaderOwned<'js>>) -> Option<Self> {\n        erased\n    }\n}\n\nimpl<'js, T: ReadableStreamReader<'js>> ReadableStreamReader<'js> for Option<T> {\n    type Class = Option<<T as ReadableStreamReader<'js>>::Class>;\n\n    fn with_reader<C>(\n        self,\n        mut ctx: C,\n        default: impl FnOnce(\n            C,\n            ReadableStreamDefaultReaderOwned<'js>,\n        ) -> Result<(C, ReadableStreamDefaultReaderOwned<'js>)>,\n        byob: impl FnOnce(\n            C,\n            ReadableStreamBYOBReaderOwned<'js>,\n        ) -> Result<(C, ReadableStreamBYOBReaderOwned<'js>)>,\n        none: impl FnOnce(C) -> Result<C>,\n    ) -> Result<(C, Self)> {\n        match self {\n            Some(mut reader) => {\n                (ctx, reader) = reader.with_reader(ctx, default, byob, none)?;\n                Ok((ctx, Some(reader)))\n            },\n            None => Ok((none(ctx)?, None)),\n        }\n    }\n\n    fn into_inner(self) -> Self::Class {\n        self.map(ReadableStreamReader::into_inner)\n    }\n\n    fn from_class(class: Self::Class) -> Self {\n        class.map(ReadableStreamReader::from_class)\n    }\n\n    fn try_from_erased(erased: Option<ReadableStreamReaderOwned<'js>>) -> Option<Self> {\n        match erased {\n            Some(r) => Some(Some(T::try_from_erased(Some(r))?)),\n            None => Some(None),\n        }\n    }\n}\n\n#[derive(Clone, Trace)]\npub(super) struct UndefinedReader;\n\nimpl<'js> ReadableStreamReader<'js> for UndefinedReader {\n    type Class = UndefinedReader;\n\n    fn with_reader<C>(\n        self,\n        ctx: C,\n        _: impl FnOnce(\n            C,\n            ReadableStreamDefaultReaderOwned<'js>,\n        ) -> Result<(C, ReadableStreamDefaultReaderOwned<'js>)>,\n        _: impl FnOnce(\n            C,\n            ReadableStreamBYOBReaderOwned<'js>,\n        ) -> Result<(C, ReadableStreamBYOBReaderOwned<'js>)>,\n        none: impl FnOnce(C) -> Result<C>,\n    ) -> Result<(C, Self)> {\n        Ok((none(ctx)?, self))\n    }\n\n    fn into_inner(self) -> Self::Class {\n        UndefinedReader\n    }\n\n    fn from_class(_: Self::Class) -> Self {\n        UndefinedReader\n    }\n\n    fn try_from_erased(erased: Option<ReadableStreamReaderOwned<'js>>) -> Option<Self> {\n        match erased {\n            None => Some(UndefinedReader),\n            _ => None,\n        }\n    }\n}\n\nimpl<'js> From<ReadableStreamDefaultReaderOwned<'js>> for ReadableStreamReaderOwned<'js> {\n    fn from(value: ReadableStreamDefaultReaderOwned<'js>) -> Self {\n        Self::ReadableStreamDefaultReader(value)\n    }\n}\n\nimpl<'js> From<ReadableStreamBYOBReaderOwned<'js>> for ReadableStreamReaderOwned<'js> {\n    fn from(value: ReadableStreamBYOBReaderOwned<'js>) -> Self {\n        Self::ReadableStreamBYOBReader(value)\n    }\n}\n\n#[derive(JsLifetime, Trace)]\npub struct ReadableStreamGenericReader<'js> {\n    pub(super) closed_promise: ResolveablePromise<'js>,\n    pub(super) stream: Option<ReadableStreamClass<'js>>,\n\n    #[qjs(skip_trace)]\n    pub(super) promise_primordials: PromisePrimordials<'js>,\n    #[qjs(skip_trace)]\n    pub(super) constructor_type_error: Constructor<'js>,\n    #[qjs(skip_trace)]\n    pub(super) constructor_range_error: Constructor<'js>,\n    #[qjs(skip_trace)]\n    pub(super) function_array_buffer_is_view: Function<'js>,\n}\n\nimpl<'js> ReadableStreamGenericReader<'js> {\n    pub(super) fn readable_stream_reader_generic_initialize(\n        ctx: &Ctx<'js>,\n        stream: OwnedBorrowMut<'js, ReadableStream<'js>>,\n    ) -> Result<Self> {\n        let closed_promise = match stream.state {\n            // If stream.[[state]] is \"readable\",\n            ReadableStreamState::Readable => {\n                // Set reader.[[closedPromise]] to a new promise.\n                ResolveablePromise::new(ctx)?\n            },\n            // Otherwise, if stream.[[state]] is \"closed\",\n            ReadableStreamState::Closed => {\n                // Set reader.[[closedPromise]] to a promise resolved with undefined.\n                ResolveablePromise::resolved_with_undefined(&stream.promise_primordials)\n            },\n            // Otherwise,\n            ReadableStreamState::Errored(ref stored_error) => {\n                // Set reader.[[closedPromise]] to a promise rejected with stream.[[storedError]].\n                let promise = ResolveablePromise::rejected_with(\n                    &stream.promise_primordials,\n                    stored_error.clone(),\n                )?;\n\n                // Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.\n                promise.set_is_handled()?;\n\n                promise\n            },\n        };\n\n        let promise_primordials = stream.promise_primordials.clone();\n        let constructor_type_error = stream.constructor_type_error.clone();\n        let constructor_range_error = stream.constructor_range_error.clone();\n        let function_array_buffer_is_view = stream.function_array_buffer_is_view.clone();\n\n        Ok(Self {\n            // Set reader.[[stream]] to stream.\n            stream: Some(stream.into_inner()),\n            closed_promise,\n            promise_primordials,\n            constructor_type_error,\n            constructor_range_error,\n            function_array_buffer_is_view,\n        })\n    }\n\n    pub(super) fn readable_stream_reader_generic_release(\n        &mut self,\n\n        stream: &mut ReadableStream<'js>,\n        controller_release_steps: impl FnOnce(),\n    ) -> Result<()> {\n        // Let stream be reader.[[stream]].\n        // Assert: stream is not undefined.\n\n        // If stream.[[state]] is \"readable\", reject reader.[[closedPromise]] with a TypeError exception.\n        if let ReadableStreamState::Readable = stream.state {\n            self.closed_promise.reject_with_constructor(\n                &stream.constructor_type_error,\n                \"Reader was released and can no longer be used to monitor the stream's closedness\",\n            )?;\n        } else {\n            // Otherwise, set reader.[[closedPromise]] to a promise rejected with a TypeError exception.\n            self.closed_promise = ResolveablePromise::rejected_with_constructor(\n                &stream.promise_primordials,\n                &stream.constructor_type_error,\n                \"Reader was released and can no longer be used to monitor the stream's closedness\",\n            )?;\n        }\n\n        // Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.\n        self.closed_promise.set_is_handled()?;\n\n        // Perform ! stream.[[controller]].[[ReleaseSteps]]().\n        controller_release_steps();\n\n        // Set stream.[[reader]] to undefined.\n        stream.reader = None;\n\n        // Set reader.[[stream]] to undefined.\n        self.stream = None;\n\n        Ok(())\n    }\n\n    pub(super) fn readable_stream_reader_generic_cancel<\n        C: ReadableStreamController<'js>,\n        R: ReadableStreamReader<'js>,\n    >(\n        ctx: Ctx<'js>,\n        // Let stream be reader.[[stream]].\n        objects: ReadableStreamObjects<'js, C, R>,\n        reason: Value<'js>,\n    ) -> Result<(Promise<'js>, ReadableStreamObjects<'js, C, R>)> {\n        // Return ! ReadableStreamCancel(stream, reason).\n        ReadableStream::readable_stream_cancel(ctx, objects, reason)\n    }\n}\n\nimpl<'js> ReadableStreamReaderClass<'js> {\n    pub(super) fn acquire_readable_stream_default_reader(\n        ctx: Ctx<'js>,\n        stream: ReadableStreamOwned<'js>,\n    ) -> Result<(\n        ReadableStreamOwned<'js>,\n        ReadableStreamDefaultReaderClass<'js>,\n    )> {\n        ReadableStreamDefaultReader::set_up_readable_stream_default_reader(&ctx, stream)\n    }\n\n    pub(super) fn acquire_readable_stream_byob_reader(\n        ctx: Ctx<'js>,\n        stream: ReadableStreamOwned<'js>,\n    ) -> Result<(ReadableStreamOwned<'js>, ReadableStreamBYOBReaderClass<'js>)> {\n        ReadableStreamBYOBReader::set_up_readable_stream_byob_reader(ctx, stream)\n    }\n}\n\nimpl<'js> IntoJs<'js> for ReadableStreamReaderClass<'js> {\n    fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {\n        match self {\n            Self::ReadableStreamDefaultReader(r) => r.into_js(ctx),\n            Self::ReadableStreamBYOBReader(r) => r.into_js(ctx),\n        }\n    }\n}\n\nimpl<'js> Trace<'js> for ReadableStreamReaderClass<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        match self {\n            Self::ReadableStreamDefaultReader(r) => r.trace(tracer),\n            Self::ReadableStreamBYOBReader(r) => r.trace(tracer),\n        }\n    }\n}\n\nimpl<'js> FromJs<'js> for ReadableStreamReaderClass<'js> {\n    fn from_js(_ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        let ty_name = value.type_name();\n        let obj = value\n            .as_object()\n            .ok_or(Error::new_from_js(ty_name, \"Object\"))?;\n\n        if let Ok(default) = obj.into_class() {\n            return Ok(Self::ReadableStreamDefaultReader(default));\n        }\n\n        if let Ok(default) = obj.into_class() {\n            return Ok(Self::ReadableStreamBYOBReader(default));\n        }\n\n        Err(Error::new_from_js(ty_name, \"ReadableStreamReader\"))\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/readable/stream/algorithms.rs",
    "content": "use std::rc::Rc;\n\nuse llrt_utils::option::{Null, Undefined};\nuse rquickjs::prelude::OnceFn;\nuse rquickjs::{\n    class::Trace, prelude::This, Ctx, Function, JsLifetime, Object, Promise, Result, Value,\n};\n\nuse crate::{\n    readable::controller::ReadableStreamControllerClass,\n    utils::promise::{promise_resolved_with, PromisePrimordials},\n};\n\n#[derive(Clone)]\npub(crate) enum StartAlgorithm<'js> {\n    ReturnUndefined,\n    Function {\n        f: Function<'js>,\n        underlying_source: Null<Undefined<Object<'js>>>,\n    },\n}\n\nimpl<'js> StartAlgorithm<'js> {\n    pub(crate) fn call(\n        &self,\n        ctx: Ctx<'js>,\n        controller: ReadableStreamControllerClass<'js>,\n    ) -> Result<Value<'js>> {\n        match self {\n            StartAlgorithm::ReturnUndefined => Ok(Value::new_undefined(ctx.clone())),\n            StartAlgorithm::Function {\n                f,\n                underlying_source,\n            } => f.call::<_, Value>((This(underlying_source.clone()), controller)),\n        }\n    }\n}\n\n#[derive(Trace, Clone)]\npub(crate) enum PullAlgorithm<'js> {\n    ReturnPromiseUndefined,\n    Function {\n        f: Function<'js>,\n        underlying_source: Null<Undefined<Object<'js>>>,\n    },\n    RustFunction(#[qjs(skip_trace)] Rc<PullRustFunction<'js>>),\n}\n\nunsafe impl<'js> JsLifetime<'js> for PullAlgorithm<'js> {\n    type Changed<'to> = PullAlgorithm<'to>;\n}\n\ntype PullRustFunction<'js> =\n    Box<dyn Fn(Ctx<'js>, ReadableStreamControllerClass<'js>) -> Result<Promise<'js>> + 'js>;\n\nimpl<'js> PullAlgorithm<'js> {\n    pub(super) fn from_fn(\n        f: impl Fn(Ctx<'js>, ReadableStreamControllerClass<'js>) -> Result<Promise<'js>> + 'js,\n    ) -> Self {\n        Self::RustFunction(Rc::new(Box::new(f)))\n    }\n\n    pub(crate) fn call(\n        &self,\n        ctx: Ctx<'js>,\n        promise_primordials: &PromisePrimordials<'js>,\n        controller: ReadableStreamControllerClass<'js>,\n    ) -> Result<Promise<'js>> {\n        match self {\n            PullAlgorithm::ReturnPromiseUndefined => {\n                Ok(promise_primordials.promise_resolved_with_undefined.clone())\n            },\n            PullAlgorithm::Function {\n                f,\n                underlying_source,\n            } => promise_resolved_with(\n                &ctx,\n                promise_primordials,\n                f.call::<_, Value>((This(underlying_source.clone()), controller)),\n            ),\n            PullAlgorithm::RustFunction(f) => f(ctx, controller),\n        }\n    }\n}\n\n#[derive(Clone, Trace)]\npub(crate) enum CancelAlgorithm<'js> {\n    ReturnPromiseUndefined,\n    Function {\n        f: Function<'js>,\n        underlying_source: Null<Undefined<Object<'js>>>,\n    },\n    RustFunction(#[qjs(skip_trace)] Rc<OnceFn<CancelRustFunction<'js>>>),\n}\n\nunsafe impl<'js> JsLifetime<'js> for CancelAlgorithm<'js> {\n    type Changed<'to> = CancelAlgorithm<'to>;\n}\n\ntype CancelRustFunction<'js> = Box<dyn FnOnce(Value<'js>) -> Result<Promise<'js>> + 'js>;\n\nimpl<'js> CancelAlgorithm<'js> {\n    pub(super) fn from_fn(f: impl FnOnce(Value<'js>) -> Result<Promise<'js>> + 'js) -> Self {\n        Self::RustFunction(Rc::new(OnceFn::new(Box::new(f))))\n    }\n\n    pub(crate) fn call(\n        &self,\n        ctx: Ctx<'js>,\n        promise_primordials: &PromisePrimordials<'js>,\n        reason: Value<'js>,\n    ) -> Result<Promise<'js>> {\n        match self {\n            CancelAlgorithm::ReturnPromiseUndefined => {\n                Ok(promise_primordials.promise_resolved_with_undefined.clone())\n            },\n            CancelAlgorithm::Function {\n                f,\n                underlying_source,\n            } => {\n                let result: Result<Value> = f.call((This(underlying_source.clone()), reason));\n                let promise = promise_resolved_with(&ctx, promise_primordials, result);\n                promise\n            },\n            CancelAlgorithm::RustFunction(f) => {\n                f.take().expect(\"cancel algorithm must only be called once\")(reason)\n            },\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/readable/stream/mod.rs",
    "content": "use std::{cell::OnceCell, panic, rc::Rc};\n\nuse crate::{\n    queuing_strategy::{QueuingStrategy, SizeAlgorithm},\n    readable::{\n        byob_reader::{ReadableStreamBYOBReader, ReadableStreamReadIntoRequest, ViewBytes},\n        byte_controller::{ReadableByteStreamController, ReadableByteStreamControllerClass},\n        controller::{ReadableStreamController, ReadableStreamControllerClass},\n        default_controller::{\n            ReadableStreamDefaultController, ReadableStreamDefaultControllerOwned,\n        },\n        default_reader::{ReadableStreamDefaultReader, ReadableStreamReadRequest},\n        iterator::{IteratorKind, IteratorRecord, ReadableStreamAsyncIterator},\n        objects::{\n            ReadableStreamBYOBObjects, ReadableStreamClassObjects,\n            ReadableStreamDefaultReaderObjects, ReadableStreamObjects,\n        },\n        reader::{\n            ReadableStreamReader, ReadableStreamReaderClass, ReadableStreamReaderOwned,\n            UndefinedReader,\n        },\n    },\n    readable_writable_pair::ReadableWritablePair,\n    utils::{\n        promise::{\n            promise_rejected_catch, promise_rejected_with, promise_rejected_with_constructor,\n            promise_resolved_with, upon_promise_fulfilment, with_promise_result,\n            PromisePrimordials,\n        },\n        UnwrapOrUndefined, ValueOrUndefined,\n    },\n    writable::WritableStreamOwned,\n};\n\nuse algorithms::{CancelAlgorithm, PullAlgorithm, StartAlgorithm};\nuse pipe::StreamPipeOptions;\nuse source::UnderlyingSource;\n\nuse llrt_utils::{\n    option::{Null, NullableOpt, Undefined},\n    primordials::{BasePrimordials, Primordial},\n    result::ResultExt,\n};\nuse rquickjs::{\n    atom::PredefinedAtom,\n    class::{OwnedBorrowMut, Trace},\n    function::Constructor,\n    prelude::{List, Opt, This},\n    Class, Coerced, Ctx, Error, Exception, FromJs, Function, IntoJs, JsLifetime, Object, Promise,\n    Result, Value,\n};\n\npub(super) mod algorithms;\nmod pipe;\npub(super) mod source;\nmod tee;\n\n#[rquickjs::class]\n#[derive(JsLifetime)]\npub(crate) struct ReadableStream<'js> {\n    pub controller: ReadableStreamControllerClass<'js>,\n    pub disturbed: bool,\n    pub state: ReadableStreamState<'js>,\n    pub reader: Option<ReadableStreamReaderClass<'js>>,\n    pub promise_primordials: PromisePrimordials<'js>,\n    pub constructor_type_error: Constructor<'js>,\n    pub constructor_range_error: Constructor<'js>,\n    pub function_array_buffer_is_view: Function<'js>,\n}\n\nimpl<'js> Trace<'js> for ReadableStream<'js> {\n    fn trace<'a>(&self, tracer: rquickjs::class::Tracer<'a, 'js>) {\n        self.controller.trace(tracer);\n        self.state.trace(tracer);\n        self.reader.trace(tracer);\n\n        self.promise_primordials.trace(tracer);\n        self.constructor_type_error.trace(tracer);\n        self.constructor_range_error.trace(tracer);\n        self.function_array_buffer_is_view.trace(tracer);\n    }\n}\n\npub(crate) type ReadableStreamClass<'js> = Class<'js, ReadableStream<'js>>;\npub(crate) type ReadableStreamOwned<'js> = OwnedBorrowMut<'js, ReadableStream<'js>>;\n\n#[derive(Debug, Trace, Clone, JsLifetime)]\npub enum ReadableStreamState<'js> {\n    Readable,\n    Closed,\n    Errored(Value<'js>),\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl<'js> ReadableStream<'js> {\n    // Streams Spec: 4.2.4: https://streams.spec.whatwg.org/#rs-prototype\n    // constructor(optional object underlyingSource, optional QueuingStrategy strategy = {});\n    #[qjs(constructor)]\n    fn new(\n        ctx: Ctx<'js>,\n        underlying_source: Opt<Undefined<Object<'js>>>,\n        queuing_strategy: Opt<Undefined<QueuingStrategy<'js>>>,\n    ) -> Result<Class<'js, Self>> {\n        // If underlyingSource is missing, set it to null.\n        let underlying_source = Null(underlying_source.0);\n\n        // Let underlyingSourceDict be underlyingSource, converted to an IDL value of type UnderlyingSource.\n        let underlying_source_dict = match underlying_source {\n            Null(None) | Null(Some(Undefined(None))) => UnderlyingSource::default(),\n            Null(Some(Undefined(Some(ref obj)))) => UnderlyingSource::from_object(obj.clone())?,\n        };\n\n        let promise_primordials = PromisePrimordials::get(&ctx)?.clone();\n        let base_primordials = BasePrimordials::get(&ctx)?;\n\n        let stream_class = Class::instance(\n            ctx.clone(),\n            Self {\n                // Set stream.[[state]] to \"readable\".\n                state: ReadableStreamState::Readable,\n                // Set stream.[[reader]] and stream.[[storedError]] to undefined.\n                reader: None,\n                // Set stream.[[disturbed]] to false.\n                disturbed: false,\n                controller: ReadableStreamControllerClass::Uninitialised,\n                constructor_type_error: base_primordials.constructor_type_error.clone(),\n                constructor_range_error: base_primordials.constructor_range_error.clone(),\n                function_array_buffer_is_view: base_primordials\n                    .function_array_buffer_is_view\n                    .clone(),\n                promise_primordials,\n            },\n        )?;\n        drop(base_primordials);\n        let stream = OwnedBorrowMut::from_class(stream_class.clone());\n        let queuing_strategy = queuing_strategy.0.and_then(|qs| qs.0);\n\n        match underlying_source_dict.r#type {\n            // If underlyingSourceDict[\"type\"] is \"bytes\":\n            Some(ReadableStreamType::Bytes) => {\n                // If strategy[\"size\"] exists, throw a RangeError exception.\n                if queuing_strategy\n                    .as_ref()\n                    .and_then(|qs| qs.size.as_ref())\n                    .is_some()\n                {\n                    return Err(Exception::throw_range(\n                        &ctx,\n                        \"The strategy for a byte stream cannot have a size function\",\n                    ));\n                }\n                // Let highWaterMark be ? ExtractHighWaterMark(strategy, 0).\n                let high_water_mark =\n                    QueuingStrategy::extract_high_water_mark(&ctx, queuing_strategy, 0.0)?;\n\n                // Perform ? SetUpReadableByteStreamControllerFromUnderlyingSource(this, underlyingSource, underlyingSourceDict, highWaterMark).\n                ReadableByteStreamController::set_up_readable_byte_stream_controller_from_underlying_source(\n                    &ctx,\n                    stream,\n                    underlying_source,\n                    underlying_source_dict,\n                    high_water_mark,\n                )?;\n            },\n            // Otherwise,\n            None => {\n                // Let sizeAlgorithm be ! ExtractSizeAlgorithm(strategy).\n                let size_algorithm =\n                    QueuingStrategy::extract_size_algorithm(queuing_strategy.as_ref());\n\n                // Let highWaterMark be ? ExtractHighWaterMark(strategy, 1).\n                let high_water_mark =\n                    QueuingStrategy::extract_high_water_mark(&ctx, queuing_strategy, 1.0)?;\n\n                // Perform ? SetUpReadableStreamDefaultControllerFromUnderlyingSource(this, underlyingSource, underlyingSourceDict, highWaterMark, sizeAlgorithm).\n                ReadableStreamDefaultController::set_up_readable_stream_default_controller_from_underlying_source(\n                    ctx,\n                    stream,\n                    underlying_source,\n                    underlying_source_dict,\n                    high_water_mark,\n                    size_algorithm,\n                )?;\n            },\n        }\n\n        Ok(stream_class)\n    }\n\n    // static ReadableStream from(any asyncIterable);\n    #[qjs(static)]\n    fn from(ctx: Ctx<'js>, async_iterable: Value<'js>) -> Result<Class<'js, Self>> {\n        // Return ? ReadableStreamFromIterable(asyncIterable).\n        Self::readable_stream_from_iterable(&ctx, async_iterable)\n    }\n\n    // readonly attribute boolean locked;\n    #[qjs(get)]\n    fn locked(&self) -> bool {\n        // Return ! IsReadableStreamLocked(this).\n        self.is_readable_stream_locked()\n    }\n\n    // Promise<undefined> cancel(optional any reason);\n    fn cancel(\n        ctx: Ctx<'js>,\n        stream: This<OwnedBorrowMut<'js, Self>>,\n        reason: Opt<Value<'js>>,\n    ) -> Result<Promise<'js>> {\n        // If ! IsReadableStreamLocked(this) is true, return a promise rejected with a TypeError exception.\n        if stream.is_readable_stream_locked() {\n            return promise_rejected_with_constructor(\n                &stream.constructor_type_error,\n                &stream.promise_primordials,\n                \"Cannot cancel a stream that already has a reader\",\n            );\n        }\n\n        let objects = ReadableStreamObjects::from_stream(stream.0).refresh_reader();\n\n        let (promise, _) =\n            Self::readable_stream_cancel(ctx.clone(), objects, reason.0.unwrap_or_undefined(&ctx))?;\n        Ok(promise)\n    }\n\n    // ReadableStreamReader getReader(optional ReadableStreamGetReaderOptions options = {});\n    fn get_reader(\n        ctx: Ctx<'js>,\n        stream: This<OwnedBorrowMut<'js, Self>>,\n        options: Opt<Option<ReadableStreamGetReaderOptions>>,\n    ) -> Result<ReadableStreamReaderClass<'js>> {\n        // If options[\"mode\"] does not exist, return ? AcquireReadableStreamDefaultReader(this).\n        let reader = match options.0 {\n            None | Some(None | Some(ReadableStreamGetReaderOptions { mode: None })) => {\n                let (_, reader) =\n                    ReadableStreamReaderClass::acquire_readable_stream_default_reader(\n                        ctx.clone(),\n                        stream.0,\n                    )?;\n                reader.into()\n            },\n            // Return ? AcquireReadableStreamBYOBReader(this).\n            Some(Some(ReadableStreamGetReaderOptions {\n                mode: Some(ReadableStreamReaderMode::Byob),\n            })) => {\n                let (_, reader) = ReadableStreamReaderClass::acquire_readable_stream_byob_reader(\n                    ctx.clone(),\n                    stream.0,\n                )?;\n                reader.into()\n            },\n        };\n\n        Ok(reader)\n    }\n\n    // ReadableStream pipeThrough(ReadableWritablePair transform, optional StreamPipeOptions options = {});\n    fn pipe_through(\n        ctx: Ctx<'js>,\n        stream: This<OwnedBorrowMut<'js, Self>>,\n        transform: ReadableWritablePair<'js>,\n        options: NullableOpt<StreamPipeOptions<'js>>,\n    ) -> Result<ReadableStreamClass<'js>> {\n        // If ! IsReadableStreamLocked(this) is true, throw a TypeError exception.\n        if stream.is_readable_stream_locked() {\n            return Err(Exception::throw_type(\n                &ctx,\n                \"ReadableStream.prototype.pipeThrough cannot be used on a locked ReadableStream\",\n            ));\n        }\n\n        let readable_class = transform.readable.clone();\n        let writable = OwnedBorrowMut::from_class(transform.writable);\n\n        // If ! IsWritableStreamLocked(transform[\"writable\"]) is true, throw a TypeError exception.\n        if writable.is_writable_stream_locked() {\n            return Err(Exception::throw_type(\n                &ctx,\n                \"ReadableStream.prototype.pipeThrough cannot be used on a locked WritableStream\",\n            ));\n        }\n\n        // Let signal be options[\"signal\"] if it exists, or undefined otherwise.\n        let options = options.0.unwrap_or_default();\n\n        // Let promise be ! ReadableStreamPipeTo(this, transform[\"writable\"], options[\"preventClose\"], options[\"preventAbort\"], options[\"preventCancel\"], signal).\n        let promise = ReadableStream::readable_stream_pipe_to(\n            ctx.clone(),\n            stream.0,\n            writable,\n            options.prevent_close,\n            options.prevent_abort,\n            options.prevent_cancel,\n            options.signal,\n        )?;\n\n        // Set promise.[[PromiseIsHandled]] to true.\n        let () = promise\n            .catch()?\n            .call((This(promise.clone()), Function::new(ctx, || {})))?;\n\n        // Return transform[\"readable\"].\n        Ok(readable_class)\n    }\n\n    // Promise<undefined> pipeTo(WritableStream destination, optional StreamPipeOptions options = {});\n    fn pipe_to(\n        ctx: Ctx<'js>,\n        stream: This<Value<'js>>,\n        destination: Value<'js>,\n        options: NullableOpt<Value<'js>>,\n    ) -> Result<Promise<'js>> {\n        with_promise_result(&ctx, || {\n            let stream =\n                ReadableStreamOwned::from_class(Class::from_value(&stream.0).or_throw_type(\n                    &ctx,\n                    \"'pipeTo' called on an object that is not a valid instance of ReadableStream.\",\n                )?);\n\n            let options = match options.0 {\n                Some(options) => Some(StreamPipeOptions::from_js(&ctx, options)?),\n                None => None,\n            };\n\n            // If ! IsReadableStreamLocked(this) is true, return a promise rejected with a TypeError exception.\n            if stream.is_readable_stream_locked() {\n                return promise_rejected_with_constructor(\n                    &stream.constructor_type_error,\n                    &stream.promise_primordials,\n                    \"ReadableStream.prototype.pipeTo cannot be used on a locked ReadableStream\",\n                );\n            }\n\n            let destination = WritableStreamOwned::from_class(\n                Class::from_value(&destination).or_throw_type(&ctx,\"'pipeTo' instructed to pipe to an object that is not a valid instance of WritableStream.\")?,\n            );\n\n            // If ! IsWritableStreamLocked(destination) is true, return a promise rejected with a TypeError exception.\n            if destination.is_writable_stream_locked() {\n                return promise_rejected_with_constructor(\n                    &stream.constructor_type_error,\n                    &stream.promise_primordials,\n                    \"ReadableStream.prototype.pipeTo cannot be used on a locked WritableStream\",\n                );\n            }\n\n            // Let signal be options[\"signal\"] if it exists, or undefined otherwise.\n            let options = options.unwrap_or_default();\n\n            // Return ! ReadableStreamPipeTo(this, destination, options[\"preventClose\"], options[\"preventAbort\"], options[\"preventCancel\"], signal).\n            Self::readable_stream_pipe_to(\n                ctx.clone(),\n                stream,\n                destination,\n                options.prevent_close,\n                options.prevent_abort,\n                options.prevent_cancel,\n                options.signal,\n            )\n        })\n    }\n\n    // sequence<ReadableStream> tee();\n    fn tee(\n        ctx: Ctx<'js>,\n        stream: This<OwnedBorrowMut<'js, Self>>,\n    ) -> Result<List<(Class<'js, Self>, Class<'js, Self>)>> {\n        // Return ? ReadableStreamTee(this, false).\n        Ok(List(Self::readable_stream_tee(\n            ctx,\n            ReadableStreamObjects::from_stream(stream.0),\n            false,\n        )?))\n    }\n\n    #[qjs(rename = PredefinedAtom::SymbolAsyncIterator)]\n    fn async_iterate(\n        ctx: Ctx<'js>,\n        stream: This<OwnedBorrowMut<'js, Self>>,\n    ) -> Result<Class<'js, ReadableStreamAsyncIterator<'js>>> {\n        Self::values(ctx, stream, Opt(None))\n    }\n\n    fn values(\n        ctx: Ctx<'js>,\n        stream: This<OwnedBorrowMut<'js, Self>>,\n        arg: Opt<Object<'js>>,\n    ) -> Result<Class<'js, ReadableStreamAsyncIterator<'js>>> {\n        // Let reader be ? AcquireReadableStreamDefaultReader(stream).\n        let (stream, reader) = ReadableStreamReaderClass::acquire_readable_stream_default_reader(\n            ctx.clone(),\n            stream.0,\n        )?;\n\n        // Let preventCancel be args[0][\"preventCancel\"].\n        let prevent_cancel = match arg.0 {\n            None => false,\n            Some(arg) => matches!(arg.get_value_or_undefined(\"preventCancel\")?, Some(true)),\n        };\n\n        let promise_primordials = stream.promise_primordials.clone();\n        let controller = stream.controller.clone();\n\n        ReadableStreamAsyncIterator::new(\n            ctx,\n            ReadableStreamClassObjects {\n                stream: stream.into_inner(),\n                controller,\n                reader,\n            },\n            promise_primordials,\n            prevent_cancel,\n        )\n    }\n}\n\nimpl<'js> ReadableStream<'js> {\n    pub(super) fn readable_stream_error<\n        C: ReadableStreamController<'js>,\n        R: ReadableStreamReader<'js>,\n    >(\n        // Let reader be stream.[[reader]].\n        mut objects: ReadableStreamObjects<'js, C, R>,\n        e: Value<'js>,\n    ) -> Result<ReadableStreamObjects<'js, C, R>> {\n        // Set stream.[[state]] to \"errored\".\n        // Set stream.[[storedError]] to e.\n        objects.stream.state = ReadableStreamState::Errored(e.clone());\n\n        objects = objects.with_reader(\n            // If reader implements ReadableStreamDefaultReader,\n            |mut objects| {\n                // Reject reader.[[closedPromise]] with e.\n                objects.reader\n                    .generic\n                    .closed_promise\n                    .reject(e.clone())?;\n\n                // Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.\n                objects.reader.generic.closed_promise.set_is_handled()?;\n\n                // Perform ! ReadableStreamDefaultReaderErrorReadRequests(reader, e).\n                objects = ReadableStreamDefaultReader::readable_stream_default_reader_error_read_requests(\n                        objects, e.clone(),\n                )?;\n                Ok(objects)\n        },\n            // Otherwise,\n            |mut objects| {\n                // Reject reader.[[closedPromise]] with e.\n                objects.reader\n                    .generic\n                    .closed_promise\n                    .reject(e.clone())?;\n\n                // Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.\n                objects.reader.generic.closed_promise.set_is_handled()?;\n\n                // Perform ! ReadableStreamBYOBReaderErrorReadIntoRequests(reader, e).\n                objects = ReadableStreamBYOBReader::readable_stream_byob_reader_error_read_into_requests(\n                    objects, e.clone(),\n                )?;\n\n                Ok(objects)\n            },\n        // If reader is undefined, return.\n        Ok)?;\n\n        Ok(objects)\n    }\n\n    pub(super) fn readable_stream_get_num_read_requests(\n        reader: &ReadableStreamDefaultReader,\n    ) -> usize {\n        reader.read_requests.len()\n    }\n\n    pub(super) fn readable_stream_get_num_read_into_requests(\n        reader: &ReadableStreamBYOBReader,\n    ) -> usize {\n        reader.read_into_requests.len()\n    }\n\n    pub(super) fn readable_stream_fulfill_read_request<C: ReadableStreamController<'js>>(\n        ctx: &Ctx<'js>,\n        // Let reader be stream.[[reader]].\n        mut objects: ReadableStreamDefaultReaderObjects<'js, C>,\n        chunk: Value<'js>,\n        done: bool,\n    ) -> Result<ReadableStreamDefaultReaderObjects<'js, C>> {\n        // Let readRequest be reader.[[readRequests]][0].\n        // Remove readRequest from reader.[[readRequests]].\n        let read_request = objects\n            .reader\n            .read_requests\n            .pop_front()\n            .expect(\"ReadableStreamFulfillReadRequest called with empty readRequests\");\n\n        if done {\n            // If done is true, perform readRequest’s close steps.\n            read_request.close_steps_typed(ctx, objects)\n        } else {\n            // Otherwise, perform readRequest’s chunk steps, given chunk.\n            read_request.chunk_steps_typed(objects, chunk)\n        }\n    }\n\n    pub(super) fn readable_stream_fulfill_read_into_request(\n        ctx: &Ctx<'js>,\n        mut objects: ReadableStreamBYOBObjects<'js>,\n        chunk: ViewBytes<'js>,\n        done: bool,\n    ) -> Result<ReadableStreamBYOBObjects<'js>> {\n        // Let readIntoRequest be reader.[[readIntoRequests]][0].\n        // Remove readIntoRequest from reader.[[readIntoRequests]].\n        let read_into_request = objects\n            .reader\n            .read_into_requests\n            .pop_front()\n            .expect(\"ReadableStreamFulfillReadIntoRequest called with empty readIntoRequests\");\n\n        if done {\n            // If done is true, perform readIntoRequest’s close steps, given chunk.\n            read_into_request.close_steps(objects, chunk.into_js(ctx)?)\n        } else {\n            // Otherwise, perform readIntoRequest’s chunk steps, given chunk.\n            read_into_request.chunk_steps(objects, chunk.into_js(ctx)?)\n        }\n    }\n\n    pub(super) fn readable_stream_close<\n        C: ReadableStreamController<'js>,\n        R: ReadableStreamReader<'js>,\n    >(\n        ctx: Ctx<'js>,\n        // Let reader be stream.[[reader]].\n        mut objects: ReadableStreamObjects<'js, C, R>,\n    ) -> Result<ReadableStreamObjects<'js, C, R>> {\n        // Set stream.[[state]] to \"closed\".\n        objects.stream.state = ReadableStreamState::Closed;\n\n        objects.with_reader(\n            |mut objects| {\n                // Resolve reader.[[closedPromise]] with undefined.\n                objects.reader.generic.closed_promise.resolve_undefined()?;\n\n                // If reader implements ReadableStreamDefaultReader,\n                // Let readRequests be reader.[[readRequests]].\n                // Set reader.[[readRequests]] to an empty list.\n                let read_requests = objects.reader.read_requests.split_off(0);\n\n                // For each readRequest of readRequests,\n                for read_request in read_requests {\n                    // Perform readRequest’s close steps.\n                    objects = read_request.close_steps_typed(&ctx, objects)?;\n                }\n\n                Ok(objects)\n            },\n            |objects| {\n                objects.reader.generic.closed_promise.resolve_undefined()?;\n\n                Ok(objects)\n            },\n            // If reader is undefined, return.\n            Ok,\n        )\n    }\n\n    pub(super) fn is_readable_stream_locked(&self) -> bool {\n        // If stream.[[reader]] is undefined, return false.\n        if self.reader.is_none() {\n            return false;\n        }\n        // Return true.\n        true\n    }\n\n    pub(super) fn readable_stream_add_read_request(\n        &mut self,\n        reader: &mut ReadableStreamDefaultReader<'js>,\n        read_request: impl ReadableStreamReadRequest<'js> + 'js,\n    ) {\n        reader.read_requests.push_back(Box::new(read_request));\n    }\n\n    pub(super) fn readable_stream_cancel<\n        C: ReadableStreamController<'js>,\n        R: ReadableStreamReader<'js>,\n    >(\n        ctx: Ctx<'js>,\n        mut objects: ReadableStreamObjects<'js, C, R>,\n        reason: Value<'js>,\n    ) -> Result<(Promise<'js>, ReadableStreamObjects<'js, C, R>)> {\n        // Set stream.[[disturbed]] to true.\n        objects.stream.disturbed = true;\n\n        match objects.stream.state {\n            // If stream.[[state]] is \"closed\", return a promise resolved with undefined.\n            ReadableStreamState::Closed => Ok((\n                // wpt tests expect that this is a new promise every time so we can't duplicate the primordial promise_resolved_with_undefined\n                promise_resolved_with(\n                    &ctx,\n                    &objects.stream.promise_primordials,\n                    Ok(Value::new_undefined(ctx.clone())),\n                )?,\n                objects,\n            )),\n            // If stream.[[state]] is \"errored\", return a promise rejected with stream.[[storedError]].\n            ReadableStreamState::Errored(ref stored_error) => Ok((\n                promise_rejected_with(&objects.stream.promise_primordials, stored_error.clone())?,\n                objects,\n            )),\n            ReadableStreamState::Readable => {\n                // Perform ! ReadableStreamClose(stream).\n                objects = ReadableStream::readable_stream_close(ctx.clone(), objects)?;\n                // Let reader be stream.[[reader]].\n                // If reader is not undefined and reader implements ReadableStreamBYOBReader,\n\n                objects = objects.with_reader(\n                    Ok,\n                    |mut objects| {\n                        // Let readIntoRequests be reader.[[readIntoRequests]].\n                        // Set reader.[[readIntoRequests]] to an empty list.\n                        let read_into_requests = objects.reader.read_into_requests.split_off(0);\n                        // For each readIntoRequest of readIntoRequests,\n                        for read_into_request in read_into_requests {\n                            // Perform readIntoRequest’s close steps, given undefined.\n                            objects = read_into_request\n                                .close_steps(objects, Value::new_undefined(ctx.clone()))?;\n                        }\n\n                        Ok(objects)\n                    },\n                    Ok,\n                )?;\n\n                // Let sourceCancelPromise be ! stream.[[controller]].[[CancelSteps]](reason).\n                let (source_cancel_promise, objects) = C::cancel_steps(&ctx, objects, reason)?;\n\n                // Return the result of reacting to sourceCancelPromise with a fulfillment step that returns undefined.\n                let promise = upon_promise_fulfilment(ctx, source_cancel_promise, |_, ()| {\n                    Ok(rquickjs::Undefined)\n                })?;\n\n                Ok((promise, objects))\n            },\n        }\n    }\n\n    pub(super) fn readable_stream_add_read_into_request(\n        reader: &mut ReadableStreamBYOBReader<'js>,\n        read_request: impl ReadableStreamReadIntoRequest<'js> + 'js,\n    ) {\n        // Append readRequest to stream.[[reader]].[[readIntoRequests]].\n        reader.read_into_requests.push_back(Box::new(read_request))\n    }\n\n    // CreateReadableStream(startAlgorithm, pullAlgorithm, cancelAlgorithm[, highWaterMark, [, sizeAlgorithm]]) performs the following steps:\n    fn create_readable_stream(\n        ctx: Ctx<'js>,\n        start_algorithm: StartAlgorithm<'js>,\n        pull_algorithm: PullAlgorithm<'js>,\n        cancel_algorithm: CancelAlgorithm<'js>,\n        high_water_mark: Option<f64>,\n        size_algorithm: Option<SizeAlgorithm<'js>>,\n    ) -> Result<\n        ReadableStreamClassObjects<'js, ReadableStreamDefaultControllerOwned<'js>, UndefinedReader>,\n    > {\n        // If highWaterMark was not passed, set it to 1.\n        let high_water_mark = high_water_mark.unwrap_or(1.0);\n\n        // If sizeAlgorithm was not passed, set it to an algorithm that returns 1.\n        let size_algorithm = size_algorithm.unwrap_or(SizeAlgorithm::AlwaysOne);\n\n        let base_primordials = BasePrimordials::get(&ctx)?;\n\n        // Let stream be a new ReadableStream.\n        let stream_class = Class::instance(\n            ctx.clone(),\n            Self {\n                // Set stream.[[state]] to \"readable\".\n                state: ReadableStreamState::Readable,\n                // Set stream.[[reader]] and stream.[[storedError]] to undefined.\n                reader: None,\n                // Set stream.[[disturbed]] to false.\n                disturbed: false,\n                controller: ReadableStreamControllerClass::Uninitialised,\n                promise_primordials: PromisePrimordials::get(&ctx)?.clone(),\n                constructor_range_error: base_primordials.constructor_range_error.clone(),\n                constructor_type_error: base_primordials.constructor_type_error.clone(),\n                function_array_buffer_is_view: base_primordials\n                    .function_array_buffer_is_view\n                    .clone(),\n            },\n        )?;\n        drop(base_primordials);\n\n        // Perform ? SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm).\n        let controller_class =\n            ReadableStreamDefaultController::set_up_readable_stream_default_controller(\n                ctx,\n                OwnedBorrowMut::from_class(stream_class.clone()),\n                start_algorithm,\n                pull_algorithm,\n                cancel_algorithm,\n                high_water_mark,\n                size_algorithm,\n            )?;\n\n        // Return stream.\n        Ok(ReadableStreamClassObjects {\n            stream: stream_class,\n            controller: controller_class,\n            reader: UndefinedReader,\n        })\n    }\n\n    // CreateReadableByteStream(startAlgorithm, pullAlgorithm, cancelAlgorithm) performs the following steps:\n    fn create_readable_byte_stream(\n        ctx: Ctx<'js>,\n        start_algorithm: StartAlgorithm<'js>,\n        pull_algorithm: PullAlgorithm<'js>,\n        cancel_algorithm: CancelAlgorithm<'js>,\n    ) -> Result<(Class<'js, Self>, ReadableByteStreamControllerClass<'js>)> {\n        let base_primordials = BasePrimordials::get(&ctx)?;\n\n        // Let stream be a new ReadableStream.\n        let stream_class = Class::instance(\n            ctx.clone(),\n            Self {\n                // Set stream.[[state]] to \"readable\".\n                state: ReadableStreamState::Readable,\n                // Set stream.[[reader]] and stream.[[storedError]] to undefined.\n                reader: None,\n                // Set stream.[[disturbed]] to false.\n                disturbed: false,\n                controller: ReadableStreamControllerClass::Uninitialised,\n                promise_primordials: PromisePrimordials::get(&ctx)?.clone(),\n                constructor_type_error: base_primordials.constructor_type_error.clone(),\n                constructor_range_error: base_primordials.constructor_range_error.clone(),\n                function_array_buffer_is_view: base_primordials\n                    .function_array_buffer_is_view\n                    .clone(),\n            },\n        )?;\n        drop(base_primordials);\n\n        // Perform ? SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm).\n        let controller_class =\n            ReadableByteStreamController::set_up_readable_byte_stream_controller(\n                ctx,\n                OwnedBorrowMut::from_class(stream_class.clone()),\n                start_algorithm,\n                pull_algorithm,\n                cancel_algorithm,\n                0.0,\n                None,\n            )?;\n\n        // Return stream.\n        Ok((stream_class, controller_class))\n    }\n\n    fn readable_stream_from_iterable(\n        ctx: &Ctx<'js>,\n        async_iterable: Value<'js>,\n    ) -> Result<Class<'js, Self>> {\n        let stream: Rc<OnceCell<Class<'js, Self>>> = Rc::new(OnceCell::new());\n\n        // Let iteratorRecord be ? GetIterator(asyncIterable, async).\n        let iterator_record =\n            IteratorRecord::get_iterator(ctx, async_iterable, IteratorKind::Async)?;\n        let iterator = iterator_record.iterator.clone();\n\n        // Let startAlgorithm be an algorithm that returns undefined.\n        let start_algorithm = StartAlgorithm::ReturnUndefined;\n\n        let promise_primordials = PromisePrimordials::get(ctx)?.clone();\n\n        // Let pullAlgorithm be the following steps:\n        let pull_algorithm = {\n            let stream = stream.clone();\n            let promise_primordials = promise_primordials.clone();\n            move |ctx: Ctx<'js>, controller: ReadableStreamControllerClass<'js>| {\n                // Let nextResult be IteratorNext(iteratorRecord).\n                let next_result: Result<Object<'js>> = iterator_record.iterator_next(&ctx, None);\n                let next_promise = match next_result {\n                    // If nextResult is an abrupt completion, return a promise rejected with nextResult.[[Value]].\n                    Err(Error::Exception) => {\n                        return promise_rejected_catch(&ctx, &promise_primordials);\n                    },\n                    Err(err) => return Err(err),\n                    // Let nextPromise be a promise resolved with nextResult.[[Value]].\n                    Ok(next_result) => promise_resolved_with(\n                        &ctx,\n                        &promise_primordials,\n                        Ok(next_result.into_inner()),\n                    )?,\n                };\n\n                // Return the result of reacting to nextPromise with the following fulfillment steps, given iterResult:\n                upon_promise_fulfilment(ctx, next_promise, {\n                    let stream = stream.clone();\n                    move |ctx, iter_result: Value<'js>| {\n                        let iter_result = match iter_result.into_object() {\n                            // If Type(iterResult) is not Object, throw a TypeError.\n                            None => {\n                                return Err(Exception::throw_type(&ctx, \"The promise returned by the iterator.next() method must fulfill with an object\"));\n                            },\n                            Some(iter_result) => iter_result,\n                        };\n\n                        // Let done be ? IteratorComplete(iterResult).\n                        let done = IteratorRecord::iterator_complete(&iter_result)?;\n\n                        let stream = OwnedBorrowMut::from_class(stream.get().cloned().expect(\"ReadableStreamFromIterable pull steps called with uninitialised stream\"));\n                        let controller = match controller {\n                        ReadableStreamControllerClass::ReadableStreamDefaultController(c) => OwnedBorrowMut::from_class(c),\n                        _ => panic!(\"ReadableStreamFromIterable pull steps called without default controller\")\n                    };\n\n                        let objects = ReadableStreamObjects::new_default(stream, controller);\n\n                        // If done is true:\n                        if done {\n                            // Perform ! ReadableStreamDefaultControllerClose(stream.[[controller]]).\n                            ReadableStreamDefaultController::readable_stream_default_controller_close(ctx.clone(), objects)?;\n                        } else {\n                            // Let value be ? IteratorValue(iterResult).\n                            let value = IteratorRecord::iterator_value(&iter_result)?;\n\n                            // Perform ! ReadableStreamDefaultControllerEnqueue(stream.[[controller]], value).\n                            ReadableStreamDefaultController::readable_stream_default_controller_enqueue(ctx.clone(), objects, value)?;\n                        }\n\n                        Ok(())\n                    }\n                })\n            }\n        };\n\n        // Let cancelAlgorithm be the following steps, given reason:\n        let cancel_algorithm = {\n            let ctx = ctx.clone();\n            let promise_primordials = promise_primordials.clone();\n            move |reason: Value<'js>| {\n                // Let iterator be iteratorRecord.[[Iterator]].\n\n                // Let returnMethod be GetMethod(iterator, \"return\").\n                let return_method: Function<'js> = match iterator.get(PredefinedAtom::Return) {\n                    // If returnMethod is an abrupt completion, return a promise rejected with returnMethod.[[Value]].\n                    Err(Error::Exception) => {\n                        return promise_rejected_catch(&ctx, &promise_primordials);\n                    },\n                    Err(err) => return Err(err),\n                    Ok(None) => {\n                        // If returnMethod.[[Value]] is undefined, return a promise resolved with undefined.\n                        return Ok(promise_primordials.promise_resolved_with_undefined.clone());\n                    },\n                    Ok(Some(return_method)) => return_method,\n                };\n\n                // Let returnResult be Call(returnMethod.[[Value]], iterator, « reason »).\n                let return_result: Result<Value<'js>> =\n                    return_method.call((This(iterator), reason));\n\n                let return_result = match return_result {\n                    // If returnResult is an abrupt completion, return a promise rejected with returnResult.[[Value]].\n                    Err(Error::Exception) => {\n                        return promise_rejected_catch(&ctx, &promise_primordials);\n                    },\n                    Err(err) => return Err(err),\n                    Ok(return_result) => return_result,\n                };\n\n                // Let returnPromise be a promise resolved with returnResult.[[Value]].\n                let return_promise =\n                    promise_resolved_with(&ctx, &promise_primordials, Ok(return_result))?;\n\n                // Return the result of reacting to returnPromise with the following fulfillment steps, given iterResult:\n                upon_promise_fulfilment(\n                    ctx,\n                    return_promise,\n                    move |ctx: Ctx<'js>, iter_result: Value<'js>| {\n                        // If Type(iterResult) is not Object, throw a TypeError.\n                        if !iter_result.is_object() {\n                            return Err(Exception::throw_type(&ctx, \"The promise returned by the iterator.next() method must fulfill with an object\"));\n                        }\n                        // Return undefined.\n                        Ok(rquickjs::Undefined)\n                    },\n                )\n            }\n        };\n\n        let objects_class = ReadableStream::create_readable_stream(\n            ctx.clone(),\n            start_algorithm,\n            PullAlgorithm::from_fn(pull_algorithm),\n            CancelAlgorithm::from_fn(cancel_algorithm),\n            Some(0.0),\n            None,\n        )?;\n        _ = stream.set(objects_class.stream.clone());\n        Ok(objects_class.stream)\n    }\n\n    pub(super) fn reader_mut(&mut self) -> Option<ReadableStreamReaderOwned<'js>> {\n        self.reader\n            .clone()\n            .map(ReadableStreamReaderOwned::from_class)\n    }\n}\n\n// enum ReadableStreamType { \"bytes\" };\nenum ReadableStreamType {\n    Bytes,\n}\n\nimpl<'js> FromJs<'js> for ReadableStreamType {\n    fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        let typ = value.type_of();\n\n        match Coerced::<String>::from_js(ctx, value)?.as_str() {\n            \"bytes\" => Ok(Self::Bytes),\n            _ => Err(Error::new_from_js(typ.as_str(), \"ReadableStreamType\")),\n        }\n    }\n}\n\nstruct ReadableStreamGetReaderOptions {\n    mode: Option<ReadableStreamReaderMode>,\n}\n\nimpl<'js> FromJs<'js> for ReadableStreamGetReaderOptions {\n    fn from_js(_ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        let ty_name = value.type_name();\n        let obj = value\n            .as_object()\n            .ok_or(Error::new_from_js(ty_name, \"Object\"))?;\n\n        let mode = obj.get_value_or_undefined::<_, ReadableStreamReaderMode>(\"mode\")?;\n\n        Ok(Self { mode })\n    }\n}\n\n// enum ReadableStreamReaderMode { \"byob\" };\nenum ReadableStreamReaderMode {\n    Byob,\n}\n\nimpl<'js> FromJs<'js> for ReadableStreamReaderMode {\n    fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        let typ = value.type_of();\n\n        match Coerced::<String>::from_js(ctx, value)?.as_str() {\n            \"byob\" => Ok(Self::Byob),\n            _ => Err(Error::new_from_js(typ.as_str(), \"ReadableStreamReaderMode\")),\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/readable/stream/pipe.rs",
    "content": "use std::{\n    cell::RefCell,\n    rc::Rc,\n    sync::atomic::{AtomicBool, Ordering},\n};\n\nuse llrt_abort::AbortSignal;\nuse llrt_utils::{option::Undefined, result::ResultExt};\nuse rquickjs::{\n    class::{OwnedBorrow, Trace},\n    prelude::{OnceFn, This},\n    Class, Coerced, Ctx, Error, FromJs, Function, Promise, Result, Value,\n};\n\nuse crate::{\n    readable::{\n        controller::ReadableStreamControllerOwned,\n        default_reader::{\n            ReadableStreamDefaultReader, ReadableStreamDefaultReaderOwned,\n            ReadableStreamReadRequest,\n        },\n        objects::{\n            ReadableStreamClassObjects, ReadableStreamDefaultReaderObjects, ReadableStreamObjects,\n        },\n        reader::ReadableStreamReaderClass,\n        stream::{ReadableStream, ReadableStreamOwned, ReadableStreamState},\n    },\n    utils::{\n        promise::{\n            promise_resolved_with, upon_promise, upon_promise_fulfilment, PromisePrimordials,\n            ResolveablePromise,\n        },\n        UnwrapOrUndefined, ValueOrUndefined,\n    },\n    writable::{\n        WritableStream, WritableStreamClassObjects, WritableStreamDefaultWriter,\n        WritableStreamDefaultWriterOwned, WritableStreamObjects, WritableStreamOwned,\n        WritableStreamState,\n    },\n};\n\nimpl<'js> ReadableStream<'js> {\n    pub(super) fn readable_stream_pipe_to(\n        ctx: Ctx<'js>,\n        source: ReadableStreamOwned<'js>,\n        dest: WritableStreamOwned<'js>,\n        prevent_close: bool,\n        prevent_abort: bool,\n        prevent_cancel: bool,\n        signal: Option<Class<'js, AbortSignal<'js>>>,\n    ) -> Result<Promise<'js>> {\n        let (source_stored_error, source_closed) = match source.state {\n            ReadableStreamState::Errored(ref stored_error) => (Some(stored_error.clone()), false),\n            ReadableStreamState::Closed => (None, true),\n            _ => (None, false),\n        };\n        let dest_stored_error = dest.stored_error();\n        let dest_closing = dest.writable_stream_close_queued_or_in_flight()\n            || matches!(dest.state, WritableStreamState::Closed);\n\n        let source_controller = source.controller.clone();\n\n        let dest_controller = dest\n            .controller\n            .clone()\n            .expect(\"pipeTo called on writable stream without controller\");\n\n        // If source.[[controller]] implements ReadableByteStreamController, let reader be either ! AcquireReadableStreamBYOBReader(source) or ! AcquireReadableStreamDefaultReader(source), at the user agent’s discretion.\n        // Otherwise, let reader be ! AcquireReadableStreamDefaultReader(source).\n        let (mut source, reader) =\n            ReadableStreamReaderClass::acquire_readable_stream_default_reader(ctx.clone(), source)?;\n\n        let source_closed_promise = reader.borrow().generic.closed_promise.promise.clone();\n\n        // Let writer be ! AcquireWritableStreamDefaultWriter(dest).\n        let (dest, writer) =\n            WritableStreamDefaultWriter::acquire_writable_stream_default_writer(&ctx, dest)?;\n\n        let dest_closed_promise = writer.borrow().closed_promise.promise.clone();\n\n        // Set source.[[disturbed]] to true.\n        source.disturbed = true;\n\n        let current_write = Rc::new(RefCell::new(\n            source\n                .promise_primordials\n                .promise_resolved_with_undefined\n                .clone(),\n        ));\n\n        let promise_primordials = source.promise_primordials.clone();\n        let constructor_type_error = source.constructor_type_error.clone();\n\n        let mut pipe_to = PipeTo {\n            source_objects: ReadableStreamClassObjects {\n                stream: source.into_inner(),\n                controller: source_controller,\n                reader,\n            },\n            dest_objects: WritableStreamClassObjects {\n                stream: dest.into_inner(),\n                controller: dest_controller,\n                writer,\n            },\n            current_write,\n            // Let shuttingDown be false.\n            shutting_down: Rc::new(AtomicBool::new(false)),\n            signal,\n            abort_callback: None,\n            // Let promise be a new promise.\n            promise: ResolveablePromise::new(&ctx)?,\n            promise_primordials: promise_primordials.clone(),\n        };\n\n        // If signal is not undefined,\n        if let Some(signal) = &pipe_to.signal {\n            // Let abortAlgorithm be the following steps:\n            let abort_algorithm = {\n                let signal = signal.clone();\n                let pipe_to = pipe_to.clone();\n                move |ctx: Ctx<'js>| -> Result<()> {\n                    // Let error be signal’s abort reason.\n                    let error = signal.borrow().reason().unwrap_or_undefined(&ctx);\n\n                    // Let actions be an empty ordered set.\n                    let mut actions =\n                        Vec::<Box<dyn FnOnce(Ctx<'js>) -> Result<Promise<'js>>>>::new();\n\n                    // If preventAbort is false, append the following action to actions:\n                    if !prevent_abort {\n                        let dest_objects = pipe_to.dest_objects.clone();\n                        let error = error.clone();\n                        actions.push(Box::new(move |ctx| {\n                            let dest_objects = WritableStreamObjects::from_class(dest_objects);\n\n                            if matches!(dest_objects.stream.state, WritableStreamState::Writable) {\n                                // If dest.[[state]] is \"writable\", return ! WritableStreamAbort(dest, error).\n                                let (promise, _) = WritableStream::writable_stream_abort(\n                                    ctx,\n                                    dest_objects,\n                                    Some(error.clone()),\n                                )?;\n                                Ok(promise)\n                            } else {\n                                // Otherwise, return a promise resolved with undefined.\n                                Ok(dest_objects\n                                    .stream\n                                    .promise_primordials\n                                    .promise_resolved_with_undefined\n                                    .clone())\n                            }\n                        }));\n                    }\n\n                    // If preventCancel is false, append the following action action to actions:\n                    if !prevent_cancel {\n                        let source_objects = pipe_to.source_objects.clone();\n                        let error = error.clone();\n                        actions.push(Box::new(move |ctx| {\n                            let source_objects = ReadableStreamObjects::from_class(source_objects);\n\n                            if let ReadableStreamState::Readable = source_objects.stream.state {\n                                // If source.[[state]] is \"readable\", return ! ReadableStreamCancel(source, error).\n                                let (promise, _) = ReadableStream::readable_stream_cancel(\n                                    ctx,\n                                    source_objects,\n                                    error.clone(),\n                                )?;\n\n                                Ok(promise)\n                            } else {\n                                // Otherwise, return a promise resolved with undefined.\n                                Ok(source_objects\n                                    .stream\n                                    .promise_primordials\n                                    .promise_resolved_with_undefined\n                                    .clone())\n                            }\n                        }));\n                    }\n\n                    // Shutdown with an action consisting of getting a promise to wait for all of the actions in actions, and with error.\n                    pipe_to.shutdown_with_action(\n                        ctx,\n                        move |ctx| {\n                            let promises: Vec<Promise<'js>> = actions\n                                .into_iter()\n                                .map(|action| action(ctx.clone()))\n                                .collect::<Result<Vec<_>>>()?;\n\n                            let all_promises: Promise<'js> =\n                                promise_primordials.promise_all.call((\n                                    This(promise_primordials.promise_constructor.clone()),\n                                    promises,\n                                ))?;\n\n                            Ok(all_promises)\n                        },\n                        Some(error),\n                    )\n                }\n            };\n\n            // If signal is aborted, perform abortAlgorithm and return promise.\n            {\n                let signal = signal.borrow();\n\n                if signal.aborted {\n                    abort_algorithm(ctx.clone())?;\n\n                    return Ok(pipe_to.promise.promise);\n                }\n            }\n\n            let abort_callback = pipe_to\n                .abort_callback\n                .insert(Function::new(ctx.clone(), OnceFn::new(abort_algorithm))?);\n\n            // Add abortAlgorithm to signal.\n            AbortSignal::set_on_abort(This(signal.clone()), ctx.clone(), abort_callback.clone())?;\n        }\n\n        // In parallel but not really; see #905, using reader and writer, read all chunks from source and write them to dest.\n        // Due to the locking provided by the reader and writer, the exact manner in which this happens is not observable to author code, and so there is flexibility in how this is done.\n        // The following constraints apply regardless of the exact algorithm used:\n\n        // Errors must be propagated forward\n        PipeTo::is_or_becomes_errored(\n            ctx.clone(),\n            source_stored_error,\n            source_closed_promise.clone(),\n            {\n                let pipe_to = pipe_to.clone();\n                move |ctx, stored_error| {\n                    if !prevent_abort {\n                        pipe_to.shutdown_with_action(\n                            ctx,\n                            {\n                                let pipe_to = pipe_to.clone();\n                                let stored_error = stored_error.clone();\n                                move |ctx| {\n                                    let dest_objects = WritableStreamObjects::from_class(\n                                        pipe_to.dest_objects.clone(),\n                                    );\n\n                                    let (promise, _) = WritableStream::writable_stream_abort(\n                                        ctx,\n                                        dest_objects,\n                                        Some(stored_error),\n                                    )?;\n\n                                    Ok(promise)\n                                }\n                            },\n                            Some(stored_error),\n                        )\n                    } else {\n                        pipe_to.shutdown(ctx, Some(stored_error))\n                    }\n                }\n            },\n        )?;\n\n        // Errors must be propagated backward\n        PipeTo::is_or_becomes_errored(ctx.clone(), dest_stored_error, dest_closed_promise, {\n            let pipe_to = pipe_to.clone();\n            move |ctx, stored_error| {\n                if !prevent_cancel {\n                    pipe_to.shutdown_with_action(\n                        ctx,\n                        {\n                            let pipe_to = pipe_to.clone();\n                            let stored_error = stored_error.clone();\n                            move |ctx| {\n                                let source_objects = ReadableStreamObjects::from_class(\n                                    pipe_to.source_objects.clone(),\n                                );\n\n                                let (promise, _) = ReadableStream::readable_stream_cancel(\n                                    ctx,\n                                    source_objects,\n                                    stored_error,\n                                )?;\n\n                                Ok(promise)\n                            }\n                        },\n                        Some(stored_error),\n                    )\n                } else {\n                    pipe_to.shutdown(ctx, Some(stored_error))\n                }\n            }\n        })?;\n\n        // Closing must be propagated forward\n        PipeTo::is_or_becomes_closed(ctx.clone(), source_closed, source_closed_promise, {\n            let pipe_to = pipe_to.clone();\n            move |ctx| {\n                if !prevent_close {\n                    pipe_to.shutdown_with_action(\n                        ctx,\n                        {\n                            let pipe_to = pipe_to.clone();\n                            move |ctx| {\n                                let dest_objects = WritableStreamObjects::from_class(pipe_to.dest_objects);\n\n                                WritableStreamDefaultWriter::writable_stream_default_writer_close_with_error_propagation(ctx, dest_objects)\n                            }\n                        },\n                        None,\n                    )\n                } else {\n                    pipe_to.shutdown(ctx, None)\n                }\n            }\n        })?;\n\n        // Closing must be propagated backward\n        if dest_closing {\n            let dest_closed: Value<'js> = constructor_type_error.call((\n                \"the destination writable stream closed before all data could be piped to it\",\n            ))?;\n\n            if !prevent_cancel {\n                pipe_to.shutdown_with_action(\n                    ctx.clone(),\n                    {\n                        let pipe_to = pipe_to.clone();\n                        let dest_closed = dest_closed.clone();\n                        move |ctx| {\n                            let source_objects =\n                                ReadableStreamObjects::from_class(pipe_to.source_objects.clone());\n\n                            let (promise, _) = ReadableStream::readable_stream_cancel(\n                                ctx,\n                                source_objects,\n                                dest_closed,\n                            )?;\n\n                            Ok(promise)\n                        }\n                    },\n                    Some(dest_closed),\n                )?;\n            } else {\n                pipe_to.shutdown(ctx.clone(), Some(dest_closed))?;\n            }\n        }\n\n        let result_promise = pipe_to.promise.promise.clone();\n        let pipe_loop_promise = pipe_to.pipe_loop(ctx)?;\n        pipe_loop_promise.set_is_handled()?;\n\n        Ok(result_promise)\n    }\n}\n\n#[derive(Clone)]\nstruct PipeTo<'js> {\n    source_objects: ReadableStreamClassObjects<\n        'js,\n        ReadableStreamControllerOwned<'js>,\n        ReadableStreamDefaultReaderOwned<'js>,\n    >,\n    dest_objects: WritableStreamClassObjects<'js, WritableStreamDefaultWriterOwned<'js>>,\n    current_write: Rc<RefCell<Promise<'js>>>,\n    shutting_down: Rc<AtomicBool>,\n    signal: Option<Class<'js, AbortSignal<'js>>>,\n    abort_callback: Option<Function<'js>>,\n    promise: ResolveablePromise<'js>,\n\n    promise_primordials: PromisePrimordials<'js>,\n}\n\nimpl<'js> PipeTo<'js> {\n    // Using reader and writer, read all chunks from this and write them to dest\n    // - Backpressure must be enforced\n    // - Shutdown must stop all activity\n    fn pipe_loop(self, ctx: Ctx<'js>) -> Result<ResolveablePromise<'js>> {\n        let loop_promise = ResolveablePromise::new(&ctx)?;\n\n        self.next(ctx, false, loop_promise.clone())?;\n\n        Ok(loop_promise)\n    }\n\n    fn next(&self, ctx: Ctx<'js>, done: bool, loop_promise: ResolveablePromise<'js>) -> Result<()> {\n        if done {\n            loop_promise.resolve_undefined()?\n        } else {\n            let pipe_step_promise = self.pipe_step(ctx.clone())?;\n            upon_promise(ctx, pipe_step_promise, {\n                {\n                    let pipe_to = self.clone();\n                    move |ctx, result| match result {\n                        Ok(done) => pipe_to.next(ctx, done, loop_promise),\n                        Err(err) => loop_promise.reject(err),\n                    }\n                }\n            })?;\n        }\n\n        Ok(())\n    }\n\n    fn pipe_step(&self, ctx: Ctx<'js>) -> Result<Promise<'js>> {\n        if self.shutting_down.load(Ordering::Acquire) {\n            return promise_resolved_with(\n                &ctx,\n                &self.promise_primordials,\n                Ok(Value::new_bool(ctx.clone(), true)),\n            );\n        }\n\n        let writer_ready = self\n            .dest_objects\n            .writer\n            .borrow()\n            .ready_promise\n            .promise\n            .clone();\n\n        upon_promise_fulfilment(ctx, writer_ready, {\n            let current_write = self.current_write.clone();\n            let source_objects = self.source_objects.clone();\n            let dest_objects = self.dest_objects.clone();\n            move |ctx: Ctx<'js>, ()| -> Result<Promise<'js>> {\n                let read_promise = ResolveablePromise::new(&ctx)?;\n\n                struct ReadRequest<'js> {\n                    dest_objects:\n                        WritableStreamClassObjects<'js, WritableStreamDefaultWriterOwned<'js>>,\n                    current_write: Rc<RefCell<Promise<'js>>>,\n                    read_promise: ResolveablePromise<'js>,\n                }\n\n                impl<'js> Trace<'js> for ReadRequest<'js> {\n                    fn trace<'a>(&self, tracer: rquickjs::class::Tracer<'a, 'js>) {\n                        self.current_write.as_ref().borrow().trace(tracer);\n                        self.read_promise.trace(tracer);\n                    }\n                }\n\n                impl<'js> ReadableStreamReadRequest<'js> for ReadRequest<'js> {\n                    fn chunk_steps(\n                        &self,\n                        objects: ReadableStreamDefaultReaderObjects<'js>,\n                        chunk: Value<'js>,\n                    ) -> Result<ReadableStreamDefaultReaderObjects<'js>> {\n                        let ctx = chunk.ctx().clone();\n\n                        // calling write can trigger user code; ensure we don't hold locks\n                        let objects = objects.into_inner();\n\n                        let dest_objects =\n                            WritableStreamObjects::from_class(self.dest_objects.clone());\n                        let write_promise =\n                            WritableStreamDefaultWriter::writable_stream_default_writer_write(\n                                ctx.clone(),\n                                dest_objects,\n                                chunk,\n                            )?;\n\n                        let write_promise: Promise<'js> = write_promise.catch()?.call((\n                            This(write_promise.clone()),\n                            Function::new(ctx.clone(), || {}),\n                        ))?;\n\n                        self.current_write.replace(write_promise);\n                        self.read_promise\n                            .resolve(Value::new_bool(ctx.clone(), false))?;\n\n                        Ok(ReadableStreamObjects::from_class(objects))\n                    }\n\n                    fn close_steps(\n                        &self,\n                        ctx: &Ctx<'js>,\n                        objects: ReadableStreamDefaultReaderObjects<'js>,\n                    ) -> Result<ReadableStreamDefaultReaderObjects<'js>> {\n                        self.read_promise\n                            .resolve(Value::new_bool(ctx.clone(), true))?;\n\n                        Ok(objects)\n                    }\n\n                    fn error_steps(\n                        &self,\n                        objects: ReadableStreamDefaultReaderObjects<'js>,\n                        reason: Value<'js>,\n                    ) -> Result<ReadableStreamDefaultReaderObjects<'js>> {\n                        self.read_promise.reject(reason)?;\n\n                        Ok(objects)\n                    }\n                }\n\n                let objects = ReadableStreamObjects::from_class(source_objects);\n\n                let promise = read_promise.promise.clone();\n\n                ReadableStreamDefaultReader::readable_stream_default_reader_read(\n                    &ctx,\n                    objects,\n                    ReadRequest {\n                        current_write,\n                        read_promise,\n                        dest_objects,\n                    },\n                )?;\n\n                Ok(promise)\n            }\n        })\n    }\n\n    fn is_or_becomes_errored(\n        ctx: Ctx<'js>,\n        stored_error: Option<Value<'js>>,\n        promise: Promise<'js>,\n        action: impl FnOnce(Ctx<'js>, Value<'js>) -> Result<()> + 'js,\n    ) -> Result<()> {\n        if let Some(stored_error) = stored_error {\n            action(ctx, stored_error)\n        } else {\n            promise.catch()?.call((\n                This(promise.clone()),\n                Function::new(ctx.clone(), OnceFn::new(action)),\n            ))\n        }\n    }\n\n    fn is_or_becomes_closed(\n        ctx: Ctx<'js>,\n        already_closed: bool,\n        promise: Promise<'js>,\n        action: impl FnOnce(Ctx<'js>) -> Result<()> + 'js,\n    ) -> Result<()> {\n        if already_closed {\n            action(ctx)?;\n        } else {\n            upon_promise_fulfilment(ctx, promise, |ctx, ()| action(ctx))?;\n        }\n        Ok(())\n    }\n\n    fn shutdown_with_action(\n        &self,\n        ctx: Ctx<'js>,\n        action: impl FnOnce(Ctx<'js>) -> Result<Promise<'js>> + 'js,\n        original_error: Option<Value<'js>>,\n    ) -> Result<()> {\n        if self.shutting_down.swap(true, Ordering::AcqRel) {\n            // already shutting down\n            return Ok(());\n        }\n\n        let do_the_rest = {\n            let pipe_to = self.clone();\n            move |ctx: Ctx<'js>| -> Result<()> {\n                let action_promise = action(ctx.clone())?;\n                upon_promise(ctx, action_promise, move |ctx, result| match result {\n                    Ok(()) => pipe_to.finalize(ctx, original_error),\n                    Err(new_error) => pipe_to.finalize(ctx, Some(new_error)),\n                })?;\n                Ok(())\n            }\n        };\n\n        let writable = {\n            let dest_stream = OwnedBorrow::from_class(self.dest_objects.stream.clone());\n            matches!(dest_stream.state, WritableStreamState::Writable)\n                && !dest_stream.writable_stream_close_queued_or_in_flight()\n        };\n\n        if writable {\n            let wait_promise =\n                Self::wait_for_writes_to_finish(ctx.clone(), self.current_write.clone())?;\n            upon_promise_fulfilment(ctx, wait_promise, |ctx: Ctx<'js>, ()| do_the_rest(ctx))?;\n        } else {\n            do_the_rest(ctx)?\n        }\n        Ok(())\n    }\n\n    fn shutdown(&self, ctx: Ctx<'js>, error: Option<Value<'js>>) -> Result<()> {\n        if self.shutting_down.swap(true, Ordering::AcqRel) {\n            // already shutting down\n            return Ok(());\n        }\n\n        let writable = {\n            let dest_stream = OwnedBorrow::from_class(self.dest_objects.stream.clone());\n            matches!(dest_stream.state, WritableStreamState::Writable)\n                && !dest_stream.writable_stream_close_queued_or_in_flight()\n        };\n\n        if writable {\n            let wait_promise =\n                Self::wait_for_writes_to_finish(ctx.clone(), self.current_write.clone())?;\n            let pipe_to = self.clone();\n            upon_promise_fulfilment(ctx, wait_promise, move |ctx, ()| {\n                pipe_to.finalize(ctx, error)\n            })?;\n        } else {\n            self.finalize(ctx, error)?;\n        }\n        Ok(())\n    }\n\n    fn wait_for_writes_to_finish(\n        ctx: Ctx<'js>,\n        current_write: Rc<RefCell<Promise<'js>>>,\n    ) -> Result<Promise<'js>> {\n        let old_current_write: Promise<'js> = current_write.as_ref().borrow().clone();\n\n        upon_promise_fulfilment(\n            ctx,\n            old_current_write.clone(),\n            move |ctx: Ctx<'js>, ()| -> Result<Undefined<Promise<'js>>> {\n                if !old_current_write.eq(&current_write.as_ref().borrow()) {\n                    Ok(Undefined(Some(Self::wait_for_writes_to_finish(\n                        ctx,\n                        current_write,\n                    )?)))\n                } else {\n                    Ok(Undefined(None))\n                }\n            },\n        )\n    }\n\n    fn finalize(&self, ctx: Ctx<'js>, error: Option<Value<'js>>) -> Result<()> {\n        let source_objects = ReadableStreamObjects::from_class(self.source_objects.clone());\n        let dest_objects = WritableStreamObjects::from_class(self.dest_objects.clone());\n\n        WritableStreamDefaultWriter::writable_stream_default_writer_release(dest_objects)?;\n        ReadableStreamDefaultReader::readable_stream_default_reader_release(source_objects)?;\n\n        if let (Some(signal), Some(abort_callback)) = (&self.signal, &self.abort_callback) {\n            AbortSignal::remove_on_abort(\n                This(signal.clone()),\n                ctx.clone(),\n                abort_callback.clone(),\n            )?;\n        }\n\n        if let Some(error) = error {\n            self.promise.reject(error)\n        } else {\n            self.promise.resolve_undefined()\n        }\n    }\n}\n\n#[derive(Default)]\npub struct StreamPipeOptions<'js> {\n    pub prevent_close: bool,\n    pub prevent_abort: bool,\n    pub prevent_cancel: bool,\n    pub signal: Option<Class<'js, AbortSignal<'js>>>,\n}\n\nimpl<'js> FromJs<'js> for StreamPipeOptions<'js> {\n    fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        let ty_name = value.type_name();\n        let obj = value\n            .as_object()\n            .ok_or(Error::new_from_js(ty_name, \"Object\"))?;\n\n        let get_bool = |key| {\n            Result::Ok(\n                obj.get_value_or_undefined::<_, Coerced<bool>>(key)?\n                    .map(|b| b.0)\n                    .unwrap_or(false),\n            ) // missing is treated as false\n        };\n\n        let prevent_abort = get_bool(\"preventAbort\")?;\n        let prevent_close = get_bool(\"preventClose\")?;\n        let prevent_cancel = get_bool(\"preventCancel\")?;\n\n        let signal = match obj.get_value_or_undefined::<_, Value<'js>>(\"signal\")? {\n            Some(signal) => Some(\n                Class::<AbortSignal>::from_js(ctx, signal)\n                    .or_throw_type(ctx, \"Invalid signal argument\")?,\n            ),\n            None => None,\n        };\n\n        Ok(Self {\n            prevent_close,\n            prevent_abort,\n            prevent_cancel,\n            signal,\n        })\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/readable/stream/source.rs",
    "content": "use rquickjs::{Function, Object, Result};\n\nuse crate::{readable::stream::ReadableStreamType, utils::ValueOrUndefined};\n\n#[derive(Default)]\npub(crate) struct UnderlyingSource<'js> {\n    // callback UnderlyingSourceStartCallback = any (ReadableStreamController controller);\n    pub(crate) start: Option<Function<'js>>,\n    // callback UnderlyingSourcePullCallback = Promise<undefined> (ReadableStreamController controller);\n    pub(crate) pull: Option<Function<'js>>,\n    // callback UnderlyingSourceCancelCallback = Promise<undefined> (optional any reason);\n    pub(crate) cancel: Option<Function<'js>>,\n    pub(super) r#type: Option<ReadableStreamType>,\n    // [EnforceRange] unsigned long long autoAllocateChunkSize;\n    pub(crate) auto_allocate_chunk_size: Option<usize>,\n}\n\nimpl<'js> UnderlyingSource<'js> {\n    pub(super) fn from_object(obj: Object<'js>) -> Result<Self> {\n        let start = obj.get_value_or_undefined::<_, _>(\"start\")?;\n        let pull = obj.get_value_or_undefined::<_, _>(\"pull\")?;\n        let cancel = obj.get_value_or_undefined::<_, _>(\"cancel\")?;\n        let r#type = obj.get_value_or_undefined::<_, _>(\"type\")?;\n        let auto_allocate_chunk_size =\n            obj.get_value_or_undefined::<_, _>(\"autoAllocateChunkSize\")?;\n\n        Ok(Self {\n            start,\n            pull,\n            cancel,\n            r#type,\n            auto_allocate_chunk_size,\n        })\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/readable/stream/tee.rs",
    "content": "use std::{\n    cell::{OnceCell, RefCell},\n    rc::Rc,\n    sync::atomic::{AtomicBool, Ordering},\n};\n\nuse llrt_utils::clone::structured_clone;\nuse rquickjs::{\n    class::{OwnedBorrowMut, Trace},\n    function::Constructor,\n    prelude::{List, OnceFn, Opt},\n    ArrayBuffer, Class, Ctx, Error, Function, IntoJs, Promise, Result, Value,\n};\n\nuse crate::{\n    readable::{\n        byob_reader::{ReadableStreamBYOBReader, ReadableStreamReadIntoRequest, ViewBytes},\n        byte_controller::{ReadableByteStreamController, ReadableByteStreamControllerOwned},\n        controller::{ReadableStreamController, ReadableStreamControllerClass},\n        default_controller::{\n            ReadableStreamDefaultController, ReadableStreamDefaultControllerOwned,\n        },\n        default_reader::{\n            ReadableStreamDefaultReader, ReadableStreamDefaultReaderOwned,\n            ReadableStreamReadRequest,\n        },\n        objects::{ReadableByteStreamObjects, ReadableStreamDefaultControllerObjects},\n        objects::{\n            ReadableStreamBYOBObjects, ReadableStreamClassObjects,\n            ReadableStreamDefaultReaderObjects, ReadableStreamObjects,\n        },\n        reader::{\n            ReadableStreamReader, ReadableStreamReaderClass, ReadableStreamReaderOwned,\n            UndefinedReader,\n        },\n        stream::{\n            algorithms::{CancelAlgorithm, PullAlgorithm, StartAlgorithm},\n            ReadableStream, ReadableStreamClass,\n        },\n    },\n    utils::promise::{upon_promise, ResolveablePromise},\n};\n\ntype ReadableStreamPair<'js> = (ReadableStreamClass<'js>, ReadableStreamClass<'js>);\n\nimpl<'js> ReadableStream<'js> {\n    pub(super) fn readable_stream_tee<C: ReadableStreamController<'js>>(\n        ctx: Ctx<'js>,\n        objects: ReadableStreamObjects<'js, C, UndefinedReader>,\n        clone_for_branch_2: bool,\n    ) -> Result<ReadableStreamPair<'js>> {\n        let (streams, _) = objects.with_controller(\n            ctx,\n            |ctx, objects| {\n                // Return ? ReadableStreamDefaultTee(stream, cloneForBranch2).\n                let (streams, objects) =\n                    Self::readable_stream_default_tee(ctx, objects, clone_for_branch_2)?;\n                Ok((streams, objects.clear_reader()))\n            },\n            |ctx, objects| {\n                // If stream.[[controller]] implements ReadableByteStreamController, return ? ReadableByteStreamTee(stream).\n                Self::readable_byte_stream_tee(ctx, objects)\n            },\n        )?;\n\n        Ok(streams)\n    }\n\n    fn readable_stream_default_tee(\n        ctx: Ctx<'js>,\n        mut objects: ReadableStreamDefaultControllerObjects<'js, UndefinedReader>,\n        clone_for_branch_2: bool,\n    ) -> Result<(\n        ReadableStreamPair<'js>,\n        ReadableStreamDefaultControllerObjects<'js, ReadableStreamDefaultReaderOwned<'js>>,\n    )> {\n        // Let reader be ? AcquireReadableStreamDefaultReader(stream).\n        let (stream, reader) = ReadableStreamReaderClass::acquire_readable_stream_default_reader(\n            ctx.clone(),\n            objects.stream,\n        )?;\n        objects.stream = stream;\n        // Let reading be false.\n        let reading = Rc::new(AtomicBool::new(false));\n        // Let readAgain be false.\n        let read_again = Rc::new(AtomicBool::new(false));\n        // Let canceled1 be false.\n        // Let canceled2 be false.\n        // Let reason1 be undefined.\n        let reason_1 = Rc::new(OnceCell::new());\n        // Let reason2 be undefined.\n        let reason_2 = Rc::new(OnceCell::new());\n        // Let branch1 be undefined.\n        let branch_1: Rc<\n            OnceCell<\n                ReadableStreamClassObjects<\n                    'js,\n                    ReadableStreamDefaultControllerOwned<'js>,\n                    UndefinedReader,\n                >,\n            >,\n        > = Rc::new(OnceCell::new());\n        // Let branch2 be undefined.\n        let branch_2: Rc<\n            OnceCell<\n                ReadableStreamClassObjects<\n                    'js,\n                    ReadableStreamDefaultControllerOwned<'js>,\n                    UndefinedReader,\n                >,\n            >,\n        > = Rc::new(OnceCell::new());\n        // Let cancelPromise be a new promise.\n        let cancel_promise = ResolveablePromise::new(&ctx)?;\n\n        // Let startAlgorithm be an algorithm that returns undefined.\n        let start_algorithm = StartAlgorithm::ReturnUndefined;\n\n        let objects_class = objects.into_inner().set_reader(reader);\n\n        let pull_algorithm = PullAlgorithm::from_fn({\n            let objects_class = objects_class.clone();\n            let reason_1 = reason_1.clone();\n            let reason_2 = reason_2.clone();\n            let branch_1 = branch_1.clone();\n            let branch_2 = branch_2.clone();\n            let cancel_promise = cancel_promise.clone();\n            move |ctx: Ctx<'js>, _| {\n                let objects = ReadableStreamObjects::from_class(objects_class.clone());\n                Self::readable_stream_default_pull_algorithm(\n                    ctx,\n                    objects,\n                    clone_for_branch_2,\n                    reading.clone(),\n                    read_again.clone(),\n                    reason_1.clone(),\n                    reason_2.clone(),\n                    branch_1.clone(),\n                    branch_2.clone(),\n                    cancel_promise.clone(),\n                )\n            }\n        });\n        let cancel_algorithm_1 = CancelAlgorithm::from_fn({\n            let objects_class = objects_class.clone();\n            let reason_1 = reason_1.clone();\n            let reason_2 = reason_2.clone();\n            let cancel_promise = cancel_promise.clone();\n            move |reason: Value<'js>| {\n                let objects = ReadableStreamObjects::from_class(objects_class.clone());\n                Self::readable_stream_cancel_1_algorithm(\n                    reason.ctx().clone(),\n                    objects,\n                    reason_1,\n                    reason_2,\n                    cancel_promise,\n                    reason,\n                )\n            }\n        });\n\n        let cancel_algorithm_2 = CancelAlgorithm::from_fn({\n            let objects_class = objects_class.clone();\n            let reason_1 = reason_1.clone();\n            let reason_2 = reason_2.clone();\n            let cancel_promise = cancel_promise.clone();\n            move |reason: Value<'js>| {\n                let objects = ReadableStreamObjects::from_class(objects_class.clone());\n                Self::readable_stream_cancel_2_algorithm(\n                    reason.ctx().clone(),\n                    objects,\n                    reason_1,\n                    reason_2,\n                    cancel_promise,\n                    reason,\n                )\n            }\n        });\n\n        // Set branch1 to ! CreateReadableStream(startAlgorithm, pullAlgorithm, cancel1Algorithm).\n        let branch_1 = {\n            let objects = Self::create_readable_stream(\n                ctx.clone(),\n                start_algorithm.clone(),\n                pull_algorithm.clone(),\n                cancel_algorithm_1,\n                None,\n                None,\n            )?;\n            _ = branch_1.set(objects.clone());\n            objects\n        };\n\n        // Set branch2 to ! CreateReadableStream(startAlgorithm, pullAlgorithm, cancel2Algorithm).\n        let branch_2 = {\n            let objects = Self::create_readable_stream(\n                ctx.clone(),\n                start_algorithm,\n                pull_algorithm,\n                cancel_algorithm_2,\n                None,\n                None,\n            )?;\n            _ = branch_2.set(objects.clone());\n            objects\n        };\n\n        upon_promise(\n            ctx.clone(),\n            objects_class\n                .reader\n                .borrow()\n                .generic\n                .closed_promise\n                .promise\n                .clone(),\n            {\n                let branch_1 = branch_1.clone();\n                let branch_2 = branch_2.clone();\n                move |_, result| match result {\n                    Ok(()) => Ok(()),\n                    // Upon rejection of reader.[[closedPromise]] with reason r,\n                    Err(reason) => {\n                        // Perform ! ReadableStreamDefaultControllerError(branch1.[[controller]], r).\n                        let objects_1 =\n                            ReadableStreamObjects::from_class_no_reader(branch_1).refresh_reader();\n                        ReadableStreamDefaultController::readable_stream_default_controller_error(\n                            objects_1,\n                            reason.clone(),\n                        )?;\n\n                        // Perform ! ReadableStreamDefaultControllerError(branch2.[[controller]], r).\n                        let objects_2 =\n                            ReadableStreamObjects::from_class_no_reader(branch_2).refresh_reader();\n                        ReadableStreamDefaultController::readable_stream_default_controller_error(\n                            objects_2, reason,\n                        )?;\n                        // If canceled1 is false or canceled2 is false, resolve cancelPromise with undefined.\n                        if reason_1.get().is_none() || reason_2.get().is_none() {\n                            cancel_promise.resolve_undefined()?;\n                        }\n\n                        Ok(())\n                    },\n                }\n            },\n        )?;\n\n        Ok((\n            (branch_1.stream, branch_2.stream),\n            ReadableStreamObjects::from_class(objects_class),\n        ))\n    }\n\n    // Let pullAlgorithm be the following steps:\n    #[allow(clippy::too_many_arguments)]\n    fn readable_stream_default_pull_algorithm(\n        ctx: Ctx<'js>,\n        mut objects: ReadableStreamDefaultControllerObjects<\n            'js,\n            ReadableStreamDefaultReaderOwned<'js>,\n        >,\n        clone_for_branch_2: bool,\n        reading: Rc<AtomicBool>,\n        read_again: Rc<AtomicBool>,\n        reason_1: Rc<OnceCell<Value<'js>>>,\n        reason_2: Rc<OnceCell<Value<'js>>>,\n        branch_1: Rc<\n            OnceCell<\n                ReadableStreamClassObjects<\n                    'js,\n                    ReadableStreamDefaultControllerOwned<'js>,\n                    UndefinedReader,\n                >,\n            >,\n        >,\n        branch_2: Rc<\n            OnceCell<\n                ReadableStreamClassObjects<\n                    'js,\n                    ReadableStreamDefaultControllerOwned<'js>,\n                    UndefinedReader,\n                >,\n            >,\n        >,\n        cancel_promise: ResolveablePromise<'js>,\n    ) -> Result<Promise<'js>> {\n        // If reading is true,\n        if reading.load(Ordering::Acquire) {\n            // Set readAgain to true.\n            read_again.store(true, Ordering::Release);\n\n            // Return a promise resolved with undefined.\n            return Ok(objects\n                .stream\n                .promise_primordials\n                .promise_resolved_with_undefined\n                .clone());\n        }\n\n        // Set reading to true.\n        reading.store(true, Ordering::Release);\n\n        #[derive(Clone)]\n        struct ReadRequest<'js> {\n            clone_for_branch_2: bool,\n            reading: Rc<AtomicBool>,\n            read_again: Rc<AtomicBool>,\n            reason_1: Rc<OnceCell<Value<'js>>>,\n            reason_2: Rc<OnceCell<Value<'js>>>,\n            branch_1: Rc<\n                OnceCell<\n                    ReadableStreamClassObjects<\n                        'js,\n                        ReadableStreamDefaultControllerOwned<'js>,\n                        UndefinedReader,\n                    >,\n                >,\n            >,\n            branch_2: Rc<\n                OnceCell<\n                    ReadableStreamClassObjects<\n                        'js,\n                        ReadableStreamDefaultControllerOwned<'js>,\n                        UndefinedReader,\n                    >,\n                >,\n            >,\n            cancel_promise: ResolveablePromise<'js>,\n        }\n\n        impl<'js> Trace<'js> for ReadRequest<'js> {\n            fn trace<'a>(&self, tracer: rquickjs::class::Tracer<'a, 'js>) {\n                if let Some(r) = self.reason_1.get() {\n                    r.trace(tracer)\n                }\n                if let Some(r) = self.reason_2.get() {\n                    r.trace(tracer)\n                }\n                if let Some(b) = self.branch_1.get() {\n                    b.trace(tracer)\n                }\n                if let Some(b) = self.branch_2.get() {\n                    b.trace(tracer)\n                }\n                self.cancel_promise.trace(tracer);\n            }\n        }\n\n        // Let readRequest be a read request with the following items:\n        impl<'js> ReadableStreamReadRequest<'js> for ReadRequest<'js> {\n            fn chunk_steps(\n                &self,\n                objects: ReadableStreamDefaultReaderObjects<'js>,\n                chunk: Value<'js>,\n            ) -> Result<ReadableStreamDefaultReaderObjects<'js>> {\n                let ctx = chunk.ctx().clone();\n                let this = self.clone();\n\n                objects\n                    .with_assert_default_controller(\n                        |objects| {\n                            let objects_class = objects.into_inner();\n                            // Queue a microtask to perform the following steps:\n                            let f = {\n                                let ctx = ctx.clone();\n                                let objects_class = objects_class.clone();\n                                move || -> Result<()> {\n                                    // Set readAgain to false.\n                                    this.read_again.store(false, Ordering::Release);\n\n                                    // Let chunk1 and chunk2 be chunk.\n                                    let chunk_1 = chunk.clone();\n                                    let chunk_2 = chunk.clone();\n\n                                    // If canceled2 is false and cloneForBranch2 is true,\n                                    let chunk_2 = if this.reason_2.get().is_none() && this.clone_for_branch_2 {\n                                        // Let cloneResult be StructuredClone(chunk2).\n                                        let clone_result: Result<Value<'_>> = structured_clone(&ctx, chunk_2, Opt(None));\n                                        match clone_result {\n                                            // If cloneResult is an abrupt completion,\n                                            Err(Error::Exception) => {\n                                                let clone_result = ctx.catch();\n                                                let objects_1 = ReadableStreamObjects::from_class(\n                                                    this.branch_1.get().cloned().expect(\n                                                        \"canceled1 set without branch1 being initialised\",\n                                                    ),\n                                                ).refresh_reader();\n\n                                                // Perform ! ReadableStreamDefaultControllerError(branch1.[[controller]], cloneResult.[[Value]]).\n                                                ReadableStreamDefaultController::readable_stream_default_controller_error(\n                                                    objects_1,\n                                                    clone_result.clone(),\n                                                )?;\n\n                                                let objects_2 = ReadableStreamObjects::from_class(\n                                                    this.branch_2.get().cloned().clone().expect(\n                                                        \"canceled2 set without branch2 being initialised\",\n                                                    ),\n                                                ).refresh_reader();\n\n                                                // Perform ! ReadableStreamDefaultControllerError(branch2.[[controller]], cloneResult.[[Value]]).\n                                                ReadableStreamDefaultController::readable_stream_default_controller_error(\n                                                    objects_2,\n                                                    clone_result.clone(),\n                                                )?;\n\n                                                // Resolve cancelPromise with ! ReadableStreamCancel(stream, cloneResult.[[Value]]).\n                                                let (promise, _) =\n                                                    ReadableStream::readable_stream_cancel(\n                                                        ctx,\n                                                        ReadableStreamObjects::from_class(objects_class),\n                                                        clone_result,\n                                                    )?;\n                                                this.cancel_promise.resolve(promise)?;\n                                                // Return.\n                                                return Ok(());\n                                            },\n                                            Ok(clone_result) => {\n                                                // Otherwise, set chunk2 to cloneResult.[[Value]].\n                                                clone_result\n                                            },\n                                            Err(err) => return Err(err),\n                                        }\n                                    } else {\n                                        chunk_2\n                                    };\n\n                                    // If canceled1 is false, perform ! ReadableStreamDefaultControllerEnqueue(branch1.[[controller]], chunk1).\n                                    if this.reason_1.get().is_none() {\n                                        let objects_1 = ReadableStreamObjects::from_class(\n                                            this.branch_1\n                                                .get()\n                                                .cloned()\n                                                .expect(\"canceled1 set without branch1 being initialised\"),\n                                        ).refresh_reader();\n\n                                        ReadableStreamDefaultController::readable_stream_default_controller_enqueue(ctx.clone(), objects_1, chunk_1)?;\n                                    }\n\n                                    // If canceled2 is false, perform ! ReadableStreamDefaultControllerEnqueue(branch2.[[controller]], chunk2).\n                                    if this.reason_2.get().is_none() {\n                                        let objects_2 = ReadableStreamObjects::from_class(\n                                            this.branch_2\n                                                .get()\n                                                .cloned()\n                                                .expect(\"canceled2 set without branch2 being initialised\"),\n                                        ).refresh_reader();\n\n                                        ReadableStreamDefaultController::readable_stream_default_controller_enqueue(ctx.clone(), objects_2, chunk_2)?;\n                                    }\n\n                                    // Set reading to false.\n                                    this.reading.store(false, Ordering::Release);\n\n                                    // If readAgain is true, perform pullAlgorithm.\n                                    if this.read_again.load(Ordering::Acquire) {\n                                        let objects = ReadableStreamObjects::from_class(objects_class);\n\n                                        ReadableStream::readable_stream_default_pull_algorithm(\n                                            ctx.clone(),\n                                            objects,\n                                            this.clone_for_branch_2,\n                                            this.reading.clone(),\n                                            this.read_again.clone(),\n                                            this.reason_1.clone(),\n                                            this.reason_2.clone(),\n                                            this.branch_1.clone(),\n                                            this.branch_2.clone(),\n                                            this.cancel_promise.clone(),\n                                        )?;\n                                    }\n\n                                    Ok(())\n                                }\n                            };\n\n                            let () = Function::new(ctx, OnceFn::new(f))?.defer(())?;\n\n\n                            Ok(ReadableStreamObjects::from_class(objects_class))\n                        },\n                    )\n            }\n\n            fn close_steps(\n                &self,\n                ctx: &Ctx<'js>,\n                objects: ReadableStreamDefaultReaderObjects<'js>,\n            ) -> Result<ReadableStreamDefaultReaderObjects<'js>> {\n                // Set reading to false.\n                self.reading.store(false, Ordering::Release);\n                // If canceled1 is false, perform ! ReadableStreamDefaultControllerClose(branch1.[[controller]]).\n                if self.reason_1.get().is_none() {\n                    let objects = ReadableStreamObjects::from_class(\n                        self.branch_1\n                            .get()\n                            .expect(\"close called without branch1 being initialised\")\n                            .clone(),\n                    )\n                    .refresh_reader();\n\n                    ReadableStreamDefaultController::readable_stream_default_controller_close(\n                        ctx.clone(),\n                        objects,\n                    )?;\n                }\n                // If canceled2 is false, perform ! ReadableStreamDefaultControllerClose(branch2.[[controller]]).\n                if self.reason_2.get().is_none() {\n                    let objects = ReadableStreamObjects::from_class(\n                        self.branch_2\n                            .get()\n                            .expect(\"close called without branch2 being initialised\")\n                            .clone(),\n                    )\n                    .refresh_reader();\n\n                    ReadableStreamDefaultController::readable_stream_default_controller_close(\n                        ctx.clone(),\n                        objects,\n                    )?;\n                }\n                // If canceled1 is false or canceled2 is false, resolve cancelPromise with undefined.\n                if self.reason_1.get().is_none() || self.reason_2.get().is_none() {\n                    self.cancel_promise.resolve_undefined()?\n                }\n                Ok(objects)\n            }\n\n            fn error_steps(\n                &self,\n                objects: ReadableStreamDefaultReaderObjects<'js>,\n                _: Value<'js>,\n            ) -> Result<ReadableStreamDefaultReaderObjects<'js>> {\n                // Set reading to false.\n                self.reading.store(false, Ordering::Release);\n                Ok(objects)\n            }\n        }\n\n        // Perform ! ReadableStreamDefaultReaderRead(reader, readRequest).\n        objects = ReadableStreamDefaultReader::readable_stream_default_reader_read(\n            &ctx,\n            objects,\n            ReadRequest {\n                clone_for_branch_2,\n                reading,\n                read_again,\n                reason_1,\n                reason_2,\n                branch_1,\n                branch_2,\n                cancel_promise,\n            },\n        )?;\n\n        // Return a promise resolved with undefined.\n        Ok(objects\n            .stream\n            .promise_primordials\n            .promise_resolved_with_undefined\n            .clone())\n    }\n\n    // Let cancel1Algorithm be the following steps, taking a reason argument:\n    fn readable_stream_cancel_1_algorithm(\n        ctx: Ctx<'js>,\n        objects: ReadableStreamObjects<\n            'js,\n            impl ReadableStreamController<'js>,\n            impl ReadableStreamReader<'js>,\n        >,\n        reason_1: Rc<OnceCell<Value<'js>>>,\n        reason_2: Rc<OnceCell<Value<'js>>>,\n        cancel_promise: ResolveablePromise<'js>,\n        reason: Value<'js>,\n    ) -> Result<Promise<'js>> {\n        // Set canceled1 to true.\n        // Set reason1 to reason.\n        reason_1\n            .set(reason.clone())\n            .expect(\"First tee stream already has a cancel reason\");\n\n        // If canceled2 is true,\n        if let Some(reason_2) = reason_2.get().cloned() {\n            // Let compositeReason be ! CreateArrayFromList(« reason1, reason2 »).\n            let composite_reason = List((reason, reason_2));\n            // Let cancelResult be ! ReadableStreamCancel(stream, compositeReason).\n            let (cancel_result, _) = ReadableStream::readable_stream_cancel(\n                ctx.clone(),\n                objects,\n                composite_reason.into_js(&ctx)?,\n            )?;\n            // Resolve cancelPromise with cancelResult.\n            cancel_promise.resolve(cancel_result)?;\n        }\n\n        // Return cancelPromise.\n        Ok(cancel_promise.promise)\n    }\n\n    // Let cancel2Algorithm be the following steps, taking a reason argument:\n    #[allow(clippy::too_many_arguments)]\n    fn readable_stream_cancel_2_algorithm(\n        ctx: Ctx<'js>,\n        objects: ReadableStreamObjects<\n            'js,\n            impl ReadableStreamController<'js>,\n            impl ReadableStreamReader<'js>,\n        >,\n        reason_1: Rc<OnceCell<Value<'js>>>,\n        reason_2: Rc<OnceCell<Value<'js>>>,\n        cancel_promise: ResolveablePromise<'js>,\n        reason: Value<'js>,\n    ) -> Result<Promise<'js>> {\n        // Set canceled2 to true.\n        // Set reason2 to reason.\n        reason_2\n            .set(reason.clone())\n            .expect(\"Second tee stream already has a cancel reason\");\n\n        // If canceled1 is true,\n        if let Some(reason_1) = reason_1.get().cloned() {\n            // Let compositeReason be ! CreateArrayFromList(« reason1, reason2 »).\n            let composite_reason = List((reason_1, reason));\n            // Let cancelResult be ! ReadableStreamCancel(stream, compositeReason).\n            let (cancel_result, _) = ReadableStream::readable_stream_cancel(\n                ctx.clone(),\n                objects,\n                composite_reason.into_js(&ctx)?,\n            )?;\n            // Resolve cancelPromise with cancelResult.\n            let () = cancel_promise.resolve(cancel_result)?;\n        }\n\n        // Return cancelPromise.\n        Ok(cancel_promise.promise)\n    }\n\n    fn readable_byte_stream_tee(\n        ctx: Ctx<'js>,\n        mut objects: ReadableByteStreamObjects<'js, UndefinedReader>,\n    ) -> Result<(\n        ReadableStreamPair<'js>,\n        ReadableByteStreamObjects<'js, UndefinedReader>,\n    )> {\n        // Let reader be ? AcquireReadableStreamDefaultReader(stream).\n        let (stream, reader) = ReadableStreamReaderClass::acquire_readable_stream_default_reader(\n            ctx.clone(),\n            objects.stream,\n        )?;\n        objects.stream = stream;\n        let reader: Rc<RefCell<ReadableStreamReaderClass<'js>>> =\n            Rc::new(RefCell::new(reader.into()));\n        // Let reading be false.\n        let reading = Rc::new(AtomicBool::new(false));\n        // Let readAgainForBranch1 be false.\n        let read_again_for_branch_1 = Rc::new(AtomicBool::new(false));\n        // Let readAgainForBranch2 be false.\n        let read_again_for_branch_2 = Rc::new(AtomicBool::new(false));\n        // Let canceled1 be false.\n        // Let canceled2 be false.\n        // Let reason1 be undefined.\n        let reason_1 = Rc::new(OnceCell::new());\n        // Let reason2 be undefined.\n        let reason_2 = Rc::new(OnceCell::new());\n        // Let branch1 be undefined.\n        let branch_1: Rc<OnceCell<Class<'js, Self>>> = Rc::new(OnceCell::new());\n        // Let branch2 be undefined.\n        let branch_2: Rc<OnceCell<Class<'js, Self>>> = Rc::new(OnceCell::new());\n        // Let cancelPromise be a new promise.\n        let cancel_promise = ResolveablePromise::new(&ctx)?;\n\n        let objects_class = objects.into_inner();\n\n        // Let pull1Algorithm be the following steps:\n        let pull_1_algorithm = PullAlgorithm::from_fn({\n            let objects_class = objects_class.clone();\n            let reader = reader.clone();\n            let reading = reading.clone();\n            let read_again_for_branch_1 = read_again_for_branch_1.clone();\n            let read_again_for_branch_2 = read_again_for_branch_2.clone();\n            let reason_1 = reason_1.clone();\n            let reason_2 = reason_2.clone();\n            let branch_1 = branch_1.clone();\n            let branch_2 = branch_2.clone();\n            let cancel_promise = cancel_promise.clone();\n            move |ctx, branch_1_controller| {\n                let objects = ReadableStreamObjects::from_class(objects_class.clone());\n\n                let branch_1_controller = OwnedBorrowMut::from_class(match branch_1_controller {\n                    ReadableStreamControllerClass::ReadableStreamByteController(c) => c,\n                    _ => panic!(\n                        \"ReadableByteStream tee pull1 algorithm called without branch1 having a byte controller\"\n                    ),\n                });\n\n                let branch_2 = OwnedBorrowMut::from_class(branch_2.get().cloned().expect(\"ReadableByteStream tee pull1 algorithm called without branch2 being initialised\"));\n                let branch_2_controller = match branch_2.controller {\n                    ReadableStreamControllerClass::ReadableStreamByteController(ref c) => {\n                        OwnedBorrowMut::from_class(c.clone())\n                    },\n                    _ => {\n                        panic!(\"ReadableByteStream tee pull1 algorithm called without branch2 having a byte controller\")\n                    },\n                };\n\n                Self::readable_byte_stream_pull_1_algorithm(\n                        ctx,\n                        objects,\n                        reader.clone(),\n                        reading.clone(),\n                        read_again_for_branch_1.clone(),\n                        read_again_for_branch_2.clone(),\n                        reason_1.clone(),\n                        reason_2.clone(),\n                        ReadableStreamObjects::new_byte(OwnedBorrowMut::from_class(branch_1.get().cloned().expect(\"ReadableByteStream tee pull1 algorithm called without branch1 being initialised\")), branch_1_controller) ,\n                        ReadableStreamObjects::new_byte(branch_2, branch_2_controller),\n                        cancel_promise.clone(),\n                    )\n            }\n        });\n\n        // Let pull2Algorithm be the following steps:\n        let pull_2_algorithm = PullAlgorithm::from_fn({\n            let objects_class = objects_class.clone();\n            let reader = reader.clone();\n            let reading = reading.clone();\n            let read_again_for_branch_1 = read_again_for_branch_1.clone();\n            let read_again_for_branch_2 = read_again_for_branch_2.clone();\n            let reason_1 = reason_1.clone();\n            let reason_2 = reason_2.clone();\n            let branch_1 = branch_1.clone();\n            let branch_2 = branch_2.clone();\n            let cancel_promise = cancel_promise.clone();\n            move |ctx, branch_2_controller| {\n                let objects = ReadableStreamObjects::from_class(objects_class.clone());\n\n                let branch_2 = OwnedBorrowMut::from_class(branch_2.get().cloned().expect(\"ReadableByteStream tee pull2 algorithm called without branch2 being initialised\"));\n                let branch_2_controller = match branch_2_controller {\n                    ReadableStreamControllerClass::ReadableStreamByteController(ref c) => {\n                        OwnedBorrowMut::from_class(c.clone())\n                    },\n                    _ => {\n                        panic!(\"ReadableByteStream tee pull2 algorithm called without branch2 having a byte controller\")\n                    },\n                };\n\n                let branch_1 = OwnedBorrowMut::from_class(branch_1.get().cloned().expect(\"ReadableByteStream tee pull2 algorithm called without branch1 being initialised\"));\n                let branch_1_controller = match branch_1.controller {\n                    ReadableStreamControllerClass::ReadableStreamByteController(ref c) => {\n                        OwnedBorrowMut::from_class(c.clone())\n                    },\n                    _ => {\n                        panic!(\"ReadableByteStream tee pull2 algorithm called without branch1 having a byte controller\")\n                    },\n                };\n                Self::readable_byte_stream_pull_2_algorithm(\n                    ctx,\n                    objects,\n                    reader.clone(),\n                    reading.clone(),\n                    read_again_for_branch_1.clone(),\n                    read_again_for_branch_2.clone(),\n                    reason_1.clone(),\n                    reason_2.clone(),\n                    ReadableStreamObjects::new_byte(branch_1, branch_1_controller),\n                    ReadableStreamObjects::new_byte(branch_2, branch_2_controller),\n                    cancel_promise.clone(),\n                )\n            }\n        });\n\n        let cancel_algorithm_1 = CancelAlgorithm::from_fn({\n            let objects_class = objects_class.clone();\n            let reader = reader.clone();\n            let reason_1 = reason_1.clone();\n            let reason_2 = reason_2.clone();\n            let cancel_promise = cancel_promise.clone();\n            move |reason: Value<'js>| {\n                let reader = ReadableStreamReaderOwned::from_class(reader.borrow().clone());\n                let objects = ReadableStreamObjects::from_class(objects_class).set_reader(reader);\n                Self::readable_stream_cancel_1_algorithm(\n                    reason.ctx().clone(),\n                    objects,\n                    reason_1,\n                    reason_2,\n                    cancel_promise,\n                    reason,\n                )\n            }\n        });\n\n        let cancel_algorithm_2 = CancelAlgorithm::from_fn({\n            let objects_class = objects_class.clone();\n            let reader = reader.clone();\n            let reason_1 = reason_1.clone();\n            let reason_2 = reason_2.clone();\n            let cancel_promise = cancel_promise.clone();\n            move |reason: Value<'js>| {\n                let reader = ReadableStreamReaderOwned::from_class(reader.borrow().clone());\n                let objects = ReadableStreamObjects::from_class(objects_class).set_reader(reader);\n                Self::readable_stream_cancel_2_algorithm(\n                    reason.ctx().clone(),\n                    objects,\n                    reason_1,\n                    reason_2,\n                    cancel_promise,\n                    reason,\n                )\n            }\n        });\n\n        // Let startAlgorithm be an algorithm that returns undefined.\n        let start_algorithm = StartAlgorithm::ReturnUndefined;\n\n        // Set branch1 to ! CreateReadableByteStream(startAlgorithm, pull1Algorithm, cancel1Algorithm).\n        let objects_1 = {\n            let (s, c) = Self::create_readable_byte_stream(\n                ctx.clone(),\n                start_algorithm.clone(),\n                pull_1_algorithm.clone(),\n                cancel_algorithm_1,\n            )?;\n            _ = branch_1.set(s.clone());\n            ReadableStreamClassObjects {\n                stream: s,\n                controller: c,\n                reader: UndefinedReader,\n            }\n        };\n\n        // Set branch2 to ! CreateReadableByteStream(startAlgorithm, pull2Algorithm, cancel2Algorithm).\n        let objects_2 = {\n            let (s, c) = Self::create_readable_byte_stream(\n                ctx.clone(),\n                start_algorithm,\n                pull_2_algorithm,\n                cancel_algorithm_2,\n            )?;\n            _ = branch_2.set(s.clone());\n            ReadableStreamClassObjects {\n                stream: s,\n                controller: c,\n                reader: UndefinedReader,\n            }\n        };\n\n        // Perform forwardReaderError, given reader.\n        let this_reader = reader.borrow().clone();\n        Self::readable_byte_stream_forward_reader_error(\n            ctx,\n            reader,\n            objects_1.clone(),\n            objects_2.clone(),\n            reason_1,\n            reason_2,\n            this_reader,\n            cancel_promise,\n        )?;\n\n        // Return « branch1, branch2 ».\n        Ok((\n            (objects_1.stream, objects_2.stream),\n            ReadableStreamObjects::from_class(objects_class),\n        ))\n    }\n\n    // Let forwardReaderError be the following steps, taking a thisReader argument:\n    #[allow(clippy::too_many_arguments)]\n    fn readable_byte_stream_forward_reader_error(\n        ctx: Ctx<'js>,\n        reader: Rc<RefCell<ReadableStreamReaderClass<'js>>>,\n        objects_1: ReadableStreamClassObjects<\n            'js,\n            ReadableByteStreamControllerOwned<'js>,\n            UndefinedReader,\n        >,\n        objects_2: ReadableStreamClassObjects<\n            'js,\n            ReadableByteStreamControllerOwned<'js>,\n            UndefinedReader,\n        >,\n        reason_1: Rc<OnceCell<Value<'js>>>,\n        reason_2: Rc<OnceCell<Value<'js>>>,\n        this_reader: ReadableStreamReaderClass<'js>,\n        cancel_promise: ResolveablePromise<'js>,\n    ) -> Result<()> {\n        // Upon rejection of thisReader.[[closedPromise]] with reason r,\n        upon_promise(\n            ctx,\n            this_reader.closed_promise(),\n            move |_, result| match result {\n                Err(r) => {\n                    // If thisReader is not reader, return.\n                    if !reader.borrow().eq(&this_reader) {\n                        return Ok(());\n                    }\n\n                    let objects_1 =\n                        ReadableStreamObjects::from_class_no_reader(objects_1).refresh_reader();\n\n                    // Perform ! ReadableByteStreamControllerError(branch1.[[controller]], r).\n                    ReadableByteStreamController::readable_byte_stream_controller_error(\n                        objects_1,\n                        r.clone(),\n                    )?;\n\n                    let objects_2 =\n                        ReadableStreamObjects::from_class_no_reader(objects_2).refresh_reader();\n\n                    // Perform ! ReadableByteStreamControllerError(branch2.[[controller]], r).\n                    ReadableByteStreamController::readable_byte_stream_controller_error(\n                        objects_2,\n                        r.clone(),\n                    )?;\n\n                    // If canceled1 is false or canceled2 is false, resolve cancelPromise with undefined.\n                    if reason_1.get().is_none() || reason_2.get().is_none() {\n                        cancel_promise.resolve_undefined()?;\n                    }\n                    Ok(())\n                },\n                Ok(()) => Ok(()),\n            },\n        )?;\n        Ok(())\n    }\n\n    // Let pullWithDefaultReader be the following steps:\n    #[allow(clippy::too_many_arguments)]\n    fn readable_byte_stream_pull_with_default_reader(\n        ctx: Ctx<'js>,\n        mut objects: ReadableByteStreamObjects<'js, UndefinedReader>,\n        reader: Rc<RefCell<ReadableStreamReaderClass<'js>>>,\n        reading: Rc<AtomicBool>,\n        read_again_for_branch_1: Rc<AtomicBool>,\n        read_again_for_branch_2: Rc<AtomicBool>,\n        reason_1: Rc<OnceCell<Value<'js>>>,\n        reason_2: Rc<OnceCell<Value<'js>>>,\n        objects_1: ReadableByteStreamObjects<'js, UndefinedReader>,\n        objects_2: ReadableByteStreamObjects<'js, UndefinedReader>,\n        cancel_promise: ResolveablePromise<'js>,\n    ) -> Result<ReadableByteStreamObjects<'js, UndefinedReader>> {\n        let objects_class_1 = objects_1.into_inner();\n        let objects_class_2 = objects_2.into_inner();\n\n        // If reader implements ReadableStreamBYOBReader,\n        let current_reader = reader.borrow().clone();\n        let current_reader = match current_reader {\n            ReadableStreamReaderClass::ReadableStreamBYOBReader(r) => {\n                let byob_reader = OwnedBorrowMut::from_class(r.clone());\n\n                // Perform ! ReadableStreamBYOBReaderRelease(reader).\n                objects = ReadableStreamBYOBReader::readable_stream_byob_reader_release(\n                    objects.set_reader(byob_reader),\n                )?\n                .clear_reader();\n                // Set reader to ! AcquireReadableStreamDefaultReader(stream).\n                let (s, new_reader) =\n                    ReadableStreamReaderClass::acquire_readable_stream_default_reader(\n                        ctx.clone(),\n                        objects.stream,\n                    )?;\n                objects.stream = s;\n                reader.replace(new_reader.clone().into());\n\n                // Perform forwardReaderError, given reader.\n                Self::readable_byte_stream_forward_reader_error(\n                    ctx.clone(),\n                    reader.clone(),\n                    objects_class_1.clone(),\n                    objects_class_2.clone(),\n                    reason_1.clone(),\n                    reason_2.clone(),\n                    new_reader.clone().into(),\n                    cancel_promise.clone(),\n                )?;\n                new_reader\n            },\n            ReadableStreamReaderClass::ReadableStreamDefaultReader(r) => r,\n        };\n\n        // Let readRequest be a read request with the following items:\n        #[derive(Clone)]\n        struct ReadRequest<'js> {\n            reader: Rc<RefCell<ReadableStreamReaderClass<'js>>>,\n            reading: Rc<AtomicBool>,\n            read_again_for_branch_1: Rc<AtomicBool>,\n            read_again_for_branch_2: Rc<AtomicBool>,\n            reason_1: Rc<OnceCell<Value<'js>>>,\n            reason_2: Rc<OnceCell<Value<'js>>>,\n            objects_class_1: ReadableStreamClassObjects<\n                'js,\n                ReadableByteStreamControllerOwned<'js>,\n                UndefinedReader,\n            >,\n            objects_class_2: ReadableStreamClassObjects<\n                'js,\n                ReadableByteStreamControllerOwned<'js>,\n                UndefinedReader,\n            >,\n            cancel_promise: ResolveablePromise<'js>,\n        }\n\n        impl<'js> Trace<'js> for ReadRequest<'js> {\n            fn trace<'a>(&self, tracer: rquickjs::class::Tracer<'a, 'js>) {\n                if let Ok(r) = self.reader.try_borrow() {\n                    r.trace(tracer)\n                }\n                if let Some(r) = self.reason_1.get() {\n                    r.trace(tracer)\n                }\n                if let Some(r) = self.reason_2.get() {\n                    r.trace(tracer)\n                }\n                self.objects_class_1.trace(tracer);\n                self.objects_class_2.trace(tracer);\n                self.cancel_promise.trace(tracer);\n            }\n        }\n\n        impl<'js> ReadableStreamReadRequest<'js> for ReadRequest<'js> {\n            fn chunk_steps(\n                &self,\n                objects: ReadableStreamDefaultReaderObjects<'js>,\n                chunk: Value<'js>,\n            ) -> Result<ReadableStreamDefaultReaderObjects<'js>> {\n                let ctx = chunk.ctx().clone();\n                let this = self.clone();\n\n                objects.with_assert_byte_controller(|objects| {\n                    let constructor_uint8array = objects.controller.array_constructor_primordials.constructor_uint8array.clone();\n                    let function_array_buffer_is_view = objects.controller.function_array_buffer_is_view.clone();\n                    let chunk = ViewBytes::from_value(&ctx, &function_array_buffer_is_view, Some(&chunk))?;\n                    let objects_class = objects.into_inner();\n                    // Queue a microtask to perform the following steps:\n                    let f = {\n                        let ctx = ctx.clone();\n                        let objects_class = objects_class.clone();\n                        move || -> Result<()> {\n                            // Set readAgainForBranch1 to false.\n                            this.read_again_for_branch_1.store(false, Ordering::Release);\n                            // Set readAgainForBranch2 to false.\n                            this.read_again_for_branch_2.store(false, Ordering::Release);\n\n                            // Let chunk1 and chunk2 be chunk.\n                            let chunk_1 = chunk.clone();\n                            let mut chunk_2 = chunk.clone();\n\n                            // If canceled1 is false and canceled2 is false,\n                            if this.reason_1.get().is_none() && this.reason_2.get().is_none() {\n                                // Let cloneResult be CloneAsUint8Array(chunk).\n                                match clone_as_uint8_array(ctx.clone(), &constructor_uint8array, &function_array_buffer_is_view, chunk) {\n                                    // If cloneResult is an abrupt completion,\n                                    Err(Error::Exception) => {\n                                        let err = ctx.catch();\n\n                                        let objects_1 =\n                                            ReadableStreamObjects::from_class(this.objects_class_1);\n\n                                        // Perform ! ReadableByteStreamControllerError(branch1.[[controller]], cloneResult.[[Value]]).\n                                        ReadableByteStreamController::readable_byte_stream_controller_error(\n                                                objects_1,\n                                                err.clone(),\n                                            )?;\n\n                                        let objects_2 =\n                                            ReadableStreamObjects::from_class(this.objects_class_2);\n\n                                        // Perform ! ReadableByteStreamControllerError(branch2.[[controller]], cloneResult.[[Value]]).\n                                        ReadableByteStreamController::readable_byte_stream_controller_error(\n                                                objects_2,\n                                                err.clone(),\n                                            )?;\n\n                                        // Resolve cancelPromise with ! ReadableStreamCancel(stream, cloneResult.[[Value]]).\n                                        let (promise, _) = ReadableStream::readable_stream_cancel(\n                                            ctx,\n                                            ReadableStreamObjects::from_class(objects_class),\n                                            err.clone(),\n                                        )?;\n                                        this.cancel_promise.resolve(promise)?;\n\n                                        // Return.\n                                        return Ok(());\n                                    },\n                                    // Otherwise, set chunk2 to cloneResult.[[Value]].\n                                    Ok(clone_result) => chunk_2 = clone_result,\n                                    Err(err) => return Err(err),\n                                };\n                            }\n\n                            // If canceled1 is false, perform ! ReadableByteStreamControllerEnqueue(branch1.[[controller]], chunk1).\n                            if this.reason_1.get().is_none() {\n                                let objects_1 = ReadableStreamObjects::from_class_no_reader(\n                                    this.objects_class_1.clone(),\n                                ).refresh_reader();\n                                ReadableByteStreamController::readable_byte_stream_controller_enqueue(\n                                    &ctx, objects_1, chunk_1,\n                                )?;\n                            }\n\n                            // If canceled2 is false, perform ! ReadableByteStreamControllerEnqueue(branch2.[[controller]], chunk2).\n                            if this.reason_2.get().is_none() {\n                                let objects_2 = ReadableStreamObjects::from_class_no_reader(\n                                    this.objects_class_2.clone(),\n                                ).refresh_reader();\n                                ReadableByteStreamController::readable_byte_stream_controller_enqueue(\n                                    &ctx, objects_2, chunk_2,\n                                )?;\n                            }\n\n                            // Set reading to false.\n                            this.reading.store(false, Ordering::Release);\n\n                            let objects_1 = ReadableStreamObjects::from_class(this.objects_class_1);\n                            let objects_2 = ReadableStreamObjects::from_class(this.objects_class_2);\n\n                            let objects = ReadableStreamObjects::from_class_no_reader(objects_class);\n\n                            // If readAgainForBranch1 is true, perform pull1Algorithm.\n                            if this.read_again_for_branch_1.load(Ordering::Acquire) {\n                                ReadableStream::readable_byte_stream_pull_1_algorithm(\n                                    ctx.clone(),\n                                    objects,\n                                    this.reader,\n                                    this.reading,\n                                    this.read_again_for_branch_1,\n                                    this.read_again_for_branch_2,\n                                    this.reason_1,\n                                    this.reason_2,\n                                    objects_1,\n                                    objects_2,\n                                    this.cancel_promise,\n                                )?;\n                            } else if this.read_again_for_branch_2.load(Ordering::Acquire) {\n                                // Otherwise, if readAgainForBranch2 is true, perform pull2Algorithm.\n                                ReadableStream::readable_byte_stream_pull_2_algorithm(\n                                    ctx.clone(),\n                                    objects,\n                                    this.reader,\n                                    this.reading,\n                                    this.read_again_for_branch_1,\n                                    this.read_again_for_branch_2,\n                                    this.reason_1,\n                                    this.reason_2,\n                                    objects_1,\n                                    objects_2,\n                                    this.cancel_promise,\n                                )?;\n                            }\n\n                            Ok(())\n                        }\n                    };\n\n                    let () = Function::new(ctx, OnceFn::new(f))?.defer(())?;\n\n                    let objects = ReadableStreamObjects::from_class(objects_class);\n\n                    Ok(objects)\n                })\n            }\n\n            fn close_steps(\n                &self,\n                ctx: &Ctx<'js>,\n                objects: ReadableStreamDefaultReaderObjects<'js>,\n            ) -> Result<ReadableStreamDefaultReaderObjects<'js>> {\n                // Set reading to false.\n                self.reading.store(false, Ordering::Release);\n\n                let mut objects_1 =\n                    ReadableStreamObjects::from_class_no_reader(self.objects_class_1.clone())\n                        .refresh_reader();\n\n                let mut objects_2 =\n                    ReadableStreamObjects::from_class_no_reader(self.objects_class_2.clone())\n                        .refresh_reader();\n\n                // If canceled1 is false, perform ! ReadableByteStreamControllerClose(branch1.[[controller]]).\n                if self.reason_1.get().is_none() {\n                    objects_1 =\n                        ReadableByteStreamController::readable_byte_stream_controller_close(\n                            ctx.clone(),\n                            objects_1,\n                        )?;\n                }\n                // If canceled2 is false, perform ! ReadableByteStreamControllerClose(branch2.[[controller]]).\n                if self.reason_2.get().is_none() {\n                    objects_2 =\n                        ReadableByteStreamController::readable_byte_stream_controller_close(\n                            ctx.clone(),\n                            objects_2,\n                        )?;\n                }\n                // If branch1.[[controller]].[[pendingPullIntos]] is not empty, perform ! ReadableByteStreamControllerRespond(branch1.[[controller]], 0).\n                if !objects_1.controller.pending_pull_intos.is_empty() {\n                    ReadableByteStreamController::readable_byte_stream_controller_respond(\n                        ctx.clone(),\n                        objects_1,\n                        0,\n                    )?\n                }\n\n                // If branch2.[[controller]].[[pendingPullIntos]] is not empty, perform ! ReadableByteStreamControllerRespond(branch2.[[controller]], 0).\n                if !objects_2.controller.pending_pull_intos.is_empty() {\n                    ReadableByteStreamController::readable_byte_stream_controller_respond(\n                        ctx.clone(),\n                        objects_2,\n                        0,\n                    )?\n                }\n\n                // If canceled1 is false or canceled2 is false, resolve cancelPromise with undefined.\n                if self.reason_1.get().is_none() || self.reason_2.get().is_none() {\n                    self.cancel_promise.resolve_undefined()?\n                }\n                Ok(objects)\n            }\n\n            fn error_steps(\n                &self,\n                objects: ReadableStreamDefaultReaderObjects<'js>,\n                _: Value<'js>,\n            ) -> Result<ReadableStreamDefaultReaderObjects<'js>> {\n                // Set reading to false.\n                self.reading.store(false, Ordering::Release);\n                Ok(objects)\n            }\n        }\n\n        // Perform ! ReadableStreamDefaultReaderRead(reader, readRequest).\n        Ok(\n            ReadableStreamDefaultReader::readable_stream_default_reader_read(\n                &ctx,\n                objects.set_reader(OwnedBorrowMut::from_class(current_reader)),\n                ReadRequest {\n                    reader,\n                    reading,\n                    read_again_for_branch_1,\n                    read_again_for_branch_2,\n                    reason_1,\n                    reason_2,\n                    objects_class_1,\n                    objects_class_2,\n                    cancel_promise,\n                },\n            )?\n            .clear_reader(),\n        )\n    }\n\n    #[allow(clippy::too_many_arguments)]\n    fn readable_byte_stream_pull_with_byob_reader(\n        ctx: Ctx<'js>,\n        mut objects: ReadableByteStreamObjects<'js, UndefinedReader>,\n        reader: Rc<RefCell<ReadableStreamReaderClass<'js>>>,\n        reading: Rc<AtomicBool>,\n        read_again_for_branch_1: Rc<AtomicBool>,\n        read_again_for_branch_2: Rc<AtomicBool>,\n        reason_1: Rc<OnceCell<Value<'js>>>,\n        reason_2: Rc<OnceCell<Value<'js>>>,\n        objects_1: ReadableByteStreamObjects<'js, UndefinedReader>,\n        objects_2: ReadableByteStreamObjects<'js, UndefinedReader>,\n        cancel_promise: ResolveablePromise<'js>,\n        view: ViewBytes<'js>,\n        for_branch_2: bool,\n    ) -> Result<ReadableByteStreamObjects<'js, UndefinedReader>> {\n        let objects_1 = objects_1.into_inner();\n        let objects_2 = objects_2.into_inner();\n\n        // If reader implements ReadableStreamDefaultReader,\n        let current_reader = reader.borrow().clone();\n        let current_reader = match current_reader {\n            ReadableStreamReaderClass::ReadableStreamDefaultReader(r) => {\n                let default_reader = OwnedBorrowMut::from_class(r.clone());\n\n                // Perform ! ReadableStreamDefaultReaderRelease(reader).\n                objects = ReadableStreamDefaultReader::readable_stream_default_reader_release(\n                    objects.set_reader(default_reader),\n                )?\n                .clear_reader();\n\n                // Set reader to ! AcquireReadableStreamBYOBReader(stream).\n                let (s, new_reader) =\n                    ReadableStreamReaderClass::acquire_readable_stream_byob_reader(\n                        ctx.clone(),\n                        objects.stream,\n                    )?;\n                objects.stream = s;\n                reader.replace(new_reader.clone().into());\n\n                // Perform forwardReaderError, given reader.\n                Self::readable_byte_stream_forward_reader_error(\n                    ctx.clone(),\n                    reader.clone(),\n                    objects_1.clone(),\n                    objects_2.clone(),\n                    reason_1.clone(),\n                    reason_2.clone(),\n                    new_reader.clone().into(),\n                    cancel_promise.clone(),\n                )?;\n\n                new_reader\n            },\n            ReadableStreamReaderClass::ReadableStreamBYOBReader(r) => r.clone(),\n        };\n\n        // Let byobBranch be branch2 if forBranch2 is true, and branch1 otherwise.\n        // Let otherBranch be branch2 if forBranch2 is false, and branch1 otherwise.\n        let (byob_objects, other_objects) = if for_branch_2 {\n            (objects_2.clone(), objects_1.clone())\n        } else {\n            (objects_1.clone(), objects_2.clone())\n        };\n\n        // Let readIntoRequest be a read-into request with the following items:\n        #[derive(Clone)]\n        struct ReadIntoRequest<'js> {\n            reader: Rc<RefCell<ReadableStreamReaderClass<'js>>>,\n            reading: Rc<AtomicBool>,\n            read_again_for_branch_1: Rc<AtomicBool>,\n            read_again_for_branch_2: Rc<AtomicBool>,\n            reason_1: Rc<OnceCell<Value<'js>>>,\n            reason_2: Rc<OnceCell<Value<'js>>>,\n            objects_1: ReadableStreamClassObjects<\n                'js,\n                ReadableByteStreamControllerOwned<'js>,\n                UndefinedReader,\n            >,\n            objects_2: ReadableStreamClassObjects<\n                'js,\n                ReadableByteStreamControllerOwned<'js>,\n                UndefinedReader,\n            >,\n            byob_objects: ReadableStreamClassObjects<\n                'js,\n                ReadableByteStreamControllerOwned<'js>,\n                UndefinedReader,\n            >,\n            other_objects: ReadableStreamClassObjects<\n                'js,\n                ReadableByteStreamControllerOwned<'js>,\n                UndefinedReader,\n            >,\n            cancel_promise: ResolveablePromise<'js>,\n            for_branch_2: bool,\n        }\n\n        impl<'js> Trace<'js> for ReadIntoRequest<'js> {\n            fn trace<'a>(&self, tracer: rquickjs::class::Tracer<'a, 'js>) {\n                if let Ok(r) = self.reader.try_borrow() {\n                    r.trace(tracer)\n                }\n                if let Some(r) = self.reason_1.get() {\n                    r.trace(tracer)\n                }\n                if let Some(r) = self.reason_2.get() {\n                    r.trace(tracer)\n                }\n                self.objects_1.trace(tracer);\n                self.objects_2.trace(tracer);\n                self.byob_objects.trace(tracer);\n                self.other_objects.trace(tracer);\n                self.cancel_promise.trace(tracer);\n            }\n        }\n\n        impl<'js> ReadableStreamReadIntoRequest<'js> for ReadIntoRequest<'js> {\n            fn chunk_steps(\n                &self,\n                objects: ReadableStreamBYOBObjects<'js>,\n                chunk: Value<'js>,\n            ) -> Result<ReadableStreamBYOBObjects<'js>> {\n                let ctx = chunk.ctx().clone();\n\n                let constructor_uint8array = objects\n                    .controller\n                    .array_constructor_primordials\n                    .constructor_uint8array\n                    .clone();\n                let function_array_buffer_is_view =\n                    objects.controller.function_array_buffer_is_view.clone();\n                let chunk =\n                    ViewBytes::from_value(&ctx, &function_array_buffer_is_view, Some(&chunk))?;\n\n                let objects_class = objects.into_inner();\n\n                // Queue a microtask to perform the following steps:\n                let f = {\n                    let ctx = ctx.clone();\n                    let objects_class = objects_class.clone();\n                    let this = self.clone();\n                    move || -> Result<()> {\n                        // Set readAgainForBranch1 to false.\n                        this.read_again_for_branch_1.store(false, Ordering::Release);\n                        // Set readAgainForBranch2 to false.\n                        this.read_again_for_branch_2.store(false, Ordering::Release);\n\n                        // Let byobCanceled be canceled2 if forBranch2 is true, and canceled1 otherwise.\n                        // Let otherCanceled be canceled2 if forBranch2 is false, and canceled1 otherwise.\n                        let (byob_canceled, other_canceled) = if this.for_branch_2 {\n                            (this.reason_2.get().is_some(), this.reason_1.get().is_some())\n                        } else {\n                            (this.reason_1.get().is_some(), this.reason_2.get().is_some())\n                        };\n\n                        // If otherCanceled is false,\n                        if !other_canceled {\n                            // Let cloneResult be CloneAsUint8Array(chunk).\n                            match clone_as_uint8_array(\n                                ctx.clone(),\n                                &constructor_uint8array,\n                                &function_array_buffer_is_view,\n                                chunk.clone(),\n                            ) {\n                                // If cloneResult is an abrupt completion,\n                                Err(Error::Exception) => {\n                                    let err = ctx.catch();\n\n                                    let byob_objects = ReadableStreamObjects::from_class_no_reader(\n                                        this.byob_objects.clone(),\n                                    )\n                                    .refresh_reader();\n\n                                    // Perform ! ReadableByteStreamControllerError(byobBranch.[[controller]], cloneResult.[[Value]]).\n                                    ReadableByteStreamController::readable_byte_stream_controller_error(\n                                        byob_objects,\n                                        err.clone(),\n                                    )?;\n\n                                    let other_objects =\n                                        ReadableStreamObjects::from_class_no_reader(\n                                            this.other_objects.clone(),\n                                        )\n                                        .refresh_reader();\n\n                                    // Perform ! ReadableByteStreamControllerError(otherBranch.[[controller]], cloneResult.[[Value]]).\n                                    ReadableByteStreamController::readable_byte_stream_controller_error(\n                                        other_objects,\n                                        err.clone(),\n                                    )?;\n\n                                    // Resolve cancelPromise with ! ReadableStreamCancel(stream, cloneResult.[[Value]]).\n                                    let (promise, _) = ReadableStream::readable_stream_cancel(\n                                        ctx,\n                                        ReadableStreamObjects::from_class(objects_class),\n                                        err.clone(),\n                                    )?;\n                                    this.cancel_promise.resolve(promise)?;\n\n                                    // Return.\n                                    return Ok(());\n                                },\n                                // Otherwise, let clonedChunk be cloneResult.[[Value]].\n                                Ok(cloned_chunk) => {\n                                    // If byobCanceled is false, perform ! ReadableByteStreamControllerRespondWithNewView(byobBranch.[[controller]], chunk).\n                                    if !byob_canceled {\n                                        let byob_objects =\n                                            ReadableStreamObjects::from_class_no_reader(\n                                                this.byob_objects.clone(),\n                                            )\n                                            .refresh_reader();\n\n                                        ReadableByteStreamController::readable_byte_stream_controller_respond_with_new_view(ctx.clone(), byob_objects, chunk)?;\n                                    }\n\n                                    let other_objects =\n                                        ReadableStreamObjects::from_class_no_reader(\n                                            this.other_objects.clone(),\n                                        )\n                                        .refresh_reader();\n\n                                    // Perform ! ReadableByteStreamControllerEnqueue(otherBranch.[[controller]], clonedChunk).\n                                    ReadableByteStreamController::readable_byte_stream_controller_enqueue(&ctx, other_objects, cloned_chunk)?;\n                                },\n                                Err(err) => return Err(err),\n                            };\n                        } else if !byob_canceled {\n                            let byob_objects = ReadableStreamObjects::from_class_no_reader(\n                                this.byob_objects.clone(),\n                            )\n                            .refresh_reader();\n\n                            // Otherwise, if byobCanceled is false, perform ! ReadableByteStreamControllerRespondWithNewView(byobBranch.[[controller]], chunk).\n                            ReadableByteStreamController::readable_byte_stream_controller_respond_with_new_view(ctx.clone(), byob_objects, chunk)?;\n                        }\n\n                        let objects_1 = ReadableStreamObjects::from_class(this.objects_1.clone());\n                        let objects_2 = ReadableStreamObjects::from_class(this.objects_2.clone());\n\n                        // Set reading to false.\n                        this.reading.store(false, Ordering::Release);\n\n                        // If readAgainForBranch1 is true, perform pull1Algorithm.\n                        if this.read_again_for_branch_1.load(Ordering::Acquire) {\n                            ReadableStream::readable_byte_stream_pull_1_algorithm(\n                                ctx.clone(),\n                                ReadableStreamObjects::from_class(objects_class).clear_reader(),\n                                this.reader.clone(),\n                                this.reading.clone(),\n                                this.read_again_for_branch_1.clone(),\n                                this.read_again_for_branch_2.clone(),\n                                this.reason_1.clone(),\n                                this.reason_2.clone(),\n                                objects_1,\n                                objects_2,\n                                this.cancel_promise.clone(),\n                            )?;\n                        } else if this.read_again_for_branch_2.load(Ordering::Acquire) {\n                            // Otherwise, if readAgainForBranch2 is true, perform pull2Algorithm.\n                            ReadableStream::readable_byte_stream_pull_2_algorithm(\n                                ctx.clone(),\n                                ReadableStreamObjects::from_class(objects_class).clear_reader(),\n                                this.reader.clone(),\n                                this.reading.clone(),\n                                this.read_again_for_branch_1.clone(),\n                                this.read_again_for_branch_2.clone(),\n                                this.reason_1.clone(),\n                                this.reason_2.clone(),\n                                objects_1,\n                                objects_2,\n                                this.cancel_promise.clone(),\n                            )?;\n                        }\n\n                        Ok(())\n                    }\n                };\n\n                let () = Function::new(ctx, OnceFn::new(f))?.defer(())?;\n\n                let objects = ReadableStreamObjects::from_class(objects_class);\n\n                Ok(objects)\n            }\n\n            fn close_steps(\n                &self,\n                objects: ReadableStreamBYOBObjects<'js>,\n                chunk: Value<'js>,\n            ) -> Result<ReadableStreamBYOBObjects<'js>> {\n                let ctx = chunk.ctx().clone();\n\n                // Set reading to false.\n                self.reading.store(false, Ordering::Release);\n\n                // Let byobCanceled be canceled2 if forBranch2 is true, and canceled1 otherwise.\n                // Let otherCanceled be canceled2 if forBranch2 is false, and canceled1 otherwise.\n                let (byob_canceled, other_canceled) = if self.for_branch_2 {\n                    (self.reason_2.get().is_some(), self.reason_1.get().is_some())\n                } else {\n                    (self.reason_1.get().is_some(), self.reason_2.get().is_some())\n                };\n\n                // If byobCanceled is false, perform ! ReadableByteStreamControllerClose(byobBranch.[[controller]]).\n                if !byob_canceled {\n                    let byob_objects =\n                        ReadableStreamObjects::from_class_no_reader(self.byob_objects.clone())\n                            .refresh_reader();\n\n                    ReadableByteStreamController::readable_byte_stream_controller_close(\n                        ctx.clone(),\n                        byob_objects,\n                    )?;\n                }\n                // If otherCanceled is false, perform ! ReadableByteStreamControllerClose(otherBranch.[[controller]]).\n                if !other_canceled {\n                    let other_objects =\n                        ReadableStreamObjects::from_class_no_reader(self.other_objects.clone())\n                            .refresh_reader();\n\n                    ReadableByteStreamController::readable_byte_stream_controller_close(\n                        ctx.clone(),\n                        other_objects,\n                    )?;\n                }\n\n                // If chunk is not undefined,\n                if !chunk.is_undefined() {\n                    let chunk = ViewBytes::from_value(\n                        &ctx,\n                        &objects.controller.function_array_buffer_is_view,\n                        Some(&chunk),\n                    )?;\n\n                    // If byobCanceled is false, perform ! ReadableByteStreamControllerRespondWithNewView(byobBranch.[[controller]], chunk).\n                    if !byob_canceled {\n                        let byob_objects =\n                            ReadableStreamObjects::from_class_no_reader(self.byob_objects.clone())\n                                .refresh_reader();\n\n                        ReadableByteStreamController::readable_byte_stream_controller_respond_with_new_view(ctx.clone(), byob_objects, chunk)?;\n                    }\n\n                    let other_objects =\n                        ReadableStreamObjects::from_class_no_reader(self.other_objects.clone())\n                            .refresh_reader();\n\n                    // If otherCanceled is false and otherBranch.[[controller]].[[pendingPullIntos]] is not empty, perform ! ReadableByteStreamControllerRespond(otherBranch.[[controller]], 0).\n                    if !other_canceled && !other_objects.controller.pending_pull_intos.is_empty() {\n                        ReadableByteStreamController::readable_byte_stream_controller_respond(\n                            ctx.clone(),\n                            other_objects,\n                            0,\n                        )?;\n                    }\n                }\n\n                // If byobCanceled is false or otherCanceled is false, resolve cancelPromise with undefined.\n                if !byob_canceled || !other_canceled {\n                    self.cancel_promise.resolve_undefined()?\n                }\n\n                Ok(objects)\n            }\n\n            fn error_steps(\n                &self,\n                objects: ReadableStreamBYOBObjects<'js>,\n                _: Value<'js>,\n            ) -> Result<ReadableStreamBYOBObjects<'js>> {\n                // Set reading to false.\n                self.reading.store(false, Ordering::Release);\n                Ok(objects)\n            }\n        }\n\n        // Perform ! ReadableStreamBYOBReaderRead(reader, view, 1, readIntoRequest).\n        Ok(ReadableStreamBYOBReader::readable_stream_byob_reader_read(\n            &ctx,\n            objects.set_reader(OwnedBorrowMut::from_class(current_reader)),\n            view,\n            1,\n            ReadIntoRequest {\n                reader,\n                reading,\n                read_again_for_branch_1,\n                read_again_for_branch_2,\n                reason_1,\n                reason_2,\n                objects_1,\n                objects_2,\n                byob_objects,\n                other_objects,\n                cancel_promise,\n                for_branch_2,\n            },\n        )?\n        .clear_reader())\n    }\n\n    // Let pull1Algorithm be the following steps:\n    #[allow(clippy::too_many_arguments)]\n    fn readable_byte_stream_pull_1_algorithm(\n        ctx: Ctx<'js>,\n        mut objects: ReadableByteStreamObjects<'js, UndefinedReader>,\n        reader: Rc<RefCell<ReadableStreamReaderClass<'js>>>,\n        reading: Rc<AtomicBool>,\n        read_again_for_branch_1: Rc<AtomicBool>,\n        read_again_for_branch_2: Rc<AtomicBool>,\n        reason_1: Rc<OnceCell<Value<'js>>>,\n        reason_2: Rc<OnceCell<Value<'js>>>,\n        mut objects_1: ReadableByteStreamObjects<'js, UndefinedReader>,\n        objects_2: ReadableByteStreamObjects<'js, UndefinedReader>,\n        cancel_promise: ResolveablePromise<'js>,\n    ) -> Result<Promise<'js>> {\n        // If reading is true,\n        if reading.swap(true, Ordering::AcqRel) {\n            // Set readAgainForBranch1 to true.\n            read_again_for_branch_1.store(true, Ordering::Release);\n            // Return a promise resolved with undefined.\n            return Ok(objects\n                .stream\n                .promise_primordials\n                .promise_resolved_with_undefined\n                .clone());\n        }\n        // Set reading to true.\n\n        // Let byobRequest be ! ReadableByteStreamControllerGetBYOBRequest(branch1.[[controller]]).\n        let (byob_request, branch_1_controller) =\n            ReadableByteStreamController::readable_byte_stream_controller_get_byob_request(\n                ctx.clone(),\n                objects_1.controller,\n            )?;\n        objects_1.controller = branch_1_controller;\n\n        // If byobRequest is null, perform pullWithDefaultReader.\n        objects = match byob_request.0 {\n            None => Self::readable_byte_stream_pull_with_default_reader(\n                ctx.clone(),\n                objects,\n                reader.clone(),\n                reading.clone(),\n                read_again_for_branch_1,\n                read_again_for_branch_2,\n                reason_1,\n                reason_2,\n                objects_1,\n                objects_2,\n                cancel_promise.clone(),\n            )?,\n            // Otherwise, perform pullWithBYOBReader, given byobRequest.[[view]] and false.\n            Some(byob_request) => {\n                let view = byob_request.borrow().view.clone().expect(\n                    \"ReadableByteStream tee pull1Algorithm called with invalidated byobRequest\",\n                );\n                Self::readable_byte_stream_pull_with_byob_reader(\n                    ctx.clone(),\n                    objects,\n                    reader.clone(),\n                    reading.clone(),\n                    read_again_for_branch_1,\n                    read_again_for_branch_2,\n                    reason_1,\n                    reason_2,\n                    objects_1,\n                    objects_2,\n                    cancel_promise.clone(),\n                    view,\n                    false,\n                )?\n            },\n        };\n\n        // Return a promise resolved with undefined.\n        Ok(objects\n            .stream\n            .promise_primordials\n            .promise_resolved_with_undefined\n            .clone())\n    }\n\n    // Let pull2Algorithm be the following steps:\n    #[allow(clippy::too_many_arguments)]\n    fn readable_byte_stream_pull_2_algorithm(\n        ctx: Ctx<'js>,\n        mut objects: ReadableByteStreamObjects<'js, UndefinedReader>,\n        reader: Rc<RefCell<ReadableStreamReaderClass<'js>>>,\n        reading: Rc<AtomicBool>,\n        read_again_for_branch_1: Rc<AtomicBool>,\n        read_again_for_branch_2: Rc<AtomicBool>,\n        reason_1: Rc<OnceCell<Value<'js>>>,\n        reason_2: Rc<OnceCell<Value<'js>>>,\n        objects_1: ReadableByteStreamObjects<'js, UndefinedReader>,\n        mut objects_2: ReadableByteStreamObjects<'js, UndefinedReader>,\n        cancel_promise: ResolveablePromise<'js>,\n    ) -> Result<Promise<'js>> {\n        // If reading is true,\n        if reading.swap(true, Ordering::AcqRel) {\n            // Set readAgainForBranch2 to true.\n            read_again_for_branch_2.store(true, Ordering::Release);\n            // Return a promise resolved with undefined.\n            return Ok(objects\n                .stream\n                .promise_primordials\n                .promise_resolved_with_undefined\n                .clone());\n        }\n        // Set reading to true.\n\n        // Let byobRequest be ! ReadableByteStreamControllerGetBYOBRequest(branch2.[[controller]]).\n        let (byob_request, branch_2_controller) =\n            ReadableByteStreamController::readable_byte_stream_controller_get_byob_request(\n                ctx.clone(),\n                objects_2.controller,\n            )?;\n        objects_2.controller = branch_2_controller;\n\n        // If byobRequest is null, perform pullWithDefaultReader.\n        objects = match byob_request.0 {\n            None => Self::readable_byte_stream_pull_with_default_reader(\n                ctx.clone(),\n                objects,\n                reader.clone(),\n                reading.clone(),\n                read_again_for_branch_1,\n                read_again_for_branch_2,\n                reason_1,\n                reason_2,\n                objects_1,\n                objects_2,\n                cancel_promise,\n            )?,\n            // Otherwise, perform pullWithBYOBReader, given byobRequest.[[view]] and true.\n            Some(byob_request) => Self::readable_byte_stream_pull_with_byob_reader(\n                ctx.clone(),\n                objects,\n                reader.clone(),\n                reading.clone(),\n                read_again_for_branch_1,\n                read_again_for_branch_2,\n                reason_1,\n                reason_2,\n                objects_1,\n                objects_2,\n                cancel_promise,\n                byob_request.borrow().view.clone().expect(\n                    \"ReadableByteStream tee pull2Algorithm called with invalidated byobRequest\",\n                ),\n                true,\n            )?,\n        };\n\n        // Return a promise resolved with undefined.\n        Ok(objects\n            .stream\n            .promise_primordials\n            .promise_resolved_with_undefined\n            .clone())\n    }\n}\n\nfn clone_as_uint8_array<'js>(\n    ctx: Ctx<'js>,\n    constructor_uint8array: &Constructor<'js>,\n    function_array_buffer_is_view: &Function<'js>,\n    chunk: ViewBytes<'js>,\n) -> Result<ViewBytes<'js>> {\n    let (buffer, byte_length, byte_offset) = chunk.get_array_buffer()?;\n\n    // Let buffer be ? CloneArrayBuffer(O.[[ViewedArrayBuffer]], O.[[ByteOffset]], O.[[ByteLength]], %ArrayBuffer%).\n    let buffer = ArrayBuffer::new_copy(\n        ctx.clone(),\n        &buffer\n            .as_bytes()\n            .expect(\"CloneAsUInt8Array called on detached buffer\")\n            [byte_offset..byte_offset + byte_length],\n    )?;\n\n    // Let array be ! Construct(%Uint8Array%, « buffer »).\n    // Return array.\n    ViewBytes::from_value(\n        &ctx,\n        function_array_buffer_is_view,\n        Some(&constructor_uint8array.construct((buffer,))?),\n    )\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/readable_writable_pair.rs",
    "content": "use rquickjs::{Ctx, Error, FromJs, Result, Value};\n\nuse crate::{readable::ReadableStreamClass, writable::WritableStreamClass};\n\n/// An object containing a pair of linked streams, one readable and one writable\n/// https://streams.spec.whatwg.org/#dictdef-readablewritablepair\npub struct ReadableWritablePair<'js> {\n    pub readable: ReadableStreamClass<'js>,\n    pub writable: WritableStreamClass<'js>,\n}\n\nimpl<'js> FromJs<'js> for ReadableWritablePair<'js> {\n    fn from_js(_ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {\n        let ty_name = value.type_name();\n        let obj = value\n            .as_object()\n            .ok_or(Error::new_from_js(ty_name, \"Object\"))?;\n\n        let readable = obj.get::<_, ReadableStreamClass<'js>>(\"readable\")?;\n        let writable = obj.get::<_, WritableStreamClass<'js>>(\"writable\")?;\n\n        Ok(Self { readable, writable })\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/utils/mod.rs",
    "content": "use llrt_utils::option::Undefined;\nuse rquickjs::{\n    class::{JsClass, OwnedBorrowMut},\n    Class, Ctx, FromJs, IntoAtom, Object, Result, Value,\n};\n\npub mod promise;\npub mod queue;\n\n// the trait used elsewhere in this repo accepts null values as 'None', which causes many web platform tests to fail as they\n// like to check that undefined is accepted and null isn't.\npub trait ValueOrUndefined<'js> {\n    fn get_value_or_undefined<K: IntoAtom<'js> + Clone, V: FromJs<'js>>(\n        &self,\n        k: K,\n    ) -> Result<Option<V>>;\n}\n\nimpl<'js> ValueOrUndefined<'js> for Object<'js> {\n    fn get_value_or_undefined<K: IntoAtom<'js> + Clone, V: FromJs<'js> + Sized>(\n        &self,\n        k: K,\n    ) -> Result<Option<V>> {\n        let value = self.get::<K, Value<'js>>(k)?;\n        Ok(Undefined::from_js(self.ctx(), value)?.0)\n    }\n}\n\nimpl<'js> ValueOrUndefined<'js> for Value<'js> {\n    fn get_value_or_undefined<K: IntoAtom<'js> + Clone, V: FromJs<'js>>(\n        &self,\n        k: K,\n    ) -> Result<Option<V>> {\n        if let Some(obj) = self.as_object() {\n            return obj.get_value_or_undefined(k);\n        }\n        Ok(None)\n    }\n}\n\npub trait UnwrapOrUndefined<'js> {\n    fn unwrap_or_undefined(self, ctx: &Ctx<'js>) -> Value<'js>;\n}\n\nimpl<'js> UnwrapOrUndefined<'js> for Option<Value<'js>> {\n    fn unwrap_or_undefined(self, ctx: &Ctx<'js>) -> Value<'js> {\n        self.unwrap_or_else(|| Value::new_undefined(ctx.clone()))\n    }\n}\n\npub fn class_from_owned_borrow_mut<'js, T: JsClass<'js>>(\n    borrow: OwnedBorrowMut<'js, T>,\n) -> (Class<'js, T>, OwnedBorrowMut<'js, T>) {\n    let class = borrow.into_inner();\n    let borrow = OwnedBorrowMut::from_class(class.clone());\n    (class, borrow)\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/utils/promise.rs",
    "content": "use std::{cell::Cell, rc::Rc};\n\nuse llrt_utils::primordials::Primordial;\nuse rquickjs::{\n    atom::PredefinedAtom,\n    class::{Trace, Tracer},\n    function::Constructor,\n    prelude::{IntoArg, OnceFn, This},\n    promise::PromiseState,\n    Ctx, Error, FromJs, Function, IntoJs, JsLifetime, Promise, Result, Value,\n};\n\npub fn promise_rejected_with<'js>(\n    primordials: &PromisePrimordials<'js>,\n    value: Value<'js>,\n) -> Result<Promise<'js>> {\n    primordials\n        .promise_reject\n        .call((This(primordials.promise_constructor.clone()), value))\n}\n\npub fn promise_rejected_catch<'js>(\n    ctx: &Ctx<'js>,\n    promise_primordials: &PromisePrimordials<'js>,\n) -> Result<Promise<'js>> {\n    promise_rejected_with(promise_primordials, ctx.catch())\n}\n\npub fn promise_rejected_with_constructor<'js, T: From<Error>>(\n    constructor: &Constructor<'js>,\n    promise_primordials: &PromisePrimordials<'js>,\n    msg: &str,\n) -> std::result::Result<Promise<'js>, T> {\n    let e: Value = constructor.call((msg,))?;\n    Ok(promise_rejected_with(promise_primordials, e)?)\n}\n\npub fn promise_resolved_with<'js>(\n    ctx: &Ctx<'js>,\n    primordials: &PromisePrimordials<'js>,\n    value: Result<Value<'js>>,\n) -> Result<Promise<'js>> {\n    match value {\n        Ok(value) => primordials\n            .promise_resolve\n            .call((This(primordials.promise_constructor.clone()), value)),\n        Err(Error::Exception) => primordials\n            .promise_reject\n            .call((This(primordials.promise_constructor.clone()), ctx.catch())),\n        Err(err) => Err(err),\n    }\n}\n\n#[derive(JsLifetime, Clone)]\npub struct PromisePrimordials<'js> {\n    pub promise_constructor: Constructor<'js>,\n    pub promise_resolve: Function<'js>,\n    pub promise_reject: Function<'js>,\n    pub promise_all: Function<'js>,\n    pub promise_resolved_with_undefined: Promise<'js>,\n}\n\nimpl<'js> Trace<'js> for PromisePrimordials<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.promise_constructor.trace(tracer);\n        self.promise_resolve.trace(tracer);\n        self.promise_reject.trace(tracer);\n        self.promise_all.trace(tracer);\n        self.promise_resolved_with_undefined.trace(tracer);\n    }\n}\n\nimpl<'js> Primordial<'js> for PromisePrimordials<'js> {\n    fn new(ctx: &Ctx<'js>) -> Result<Self>\n    where\n        Self: Sized,\n    {\n        let promise_constructor: Constructor<'js> = ctx.globals().get(PredefinedAtom::Promise)?;\n        let promise_resolve: Function<'js> = promise_constructor.get(\"resolve\")?;\n        let promise_reject: Function<'js> = promise_constructor.get(\"reject\")?;\n        let promise_all: Function<'js> = promise_constructor.get(\"all\")?;\n\n        let promise_resolved_with_undefined = promise_resolve.call((\n            This(promise_constructor.clone()),\n            Value::new_undefined(ctx.clone()),\n        ))?;\n\n        Ok(Self {\n            promise_constructor,\n            promise_resolve,\n            promise_reject,\n            promise_all,\n            promise_resolved_with_undefined,\n        })\n    }\n}\n\n// https://webidl.spec.whatwg.org/#dfn-perform-steps-once-promise-is-settled\npub fn upon_promise<'js, Input: FromJs<'js> + 'js, Output: IntoJs<'js> + 'js>(\n    ctx: Ctx<'js>,\n    promise: Promise<'js>,\n    then: impl FnOnce(Ctx<'js>, std::result::Result<Input, Value<'js>>) -> Result<Output> + 'js,\n) -> Result<Promise<'js>> {\n    let then = Rc::new(Cell::new(Some(then)));\n    let then2 = then.clone();\n    promise.then()?.call((\n        This(promise.clone()),\n        Function::new(\n            ctx.clone(),\n            OnceFn::new(move |ctx, input| {\n                then.take()\n                    .expect(\"Promise.then should only call either resolve or reject\")(\n                    ctx,\n                    Ok(input),\n                )\n            }),\n        ),\n        Function::new(\n            ctx,\n            OnceFn::new(move |ctx, e: Value<'js>| {\n                then2\n                    .take()\n                    .expect(\"Promise.then should only call either resolve or reject\")(\n                    ctx, Err(e)\n                )\n            }),\n        ),\n    ))\n}\n\npub fn upon_promise_fulfilment<'js, Input: FromJs<'js> + 'js, Output: IntoJs<'js> + 'js>(\n    ctx: Ctx<'js>,\n    promise: Promise<'js>,\n    then: impl FnOnce(Ctx<'js>, Input) -> Result<Output> + 'js,\n) -> Result<Promise<'js>> {\n    promise.then()?.call((\n        This(promise.clone()),\n        Function::new(ctx.clone(), OnceFn::new(then)),\n    ))\n}\n\n#[derive(Debug, JsLifetime, Clone)]\npub struct ResolveablePromise<'js> {\n    pub promise: Promise<'js>,\n    resolve: Option<Function<'js>>,\n    reject: Option<Function<'js>>,\n}\n\nimpl<'js> ResolveablePromise<'js> {\n    pub fn new(ctx: &Ctx<'js>) -> Result<Self> {\n        let (promise, resolve, reject) = Promise::new(ctx)?;\n        Ok(Self {\n            promise,\n            resolve: Some(resolve),\n            reject: Some(reject),\n        })\n    }\n\n    pub fn resolved_with_undefined(primordials: &PromisePrimordials<'js>) -> Self {\n        Self {\n            promise: primordials.promise_resolved_with_undefined.clone(),\n            resolve: None,\n            reject: None,\n        }\n    }\n\n    pub fn rejected_with(primordials: &PromisePrimordials<'js>, error: Value<'js>) -> Result<Self> {\n        Ok(Self {\n            promise: promise_rejected_with(primordials, error)?,\n            resolve: None,\n            reject: None,\n        })\n    }\n\n    pub fn rejected_with_constructor(\n        primordials: &PromisePrimordials<'js>,\n        constructor: &Constructor<'js>,\n        msg: &str,\n    ) -> Result<Self> {\n        Ok(Self {\n            promise: promise_rejected_with_constructor::<rquickjs::Error>(\n                constructor,\n                primordials,\n                msg,\n            )?,\n            resolve: None,\n            reject: None,\n        })\n    }\n\n    pub fn resolve(&self, value: impl IntoArg<'js>) -> Result<()> {\n        if let Some(resolve) = &self.resolve {\n            let () = resolve.call((value,))?;\n        }\n        Ok(())\n    }\n\n    pub fn resolve_undefined(&self) -> Result<()> {\n        if let Some(resolve) = &self.resolve {\n            let () = resolve.call((rquickjs::Undefined,))?;\n        }\n        Ok(())\n    }\n\n    pub fn reject(&self, value: impl IntoArg<'js>) -> Result<()> {\n        if let Some(reject) = &self.reject {\n            let () = reject.call((value,))?;\n        }\n        Ok(())\n    }\n\n    pub fn reject_with_constructor(&self, constructor: &Constructor<'js>, msg: &str) -> Result<()> {\n        if let Some(reject) = &self.reject {\n            let e: Value = constructor.call((msg,))?;\n            let () = reject.call((e,))?;\n        }\n        Ok(())\n    }\n\n    pub fn is_pending(&self) -> bool {\n        self.promise.state() == PromiseState::Pending\n    }\n\n    pub fn set_is_handled(&self) -> Result<()> {\n        self.promise.catch()?.call((\n            This(self.promise.clone()),\n            Function::new(self.promise.ctx().clone(), || {}),\n        ))\n    }\n}\n\nimpl<'js> Trace<'js> for ResolveablePromise<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.promise.trace(tracer);\n        self.resolve.trace(tracer);\n        self.reject.trace(tracer);\n    }\n}\n\npub fn with_promise_result<'js>(\n    ctx: &Ctx<'js>,\n    f: impl FnOnce() -> Result<Promise<'js>>,\n) -> Result<Promise<'js>> {\n    match f() {\n        Ok(value) => Ok(value),\n        Err(Error::Exception) => promise_rejected_catch(ctx, &*PromisePrimordials::get(ctx)?),\n        Err(err) => Err(err),\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/utils/queue.rs",
    "content": "use std::collections::VecDeque;\n\nuse rquickjs::{class::Trace, Ctx, Exception, JsLifetime, Result, Value};\n\nuse crate::queuing_strategy::SizeValue;\n\n/// QueueWithSize is present in readable and writable streams and abstracts away certain queue operations\n/// https://streams.spec.whatwg.org/#queue-with-sizes\n#[derive(JsLifetime, Trace)]\npub struct QueueWithSizes<'js> {\n    pub queue: VecDeque<ValueWithSize<'js>>,\n    pub queue_total_size: f64,\n}\n\nimpl<'js> QueueWithSizes<'js> {\n    pub fn new() -> Self {\n        Self {\n            queue: VecDeque::new(),\n            queue_total_size: 0.0,\n        }\n    }\n\n    pub fn enqueue_value_with_size(\n        &mut self,\n        ctx: &Ctx<'js>,\n        value: Value<'js>,\n        size: SizeValue<'js>,\n    ) -> Result<()> {\n        let size = match is_non_negative_number(size) {\n            None => {\n                // If ! IsNonNegativeNumber(size) is false, throw a RangeError exception.\n                return Err(Exception::throw_range(\n                    ctx,\n                    \"Size must be a finite, non-NaN, non-negative number.\",\n                ));\n            },\n            Some(size) => size,\n        };\n\n        // If size is +∞, throw a RangeError exception.\n        if size.is_infinite() {\n            return Err(Exception::throw_range(\n                ctx,\n                \"Size must be a finite, non-NaN, non-negative number.\",\n            ));\n        };\n\n        // Append a new value-with-size with value value and size size to container.[[queue]].\n        self.queue.push_back(ValueWithSize { value, size });\n\n        // Set container.[[queueTotalSize]] to container.[[queueTotalSize]] + size.\n        self.queue_total_size += size;\n\n        Ok(())\n    }\n\n    pub fn dequeue_value(&mut self) -> Value<'js> {\n        // Let valueWithSize be container.[[queue]][0].\n        // Remove valueWithSize from container.[[queue]].\n        let value_with_size = self\n            .queue\n            .pop_front()\n            .expect(\"DequeueValue called with empty queue\");\n        // Set container.[[queueTotalSize]] to container.[[queueTotalSize]] − valueWithSize’s size.\n        self.queue_total_size -= value_with_size.size;\n        // If container.[[queueTotalSize]] < 0, set container.[[queueTotalSize]] to 0. (This can occur due to rounding errors.)\n        if self.queue_total_size < 0.0 {\n            self.queue_total_size = 0.0\n        }\n        value_with_size.value\n    }\n\n    pub fn reset_queue(&mut self) {\n        // Set container.[[queue]] to a new empty list.\n        self.queue.clear();\n        // Set container.[[queueTotalSize]] to 0.\n        self.queue_total_size = 0.0;\n    }\n}\n\n#[derive(JsLifetime, Trace, Clone)]\npub struct ValueWithSize<'js> {\n    pub value: Value<'js>,\n    size: f64,\n}\n\nfn is_non_negative_number(value: SizeValue<'_>) -> Option<f64> {\n    // If Type(v) is not Number, return false.\n    let number = value.as_number()?;\n    // If v is NaN, return false.\n    if number.is_nan() {\n        return None;\n    }\n\n    // If v < 0, return false.\n    if number < 0.0 {\n        return None;\n    }\n\n    // Return true.\n    Some(number)\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/writable/default_controller.rs",
    "content": "use llrt_abort::{AbortController, AbortSignal};\nuse llrt_utils::{\n    object::CreateSymbol,\n    option::{Null, Undefined},\n    primordials::Primordial,\n};\nuse rquickjs::{\n    class::{JsClass, OwnedBorrowMut, Trace},\n    function::Constructor,\n    methods,\n    prelude::{Opt, This},\n    Class, Ctx, Error, Exception, Function, JsLifetime, Object, Promise, Result, Symbol, Value,\n};\n\nuse crate::{\n    queuing_strategy::{SizeAlgorithm, SizeValue},\n    utils::{\n        class_from_owned_borrow_mut,\n        promise::{promise_resolved_with, upon_promise, PromisePrimordials},\n        queue::QueueWithSizes,\n        UnwrapOrUndefined,\n    },\n    writable::{\n        default_writer::WritableStreamDefaultWriterOwned,\n        objects::{WritableStreamClassObjects, WritableStreamObjects},\n        stream::{\n            sink::UnderlyingSink, WritableStream, WritableStreamClass, WritableStreamOwned,\n            WritableStreamState,\n        },\n        writer::{UndefinedWriter, WritableStreamWriter},\n    },\n};\n\n#[rquickjs::class]\n#[derive(JsLifetime, Trace)]\npub(crate) struct WritableStreamDefaultController<'js> {\n    abort_algorithm: Option<AbortAlgorithm<'js>>,\n    close_algorithm: Option<CloseAlgorithm<'js>>,\n    container: QueueWithSizes<'js>,\n    pub(super) started: bool,\n    strategy_hwm: f64,\n    strategy_size_algorithm: Option<SizeAlgorithm<'js>>,\n    pub(super) abort_controller: Class<'js, AbortController<'js>>,\n    pub(super) stream: WritableStreamClass<'js>,\n    write_algorithm: Option<WriteAlgorithm<'js>>,\n\n    primordials: WritableStreamDefaultControllerPrimordials<'js>,\n}\n\npub(crate) type WritableStreamDefaultControllerClass<'js> =\n    Class<'js, WritableStreamDefaultController<'js>>;\npub(crate) type WritableStreamDefaultControllerOwned<'js> =\n    OwnedBorrowMut<'js, WritableStreamDefaultController<'js>>;\n\nimpl<'js> WritableStreamDefaultController<'js> {\n    pub(super) fn set_up_writable_stream_default_controller_from_underlying_sink(\n        ctx: Ctx<'js>,\n        stream: WritableStreamOwned<'js>,\n        underlying_sink: Null<Undefined<Object<'js>>>,\n        underlying_sink_dict: UnderlyingSink<'js>,\n        high_water_mark: f64,\n        size_algorithm: SizeAlgorithm<'js>,\n    ) -> Result<()> {\n        let (start_algorithm, write_algorithm, close_algorithm, abort_algorithm) = (\n            // If underlyingSinkDict[\"start\"] exists, then set startAlgorithm to an algorithm which returns the result of invoking underlyingSinkDict[\"start\"] with argument list\n            // « controller », exception behavior \"rethrow\", and callback this value underlyingSink.\n            underlying_sink_dict\n                .start\n                .map(|f| StartAlgorithm::Function {\n                    f,\n                    underlying_sink: underlying_sink.clone(),\n                })\n                .unwrap_or(StartAlgorithm::ReturnUndefined),\n            // If underlyingSinkDict[\"write\"] exists, then set writeAlgorithm to an algorithm which takes an argument chunk and returns the result of invoking underlyingSinkDict[\"write\"] with argument list\n            // « chunk, controller » and callback this value underlyingSink.\n            underlying_sink_dict\n                .write\n                .map(|f| WriteAlgorithm::Function {\n                    f,\n                    underlying_sink: underlying_sink.clone(),\n                })\n                .unwrap_or(WriteAlgorithm::ReturnPromiseUndefined),\n            // If underlyingSinkDict[\"close\"] exists, then set closeAlgorithm to an algorithm which returns the result of invoking underlyingSinkDict[\"close\"] with argument list\n            // «» and callback this value underlyingSink.\n            underlying_sink_dict\n                .close\n                .map(|f| CloseAlgorithm::Function {\n                    f,\n                    underlying_sink: underlying_sink.clone(),\n                })\n                .unwrap_or(CloseAlgorithm::ReturnPromiseUndefined),\n            // If underlyingSinkDict[\"abort\"] exists, then set abortAlgorithm to an algorithm which takes an argument reason and returns the result of invoking underlyingSinkDict[\"abort\"] with argument list\n            // « reason » and callback this value underlyingSink.\n            underlying_sink_dict\n                .abort\n                .map(|f| AbortAlgorithm::Function {\n                    f,\n                    underlying_sink: underlying_sink.clone(),\n                })\n                .unwrap_or(AbortAlgorithm::ReturnPromiseUndefined),\n        );\n\n        // Perform ? SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm).\n        Self::set_up_writable_stream_default_controller(\n            ctx,\n            stream,\n            start_algorithm,\n            write_algorithm,\n            close_algorithm,\n            abort_algorithm,\n            high_water_mark,\n            size_algorithm,\n        )\n    }\n\n    #[allow(clippy::too_many_arguments)]\n    fn set_up_writable_stream_default_controller(\n        ctx: Ctx<'js>,\n        stream: WritableStreamOwned<'js>,\n        start_algorithm: StartAlgorithm<'js>,\n        write_algorithm: WriteAlgorithm<'js>,\n        close_algorithm: CloseAlgorithm<'js>,\n        abort_algorithm: AbortAlgorithm<'js>,\n        high_water_mark: f64,\n        size_algorithm: SizeAlgorithm<'js>,\n    ) -> Result<()> {\n        // TODO: needed?\n        let (stream_class, mut stream) = class_from_owned_borrow_mut(stream);\n\n        let controller = Self {\n            // Set controller.[[stream]] to stream.\n            stream: stream_class,\n\n            // Perform ! ResetQueue(controller).\n            container: QueueWithSizes::new(),\n\n            // Set controller.[[abortController]] to a new AbortController.\n            abort_controller: Class::instance(ctx.clone(), AbortController::new(ctx.clone())?)?,\n\n            // Set controller.[[started]] to false.\n            started: false,\n\n            // Set controller.[[strategySizeAlgorithm]] to sizeAlgorithm.\n            strategy_size_algorithm: Some(size_algorithm),\n            // Set controller.[[strategyHWM]] to highWaterMark.\n            strategy_hwm: high_water_mark,\n\n            // Set controller.[[writeAlgorithm]] to writeAlgorithm.\n            write_algorithm: Some(write_algorithm),\n            // Set controller.[[closeAlgorithm]] to closeAlgorithm.\n            close_algorithm: Some(close_algorithm),\n            // Set controller.[[abortAlgorithm]] to abortAlgorithm.\n            abort_algorithm: Some(abort_algorithm),\n\n            primordials: WritableStreamDefaultControllerPrimordials::get(&ctx)?.clone(),\n        };\n\n        let controller_class = Class::instance(ctx.clone(), controller)?;\n\n        // Set stream.[[controller]] to controller.\n        stream.controller = Some(controller_class.clone());\n\n        let objects = WritableStreamObjects::from_stream(stream);\n\n        // Let backpressure be ! WritableStreamDefaultControllerGetBackpressure(controller).\n        let backpressure = objects\n            .controller\n            .writable_stream_default_controller_get_backpressure();\n        // Perform ! WritableStreamUpdateBackpressure(stream, backpressure).\n        let objects = WritableStream::writable_stream_update_backpressure(\n            ctx.clone(),\n            objects,\n            backpressure,\n        )?;\n        let promise_primordials = objects.stream.promise_primordials.clone();\n\n        // Let startResult be the result of performing startAlgorithm. (This may throw an exception.)\n        let (start_result, objects_class) =\n            Self::start_algorithm(ctx.clone(), objects, start_algorithm)?;\n\n        // Let startPromise be a promise resolved with startResult.\n        let start_promise = promise_resolved_with(&ctx, &promise_primordials, Ok(start_result))?;\n\n        let _ = upon_promise::<Value<'js>, _>(ctx.clone(), start_promise, {\n            move |ctx, result| {\n                let mut objects =\n                    WritableStreamObjects::from_class_no_writer(objects_class).refresh_writer();\n                match result {\n                    // Upon fulfillment of startPromise,\n                    Ok(_) => {\n                        // Set controller.[[started]] to true.\n                        objects.controller.started = true;\n                        // Perform ! WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller).\n                        Self::writable_stream_default_controller_advance_queue_if_needed(\n                            ctx, objects,\n                        )?;\n                    },\n                    // Upon rejection of startPromise with reason r,\n                    Err(r) => {\n                        // Set controller.[[started]] to true.\n                        objects.controller.started = true;\n\n                        // Perform ! WritableStreamDealWithRejection(stream, r).\n                        WritableStream::writable_stream_deal_with_rejection(ctx, objects, r)?;\n                    },\n                }\n                Ok(())\n            }\n        })?;\n\n        Ok(())\n    }\n\n    pub(super) fn writable_stream_default_controller_close<W: WritableStreamWriter<'js>>(\n        ctx: Ctx<'js>,\n        mut objects: WritableStreamObjects<'js, W>,\n    ) -> Result<WritableStreamObjects<'js, W>> {\n        let close_sentinel = objects\n            .controller\n            .primordials\n            .close_sentinel\n            .as_value()\n            .clone();\n\n        // Perform ! EnqueueValueWithSize(controller, close sentinel, 0).\n        objects.controller.container.enqueue_value_with_size(\n            &ctx,\n            close_sentinel,\n            SizeValue::Native(0.0),\n        )?;\n\n        // Perform ! WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller).\n        objects = Self::writable_stream_default_controller_advance_queue_if_needed(ctx, objects)?;\n\n        Ok(objects)\n    }\n\n    pub(super) fn writable_stream_default_controller_get_desired_size(&self) -> f64 {\n        self.strategy_hwm - self.container.queue_total_size\n    }\n\n    pub fn writable_stream_default_controller_get_backpressure(&self) -> bool {\n        // Let desiredSize be ! WritableStreamDefaultControllerGetDesiredSize(controller).\n        let desired_size = self.writable_stream_default_controller_get_desired_size();\n        // Return true if desiredSize ≤ 0, or false otherwise.\n        desired_size <= 0.0\n    }\n\n    pub(super) fn writable_stream_default_controller_get_chunk_size(\n        ctx: Ctx<'js>,\n        mut objects: WritableStreamObjects<'js, WritableStreamDefaultWriterOwned<'js>>,\n        chunk: Value<'js>,\n    ) -> Result<(\n        SizeValue<'js>,\n        WritableStreamObjects<'js, WritableStreamDefaultWriterOwned<'js>>,\n    )> {\n        let (return_value, objects_class) =\n            Self::strategy_size_algorithm(ctx.clone(), objects, chunk);\n\n        // Let returnValue be the result of performing controller.[[strategySizeAlgorithm]], passing in chunk, and interpreting the result as a completion record.\n        match return_value {\n            Ok(chunk_size) => {\n                objects = WritableStreamObjects::from_class(objects_class);\n                Ok((chunk_size, objects))\n            },\n            // If returnValue is an abrupt completion,\n            Err(Error::Exception) => {\n                let reason = ctx.catch();\n\n                objects = WritableStreamObjects::from_class(objects_class);\n\n                // Perform ! WritableStreamDefaultControllerErrorIfNeeded(controller, returnValue.[[Value]]).\n                objects = Self::writable_stream_default_controller_error_if_needed(\n                    ctx.clone(),\n                    objects,\n                    reason,\n                )?;\n\n                // Return 1.\n                Ok((SizeValue::Native(1.0), objects))\n            },\n            Err(err) => Err(err),\n        }\n    }\n\n    fn writable_stream_default_controller_error_if_needed(\n        ctx: Ctx<'js>,\n        objects: WritableStreamObjects<'js, WritableStreamDefaultWriterOwned<'js>>,\n        error: Value<'js>,\n    ) -> Result<WritableStreamObjects<'js, WritableStreamDefaultWriterOwned<'js>>> {\n        // If controller.[[stream]].[[state]] is \"writable\", perform ! WritableStreamDefaultControllerError(controller, error).\n        if let WritableStreamState::Writable = objects.stream.state {\n            Self::writable_stream_default_controller_error(ctx, objects, error)\n        } else {\n            Ok(objects)\n        }\n    }\n\n    fn writable_stream_default_controller_error<W: WritableStreamWriter<'js>>(\n        ctx: Ctx<'js>,\n        // Let stream be controller.[[stream]].\n        mut objects: WritableStreamObjects<'js, W>,\n        reason: Value<'js>,\n    ) -> Result<WritableStreamObjects<'js, W>> {\n        // Perform ! WritableStreamDefaultControllerClearAlgorithms(controller).\n        objects\n            .controller\n            .writable_stream_default_controller_clear_algorithms();\n\n        // Perform ! WritableStreamStartErroring(stream, error).\n        objects = WritableStream::writable_stream_start_erroring(ctx, objects, reason)?;\n\n        Ok(objects)\n    }\n\n    fn writable_stream_default_controller_clear_algorithms(&mut self) {\n        // Set controller.[[writeAlgorithm]] to undefined.\n        self.write_algorithm = None;\n\n        // Set controller.[[closeAlgorithm]] to undefined.\n        self.close_algorithm = None;\n\n        // Set controller.[[abortAlgorithm]] to undefined.\n        self.abort_algorithm = None;\n\n        // Set controller.[[strategySizeAlgorithm]] to undefined.\n        self.strategy_size_algorithm = None;\n    }\n\n    pub(super) fn writable_stream_default_controller_write(\n        ctx: Ctx<'js>,\n        // Let stream be controller.[[stream]].\n        mut objects: WritableStreamObjects<'js, WritableStreamDefaultWriterOwned<'js>>,\n        chunk: Value<'js>,\n        chunk_size: SizeValue<'js>,\n    ) -> Result<WritableStreamObjects<'js, WritableStreamDefaultWriterOwned<'js>>> {\n        // Let enqueueResult be EnqueueValueWithSize(controller, chunk, chunkSize).\n        let enqueue_result = objects\n            .controller\n            .container\n            .enqueue_value_with_size(&ctx, chunk, chunk_size);\n\n        match enqueue_result {\n            // If enqueueResult is an abrupt completion,\n            Err(Error::Exception) => {\n                let reason = ctx.catch();\n                // Perform ! WritableStreamDefaultControllerErrorIfNeeded(controller, enqueueResult.[[Value]]).\n                objects =\n                    Self::writable_stream_default_controller_error_if_needed(ctx, objects, reason)?;\n\n                return Ok(objects);\n            },\n            Err(err) => return Err(err),\n            Ok(()) => {},\n        }\n\n        // If ! WritableStreamCloseQueuedOrInFlight(stream) is false and stream.[[state]] is \"writable\",\n        if !objects.stream.writable_stream_close_queued_or_in_flight()\n            && matches!(objects.stream.state, WritableStreamState::Writable)\n        {\n            // Let backpressure be ! WritableStreamDefaultControllerGetBackpressure(controller).\n            let backpressure = objects\n                .controller\n                .writable_stream_default_controller_get_backpressure();\n\n            // Perform ! WritableStreamUpdateBackpressure(stream, backpressure).\n            objects = WritableStream::writable_stream_update_backpressure(\n                ctx.clone(),\n                objects,\n                backpressure,\n            )?;\n        }\n\n        // Perform ! WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller).\n        let objects =\n            Self::writable_stream_default_controller_advance_queue_if_needed(ctx, objects)?;\n\n        Ok(objects)\n    }\n\n    fn writable_stream_default_controller_advance_queue_if_needed<W: WritableStreamWriter<'js>>(\n        ctx: Ctx<'js>,\n        // Let stream be controller.[[stream]].\n        objects: WritableStreamObjects<'js, W>,\n    ) -> Result<WritableStreamObjects<'js, W>> {\n        // If controller.[[started]] is false, return.\n        // If stream.[[inFlightWriteRequest]] is not undefined, return.\n        if !objects.controller.started || objects.stream.in_flight_write_request.is_some() {\n            return Ok(objects);\n        }\n\n        // Let state be stream.[[state]].\n\n        // If state is \"erroring\",\n        if let WritableStreamState::Erroring(ref stored_error) = objects.stream.state {\n            let stored_error = stored_error.clone();\n            // Perform ! WritableStreamFinishErroring(stream).\n            // Return.\n            return WritableStream::writable_stream_finish_erroring(ctx, objects, stored_error);\n        }\n\n        let value = match objects.controller.container.queue.front() {\n            // If controller.[[queue]] is empty, return.\n            None => {\n                return Ok(objects);\n            },\n            // Let value be ! PeekQueueValue(controller).\n            Some(value) => value.clone(),\n        };\n\n        if value.value.as_symbol() == Some(&objects.controller.primordials.close_sentinel) {\n            // If value is the close sentinel, perform ! WritableStreamDefaultControllerProcessClose(controller).\n            Self::writable_stream_default_controller_process_close(ctx, objects)\n        } else {\n            // Otherwise, perform ! WritableStreamDefaultControllerProcessWrite(controller, value).\n            Self::writable_stream_default_controller_process_write(ctx, objects, value.value)\n        }\n    }\n\n    fn writable_stream_default_controller_process_close<W: WritableStreamWriter<'js>>(\n        ctx: Ctx<'js>,\n        // Let stream be controller.[[stream]].\n        mut objects: WritableStreamObjects<'js, W>,\n    ) -> Result<WritableStreamObjects<'js, W>> {\n        // Perform ! WritableStreamMarkCloseRequestInFlight(stream).\n        objects\n            .stream\n            .writable_stream_mark_close_request_in_flight();\n\n        // Perform ! DequeueValue(controller).\n        objects.controller.container.dequeue_value();\n\n        // Assert: controller.[[queue]] is empty.\n\n        // Let sinkClosePromise be the result of performing controller.[[closeAlgorithm]].\n        let (sink_close_promise, objects_class) = Self::close_algorithm(&ctx, objects)?;\n\n        objects = WritableStreamObjects::from_class(objects_class.clone());\n\n        // Perform ! WritableStreamDefaultControllerClearAlgorithms(controller).\n        objects\n            .controller\n            .writable_stream_default_controller_clear_algorithms();\n\n        upon_promise::<Value<'js>, ()>(ctx, sink_close_promise, |ctx, result| {\n            let objects = WritableStreamObjects::from_class(objects_class);\n            match result {\n                // Upon fulfillment of sinkClosePromise,\n                Ok(_) => {\n                    // Perform ! WritableStreamFinishInFlightClose(stream).\n                    WritableStream::writable_stream_finish_in_flight_close(objects)?;\n                },\n                // Upon rejection of sinkClosePromise with reason reason,\n                Err(reason) => {\n                    // Perform ! WritableStreamFinishInFlightCloseWithError(stream, reason).\n                    WritableStream::writable_stream_finish_in_flight_close_with_error(\n                        ctx, objects, reason,\n                    )?;\n                },\n            }\n\n            Ok(())\n        })?;\n\n        Ok(objects)\n    }\n\n    fn writable_stream_default_controller_process_write<W: WritableStreamWriter<'js>>(\n        ctx: Ctx<'js>,\n        // Let stream be controller.[[stream]].\n        mut objects: WritableStreamObjects<'js, W>,\n        chunk: Value<'js>,\n    ) -> Result<WritableStreamObjects<'js, W>> {\n        // Perform ! WritableStreamMarkFirstWriteRequestInFlight(stream).\n        objects\n            .stream\n            .writable_stream_mark_first_write_request_in_flight();\n\n        // Let sinkWritePromise be the result of performing controller.[[writeAlgorithm]], passing in chunk.\n        let (sink_write_promise, objects_class) = Self::write_algorithm(&ctx, objects, chunk)?;\n\n        // Upon fulfillment of sinkWritePromise,\n        upon_promise::<Value<'js>, ()>(ctx, sink_write_promise, {\n            let objects_class = objects_class.clone();\n            |ctx, result| {\n                let mut objects = WritableStreamObjects::from_class(objects_class).refresh_writer();\n                match result {\n                    Ok(_) => {\n                        // Upon fulfillment of sinkWritePromise,\n                        // Perform ! WritableStreamFinishInFlightWrite(stream).\n                        objects.stream.writable_stream_finish_in_flight_write()?;\n\n                        // Let state be stream.[[state]].\n                        let state = &objects.stream.state;\n\n                        // Perform ! DequeueValue(controller).\n                        objects.controller.container.dequeue_value();\n\n                        // If ! WritableStreamCloseQueuedOrInFlight(stream) is false and state is \"writable\",\n                        if !objects.stream.writable_stream_close_queued_or_in_flight()\n                            && matches!(state, WritableStreamState::Writable)\n                        {\n                            // Let backpressure be ! WritableStreamDefaultControllerGetBackpressure(controller).\n                            let backpressure = objects\n                                .controller\n                                .writable_stream_default_controller_get_backpressure();\n\n                            // Perform ! WritableStreamUpdateBackpressure(stream, backpressure).\n                            objects = WritableStream::writable_stream_update_backpressure(\n                                ctx.clone(),\n                                objects,\n                                backpressure,\n                            )?;\n                        }\n\n                        // Perform ! WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller).\n                        WritableStreamDefaultController::writable_stream_default_controller_advance_queue_if_needed(ctx, objects)?;\n                    },\n                    Err(reason) => {\n                        // Upon rejection of sinkWritePromise with reason,\n                        if let WritableStreamState::Writable = objects.stream.state {\n                            // If stream.[[state]] is \"writable\", perform ! WritableStreamDefaultControllerClearAlgorithms(controller).\n                            objects\n                                .controller\n                                .writable_stream_default_controller_clear_algorithms();\n                        }\n                        // Perform ! WritableStreamFinishInFlightWriteWithError(stream, reason).\n                        WritableStream::writable_stream_finish_in_flight_write_with_error(\n                            ctx, objects, reason,\n                        )?;\n                    },\n                }\n\n                Ok(())\n            }\n        })?;\n\n        Ok(WritableStreamObjects::from_class(objects_class))\n    }\n\n    pub(super) fn error_steps(&mut self) {\n        // Perform ! ResetQueue(this).\n        self.reset_queue()\n    }\n\n    fn reset_queue(&mut self) {\n        // Set container.[[queue]] to a new empty list.\n        self.container.queue.clear();\n        // Set container.[[queueTotalSize]] to 0.\n        self.container.queue_total_size = 0.0;\n    }\n\n    pub(super) fn abort_steps<W: WritableStreamWriter<'js>>(\n        ctx: &Ctx<'js>,\n        mut objects: WritableStreamObjects<'js, W>,\n        reason: Value<'js>,\n    ) -> Result<(Promise<'js>, WritableStreamObjects<'js, W>)> {\n        // Let result be the result of performing this.[[abortAlgorithm]], passing reason.\n        let (result, objects_class) = Self::abort_algorithm(ctx, objects, reason)?;\n\n        objects = WritableStreamObjects::from_class(objects_class);\n\n        // Perform ! WritableStreamDefaultControllerClearAlgorithms(this).\n        objects\n            .controller\n            .writable_stream_default_controller_clear_algorithms();\n\n        // Return result.\n        Ok((result, objects))\n    }\n\n    fn strategy_size_algorithm(\n        ctx: Ctx<'js>,\n        objects: WritableStreamObjects<'js, WritableStreamDefaultWriterOwned<'js>>,\n        chunk: Value<'js>,\n    ) -> (\n        Result<SizeValue<'js>>,\n        WritableStreamClassObjects<'js, WritableStreamDefaultWriterOwned<'js>>,\n    ) {\n        let strategy_size_algorithm = objects\n            .controller\n            .strategy_size_algorithm\n            .clone()\n            .unwrap_or(SizeAlgorithm::AlwaysOne);\n\n        let objects_class = objects.into_inner();\n\n        (strategy_size_algorithm.call(ctx, chunk), objects_class)\n    }\n\n    fn start_algorithm(\n        ctx: Ctx<'js>,\n        objects: WritableStreamObjects<'js, UndefinedWriter>,\n        start_algorithm: StartAlgorithm<'js>,\n    ) -> Result<(Value<'js>, WritableStreamClassObjects<'js, UndefinedWriter>)> {\n        let objects_class = objects.into_inner();\n\n        Ok((\n            start_algorithm.call(ctx, objects_class.controller.clone())?,\n            objects_class,\n        ))\n    }\n\n    fn write_algorithm<W: WritableStreamWriter<'js>>(\n        ctx: &Ctx<'js>,\n        objects: WritableStreamObjects<'js, W>,\n        chunk: Value<'js>,\n    ) -> Result<(Promise<'js>, WritableStreamClassObjects<'js, W>)> {\n        let write_algorithm =\n            objects.controller.write_algorithm.clone().expect(\n                \"write algorithm used after WritableStreamDefaultControllerClearAlgorithms\",\n            );\n        let promise_primordials = objects.stream.promise_primordials.clone();\n        let objects_class = objects.into_inner();\n\n        Ok((\n            write_algorithm.call(\n                ctx,\n                &promise_primordials,\n                objects_class.controller.clone().clone(),\n                chunk,\n            )?,\n            objects_class,\n        ))\n    }\n\n    fn close_algorithm<W: WritableStreamWriter<'js>>(\n        ctx: &Ctx<'js>,\n        objects: WritableStreamObjects<'js, W>,\n    ) -> Result<(Promise<'js>, WritableStreamClassObjects<'js, W>)> {\n        let close_algorithm =\n            objects.controller.close_algorithm.clone().expect(\n                \"close algorithm used after WritableStreamDefaultControllerClearAlgorithms\",\n            );\n        let promise_primordials = objects.stream.promise_primordials.clone();\n        let objects_class = objects.into_inner();\n\n        Ok((\n            close_algorithm.call(ctx, &promise_primordials)?,\n            objects_class,\n        ))\n    }\n\n    fn abort_algorithm<W: WritableStreamWriter<'js>>(\n        ctx: &Ctx<'js>,\n        objects: WritableStreamObjects<'js, W>,\n        reason: Value<'js>,\n    ) -> Result<(Promise<'js>, WritableStreamClassObjects<'js, W>)> {\n        let abort_algorithm =\n            objects.controller.abort_algorithm.clone().expect(\n                \"abort algorithm used after WritableStreamDefaultControllerClearAlgorithms\",\n            );\n        let promise_primordials = objects.stream.promise_primordials.clone();\n        let objects_class = objects.into_inner();\n\n        Ok((\n            abort_algorithm.call(ctx, &promise_primordials, reason)?,\n            objects_class,\n        ))\n    }\n}\n\n#[methods(rename_all = \"camelCase\")]\nimpl<'js> WritableStreamDefaultController<'js> {\n    // this is required by web platform tests\n    #[qjs(get)]\n    pub fn constructor(ctx: Ctx<'js>) -> Result<Option<Constructor<'js>>> {\n        <WritableStreamDefaultController as JsClass>::constructor(&ctx)\n    }\n\n    #[qjs(constructor)]\n    fn new(ctx: Ctx<'js>) -> Result<Class<'js, Self>> {\n        Err(Exception::throw_type(&ctx, \"Illegal constructor\"))\n    }\n\n    // readonly attribute AbortSignal signal;\n    #[qjs(get)]\n    fn signal(&self) -> Class<'js, AbortSignal<'js>> {\n        // Return this.[[abortController]]'s signal.\n        self.abort_controller.borrow().signal()\n    }\n\n    // undefined error(optional any e);\n    fn error(\n        ctx: Ctx<'js>,\n        controller: This<OwnedBorrowMut<'js, Self>>,\n        e: Opt<Value<'js>>,\n    ) -> Result<()> {\n        let objects = WritableStreamObjects::from_controller(controller.0);\n\n        // Let state be this.[[stream]].[[state]].\n        // If state is not \"writable\", return.\n        if !matches!(objects.stream.state, WritableStreamState::Writable) {\n            return Ok(());\n        }\n\n        // Perform ! WritableStreamDefaultControllerError(this, e).\n        Self::writable_stream_default_controller_error(\n            ctx.clone(),\n            objects.refresh_writer(),\n            e.0.unwrap_or_undefined(&ctx),\n        )?;\n\n        Ok(())\n    }\n}\n\n#[derive(Clone)]\nenum StartAlgorithm<'js> {\n    ReturnUndefined,\n    Function {\n        f: Function<'js>,\n        underlying_sink: Null<Undefined<Object<'js>>>,\n    },\n}\n\nimpl<'js> StartAlgorithm<'js> {\n    fn call(\n        &self,\n        ctx: Ctx<'js>,\n        controller: WritableStreamDefaultControllerClass<'js>,\n    ) -> Result<Value<'js>> {\n        match self {\n            StartAlgorithm::ReturnUndefined => Ok(Value::new_undefined(ctx.clone())),\n            StartAlgorithm::Function { f, underlying_sink } => {\n                f.call::<_, Value>((This(underlying_sink.clone()), controller))\n            },\n        }\n    }\n}\n\n#[derive(JsLifetime, Trace, Clone)]\nenum WriteAlgorithm<'js> {\n    ReturnPromiseUndefined,\n    Function {\n        f: Function<'js>,\n        underlying_sink: Null<Undefined<Object<'js>>>,\n    },\n}\n\nimpl<'js> WriteAlgorithm<'js> {\n    fn call(\n        &self,\n        ctx: &Ctx<'js>,\n        promise_primordials: &PromisePrimordials<'js>,\n        controller: WritableStreamDefaultControllerClass<'js>,\n        chunk: Value<'js>,\n    ) -> Result<Promise<'js>> {\n        match self {\n            WriteAlgorithm::ReturnPromiseUndefined => {\n                Ok(promise_primordials.promise_resolved_with_undefined.clone())\n            },\n            WriteAlgorithm::Function { f, underlying_sink } => promise_resolved_with(\n                ctx,\n                promise_primordials,\n                f.call::<_, Value>((This(underlying_sink.clone()), chunk, controller)),\n            ),\n        }\n    }\n}\n\n#[derive(JsLifetime, Trace, Clone)]\nenum CloseAlgorithm<'js> {\n    ReturnPromiseUndefined,\n    Function {\n        f: Function<'js>,\n        underlying_sink: Null<Undefined<Object<'js>>>,\n    },\n}\n\nimpl<'js> CloseAlgorithm<'js> {\n    fn call(\n        &self,\n        ctx: &Ctx<'js>,\n        promise_primordials: &PromisePrimordials<'js>,\n    ) -> Result<Promise<'js>> {\n        match self {\n            CloseAlgorithm::ReturnPromiseUndefined => {\n                Ok(promise_primordials.promise_resolved_with_undefined.clone())\n            },\n            CloseAlgorithm::Function { f, underlying_sink } => promise_resolved_with(\n                ctx,\n                promise_primordials,\n                f.call::<_, Value>((This(underlying_sink.clone()),)),\n            ),\n        }\n    }\n}\n\n#[derive(JsLifetime, Trace, Clone)]\nenum AbortAlgorithm<'js> {\n    ReturnPromiseUndefined,\n    Function {\n        f: Function<'js>,\n        underlying_sink: Null<Undefined<Object<'js>>>,\n    },\n}\n\nimpl<'js> AbortAlgorithm<'js> {\n    fn call(\n        &self,\n        ctx: &Ctx<'js>,\n        promise_primordials: &PromisePrimordials<'js>,\n        reason: Value<'js>,\n    ) -> Result<Promise<'js>> {\n        match self {\n            AbortAlgorithm::ReturnPromiseUndefined => {\n                Ok(promise_primordials.promise_resolved_with_undefined.clone())\n            },\n            AbortAlgorithm::Function { f, underlying_sink } => promise_resolved_with(\n                ctx,\n                promise_primordials,\n                f.call::<_, Value>((This(underlying_sink.clone()), reason)),\n            ),\n        }\n    }\n}\n\n#[derive(Trace, Clone, JsLifetime)]\npub(crate) struct WritableStreamDefaultControllerPrimordials<'js> {\n    close_sentinel: Symbol<'js>,\n}\n\nimpl<'js> Primordial<'js> for WritableStreamDefaultControllerPrimordials<'js> {\n    fn new(ctx: &Ctx<'js>) -> Result<Self>\n    where\n        Self: Sized,\n    {\n        Ok(Self {\n            close_sentinel: Symbol::for_description(ctx, \"close sentinel\")?,\n        })\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/writable/default_writer.rs",
    "content": "use llrt_utils::option::Null;\nuse rquickjs::{\n    class::{JsClass, OwnedBorrow, OwnedBorrowMut, Trace},\n    function::Constructor,\n    prelude::{Opt, This},\n    Class, Ctx, Exception, JsLifetime, Promise, Result, Value,\n};\n\nuse crate::{\n    utils::{\n        promise::{\n            promise_rejected_with, promise_rejected_with_constructor, PromisePrimordials,\n            ResolveablePromise,\n        },\n        UnwrapOrUndefined,\n    },\n    writable::{\n        default_controller::WritableStreamDefaultController,\n        objects::WritableStreamObjects,\n        stream::{WritableStream, WritableStreamOwned, WritableStreamState},\n        writer::WritableStreamWriter,\n    },\n};\n\n#[rquickjs::class]\n#[derive(JsLifetime)]\npub(crate) struct WritableStreamDefaultWriter<'js> {\n    pub(crate) ready_promise: ResolveablePromise<'js>,\n    pub(crate) closed_promise: ResolveablePromise<'js>,\n    pub(super) stream: Option<Class<'js, WritableStream<'js>>>,\n\n    constructor_type_error: Constructor<'js>,\n    promise_primordials: PromisePrimordials<'js>,\n}\n\nimpl<'js> Trace<'js> for WritableStreamDefaultWriter<'js> {\n    fn trace<'a>(&self, tracer: rquickjs::class::Tracer<'a, 'js>) {\n        self.ready_promise.trace(tracer);\n        self.closed_promise.trace(tracer);\n        self.stream.trace(tracer);\n        self.constructor_type_error.trace(tracer);\n        self.promise_primordials.trace(tracer);\n    }\n}\n\npub(crate) type WritableStreamDefaultWriterClass<'js> =\n    Class<'js, WritableStreamDefaultWriter<'js>>;\npub(crate) type WritableStreamDefaultWriterOwned<'js> =\n    OwnedBorrowMut<'js, WritableStreamDefaultWriter<'js>>;\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl<'js> WritableStreamDefaultWriter<'js> {\n    // this is required by web platform tests\n    #[qjs(get)]\n    pub fn constructor(ctx: Ctx<'js>) -> Result<Option<Constructor<'js>>> {\n        <WritableStreamDefaultWriter as JsClass>::constructor(&ctx)\n    }\n\n    #[qjs(constructor)]\n    fn new(ctx: Ctx<'js>, stream: WritableStreamOwned<'js>) -> Result<Class<'js, Self>> {\n        // Perform ? SetUpWritableStreamDefaultWriter(this, stream).\n        let (_, writer) = Self::set_up_writable_stream_default_writer(&ctx, stream)?;\n        Ok(writer)\n    }\n\n    #[qjs(get)]\n    fn closed(writer: This<OwnedBorrowMut<'js, Self>>) -> Promise<'js> {\n        // Return this.[[closedPromise]].\n        writer.0.closed_promise.promise.clone()\n    }\n\n    #[qjs(get)]\n    fn desired_size(ctx: Ctx<'js>, writer: This<OwnedBorrowMut<'js, Self>>) -> Result<Null<f64>> {\n        match writer.0.stream {\n            // If this.[[stream]] is undefined, throw a TypeError exception.\n            None => Err(Exception::throw_type(\n                &ctx,\n                \"Cannot desiredSize a stream using a released writer\",\n            )),\n            Some(ref stream) => {\n                // Return ! WritableStreamDefaultWriterGetDesiredSize(this).\n                Self::writable_stream_default_writer_get_desired_size(&OwnedBorrowMut::from_class(\n                    stream.clone(),\n                ))\n            },\n        }\n    }\n\n    #[qjs(get)]\n    fn ready(writer: This<OwnedBorrowMut<'js, Self>>) -> Promise<'js> {\n        // Return this.[[readyPromise]].\n        writer.0.ready_promise.promise.clone()\n    }\n\n    fn abort(\n        ctx: Ctx<'js>,\n        writer: This<OwnedBorrowMut<'js, Self>>,\n        reason: Opt<Value<'js>>,\n    ) -> Result<Promise<'js>> {\n        // If this.[[stream]] is undefined, throw a TypeError exception.\n        if writer.0.stream.is_none() {\n            promise_rejected_with_constructor(\n                &writer.constructor_type_error,\n                &writer.promise_primordials,\n                \"Cannot abort a stream using a released writer\",\n            )\n        } else {\n            let objects = WritableStreamObjects::from_writer(writer.0);\n\n            // Return ! WritableStreamDefaultWriterAbort(this, reason).\n            Self::writable_stream_default_writer_abort(ctx.clone(), objects, reason.0)\n        }\n    }\n\n    fn close(ctx: Ctx<'js>, writer: This<OwnedBorrowMut<'js, Self>>) -> Result<Promise<'js>> {\n        // If this.[[stream]] is undefined, throw a TypeError exception.\n        if writer.0.stream.is_none() {\n            promise_rejected_with_constructor(\n                &writer.constructor_type_error,\n                &writer.promise_primordials,\n                \"Cannot close a stream using a released writer\",\n            )\n        } else {\n            let objects = WritableStreamObjects::from_writer(writer.0);\n\n            // If ! WritableStreamCloseQueuedOrInFlight(stream) is true, return a promise rejected with a TypeError exception.\n            if objects.stream.writable_stream_close_queued_or_in_flight() {\n                return promise_rejected_with_constructor(\n                    &objects.writer.constructor_type_error,\n                    &objects.writer.promise_primordials,\n                    \"Cannot close an already-closing\",\n                );\n            }\n\n            // Return ! WritableStreamDefaultWriterClose(this).\n            Self::writable_stream_default_writer_close(ctx, objects)\n        }\n    }\n\n    fn release_lock(writer: This<OwnedBorrowMut<'js, Self>>) -> Result<()> {\n        // If stream is undefined, return.\n        if writer.0.stream.is_none() {\n            Ok(())\n        } else {\n            let objects = WritableStreamObjects::from_writer(writer.0);\n\n            // Perform ! WritableStreamDefaultWriterRelease(this).\n            Self::writable_stream_default_writer_release(objects)\n        }\n    }\n\n    fn write(\n        ctx: Ctx<'js>,\n        writer: This<OwnedBorrowMut<'js, Self>>,\n        chunk: Opt<Value<'js>>,\n    ) -> Result<Promise<'js>> {\n        // If this.[[stream]] is undefined, throw a TypeError exception.\n        if writer.0.stream.is_none() {\n            promise_rejected_with_constructor(\n                &writer.constructor_type_error,\n                &writer.promise_primordials,\n                \"Cannot write a stream using a released writer\",\n            )\n        } else {\n            let objects = WritableStreamObjects::from_writer(writer.0);\n\n            // Return ! WritableStreamDefaultWriterWrite(this, chunk).\n            Self::writable_stream_default_writer_write(\n                ctx.clone(),\n                objects,\n                chunk.0.unwrap_or_undefined(&ctx),\n            )\n        }\n    }\n}\n\nimpl<'js> WritableStreamDefaultWriter<'js> {\n    pub(crate) fn acquire_writable_stream_default_writer(\n        ctx: &Ctx<'js>,\n        stream: WritableStreamOwned<'js>,\n    ) -> Result<(WritableStreamOwned<'js>, Class<'js, Self>)> {\n        Self::set_up_writable_stream_default_writer(ctx, stream)\n    }\n\n    pub(super) fn set_up_writable_stream_default_writer(\n        ctx: &Ctx<'js>,\n        mut stream: WritableStreamOwned<'js>,\n    ) -> Result<(WritableStreamOwned<'js>, Class<'js, Self>)> {\n        // If ! IsWritableStreamLocked(stream) is true, throw a TypeError exception.\n        if stream.is_writable_stream_locked() {\n            return Err(Exception::throw_type(\n                ctx,\n                \"This stream has already been locked for exclusive writing by another writer\",\n            ));\n        }\n\n        let promise_primordials = stream.promise_primordials.clone();\n        let constructor_type_error = stream.constructor_type_error.clone();\n        let stream_class = stream.into_inner();\n        stream = OwnedBorrowMut::from_class(stream_class.clone());\n\n        let (ready_promise, closed_promise) = match stream.state {\n            WritableStreamState::Writable => {\n                let ready_promise =\n                    if !stream.writable_stream_close_queued_or_in_flight() && stream.backpressure {\n                        // If ! WritableStreamCloseQueuedOrInFlight(stream) is false and stream.[[backpressure]] is true, set writer.[[readyPromise]] to a new promise.\n                        ResolveablePromise::new(ctx)?\n                    } else {\n                        // Otherwise, set writer.[[readyPromise]] to a promise resolved with undefined.\n                        ResolveablePromise::resolved_with_undefined(&stream.promise_primordials)\n                    };\n\n                // Set writer.[[closedPromise]] to a new promise.\n                (ready_promise, ResolveablePromise::new(ctx)?)\n            },\n            WritableStreamState::Erroring(ref stored_error) => {\n                let ready_promise = ResolveablePromise::rejected_with(\n                    &stream.promise_primordials,\n                    stored_error.clone(),\n                )?;\n                ready_promise.set_is_handled()?;\n                // Set writer.[[closedPromise]] to a new promise.\n                (ready_promise, ResolveablePromise::new(ctx)?)\n            },\n            WritableStreamState::Closed => {\n                let promise =\n                    ResolveablePromise::resolved_with_undefined(&stream.promise_primordials);\n                // Set writer.[[readyPromise]] to a promise resolved with undefined.\n                // Set writer.[[closedPromise]] to a promise resolved with undefined.\n                (promise.clone(), promise)\n            },\n            // Let storedError be stream.[[storedError]].\n            WritableStreamState::Errored(ref stored_error) => {\n                let promise = ResolveablePromise::rejected_with(\n                    &stream.promise_primordials,\n                    stored_error.clone(),\n                )?;\n                promise.set_is_handled()?;\n                // Set writer.[[readyPromise]] to a promise rejected with storedError.\n                // Set writer.[[readyPromise]].[[PromiseIsHandled]] to true.\n                // Set writer.[[closedPromise]] to a promise rejected with storedError.\n                // Set writer.[[closedPromise]].[[PromiseIsHandled]] to true.\n                (promise.clone(), promise)\n            },\n        };\n\n        let writer = Self {\n            ready_promise,\n            closed_promise,\n            // Set writer.[[stream]] to stream.\n            stream: Some(stream_class),\n            promise_primordials,\n            constructor_type_error,\n        };\n\n        let writer = Class::instance(ctx.clone(), writer)?;\n\n        stream.writer = Some(writer.clone());\n\n        Ok((stream, writer))\n    }\n\n    pub(super) fn writable_stream_default_writer_ensure_ready_promise_rejected(\n        &mut self,\n        promise_primordials: &PromisePrimordials<'js>,\n        error: Value<'js>,\n    ) -> Result<()> {\n        if self.ready_promise.is_pending() {\n            // If writer.[[readyPromise]].[[PromiseState]] is \"pending\", reject writer.[[readyPromise]] with error.\n            self.ready_promise.reject(error)?;\n        } else {\n            // Otherwise, set writer.[[readyPromise]] to a promise rejected with error.\n            self.ready_promise = ResolveablePromise::rejected_with(promise_primordials, error)?;\n        }\n\n        // Set writer.[[readyPromise]].[[PromiseIsHandled]] to true.\n        self.ready_promise.set_is_handled()?;\n        Ok(())\n    }\n\n    pub(super) fn writable_stream_default_writer_ensure_closed_promise_rejected(\n        &mut self,\n        promise_primordials: &PromisePrimordials<'js>,\n        error: Value<'js>,\n    ) -> Result<()> {\n        if self.closed_promise.is_pending() {\n            // If writer.[[closedPromise]].[[PromiseState]] is \"pending\", reject writer.[[closedPromise]] with error.\n            self.closed_promise.reject(error)?;\n        } else {\n            // Otherwise, set writer.[[closedPromise]] to a promise rejected with error.\n            self.closed_promise = ResolveablePromise::rejected_with(promise_primordials, error)?;\n        }\n\n        // Set writer.[[closedPromise]].[[PromiseIsHandled]] to true.\n        self.closed_promise.set_is_handled()?;\n        Ok(())\n    }\n\n    pub(super) fn writable_stream_default_writer_get_desired_size(\n        // Let stream be writer.[[stream]].\n        stream: &WritableStream<'js>,\n    ) -> Result<Null<f64>> {\n        // Let state be stream.[[state]].\n        // If state is \"errored\" or \"erroring\", return null.\n        if matches!(\n            stream.state,\n            WritableStreamState::Errored(_) | WritableStreamState::Erroring(_)\n        ) {\n            return Ok(Null(None));\n        }\n\n        // If state is \"closed\", return 0.\n        if matches!(stream.state, WritableStreamState::Closed) {\n            return Ok(Null(Some(0.0)));\n        }\n\n        // Return ! WritableStreamDefaultControllerGetDesiredSize(stream.[[controller]]).\n        let controller = OwnedBorrow::from_class(\n            stream\n                .controller\n                .clone()\n                .expect(\"Stream in state writable must have a controller\"),\n        );\n\n        Ok(Null(Some(\n            controller.writable_stream_default_controller_get_desired_size(),\n        )))\n    }\n\n    fn writable_stream_default_writer_abort(\n        ctx: Ctx<'js>,\n        objects: WritableStreamObjects<'js, OwnedBorrowMut<'js, Self>>,\n        reason: Option<Value<'js>>,\n    ) -> Result<Promise<'js>> {\n        // Return ! WritableStreamAbort(stream, reason).\n        let (promise, _) = WritableStream::writable_stream_abort(ctx, objects, reason)?;\n        Ok(promise)\n    }\n\n    fn writable_stream_default_writer_close(\n        ctx: Ctx<'js>,\n        objects: WritableStreamObjects<'js, OwnedBorrowMut<'js, Self>>,\n    ) -> Result<Promise<'js>> {\n        // Return ! WritableStreamClose(stream).\n        let (promise, _) = WritableStream::writable_stream_close(ctx, objects)?;\n        Ok(promise)\n    }\n\n    pub(crate) fn writable_stream_default_writer_close_with_error_propagation(\n        ctx: Ctx<'js>,\n        // Let stream be writer.[[stream]].\n        objects: WritableStreamObjects<'js, OwnedBorrowMut<'js, Self>>,\n    ) -> Result<Promise<'js>> {\n        // Let state be stream.[[state]].\n        // If ! WritableStreamCloseQueuedOrInFlight(stream) is true or state is \"closed\", return a promise resolved with undefined.\n        if objects.stream.writable_stream_close_queued_or_in_flight()\n            || matches!(objects.stream.state, WritableStreamState::Closed)\n        {\n            return Ok(objects\n                .stream\n                .promise_primordials\n                .promise_resolved_with_undefined\n                .clone());\n        }\n\n        // If state is \"errored\", return a promise rejected with stream.[[storedError]].\n        if let WritableStreamState::Errored(ref stored_error) = objects.stream.state {\n            return promise_rejected_with(\n                &objects.stream.promise_primordials,\n                stored_error.clone(),\n            );\n        }\n\n        // Return ! WritableStreamDefaultWriterClose(writer).\n        Self::writable_stream_default_writer_close(ctx, objects)\n    }\n\n    pub(crate) fn writable_stream_default_writer_release(\n        mut objects: WritableStreamObjects<'js, OwnedBorrowMut<'js, Self>>,\n    ) -> Result<()> {\n        // Let releasedError be a new TypeError.\n        let released_error: Value = objects.stream.constructor_type_error.call((\n            \"Writer was released and can no longer be used to monitor the stream's closedness\",\n        ))?;\n\n        // Perform ! WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, releasedError).\n        objects\n            .writer\n            .writable_stream_default_writer_ensure_ready_promise_rejected(\n                &objects.stream.promise_primordials,\n                released_error.clone(),\n            )?;\n        // Perform ! WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer, releasedError).\n        objects\n            .writer\n            .writable_stream_default_writer_ensure_closed_promise_rejected(\n                &objects.stream.promise_primordials,\n                released_error,\n            )?;\n\n        // Set stream.[[writer]] to undefined.\n        objects.stream.writer = None;\n        // Set writer.[[stream]] to undefined.\n        objects.writer.stream = None;\n\n        Ok(())\n    }\n\n    pub(crate) fn writable_stream_default_writer_write(\n        ctx: Ctx<'js>,\n        objects: WritableStreamObjects<'js, OwnedBorrowMut<'js, Self>>,\n        chunk: Value<'js>,\n    ) -> Result<Promise<'js>> {\n        // Let chunkSize be ! WritableStreamDefaultControllerGetChunkSize(controller, chunk).\n        let (chunk_size, mut objects) =\n            WritableStreamDefaultController::writable_stream_default_controller_get_chunk_size(\n                ctx.clone(),\n                objects,\n                chunk.clone(),\n            )?;\n\n        let stream_class = objects.stream.into_inner();\n        objects.stream = OwnedBorrowMut::from_class(stream_class.clone());\n\n        // If stream is not equal to writer.[[stream]], return a promise rejected with a TypeError exception.\n        if objects.writer.stream != Some(stream_class) {\n            return promise_rejected_with_constructor(\n                &objects.stream.constructor_type_error,\n                &objects.stream.promise_primordials,\n                \"Cannot write to a stream using a released writer\",\n            );\n        }\n\n        // Let state be stream.[[state]].\n        // If state is \"errored\", return a promise rejected with stream.[[storedError]].\n        if let WritableStreamState::Errored(ref stored_error) = objects.stream.state {\n            return promise_rejected_with(\n                &objects.stream.promise_primordials,\n                stored_error.clone(),\n            );\n        }\n\n        // If ! WritableStreamCloseQueuedOrInFlight(stream) is true or state is \"closed\", return a promise rejected with a TypeError exception indicating that the stream is closing or closed.\n        if objects.stream.writable_stream_close_queued_or_in_flight()\n            || matches!(objects.stream.state, WritableStreamState::Closed)\n        {\n            return promise_rejected_with_constructor(\n                &objects.stream.constructor_type_error,\n                &objects.stream.promise_primordials,\n                \"The stream is closing or closed and cannot be written to\",\n            );\n        }\n\n        // If state is \"erroring\", return a promise rejected with stream.[[storedError]].\n        if let WritableStreamState::Erroring(ref stored_error) = objects.stream.state {\n            return promise_rejected_with(\n                &objects.stream.promise_primordials,\n                stored_error.clone(),\n            );\n        }\n\n        // Let promise be ! WritableStreamAddWriteRequest(stream).\n        let promise = objects.stream.writable_stream_add_write_request(&ctx);\n        // Perform ! WritableStreamDefaultControllerWrite(controller, chunk, chunkSize).\n        WritableStreamDefaultController::writable_stream_default_controller_write(\n            ctx, objects, chunk, chunk_size,\n        )?;\n\n        // Return promise.\n        promise\n    }\n}\n\nimpl<'js> WritableStreamWriter<'js> for WritableStreamDefaultWriterOwned<'js> {\n    type Class = WritableStreamDefaultWriterClass<'js>;\n\n    fn with_writer<C>(\n        self,\n        ctx: C,\n        default: impl FnOnce(\n            C,\n            WritableStreamDefaultWriterOwned<'js>,\n        ) -> Result<(C, WritableStreamDefaultWriterOwned<'js>)>,\n        _: impl FnOnce(C) -> Result<C>,\n    ) -> Result<(C, Self)> {\n        default(ctx, self)\n    }\n\n    fn into_inner(self) -> Self::Class {\n        self.into_inner()\n    }\n\n    fn from_class(class: Self::Class) -> Self {\n        OwnedBorrowMut::from_class(class)\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/writable/mod.rs",
    "content": "mod default_controller;\nmod default_writer;\nmod objects;\nmod stream;\nmod writer;\n\npub(crate) use default_controller::{\n    WritableStreamDefaultController, WritableStreamDefaultControllerPrimordials,\n};\npub(crate) use default_writer::{WritableStreamDefaultWriter, WritableStreamDefaultWriterOwned};\npub(crate) use objects::{WritableStreamClassObjects, WritableStreamObjects};\npub(crate) use stream::{\n    WritableStream, WritableStreamClass, WritableStreamOwned, WritableStreamState,\n};\n"
  },
  {
    "path": "modules/llrt_stream_web/src/writable/objects.rs",
    "content": "use rquickjs::{class::OwnedBorrowMut, Class, Result};\n\nuse crate::writable::{\n    default_controller::{\n        WritableStreamDefaultControllerClass, WritableStreamDefaultControllerOwned,\n    },\n    default_writer::WritableStreamDefaultWriterOwned,\n    stream::{WritableStream, WritableStreamOwned},\n    writer::{UndefinedWriter, WritableStreamWriter},\n};\n\npub(crate) struct WritableStreamObjects<'js, W> {\n    pub(crate) stream: WritableStreamOwned<'js>,\n    pub(crate) controller: WritableStreamDefaultControllerOwned<'js>,\n    pub(crate) writer: W,\n}\n\npub(crate) struct WritableStreamClassObjects<'js, W: WritableStreamWriter<'js>> {\n    pub(crate) stream: Class<'js, WritableStream<'js>>,\n    pub(crate) controller: WritableStreamDefaultControllerClass<'js>,\n    pub(crate) writer: W::Class,\n}\n\nimpl<'js, W: WritableStreamWriter<'js>> Clone for WritableStreamClassObjects<'js, W> {\n    fn clone(&self) -> Self {\n        Self {\n            stream: self.stream.clone(),\n            controller: self.controller.clone(),\n            writer: self.writer.clone(),\n        }\n    }\n}\n\nimpl<'js, W: WritableStreamWriter<'js>> WritableStreamObjects<'js, W> {\n    pub(super) fn into_inner(self) -> WritableStreamClassObjects<'js, W> {\n        WritableStreamClassObjects {\n            stream: self.stream.into_inner(),\n            controller: self.controller.into_inner(),\n            writer: self.writer.into_inner(),\n        }\n    }\n\n    pub(crate) fn from_class(objects_class: WritableStreamClassObjects<'js, W>) -> Self {\n        Self {\n            stream: OwnedBorrowMut::from_class(objects_class.stream),\n            controller: OwnedBorrowMut::from_class(objects_class.controller),\n            writer: W::from_class(objects_class.writer),\n        }\n    }\n\n    pub(super) fn from_class_no_writer(\n        objects_class: WritableStreamClassObjects<'js, W>,\n    ) -> WritableStreamObjects<'js, UndefinedWriter> {\n        WritableStreamObjects {\n            stream: OwnedBorrowMut::from_class(objects_class.stream),\n            controller: OwnedBorrowMut::from_class(objects_class.controller),\n            writer: UndefinedWriter,\n        }\n    }\n\n    pub(super) fn with_writer(\n        mut self,\n        default: impl FnOnce(\n            WritableStreamObjects<'js, WritableStreamDefaultWriterOwned<'js>>,\n        ) -> Result<\n            WritableStreamObjects<'js, WritableStreamDefaultWriterOwned<'js>>,\n        >,\n        none: impl FnOnce(\n            WritableStreamObjects<'js, UndefinedWriter>,\n        ) -> Result<WritableStreamObjects<'js, UndefinedWriter>>,\n    ) -> Result<Self> {\n        ((self.stream, self.controller), self.writer) = self.writer.with_writer(\n            (self.stream, self.controller),\n            |(stream, controller), writer| {\n                let objects = default(WritableStreamObjects {\n                    stream,\n                    controller,\n                    writer,\n                })?;\n\n                Ok(((objects.stream, objects.controller), objects.writer))\n            },\n            |(stream, controller)| {\n                let objects = none(WritableStreamObjects {\n                    stream,\n                    controller,\n                    writer: UndefinedWriter,\n                })?;\n\n                Ok((objects.stream, objects.controller))\n            },\n        )?;\n\n        Ok(self)\n    }\n}\n\nimpl<'js, W: WritableStreamWriter<'js>> WritableStreamObjects<'js, W> {\n    pub(super) fn refresh_writer(\n        mut self,\n    ) -> WritableStreamObjects<'js, Option<WritableStreamDefaultWriterOwned<'js>>> {\n        drop(self.writer);\n        let writer = self.stream.writer_mut();\n        WritableStreamObjects {\n            stream: self.stream,\n            controller: self.controller,\n            writer,\n        }\n    }\n}\n\nimpl<'js> WritableStreamObjects<'js, UndefinedWriter> {\n    pub(super) fn from_stream(stream: WritableStreamOwned<'js>) -> Self {\n        let controller = OwnedBorrowMut::from_class(\n            stream\n                .controller\n                .clone()\n                .expect(\"WritableStream must have controller\"),\n        );\n\n        WritableStreamObjects {\n            stream,\n            controller,\n            writer: UndefinedWriter,\n        }\n    }\n\n    pub(super) fn from_controller(controller: WritableStreamDefaultControllerOwned<'js>) -> Self {\n        let stream = OwnedBorrowMut::from_class(controller.stream.clone());\n\n        WritableStreamObjects {\n            stream,\n            controller,\n            writer: UndefinedWriter,\n        }\n    }\n}\n\nimpl<'js> WritableStreamObjects<'js, WritableStreamDefaultWriterOwned<'js>> {\n    pub(super) fn from_writer(writer: WritableStreamDefaultWriterOwned<'js>) -> Self {\n        let stream = OwnedBorrowMut::from_class(\n            writer\n                .stream\n                .clone()\n                .expect(\"WritableStreamDefaultWriter must have a stream\"),\n        );\n\n        let controller = OwnedBorrowMut::from_class(\n            stream\n                .controller\n                .clone()\n                .expect(\"WritableStreamDefaultWriter stream must have a controller\"),\n        );\n\n        WritableStreamObjects {\n            stream,\n            controller,\n            writer,\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/writable/stream/mod.rs",
    "content": "use std::collections::VecDeque;\n\nuse llrt_abort::AbortController;\nuse llrt_utils::{\n    option::{Null, Undefined},\n    primordials::{BasePrimordials, Primordial},\n};\nuse rquickjs::{\n    class::{OwnedBorrowMut, Trace, Tracer},\n    function::Constructor,\n    prelude::{Opt, This},\n    Class, Ctx, Exception, JsLifetime, Object, Promise, Result, Value,\n};\n\nuse crate::{\n    queuing_strategy::QueuingStrategy,\n    utils::{\n        promise::{\n            promise_rejected_with_constructor, upon_promise, PromisePrimordials, ResolveablePromise,\n        },\n        UnwrapOrUndefined,\n    },\n    writable::{\n        default_controller::{\n            WritableStreamDefaultController, WritableStreamDefaultControllerClass,\n        },\n        default_writer::{\n            WritableStreamDefaultWriter, WritableStreamDefaultWriterClass,\n            WritableStreamDefaultWriterOwned,\n        },\n        objects::WritableStreamObjects,\n        writer::WritableStreamWriter,\n    },\n};\nuse sink::UnderlyingSink;\n\npub(super) mod sink;\n\n#[rquickjs::class]\n#[derive(JsLifetime)]\npub struct WritableStream<'js> {\n    pub(super) backpressure: bool,\n    close_request: Option<ResolveablePromise<'js>>,\n    pub(crate) controller: Option<WritableStreamDefaultControllerClass<'js>>,\n    pub in_flight_write_request: Option<ResolveablePromise<'js>>,\n    in_flight_close_request: Option<ResolveablePromise<'js>>,\n    pending_abort_request: Option<PendingAbortRequest<'js>>,\n    pub(crate) state: WritableStreamState<'js>,\n    pub(crate) writer: Option<WritableStreamDefaultWriterClass<'js>>,\n    write_requests: VecDeque<ResolveablePromise<'js>>,\n    pub(super) constructor_type_error: Constructor<'js>,\n    pub(crate) promise_primordials: PromisePrimordials<'js>,\n}\n\nimpl<'js> Trace<'js> for WritableStream<'js> {\n    fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {\n        self.close_request.trace(tracer);\n        self.controller.trace(tracer);\n        self.in_flight_write_request.trace(tracer);\n        self.in_flight_close_request.trace(tracer);\n        self.pending_abort_request.trace(tracer);\n        self.state.trace(tracer);\n        self.writer.trace(tracer);\n        self.write_requests.trace(tracer);\n        self.constructor_type_error.trace(tracer);\n        self.promise_primordials.trace(tracer);\n    }\n}\n\npub(crate) type WritableStreamClass<'js> = Class<'js, WritableStream<'js>>;\npub(crate) type WritableStreamOwned<'js> = OwnedBorrowMut<'js, WritableStream<'js>>;\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl<'js> WritableStream<'js> {\n    // constructor(optional object underlyingSink, optional QueuingStrategy strategy = {});\n    #[qjs(constructor)]\n    fn new(\n        ctx: Ctx<'js>,\n        underlying_sink: Opt<Undefined<Object<'js>>>,\n        queuing_strategy: Opt<Undefined<QueuingStrategy<'js>>>,\n    ) -> Result<Class<'js, Self>> {\n        // If underlyingSink is missing, set it to null.\n        let underlying_sink = Null(underlying_sink.0);\n\n        // Let underlyingSinkDict be underlyingSink, converted to an IDL value of type UnderlyingSink.\n        let underlying_sink_dict = match underlying_sink {\n            Null(None) | Null(Some(Undefined(None))) => UnderlyingSink::default(),\n            Null(Some(Undefined(Some(ref obj)))) => UnderlyingSink::from_object(obj.clone())?,\n        };\n\n        // If underlyingSinkDict[\"type\"] exists, throw a RangeError exception.\n        if underlying_sink_dict.r#type.is_some() {\n            return Err(Exception::throw_range(&ctx, \"Invalid type is specified\"));\n        }\n\n        // Perform ! InitializeWritableStream(this).\n        let stream_class = Class::instance(\n            ctx.clone(),\n            Self {\n                // Set stream.[[state]] to \"writable\".\n                state: WritableStreamState::Writable,\n                // Set stream.[[storedError]], stream.[[writer]], stream.[[controller]], stream.[[inFlightWriteRequest]], stream.[[closeRequest]], stream.[[inFlightCloseRequest]], and stream.[[pendingAbortRequest]] to undefined.\n                writer: None,\n                controller: None,\n                in_flight_write_request: None,\n                close_request: None,\n                in_flight_close_request: None,\n                pending_abort_request: None,\n                // Set stream.[[writeRequests]] to a new empty list.\n                write_requests: VecDeque::new(),\n                // Set stream.[[backpressure]] to false.\n                backpressure: false,\n                constructor_type_error: BasePrimordials::get(&ctx)?.constructor_type_error.clone(),\n                promise_primordials: PromisePrimordials::get(&ctx)?.clone(),\n            },\n        )?;\n        let stream = OwnedBorrowMut::from_class(stream_class.clone());\n        let queuing_strategy = queuing_strategy.0.and_then(|qs| qs.0);\n\n        // Let sizeAlgorithm be ! ExtractSizeAlgorithm(strategy).\n        let size_algorithm = QueuingStrategy::extract_size_algorithm(queuing_strategy.as_ref());\n\n        // Let highWaterMark be ? ExtractHighWaterMark(strategy, 1).\n        let high_water_mark =\n            QueuingStrategy::extract_high_water_mark(&ctx, queuing_strategy, 1.0)?;\n\n        // Perform ? SetUpWritableStreamDefaultControllerFromUnderlyingSink(this, underlyingSink, underlyingSinkDict, highWaterMark, sizeAlgorithm).\n        WritableStreamDefaultController::set_up_writable_stream_default_controller_from_underlying_sink(ctx, stream, underlying_sink, underlying_sink_dict, high_water_mark, size_algorithm)?;\n\n        Ok(stream_class)\n    }\n\n    // readonly attribute boolean locked;\n    #[qjs(get)]\n    fn locked(&self) -> bool {\n        // Return ! IsWritableStreamLocked(this).\n        self.is_writable_stream_locked()\n    }\n\n    fn abort(\n        ctx: Ctx<'js>,\n        stream: This<OwnedBorrowMut<'js, Self>>,\n        reason: Opt<Value<'js>>,\n    ) -> Result<Promise<'js>> {\n        if stream.is_writable_stream_locked() {\n            // If ! IsWritableStreamLocked(this) is true, return a promise rejected with a TypeError exception.\n            return promise_rejected_with_constructor(\n                &stream.constructor_type_error,\n                &stream.promise_primordials,\n                \"Cannot abort a stream that already has a writer\",\n            );\n        }\n\n        let objects = WritableStreamObjects::from_stream(stream.0);\n\n        // Return ! WritableStreamAbort(this, reason).\n        let (promise, _) = Self::writable_stream_abort(ctx.clone(), objects, reason.0)?;\n\n        Ok(promise)\n    }\n\n    fn close(ctx: Ctx<'js>, stream: This<OwnedBorrowMut<'js, Self>>) -> Result<Promise<'js>> {\n        if stream.is_writable_stream_locked() {\n            // If ! IsWritableStreamLocked(this) is true, return a promise rejected with a TypeError exception.\n            return promise_rejected_with_constructor(\n                &stream.constructor_type_error,\n                &stream.promise_primordials,\n                \"Cannot close a stream that already has a writer\",\n            );\n        }\n\n        if Self::writable_stream_close_queued_or_in_flight(&stream.0) {\n            // If ! WritableStreamCloseQueuedOrInFlight(this) is true, return a promise rejected with a TypeError exception.\n            return promise_rejected_with_constructor(\n                &stream.constructor_type_error,\n                &stream.promise_primordials,\n                \"Cannot close an already-closing stream\",\n            );\n        }\n\n        let objects = WritableStreamObjects::from_stream(stream.0);\n\n        // Return ! WritableStreamClose(this).\n        let (promise, _) = Self::writable_stream_close(ctx.clone(), objects)?;\n\n        Ok(promise)\n    }\n\n    fn get_writer(\n        ctx: Ctx<'js>,\n        stream: This<OwnedBorrowMut<'js, Self>>,\n    ) -> Result<WritableStreamDefaultWriterClass<'js>> {\n        // Return ? AcquireWritableStreamDefaultWriter(this).\n        let (_, writer) =\n            WritableStreamDefaultWriter::acquire_writable_stream_default_writer(&ctx, stream.0)?;\n\n        Ok(writer)\n    }\n}\n\nimpl<'js> WritableStream<'js> {\n    pub(crate) fn is_writable_stream_locked(&self) -> bool {\n        if self.writer.is_none() {\n            // If stream.[[writer]] is undefined, return false.\n            false\n        } else {\n            // Return true.\n            true\n        }\n    }\n\n    pub(crate) fn writable_stream_abort<W: WritableStreamWriter<'js>>(\n        ctx: Ctx<'js>,\n        mut objects: WritableStreamObjects<'js, W>,\n        mut reason: Option<Value<'js>>,\n    ) -> Result<(Promise<'js>, WritableStreamObjects<'js, W>)> {\n        // If stream.[[state]] is \"closed\" or \"errored\", return a promise resolved with undefined.\n        if matches!(\n            objects.stream.state,\n            WritableStreamState::Closed | WritableStreamState::Errored(_)\n        ) {\n            return Ok((\n                objects\n                    .stream\n                    .promise_primordials\n                    .promise_resolved_with_undefined\n                    .clone(),\n                objects,\n            ));\n        }\n\n        // Signal abort on stream.[[controller]].[[abortController]] with reason.\n        {\n            // this executes user code, so we should ensure we hold no locks\n            let abort_controller = objects.controller.abort_controller.clone();\n            let objects_class = objects.into_inner();\n            AbortController::abort(ctx.clone(), This(abort_controller), Opt(reason.clone()))?;\n            objects = WritableStreamObjects::from_class(objects_class);\n        }\n\n        // Let state be stream.[[state]].\n        // If state is \"closed\" or \"errored\", return a promise resolved with undefined.\n        if matches!(\n            objects.stream.state,\n            WritableStreamState::Closed | WritableStreamState::Errored(_)\n        ) {\n            return Ok((\n                objects\n                    .stream\n                    .promise_primordials\n                    .promise_resolved_with_undefined\n                    .clone(),\n                objects,\n            ));\n        }\n\n        // If stream.[[pendingAbortRequest]] is not undefined, return stream.[[pendingAbortRequest]]'s promise.\n        match objects.stream.pending_abort_request {\n            None => {},\n            Some(ref pending_abort_request) => {\n                return Ok((pending_abort_request.promise.promise.clone(), objects))\n            },\n        }\n\n        let was_already_erroring = match objects.stream.state {\n            // If state is \"erroring\",\n            // Set wasAlreadyErroring to true.\n            // Set reason to undefined.\n            WritableStreamState::Erroring(_) => {\n                reason = None;\n                true\n            },\n            // Let wasAlreadyErroring be false.\n            _ => false,\n        };\n\n        // Let promise be a new promise.\n        let promise = ResolveablePromise::new(&ctx)?;\n\n        let reason = reason.unwrap_or_undefined(&ctx);\n\n        // Set stream.[[pendingAbortRequest]] to a new pending abort request whose promise is promise, reason is reason, and was already erroring is wasAlreadyErroring.\n        objects.stream.pending_abort_request = Some(PendingAbortRequest {\n            promise: promise.clone(),\n            reason: reason.clone(),\n            was_already_erroring,\n        });\n\n        // If wasAlreadyErroring is false, perform ! WritableStreamStartErroring(stream, reason).\n        if !was_already_erroring {\n            objects = Self::writable_stream_start_erroring(ctx, objects, reason)?;\n        }\n\n        Ok((promise.promise.clone(), objects))\n    }\n\n    pub(super) fn writable_stream_close<W: WritableStreamWriter<'js>>(\n        ctx: Ctx<'js>,\n        mut objects: WritableStreamObjects<'js, W>,\n    ) -> Result<(Promise<'js>, WritableStreamObjects<'js, W>)> {\n        // Let state be stream.[[state]].\n        // If state is \"closed\" or \"errored\", return a promise rejected with a TypeError exception.\n        if matches!(\n            objects.stream.state,\n            WritableStreamState::Closed | WritableStreamState::Errored(_)\n        ) {\n            return Ok((\n                promise_rejected_with_constructor::<rquickjs::Error>(\n                    &objects.stream.constructor_type_error,\n                    &objects.stream.promise_primordials,\n                    \"The stream is not in the writable state and cannot be closed\",\n                )?,\n                objects,\n            ));\n        }\n\n        // Let promise be a new promise.\n        let promise = ResolveablePromise::new(&ctx)?;\n        // Set stream.[[closeRequest]] to promise.\n        objects.stream.close_request = Some(promise.clone());\n\n        // Let writer be stream.[[writer]].\n        // If writer is not undefined, and stream.[[backpressure]] is true, and state is \"writable\", resolve writer.[[readyPromise]] with undefined.\n        objects = objects.with_writer(\n            |objects| {\n                if objects.stream.backpressure\n                    && matches!(objects.stream.state, WritableStreamState::Writable)\n                {\n                    let () = objects.writer.ready_promise.resolve_undefined()?;\n                }\n                Ok(objects)\n            },\n            Ok,\n        )?;\n\n        // Perform ! WritableStreamDefaultControllerClose(stream.[[controller]]).\n        objects = WritableStreamDefaultController::writable_stream_default_controller_close(\n            ctx, objects,\n        )?;\n\n        // Return promise.\n        Ok((promise.promise.clone(), objects))\n    }\n\n    pub(super) fn writable_stream_start_erroring<W: WritableStreamWriter<'js>>(\n        ctx: Ctx<'js>,\n        // Let controller be stream.[[controller]].\n        // Let writer be stream.[[writer]].\n        mut objects: WritableStreamObjects<'js, W>,\n        reason: Value<'js>,\n    ) -> Result<WritableStreamObjects<'js, W>> {\n        // Set stream.[[state]] to \"erroring\".\n        // Set stream.[[storedError]] to reason.\n        objects.stream.state = WritableStreamState::Erroring(reason.clone());\n\n        // If writer is not undefined, perform ! WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, reason).\n        objects = objects.with_writer(\n            |mut objects| {\n                objects\n                    .writer\n                    .writable_stream_default_writer_ensure_ready_promise_rejected(\n                        &objects.stream.promise_primordials,\n                        reason.clone(),\n                    )?;\n                Ok(objects)\n            },\n            Ok,\n        )?;\n\n        // If ! WritableStreamHasOperationMarkedInFlight(stream) is false and controller.[[started]] is true, perform ! WritableStreamFinishErroring(stream).\n        if !objects\n            .stream\n            .writable_stream_has_operation_marked_in_flight()\n            && objects.controller.started\n        {\n            objects = Self::writable_stream_finish_erroring(ctx, objects, reason)?;\n        }\n\n        Ok(objects)\n    }\n\n    pub(super) fn writable_stream_finish_erroring<W: WritableStreamWriter<'js>>(\n        ctx: Ctx<'js>,\n        mut objects: WritableStreamObjects<'js, W>,\n        // Let storedError be stream.[[storedError]].\n        stored_error: Value<'js>,\n    ) -> Result<WritableStreamObjects<'js, W>> {\n        // Set stream.[[state]] to \"errored\".\n        objects.stream.state = WritableStreamState::Errored(stored_error.clone());\n\n        // Perform ! stream.[[controller]].[[ErrorSteps]]().\n        objects.controller.error_steps();\n\n        // For each writeRequest of stream.[[writeRequests]]:\n        for write_request in &mut objects.stream.write_requests {\n            let () = write_request.reject(stored_error.clone())?;\n        }\n\n        // Set stream.[[writeRequests]] to an empty list.\n        objects.stream.write_requests.clear();\n\n        // Let abortRequest be stream.[[pendingAbortRequest]].\n        // Set stream.[[pendingAbortRequest]] to undefined.\n        let abort_request = if let Some(pending_abort_request) =\n            objects.stream.pending_abort_request.take()\n        {\n            pending_abort_request\n        } else {\n            // If stream.[[pendingAbortRequest]] is undefined,\n            // Perform ! WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream).\n            objects =\n                WritableStream::writable_stream_reject_close_and_closed_promise_if_needed(objects)?;\n            // Return.\n            return Ok(objects);\n        };\n\n        // If abortRequest’s was already erroring is true,\n        if abort_request.was_already_erroring {\n            // Reject abortRequest’s promise with storedError.\n            let () = abort_request.promise.reject(stored_error.clone())?;\n\n            // Perform ! WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream).\n            objects =\n                WritableStream::writable_stream_reject_close_and_closed_promise_if_needed(objects)?;\n\n            // Return.\n            return Ok(objects);\n        }\n\n        // Let promise be ! stream.[[controller]].[[AbortSteps]](abortRequest’s reason).\n        let (promise, objects) =\n            WritableStreamDefaultController::abort_steps(&ctx, objects, abort_request.reason)?;\n\n        let objects_class = objects.into_inner();\n\n        // Upon fulfillment of promise,\n        let _ = upon_promise::<Value<'js>, _>(ctx.clone(), promise, {\n            let objects_class = objects_class.clone();\n            move |_, result| {\n                let objects =\n                    WritableStreamObjects::from_class_no_writer(objects_class).refresh_writer();\n                match result {\n                    // Upon fulfillment of promise,\n                    Ok(_) => {\n                        // Resolve abortRequest’s promise with undefined.\n                        let () = abort_request.promise.resolve_undefined()?;\n                        // Perform ! WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream).\n                        WritableStream::writable_stream_reject_close_and_closed_promise_if_needed(\n                            objects,\n                        )?;\n                        Ok(())\n                    },\n                    // Upon rejection of promise with reason reason,\n                    Err(reason) => {\n                        // Reject abortRequest’s promise with reason.\n                        let () = abort_request.promise.reject(reason)?;\n                        // Perform ! WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream).\n                        WritableStream::writable_stream_reject_close_and_closed_promise_if_needed(\n                            objects,\n                        )?;\n                        Ok(())\n                    },\n                }\n            }\n        })?;\n\n        Ok(WritableStreamObjects::from_class(objects_class))\n    }\n\n    fn writable_stream_reject_close_and_closed_promise_if_needed<W: WritableStreamWriter<'js>>(\n        // Let writer be stream.[[writer]].\n        mut objects: WritableStreamObjects<'js, W>,\n    ) -> Result<WritableStreamObjects<'js, W>> {\n        // If stream.[[closeRequest]] is not undefined,\n        if let Some(ref close_request) = objects.stream.close_request {\n            // Reject stream.[[closeRequest]] with stream.[[storedError]].\n            let () = close_request.reject(objects.stream.stored_error())?;\n            // Set stream.[[closeRequest]] to undefined.\n            objects.stream.close_request = None;\n        }\n\n        // If writer is not undefined,\n        objects.with_writer(\n            |objects| {\n                // Reject writer.[[closedPromise]] with stream.[[storedError]].\n                let () = objects\n                    .writer\n                    .closed_promise\n                    .reject(objects.stream.stored_error())?;\n\n                // Set writer.[[closedPromise]].[[PromiseIsHandled]] to true.\n                objects.writer.closed_promise.set_is_handled()?;\n\n                Ok(objects)\n            },\n            Ok,\n        )\n    }\n\n    pub(super) fn writable_stream_mark_first_write_request_in_flight(&mut self) {\n        // Let writeRequest be stream.[[writeRequests]][0].\n        // Remove writeRequest from stream.[[writeRequests]].\n        let write_request = self.write_requests.pop_front().expect(\"writable_stream_mark_first_write_request_in_flight must be called with non-empty write requests\");\n        // Set stream.[[inFlightWriteRequest]] to writeRequest.\n        self.in_flight_write_request = Some(write_request);\n    }\n\n    pub(super) fn writable_stream_mark_close_request_in_flight(&mut self) {\n        // Set stream.[[inFlightCloseRequest]] to stream.[[closeRequest]].\n        // Set stream.[[closeRequest]] to undefined.\n        self.in_flight_close_request =\n            Some(self.close_request.take().expect(\n                \"writable_stream_mark_close_request_in_flight called without close request\",\n            ))\n    }\n\n    fn writable_stream_has_operation_marked_in_flight(&self) -> bool {\n        if self.in_flight_write_request.is_none() && self.in_flight_close_request.is_none() {\n            // If stream.[[inFlightWriteRequest]] is undefined and stream.[[inFlightCloseRequest]] is undefined, return false.\n            false\n        } else {\n            // Return true.\n            true\n        }\n    }\n\n    pub(crate) fn writable_stream_close_queued_or_in_flight(&self) -> bool {\n        if self.close_request.is_none() && self.in_flight_close_request.is_none() {\n            // If stream.[[closeRequest]] is undefined and stream.[[inFlightCloseRequest]] is undefined, return false.\n            false\n        } else {\n            // Return true.\n            true\n        }\n    }\n\n    pub(super) fn writable_stream_add_write_request(\n        &mut self,\n        ctx: &Ctx<'js>,\n    ) -> Result<Promise<'js>> {\n        // Let promise be a new promise.\n        let promise = ResolveablePromise::new(ctx)?;\n        // Append promise to stream.[[writeRequests]].\n        self.write_requests.push_back(promise.clone());\n        Ok(promise.promise.clone())\n    }\n\n    pub(super) fn writable_stream_finish_in_flight_write_with_error<\n        W: WritableStreamWriter<'js>,\n    >(\n        ctx: Ctx<'js>,\n        mut objects: WritableStreamObjects<'js, W>,\n        error: Value<'js>,\n    ) -> Result<()> {\n        // Reject stream.[[inFlightWriteRequest]] with error.\n        // Set stream.[[inFlightWriteRequest]] to undefined.\n        objects.stream.in_flight_write_request.take().expect(\"writable_stream_finish_in_flight_write_with_error called without in flight write request\").reject(error.clone())?;\n\n        // Perform ! WritableStreamDealWithRejection(stream, error).\n        Self::writable_stream_deal_with_rejection(ctx, objects, error)?;\n\n        Ok(())\n    }\n\n    pub(super) fn writable_stream_finish_in_flight_close_with_error<\n        W: WritableStreamWriter<'js>,\n    >(\n        ctx: Ctx<'js>,\n        mut objects: WritableStreamObjects<'js, W>,\n        error: Value<'js>,\n    ) -> Result<()> {\n        // Reject stream.[[inFlightCloseRequest]] with error.\n        // Set stream.[[inFlightCloseRequest]] to undefined.\n        objects.stream.in_flight_close_request.take().expect(\"writable_stream_finish_in_flight_close_with_error called without in flight close request\").reject(error.clone())?;\n\n        // Assert: stream.[[state]] is \"writable\" or \"erroring\".\n\n        // If stream.[[pendingAbortRequest]] is not undefined,\n        if let Some(pending_abort_request) = objects.stream.pending_abort_request.take() {\n            // Reject stream.[[pendingAbortRequest]]'s promise with error.\n            // Set stream.[[pendingAbortRequest]] to undefined.\n            pending_abort_request.promise.reject(error.clone())?\n        }\n\n        // Perform ! WritableStreamDealWithRejection(stream, error).\n        Self::writable_stream_deal_with_rejection(ctx, objects, error)?;\n\n        Ok(())\n    }\n\n    pub(super) fn writable_stream_deal_with_rejection<W: WritableStreamWriter<'js>>(\n        ctx: Ctx<'js>,\n        objects: WritableStreamObjects<'js, W>,\n        error: Value<'js>,\n    ) -> Result<WritableStreamObjects<'js, W>> {\n        // Let state be stream.[[state]].\n        match &objects.stream.state {\n            // If state is \"writable\",\n            WritableStreamState::Writable => {\n                // Perform ! WritableStreamStartErroring(stream, error).\n                Self::writable_stream_start_erroring(ctx, objects, error)\n            },\n            WritableStreamState::Erroring(ref stored_error) => {\n                let stored_error = stored_error.clone();\n                // Perform ! WritableStreamFinishErroring(stream).\n                Self::writable_stream_finish_erroring(ctx, objects, stored_error)\n            },\n            other => panic!(\"WritableStreamDealWithRejection must be called in state 'writable' or 'erroring', found {other:?}\"),\n        }\n    }\n\n    pub(super) fn writable_stream_finish_in_flight_write(&mut self) -> Result<()> {\n        // Resolve stream.[[inFlightWriteRequest]] with undefined.\n        // Set stream.[[inFlightWriteRequest]] to undefined.\n        self.in_flight_write_request\n            .take()\n            .expect(\"writable_stream_finish_in_flight_write called without in flight write request\")\n            .resolve_undefined()\n    }\n\n    pub(super) fn writable_stream_finish_in_flight_close<W: WritableStreamWriter<'js>>(\n        // Let writer be stream.[[writer]].\n        mut objects: WritableStreamObjects<'js, W>,\n    ) -> Result<WritableStreamObjects<'js, W>> {\n        // Assert: stream.[[inFlightCloseRequest]] is not undefined.\n\n        // Resolve stream.[[inFlightCloseRequest]] with undefined.\n        // Set stream.[[inFlightCloseRequest]] to undefined.\n        objects\n            .stream\n            .in_flight_close_request\n            .take()\n            .expect(\"writable_stream_finish_in_flight_close called without in flight close request\")\n            .resolve_undefined()?;\n\n        // Let state be stream.[[state]].\n        // If state is \"erroring\",\n        if let WritableStreamState::Erroring(_) = objects.stream.state {\n            // Set stream.[[storedError]] to undefined.\n            // (implicitly covered by change to Closed below)\n\n            // If stream.[[pendingAbortRequest]] is not undefined,\n            if let Some(pending_abort_request) = objects.stream.pending_abort_request.take() {\n                // Resolve stream.[[pendingAbortRequest]]'s promise with undefined.\n                // Set stream.[[pendingAbortRequest]] to undefined.\n                pending_abort_request.promise.resolve_undefined()?;\n            }\n        }\n\n        // Set stream.[[state]] to \"closed\".\n        objects.stream.state = WritableStreamState::Closed;\n\n        // If writer is not undefined, resolve writer.[[closedPromise]] with undefined.\n        objects.with_writer(\n            |objects| {\n                objects.writer.closed_promise.resolve_undefined()?;\n\n                Ok(objects)\n            },\n            Ok,\n        )\n    }\n\n    pub(super) fn writable_stream_update_backpressure<W: WritableStreamWriter<'js>>(\n        ctx: Ctx<'js>,\n        // Let writer be stream.[[writer]].\n        mut objects: WritableStreamObjects<'js, W>,\n        backpressure: bool,\n    ) -> Result<WritableStreamObjects<'js, W>> {\n        // If writer is not undefined and backpressure is not stream.[[backpressure]],\n        objects = objects.with_writer(\n            |mut objects| {\n                if backpressure != objects.stream.backpressure {\n                    if backpressure {\n                        // If backpressure is true, set writer.[[readyPromise]] to a new promise.\n                        objects.writer.ready_promise = ResolveablePromise::new(&ctx)?;\n                    } else {\n                        // Otherwise,\n                        // Resolve writer.[[readyPromise]] with undefined.\n                        objects.writer.ready_promise.resolve_undefined()?\n                    }\n                }\n\n                Ok(objects)\n            },\n            Ok,\n        )?;\n\n        // Set stream.[[backpressure]] to backpressure.\n        objects.stream.backpressure = backpressure;\n\n        Ok(objects)\n    }\n\n    pub(super) fn writer_mut(&mut self) -> Option<WritableStreamDefaultWriterOwned<'js>> {\n        self.writer.clone().map(OwnedBorrowMut::from_class)\n    }\n\n    pub(crate) fn stored_error(&self) -> Option<Value<'js>> {\n        match self.state {\n            WritableStreamState::Erroring(ref stored_error)\n            | WritableStreamState::Errored(ref stored_error) => Some(stored_error.clone()),\n            _ => None,\n        }\n    }\n}\n\n#[derive(Debug, Trace, Clone, JsLifetime)]\npub(crate) enum WritableStreamState<'js> {\n    Writable,\n    Closed,\n    Erroring(Value<'js>),\n    Errored(Value<'js>),\n}\n\n#[derive(JsLifetime, Trace)]\nstruct PendingAbortRequest<'js> {\n    promise: ResolveablePromise<'js>,\n    reason: Value<'js>,\n    was_already_erroring: bool,\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/writable/stream/sink.rs",
    "content": "use rquickjs::{Function, Object, Result, Value};\n\nuse crate::utils::ValueOrUndefined;\n\n#[derive(Default)]\npub struct UnderlyingSink<'js> {\n    // callback UnderlyingSinkStartCallback = any (WritableStreamDefaultController controller);\n    pub start: Option<Function<'js>>,\n    // callback UnderlyingSinkWriteCallback = Promise<undefined> (any chunk, WritableStreamDefaultController controller);\n    pub write: Option<Function<'js>>,\n    // callback UnderlyingSinkCloseCallback = Promise<undefined> ();\n    pub close: Option<Function<'js>>,\n    // callback UnderlyingSinkAbortCallback = Promise<undefined> (optional any reason);\n    pub abort: Option<Function<'js>>,\n    pub r#type: Option<Value<'js>>,\n}\n\nimpl<'js> UnderlyingSink<'js> {\n    pub fn from_object(obj: Object<'js>) -> Result<Self> {\n        let start = obj.get_value_or_undefined::<_, _>(\"start\")?;\n        let write = obj.get_value_or_undefined::<_, _>(\"write\")?;\n        let close = obj.get_value_or_undefined::<_, _>(\"close\")?;\n        let abort = obj.get_value_or_undefined::<_, _>(\"abort\")?;\n        let r#type = obj.get_value_or_undefined::<_, _>(\"type\")?;\n\n        Ok(Self {\n            start,\n            write,\n            close,\n            abort,\n            r#type,\n        })\n    }\n}\n"
  },
  {
    "path": "modules/llrt_stream_web/src/writable/writer.rs",
    "content": "use rquickjs::{class::Trace, Result};\n\nuse crate::writable::default_writer::WritableStreamDefaultWriterOwned;\n\npub(crate) trait WritableStreamWriter<'js>: Sized + 'js {\n    type Class: Clone + Trace<'js>;\n\n    fn with_writer<C>(\n        self,\n        ctx: C,\n        default: impl FnOnce(\n            C,\n            WritableStreamDefaultWriterOwned<'js>,\n        ) -> Result<(C, WritableStreamDefaultWriterOwned<'js>)>,\n        none: impl FnOnce(C) -> Result<C>,\n    ) -> Result<(C, Self)>;\n\n    fn into_inner(self) -> Self::Class;\n\n    fn from_class(class: Self::Class) -> Self;\n}\n\n#[derive(Clone, Trace)]\npub(super) struct UndefinedWriter;\n\nimpl<'js> WritableStreamWriter<'js> for UndefinedWriter {\n    type Class = UndefinedWriter;\n\n    fn with_writer<C>(\n        self,\n        ctx: C,\n        _: impl FnOnce(\n            C,\n            WritableStreamDefaultWriterOwned<'js>,\n        ) -> Result<(C, WritableStreamDefaultWriterOwned<'js>)>,\n        none: impl FnOnce(C) -> Result<C>,\n    ) -> Result<(C, Self)> {\n        Ok((none(ctx)?, self))\n    }\n\n    fn into_inner(self) -> Self::Class {\n        self\n    }\n\n    fn from_class(class: Self::Class) -> Self {\n        class\n    }\n}\n\nimpl<'js, T: WritableStreamWriter<'js>> WritableStreamWriter<'js> for Option<T> {\n    type Class = Option<<T as WritableStreamWriter<'js>>::Class>;\n\n    fn with_writer<C>(\n        self,\n        mut ctx: C,\n        default: impl FnOnce(\n            C,\n            WritableStreamDefaultWriterOwned<'js>,\n        ) -> Result<(C, WritableStreamDefaultWriterOwned<'js>)>,\n        none: impl FnOnce(C) -> Result<C>,\n    ) -> Result<(C, Self)> {\n        match self {\n            Some(mut writer) => {\n                (ctx, writer) = writer.with_writer(ctx, default, none)?;\n                Ok((ctx, Some(writer)))\n            },\n            None => Ok((none(ctx)?, None)),\n        }\n    }\n\n    fn into_inner(self) -> Self::Class {\n        self.map(WritableStreamWriter::into_inner)\n    }\n\n    fn from_class(class: Self::Class) -> Self {\n        class.map(WritableStreamWriter::from_class)\n    }\n}\n"
  },
  {
    "path": "modules/llrt_string_decoder/Cargo.toml",
    "content": "[package]\nname = \"llrt_string_decoder\"\ndescription = \"LLRT Module string_decoder\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\nreadme = \"README.md\"\n\n[lib]\nname = \"llrt_string_decoder\"\npath = \"src/lib.rs\"\n\n[dependencies]\nllrt_buffer = { version = \"0.8.1-beta\", path = \"../llrt_buffer\" }\nllrt_encoding = { version = \"0.8.1-beta\", path = \"../../libs/llrt_encoding\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", default-features = false }\n\n[dev-dependencies]\nllrt_test = { path = \"../../libs/llrt_test\" }\ntokio = { version = \"1\", features = [\"test-util\"], default-features = false }\n"
  },
  {
    "path": "modules/llrt_string_decoder/src/lib.rs",
    "content": "use llrt_utils::module::{export_default, ModuleInfo};\nuse rquickjs::{\n    module::{Declarations, Exports, ModuleDef},\n    Class, Ctx, Result,\n};\n\nuse self::string_decoder::StringDecoder;\n\nmod string_decoder;\n\npub struct StringDecoderModule;\n\nimpl ModuleDef for StringDecoderModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(stringify!(StringDecoder))?;\n        declare.declare(\"default\")?;\n\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        export_default(ctx, exports, |default| {\n            Class::<StringDecoder>::define(default)?;\n            Ok(())\n        })?;\n\n        Ok(())\n    }\n}\n\nimpl From<StringDecoderModule> for ModuleInfo<StringDecoderModule> {\n    fn from(val: StringDecoderModule) -> Self {\n        ModuleInfo {\n            name: \"string_decoder\",\n            module: val,\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use llrt_test::{call_test, test_async_with, ModuleEvaluator};\n\n    use super::*;\n\n    #[tokio::test]\n    async fn test_utf_8() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                llrt_buffer::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<StringDecoderModule>(ctx.clone(), \"string_decoder\")\n                    .await\n                    .unwrap();\n\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { StringDecoder } from 'string_decoder';\n\n                        export async function test() {\n                            const decoder = new StringDecoder('utf-8');\n\n                            const cent = Buffer.from([0xC2, 0xA2]);\n\n                            return decoder.write(cent);\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<String, _>(&ctx, &module, ()).await;\n                assert_eq!(result, \"¢\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_utf8_byte_by_byte() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                llrt_buffer::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<StringDecoderModule>(ctx.clone(), \"string_decoder\")\n                    .await\n                    .unwrap();\n\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { StringDecoder } from 'string_decoder';\n\n                        export async function test() {\n                            const decoder = new StringDecoder('utf8');\n                            const data = Buffer.from(\"☃💩\");\n\n                            let res = \"\";\n                            for (let i = 0; i < data.length; i++) {\n                                res += decoder.write(data.slice(i, i + 1));\n                            }\n                            res += decoder.end();\n\n                            return res;\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<String, _>(&ctx, &module, ()).await;\n                assert_eq!(result, \"☃💩\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_base64() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                llrt_buffer::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<StringDecoderModule>(ctx.clone(), \"string_decoder\")\n                    .await\n                    .unwrap();\n\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { StringDecoder } from 'string_decoder';\n\n                        export async function test() {\n                            const decoder = new StringDecoder('base64');\n                            let res = \"\";\n                            res += decoder.write(Buffer.of(0x61));\n                            res += decoder.end();\n                            res += decoder.write(Buffer.of());\n                            res += decoder.end();\n                            return res;\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<String, _>(&ctx, &module, ()).await;\n                assert_eq!(result, \"YQ==\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_utf16le() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                llrt_buffer::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<StringDecoderModule>(ctx.clone(), \"string_decoder\")\n                    .await\n                    .unwrap();\n\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { StringDecoder } from 'string_decoder';\n\n                        export async function test() {\n                            const decoder = new StringDecoder('utf16le');\n                            let res = \"\";\n                            res += decoder.write(Buffer.of(0x61, 0x00));\n                            res += decoder.end();\n                            res += decoder.write(Buffer.of());\n                            res += decoder.end();\n                            return res;\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<String, _>(&ctx, &module, ()).await;\n                assert_eq!(result, \"a\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_utf16le_invalid_high_surrogate() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                llrt_buffer::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<StringDecoderModule>(ctx.clone(), \"string_decoder\")\n                    .await\n                    .unwrap();\n\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { StringDecoder } from 'string_decoder';\n\n                        export async function test() {\n                            const decoder = new StringDecoder('utf16le');\n                            let res = \"\";\n                            res += decoder.write(Buffer.of(0x3d, 0xd8));\n                            res += decoder.write(Buffer.of(0x61, 0x00));\n                            res += decoder.end();\n                            return res;\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<String, _>(&ctx, &module, ()).await;\n                assert_eq!(result, \"\\u{FFFD}a\");\n            })\n        })\n        .await;\n    }\n\n    #[tokio::test]\n    async fn test_utf16le_byte_by_byte() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                llrt_buffer::init(&ctx).unwrap();\n                ModuleEvaluator::eval_rust::<StringDecoderModule>(ctx.clone(), \"string_decoder\")\n                    .await\n                    .unwrap();\n\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { StringDecoder } from 'string_decoder';\n\n                        export async function test() {\n                            const decoder = new StringDecoder('utf16le');\n\n                            let res = \"\";\n\n                            res += decoder.write(Buffer.of(0x3d, 0xd8, 0x4d));\n                            res += decoder.write(Buffer.of(0xdc));\n                            res += decoder.end();\n\n                            res += decoder.write(Buffer.of(0x3d, 0xd8));\n                            res += decoder.write(Buffer.of(0x4d));\n                            res += decoder.write(Buffer.of(0xdc));\n                            res += decoder.end();\n\n                            res += decoder.write(Buffer.of(0x3d));\n                            res += decoder.write(Buffer.of(0xd8));\n                            res += decoder.write(Buffer.of(0x4d));\n                            res += decoder.write(Buffer.of(0xdc));\n                            res += decoder.end();\n\n                            res += decoder.write(Buffer.of(0x3d));\n                            res += decoder.write(Buffer.of(0xd8, 0x4d));\n                            res += decoder.write(Buffer.of(0xdc));\n                            res += decoder.end();\n\n                            res += decoder.write(Buffer.of(0x3d));\n                            res += decoder.write(Buffer.of(0xd8));\n                            res += decoder.write(Buffer.of(0x4d, 0xdc));\n                            res += decoder.end();\n\n                            res += decoder.write(Buffer.of(0x3d));\n                            res += decoder.write(Buffer.of(0xd8, 0x4d, 0Xdc));\n                            res += decoder.end();\n\n                            return res;\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<String, _>(&ctx, &module, ()).await;\n                assert_eq!(result, \"👍👍👍👍👍👍\");\n            })\n        })\n        .await;\n    }\n}\n"
  },
  {
    "path": "modules/llrt_string_decoder/src/string_decoder.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_buffer::ArrayBufferView;\nuse llrt_encoding::Encoder;\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{function::Opt, CString, Ctx, Exception, Result};\n\n#[derive(rquickjs::class::Trace, rquickjs::JsLifetime)]\n#[rquickjs::class]\npub struct StringDecoder {\n    #[qjs(skip_trace)]\n    encoder: Encoder,\n    buffer: Vec<u8>,\n    buffered_bytes: usize,\n    missing_bytes: usize,\n}\n\nimpl StringDecoder {\n    fn make_string(&self, ctx: &Ctx<'_>, data: &[u8]) -> Result<String> {\n        self.encoder\n            .encode_to_string(data, true)\n            .map_err(|_| Exception::throw_internal(ctx, \"Encoding error\"))\n    }\n\n    /// Try to decode the given buffer and store the incomplete bytes.\n    /// The logic was adapted from the [Node implementation].\n    ///\n    /// [Node implementation]: https://github.com/nodejs/node/blob/ba06c5c509956dc413f91b755c1c93798bb700d4/src/string_decoder.cc#L66\n    fn decode_data(&mut self, ctx: &Ctx<'_>, mut data: &[u8]) -> Result<String> {\n        let mut result = String::new();\n\n        if matches!(\n            self.encoder,\n            Encoder::Utf8 | Encoder::Utf16le | Encoder::Base64\n        ) {\n            // See if we want bytes to finish a character from the previous\n            // chunk; if so, copy the new bytes to the missing bytes buffer\n            // and create a string from it that is to be prepended to the main body.\n            if self.missing_bytes > 0 {\n                if matches!(self.encoder, Encoder::Utf8) {\n                    // For UTF-8, we need special alignment treatment:\n                    // If an incomplete character is found at a chunk boundary, we use\n                    // its remainder and try to decode it.\n                    let mut i = 0;\n                    while i < data.len() && i < self.missing_bytes {\n                        if (data[i] & 0xC0) != 0x80 {\n                            // This byte is not a continuation byte even though it should have\n                            // been one. We stop decoding of the incomplete character at this\n                            // point (but still use the rest of the incomplete bytes from this\n                            // chunk) and assume that the new, unexpected byte starts a new one.\n                            self.missing_bytes = 0;\n                            self.buffer.extend_from_slice(&data[..i]);\n                            self.buffered_bytes += i;\n                            data = &data[i..];\n                            break;\n                        }\n                        i += 1;\n                    }\n                } else if matches!(self.encoder, Encoder::Utf16le) {\n                    // For UTF-16le, we need special alignment treatment:\n                    // If we have a high surrogate we need to extend the missing bytes\n                    // to 3 to get the low surrogate.\n                    let mut i = 0;\n                    while i < data.len() && i < self.missing_bytes {\n                        if (data[i] & 0xFC) == 0xD8 {\n                            self.missing_bytes = 3;\n                            break;\n                        }\n                        i += 1;\n                    }\n                }\n\n                let found_bytes = std::cmp::min(data.len(), self.missing_bytes);\n                self.buffer.extend_from_slice(&data[..found_bytes]);\n\n                data = &data[found_bytes..];\n\n                self.missing_bytes -= found_bytes;\n                self.buffered_bytes += found_bytes;\n                if self.missing_bytes == 0 {\n                    // We have enough bytes to decode the buffered character\n                    result = self.make_string(ctx, &self.buffer)?;\n                    self.buffer.clear();\n                    self.buffered_bytes = 0;\n                }\n            }\n\n            // It could be that trying to finish the previous chunk already\n            // consumed all data that we received in this chunk.\n            if data.is_empty() {\n                return Ok(result);\n            } else {\n                // If not, that means is no character left to finish at this point.\n\n                // See whether there is a character that we may have to cut off and\n                // finish when receiving the next chunk.\n                if matches!(self.encoder, Encoder::Utf8) && (data[data.len() - 1] & 0x80) != 0 {\n                    let mut i = data.len() - 1;\n                    loop {\n                        self.buffered_bytes += 1;\n                        if (data[i] & 0xC0) == 0x80 {\n                            // This byte does not start a character (a \"trailing\" byte).\n                            if self.buffered_bytes >= 4 || i == 0 {\n                                // We either have more then 4 trailing bytes (which means\n                                // the current character would not be inside the range for\n                                // valid Unicode, and in particular cannot be represented\n                                // through JavaScript's UTF-16-based approach to strings), or the\n                                // current buffer does not contain the start of an UTF-8 character\n                                // at all. Either way, this is invalid UTF8 and we can just\n                                // let the engine's decoder handle it.\n                                self.buffer.clear();\n                                self.buffered_bytes = 0;\n                                break;\n                            }\n                        } else {\n                            // Found the first byte of a UTF-8 character. By looking at the\n                            // upper bits we can tell how long the character *should* be.\n                            if (data[i] & 0xE0) == 0xC0 {\n                                self.missing_bytes = 2;\n                            } else if (data[i] & 0xF0) == 0xE0 {\n                                self.missing_bytes = 3;\n                            } else if (data[i] & 0xF8) == 0xF0 {\n                                self.missing_bytes = 4;\n                            } else {\n                                // This lead byte would indicate a character outside of the\n                                // representable range.\n                                self.buffered_bytes = 0;\n                                break;\n                            }\n\n                            if self.buffered_bytes >= self.missing_bytes {\n                                // Received more or exactly as many trailing bytes than the lead\n                                // character would indicate. In the \"==\" case, we have valid\n                                // data and don't need to slice anything off;\n                                // in the \">\" case, this is invalid UTF-8 anyway.\n                                self.missing_bytes = 0;\n                                self.buffered_bytes = 0;\n                            }\n\n                            self.missing_bytes -= self.buffered_bytes;\n                            break;\n                        }\n                        i -= 1;\n                    }\n                } else if matches!(self.encoder, Encoder::Utf16le) {\n                    // WARN: For UTF-16LE we deviate from the specification when an invalid\n                    // high surrogate is found. The spec says we should keep it as is, but\n                    // there no way to encode in UTF-8 (required to interface with quickjs).\n                    // For now, we will replace it with a replacement character.\n                    // See https://github.com/quickjs-ng/quickjs/issues/992\n                    if (data.len() % 2) == 1 {\n                        // We got half a codepoint, and need the second byte of it.\n                        // But we need to avoid rendering high surrogates before we\n                        // have the full character.\n                        if data.len() >= 3 && (data[data.len() - 2] & 0xFC) == 0xD8 {\n                            self.buffered_bytes = 3;\n                            self.missing_bytes = 1;\n                        } else {\n                            self.buffered_bytes = 1;\n                            self.missing_bytes = 1;\n                        }\n                    } else if (data[data.len() - 1] & 0xFC) == 0xD8 {\n                        // Half a split UTF-16 character.\n                        self.buffered_bytes = 2;\n                        self.missing_bytes = 2;\n                    }\n                } else if matches!(self.encoder, Encoder::Base64) {\n                    self.buffered_bytes = data.len() % 3;\n                    if self.buffered_bytes > 0 {\n                        self.missing_bytes = 3 - self.buffered_bytes;\n                    }\n                }\n\n                if self.buffered_bytes > 0 {\n                    // Copy the requested number of buffered bytes from the end of the\n                    // input into the incomplete character buffer.\n                    self.buffer\n                        .extend_from_slice(&data[data.len() - self.buffered_bytes..]);\n                    data = &data[..data.len() - self.buffered_bytes];\n                }\n\n                if !data.is_empty() {\n                    result.push_str(&self.make_string(ctx, data)?);\n                }\n            }\n\n            Ok(result)\n        } else {\n            // For ASCII, HEX, and LATIN1, we can decode everything directly\n            self.make_string(ctx, data)\n        }\n    }\n\n    fn flush(&mut self, ctx: &Ctx<'_>) -> Result<String> {\n        if matches!(self.encoder, Encoder::Utf16le) && self.buffered_bytes % 2 == 1 {\n            // Ignore a single trailing byte, like the JS decoder does.\n            self.missing_bytes -= 1;\n            self.buffered_bytes -= 1;\n        }\n\n        if self.buffered_bytes == 0 {\n            return Ok(String::new());\n        }\n\n        let res = self.make_string(ctx, &self.buffer);\n\n        self.missing_bytes = 0;\n        self.buffered_bytes = 0;\n        self.buffer.clear();\n\n        res\n    }\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl StringDecoder {\n    #[qjs(constructor)]\n    pub fn new(ctx: Ctx<'_>, encoding: Opt<CString<'_>>) -> Result<Self> {\n        let encoding = encoding.0.as_ref().map(|e| e.as_str()).unwrap_or(\"utf-8\");\n\n        let encoder = Encoder::from_str(encoding).map_err(|_| {\n            let msg = [\"Unknown encoding: \", encoding].concat();\n            Exception::throw_type(&ctx, &msg)\n        })?;\n\n        Ok(Self {\n            encoder,\n            buffer: Vec::new(),\n            buffered_bytes: 0,\n            missing_bytes: 0,\n        })\n    }\n\n    #[qjs(get)]\n    pub fn encoding(&self) -> &str {\n        self.encoder.as_label()\n    }\n\n    pub fn end(&mut self, ctx: Ctx<'_>, buffer: Opt<ArrayBufferView<'_>>) -> Result<String> {\n        let output = if let Some(data) = buffer.0.as_ref().and_then(|b| b.as_bytes()) {\n            Some(self.decode_data(&ctx, data)?)\n        } else {\n            None\n        };\n\n        let flush = self.flush(&ctx)?;\n        Ok(output\n            .map(|mut o| {\n                o.push_str(&flush);\n                o\n            })\n            .unwrap_or(flush))\n    }\n\n    pub fn write(&mut self, ctx: Ctx<'_>, buffer: ArrayBufferView<'_>) -> Result<String> {\n        let data = buffer\n            .as_bytes()\n            .or_throw_msg(&ctx, \"Buffer has already been used\")?;\n        self.decode_data(&ctx, data)\n    }\n}\n"
  },
  {
    "path": "modules/llrt_temporal/Cargo.toml",
    "content": "[package]\nname = \"llrt_temporal\"\ndescription = \"LLRT Module temporal\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\nreadme = \"README.md\"\n\n[lib]\nname = \"llrt_temporal\"\npath = \"src/lib.rs\"\n\n[dependencies]\njiff = { version = \"0.2\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", features = [\"macro\"], default-features = false }\n"
  },
  {
    "path": "modules/llrt_temporal/src/duration.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{cmp::Ordering, str::FromStr};\n\nuse jiff::{Span, SpanCompare};\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{\n    atom::PredefinedAtom,\n    class::Trace,\n    prelude::{Opt, Rest},\n    Class, Ctx, Exception, JsLifetime, Object, Result, Value,\n};\n\nuse crate::utils::date::fill_duration_from_iter as fill_date_from_iter;\nuse crate::utils::round::span::SpanRoundOption;\nuse crate::utils::span::SpanExt;\nuse crate::utils::time::fill_duration_from_iter as fill_time_from_iter;\nuse crate::utils::total::span::SpanTotalOption;\n\n#[derive(Clone, JsLifetime, Trace)]\n#[rquickjs::class]\npub(crate) struct Duration {\n    #[qjs(skip_trace)]\n    inner: Span,\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl Duration {\n    #[qjs(constructor)]\n    fn new<'js>(ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<Self> {\n        let obj = Self::fill_object(&ctx, &args)?;\n        Self::from_object(&ctx, &obj)\n    }\n\n    #[qjs(static)]\n    fn compare(ctx: Ctx<'_>, duration1: Self, duration2: Self, opt: Opt<Value<'_>>) -> Result<i8> {\n        let sc = Self::into_span_compare(&duration2.inner, &opt);\n        match duration1.inner.compare(sc).or_throw_range(&ctx, \"\")? {\n            Ordering::Less => Ok(-1),\n            Ordering::Equal => Ok(0),\n            Ordering::Greater => Ok(1),\n        }\n    }\n\n    #[qjs(static)]\n    fn from(ctx: Ctx<'_>, info: Value<'_>) -> Result<Self> {\n        Self::from_value(&ctx, &info)\n    }\n\n    fn abs(&self) -> Self {\n        let span = self.inner.abs();\n        Self { inner: span }\n    }\n\n    fn add(&self, ctx: Ctx<'_>, other: Value<'_>) -> Result<Self> {\n        let duration = Self::from_value(&ctx, &other)?;\n        let span = duration.into_inner();\n        let span = self.inner.checked_add(span).or_throw_range(&ctx, \"\")?;\n        Ok(Self { inner: span })\n    }\n\n    fn negated(&self) -> Self {\n        let span = self.inner.negate();\n        Self { inner: span }\n    }\n\n    fn round(&self, ctx: Ctx<'_>, options: Value<'_>) -> Result<Self> {\n        let round = SpanRoundOption::from_value(&ctx, &options)?;\n        let round = round.into_inner();\n        let dt = self.inner.round(round).or_throw_range(&ctx, \"\")?;\n        Ok(Self { inner: dt })\n    }\n\n    fn subtract(&self, ctx: Ctx<'_>, other: Value<'_>) -> Result<Self> {\n        let duration = Self::from_value(&ctx, &other)?;\n        let span = duration.into_inner();\n        let span = self.inner.checked_sub(span).or_throw_range(&ctx, \"\")?;\n        Ok(Self { inner: span })\n    }\n\n    #[allow(clippy::inherent_to_string)]\n    #[qjs(rename = PredefinedAtom::ToJSON)]\n    fn to_json(&self) -> String {\n        self.inner.to_string()\n    }\n\n    #[allow(clippy::inherent_to_string)]\n    #[qjs(rename = PredefinedAtom::ToString)]\n    fn to_string(&self) -> String {\n        self.inner.to_string()\n    }\n\n    fn total(&self, ctx: Ctx<'_>, options: Value<'_>) -> Result<f64> {\n        let total = SpanTotalOption::from_value(&ctx, &options)?;\n        let total = total.into_inner();\n        let num = self.inner.total(total).or_throw_range(&ctx, \"\")?;\n        Ok(num)\n    }\n\n    fn value_of(&self, ctx: Ctx<'_>) -> Result<()> {\n        Err(Exception::throw_type(\n            &ctx,\n            \"can't convert Duration to primitive type\",\n        ))\n    }\n\n    fn with(&self, ctx: Ctx<'_>, info: Value<'_>) -> Result<Self> {\n        let span = self.inner.span_with(&ctx, &info)?;\n        Ok(Self { inner: span })\n    }\n\n    #[qjs(get)]\n    fn blank(&self) -> bool {\n        self.inner.signum() == 0\n    }\n\n    #[qjs(get)]\n    fn days(&self) -> i32 {\n        self.inner.get_days()\n    }\n\n    #[qjs(get)]\n    fn hours(&self) -> i32 {\n        self.inner.get_hours()\n    }\n\n    #[qjs(get)]\n    fn microseconds(&self) -> i64 {\n        self.inner.get_microseconds()\n    }\n\n    #[qjs(get)]\n    fn milliseconds(&self) -> i64 {\n        self.inner.get_milliseconds()\n    }\n\n    #[qjs(get)]\n    fn minutes(&self) -> i64 {\n        self.inner.get_minutes()\n    }\n\n    #[qjs(get)]\n    fn months(&self) -> i32 {\n        self.inner.get_months()\n    }\n\n    #[qjs(get)]\n    fn nanoseconds(&self) -> i64 {\n        self.inner.get_nanoseconds()\n    }\n\n    #[qjs(get)]\n    fn seconds(&self) -> i64 {\n        self.inner.get_seconds()\n    }\n\n    #[qjs(get)]\n    fn sign(&self) -> i8 {\n        self.inner.signum()\n    }\n\n    #[qjs(get)]\n    fn weeks(&self) -> i32 {\n        self.inner.get_weeks()\n    }\n\n    #[qjs(get)]\n    fn years(&self) -> i16 {\n        self.inner.get_years()\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    fn to_string_tag(&self) -> &'static str {\n        \"Temporal.Duration\"\n    }\n}\n\nimpl Duration {\n    fn fill_object<'js>(ctx: &Ctx<'js>, args: &Rest<Value<'js>>) -> Result<Object<'js>> {\n        let obj = Object::new(ctx.clone())?;\n        let mut iter = args.0.iter().cloned();\n        fill_date_from_iter(&obj, &mut iter)?;\n        fill_time_from_iter(&obj, &mut iter)?;\n        Ok(obj)\n    }\n\n    fn from_object(ctx: &Ctx<'_>, obj: &Object<'_>) -> Result<Self> {\n        let span = Span::from_object(ctx, obj)?;\n        Ok(Self { inner: span })\n    }\n\n    pub(crate) fn from_value(ctx: &Ctx<'_>, value: &Value<'_>) -> Result<Self> {\n        if let Some(obj) = value.as_object() {\n            if let Some(cls) = Class::<Self>::from_object(obj) {\n                return Ok(cls.borrow().clone());\n            }\n            return Self::from_object(ctx, obj);\n        }\n\n        let str = value\n            .as_string()\n            .and_then(|s| s.to_string().ok())\n            .or_throw_type(ctx, \"Cannot convert value to string\")?;\n\n        let span = Span::from_str(&str).or_throw_range(ctx, \"\")?;\n        Ok(Self { inner: span })\n    }\n\n    pub(crate) fn into_inner(self) -> Span {\n        self.inner\n    }\n\n    fn into_span_compare<'a>(span: &Span, value: &Opt<Value<'a>>) -> SpanCompare<'a> {\n        Span::into_span_compare(span, value)\n    }\n\n    pub(crate) fn new_object(span: Span) -> Self {\n        Self { inner: span }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_temporal/src/instant.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{cmp::Ordering, str::FromStr};\n\nuse jiff::{Timestamp, Zoned};\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{\n    atom::PredefinedAtom, class::Trace, prelude::Opt, BigInt, Class, Ctx, Exception, JsLifetime,\n    Result, Value,\n};\n\nuse crate::duration::Duration;\nuse crate::utils::round::timestamp::TimestampRoundOption;\nuse crate::zoned_date_time::ZonedDateTime;\n\nuse super::extract_bigint_or_number;\n\n#[derive(Clone, JsLifetime, Trace)]\n#[rquickjs::class]\npub(crate) struct Instant {\n    #[qjs(skip_trace)]\n    inner: Timestamp,\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl Instant {\n    #[qjs(constructor)]\n    fn new(ctx: Ctx<'_>, nanos: Value<'_>) -> Result<Self> {\n        Self::from_epoch_nanoseconds(ctx, nanos)\n    }\n\n    #[qjs(static)]\n    fn compare(instant1: Self, instant2: Self) -> i8 {\n        match instant1.inner.cmp(&instant2.inner) {\n            Ordering::Less => -1,\n            Ordering::Equal => 0,\n            Ordering::Greater => 1,\n        }\n    }\n\n    #[qjs(static)]\n    fn from(ctx: Ctx<'_>, info: Value<'_>) -> Result<Self> {\n        if let Some(obj) = info.as_object() {\n            if let Some(cls) = Class::<Self>::from_object(obj) {\n                return Ok(cls.borrow().clone());\n            }\n        }\n\n        let str = info\n            .as_string()\n            .and_then(|s| s.to_string().ok())\n            .or_throw_type(&ctx, \"Cannot convert value to string\")?;\n\n        Self::from_str(&ctx, &str)\n    }\n\n    #[qjs(static)]\n    fn from_epoch_milliseconds(ctx: Ctx<'_>, ms: f64) -> Result<Self> {\n        let ns = (ms * 1_000_000.0) as i128;\n        Self::from_nanosecond(&ctx, ns)\n    }\n\n    #[qjs(static)]\n    fn from_epoch_nanoseconds(ctx: Ctx<'_>, ns: Value<'_>) -> Result<Self> {\n        let ns = extract_bigint_or_number(&ctx, &ns)?;\n        Self::from_nanosecond(&ctx, ns)\n    }\n\n    fn add(&self, ctx: Ctx<'_>, duration: Value<'_>) -> Result<Self> {\n        let duration = Duration::from_value(&ctx, &duration)?;\n        let span = duration.into_inner();\n        let ts = self.inner.checked_add(span).or_throw_range(&ctx, \"\")?;\n        Ok(Self { inner: ts })\n    }\n\n    fn equals(&self, other: Self) -> bool {\n        self.inner == other.inner\n    }\n\n    fn round(&self, ctx: Ctx<'_>, options: Value<'_>) -> Result<Self> {\n        let round = TimestampRoundOption::from_value(&ctx, &options)?;\n        let round = round.into_inner();\n        let ts = self.inner.round(round).or_throw_range(&ctx, \"\")?;\n        Ok(Self { inner: ts })\n    }\n\n    fn since(&self, other: Self) -> Duration {\n        Duration::new_object(self.inner - other.inner)\n    }\n\n    fn subtract(&self, ctx: Ctx<'_>, duration: Value<'_>) -> Result<Self> {\n        let duration = Duration::from_value(&ctx, &duration)?;\n        let span = duration.into_inner();\n        let ts = self.inner.checked_sub(span).or_throw_range(&ctx, \"\")?;\n        Ok(Self { inner: ts })\n    }\n\n    #[allow(clippy::inherent_to_string)]\n    #[qjs(rename = PredefinedAtom::ToJSON)]\n    fn to_json(&self) -> String {\n        self.inner.to_string()\n    }\n\n    #[allow(clippy::inherent_to_string)]\n    #[qjs(rename = PredefinedAtom::ToString)]\n    fn to_string(&self) -> String {\n        self.inner.to_string()\n    }\n\n    #[qjs(rename = \"toZonedDateTimeISO\")]\n    fn to_zoned_dt_iso(&self, ctx: Ctx<'_>, timezone: Opt<String>) -> Result<ZonedDateTime> {\n        let tz = timezone.as_deref().unwrap_or(\"UTC\");\n        ZonedDateTime::from_ts_tz(&ctx, &self.inner, tz)\n    }\n\n    fn until(&self, other: Self) -> Duration {\n        Duration::new_object(other.inner - self.inner)\n    }\n\n    fn value_of(&self, ctx: Ctx<'_>) -> Result<()> {\n        Err(Exception::throw_type(\n            &ctx,\n            \"can't convert Instant to primitive type\",\n        ))\n    }\n\n    #[qjs(get)]\n    fn epoch_milliseconds(&self) -> i64 {\n        self.inner.as_millisecond()\n    }\n\n    #[qjs(get)]\n    fn epoch_nanoseconds<'js>(&self, ctx: Ctx<'js>) -> Result<BigInt<'js>> {\n        let ns = self.inner.as_nanosecond();\n        let ns = ns.try_into().or_throw_range(&ctx, \"\")?;\n        BigInt::from_i64(ctx, ns)\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    fn to_string_tag(&self) -> &'static str {\n        \"Temporal.Instant\"\n    }\n}\n\nimpl Instant {\n    fn from_nanosecond(ctx: &Ctx<'_>, ns: i128) -> Result<Self> {\n        let ts = Timestamp::from_nanosecond(ns).or_throw_range(ctx, \"\")?;\n        Ok(Self { inner: ts })\n    }\n\n    fn from_str(ctx: &Ctx<'_>, str: &str) -> Result<Self> {\n        let ts = Timestamp::from_str(str).or_throw_range(ctx, \"\")?;\n        Ok(Self { inner: ts })\n    }\n\n    pub(crate) fn from_zoned(zoned: &Zoned) -> Self {\n        let ts = zoned.timestamp();\n        Self { inner: ts }\n    }\n\n    pub(crate) fn now() -> Self {\n        let ts = Timestamp::now();\n        Self { inner: ts }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_temporal/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nmod duration;\nmod instant;\nmod now;\nmod plain_date;\nmod plain_date_time;\nmod plain_time;\nmod utils;\nmod zoned_date_time;\n\nuse std::str::FromStr;\n\nuse jiff::civil::Time;\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{Class, Ctx, Exception, Object, Result, Value};\n\nuse crate::duration::Duration;\nuse crate::instant::Instant;\nuse crate::plain_date::PlainDate;\nuse crate::plain_date_time::PlainDateTime;\nuse crate::plain_time::PlainTime;\nuse crate::zoned_date_time::ZonedDateTime;\n\npub fn init(ctx: &Ctx<'_>) -> Result<()> {\n    let temporal = Object::new(ctx.clone())?;\n\n    Class::<Duration>::define(&temporal)?;\n    Class::<Instant>::define(&temporal)?;\n    Class::<PlainDate>::define(&temporal)?;\n    Class::<PlainDateTime>::define(&temporal)?;\n    Class::<PlainTime>::define(&temporal)?;\n    Class::<ZonedDateTime>::define(&temporal)?;\n    temporal.set(\"Now\", now::define_object(ctx)?)?;\n\n    ctx.globals().set(\"Temporal\", temporal)?;\n    Ok(())\n}\n\npub(crate) fn extract_bigint_or_number(ctx: &Ctx<'_>, value: &Value<'_>) -> Result<i128> {\n    if let Some(num) = value.as_number() {\n        if !num.is_finite() {\n            return Err(Exception::throw_message(ctx, \"Invalid value\"));\n        }\n        Ok(num as i128)\n    } else if let Some(bigint) = value.as_big_int() {\n        match bigint.clone().to_i64() {\n            Ok(v) => Ok(v as i128),\n            Err(_) => Err(Exception::throw_message(ctx, \"BigInt value out of range\")),\n        }\n    } else {\n        Err(Exception::throw_message(ctx, \"Expected number or BigInt\"))\n    }\n}\n\npub(crate) fn extract_time(ctx: &Ctx<'_>, val: &Option<Value<'_>>) -> Result<Time> {\n    let mut tm = Time::MIN;\n\n    let Some(val) = &val else {\n        return Ok(tm);\n    };\n\n    if let Some(str) = val.as_string() {\n        if let Ok(v) = str.to_string() {\n            tm = Time::from_str(&v).or_throw_range(ctx, \"\")?;\n        }\n    } else if let Some(obj) = val.as_object() {\n        if let Some(v) = Class::<PlainTime>::from_object(obj) {\n            let pt = v.borrow().clone();\n            tm = pt.into_inner();\n        }\n    }\n    Ok(tm)\n}\n\npub(crate) fn extract_time_and_timezone(ctx: &Ctx<'_>, val: &Value<'_>) -> Result<(Time, String)> {\n    let (mut tm, mut tz) = (Time::MIN, None);\n\n    if let Some(str) = val.as_string() {\n        if let Ok(v) = str.to_string() {\n            tz = Some(v);\n        }\n    } else if let Some(obj) = val.as_object() {\n        if let Ok(v) = obj.get::<_, String>(\"plainTime\") {\n            tm = Time::from_str(&v).or_throw_range(ctx, \"\")?;\n        } else if let Ok(v) = obj.get::<_, PlainTime>(\"plainTime\") {\n            tm = v.into_inner();\n        }\n\n        if let Ok(v) = obj.get::<_, String>(\"timeZone\") {\n            tz = Some(v);\n        } else if let Ok(v) = obj.get::<_, ZonedDateTime>(\"timeZone\") {\n            tz = Some(v.into_inner().time_zone().iana_name().unwrap().into());\n        }\n    }\n\n    let tz = tz.or_throw_type(\n        ctx,\n        \"timeZone is not a string or a Temporal.ZonedDateTime instance\",\n    )?;\n    Ok((tm, tz))\n}\n"
  },
  {
    "path": "modules/llrt_temporal/src/now.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse jiff::{tz::TimeZone, Timestamp, Zoned};\nuse rquickjs::{\n    atom::PredefinedAtom,\n    prelude::{Func, Opt},\n    Ctx, Object, Result,\n};\n\nuse crate::instant::Instant;\nuse crate::plain_date::PlainDate;\nuse crate::plain_date_time::PlainDateTime;\nuse crate::plain_time::PlainTime;\nuse crate::zoned_date_time::ZonedDateTime;\n\npub(crate) fn define_object<'a>(ctx: &Ctx<'a>) -> Result<Object<'a>> {\n    let obj = Object::new(ctx.clone())?;\n    obj.set(\"instant\", Func::from(Instant::now))?;\n    obj.set(\"plainDateISO\", Func::from(plain_date_iso))?;\n    obj.set(\"plainDateTimeISO\", Func::from(plain_datetime_iso))?;\n    obj.set(\"plainTimeISO\", Func::from(plain_time_iso))?;\n    obj.set(\"timeZoneId\", Func::from(time_zone_id))?;\n    obj.set(\"zonedDateTimeISO\", Func::from(zoned_datetime_iso))?;\n    obj.set(PredefinedAtom::SymbolToStringTag, \"Temporal.Now\")?;\n    Ok(obj)\n}\n\nfn plain_date_iso(ctx: Ctx<'_>, timezone: Opt<String>) -> Result<PlainDate> {\n    let (ts, tz) = parts_of_zoned_now(timezone);\n    PlainDate::from_ts_tz(&ctx, &ts, &tz)\n}\n\nfn plain_datetime_iso(ctx: Ctx<'_>, timezone: Opt<String>) -> Result<PlainDateTime> {\n    let (ts, tz) = parts_of_zoned_now(timezone);\n    PlainDateTime::from_ts_tz(&ctx, &ts, &tz)\n}\n\nfn plain_time_iso(ctx: Ctx<'_>, timezone: Opt<String>) -> Result<PlainTime> {\n    let (ts, tz) = parts_of_zoned_now(timezone);\n    PlainTime::from_ts_tz(&ctx, &ts, &tz)\n}\n\nfn time_zone_id() -> String {\n    let tz: TimeZone = TimeZone::system();\n    tz.iana_name()\n        .map(|s| s.to_string())\n        .unwrap_or_else(|| \"UTC\".to_string())\n}\n\nfn zoned_datetime_iso(ctx: Ctx<'_>, timezone: Opt<String>) -> Result<ZonedDateTime> {\n    let (ts, tz) = parts_of_zoned_now(timezone);\n    ZonedDateTime::from_ts_tz(&ctx, &ts, &tz)\n}\n\nfn parts_of_zoned_now(timezone: Opt<String>) -> (Timestamp, String) {\n    let zoned = Zoned::now();\n    let ts = zoned.timestamp();\n    let tz = zoned.time_zone().iana_name().unwrap_or(\"UTC\");\n    let tz = timezone.0.unwrap_or(tz.to_string());\n    (ts, tz)\n}\n"
  },
  {
    "path": "modules/llrt_temporal/src/plain_date.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{cmp::Ordering, str::FromStr};\n\nuse jiff::{\n    civil::{Date, DateTime},\n    Timestamp,\n};\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{\n    atom::PredefinedAtom,\n    class::Trace,\n    prelude::{Opt, Rest},\n    Class, Ctx, Exception, JsLifetime, Object, Result, Value,\n};\n\nuse crate::duration::Duration;\nuse crate::plain_date_time::PlainDateTime;\nuse crate::utils::date::{fill_from_iter, DateExt};\nuse crate::zoned_date_time::ZonedDateTime;\n\nuse super::{extract_time, extract_time_and_timezone};\n\n#[derive(Clone, JsLifetime, Trace)]\n#[rquickjs::class]\npub(crate) struct PlainDate {\n    #[qjs(skip_trace)]\n    inner: Date,\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl PlainDate {\n    #[qjs(constructor)]\n    fn new<'js>(ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<Self> {\n        let obj = Self::fill_object(&ctx, &args)?;\n        Self::from_object(&ctx, &obj)\n    }\n\n    #[qjs(static)]\n    fn compare(date1: Self, date2: Self) -> i8 {\n        match date1.inner.cmp(&date2.inner) {\n            Ordering::Less => -1,\n            Ordering::Equal => 0,\n            Ordering::Greater => 1,\n        }\n    }\n\n    #[qjs(static)]\n    fn from(ctx: Ctx<'_>, info: Value<'_>) -> Result<Self> {\n        if let Some(obj) = info.as_object() {\n            if let Some(cls) = Class::<Self>::from_object(obj) {\n                return Ok(cls.borrow().clone());\n            }\n            if let Some(cls) = Class::<PlainDateTime>::from_object(obj) {\n                let pdt = cls.borrow().clone();\n                return Ok(pdt.to_plain_date());\n            }\n            if let Some(cls) = Class::<ZonedDateTime>::from_object(obj) {\n                let zdt = cls.borrow().clone();\n                return Ok(zdt.to_plain_date());\n            }\n            return Self::from_object(&ctx, obj);\n        }\n\n        let str = info\n            .as_string()\n            .and_then(|s| s.to_string().ok())\n            .or_throw_type(&ctx, \"Cannot convert value to string\")?;\n\n        Self::from_str(&ctx, &str)\n    }\n\n    fn add(&self, ctx: Ctx<'_>, duration: Value<'_>) -> Result<Self> {\n        let duration = Duration::from_value(&ctx, &duration)?;\n        let span = duration.into_inner();\n        let zoned = self.inner.checked_add(span).or_throw_range(&ctx, \"\")?;\n        Ok(Self { inner: zoned })\n    }\n\n    fn equals(&self, other: Self) -> bool {\n        self.inner == other.inner\n    }\n\n    fn since(&self, other: Self) -> Duration {\n        Duration::new_object(self.inner - other.inner)\n    }\n\n    fn subtract(&self, ctx: Ctx<'_>, duration: Value<'_>) -> Result<Self> {\n        let duration = Duration::from_value(&ctx, &duration)?;\n        let span = duration.into_inner();\n        let date = self.inner.checked_sub(span).or_throw_range(&ctx, \"\")?;\n        Ok(Self { inner: date })\n    }\n\n    #[allow(clippy::inherent_to_string)]\n    #[qjs(rename = PredefinedAtom::ToJSON)]\n    fn to_json(&self) -> String {\n        self.inner.to_string()\n    }\n\n    fn to_plain_date_time(&self, ctx: Ctx<'_>, value: Opt<Value<'_>>) -> Result<PlainDateTime> {\n        let time = extract_time(&ctx, &value.0)?;\n        let dt = DateTime::from_parts(self.inner, time);\n        Ok(PlainDateTime::new_object(dt))\n    }\n\n    #[allow(clippy::inherent_to_string)]\n    #[qjs(rename = PredefinedAtom::ToString)]\n    fn to_string(&self) -> String {\n        self.inner.to_string()\n    }\n\n    fn to_zoned_date_time(&self, ctx: Ctx<'_>, value: Value<'_>) -> Result<ZonedDateTime> {\n        let (time, tz) = extract_time_and_timezone(&ctx, &value)?;\n        let dt = DateTime::from_parts(self.inner, time);\n        let zoned = dt.in_tz(&tz).or_throw_range(&ctx, \"\")?;\n        Ok(ZonedDateTime::new_object(zoned))\n    }\n\n    fn until(&self, other: Self) -> Duration {\n        Duration::new_object(other.inner - self.inner)\n    }\n\n    fn value_of(&self, ctx: Ctx<'_>) -> Result<()> {\n        Err(Exception::throw_type(\n            &ctx,\n            \"can't convert PlainDate to primitive type\",\n        ))\n    }\n\n    fn with(&self, ctx: Ctx<'_>, info: Value<'_>) -> Result<Self> {\n        let date = self.inner.date_with(&ctx, &info)?;\n        Ok(Self { inner: date })\n    }\n\n    #[qjs(get)]\n    fn calendar_id() -> &'static str {\n        \"iso8601\"\n    }\n\n    #[qjs(get)]\n    fn day(&self) -> i8 {\n        self.inner.day()\n    }\n\n    #[qjs(get)]\n    fn day_of_year(&self) -> i16 {\n        self.inner.day_of_year()\n    }\n\n    #[qjs(get)]\n    fn days_in_month(&self) -> i8 {\n        self.inner.days_in_month()\n    }\n\n    #[qjs(get)]\n    fn days_in_year(&self) -> i16 {\n        self.inner.days_in_year()\n    }\n\n    #[qjs(get)]\n    fn in_leap_year(&self) -> bool {\n        self.inner.in_leap_year()\n    }\n\n    #[qjs(get)]\n    fn month(&self) -> i8 {\n        self.inner.month()\n    }\n\n    #[qjs(get)]\n    fn year(&self) -> i16 {\n        self.inner.year()\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    fn to_string_tag(&self) -> &'static str {\n        \"Temporal.PlainDate\"\n    }\n}\n\nimpl PlainDate {\n    fn fill_object<'js>(ctx: &Ctx<'js>, args: &Rest<Value<'js>>) -> Result<Object<'js>> {\n        let obj = Object::new(ctx.clone())?;\n        let mut iter = args.0.iter().cloned();\n        fill_from_iter(&obj, &mut iter, true)?;\n        Ok(obj)\n    }\n\n    fn from_object(ctx: &Ctx<'_>, obj: &Object<'_>) -> Result<Self> {\n        let date = Date::from_object(ctx, obj)?;\n        Ok(Self { inner: date })\n    }\n\n    fn from_str(ctx: &Ctx<'_>, str: &str) -> Result<Self> {\n        let date = Date::from_str(str).or_throw_range(ctx, \"\")?;\n        Ok(Self { inner: date })\n    }\n\n    pub(crate) fn from_ts_tz(ctx: &Ctx<'_>, ts: &Timestamp, tz: &str) -> Result<Self> {\n        let zoned = ts.in_tz(tz).or_throw_range(ctx, \"\")?;\n        let zdt = ZonedDateTime::new_object(zoned);\n        Ok(zdt.to_plain_date())\n    }\n\n    pub(crate) fn into_inner(self) -> Date {\n        self.inner\n    }\n\n    pub(crate) fn new_object(date: Date) -> Self {\n        Self { inner: date }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_temporal/src/plain_date_time.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{cmp::Ordering, str::FromStr};\n\nuse jiff::{civil::DateTime, Timestamp};\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{\n    atom::PredefinedAtom,\n    class::Trace,\n    prelude::{Opt, Rest},\n    Class, Ctx, Exception, JsLifetime, Object, Result, Value,\n};\n\nuse crate::plain_date::PlainDate;\nuse crate::plain_time::PlainTime;\nuse crate::utils::date::fill_from_iter as fill_date_from_iter;\nuse crate::utils::date_time::DateTimeExt;\nuse crate::utils::round::date_time::DateTimeRoundOption;\nuse crate::utils::time::fill_from_iter as fill_time_from_iter;\nuse crate::zoned_date_time::ZonedDateTime;\nuse crate::{duration::Duration, extract_time};\n\n#[derive(Clone, JsLifetime, Trace)]\n#[rquickjs::class]\npub(crate) struct PlainDateTime {\n    #[qjs(skip_trace)]\n    inner: DateTime,\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl PlainDateTime {\n    #[qjs(constructor)]\n    fn new<'js>(ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<Self> {\n        let obj = Self::fill_object(&ctx, &args)?;\n        Self::from_object(&ctx, &obj)\n    }\n\n    #[qjs(static)]\n    fn compare(datetime1: Self, datetime2: Self) -> i8 {\n        match datetime1.inner.cmp(&datetime2.inner) {\n            Ordering::Less => -1,\n            Ordering::Equal => 0,\n            Ordering::Greater => 1,\n        }\n    }\n\n    #[qjs(static)]\n    fn from(ctx: Ctx<'_>, info: Value<'_>) -> Result<Self> {\n        if let Some(obj) = info.as_object() {\n            if let Some(cls) = Class::<Self>::from_object(obj) {\n                return Ok(cls.borrow().clone());\n            }\n            return Self::from_object(&ctx, obj);\n        }\n\n        let str = info\n            .as_string()\n            .and_then(|s| s.to_string().ok())\n            .or_throw_type(&ctx, \"Cannot convert value to string\")?;\n\n        Self::from_str(&ctx, &str)\n    }\n\n    fn add(&self, ctx: Ctx<'_>, duration: Value<'_>) -> Result<Self> {\n        let duration = Duration::from_value(&ctx, &duration)?;\n        let span = duration.into_inner();\n        let dt = self.inner.checked_add(span).or_throw_range(&ctx, \"\")?;\n        Ok(Self { inner: dt })\n    }\n\n    fn equals(&self, other: Self) -> bool {\n        self.inner == other.inner\n    }\n\n    fn round(&self, ctx: Ctx<'_>, options: Value<'_>) -> Result<Self> {\n        let round = DateTimeRoundOption::from_value(&ctx, &options)?;\n        let round = round.into_inner();\n        let dt = self.inner.round(round).or_throw_range(&ctx, \"\")?;\n        Ok(Self { inner: dt })\n    }\n\n    fn since(&self, other: Self) -> Duration {\n        Duration::new_object(self.inner - other.inner)\n    }\n\n    fn subtract(&self, ctx: Ctx<'_>, duration: Value<'_>) -> Result<Self> {\n        let duration = Duration::from_value(&ctx, &duration)?;\n        let span = duration.into_inner();\n        let dt = self.inner.checked_sub(span).or_throw_range(&ctx, \"\")?;\n        Ok(Self { inner: dt })\n    }\n\n    #[allow(clippy::inherent_to_string)]\n    #[qjs(rename = PredefinedAtom::ToJSON)]\n    fn to_json(&self) -> String {\n        self.inner.to_string()\n    }\n\n    pub(crate) fn to_plain_date(&self) -> PlainDate {\n        let date = self.inner.date();\n        PlainDate::new_object(date)\n    }\n\n    pub(crate) fn to_plain_time(&self) -> PlainTime {\n        let time = self.inner.time();\n        PlainTime::new_object(time)\n    }\n\n    #[allow(clippy::inherent_to_string)]\n    #[qjs(rename = PredefinedAtom::ToString)]\n    fn to_string(&self) -> String {\n        self.inner.to_string()\n    }\n\n    fn to_zoned_date_time(&self, ctx: Ctx<'_>, tz: String) -> Result<ZonedDateTime> {\n        let zoned = self.inner.in_tz(&tz).or_throw_range(&ctx, \"\")?;\n        Ok(ZonedDateTime::new_object(zoned))\n    }\n\n    fn until(&self, other: Self) -> Duration {\n        Duration::new_object(other.inner - self.inner)\n    }\n\n    fn value_of(&self, ctx: Ctx<'_>) -> Result<()> {\n        Err(Exception::throw_type(\n            &ctx,\n            \"can't convert PlainDateTime to primitive type\",\n        ))\n    }\n\n    fn with(&self, ctx: Ctx<'_>, info: Value<'_>) -> Result<Self> {\n        let dt = self.inner.date_time_with(&ctx, &info)?;\n        Ok(Self { inner: dt })\n    }\n\n    fn with_plain_time(&self, ctx: Ctx<'_>, val: Opt<Value<'_>>) -> Result<Self> {\n        let time = extract_time(&ctx, &val.0)?;\n        let dt = DateTime::from_parts(self.inner.date(), time);\n        Ok(Self { inner: dt })\n    }\n\n    #[qjs(get)]\n    fn calendar_id() -> &'static str {\n        \"iso8601\"\n    }\n\n    #[qjs(get)]\n    fn day(&self) -> i8 {\n        self.inner.day()\n    }\n\n    #[qjs(get)]\n    fn day_of_year(&self) -> i16 {\n        self.inner.day_of_year()\n    }\n\n    #[qjs(get)]\n    fn days_in_month(&self) -> i8 {\n        self.inner.days_in_month()\n    }\n\n    #[qjs(get)]\n    fn days_in_year(&self) -> i16 {\n        self.inner.days_in_year()\n    }\n\n    #[qjs(get)]\n    fn hour(&self) -> i8 {\n        self.inner.hour()\n    }\n\n    #[qjs(get)]\n    fn in_leap_year(&self) -> bool {\n        self.inner.in_leap_year()\n    }\n\n    #[qjs(get)]\n    fn microsecond(&self) -> i16 {\n        self.inner.microsecond()\n    }\n\n    #[qjs(get)]\n    fn millisecond(&self) -> i16 {\n        self.inner.millisecond()\n    }\n\n    #[qjs(get)]\n    fn minute(&self) -> i8 {\n        self.inner.minute()\n    }\n\n    #[qjs(get)]\n    fn month(&self) -> i8 {\n        self.inner.month()\n    }\n\n    #[qjs(get)]\n    fn nanosecond(&self) -> i16 {\n        self.inner.nanosecond()\n    }\n\n    #[qjs(get)]\n    fn second(&self) -> i8 {\n        self.inner.second()\n    }\n\n    #[qjs(get)]\n    fn year(&self) -> i16 {\n        self.inner.year()\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    fn to_string_tag(&self) -> &'static str {\n        \"Temporal.PlainDateTime\"\n    }\n}\n\nimpl PlainDateTime {\n    fn fill_object<'js>(ctx: &Ctx<'js>, args: &Rest<Value<'js>>) -> Result<Object<'js>> {\n        let obj = Object::new(ctx.clone())?;\n        let mut iter = args.0.iter().cloned();\n        fill_date_from_iter(&obj, &mut iter, false)?;\n        fill_time_from_iter(&obj, &mut iter, true)?;\n        Ok(obj)\n    }\n\n    fn from_object(ctx: &Ctx<'_>, obj: &Object<'_>) -> Result<Self> {\n        let dt = DateTime::from_object(ctx, obj)?;\n        Ok(Self { inner: dt })\n    }\n\n    fn from_str(ctx: &Ctx<'_>, str: &str) -> Result<Self> {\n        let dt = DateTime::from_str(str).or_throw_range(ctx, \"\")?;\n        Ok(Self { inner: dt })\n    }\n\n    pub(crate) fn from_ts_tz(ctx: &Ctx<'_>, ts: &Timestamp, tz: &str) -> Result<Self> {\n        let zoned = ts.in_tz(tz).or_throw_range(ctx, \"\")?;\n        let zdt = ZonedDateTime::new_object(zoned);\n        Ok(zdt.to_plain_date_time())\n    }\n\n    pub(crate) fn into_inner(self) -> DateTime {\n        self.inner\n    }\n\n    pub(crate) fn new_object(dt: DateTime) -> Self {\n        Self { inner: dt }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_temporal/src/plain_time.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{cmp::Ordering, str::FromStr};\n\nuse jiff::{civil::Time, Timestamp};\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{\n    atom::PredefinedAtom, class::Trace, prelude::Rest, Class, Ctx, Exception, JsLifetime, Object,\n    Result, Value,\n};\n\nuse crate::duration::Duration;\nuse crate::plain_date_time::PlainDateTime;\nuse crate::utils::round::time::TimeRoundOption;\nuse crate::utils::time::{fill_from_iter, TimeExt};\nuse crate::zoned_date_time::ZonedDateTime;\n\n#[derive(Clone, JsLifetime, Trace)]\n#[rquickjs::class]\npub(crate) struct PlainTime {\n    #[qjs(skip_trace)]\n    inner: Time,\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl PlainTime {\n    #[qjs(constructor)]\n    fn new<'js>(ctx: Ctx<'js>, args: Rest<Value<'js>>) -> Result<Self> {\n        let obj = Self::fill_object(&ctx, &args)?;\n        Self::from_object(&ctx, &obj)\n    }\n\n    #[qjs(static)]\n    fn compare(time1: Self, time2: Self) -> i8 {\n        match time1.inner.cmp(&time2.inner) {\n            Ordering::Less => -1,\n            Ordering::Equal => 0,\n            Ordering::Greater => 1,\n        }\n    }\n\n    #[qjs(static)]\n    fn from(ctx: Ctx<'_>, info: Value<'_>) -> Result<Self> {\n        if let Some(obj) = info.as_object() {\n            if let Some(cls) = Class::<Self>::from_object(obj) {\n                return Ok(cls.borrow().clone());\n            }\n            if let Some(cls) = Class::<PlainDateTime>::from_object(obj) {\n                let pdt = cls.borrow().clone();\n                return Ok(pdt.to_plain_time());\n            }\n            if let Some(cls) = Class::<ZonedDateTime>::from_object(obj) {\n                let zdt = cls.borrow().clone();\n                return Ok(zdt.to_plain_time());\n            }\n            return Self::from_object(&ctx, obj);\n        }\n\n        let str = info\n            .as_string()\n            .and_then(|s| s.to_string().ok())\n            .or_throw_type(&ctx, \"Cannot convert value to string\")?;\n\n        Self::from_str(&ctx, &str)\n    }\n\n    fn add(&self, ctx: Ctx<'_>, duration: Value<'_>) -> Result<Self> {\n        let duration = Duration::from_value(&ctx, &duration)?;\n        let span = duration.into_inner();\n        let time = self.inner.checked_add(span).or_throw_range(&ctx, \"\")?;\n        Ok(Self { inner: time })\n    }\n\n    fn equals(&self, other: Self) -> bool {\n        self.inner == other.inner\n    }\n\n    fn round(&self, ctx: Ctx<'_>, options: Value<'_>) -> Result<Self> {\n        let round = TimeRoundOption::from_value(&ctx, &options)?;\n        let round = round.into_inner();\n        let time = self.inner.round(round).or_throw_range(&ctx, \"\")?;\n        Ok(Self { inner: time })\n    }\n\n    fn since(&self, other: Self) -> Duration {\n        Duration::new_object(self.inner - other.inner)\n    }\n\n    fn subtract(&self, ctx: Ctx<'_>, duration: Value<'_>) -> Result<Self> {\n        let duration = Duration::from_value(&ctx, &duration)?;\n        let span = duration.into_inner();\n        let time = self.inner.checked_sub(span).or_throw_range(&ctx, \"\")?;\n        Ok(Self { inner: time })\n    }\n\n    #[allow(clippy::inherent_to_string)]\n    #[qjs(rename = PredefinedAtom::ToJSON)]\n    fn to_json(&self) -> String {\n        self.inner.to_string()\n    }\n\n    #[allow(clippy::inherent_to_string)]\n    #[qjs(rename = PredefinedAtom::ToString)]\n    fn to_string(&self) -> String {\n        self.inner.to_string()\n    }\n\n    fn until(&self, other: Self) -> Duration {\n        Duration::new_object(other.inner - self.inner)\n    }\n\n    fn value_of(&self, ctx: Ctx<'_>) -> Result<()> {\n        Err(Exception::throw_type(\n            &ctx,\n            \"can't convert PlainTime to primitive type\",\n        ))\n    }\n\n    fn with(&self, ctx: Ctx<'_>, info: Value<'_>) -> Result<Self> {\n        let time = self.inner.time_with(&ctx, &info)?;\n        Ok(Self { inner: time })\n    }\n\n    #[qjs(get)]\n    fn hour(&self) -> i8 {\n        self.inner.hour()\n    }\n\n    #[qjs(get)]\n    fn microsecond(&self) -> i16 {\n        self.inner.microsecond()\n    }\n\n    #[qjs(get)]\n    fn millisecond(&self) -> i16 {\n        self.inner.millisecond()\n    }\n\n    #[qjs(get)]\n    fn minute(&self) -> i8 {\n        self.inner.minute()\n    }\n\n    #[qjs(get)]\n    fn nanosecond(&self) -> i16 {\n        self.inner.nanosecond()\n    }\n\n    #[qjs(get)]\n    fn second(&self) -> i8 {\n        self.inner.second()\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    fn to_string_tag(&self) -> &'static str {\n        \"Temporal.PlainTime\"\n    }\n}\n\nimpl PlainTime {\n    fn fill_object<'js>(ctx: &Ctx<'js>, args: &Rest<Value<'js>>) -> Result<Object<'js>> {\n        let obj = Object::new(ctx.clone())?;\n        let mut iter = args.0.iter().cloned();\n        fill_from_iter(&obj, &mut iter, true)?;\n        Ok(obj)\n    }\n\n    fn from_object(ctx: &Ctx<'_>, obj: &Object<'_>) -> Result<Self> {\n        let time = Time::from_object(ctx, obj)?;\n        Ok(Self { inner: time })\n    }\n\n    fn from_str(ctx: &Ctx<'_>, str: &str) -> Result<Self> {\n        let time = Time::from_str(str).or_throw_range(ctx, \"\")?;\n        Ok(Self { inner: time })\n    }\n\n    pub(crate) fn from_ts_tz(ctx: &Ctx<'_>, ts: &Timestamp, tz: &str) -> Result<Self> {\n        let zoned = ts.in_tz(tz).or_throw_range(ctx, \"\")?;\n        let zdt = ZonedDateTime::new_object(zoned);\n        Ok(zdt.to_plain_time())\n    }\n\n    pub(crate) fn into_inner(self) -> Time {\n        self.inner\n    }\n\n    pub(crate) fn new_object(time: Time) -> Self {\n        Self { inner: time }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_temporal/src/utils/date.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse jiff::civil::Date;\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{Ctx, Object, Result, Value};\n\npub trait DateExt {\n    fn from_object(ctx: &Ctx<'_>, obj: &Object<'_>) -> Result<Date>;\n    fn date_with(&self, ctx: &Ctx<'_>, value: &Value<'_>) -> Result<Date>;\n}\n\nimpl DateExt for Date {\n    fn from_object(ctx: &Ctx<'_>, obj: &Object<'_>) -> Result<Self> {\n        from_obj(ctx, obj)\n    }\n\n    fn date_with(&self, ctx: &Ctx<'_>, value: &Value<'_>) -> Result<Self> {\n        let obj = value\n            .as_object()\n            .or_throw_type(ctx, \"Cannot convert value to object\")?;\n\n        into_date(ctx, self, obj)\n    }\n}\n\nfn from_obj(ctx: &Ctx<'_>, obj: &Object<'_>) -> Result<Date> {\n    let year = obj.get::<_, i16>(\"year\").or_throw_range(ctx, \"\")?;\n    let month = obj.get::<_, i8>(\"month\").or_throw_range(ctx, \"\")?;\n    let day = obj.get::<_, i8>(\"day\").or_throw_range(ctx, \"\")?;\n\n    let date = Date::new(year, month, day).or_throw_range(ctx, \"\")?;\n    Ok(date)\n}\n\nfn into_date(ctx: &Ctx<'_>, date: &Date, obj: &Object<'_>) -> Result<Date> {\n    let mut date = date.with();\n    if let Ok(v) = obj.get::<_, i16>(\"yaer\") {\n        date = date.year(v);\n    }\n    if let Ok(v) = obj.get::<_, i8>(\"month\") {\n        date = date.month(v);\n    }\n    if let Ok(v) = obj.get::<_, i8>(\"day\") {\n        date = date.day(v);\n    }\n    date.build().or_throw_range(ctx, \"\")\n}\n\npub(crate) fn fill_from_iter<'js, I>(obj: &Object<'js>, iter: &mut I, calendar: bool) -> Result<()>\nwhere\n    I: Iterator<Item = Value<'js>>,\n{\n    if let Some(v) = iter.next() {\n        obj.set(\"year\", v)?;\n    }\n    if let Some(v) = iter.next() {\n        obj.set(\"month\", v)?;\n    }\n    if let Some(v) = iter.next() {\n        obj.set(\"day\", v)?;\n    }\n    if calendar {\n        if let Some(v) = iter.next() {\n            obj.set(\"calendar\", v)?;\n        }\n    }\n    Ok(())\n}\n\npub(crate) fn fill_duration_from_iter<'js, I>(obj: &Object<'js>, iter: &mut I) -> Result<()>\nwhere\n    I: Iterator<Item = Value<'js>>,\n{\n    if let Some(v) = iter.next() {\n        obj.set(\"years\", v)?;\n    }\n    if let Some(v) = iter.next() {\n        obj.set(\"months\", v)?;\n    }\n    if let Some(v) = iter.next() {\n        obj.set(\"weeks\", v)?;\n    }\n    if let Some(v) = iter.next() {\n        obj.set(\"days\", v)?;\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "modules/llrt_temporal/src/utils/date_time.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse jiff::civil::{Date, DateTime, Time};\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{Ctx, Object, Result, Value};\n\nuse super::date::DateExt;\nuse super::time::TimeExt;\n\npub trait DateTimeExt {\n    fn from_object(ctx: &Ctx<'_>, obj: &Object<'_>) -> Result<DateTime>;\n    fn date_time_with(&self, ctx: &Ctx<'_>, value: &Value<'_>) -> Result<DateTime>;\n}\n\nimpl DateTimeExt for DateTime {\n    fn from_object(ctx: &Ctx<'_>, obj: &Object<'_>) -> Result<Self> {\n        from_obj(ctx, obj)\n    }\n\n    fn date_time_with(&self, ctx: &Ctx<'_>, value: &Value<'_>) -> Result<Self> {\n        let obj = value\n            .as_object()\n            .or_throw_type(ctx, \"Cannot convert value to object\")?;\n\n        into_date_time(ctx, self, obj)\n    }\n}\n\nfn from_obj(ctx: &Ctx<'_>, obj: &Object<'_>) -> Result<DateTime> {\n    let date = Date::from_object(ctx, obj)?;\n    let time = Time::from_object(ctx, obj)?;\n    let dt = DateTime::from_parts(date, time);\n    Ok(dt)\n}\n\nfn into_date_time(ctx: &Ctx<'_>, dt: &DateTime, obj: &Object<'_>) -> Result<DateTime> {\n    let mut dt = dt.with();\n    if let Ok(v) = obj.get::<_, i16>(\"yaer\") {\n        dt = dt.year(v);\n    }\n    if let Ok(v) = obj.get::<_, i8>(\"month\") {\n        dt = dt.month(v);\n    }\n    if let Ok(v) = obj.get::<_, i8>(\"day\") {\n        dt = dt.day(v);\n    }\n    if let Ok(v) = obj.get::<_, i8>(\"hour\") {\n        dt = dt.hour(v);\n    }\n    if let Ok(v) = obj.get::<_, i8>(\"minute\") {\n        dt = dt.minute(v);\n    }\n    if let Ok(v) = obj.get::<_, i8>(\"second\") {\n        dt = dt.second(v);\n    }\n    if let Ok(v) = obj.get::<_, i16>(\"millisecond\") {\n        dt = dt.millisecond(v);\n    }\n    if let Ok(v) = obj.get::<_, i16>(\"microsecond\") {\n        dt = dt.microsecond(v);\n    }\n    if let Ok(v) = obj.get::<_, i16>(\"nanosecond\") {\n        dt = dt.nanosecond(v);\n    }\n    dt.build().or_throw_range(ctx, \"\")\n}\n"
  },
  {
    "path": "modules/llrt_temporal/src/utils/mod.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\npub mod date;\npub mod date_time;\npub mod round;\npub mod span;\npub mod time;\npub mod total;\npub mod zoned;\n\nuse jiff::{RoundMode, Unit};\nuse rquickjs::{Ctx, Exception, Result};\n\npub(crate) fn get_unit(ctx: &Ctx, unit: &str) -> Result<Unit> {\n    let unit = match unit {\n        \"day\" => Unit::Day,\n        \"hour\" => Unit::Hour,\n        \"minute\" => Unit::Minute,\n        \"second\" => Unit::Second,\n        \"millisecond\" => Unit::Millisecond,\n        \"microsecond\" => Unit::Microsecond,\n        \"nanosecond\" => Unit::Nanosecond,\n        _ => return Err(Exception::throw_type(ctx, \"Cannot convert to unit\")),\n    };\n    Ok(unit)\n}\n\npub(crate) fn get_duration_unit(ctx: &Ctx, unit: &Option<String>) -> Result<Option<Unit>> {\n    let Some(unit) = unit else {\n        return Ok(None);\n    };\n    let unit = match unit.as_str() {\n        \"years\" => Unit::Year,\n        \"months\" => Unit::Month,\n        \"weeks\" => Unit::Week,\n        \"days\" => Unit::Day,\n        \"hours\" => Unit::Hour,\n        \"minutes\" => Unit::Minute,\n        \"seconds\" => Unit::Second,\n        \"milliseconds\" => Unit::Millisecond,\n        \"microseconds\" => Unit::Microsecond,\n        \"nanoseconds\" => Unit::Nanosecond,\n        _ => return Err(Exception::throw_type(ctx, \"Cannot convert to unit\")),\n    };\n    Ok(Some(unit))\n}\n\npub(crate) fn get_round_mode(ctx: &Ctx, mode: &Option<String>) -> Result<RoundMode> {\n    let mode = match mode.clone().unwrap_or_else(|| \"halfExpand\".into()).as_ref() {\n        \"ceil\" => RoundMode::Ceil,\n        \"floor\" => RoundMode::Floor,\n        \"expand\" => RoundMode::Expand,\n        \"trunc\" => RoundMode::Trunc,\n        \"halfCeil\" => RoundMode::HalfCeil,\n        \"halfFloor\" => RoundMode::HalfFloor,\n        \"halfExpand\" => RoundMode::HalfExpand,\n        \"halfTrunc\" => RoundMode::HalfTrunc,\n        \"halfEven\" => RoundMode::HalfEven,\n        _ => return Err(Exception::throw_type(ctx, \"Cannot convert to RoundMode\")),\n    };\n    Ok(mode)\n}\n"
  },
  {
    "path": "modules/llrt_temporal/src/utils/round/date_time.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse jiff::{civil::DateTimeRound, RoundMode, Unit};\n\nuse super::{RoundBuilder, RoundOption};\n\nimpl RoundBuilder for DateTimeRound {\n    fn new() -> Self {\n        DateTimeRound::new()\n    }\n\n    fn smallest(self, unit: Unit) -> Self {\n        self.smallest(unit)\n    }\n\n    fn mode(self, mode: RoundMode) -> Self {\n        self.mode(mode)\n    }\n\n    fn increment(self, increment: i64) -> Self {\n        self.increment(increment)\n    }\n}\n\npub(crate) type DateTimeRoundOption = RoundOption<DateTimeRound>;\n"
  },
  {
    "path": "modules/llrt_temporal/src/utils/round/mod.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\npub mod date_time;\npub mod span;\npub mod time;\npub mod timestamp;\npub mod zoned;\n\nuse jiff::{RoundMode, Unit};\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{Ctx, Result, Value};\n\nuse crate::utils::{get_round_mode, get_unit};\n\npub(crate) trait RoundBuilder: Sized {\n    fn new() -> Self;\n    fn smallest(self, unit: Unit) -> Self;\n    fn mode(self, mode: RoundMode) -> Self;\n    fn increment(self, increment: i64) -> Self;\n}\n\npub(crate) struct RoundOption<T> {\n    inner: T,\n}\n\nimpl<T: RoundBuilder> RoundOption<T> {\n    pub(crate) fn from_value(ctx: &Ctx<'_>, value: &Value<'_>) -> Result<Self> {\n        if let Some(obj) = value.as_object() {\n            let unit = obj\n                .get::<_, String>(\"smallestUnit\")\n                .or_throw_range(ctx, \"\")?;\n            let mode = obj.get::<_, String>(\"roundingMode\").ok();\n            let increment = obj.get::<_, i64>(\"roundingIncrement\").ok();\n            let round = Self::from(ctx, &unit, &mode, &increment)?;\n            return Ok(Self { inner: round });\n        }\n\n        let unit = value\n            .as_string()\n            .and_then(|s| s.to_string().ok())\n            .or_throw_type(ctx, \"Cannot convert value to string\")?;\n        let round = Self::from(ctx, &unit, &None, &None)?;\n        Ok(Self { inner: round })\n    }\n\n    pub(crate) fn into_inner(self) -> T {\n        self.inner\n    }\n\n    fn from(ctx: &Ctx, unit: &str, mode: &Option<String>, increment: &Option<i64>) -> Result<T> {\n        let unit = get_unit(ctx, unit).or_throw_range(ctx, \"\")?;\n        let mode = get_round_mode(ctx, mode)?;\n        let increment = increment.unwrap_or(1);\n        Ok(T::new().smallest(unit).mode(mode).increment(increment))\n    }\n}\n"
  },
  {
    "path": "modules/llrt_temporal/src/utils/round/span.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse jiff::{Span, SpanRound, Unit};\nuse rquickjs::{Ctx, Result, Value};\n\nuse crate::utils::span::SpanExt;\nuse crate::utils::{get_duration_unit, get_round_mode};\n\npub(crate) struct SpanRoundOption<'a> {\n    inner: SpanRound<'a>,\n}\n\nimpl<'a> SpanRoundOption<'a> {\n    pub(crate) fn from_value(ctx: &Ctx<'_>, value: &Value<'a>) -> Result<Self> {\n        if let Some(obj) = value.as_object() {\n            let p1 = obj.get::<_, String>(\"largestUnit\").ok();\n            let p2 = obj.get::<_, Value>(\"relativeTo\").ok();\n            let p3 = obj.get::<_, i64>(\"roundingIncrement\").ok();\n            let p4 = obj.get::<_, String>(\"roundingMode\").ok();\n            let p5 = obj.get::<_, String>(\"smallestUnit\").ok();\n            let round = Self::from(ctx, &p1, &p2, &p3, &p4, &p5)?;\n            return Ok(Self { inner: round });\n        }\n\n        let unit = value.as_string().and_then(|s| s.to_string().ok());\n        let round = Self::from(ctx, &None, &None, &None, &None, &unit)?;\n        Ok(Self { inner: round })\n    }\n\n    pub(crate) fn into_inner(self) -> SpanRound<'a> {\n        self.inner\n    }\n\n    fn from(\n        ctx: &Ctx,\n        largest_unit: &Option<String>,\n        relative_to: &Option<Value<'a>>,\n        increment: &Option<i64>,\n        mode: &Option<String>,\n        smallest_unit: &Option<String>,\n    ) -> Result<SpanRound<'a>> {\n        let largest_unit = get_duration_unit(ctx, largest_unit)?;\n        let relative_to = Span::into_span_relative_to(relative_to);\n        let increment = increment.unwrap_or(1);\n        let mode = get_round_mode(ctx, mode)?;\n        let smallest_unit = get_duration_unit(ctx, smallest_unit)?;\n\n        let mut span_round = SpanRound::new().mode(mode).increment(increment);\n        if let Some(largest_unit) = largest_unit {\n            span_round = span_round.largest(largest_unit);\n        }\n        if let Some(smallest_unit) = smallest_unit {\n            span_round = span_round.smallest(smallest_unit);\n        }\n        if let Some(relative_to) = relative_to {\n            span_round = span_round.relative(relative_to);\n        } else if largest_unit.is_some_and(|u| u < Unit::Day) {\n            span_round = span_round.days_are_24_hours();\n        }\n        Ok(span_round)\n    }\n}\n"
  },
  {
    "path": "modules/llrt_temporal/src/utils/round/time.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse jiff::{civil::TimeRound, RoundMode, Unit};\n\nuse super::{RoundBuilder, RoundOption};\n\nimpl RoundBuilder for TimeRound {\n    fn new() -> Self {\n        TimeRound::new()\n    }\n\n    fn smallest(self, unit: Unit) -> Self {\n        self.smallest(unit)\n    }\n\n    fn mode(self, mode: RoundMode) -> Self {\n        self.mode(mode)\n    }\n\n    fn increment(self, increment: i64) -> Self {\n        self.increment(increment)\n    }\n}\n\npub(crate) type TimeRoundOption = RoundOption<TimeRound>;\n"
  },
  {
    "path": "modules/llrt_temporal/src/utils/round/timestamp.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse jiff::{RoundMode, TimestampRound, Unit};\n\nuse super::{RoundBuilder, RoundOption};\n\nimpl RoundBuilder for TimestampRound {\n    fn new() -> Self {\n        TimestampRound::new()\n    }\n\n    fn smallest(self, unit: Unit) -> Self {\n        self.smallest(unit)\n    }\n\n    fn mode(self, mode: RoundMode) -> Self {\n        self.mode(mode)\n    }\n\n    fn increment(self, increment: i64) -> Self {\n        self.increment(increment)\n    }\n}\n\npub(crate) type TimestampRoundOption = RoundOption<TimestampRound>;\n"
  },
  {
    "path": "modules/llrt_temporal/src/utils/round/zoned.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse jiff::{RoundMode, Unit, ZonedRound};\n\nuse super::{RoundBuilder, RoundOption};\n\nimpl RoundBuilder for ZonedRound {\n    fn new() -> Self {\n        ZonedRound::new()\n    }\n\n    fn smallest(self, unit: Unit) -> Self {\n        self.smallest(unit)\n    }\n\n    fn mode(self, mode: RoundMode) -> Self {\n        self.mode(mode)\n    }\n\n    fn increment(self, increment: i64) -> Self {\n        self.increment(increment)\n    }\n}\n\npub(crate) type ZonedRoundOption = RoundOption<ZonedRound>;\n"
  },
  {
    "path": "modules/llrt_temporal/src/utils/span.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse jiff::{Span, SpanCompare, SpanRelativeTo};\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{prelude::Opt, Class, Ctx, Object, Result, Value};\n\nuse crate::plain_date::PlainDate;\nuse crate::plain_date_time::PlainDateTime;\nuse crate::zoned_date_time::ZonedDateTime;\n\npub trait SpanExt {\n    fn from_object(ctx: &Ctx<'_>, obj: &Object<'_>) -> Result<Span>;\n    fn span_with(self, ctx: &Ctx<'_>, value: &Value<'_>) -> Result<Span>;\n    fn into_span_compare<'a>(span: &Span, value: &Opt<Value<'a>>) -> SpanCompare<'a>;\n    fn into_span_relative_to<'a>(value: &Option<Value<'a>>) -> Option<SpanRelativeTo<'a>>;\n}\n\nimpl SpanExt for Span {\n    fn from_object(ctx: &Ctx<'_>, obj: &Object<'_>) -> Result<Self> {\n        into_span(ctx, None, obj)\n    }\n\n    fn span_with(self, ctx: &Ctx<'_>, value: &Value<'_>) -> Result<Self> {\n        let obj = value\n            .as_object()\n            .or_throw_type(ctx, \"Cannot convert value to object\")?;\n\n        into_span(ctx, Some(self), obj)\n    }\n\n    fn into_span_compare<'a>(span: &Span, value: &Opt<Value<'a>>) -> SpanCompare<'a> {\n        let Some(ref value) = value.0 else {\n            return span.into();\n        };\n        if let Some(object) = value.as_object() {\n            if let Ok(v) = object.get::<_, Value>(\"relativeTo\") {\n                if let Some(relative) = Self::into_span_relative_to(&Some(v)) {\n                    return (span, relative).into();\n                }\n            }\n        }\n        span.into()\n    }\n\n    fn into_span_relative_to<'a>(value: &Option<Value<'a>>) -> Option<SpanRelativeTo<'a>> {\n        let Some(value) = value else {\n            return None;\n        };\n        if let Some(obj) = value.as_object() {\n            if let Some(cls) = Class::<PlainDate>::from_object(obj) {\n                let pd = cls.borrow().clone();\n                return Some(pd.into_inner().into());\n            }\n            if let Some(cls) = Class::<PlainDateTime>::from_object(obj) {\n                let pdt = cls.borrow().clone();\n                return Some(pdt.into_inner().into());\n            }\n            if let Some(cls) = Class::<ZonedDateTime>::from_object(obj) {\n                let zdt = cls.borrow().clone();\n                return Some(zdt.into_inner().datetime().into());\n            }\n        }\n        None\n    }\n}\n\nfn into_span(ctx: &Ctx<'_>, span: Option<Span>, obj: &Object<'_>) -> Result<Span> {\n    let mut span = span.unwrap_or_default();\n    if let Ok(v) = obj.get::<_, i64>(\"days\") {\n        span = span.try_days(v).or_throw_range(ctx, \"\")?;\n    }\n    if let Ok(v) = obj.get::<_, i64>(\"hours\") {\n        span = span.try_hours(v).or_throw_range(ctx, \"\")?;\n    }\n    if let Ok(v) = obj.get::<_, i64>(\"microseconds\") {\n        span = span.try_microseconds(v).or_throw_range(ctx, \"\")?;\n    }\n    if let Ok(v) = obj.get::<_, i64>(\"milliseconds\") {\n        span = span.try_milliseconds(v).or_throw_range(ctx, \"\")?;\n    }\n    if let Ok(v) = obj.get::<_, i64>(\"minutes\") {\n        span = span.try_minutes(v).or_throw_range(ctx, \"\")?;\n    }\n    if let Ok(v) = obj.get::<_, i64>(\"months\") {\n        span = span.try_months(v).or_throw_range(ctx, \"\")?;\n    }\n    if let Ok(v) = obj.get::<_, i64>(\"nanoseconds\") {\n        span = span.try_nanoseconds(v).or_throw_range(ctx, \"\")?;\n    }\n    if let Ok(v) = obj.get::<_, i64>(\"seconds\") {\n        span = span.try_seconds(v).or_throw_range(ctx, \"\")?;\n    }\n    if let Ok(v) = obj.get::<_, i64>(\"weeks\") {\n        span = span.try_weeks(v).or_throw_range(ctx, \"\")?;\n    }\n    if let Ok(v) = obj.get::<_, i64>(\"years\") {\n        span = span.try_years(v).or_throw_range(ctx, \"\")?;\n    }\n    Ok(span)\n}\n"
  },
  {
    "path": "modules/llrt_temporal/src/utils/time.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse jiff::civil::Time;\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{Ctx, Object, Result, Value};\n\npub trait TimeExt {\n    fn from_object(ctx: &Ctx<'_>, obj: &Object<'_>) -> Result<Time>;\n    fn time_with(&self, ctx: &Ctx<'_>, value: &Value<'_>) -> Result<Time>;\n}\n\nimpl TimeExt for Time {\n    fn from_object(ctx: &Ctx<'_>, obj: &Object<'_>) -> Result<Self> {\n        from_obj(ctx, obj)\n    }\n\n    fn time_with(&self, ctx: &Ctx<'_>, value: &Value<'_>) -> Result<Self> {\n        let obj = value\n            .as_object()\n            .or_throw_type(ctx, \"Cannot convert value to object\")?;\n\n        into_time(ctx, self, obj)\n    }\n}\n\nfn from_obj(ctx: &Ctx<'_>, obj: &Object<'_>) -> Result<Time> {\n    let hour = obj.get::<_, i8>(\"hour\").unwrap_or_default();\n    let minute = obj.get::<_, i8>(\"minute\").unwrap_or_default();\n    let second = obj.get::<_, i8>(\"second\").unwrap_or_default();\n\n    let millis = obj.get::<_, i32>(\"millisecond\").unwrap_or_default();\n    let micros = obj.get::<_, i32>(\"microsecond\").unwrap_or_default();\n    let nanos = obj.get::<_, i32>(\"nanosecond\").unwrap_or_default();\n    let subsec_ns = nanos + micros * 1_000 + millis * 1_000_000;\n\n    let time = Time::new(hour, minute, second, subsec_ns).or_throw_range(ctx, \"\")?;\n    Ok(time)\n}\n\nfn into_time(ctx: &Ctx<'_>, time: &Time, obj: &Object<'_>) -> Result<Time> {\n    let mut time = time.with();\n    if let Ok(v) = obj.get::<_, i8>(\"hour\") {\n        time = time.hour(v);\n    }\n    if let Ok(v) = obj.get::<_, i8>(\"minute\") {\n        time = time.minute(v);\n    }\n    if let Ok(v) = obj.get::<_, i8>(\"second\") {\n        time = time.second(v);\n    }\n    if let Ok(v) = obj.get::<_, i16>(\"millisecond\") {\n        time = time.millisecond(v);\n    }\n    if let Ok(v) = obj.get::<_, i16>(\"microsecond\") {\n        time = time.microsecond(v);\n    }\n    if let Ok(v) = obj.get::<_, i16>(\"nanosecond\") {\n        time = time.nanosecond(v);\n    }\n    time.build().or_throw_range(ctx, \"\")\n}\n\npub(crate) fn fill_from_iter<'js, I>(obj: &Object<'js>, iter: &mut I, calendar: bool) -> Result<()>\nwhere\n    I: Iterator<Item = Value<'js>>,\n{\n    if let Some(v) = iter.next() {\n        obj.set(\"hour\", v)?;\n    }\n    if let Some(v) = iter.next() {\n        obj.set(\"minute\", v)?;\n    }\n    if let Some(v) = iter.next() {\n        obj.set(\"second\", v)?;\n    }\n    if let Some(v) = iter.next() {\n        obj.set(\"millisecond\", v)?;\n    }\n    if let Some(v) = iter.next() {\n        obj.set(\"microsecond\", v)?;\n    }\n    if let Some(v) = iter.next() {\n        obj.set(\"nanosecond\", v)?;\n    }\n    if calendar {\n        if let Some(v) = iter.next() {\n            obj.set(\"calendar\", v)?;\n        }\n    }\n    Ok(())\n}\n\npub(crate) fn fill_duration_from_iter<'js, I>(obj: &Object<'js>, iter: &mut I) -> Result<()>\nwhere\n    I: Iterator<Item = Value<'js>>,\n{\n    if let Some(v) = iter.next() {\n        obj.set(\"hours\", v)?;\n    }\n    if let Some(v) = iter.next() {\n        obj.set(\"minutes\", v)?;\n    }\n    if let Some(v) = iter.next() {\n        obj.set(\"seconds\", v)?;\n    }\n    if let Some(v) = iter.next() {\n        obj.set(\"milliseconds\", v)?;\n    }\n    if let Some(v) = iter.next() {\n        obj.set(\"microseconds\", v)?;\n    }\n    if let Some(v) = iter.next() {\n        obj.set(\"nanoseconds\", v)?;\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "modules/llrt_temporal/src/utils/total/mod.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\npub mod span;\n"
  },
  {
    "path": "modules/llrt_temporal/src/utils/total/span.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse jiff::{Span, SpanTotal, Unit};\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{Ctx, Result, Value};\n\nuse crate::utils::get_duration_unit;\nuse crate::utils::span::SpanExt;\n\npub(crate) struct SpanTotalOption<'a> {\n    inner: SpanTotal<'a>,\n}\n\nimpl<'a> SpanTotalOption<'a> {\n    pub(crate) fn from_value(ctx: &Ctx<'_>, value: &Value<'a>) -> Result<Self> {\n        if let Some(obj) = value.as_object() {\n            let relative_to = obj.get::<_, Value>(\"relativeTo\").ok();\n            let unit = obj.get::<_, String>(\"unit\").ok();\n            let total = Self::from(ctx, &relative_to, &unit)?;\n            return Ok(Self { inner: total });\n        }\n\n        let unit = value.as_string().and_then(|s| s.to_string().ok());\n        let total = Self::from(ctx, &None, &unit)?;\n        Ok(Self { inner: total })\n    }\n\n    pub(crate) fn into_inner(self) -> SpanTotal<'a> {\n        self.inner\n    }\n\n    fn from(\n        ctx: &Ctx,\n        relative_to: &Option<Value<'a>>,\n        unit: &Option<String>,\n    ) -> Result<SpanTotal<'a>> {\n        let relative_to = Span::into_span_relative_to(relative_to);\n        let unit = get_duration_unit(ctx, unit)?;\n        let unit = unit.or_throw_range(ctx, \"Invalid unit\")?;\n\n        if let Some(relative_to) = relative_to {\n            Ok((unit, relative_to).into())\n        } else if unit < Unit::Day {\n            let span_total: SpanTotal = unit.into();\n            Ok(span_total.days_are_24_hours())\n        } else {\n            Ok(unit.into())\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_temporal/src/utils/zoned.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse jiff::{civil::DateTime, Zoned};\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{Ctx, Object, Result, Value};\n\nuse crate::utils::date_time::DateTimeExt;\n\npub trait ZonedExt {\n    fn from_object(ctx: &Ctx<'_>, obj: &Object<'_>) -> Result<Zoned>;\n    fn zoned_with(&self, ctx: &Ctx<'_>, value: &Value<'_>) -> Result<Zoned>;\n}\n\nimpl ZonedExt for Zoned {\n    fn from_object(ctx: &Ctx<'_>, obj: &Object<'_>) -> Result<Self> {\n        from_obj(ctx, obj)\n    }\n\n    fn zoned_with(&self, ctx: &Ctx<'_>, value: &Value<'_>) -> Result<Self> {\n        let obj = value\n            .as_object()\n            .or_throw_type(ctx, \"Cannot convert value to object\")?;\n\n        into_zoned(ctx, self, obj)\n    }\n}\n\nfn from_obj(ctx: &Ctx<'_>, obj: &Object<'_>) -> Result<Zoned> {\n    let dt = DateTime::from_object(ctx, obj)?;\n    let tz = obj.get::<_, String>(\"timeZone\").or_throw_type(ctx, \"\")?;\n    dt.in_tz(&tz).or_throw_range(ctx, \"\")\n}\n\nfn into_zoned(ctx: &Ctx<'_>, zoned: &Zoned, obj: &Object<'_>) -> Result<Zoned> {\n    let mut zoned = zoned.with();\n    if let Ok(v) = obj.get::<_, i8>(\"day\") {\n        zoned = zoned.day(v);\n    }\n    if let Ok(v) = obj.get::<_, i8>(\"hour\") {\n        zoned = zoned.hour(v);\n    }\n    if let Ok(v) = obj.get::<_, i16>(\"microsecond\") {\n        zoned = zoned.microsecond(v);\n    }\n    if let Ok(v) = obj.get::<_, i16>(\"millisecond\") {\n        zoned = zoned.millisecond(v);\n    }\n    if let Ok(v) = obj.get::<_, i8>(\"minute\") {\n        zoned = zoned.minute(v);\n    }\n    if let Ok(v) = obj.get::<_, i8>(\"month\") {\n        zoned = zoned.month(v);\n    }\n    if let Ok(v) = obj.get::<_, i16>(\"nanosecond\") {\n        zoned = zoned.nanosecond(v);\n    }\n    if let Ok(v) = obj.get::<_, i8>(\"second\") {\n        zoned = zoned.second(v);\n    }\n    if let Ok(v) = obj.get::<_, i16>(\"year\") {\n        zoned = zoned.year(v);\n    }\n    zoned.build().or_throw_range(ctx, \"\")\n}\n"
  },
  {
    "path": "modules/llrt_temporal/src/zoned_date_time.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{cmp::Ordering, str::FromStr};\n\nuse jiff::{Timestamp, Zoned};\nuse llrt_utils::result::ResultExt;\nuse rquickjs::Object;\nuse rquickjs::{\n    atom::PredefinedAtom, class::Trace, prelude::Opt, BigInt, Class, Ctx, Exception, JsLifetime,\n    Result, Value,\n};\n\nuse crate::duration::Duration;\nuse crate::instant::Instant;\nuse crate::plain_date::PlainDate;\nuse crate::plain_date_time::PlainDateTime;\nuse crate::plain_time::PlainTime;\nuse crate::utils::round::zoned::ZonedRoundOption;\nuse crate::utils::zoned::ZonedExt;\n\nuse super::extract_bigint_or_number;\n\n#[derive(Clone, JsLifetime, Trace)]\n#[rquickjs::class]\npub(crate) struct ZonedDateTime {\n    #[qjs(skip_trace)]\n    inner: Zoned,\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl ZonedDateTime {\n    #[qjs(constructor)]\n    fn new(ctx: Ctx<'_>, nanos: Value<'_>, tz: Opt<String>) -> Result<Self> {\n        Self::from_epoch_nanoseconds(&ctx, &nanos, &tz)\n    }\n\n    #[qjs(static)]\n    fn compare(datetime1: Self, datetime2: Self) -> i8 {\n        match datetime1.inner.cmp(&datetime2.inner) {\n            Ordering::Less => -1,\n            Ordering::Equal => 0,\n            Ordering::Greater => 1,\n        }\n    }\n\n    #[qjs(static)]\n    fn from(ctx: Ctx<'_>, info: Value<'_>) -> Result<Self> {\n        if let Some(obj) = info.as_object() {\n            if let Some(cls) = Class::<Self>::from_object(obj) {\n                return Ok(cls.borrow().clone());\n            }\n            return Self::from_object(&ctx, obj);\n        }\n\n        let str = info\n            .as_string()\n            .and_then(|s| s.to_string().ok())\n            .or_throw_type(&ctx, \"Cannot convert value to string\")?;\n\n        Self::from_str(&ctx, &str)\n    }\n\n    fn add(&self, ctx: Ctx<'_>, duration: Value<'_>) -> Result<Self> {\n        let duration = Duration::from_value(&ctx, &duration)?;\n        let span = duration.into_inner();\n        let zoned = self.inner.checked_add(span).or_throw_range(&ctx, \"\")?;\n        Ok(Self { inner: zoned })\n    }\n\n    fn equals(&self, other: Self) -> bool {\n        self.inner == other.inner\n    }\n\n    #[qjs(rename = \"getTimeZoneTransition\")]\n    fn get_tz_transition<'js>(&self, ctx: Ctx<'js>, options: Value<'_>) -> Result<Value<'js>> {\n        let tz = self.inner.time_zone();\n        let tzt = match get_timezone_direction(&ctx, &options)? {\n            Direction::Next => tz.following(self.inner.timestamp()).next(),\n            Direction::Previous => tz.preceding(self.inner.timestamp()).next(),\n        };\n        let Some(tzt) = tzt else {\n            return Ok(Value::new_null(ctx.clone()));\n        };\n        let zoned = tzt.timestamp().to_zoned(tz.clone());\n        Self::new_instance(&ctx, zoned)\n    }\n\n    fn round(&self, ctx: Ctx<'_>, options: Value<'_>) -> Result<Self> {\n        let round = ZonedRoundOption::from_value(&ctx, &options)?;\n        let round = round.into_inner();\n        let zoned = self.inner.round(round).or_throw_range(&ctx, \"\")?;\n        Ok(Self { inner: zoned })\n    }\n\n    fn since(&self, other: Self) -> Duration {\n        Duration::new_object(self.inner.clone() - other.inner)\n    }\n\n    fn subtract(&self, ctx: Ctx<'_>, duration: Value<'_>) -> Result<Self> {\n        let duration = Duration::from_value(&ctx, &duration)?;\n        let span = duration.into_inner();\n        let zoned = self.inner.checked_sub(span).or_throw_range(&ctx, \"\")?;\n        Ok(Self { inner: zoned })\n    }\n\n    fn to_instant(&self) -> Instant {\n        Instant::from_zoned(&self.inner)\n    }\n\n    #[allow(clippy::inherent_to_string)]\n    #[qjs(rename = PredefinedAtom::ToJSON)]\n    fn to_json(&self) -> String {\n        self.inner.to_string()\n    }\n\n    pub(crate) fn to_plain_date(&self) -> PlainDate {\n        let date = self.inner.date();\n        PlainDate::new_object(date)\n    }\n\n    pub(crate) fn to_plain_date_time(&self) -> PlainDateTime {\n        let dt = self.inner.datetime();\n        PlainDateTime::new_object(dt)\n    }\n\n    pub(crate) fn to_plain_time(&self) -> PlainTime {\n        let time = self.inner.time();\n        PlainTime::new_object(time)\n    }\n\n    #[allow(clippy::inherent_to_string)]\n    #[qjs(rename = PredefinedAtom::ToString)]\n    fn to_string(&self) -> String {\n        self.inner.to_string()\n    }\n\n    fn until(&self, other: Self) -> Duration {\n        Duration::new_object(other.inner - self.inner.clone())\n    }\n\n    fn value_of(&self, ctx: Ctx<'_>) -> Result<()> {\n        Err(Exception::throw_type(\n            &ctx,\n            \"can't convert ZonedDateTime to primitive type\",\n        ))\n    }\n\n    fn with(&self, ctx: Ctx<'_>, info: Value<'_>) -> Result<Self> {\n        let zoned = self.inner.zoned_with(&ctx, &info)?;\n        Ok(Self { inner: zoned })\n    }\n\n    fn with_time_zone(&self, ctx: Ctx<'_>, tz: String) -> Result<Self> {\n        let zoned = self.inner.in_tz(&tz).or_throw_range(&ctx, \"\")?;\n        Ok(Self { inner: zoned })\n    }\n\n    #[qjs(get)]\n    fn day(&self) -> i8 {\n        self.inner.day()\n    }\n\n    #[qjs(get)]\n    fn day_of_year(&self) -> i16 {\n        self.inner.day_of_year()\n    }\n\n    #[qjs(get)]\n    fn days_in_month(&self) -> i8 {\n        self.inner.days_in_month()\n    }\n\n    #[qjs(get)]\n    fn days_in_year(&self) -> i16 {\n        self.inner.days_in_year()\n    }\n\n    #[qjs(get)]\n    fn epoch_milliseconds(&self) -> i64 {\n        self.inner.timestamp().as_millisecond()\n    }\n\n    #[qjs(get)]\n    fn epoch_nanoseconds<'js>(&self, ctx: Ctx<'js>) -> Result<BigInt<'js>> {\n        let ns = self.inner.timestamp().as_nanosecond();\n        let ns = ns.try_into().or_throw_range(&ctx, \"\")?;\n        BigInt::from_i64(ctx, ns)\n    }\n\n    #[qjs(get)]\n    fn hour(&self) -> i8 {\n        self.inner.hour()\n    }\n\n    #[qjs(get)]\n    fn in_leap_year(&self) -> bool {\n        self.inner.in_leap_year()\n    }\n\n    #[qjs(get)]\n    fn microsecond(&self) -> i16 {\n        self.inner.microsecond()\n    }\n\n    #[qjs(get)]\n    fn millisecond(&self) -> i16 {\n        self.inner.millisecond()\n    }\n\n    #[qjs(get)]\n    fn minute(&self) -> i8 {\n        self.inner.minute()\n    }\n\n    #[qjs(get)]\n    fn month(&self) -> i8 {\n        self.inner.month()\n    }\n\n    #[qjs(get)]\n    fn nanosecond(&self) -> i16 {\n        self.inner.nanosecond()\n    }\n\n    #[qjs(get)]\n    fn offset(&self) -> String {\n        let offset = self.inner.offset().to_string();\n        match offset.len() {\n            3 => [&offset, \":00\"].concat(),\n            _ => offset,\n        }\n    }\n\n    #[qjs(get)]\n    fn second(&self) -> i8 {\n        self.inner.second()\n    }\n\n    #[qjs(get)]\n    fn time_zone_id(&self) -> String {\n        self.inner\n            .time_zone()\n            .iana_name()\n            .map(|s| s.to_string())\n            .unwrap_or_else(|| \"Etc/Unknown\".to_string())\n    }\n\n    #[qjs(get)]\n    fn year(&self) -> i16 {\n        self.inner.year()\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    fn to_string_tag(&self) -> &'static str {\n        \"Temporal.ZonedDateTime\"\n    }\n}\n\nimpl ZonedDateTime {\n    fn from_epoch_nanoseconds(ctx: &Ctx<'_>, ns: &Value<'_>, tz: &Option<String>) -> Result<Self> {\n        let nanos = extract_bigint_or_number(ctx, ns)?;\n        Self::from_nanosecond(ctx, nanos, tz)\n    }\n\n    fn from_nanosecond(ctx: &Ctx<'_>, ns: i128, tz: &Option<String>) -> Result<Self> {\n        let ts = Timestamp::from_nanosecond(ns).or_throw_range(ctx, \"\")?;\n        let tz = tz.as_deref().unwrap_or(\"UTC\");\n        Self::from_ts_tz(ctx, &ts, tz)\n    }\n\n    fn from_object(ctx: &Ctx<'_>, obj: &Object<'_>) -> Result<Self> {\n        let zoned = Zoned::from_object(ctx, obj)?;\n        Ok(Self { inner: zoned })\n    }\n\n    pub(crate) fn from_ts_tz(ctx: &Ctx<'_>, ts: &Timestamp, tz: &str) -> Result<Self> {\n        let zoned = ts.in_tz(tz).or_throw_range(ctx, \"\")?;\n        Ok(Self { inner: zoned })\n    }\n\n    fn from_str(ctx: &Ctx<'_>, str: &str) -> Result<Self> {\n        let zoned = Zoned::from_str(str).or_throw_range(ctx, \"\")?;\n        Ok(Self { inner: zoned })\n    }\n\n    pub(crate) fn into_inner(self) -> Zoned {\n        self.inner\n    }\n\n    fn new_instance<'js>(ctx: &Ctx<'js>, zoned: Zoned) -> Result<Value<'js>> {\n        let zdt = Class::instance(ctx.clone(), Self { inner: zoned })?;\n        Ok(zdt.into_value())\n    }\n\n    pub(crate) fn new_object(zoned: Zoned) -> Self {\n        Self { inner: zoned }\n    }\n}\n\nenum Direction {\n    Next,\n    Previous,\n}\n\nfn get_timezone_direction(ctx: &Ctx<'_>, val: &Value<'_>) -> Result<Direction> {\n    fn matching(ctx: &Ctx, str: &str) -> Result<Direction> {\n        match str {\n            \"next\" => Ok(Direction::Next),\n            \"previous\" => Ok(Direction::Previous),\n            _ => Err(Exception::throw_type(ctx, \"Invalid direction\")),\n        }\n    }\n\n    if let Some(str) = val.as_string() {\n        if let Ok(v) = str.to_string() {\n            return matching(ctx, v.as_str());\n        }\n    } else if let Some(obj) = val.as_object() {\n        if let Ok(v) = obj.get::<_, String>(\"direction\") {\n            return matching(ctx, v.as_str());\n        }\n    }\n    Err(Exception::throw_type(ctx, \"Invalid direction\"))\n}\n"
  },
  {
    "path": "modules/llrt_timers/Cargo.toml",
    "content": "[package]\nname = \"llrt_timers\"\ndescription = \"LLRT Module timers\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\n\n[lib]\nname = \"llrt_timers\"\npath = \"src/lib.rs\"\n\n[dependencies]\nllrt_context = { version = \"0.8.1-beta\", path = \"../../libs/llrt_context\" }\nllrt_hooking = { version = \"0.8.1-beta\", path = \"../../libs/llrt_hooking\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nonce_cell = { version = \"1\", features = [\"std\"], default-features = false }\nrquickjs = { version = \"0.11\", default-features = false }\ntokio = { version = \"1\", features = [\n  \"macros\",\n  \"sync\",\n  \"time\",\n], default-features = false }\n\n[dev-dependencies]\nllrt_test = { path = \"../../libs/llrt_test\" }\n"
  },
  {
    "path": "modules/llrt_timers/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{\n    pin::{pin, Pin},\n    ptr::NonNull,\n    rc::Rc,\n    sync::{\n        atomic::{AtomicUsize, Ordering},\n        Mutex, MutexGuard,\n    },\n    time::Duration,\n};\n\nuse llrt_context::CtxExtension;\npub use llrt_hooking::{invoke_async_hook, register_finalization_registry, HookType};\nuse llrt_utils::{\n    module::{export_default, ModuleInfo},\n    provider::ProviderType,\n};\nuse once_cell::sync::Lazy;\nuse rquickjs::{\n    module::{Declarations, Exports, ModuleDef},\n    prelude::{Func, Opt},\n    qjs, Ctx, Exception, Function, Persistent, Result, Value,\n};\nuse tokio::{\n    select,\n    sync::Notify,\n    time::{Instant, Sleep},\n};\n\nstatic TIMER_ID: AtomicUsize = AtomicUsize::new(0);\nstatic RT_TIMER_STATE: Lazy<Mutex<Vec<RuntimeTimerState>>> = Lazy::new(|| Mutex::new(Vec::new()));\n\npub struct RuntimeTimerState {\n    timers: Vec<Timeout>,\n    rt: *mut qjs::JSRuntime,\n    running: bool,\n    deadline: Instant,\n    notify: Rc<Notify>,\n}\nimpl RuntimeTimerState {\n    fn new(rt: *mut qjs::JSRuntime) -> Self {\n        let deadline = Instant::now() + Duration::from_secs(86400 * 365 * 30);\n        Self {\n            timers: Default::default(),\n            rt,\n            deadline,\n            running: false,\n            notify: Default::default(),\n        }\n    }\n}\n\nunsafe impl Send for RuntimeTimerState {}\n\n#[derive(Clone)]\npub struct Timeout {\n    callback: Option<Persistent<Function<'static>>>,\n    deadline: Instant,\n    raw_ctx: NonNull<qjs::JSContext>,\n    id: usize,\n    repeating: bool,\n    interval: u64,\n}\n\nimpl Default for Timeout {\n    fn default() -> Self {\n        Self {\n            callback: None,\n            deadline: Instant::now(),\n            raw_ctx: NonNull::dangling(),\n            id: 0,\n            repeating: false,\n            interval: 0,\n        }\n    }\n}\n\nfn queue_microtask<'js>(_ctx: Ctx<'js>, cb: Function<'js>) -> Result<()> {\n    // SAFETY: Since it checks in advance whether it is an Function type, we can always get a pointer to the Function.\n    let uid = unsafe { qjs::JS_VALUE_GET_PTR(cb.as_raw()) } as usize;\n    register_finalization_registry(&_ctx, cb.clone().into_value(), uid)?;\n    invoke_async_hook(&_ctx, HookType::Init, ProviderType::Microtask, uid)?;\n    // NOTE: Defer simply registers a task in a microtask queue\n    // and is separate from the timing of when the actual callback runs.\n    // Therefore, asynchronous before/after hooks are not meaningful and will not be implemented.\n\n    cb.defer::<()>(())?;\n    Ok(())\n}\n\npub fn set_timeout_interval<'js>(\n    ctx: &Ctx<'js>,\n    cb: Function<'js>,\n    delay: u64,\n    provider_type: ProviderType,\n) -> Result<usize> {\n    // SAFETY: Since it checks in advance whether it is an Function type, we can always get a pointer to the Function.\n    let uid = unsafe { qjs::JS_VALUE_GET_PTR(cb.as_raw()) } as usize;\n\n    // NOTE: https://noncodersuccess.medium.com/understanding-setimmediate-vs-settimeout-in-node-js-6a3ef8fc02d4\n    // If `setImmediate(fn)` and `setTimeout(fn, 0) are queued at the exact same time,\n    // `setImmediate(fn) takes precedence in Node.js, regardless of their execution order.\n    // This is due to the specifications of the Node.js event loop.\n    // The event loop specifications of LLRT are completely different from those of Node.js,\n    // but to make them the same, `setImmedaite()` is executed before any delay setting of `setTimeout()`.\n    let (repeating, deadline) = match provider_type {\n        ProviderType::Immediate => (false, Instant::now() - Duration::from_secs(600)), // before any setTimeout(fn, delay)\n        ProviderType::Timeout => (false, Instant::now() + Duration::from_millis(delay)),\n        ProviderType::Interval => (true, Instant::now() + Duration::from_millis(delay)),\n        _ => {\n            return Err(Exception::throw_type(\n                ctx,\n                \"The specified provider type is not supported.\",\n            ))\n        },\n    };\n\n    register_finalization_registry(ctx, cb.clone().into_value(), uid)?;\n    invoke_async_hook(ctx, HookType::Init, provider_type, uid)?;\n\n    let id = TIMER_ID.fetch_add(1, Ordering::Relaxed);\n\n    let callback = Persistent::<Function>::save(ctx, cb);\n\n    let timeout = Timeout {\n        deadline,\n        callback: Some(callback),\n        raw_ctx: ctx.as_raw(),\n        id,\n        repeating,\n        interval: delay,\n    };\n\n    let rt_ptr = unsafe { qjs::JS_GetRuntime(ctx.as_raw().as_ptr()) };\n\n    let mut rt_timer = RT_TIMER_STATE.lock().unwrap();\n    let state = get_timer_state(&mut rt_timer, rt_ptr);\n    state.timers.push(timeout);\n    let task_running = state.running;\n    if task_running {\n        if deadline < state.deadline {\n            state.deadline = deadline;\n            state.notify.notify_one();\n        }\n    } else {\n        state.running = true;\n        let timer_abort = state.notify.clone();\n        drop(rt_timer);\n        create_spawn_loop(rt_ptr, ctx, timer_abort, deadline)?;\n    }\n\n    Ok(id)\n}\n\nfn get_timer_state<'a>(\n    state_ref: &'a mut MutexGuard<Vec<RuntimeTimerState>>,\n    rt: *mut qjs::JSRuntime,\n) -> &'a mut RuntimeTimerState {\n    let rt_timers = state_ref.iter_mut().find(|state| state.rt == rt);\n\n    //save a branch\n    unsafe { rt_timers.unwrap_unchecked() }\n}\n\nfn clear_timeout_interval(ctx: Ctx<'_>, id: Opt<Value>) -> Result<()> {\n    if let Some(id) = id.0.and_then(|v| v.as_number()) {\n        let id = id as usize;\n        let rt = unsafe { qjs::JS_GetRuntime(ctx.as_raw().as_ptr()) };\n        let mut rt_timers = RT_TIMER_STATE.lock().unwrap();\n\n        let state = get_timer_state(&mut rt_timers, rt);\n        if let Some(timeout) = state.timers.iter_mut().find(|t| t.id == id) {\n            let _ = timeout.callback.take();\n            timeout.repeating = false;\n            timeout.deadline = Instant::now() - Duration::from_secs(1);\n            state.notify.notify_one()\n        }\n    }\n\n    Ok(())\n}\n\npub struct TimersModule;\n\nimpl ModuleDef for TimersModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(\"setTimeout\")?;\n        declare.declare(\"clearTimeout\")?;\n        declare.declare(\"setInterval\")?;\n        declare.declare(\"setImmediate\")?;\n        declare.declare(\"clearInterval\")?;\n        declare.declare(\"queueMicrotask\")?;\n        declare.declare(\"default\")?;\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        let globals = ctx.globals();\n\n        export_default(ctx, exports, |default| {\n            let functions = [\n                \"setTimeout\",\n                \"clearTimeout\",\n                \"setInterval\",\n                \"clearInterval\",\n                \"setImmediate\",\n                \"queueMicrotask\",\n            ];\n            for func_name in functions {\n                let function: Function = globals.get(func_name)?;\n                default.set(func_name, function)?;\n            }\n            Ok(())\n        })?;\n\n        Ok(())\n    }\n}\n\nimpl From<TimersModule> for ModuleInfo<TimersModule> {\n    fn from(val: TimersModule) -> Self {\n        ModuleInfo {\n            name: \"timers\",\n            module: val,\n        }\n    }\n}\n\npub fn init(ctx: &Ctx<'_>) -> Result<()> {\n    let rt_ptr = unsafe { qjs::JS_GetRuntime(ctx.as_raw().as_ptr()) };\n\n    let mut rt_timers = RT_TIMER_STATE.lock().unwrap();\n    rt_timers.push(RuntimeTimerState::new(rt_ptr));\n\n    let globals = ctx.globals();\n\n    globals.set(\n        \"setTimeout\",\n        Func::from(move |ctx, cb, delay: Opt<f64>| {\n            let delay = delay.unwrap_or(0.).max(0.) as u64;\n            set_timeout_interval(&ctx, cb, delay, ProviderType::Timeout)\n        }),\n    )?;\n\n    globals.set(\n        \"setInterval\",\n        Func::from(move |ctx, cb, delay: Opt<f64>| {\n            let delay = delay.unwrap_or(0.).max(0.) as u64;\n            set_timeout_interval(&ctx, cb, delay, ProviderType::Interval)\n        }),\n    )?;\n\n    globals.set(\"clearTimeout\", Func::from(clear_timeout_interval))?;\n\n    globals.set(\"clearInterval\", Func::from(clear_timeout_interval))?;\n\n    globals.set(\n        \"setImmediate\",\n        Func::from(move |ctx, cb| set_timeout_interval(&ctx, cb, 0, ProviderType::Immediate)),\n    )?;\n\n    globals.set(\"queueMicrotask\", Func::from(queue_microtask))?;\n\n    Ok(())\n}\n\n#[inline(always)]\nfn create_spawn_loop(\n    rt: *mut qjs::JSRuntime,\n    ctx: &Ctx<'_>,\n    timer_abort: Rc<Notify>,\n    deadline: Instant,\n) -> Result<()> {\n    ctx.spawn_exit_simple(async move {\n        let mut sleep = pin!(tokio::time::sleep_until(deadline));\n\n        let mut executing_timers: Vec<Option<ExecutingTimer>> = Default::default();\n\n        loop {\n            select! {\n                _ = timer_abort.notified() => {}\n                _ = sleep.as_mut() => {}\n            }\n\n            if !poll_timers(rt, &mut executing_timers, Some(&mut sleep), None)? {\n                break;\n            }\n        }\n        Ok(())\n    });\n\n    Ok(())\n}\n\npub struct ExecutingTimer(\n    Instant,\n    NonNull<qjs::JSContext>,\n    Persistent<Function<'static>>,\n);\n\nunsafe impl Send for ExecutingTimer {}\n\npub fn poll_timers(\n    rt: *mut qjs::JSRuntime,\n    call_vec: &mut Vec<Option<ExecutingTimer>>,\n    sleep: Option<&mut Pin<&mut Sleep>>,\n    deadline: Option<&mut Instant>,\n) -> Result<bool> {\n    static MIN_SLEEP: Duration = Duration::from_millis(4);\n    static FAR_FUTURE: Duration = Duration::from_secs(84200 * 365 * 30);\n\n    let mut rt_timers = RT_TIMER_STATE.lock().unwrap();\n    let state = get_timer_state(&mut rt_timers, rt);\n    let now = Instant::now();\n\n    let mut had_items = false;\n    let mut lowest = now + FAR_FUTURE;\n    state.timers.retain_mut(|timeout| {\n        had_items = true;\n        if timeout.deadline < now {\n            let ctx = timeout.raw_ctx;\n            if let Some(cb) = timeout.callback.take() {\n                if !timeout.repeating {\n                    call_vec.push(Some(ExecutingTimer(timeout.deadline, ctx, cb)));\n                    return false;\n                }\n                timeout.deadline = now + Duration::from_millis(timeout.interval);\n                if timeout.deadline < lowest {\n                    lowest = timeout.deadline;\n                }\n                call_vec.push(Some(ExecutingTimer(timeout.deadline, ctx, cb.clone())));\n                timeout.callback.replace(cb);\n            } else {\n                return false;\n            }\n        } else if timeout.deadline < lowest {\n            lowest = timeout.deadline;\n        }\n        true\n    });\n\n    let has_items = !state.timers.is_empty();\n\n    if had_items {\n        if lowest - now < MIN_SLEEP {\n            lowest = now + MIN_SLEEP;\n        }\n        if let Some(sleep) = sleep {\n            sleep.as_mut().reset(lowest);\n        }\n        if let Some(deadline) = deadline {\n            *deadline = lowest;\n        }\n        state.deadline = lowest;\n    }\n\n    drop(rt_timers);\n\n    call_vec.sort_unstable_by_key(|v| v.as_ref().map(|v| v.0));\n\n    let mut is_first_time = true;\n    for item in call_vec.iter_mut() {\n        if let Some(ExecutingTimer(_, ctx, timeout)) = item.take() {\n            let ctx2 = unsafe { Ctx::from_raw(ctx) };\n\n            if is_first_time {\n                while ctx2.execute_pending_job() {}\n                is_first_time = false;\n            }\n\n            if let Ok(timeout) = timeout.restore(&ctx2) {\n                // SAFETY: Since it checks in advance whether it is an Function type, we can always get a pointer to the Function.\n                let uid: usize = unsafe { qjs::JS_VALUE_GET_PTR(timeout.as_raw()) } as usize;\n\n                invoke_async_hook(&ctx2, HookType::Before, ProviderType::None, uid)?;\n\n                timeout.call::<_, ()>(())?;\n\n                invoke_async_hook(&ctx2, HookType::After, ProviderType::None, uid)?;\n            }\n\n            while ctx2.execute_pending_job() {}\n        }\n    }\n    call_vec.clear();\n\n    if !has_items {\n        let mut rt_timers = RT_TIMER_STATE.lock().unwrap();\n        let state = get_timer_state(&mut rt_timers, rt);\n        let is_empty = state.timers.is_empty();\n        state.running = !is_empty;\n\n        return Ok(!is_empty);\n    }\n    Ok(true)\n}\n\n#[cfg(test)]\nmod tests {\n    use llrt_test::{call_test, test_async_with, ModuleEvaluator};\n\n    use super::*;\n\n    #[tokio::test]\n    async fn test_timers() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                init(&ctx).unwrap();\n\n                // Assume we have a TimersModule that provides setTimeout, setImmediate, and setInterval\n                ModuleEvaluator::eval_rust::<TimersModule>(ctx.clone(), \"timers\")\n                    .await\n                    .unwrap();\n\n                // Test setTimeout\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test_setTimeout\",\n                    r#\"\n                        import { setTimeout } from 'timers';\n                        export async function test() {\n                            return new Promise((resolve) => {\n                                setTimeout(() => resolve('timeout'), 100);\n                            });\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<String, _>(&ctx, &module, ()).await;\n                assert_eq!(result, \"timeout\");\n\n                // Test setImmediate\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test_setImmediate\",\n                    r#\"\n                        import { setImmediate } from 'timers';\n                        export async function test() {\n                            return new Promise((resolve) => {\n                                setImmediate(() => resolve('immediate'));\n                            });\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<String, _>(&ctx, &module, ()).await;\n                assert_eq!(result, \"immediate\");\n\n                // Test setInterval\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test_setInterval\",\n                    r#\"\n                        import { setInterval, clearInterval } from 'timers';\n                        export async function test() {\n                            return new Promise((resolve) => {\n                                let count = 0;\n                                const intervalId = setInterval(() => {\n                                    count++;\n                                    if (count === 3) {\n                                        clearInterval(intervalId);\n                                        resolve(count);\n                                    }\n                                }, 10);\n                            });\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<i32, _>(&ctx, &module, ()).await;\n                assert_eq!(result, 3);\n\n                // Test nested timers\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test_nestedTimers\",\n                    r#\"\n                        import { setTimeout, setImmediate } from 'timers';\n                        export async function test() {\n                            return new Promise((resolve) => {\n                                setTimeout(() => {\n                                    setImmediate(() => {\n                                        setTimeout(() => {\n                                            resolve('nested');\n                                        }, 10);\n                                    });\n                                }, 10);\n                            });\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<String, _>(&ctx, &module, ()).await;\n                assert_eq!(result, \"nested\");\n\n                // Test canceling timeout\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test_cancelTimeout\",\n                    r#\"\n                        import { setTimeout, clearTimeout } from 'timers';\n                        export async function test() {\n                            return new Promise((resolve) => {\n                                const timeoutId = setTimeout(() => {\n                                    resolve('should not happen');\n                                }, 10);\n                                clearTimeout(timeoutId);\n                                setTimeout(() => resolve('canceled'), 20);\n                            });\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<String, _>(&ctx, &module, ()).await;\n                assert_eq!(result, \"canceled\");\n\n                // Test multiple intervals\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test_multipleIntervals\",\n                    r#\"\n                        import { setInterval, clearInterval } from 'timers';\n                        export async function test() {\n                            return new Promise((resolve) => {\n                                let count1 = 0, count2 = 0;\n                                const id1 = setInterval(() => {\n                                    count1++;\n                                    if (count1 === 2) clearInterval(id1);\n                                }, 10);\n                                const id2 = setInterval(() => {\n                                    count2++;\n                                    if (count2 === 3) {\n                                        clearInterval(id2);\n                                        resolve([count1, count2]);\n                                    }\n                                }, 20);\n                            });\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let result = call_test::<Vec<i32>, _>(&ctx, &module, ()).await;\n                assert_eq!(result, vec![2, 3]);\n            })\n        })\n        .await;\n    }\n}\n"
  },
  {
    "path": "modules/llrt_tls/Cargo.toml",
    "content": "[package]\nname = \"llrt_tls\"\ndescription = \"LLRT Module tls\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\nreadme = \"README.md\"\n\n[lib]\nname = \"llrt_tls\"\npath = \"src/lib.rs\"\n\n[features]\ndefault = [\"webpki-roots\", \"tls-ring\"]\n\nwebpki-roots = [\"dep:webpki-roots\"]\nnative-roots = [\"dep:rustls-native-certs\"]\n\n# TLS crypto backend features (rustls-based)\ntls-ring = [\"dep:rustls\", \"rustls/ring\"]\ntls-aws-lc = [\"dep:rustls\", \"rustls/aws_lc_rs\"]\ntls-graviola = [\"dep:rustls\", \"dep:rustls-graviola\"]\n\n# OpenSSL TLS backend\ntls-openssl = [\"dep:openssl\"]\n\n[dependencies]\nonce_cell = { version = \"1\", features = [\"std\"], default-features = false }\nrustls = { version = \"0.23\", features = [\n  \"std\",\n  \"tls12\",\n], default-features = false, optional = true }\nrustls-graviola = { version = \"0.3\", git = \"https://github.com/ctz/graviola.git\", default-features = false, optional = true }\nopenssl = { version = \"0.10\", optional = true }\nwebpki-roots = { version = \"1\", default-features = false, optional = true }\nrustls-native-certs = { version = \"0.8\", default-features = false, optional = true }\ntracing = { version = \"0.1\", default-features = false }\n\n[dev-dependencies]\n"
  },
  {
    "path": "modules/llrt_tls/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\n// Ensure only one TLS backend is selected\n#[cfg(all(feature = \"tls-ring\", feature = \"tls-aws-lc\"))]\ncompile_error!(\"Features `tls-ring` and `tls-aws-lc` are mutually exclusive\");\n\n#[cfg(all(feature = \"tls-ring\", feature = \"tls-graviola\"))]\ncompile_error!(\"Features `tls-ring` and `tls-graviola` are mutually exclusive\");\n\n#[cfg(all(feature = \"tls-ring\", feature = \"tls-openssl\"))]\ncompile_error!(\"Features `tls-ring` and `tls-openssl` are mutually exclusive\");\n\n#[cfg(all(feature = \"tls-aws-lc\", feature = \"tls-graviola\"))]\ncompile_error!(\"Features `tls-aws-lc` and `tls-graviola` are mutually exclusive\");\n\n#[cfg(all(feature = \"tls-aws-lc\", feature = \"tls-openssl\"))]\ncompile_error!(\"Features `tls-aws-lc` and `tls-openssl` are mutually exclusive\");\n\n#[cfg(all(feature = \"tls-graviola\", feature = \"tls-openssl\"))]\ncompile_error!(\"Features `tls-graviola` and `tls-openssl` are mutually exclusive\");\n\n#[cfg(any(feature = \"tls-ring\", feature = \"tls-aws-lc\", feature = \"tls-graviola\"))]\nmod rustls_config;\n\n#[cfg(any(feature = \"tls-ring\", feature = \"tls-aws-lc\", feature = \"tls-graviola\"))]\npub use rustls_config::*;\n\n#[cfg(any(feature = \"tls-ring\", feature = \"tls-aws-lc\", feature = \"tls-graviola\"))]\nmod no_verification;\n\n#[cfg(feature = \"tls-openssl\")]\nmod openssl_config;\n\n#[cfg(feature = \"tls-openssl\")]\npub use openssl_config::*;\n\n// Once we are ready to add the node TLS module, it should be here.\n// Right now this module is supporting the https/fetch modules.\n"
  },
  {
    "path": "modules/llrt_tls/src/no_verification.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nuse std::sync::Arc;\n\nuse rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};\nuse rustls::crypto::{verify_tls12_signature, verify_tls13_signature, CryptoProvider};\nuse rustls::pki_types::{CertificateDer, ServerName, UnixTime};\nuse rustls::{DigitallySignedStruct, Error, SignatureScheme};\n\n#[derive(Debug)]\npub struct NoCertificateVerification(Arc<CryptoProvider>);\n\nimpl NoCertificateVerification {\n    pub fn new(provider: Arc<CryptoProvider>) -> Self {\n        Self(provider)\n    }\n}\n\nimpl ServerCertVerifier for NoCertificateVerification {\n    fn verify_server_cert(\n        &self,\n        _end_entity: &CertificateDer<'_>,\n        _intermediates: &[CertificateDer<'_>],\n        _server_name: &ServerName<'_>,\n        _ocsp: &[u8],\n        _now: UnixTime,\n    ) -> Result<ServerCertVerified, Error> {\n        Ok(ServerCertVerified::assertion())\n    }\n\n    fn verify_tls12_signature(\n        &self,\n        message: &[u8],\n        cert: &CertificateDer<'_>,\n        dss: &DigitallySignedStruct,\n    ) -> Result<HandshakeSignatureValid, Error> {\n        verify_tls12_signature(\n            message,\n            cert,\n            dss,\n            &self.0.signature_verification_algorithms,\n        )\n    }\n\n    fn verify_tls13_signature(\n        &self,\n        message: &[u8],\n        cert: &CertificateDer<'_>,\n        dss: &DigitallySignedStruct,\n    ) -> Result<HandshakeSignatureValid, Error> {\n        verify_tls13_signature(\n            message,\n            cert,\n            dss,\n            &self.0.signature_verification_algorithms,\n        )\n    }\n\n    fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {\n        self.0.signature_verification_algorithms.supported_schemes()\n    }\n}\n"
  },
  {
    "path": "modules/llrt_tls/src/openssl_config.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::sync::OnceLock;\n\nuse once_cell::sync::Lazy;\nuse openssl::ssl::{SslConnectorBuilder, SslMethod, SslVerifyMode};\nuse openssl::x509::X509;\n\nstatic EXTRA_CA_CERTS: OnceLock<Vec<Vec<u8>>> = OnceLock::new();\n\npub fn set_extra_ca_certs(certs: Vec<Vec<u8>>) {\n    _ = EXTRA_CA_CERTS.set(certs);\n}\n\npub fn get_extra_ca_certs() -> Option<Vec<Vec<u8>>> {\n    let certs = EXTRA_CA_CERTS.get_or_init(Vec::new).clone();\n    if certs.is_empty() {\n        None\n    } else {\n        Some(certs)\n    }\n}\n\nstatic TLS_VERSION: OnceLock<Option<openssl::ssl::SslVersion>> = OnceLock::new();\n\npub fn set_tls_version(version: Option<openssl::ssl::SslVersion>) {\n    _ = TLS_VERSION.set(version);\n}\n\npub fn get_tls_version() -> Option<openssl::ssl::SslVersion> {\n    *TLS_VERSION.get_or_init(|| None)\n}\n\npub static TLS_CONFIG: Lazy<Result<SslConnectorBuilder, Box<dyn std::error::Error + Send + Sync>>> =\n    Lazy::new(|| {\n        build_client_config(BuildClientConfigOptions {\n            reject_unauthorized: true,\n            ca: None,\n        })\n    });\n\npub struct BuildClientConfigOptions {\n    pub reject_unauthorized: bool,\n    pub ca: Option<Vec<Vec<u8>>>,\n}\n\npub fn build_client_config(\n    options: BuildClientConfigOptions,\n) -> Result<SslConnectorBuilder, Box<dyn std::error::Error + Send + Sync>> {\n    let mut builder = openssl::ssl::SslConnector::builder(SslMethod::tls_client())?;\n\n    // TLS version\n    if let Some(version) = get_tls_version() {\n        builder.set_min_proto_version(Some(version))?;\n    }\n\n    // Certificate verification\n    if !options.reject_unauthorized {\n        builder.set_verify(SslVerifyMode::NONE);\n    } else if let Some(ca) = options.ca {\n        for cert_pem in ca {\n            let cert = X509::from_pem(&cert_pem)?;\n            builder.cert_store_mut().add_cert(cert)?;\n        }\n    } else {\n        // Use system default CA certificates\n        builder.set_default_verify_paths()?;\n\n        // Add extra CA certs if configured\n        if let Some(extra_certs) = get_extra_ca_certs() {\n            for cert_der in extra_certs {\n                if let Ok(cert) = X509::from_der(&cert_der) {\n                    let _ = builder.cert_store_mut().add_cert(cert);\n                }\n            }\n        }\n    }\n\n    Ok(builder)\n}\n"
  },
  {
    "path": "modules/llrt_tls/src/rustls_config.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nuse std::sync::{Arc, OnceLock};\n\nuse once_cell::sync::Lazy;\nuse rustls::{\n    pki_types::{pem::PemObject, CertificateDer},\n    ClientConfig, RootCertStore, SupportedProtocolVersion,\n};\n#[cfg(feature = \"webpki-roots\")]\nuse webpki_roots::TLS_SERVER_ROOTS;\n\nuse crate::no_verification::NoCertificateVerification;\n\n// Select the crypto provider based on feature flags\n#[cfg(feature = \"tls-ring\")]\nfn get_crypto_provider() -> Arc<rustls::crypto::CryptoProvider> {\n    Arc::new(rustls::crypto::ring::default_provider())\n}\n\n#[cfg(feature = \"tls-aws-lc\")]\nfn get_crypto_provider() -> Arc<rustls::crypto::CryptoProvider> {\n    Arc::new(rustls::crypto::aws_lc_rs::default_provider())\n}\n\n#[cfg(feature = \"tls-graviola\")]\nfn get_crypto_provider() -> Arc<rustls::crypto::CryptoProvider> {\n    Arc::new(rustls_graviola::default_provider())\n}\n\nstatic EXTRA_CA_CERTS: OnceLock<Vec<CertificateDer<'static>>> = OnceLock::new();\n\npub fn set_extra_ca_certs(certs: Vec<CertificateDer<'static>>) {\n    _ = EXTRA_CA_CERTS.set(certs);\n}\n\npub fn get_extra_ca_certs() -> Option<Vec<CertificateDer<'static>>> {\n    let certs = EXTRA_CA_CERTS.get_or_init(Vec::new).clone();\n    if certs.is_empty() {\n        None\n    } else {\n        Some(certs)\n    }\n}\n\nstatic TLS_VERSIONS: OnceLock<Vec<&'static SupportedProtocolVersion>> = OnceLock::new();\n\npub fn set_tls_versions(versions: Vec<&'static SupportedProtocolVersion>) {\n    _ = TLS_VERSIONS.set(versions);\n}\n\npub fn get_tls_versions() -> Option<Vec<&'static SupportedProtocolVersion>> {\n    let versions = TLS_VERSIONS.get_or_init(Vec::new).clone();\n    if versions.is_empty() {\n        None\n    } else {\n        Some(versions)\n    }\n}\n\npub static TLS_CONFIG: Lazy<Result<ClientConfig, Box<dyn std::error::Error + Send + Sync>>> =\n    Lazy::new(|| {\n        build_client_config(BuildClientConfigOptions {\n            reject_unauthorized: true,\n            ca: None,\n        })\n    });\n\npub struct BuildClientConfigOptions {\n    pub reject_unauthorized: bool,\n    pub ca: Option<Vec<Vec<u8>>>,\n}\n\npub fn build_client_config(\n    options: BuildClientConfigOptions,\n) -> Result<ClientConfig, Box<dyn std::error::Error + Send + Sync>> {\n    let provider = get_crypto_provider();\n    let builder = ClientConfig::builder_with_provider(provider.clone());\n\n    // TLS versions\n    let builder = match get_tls_versions() {\n        Some(versions) => builder.with_protocol_versions(&versions),\n        None => builder.with_safe_default_protocol_versions(),\n    }?;\n\n    // Certificate verification\n    let builder = if !options.reject_unauthorized {\n        builder\n            .dangerous()\n            .with_custom_certificate_verifier(Arc::new(NoCertificateVerification::new(provider)))\n    } else if let Some(ca) = options.ca {\n        let mut root_certificates = RootCertStore::empty();\n\n        for cert in ca {\n            root_certificates.add(CertificateDer::from_pem_slice(&cert)?)?;\n        }\n        builder.with_root_certificates(root_certificates)\n    } else {\n        let mut root_certificates = RootCertStore::empty();\n\n        #[cfg(feature = \"webpki-roots\")]\n        {\n            for cert in TLS_SERVER_ROOTS.iter().cloned() {\n                root_certificates.roots.push(cert)\n            }\n        }\n        #[cfg(feature = \"native-roots\")]\n        {\n            let load_results = rustls_native_certs::load_native_certs();\n            for cert in load_results.certs {\n                // Continue on parsing errors, as native stores often include ancient or syntactically\n                // invalid certificates, like root certificates without any X509 extensions.\n                // Inspiration: https://github.com/rustls/rustls/blob/633bf4ba9d9521a95f68766d04c22e2b01e68318/rustls/src/anchors.rs#L105-L112\n                if let Err(err) = root_certificates.add(cert) {\n                    tracing::debug!(\"rustls failed to parse DER certificate: {err:?}\");\n                }\n            }\n        }\n\n        if let Some(extra_ca_certs) = get_extra_ca_certs() {\n            root_certificates.add_parsable_certificates(extra_ca_certs);\n        }\n\n        builder.with_root_certificates(root_certificates)\n    };\n\n    Ok(builder.with_no_client_auth())\n}\n"
  },
  {
    "path": "modules/llrt_tty/Cargo.toml",
    "content": "[package]\nname = \"llrt_tty\"\ndescription = \"LLRT Module tty\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\nreadme = \"README.md\"\n\n[lib]\nname = \"llrt_tty\"\npath = \"src/lib.rs\"\n\n[dependencies]\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", default-features = false }\nlibc = { version = \"0.2\", default-features = false }\n\n[dev-dependencies]\nllrt_test = { path = \"../../libs/llrt_test\" }\ntokio = { version = \"1\", features = [\"test-util\"], default-features = false }\n"
  },
  {
    "path": "modules/llrt_tty/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_utils::module::{export_default, ModuleInfo};\nuse rquickjs::{\n    module::{Declarations, Exports, ModuleDef},\n    prelude::Func,\n    Ctx, Result,\n};\n\nfn isatty(fd: i32) -> bool {\n    unsafe { libc::isatty(fd) != 0 }\n}\n\npub struct TtyModule;\n\nimpl ModuleDef for TtyModule {\n    fn declare(declare: &Declarations<'_>) -> Result<()> {\n        declare.declare(\"isatty\")?;\n        declare.declare(\"default\")?;\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        export_default(ctx, exports, |default| {\n            default.set(\"isatty\", Func::from(isatty))?;\n            Ok(())\n        })\n    }\n}\n\nimpl From<TtyModule> for ModuleInfo<TtyModule> {\n    fn from(val: TtyModule) -> Self {\n        ModuleInfo {\n            name: \"tty\",\n            module: val,\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::TtyModule;\n    use llrt_test::{call_test, test_async_with, ModuleEvaluator};\n    use std::io::{stderr, stdin, stdout, IsTerminal};\n\n    #[tokio::test]\n    async fn test_isatty() {\n        test_async_with(|ctx| {\n            Box::pin(async move {\n                ModuleEvaluator::eval_rust::<TtyModule>(ctx.clone(), \"tty\")\n                    .await\n                    .unwrap();\n\n                let module = ModuleEvaluator::eval_js(\n                    ctx.clone(),\n                    \"test\",\n                    r#\"\n                        import { isatty } from 'tty';\n\n                        export async function test() {\n                            return new Array(3).fill(0).map((_, i) => +isatty(i)).join('')\n                        }\n                    \"#,\n                )\n                .await\n                .unwrap();\n                let expect = [\n                    stdin().is_terminal(),\n                    stdout().is_terminal(),\n                    stderr().is_terminal(),\n                ]\n                .map(|i| (i as u8).to_string())\n                .join(\"\");\n                let result = call_test::<String, _>(&ctx, &module, ()).await;\n                assert_eq!(result, expect);\n            })\n        })\n        .await;\n    }\n}\n"
  },
  {
    "path": "modules/llrt_url/Cargo.toml",
    "content": "[package]\nname = \"llrt_url\"\ndescription = \"LLRT Module url\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\nreadme = \"README.md\"\n\n[lib]\nname = \"llrt_url\"\npath = \"src/lib.rs\"\n\n[dependencies]\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", default-features = false }\nurl = { version = \"2\", features = [\"std\"], default-features = false }\n\n[dev-dependencies]\nllrt_test = { path = \"../../libs/llrt_test\" }\ntokio = { version = \"1\", features = [\"test-util\"], default-features = false }\n"
  },
  {
    "path": "modules/llrt_url/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#![allow(clippy::inherent_to_string)]\npub mod url_class;\npub mod url_search_params;\n\nuse std::{path::PathBuf, str::FromStr};\n\nuse llrt_utils::{\n    module::{export_default, ModuleInfo},\n    primordials::{BasePrimordials, Primordial},\n    result::ResultExt,\n};\nuse rquickjs::{\n    function::{Constructor, Func},\n    module::{Declarations, Exports, ModuleDef},\n    prelude::Opt,\n    Class, Coerced, Ctx, Exception, Result, Value,\n};\nuse url::{quirks, Url};\n\nuse self::url_class::{url_to_http_options, URL};\nuse self::url_search_params::URLSearchParams;\n\npub fn domain_to_unicode(domain: &str) -> String {\n    quirks::domain_to_unicode(domain)\n}\n\npub fn domain_to_ascii(domain: &str) -> String {\n    quirks::domain_to_ascii(domain)\n}\n\n//options are ignored, no windows support yet\npub fn path_to_file_url<'js>(ctx: Ctx<'js>, path: String, _: Opt<Value>) -> Result<URL<'js>> {\n    let url = Url::from_file_path(&path)\n        .map_err(|_| Exception::throw_type(&ctx, &[\"Path is not absolute: \", &path].concat()))?;\n\n    URL::from_url(ctx, url)\n}\n\n//options are ignored, no windows support yet\npub fn file_url_to_path<'js>(ctx: Ctx<'js>, url: Value<'js>) -> Result<String> {\n    let url_string = if let Ok(url) = Class::<URL>::from_value(&url) {\n        url.borrow().to_string()\n    } else {\n        url.get::<Coerced<String>>()?.to_string()\n    };\n\n    let path = url_string.trim_start_matches(\"file://\");\n\n    Ok(PathBuf::from_str(path)\n        .or_throw(&ctx)?\n        .to_string_lossy()\n        .to_string())\n}\n\npub fn url_format<'js>(url: Class<'js, URL<'js>>, options: Opt<Value<'js>>) -> Result<String> {\n    let url = url.borrow();\n    let mut string = url.protocol();\n    string.push_str(\"//\");\n\n    let mut include_fragment = true;\n    let mut unicode_encode = false;\n    let mut include_auth = true;\n    let mut include_search = true;\n\n    // Parse options if provided\n    if let Some(options) = options.into_inner() {\n        if let Some(options) = options.as_object() {\n            if let Ok(value) = options.get(\"unicode\") {\n                unicode_encode = value;\n            }\n            if let Ok(value) = options.get(\"auth\") {\n                include_auth = value;\n            }\n            if let Ok(value) = options.get(\"fragment\") {\n                include_fragment = value;\n            }\n            if let Ok(value) = options.get(\"search\") {\n                include_search = value\n            }\n        }\n    }\n\n    if include_auth {\n        let username = url.username();\n        let password = url.password();\n        if !username.is_empty() {\n            string.push_str(&username);\n            if !password.is_empty() {\n                string.push(':');\n                string.push_str(&password);\n            }\n            string.push('@');\n        }\n    }\n\n    if unicode_encode {\n        string.push_str(&domain_to_unicode(&url.host()));\n    } else {\n        string.push_str(&url.host());\n    }\n\n    string.push_str(&url.pathname());\n\n    if include_search {\n        string.push_str(&url.search());\n    }\n\n    if include_fragment {\n        string.push_str(&url.hash());\n    }\n\n    Ok(string)\n}\n\n// https://url.spec.whatwg.org/#cannot-be-a-base-url-path-state\npub fn convert_trailing_space(url: &mut Url) {\n    if matches!(\n        url.scheme(),\n        \"file\" | \"ftp\" | \"http\" | \"https\" | \"ws\" | \"wss\"\n    ) {\n        return;\n    }\n\n    let path = url.path();\n    let has_remaining = url.fragment().is_some() || url.query().is_some();\n\n    #[allow(clippy::manual_strip)]\n    if path.ends_with(' ') && has_remaining {\n        let new_path = [&path[..path.len() - 1], \"%20\"].concat();\n        url.set_path(&new_path);\n    }\n}\n\npub fn init(ctx: &Ctx<'_>) -> Result<()> {\n    let globals = ctx.globals();\n\n    Class::<URLSearchParams>::define(&globals)?;\n    Class::<URL>::define(&globals)?;\n\n    Ok(())\n}\n\npub struct UrlModule;\n\nimpl ModuleDef for UrlModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(stringify!(URL))?;\n        declare.declare(stringify!(URLSearchParams))?;\n        declare.declare(\"urlToHttpOptions\")?;\n        declare.declare(\"domainToUnicode\")?;\n        declare.declare(\"domainToASCII\")?;\n        declare.declare(\"fileURLToPath\")?;\n        declare.declare(\"pathToFileURL\")?;\n        declare.declare(\"format\")?;\n        declare.declare(\"default\")?;\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        let globals = ctx.globals();\n        BasePrimordials::init(ctx)?;\n        let url: Constructor = globals.get(stringify!(URL))?;\n        let url_search_params: Constructor = globals.get(stringify!(URLSearchParams))?;\n\n        export_default(ctx, exports, |default| {\n            default.set(stringify!(URL), url)?;\n            default.set(stringify!(URLSearchParams), url_search_params)?;\n            default.set(\"urlToHttpOptions\", Func::from(url_to_http_options))?;\n            default.set(\n                \"domainToUnicode\",\n                Func::from(|domain: String| domain_to_unicode(&domain)),\n            )?;\n            default.set(\n                \"domainToASCII\",\n                Func::from(|domain: String| domain_to_ascii(&domain)),\n            )?;\n            default.set(\"fileURLToPath\", Func::from(file_url_to_path))?;\n            default.set(\"pathToFileURL\", Func::from(path_to_file_url))?;\n            default.set(\"format\", Func::from(url_format))?;\n            Ok(())\n        })?;\n\n        Ok(())\n    }\n}\n\nimpl From<UrlModule> for ModuleInfo<UrlModule> {\n    fn from(val: UrlModule) -> Self {\n        ModuleInfo {\n            name: \"url\",\n            module: val,\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_url/src/url_class.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n#![allow(clippy::uninlined_format_args)]\nuse std::{cell::RefCell, rc::Rc};\n\nuse rquickjs::{\n    atom::PredefinedAtom, class::Trace, function::Opt, Class, Coerced, Ctx, Exception, FromJs,\n    IntoJs, Null, Object, Result, Value,\n};\nuse url::{quirks, Url};\n\nuse super::{convert_trailing_space, url_search_params::URLSearchParams};\n\n/// Naively checks for hostname delimiter, a colon \":\", that's *probably* not\n/// part of an IPv6 address\n///\n/// # Arguments\n///\n/// * `hostname` - The hostname.\n///\n/// # Returns\n///\n/// Returns whether the hostname contains a colon that's not followed by a\n/// closing square bracket.\nfn has_colon_delimiter(hostname: &str) -> bool {\n    if let Some(last_colon_index) = hostname.rfind(':') {\n        // Check if there's any closing bracket after the last colon\n        !hostname[last_colon_index..].contains(']')\n    } else {\n        false\n    }\n}\n\n/// Represents a JavaScript\n/// [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) as defined\n/// by the [WHATWG URL standard](https://url.spec.whatwg.org/) in the JavaScript\n/// context.\n///\n/// # Examples\n///\n/// ```rust,ignore\n/// // This is JavaScript\n/// const url = new URL(\"https://url.spec.whatwg.org/\");\n/// console.log(url.href);\n/// ```\n#[derive(Clone, Trace, rquickjs::JsLifetime)]\n#[rquickjs::class]\npub struct URL<'js> {\n    // URL and URLSearchParams work together to manipulate URLs, so using a\n    // reference counter (Rc) allows them to have shared ownership of the\n    // undering Url, and a RefCell allows interior mutability.\n    #[qjs(skip_trace)]\n    url: Rc<RefCell<Url>>,\n    search_params: Class<'js, URLSearchParams>,\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl<'js> URL<'js> {\n    #[qjs(constructor)]\n    pub fn new(ctx: Ctx<'js>, input: Value<'js>, base: Opt<Value<'js>>) -> Result<Self> {\n        let input: Result<Coerced<String>> = Coerced::from_js(&ctx, input);\n        if let Some(base) = base.into_inner() {\n            if let Some(base) = base.as_string() {\n                if let Ok(base) = base.to_string() {\n                    let mut url: Url = base.parse().map_err(|err| {\n                        Exception::throw_type(&ctx, format!(\"Invalid base URL: {}\", err).as_str())\n                    })?;\n\n                    if let Ok(input) = input {\n                        url = url.join(input.as_str()).map_err(|err| {\n                            Exception::throw_type(&ctx, format!(\"Invalid URL: {}\", err).as_str())\n                        })?;\n                    }\n\n                    return Self::from_url(ctx, url);\n                }\n            }\n        }\n\n        if let Ok(input) = input {\n            Self::from_str(ctx, input.as_str())\n        } else {\n            Err(Exception::throw_message(&ctx, \"Invalid URL\"))\n        }\n    }\n\n    //\n    // Properties\n    //\n\n    #[qjs(get)]\n    pub fn hash(&self) -> String {\n        quirks::hash(&self.url.borrow()).to_string()\n    }\n\n    #[qjs(set, rename = \"hash\")]\n    pub fn set_hash(&mut self, hash: String) -> String {\n        convert_trailing_space(&mut self.url.borrow_mut());\n\n        quirks::set_hash(&mut self.url.borrow_mut(), hash.as_str());\n        hash\n    }\n\n    #[qjs(get)]\n    pub fn host(&self) -> String {\n        quirks::host(&self.url.borrow()).to_string()\n    }\n\n    #[qjs(set, rename = \"host\")]\n    pub fn set_host(&mut self, host: Coerced<String>) -> String {\n        convert_trailing_space(&mut self.url.borrow_mut());\n\n        let _ = quirks::set_host(&mut self.url.borrow_mut(), host.as_str());\n        host.0\n    }\n\n    #[qjs(get)]\n    pub fn hostname(&self) -> String {\n        quirks::hostname(&self.url.borrow()).to_string()\n    }\n\n    #[qjs(set, rename = \"hostname\")]\n    pub fn set_hostname(&mut self, hostname: Coerced<String>) -> String {\n        convert_trailing_space(&mut self.url.borrow_mut());\n\n        // TODO: This should be fixed in Url\n        if !has_colon_delimiter(hostname.as_str()) {\n            let _ = quirks::set_hostname(&mut self.url.borrow_mut(), hostname.as_str());\n        }\n        hostname.0\n    }\n\n    #[qjs(get)]\n    pub fn href(&self) -> String {\n        quirks::href(&self.url.borrow()).to_string()\n    }\n\n    #[qjs(set, rename = \"href\")]\n    pub fn set_href(&mut self, href: String) -> String {\n        convert_trailing_space(&mut self.url.borrow_mut());\n\n        let _ = quirks::set_href(&mut self.url.borrow_mut(), href.as_str());\n        href\n    }\n\n    #[qjs(get)]\n    pub fn origin(&self) -> String {\n        quirks::origin(&self.url.borrow()).to_string()\n    }\n\n    #[qjs(get)]\n    pub fn password(&self) -> String {\n        quirks::password(&self.url.borrow()).to_string()\n    }\n\n    #[qjs(set, rename = \"password\")]\n    pub fn set_password(&mut self, password: Coerced<String>) -> String {\n        convert_trailing_space(&mut self.url.borrow_mut());\n\n        let _ = quirks::set_password(&mut self.url.borrow_mut(), password.as_str());\n        password.0\n    }\n\n    #[qjs(get)]\n    pub fn pathname(&self) -> String {\n        quirks::pathname(&self.url.borrow()).to_string()\n    }\n\n    #[qjs(set, rename = \"pathname\")]\n    pub fn set_pathname(&mut self, pathname: Coerced<String>) -> String {\n        convert_trailing_space(&mut self.url.borrow_mut());\n\n        quirks::set_pathname(&mut self.url.borrow_mut(), pathname.as_str());\n        pathname.0\n    }\n\n    #[qjs(get)]\n    pub fn port(&self) -> String {\n        quirks::port(&self.url.borrow()).to_string()\n    }\n\n    #[qjs(set, rename = \"port\")]\n    pub fn set_port(&mut self, ctx: Ctx<'js>, port: Value<'js>) -> Value<'js> {\n        convert_trailing_space(&mut self.url.borrow_mut());\n\n        // TODO: negative ports should be handled in Url\n        if port.is_null()\n            || port.is_undefined()\n            || (port.is_int() && unsafe { port.as_int().unwrap_unchecked() } < 0)\n        {\n            return port;\n        }\n\n        let port_string: Result<Coerced<String>> = Coerced::from_js(&ctx, port.clone());\n        if let Ok(port_string) = port_string {\n            let _ = quirks::set_port(&mut self.url.borrow_mut(), port_string.as_str());\n        }\n        port\n    }\n\n    #[qjs(get)]\n    pub fn protocol(&self) -> String {\n        quirks::protocol(&self.url.borrow()).to_string()\n    }\n\n    #[qjs(set, rename = \"protocol\")]\n    pub fn set_protocol(&mut self, protocol: Coerced<String>) -> String {\n        convert_trailing_space(&mut self.url.borrow_mut());\n\n        let _ = quirks::set_protocol(&mut self.url.borrow_mut(), protocol.as_str());\n        protocol.0\n    }\n\n    #[qjs(get)]\n    pub fn search(&self) -> String {\n        quirks::search(&self.url.borrow()).to_string()\n    }\n\n    #[qjs(set, rename = \"search\")]\n    pub fn set_search(&mut self, search: Coerced<String>) -> String {\n        convert_trailing_space(&mut self.url.borrow_mut());\n\n        quirks::set_search(&mut self.url.borrow_mut(), search.as_str());\n        search.0\n    }\n\n    #[qjs(get)]\n    pub fn search_params(&self) -> &Value<'js> {\n        self.search_params.as_value()\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    pub fn to_string_tag(&self) -> &'static str {\n        stringify!(URL)\n    }\n\n    #[qjs(get)]\n    pub fn username(&self) -> String {\n        quirks::username(&self.url.borrow()).to_string()\n    }\n\n    #[qjs(set, rename = \"username\")]\n    pub fn set_username(&mut self, username: Coerced<String>) -> String {\n        convert_trailing_space(&mut self.url.borrow_mut());\n\n        let _ = quirks::set_username(&mut self.url.borrow_mut(), username.as_str());\n        username.0\n    }\n\n    //\n    // Static methods\n    //\n\n    #[qjs(static)]\n    pub fn can_parse(ctx: Ctx<'js>, input: Value<'js>, base: Opt<Value<'js>>) -> bool {\n        Self::new(ctx, input, base).is_ok()\n    }\n\n    #[qjs(static)]\n    pub fn parse(ctx: Ctx<'js>, input: Value<'js>, base: Opt<Value<'js>>) -> Result<Value<'js>> {\n        Self::new(ctx.clone(), input, base)\n            .map_or_else(|_| Null.into_js(&ctx), |instance| instance.into_js(&ctx))\n    }\n\n    //\n    // Instance methods\n    //\n\n    #[qjs(rename = PredefinedAtom::ToJSON)]\n    pub fn to_json(&self) -> String {\n        // https://developer.mozilla.org/en-US/docs/Web/API/URL/toJSON\n        self.to_string()\n    }\n\n    pub fn to_string(&self) -> String {\n        self.url.borrow().to_string()\n    }\n}\n\nimpl<'js> URL<'js> {\n    pub fn from_str(ctx: Ctx<'js>, input: &str) -> Result<Self> {\n        let url: Url = input\n            .parse()\n            .map_err(|_| Exception::throw_type(&ctx, \"Invalid URL\"))?;\n        Self::from_url(ctx, url)\n    }\n\n    pub fn from_url(ctx: Ctx<'js>, url: Url) -> Result<Self> {\n        let url = Rc::new(RefCell::new(url));\n        let search_params = URLSearchParams::from_url(&url);\n        let search_params = Class::instance(ctx, search_params)?;\n\n        Ok(Self { url, search_params })\n    }\n}\n\npub fn url_to_http_options<'js>(ctx: Ctx<'js>, url: Class<'js, URL<'js>>) -> Result<Object<'js>> {\n    let obj = Object::new(ctx)?;\n\n    let url = url.borrow();\n\n    let port = url.port();\n    let username = url.username();\n    let search = url.search();\n    let hash = url.url.borrow().fragment().unwrap_or(\"\").to_string();\n\n    obj.set(\"protocol\", url.protocol())?;\n    obj.set(\"hostname\", url.hostname())?;\n\n    if !hash.is_empty() {\n        obj.set(\"hash\", hash)?;\n    }\n    if !search.is_empty() {\n        obj.set(\"search\", search)?;\n    }\n\n    obj.set(\"pathname\", url.pathname())?;\n    obj.set(\"path\", [url.pathname(), url.search()].join(\"\"))?;\n    obj.set(\"href\", url.href())?;\n\n    if !username.is_empty() {\n        obj.set(\"auth\", [username, \":\".to_string(), url.password()].join(\"\"))?;\n    }\n\n    if !port.is_empty() {\n        obj.set(\"port\", port)?;\n    }\n\n    Ok(obj)\n}\n"
  },
  {
    "path": "modules/llrt_url/src/url_search_params.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::{cell::RefCell, collections::HashSet, rc::Rc};\n\nuse llrt_utils::{\n    class::IteratorDef,\n    primordials::{BasePrimordials, Primordial},\n};\nuse rquickjs::{\n    atom::PredefinedAtom, class::Trace, function::Opt, Array, Class, Coerced, Ctx, Exception,\n    FromJs, Function, IntoJs, Null, Object, Result, Symbol, Value,\n};\nuse url::Url;\n\nuse super::convert_trailing_space;\n\n/// Represents `URLSearchParams` in the JavaScript context\n///\n/// <https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams>\n///\n/// # Examples\n///\n/// ```rust,ignore\n/// // This is JavaScript\n/// const params = new URLSearchParams();\n/// params.set(\"foo\", \"bar\");\n/// ```\n#[derive(Clone, Trace, rquickjs::JsLifetime)]\n#[rquickjs::class]\npub struct URLSearchParams {\n    // URL and URLSearchParams work together to manipulate URLs, so using a\n    // reference counter (Rc) allows them to have shared ownership of the\n    // undering Url, and a RefCell allows interior mutability.\n    #[qjs(skip_trace)]\n    pub url: Rc<RefCell<Url>>,\n}\n\n// URLSearchParams is designed to operate directly on the underlying Url to\n// avoid maintaining derived state that can get out of sync. When it's used\n// independently, it still needs a valid URL (http://example.com), but this\n// doesn't have any effect on using URLSearchParams with URL as the params are\n// stringified when added to a URL.\n//\n// ```js\n// const params = new URLSearchParams(\"foo=bar\");\n// const url = new URL(\"http://github.com\");\n// url.search = params; // This works as expected\n// ```\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl<'js> URLSearchParams {\n    #[qjs(constructor)]\n    pub fn new(ctx: Ctx<'js>, init: Opt<Value<'js>>) -> Result<Self> {\n        if let Some(init) = init.into_inner() {\n            if init.is_string() {\n                let string: String = Coerced::from_js(&ctx, init)?.0;\n                return Ok(Self::from_str(string));\n            } else if init.is_array() {\n                return Self::from_array(&ctx, unsafe { init.into_array().unwrap_unchecked() });\n            } else if init.is_object() {\n                return Self::from_object(&ctx, unsafe { init.into_object().unwrap_unchecked() });\n            }\n        }\n        let url: Url = unsafe { \"http://example.com\".parse().unwrap_unchecked() };\n\n        Ok(URLSearchParams {\n            url: Rc::new(RefCell::new(url)),\n        })\n    }\n\n    //\n    // Properties\n    //\n\n    #[qjs(get)]\n    pub fn size(&self) -> usize {\n        self.url.borrow().query_pairs().count()\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    pub fn to_string_tag(&self) -> &'static str {\n        stringify!(URLSearchParams)\n    }\n\n    //\n    // Instance methods\n    //\n\n    pub fn append(&mut self, key: Coerced<String>, value: Coerced<String>) {\n        convert_trailing_space(&mut self.url.borrow_mut());\n\n        self.url\n            .borrow_mut()\n            .query_pairs_mut()\n            .append_pair(key.as_str(), value.as_str());\n    }\n\n    pub fn delete(&mut self, ctx: Ctx<'js>, key: Coerced<String>, value: Opt<Value<'js>>) {\n        convert_trailing_space(&mut self.url.borrow_mut());\n\n        let key = key.0;\n\n        let value = get_coerced_string_value(&ctx, value);\n\n        let new_pairs: Vec<_> = self\n            .url\n            .borrow()\n            .query_pairs()\n            .filter(|(k, v)| {\n                if let Some(value) = value.as_ref() {\n                    return !(*k == key && *v == *value);\n                }\n                *k != key\n            })\n            .map(|(k, v)| (k.to_string(), v.to_string()))\n            .collect();\n\n        if !new_pairs.is_empty() {\n            self.url\n                .borrow_mut()\n                .query_pairs_mut()\n                .clear()\n                .extend_pairs(new_pairs);\n        } else {\n            self.url.borrow_mut().set_query(None);\n        }\n    }\n\n    pub fn entries(&self, ctx: Ctx<'js>) -> Result<Value<'js>> {\n        self.js_iterator(ctx)\n    }\n\n    pub fn for_each(&self, callback: Function<'js>) -> Result<()> {\n        self.url\n            .borrow()\n            .query_pairs()\n            .into_owned()\n            .try_for_each(|(k, v)| callback.call((v, k)))?;\n        Ok(())\n    }\n\n    pub fn get(&mut self, ctx: Ctx<'js>, key: String) -> Result<Value<'js>> {\n        match self\n            .url\n            .borrow()\n            .query_pairs()\n            .find(|(k, _)| *k == key)\n            .map(|(_, v)| v)\n        {\n            Some(value) => value.into_js(&ctx),\n            None => Null.into_js(&ctx),\n        }\n    }\n\n    pub fn get_all(&mut self, key: String) -> Vec<String> {\n        self.url\n            .borrow()\n            .query_pairs()\n            .filter_map(|(k, v)| if k == key { Some(v.to_string()) } else { None })\n            .collect()\n    }\n\n    pub fn has(&self, ctx: Ctx<'js>, key: Coerced<String>, value: Opt<Value<'js>>) -> bool {\n        let value = get_coerced_string_value(&ctx, value);\n        let key = key.0;\n        self.url.borrow().query_pairs().any(|(k, v)| {\n            if let Some(value) = value.as_ref() {\n                return *k == key && *v == *value;\n            }\n            *k == key\n        })\n    }\n\n    pub fn keys(&mut self) -> Vec<String> {\n        self.url\n            .borrow()\n            .query_pairs()\n            .map(|(k, _)| k.to_string())\n            .collect()\n    }\n\n    pub fn set(&mut self, key: Coerced<String>, value: Coerced<String>) {\n        convert_trailing_space(&mut self.url.borrow_mut());\n\n        let key = key.0;\n        let value = value.0;\n\n        // Use a HashSet just to filter duplicates\n        let mut uniques = HashSet::new();\n        let mut new_query_pairs: Vec<(String, String)> = Vec::new();\n\n        for (k, v) in self.url.borrow().query_pairs() {\n            // Update the value for an existing key\n            let value = if k == key {\n                value.clone()\n            } else {\n                v.to_string()\n            };\n\n            let query_pair = (k.to_string(), value);\n            if uniques.insert(query_pair.clone()) {\n                new_query_pairs.push(query_pair);\n            }\n        }\n\n        // Append a new key/value pair\n        let query_pair = (key, value);\n        if uniques.insert(query_pair.clone()) {\n            new_query_pairs.push(query_pair);\n        }\n\n        self.url\n            .borrow_mut()\n            .query_pairs_mut()\n            .clear()\n            .extend_pairs(new_query_pairs);\n    }\n\n    pub fn sort(&mut self) {\n        let mut new_pairs: Vec<(String, String)> =\n            self.url.borrow().query_pairs().into_owned().collect();\n        new_pairs.sort_by(|(a, _), (b, _)| a.cmp(b));\n\n        if new_pairs.is_empty() {\n            self.url.borrow_mut().set_query(None);\n        } else {\n            self.url\n                .borrow_mut()\n                .query_pairs_mut()\n                .clear()\n                .extend_pairs(new_pairs);\n        }\n    }\n\n    pub fn to_string(&self) -> String {\n        // The Url create doesn't properly encode query params for all edge\n        // cases, so we need to construct the query string by percent-encoding\n        // each key/value\n        // TODO: This should probably be fixed in the Url crate\n        let url = self.url.borrow();\n        url.query_pairs().fold(\n            String::with_capacity(url.query().map_or(0, |q| q.len())),\n            |mut acc, (key, value)| {\n                if !acc.is_empty() {\n                    acc.push('&');\n                }\n                url::form_urlencoded::byte_serialize(key.as_bytes()).for_each(|b| acc.push_str(b));\n                acc.push('=');\n                url::form_urlencoded::byte_serialize(value.as_bytes())\n                    .for_each(|b| acc.push_str(b));\n                acc\n            },\n        )\n    }\n\n    pub fn values(&mut self) -> Vec<String> {\n        self.url\n            .borrow()\n            .query_pairs()\n            .map(|(_, v)| v.to_string())\n            .collect()\n    }\n\n    #[qjs(rename = PredefinedAtom::SymbolIterator)]\n    pub fn iterator(&self, ctx: Ctx<'js>) -> Result<Class<'js, URLSearchParamsIter>> {\n        Class::instance(\n            ctx,\n            URLSearchParamsIter {\n                index: 0,\n                params: self.clone(),\n            },\n        )\n    }\n}\n\nimpl<'js> URLSearchParams {\n    #[allow(clippy::should_implement_trait)]\n    pub fn from_str(query: String) -> Self {\n        let query = if !query.starts_with('?') {\n            [\"?\", &query].concat()\n        } else {\n            query\n        };\n        let url = unsafe {\n            \"http://example.com\"\n                .parse::<Url>()\n                .unwrap_unchecked()\n                .join(&query)\n                .unwrap_unchecked()\n        };\n        Self {\n            url: Rc::new(RefCell::new(url)),\n        }\n    }\n\n    pub fn from_url(url: &Rc<RefCell<Url>>) -> Self {\n        Self {\n            url: Rc::clone(url),\n        }\n    }\n\n    pub fn from_array(ctx: &Ctx<'js>, array: Array) -> Result<Self> {\n        let mut url: Url = \"http://example.com\".parse().unwrap();\n        let query_pairs: Vec<(String, String)> = array\n            .into_iter()\n            .map(|value| {\n                if let Ok(value) = value {\n                    if let Some(pair) = value.as_array() {\n                        if pair.len() == 2 {\n                            if let Ok(key) = pair.get::<Coerced<String>>(0) {\n                                if let Ok(value) = pair.get::<Coerced<String>>(1) {\n                                    return Ok((key.to_string(), value.to_string()));\n                                }\n                            }\n                        }\n                    }\n                };\n                Err(Exception::throw_type(\n                    ctx,\n                    \"Invalid tuple: Each query pair must be an iterable [name, value] tuple\",\n                ))\n            })\n            .collect::<Result<Vec<_>>>()?\n            .into_iter()\n            .collect();\n\n        url.query_pairs_mut().extend_pairs(query_pairs);\n\n        Ok(Self {\n            url: Rc::new(RefCell::new(url)),\n        })\n    }\n\n    pub fn from_object(ctx: &Ctx<'js>, object: Object<'js>) -> Result<Self> {\n        let iterator = Symbol::iterator(ctx.clone());\n        if object.contains_key(iterator)? {\n            let query_pairs: Array = BasePrimordials::get(ctx)?\n                .function_array_from\n                .call((object,))?;\n            return Self::from_array(ctx, query_pairs);\n        }\n\n        let mut url: Url = \"http://example.com\".parse().unwrap();\n        let query_pairs: Vec<(String, String)> = object\n            .keys::<Value<'js>>()\n            .map(|key| {\n                let key = key?;\n                let key_string: String = Coerced::from_js(ctx, key.clone())?.0;\n                let value: String = object.get::<_, Coerced<String>>(key)?.0;\n                Ok((key_string, value))\n            })\n            .collect::<Result<Vec<_>>>()?\n            .into_iter()\n            .collect();\n\n        url.query_pairs_mut().extend_pairs(query_pairs);\n\n        Ok(Self {\n            url: Rc::new(RefCell::new(url)),\n        })\n    }\n}\n\n#[derive(Trace, rquickjs::JsLifetime)]\n#[rquickjs::class]\npub struct URLSearchParamsIter {\n    params: URLSearchParams,\n    index: u32,\n}\n\n#[rquickjs::methods]\nimpl<'js> URLSearchParamsIter {\n    pub fn next(&mut self, ctx: Ctx<'js>) -> Result<Object<'js>> {\n        let obj = Object::new(ctx.clone())?;\n        let value = (*self.params.url.borrow())\n            .query_pairs()\n            .nth(self.index as _)\n            .map(|(k, v)| vec![k.to_string(), v.to_string()]);\n\n        if let Some(value) = value {\n            obj.set(\"done\", false)?;\n            obj.set(\"value\", value)?;\n        } else {\n            obj.set(\"done\", true)?;\n        }\n\n        self.index += 1;\n\n        Ok(obj)\n    }\n}\n\nimpl<'js> IteratorDef<'js> for URLSearchParams {\n    fn js_entries(&self, ctx: Ctx<'js>) -> Result<Array<'js>> {\n        let array = Array::new(ctx.clone())?;\n        for (idx, (key, value)) in self.url.borrow().query_pairs().into_owned().enumerate() {\n            let entry = Array::new(ctx.clone())?;\n            entry.set(0, key)?;\n            entry.set(1, value)?;\n            array.set(idx, entry)?;\n        }\n        Ok(array)\n    }\n}\n\nfn get_coerced_string_value<'js>(ctx: &Ctx<'js>, value: Opt<Value<'js>>) -> Option<String> {\n    if let Some(value) = value.0 {\n        if !value.is_undefined() {\n            if let Ok(value) = Coerced::<String>::from_js(ctx, value) {\n                return Some(value.0);\n            }\n        }\n    };\n    None\n}\n\n#[cfg(test)]\nmod tests {\n    use llrt_test::test_sync_with;\n    use rquickjs::{CatchResultExt, Class};\n\n    use super::*;\n\n    #[tokio::test]\n    async fn test_basic() {\n        test_sync_with(|ctx| {\n            Class::<URLSearchParams>::define(&ctx.globals()).unwrap();\n            let result = ctx\n                .eval::<String, _>(\n                    r#\"\n                const params = new URLSearchParams();\n                params.append('a', '1');\n                params.append('b', '2');\n                params.append('a', '3');\n                params.append('b', '4');\n                params.append('c', 8);\n                params.delete('a');\n                params.delete('b', '2');\n                params.toString()\n            \"#,\n                )\n                .catch(&ctx)\n                .unwrap();\n            assert_eq!(result, \"b=4&c=8\");\n            Ok(())\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_iterate() {\n        test_sync_with(|ctx| {\n            Class::<URLSearchParams>::define(&ctx.globals()).unwrap();\n            let result = ctx\n                .eval::<String, _>(\n                    r#\"\n                const params = new URLSearchParams();\n                params.append('a', '1');\n                params.append('b', '2');\n                params.append('a', '3');\n                let res = [];\n                for (const [name, value] of params) {\n                    res.push(`${name}=${value}`);\n                }\n                res.join('&')\n            \"#,\n                )\n                .catch(&ctx)\n                .unwrap();\n            assert_eq!(result, \"a=1&b=2&a=3\");\n            Ok(())\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_iterate_entries() {\n        test_sync_with(|ctx| {\n            Class::<URLSearchParams>::define(&ctx.globals()).unwrap();\n            let result = ctx\n                .eval::<String, _>(\n                    r#\"\n                const params = new URLSearchParams();\n                params.append('a', '1');\n                params.append('b', '2');\n                params.append('a', '3');\n                let res = [];\n                for (const [name, value] of params.entries()) {\n                    res.push(`${name}=${value}`);\n                }\n                res.join('&')\n            \"#,\n                )\n                .catch(&ctx)\n                .unwrap();\n            assert_eq!(result, \"a=1&b=2&a=3\");\n            Ok(())\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_iterate_keys() {\n        test_sync_with(|ctx| {\n            Class::<URLSearchParams>::define(&ctx.globals()).unwrap();\n            let result = ctx\n                .eval::<String, _>(\n                    r#\"\n                const params = new URLSearchParams();\n                params.append('a', '1');\n                params.append('b', '2');\n                params.append('a', '3');\n                let res = [];\n                for (const name of params.keys()) {\n                    res.push(name);\n                }\n                res.join('&')\n            \"#,\n                )\n                .catch(&ctx)\n                .unwrap();\n            assert_eq!(result, \"a&b&a\");\n            Ok(())\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_iterate_values() {\n        test_sync_with(|ctx| {\n            Class::<URLSearchParams>::define(&ctx.globals()).unwrap();\n            let result = ctx\n                .eval::<String, _>(\n                    r#\"\n                const params = new URLSearchParams();\n                params.append('a', '1');\n                params.append('b', '2');\n                params.append('a', '3');\n                let res = [];\n                for (const name of params.values()) {\n                    res.push(name);\n                }\n                res.join('&')\n            \"#,\n                )\n                .catch(&ctx)\n                .unwrap();\n            assert_eq!(result, \"1&2&3\");\n            Ok(())\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_new_string() {\n        test_sync_with(|ctx| {\n            Class::<URLSearchParams>::define(&ctx.globals()).unwrap();\n            let result = ctx\n                .eval::<String, _>(\n                    r#\"\n                const params = new URLSearchParams('a=1&b=2&a=3');\n                params.toString()\n            \"#,\n                )\n                .catch(&ctx)\n                .unwrap();\n            assert_eq!(result, \"a=1&b=2&a=3\");\n            Ok(())\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_new_string_url() {\n        test_sync_with(|ctx| {\n            Class::<URLSearchParams>::define(&ctx.globals()).unwrap();\n            let result = ctx\n                .eval::<String, _>(\n                    r#\"\n                const params = new URLSearchParams('https://google.com?a=1&b=2&a=3');\n                params.toString()\n            \"#,\n                )\n                .catch(&ctx)\n                .unwrap();\n            assert_eq!(result, \"https%3A%2F%2Fgoogle.com%3Fa=1&b=2&a=3\");\n            Ok(())\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_new_object() {\n        test_sync_with(|ctx| {\n            Class::<URLSearchParams>::define(&ctx.globals()).unwrap();\n            let result = ctx\n                .eval::<String, _>(\n                    r#\"\n                const params = new URLSearchParams({'a': 1, 'b': 2});\n                params.toString()\n            \"#,\n                )\n                .catch(&ctx)\n                .unwrap();\n            assert_eq!(result, \"a=1&b=2\");\n            Ok(())\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_new_array() {\n        test_sync_with(|ctx| {\n            Class::<URLSearchParams>::define(&ctx.globals()).unwrap();\n            let result = ctx\n                .eval::<String, _>(\n                    r#\"\n                const params = new URLSearchParams([['a', 1], ['b', 2], ['a', 3]]);\n                params.toString()\n            \"#,\n                )\n                .catch(&ctx)\n                .unwrap();\n            assert_eq!(result, \"a=1&b=2&a=3\");\n            Ok(())\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_new_iterator() {\n        test_sync_with(|ctx| {\n            BasePrimordials::init(&ctx)?;\n            Class::<URLSearchParams>::define(&ctx.globals()).unwrap();\n            let result = ctx\n                .eval::<String, _>(\n                    r#\"\n                const params = new URLSearchParams();\n                params.append('a', '1');\n                params.append('b', '2');\n                params.append('a', '3');\n                const params2 = new URLSearchParams(params.entries());\n                params2.toString()\n            \"#,\n                )\n                .catch(&ctx)\n                .unwrap();\n            assert_eq!(result, \"a=1&b=2&a=3\");\n            Ok(())\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_size() {\n        test_sync_with(|ctx| {\n            Class::<URLSearchParams>::define(&ctx.globals()).unwrap();\n            let result = ctx\n                .eval::<usize, _>(\n                    r#\"\n                const params = new URLSearchParams();\n                params.append('a', '1');\n                params.append('b', '2');\n                params.append('a', '3');\n                params.size\n            \"#,\n                )\n                .catch(&ctx)\n                .unwrap();\n            assert_eq!(result, 3);\n            Ok(())\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_set() {\n        test_sync_with(|ctx| {\n            Class::<URLSearchParams>::define(&ctx.globals()).unwrap();\n            let result = ctx\n                .eval::<String, _>(\n                    r#\"\n                const params = new URLSearchParams();\n                params.append('a', '1');\n                params.append('b', '2');\n                params.append('a', '3');\n                params.set('a', '4');\n                params.toString()\n            \"#,\n                )\n                .catch(&ctx)\n                .unwrap();\n            assert_eq!(result, \"a=4&b=2\");\n            Ok(())\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_get() {\n        test_sync_with(|ctx| {\n            Class::<URLSearchParams>::define(&ctx.globals()).unwrap();\n            let result = ctx\n                .eval::<String, _>(\n                    r#\"\n                const params = new URLSearchParams();\n                params.append('a', '1');\n                params.append('b', '2');\n                params.append('a', '3');\n                params.get('a')\n            \"#,\n                )\n                .catch(&ctx)\n                .unwrap();\n            assert_eq!(result, \"1\");\n            Ok(())\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_get_missing() {\n        test_sync_with(|ctx| {\n            Class::<URLSearchParams>::define(&ctx.globals()).unwrap();\n            let result = ctx\n                .eval::<bool, _>(\n                    r#\"\n                const params = new URLSearchParams();\n                params.append('a', '1');\n                params.append('b', '2');\n                params.append('a', '3');\n                params.get('c') === null\n            \"#,\n                )\n                .catch(&ctx)\n                .unwrap();\n            assert!(result);\n            Ok(())\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_get_all() {\n        test_sync_with(|ctx| {\n            Class::<URLSearchParams>::define(&ctx.globals()).unwrap();\n            let result = ctx\n                .eval::<String, _>(\n                    r#\"\n                const params = new URLSearchParams();\n                params.append('a', '1');\n                params.append('b', '2');\n                params.append('a', '3');\n                params.getAll('a').join('&')\n            \"#,\n                )\n                .catch(&ctx)\n                .unwrap();\n            assert_eq!(result, \"1&3\");\n            Ok(())\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_get_all_missing() {\n        test_sync_with(|ctx| {\n            Class::<URLSearchParams>::define(&ctx.globals()).unwrap();\n            let result = ctx\n                .eval::<String, _>(\n                    r#\"\n                const params = new URLSearchParams();\n                params.append('a', '1');\n                params.append('b', '2');\n                params.append('a', '3');\n                params.getAll('c').join('&')\n            \"#,\n                )\n                .catch(&ctx)\n                .unwrap();\n            assert_eq!(result, \"\");\n            Ok(())\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_has() {\n        test_sync_with(|ctx| {\n            Class::<URLSearchParams>::define(&ctx.globals()).unwrap();\n            let result = ctx\n                .eval::<bool, _>(\n                    r#\"\n                const params = new URLSearchParams();\n                params.append('a', '1');\n                params.append('b', '2');\n                params.append('a', '3');\n                params.has('b')\n            \"#,\n                )\n                .catch(&ctx)\n                .unwrap();\n            assert!(result);\n            Ok(())\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_has_value() {\n        test_sync_with(|ctx| {\n            Class::<URLSearchParams>::define(&ctx.globals()).unwrap();\n            let result = ctx\n                .eval::<bool, _>(\n                    r#\"\n                const params = new URLSearchParams();\n                params.append('a', '1');\n                params.append('b', '2');\n                params.append('a', '3');\n                params.has('b', 5)\n            \"#,\n                )\n                .catch(&ctx)\n                .unwrap();\n            assert!(!result);\n            Ok(())\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_has_not() {\n        test_sync_with(|ctx| {\n            Class::<URLSearchParams>::define(&ctx.globals()).unwrap();\n            let result = ctx\n                .eval::<bool, _>(\n                    r#\"\n                const params = new URLSearchParams();\n                params.append('a', '1');\n                params.append('b', '2');\n                params.append('a', '3');\n                params.has('c')\n            \"#,\n                )\n                .catch(&ctx)\n                .unwrap();\n            assert!(!result);\n            Ok(())\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_sort() {\n        test_sync_with(|ctx| {\n            Class::<URLSearchParams>::define(&ctx.globals()).unwrap();\n            let result = ctx\n                .eval::<String, _>(\n                    r#\"\n                const params = new URLSearchParams();\n                params.append('a', '3');\n                params.append('b', '2');\n                params.append('a', '1');\n                params.sort();\n                params.toString()\n            \"#,\n                )\n                .catch(&ctx)\n                .unwrap();\n            assert_eq!(result, \"a=3&a=1&b=2\");\n            Ok(())\n        })\n        .await\n    }\n\n    #[tokio::test]\n    async fn test_for_each() {\n        test_sync_with(|ctx| {\n            Class::<URLSearchParams>::define(&ctx.globals()).unwrap();\n            let result = ctx\n                .eval::<String, _>(\n                    r#\"\n                const params = new URLSearchParams();\n                params.append('a', '3');\n                params.append('b', '2');\n                params.append('a', '1');\n                let res = [];\n                params.forEach((value, name) => {\n                    res.push(`${name}=${value}`);\n                });\n                res.join('&')\n            \"#,\n                )\n                .catch(&ctx)\n                .unwrap();\n            assert_eq!(result, \"a=3&b=2&a=1\");\n            Ok(())\n        })\n        .await\n    }\n}\n"
  },
  {
    "path": "modules/llrt_util/Cargo.toml",
    "content": "[package]\nname = \"llrt_util\"\ndescription = \"LLRT Module util\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\nreadme = \"README.md\"\n\n[lib]\nname = \"llrt_util\"\npath = \"src/lib.rs\"\n\n[dependencies]\nllrt_context = { version = \"0.8.1-beta\", path = \"../../libs/llrt_context\" }\nllrt_encoding = { version = \"0.8.1-beta\", path = \"../../libs/llrt_encoding\" }\nllrt_logging = { version = \"0.8.1-beta\", path = \"../../libs/llrt_logging\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", default-features = false }\n"
  },
  {
    "path": "modules/llrt_util/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\npub mod text_decoder;\npub mod text_encoder;\n\nuse llrt_logging::format_plain;\nuse llrt_utils::module::{export_default, ModuleInfo};\nuse rquickjs::{\n    function::Func,\n    module::{Declarations, Exports, ModuleDef},\n    Class, Ctx, Function, Object, Result,\n};\nuse text_decoder::TextDecoder;\nuse text_encoder::TextEncoder;\n\nfn inherits<'js>(ctor: Function<'js>, super_ctor: Function<'js>) -> Result<()> {\n    let super_proto: Object<'js> = super_ctor.get(\"prototype\")?;\n    let proto: Object<'js> = ctor.get(\"prototype\")?;\n    proto.set_prototype(Some(&super_proto))?;\n    ctor.set(\"super_\", super_ctor)?;\n    Ok(())\n}\n\npub struct UtilModule;\n\nimpl ModuleDef for UtilModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(stringify!(TextDecoder))?;\n        declare.declare(stringify!(TextEncoder))?;\n        declare.declare(stringify!(format))?;\n        declare.declare(stringify!(inherits))?;\n        declare.declare(\"default\")?;\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        export_default(ctx, exports, |default| {\n            let globals = ctx.globals();\n\n            let encoder: Function = globals.get(stringify!(TextEncoder))?;\n            let decoder: Function = globals.get(stringify!(TextDecoder))?;\n\n            default.set(stringify!(TextEncoder), encoder)?;\n            default.set(stringify!(TextDecoder), decoder)?;\n            default.set(\n                \"format\",\n                Func::from(|ctx, args| format_plain(ctx, true, args)),\n            )?;\n            default.set(\"inherits\", Func::from(inherits))?;\n\n            Ok(())\n        })\n    }\n}\n\nimpl From<UtilModule> for ModuleInfo<UtilModule> {\n    fn from(val: UtilModule) -> Self {\n        ModuleInfo {\n            name: \"util\",\n            module: val,\n        }\n    }\n}\n\npub fn init(ctx: &Ctx<'_>) -> Result<()> {\n    let globals = ctx.globals();\n\n    Class::<TextEncoder>::define(&globals)?;\n    Class::<TextDecoder>::define(&globals)?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "modules/llrt_util/src/text_decoder.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_encoding::Encoder;\nuse llrt_utils::{bytes::ObjectBytes, object::ObjectExt, result::ResultExt};\nuse rquickjs::{atom::PredefinedAtom, function::Opt, Ctx, Object, Result};\n\n#[rquickjs::class]\n#[derive(rquickjs::class::Trace, rquickjs::JsLifetime)]\npub struct TextDecoder {\n    #[qjs(skip_trace)]\n    encoder: Encoder,\n    fatal: bool,\n    ignore_bom: bool,\n}\n\n#[rquickjs::methods]\nimpl<'js> TextDecoder {\n    #[qjs(constructor)]\n    pub fn new(ctx: Ctx<'js>, label: Opt<String>, options: Opt<Object<'js>>) -> Result<Self> {\n        let mut fatal = false;\n        let mut ignore_bom = false;\n\n        let encoder = Encoder::from_optional_str(label.as_deref()).or_throw_range(&ctx, \"\")?;\n\n        if let Some(options) = options.0 {\n            if let Some(opt) = options.get_optional(\"fatal\")? {\n                fatal = opt;\n            }\n            if let Some(opt) = options.get_optional(\"ignoreBOM\")? {\n                ignore_bom = opt;\n            }\n        }\n\n        Ok(TextDecoder {\n            encoder,\n            fatal,\n            ignore_bom,\n        })\n    }\n\n    #[qjs(get)]\n    fn encoding(&self) -> &str {\n        self.encoder.as_label()\n    }\n\n    #[qjs(get)]\n    fn fatal(&self) -> bool {\n        self.fatal\n    }\n\n    #[qjs(get, rename = \"ignoreBOM\")]\n    fn ignore_bom(&self) -> bool {\n        self.ignore_bom\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    pub fn to_string_tag(&self) -> &'static str {\n        stringify!(TextDecoder)\n    }\n\n    pub fn decode(&self, ctx: Ctx<'js>, bytes: ObjectBytes<'js>) -> Result<String> {\n        let bytes = bytes.as_bytes(&ctx)?;\n        let start_pos = if !self.ignore_bom {\n            match (&self.encoder, bytes.get(..3)) {\n                (Encoder::Utf16le, Some([0xFF, 0xFE, ..])) => 2,\n                (Encoder::Utf16be, Some([0xFE, 0xFF, ..])) => 2,\n                (Encoder::Utf8, Some([0xEF, 0xBB, 0xBF])) => 3,\n                _ => 0,\n            }\n        } else {\n            0\n        };\n\n        self.encoder\n            .encode_to_string(&bytes[start_pos..], !self.fatal)\n            .or_throw_type(&ctx, \"\")\n    }\n}\n"
  },
  {
    "path": "modules/llrt_util/src/text_encoder.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_utils::result::ResultExt;\nuse rquickjs::{\n    atom::PredefinedAtom, function::Opt, Ctx, Exception, Object, Result, TypedArray, Value,\n};\n\n#[derive(rquickjs::class::Trace, rquickjs::JsLifetime)]\n#[rquickjs::class]\npub struct TextEncoder {}\n\nimpl Default for TextEncoder {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n#[rquickjs::methods(rename_all = \"camelCase\")]\nimpl TextEncoder {\n    #[qjs(constructor)]\n    pub fn new() -> Self {\n        Self {}\n    }\n\n    #[qjs(get)]\n    fn encoding(&self) -> &str {\n        \"utf-8\"\n    }\n\n    #[qjs(get, rename = PredefinedAtom::SymbolToStringTag)]\n    pub fn to_string_tag(&self) -> &'static str {\n        stringify!(TextEncoder)\n    }\n\n    pub fn encode<'js>(&self, ctx: Ctx<'js>, string: Opt<Value<'js>>) -> Result<Value<'js>> {\n        if let Some(string) = string.0 {\n            if let Some(string) = string.as_string() {\n                let string = string.to_string()?;\n                return TypedArray::new(ctx.clone(), string.as_bytes())\n                    .map(|m: TypedArray<'_, u8>| m.into_value());\n            } else if !string.is_undefined() {\n                return Err(Exception::throw_message(\n                    &ctx,\n                    \"The \\\"string\\\" argument must be a string.\",\n                ));\n            }\n        }\n\n        TypedArray::new(ctx.clone(), []).map(|m: TypedArray<'_, u8>| m.into_value())\n    }\n\n    pub fn encode_into<'js>(\n        &self,\n        ctx: Ctx<'js>,\n        src: String,\n        dst: Value<'js>,\n    ) -> Result<Object<'js>> {\n        if let Ok(typed_array) = TypedArray::<u8>::from_value(dst) {\n            let dst_length = typed_array.len();\n            let dst_offset: usize = typed_array.get(\"byteOffset\")?;\n            let array_buffer = typed_array.arraybuffer()?;\n            let raw = array_buffer\n                .as_raw()\n                .ok_or(\"ArrayBuffer is detached\")\n                .or_throw(&ctx)?;\n\n            let dst = unsafe {\n                std::slice::from_raw_parts_mut(raw.ptr.as_ptr().add(dst_offset), dst_length)\n            };\n\n            let mut written = 0;\n            let dst_len = dst.len();\n            for ch in src.chars() {\n                let len = ch.len_utf8();\n                if written + len > dst_len {\n                    break;\n                }\n                written += len;\n            }\n            dst[..written].copy_from_slice(&src.as_bytes()[..written]);\n            let read: usize = src[..written].chars().map(char::len_utf16).sum();\n\n            let obj = Object::new(ctx)?;\n            obj.set(\"read\", read)?;\n            obj.set(\"written\", written)?;\n            Ok(obj)\n        } else {\n            Err(Exception::throw_type(\n                &ctx,\n                \"The \\\"dest\\\" argument must be an instance of Uint8Array.\",\n            ))\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_zlib/Cargo.toml",
    "content": "[package]\nname = \"llrt_zlib\"\ndescription = \"LLRT Module zlib\"\nversion = \"0.8.1-beta\"\nedition = \"2021\"\nlicense = \"Apache-2.0\"\nrepository = \"https://github.com/awslabs/llrt\"\nreadme = \"README.md\"\n\n[lib]\nname = \"llrt_zlib\"\npath = \"src/lib.rs\"\n\n[features]\ndefault = [\"compression-c\"]\n\ncompression-c = [\n  \"llrt_compression/brotli-c\",\n  \"llrt_compression/flate2-c\",\n  \"llrt_compression/zstd-c\",\n]\n\ncompression-rust = [\n  \"llrt_compression/brotli-rust\",\n  \"llrt_compression/flate2-rust\",\n  \"llrt_compression/zstd-rust\",\n]\n\n[dependencies]\nllrt_buffer = { version = \"0.8.1-beta\", path = \"../llrt_buffer\" }\nllrt_compression = { version = \"0.8.1-beta\", path = \"../../libs/llrt_compression\", default-features = false }\nllrt_context = { version = \"0.8.1-beta\", path = \"../../libs/llrt_context\" }\nllrt_utils = { version = \"0.8.1-beta\", path = \"../../libs/llrt_utils\", default-features = false }\nrquickjs = { version = \"0.11\", features = [\"std\"], default-features = false }\n\n[dev-dependencies]\nllrt_test = { path = \"../../libs/llrt_test\" }\n"
  },
  {
    "path": "modules/llrt_zlib/src/brotli.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::io::Read;\n\nuse llrt_buffer::Buffer;\nuse llrt_context::CtxExtension;\nuse llrt_utils::{bytes::ObjectBytes, result::ResultExt};\nuse rquickjs::{\n    prelude::{Opt, Rest},\n    Ctx, Error, Exception, Function, IntoJs, Null, Result, Value,\n};\n\nuse super::{define_cb_function, define_sync_function};\n\nenum BrotliCommand {\n    Compress,\n    Decompress,\n}\n\nfn brotli_converter<'js>(\n    ctx: Ctx<'js>,\n    bytes: ObjectBytes<'js>,\n    _options: Opt<Value<'js>>,\n    command: BrotliCommand,\n) -> Result<Value<'js>> {\n    let src = bytes.as_bytes(&ctx)?;\n\n    let mut dst: Vec<u8> = Vec::with_capacity(src.len());\n\n    let _ = match command {\n        BrotliCommand::Compress => llrt_compression::brotli::encoder(src).read_to_end(&mut dst)?,\n        BrotliCommand::Decompress => {\n            llrt_compression::brotli::decoder(src).read_to_end(&mut dst)?\n        },\n    };\n\n    Buffer(dst).into_js(&ctx)\n}\n\ndefine_cb_function!(br_comp, brotli_converter, BrotliCommand::Compress);\ndefine_sync_function!(br_comp_sync, brotli_converter, BrotliCommand::Compress);\n\ndefine_cb_function!(br_decomp, brotli_converter, BrotliCommand::Decompress);\ndefine_sync_function!(br_decomp_sync, brotli_converter, BrotliCommand::Decompress);\n"
  },
  {
    "path": "modules/llrt_zlib/src/lib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse llrt_utils::module::{export_default, ModuleInfo};\nuse rquickjs::{\n    function::Func,\n    module::{Declarations, Exports, ModuleDef},\n    Ctx, Result,\n};\n\nmod brotli;\nmod zlib;\nmod zstd;\n\nuse self::brotli::{br_comp, br_comp_sync, br_decomp, br_decomp_sync};\nuse self::zlib::{\n    deflate, deflate_raw, deflate_raw_sync, deflate_sync, gunzip, gunzip_sync, gzip, gzip_sync,\n    inflate, inflate_raw, inflate_raw_sync, inflate_sync,\n};\nuse self::zstd::{zstd_comp, zstd_comp_sync, zstd_decomp, zstd_decomp_sync};\n\n#[macro_export]\nmacro_rules! define_sync_function {\n    ($fn_name:ident, $converter:expr, $command:expr) => {\n        pub(crate) fn $fn_name<'js>(\n            ctx: Ctx<'js>,\n            value: ObjectBytes<'js>,\n            options: Opt<Value<'js>>,\n        ) -> Result<Value<'js>> {\n            $converter(ctx.clone(), value, options, $command)\n        }\n    };\n}\n\n#[macro_export]\nmacro_rules! define_cb_function {\n    ($fn_name:ident, $converter:expr, $command:expr) => {\n        pub(crate) fn $fn_name<'js>(\n            ctx: Ctx<'js>,\n            value: ObjectBytes<'js>,\n            args: Rest<Value<'js>>,\n        ) -> Result<()> {\n            let mut args_iter = args.0.into_iter().rev();\n            let cb: Function = args_iter\n                .next()\n                .and_then(|v| v.into_function())\n                .or_throw_msg(&ctx, \"Callback parameter is not a function\")?;\n            let options = match args_iter.next() {\n                Some(v) => Opt(Some(v)),\n                None => Opt(None),\n            };\n\n            ctx.clone().spawn_exit(async move {\n                match $converter(ctx.clone(), value, options, $command) {\n                    Ok(obj) => {\n                        () = cb.call((Null.into_js(&ctx), obj))?;\n                        Ok::<_, Error>(())\n                    },\n                    Err(err) => {\n                        () = cb.call((Exception::from_message(ctx, &err.to_string()),))?;\n                        Ok(())\n                    },\n                }\n            })?;\n            Ok(())\n        }\n    };\n}\npub struct ZlibModule;\n\nimpl ModuleDef for ZlibModule {\n    fn declare(declare: &Declarations) -> Result<()> {\n        declare.declare(\"deflate\")?;\n        declare.declare(\"deflateSync\")?;\n\n        declare.declare(\"deflateRaw\")?;\n        declare.declare(\"deflateRawSync\")?;\n\n        declare.declare(\"gzip\")?;\n        declare.declare(\"gzipSync\")?;\n\n        declare.declare(\"inflate\")?;\n        declare.declare(\"inflateSync\")?;\n\n        declare.declare(\"inflateRaw\")?;\n        declare.declare(\"inflateRawSync\")?;\n\n        declare.declare(\"gunzip\")?;\n        declare.declare(\"gunzipSync\")?;\n\n        declare.declare(\"brotliCompress\")?;\n        declare.declare(\"brotliCompressSync\")?;\n\n        declare.declare(\"brotliDecompress\")?;\n        declare.declare(\"brotliDecompressSync\")?;\n\n        declare.declare(\"zstdCompress\")?;\n        declare.declare(\"zstdCompressSync\")?;\n\n        declare.declare(\"zstdDecompress\")?;\n        declare.declare(\"zstdDecompressSync\")?;\n\n        declare.declare(\"default\")?;\n        Ok(())\n    }\n\n    fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {\n        export_default(ctx, exports, |default| {\n            default.set(\"deflate\", Func::from(deflate))?;\n            default.set(\"deflateSync\", Func::from(deflate_sync))?;\n\n            default.set(\"deflateRaw\", Func::from(deflate_raw))?;\n            default.set(\"deflateRawSync\", Func::from(deflate_raw_sync))?;\n\n            default.set(\"gzip\", Func::from(gzip))?;\n            default.set(\"gzipSync\", Func::from(gzip_sync))?;\n\n            default.set(\"inflate\", Func::from(inflate))?;\n            default.set(\"inflateSync\", Func::from(inflate_sync))?;\n\n            default.set(\"inflateRaw\", Func::from(inflate_raw))?;\n            default.set(\"inflateRawSync\", Func::from(inflate_raw_sync))?;\n\n            default.set(\"gunzip\", Func::from(gunzip))?;\n            default.set(\"gunzipSync\", Func::from(gunzip_sync))?;\n\n            default.set(\"brotliCompress\", Func::from(br_comp))?;\n            default.set(\"brotliCompressSync\", Func::from(br_comp_sync))?;\n\n            default.set(\"brotliDecompress\", Func::from(br_decomp))?;\n            default.set(\"brotliDecompressSync\", Func::from(br_decomp_sync))?;\n\n            default.set(\"zstdCompress\", Func::from(zstd_comp))?;\n            default.set(\"zstdCompressSync\", Func::from(zstd_comp_sync))?;\n\n            default.set(\"zstdDecompress\", Func::from(zstd_decomp))?;\n            default.set(\"zstdDecompressSync\", Func::from(zstd_decomp_sync))?;\n\n            Ok(())\n        })\n    }\n}\n\nimpl From<ZlibModule> for ModuleInfo<ZlibModule> {\n    fn from(val: ZlibModule) -> Self {\n        ModuleInfo {\n            name: \"zlib\",\n            module: val,\n        }\n    }\n}\n"
  },
  {
    "path": "modules/llrt_zlib/src/zlib.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::io::Read;\n\nuse llrt_buffer::Buffer;\nuse llrt_context::CtxExtension;\nuse llrt_utils::{bytes::ObjectBytes, object::ObjectExt, result::ResultExt};\nuse rquickjs::{\n    prelude::{Opt, Rest},\n    Ctx, Error, Exception, Function, IntoJs, Null, Result, Value,\n};\n\nuse super::{define_cb_function, define_sync_function};\n\nenum ZlibCommand {\n    Deflate,\n    DeflateRaw,\n    Gzip,\n    Inflate,\n    InflateRaw,\n    Gunzip,\n}\n\nfn zlib_converter<'js>(\n    ctx: Ctx<'js>,\n    bytes: ObjectBytes<'js>,\n    options: Opt<Value<'js>>,\n    command: ZlibCommand,\n) -> Result<Value<'js>> {\n    let src = bytes.as_bytes(&ctx)?;\n\n    let mut level = llrt_compression::zlib::Compression::default();\n    if let Some(options) = options.0 {\n        if let Some(opt) = options.get_optional(\"level\")? {\n            level = llrt_compression::zlib::Compression::new(opt);\n        }\n    }\n\n    let mut dst: Vec<u8> = Vec::with_capacity(src.len());\n\n    let _ = match command {\n        ZlibCommand::Deflate => {\n            llrt_compression::zlib::encoder(src, level).read_to_end(&mut dst)?\n        },\n        ZlibCommand::DeflateRaw => {\n            llrt_compression::deflate::encoder(src, level).read_to_end(&mut dst)?\n        },\n        ZlibCommand::Gzip => llrt_compression::gz::encoder(src, level).read_to_end(&mut dst)?,\n        ZlibCommand::Inflate => llrt_compression::zlib::decoder(src).read_to_end(&mut dst)?,\n        ZlibCommand::InflateRaw => llrt_compression::deflate::decoder(src).read_to_end(&mut dst)?,\n        ZlibCommand::Gunzip => llrt_compression::gz::decoder(src).read_to_end(&mut dst)?,\n    };\n\n    Buffer(dst).into_js(&ctx)\n}\n\ndefine_cb_function!(deflate, zlib_converter, ZlibCommand::Deflate);\ndefine_sync_function!(deflate_sync, zlib_converter, ZlibCommand::Deflate);\n\ndefine_cb_function!(deflate_raw, zlib_converter, ZlibCommand::DeflateRaw);\ndefine_sync_function!(deflate_raw_sync, zlib_converter, ZlibCommand::DeflateRaw);\n\ndefine_cb_function!(gzip, zlib_converter, ZlibCommand::Gzip);\ndefine_sync_function!(gzip_sync, zlib_converter, ZlibCommand::Gzip);\n\ndefine_cb_function!(inflate, zlib_converter, ZlibCommand::Inflate);\ndefine_sync_function!(inflate_sync, zlib_converter, ZlibCommand::Inflate);\n\ndefine_cb_function!(inflate_raw, zlib_converter, ZlibCommand::InflateRaw);\ndefine_sync_function!(inflate_raw_sync, zlib_converter, ZlibCommand::InflateRaw);\n\ndefine_cb_function!(gunzip, zlib_converter, ZlibCommand::Gunzip);\ndefine_sync_function!(gunzip_sync, zlib_converter, ZlibCommand::Gunzip);\n"
  },
  {
    "path": "modules/llrt_zlib/src/zstd.rs",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nuse std::io::Read;\n\nuse llrt_buffer::Buffer;\nuse llrt_context::CtxExtension;\nuse llrt_utils::{bytes::ObjectBytes, object::ObjectExt, result::ResultExt};\nuse rquickjs::{\n    prelude::{Opt, Rest},\n    Ctx, Error, Exception, Function, IntoJs, Null, Result, Value,\n};\n\nuse super::{define_cb_function, define_sync_function};\n\nenum ZstdCommand {\n    Compress,\n    Decompress,\n}\n\nfn zstd_converter<'js>(\n    ctx: Ctx<'js>,\n    bytes: ObjectBytes<'js>,\n    options: Opt<Value<'js>>,\n    command: ZstdCommand,\n) -> Result<Value<'js>> {\n    let src = bytes.as_bytes(&ctx)?;\n\n    let mut level = llrt_compression::zstd::DEFAULT_COMPRESSION_LEVEL;\n    if let Some(options) = options.0 {\n        if let Some(opt) = options.get_optional(\"level\")? {\n            level = opt;\n        }\n    }\n\n    let mut dst: Vec<u8> = Vec::with_capacity(src.len());\n\n    let _ = match command {\n        ZstdCommand::Compress => {\n            llrt_compression::zstd::encoder(src, level)?.read_to_end(&mut dst)?\n        },\n        ZstdCommand::Decompress => llrt_compression::zstd::decoder(src)?.read_to_end(&mut dst)?,\n    };\n\n    Buffer(dst).into_js(&ctx)\n}\n\ndefine_cb_function!(zstd_comp, zstd_converter, ZstdCommand::Compress);\ndefine_sync_function!(zstd_comp_sync, zstd_converter, ZstdCommand::Compress);\n\ndefine_cb_function!(zstd_decomp, zstd_converter, ZstdCommand::Decompress);\ndefine_sync_function!(zstd_decomp_sync, zstd_converter, ZstdCommand::Decompress);\n"
  },
  {
    "path": "pack",
    "content": "#!/usr/bin/env bash\n# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n# SPDX-License-Identifier: Apache-2.0\n\nset -e\n\nif [ \"$#\" -ne 2 ]; then\n  echo \"Error: Two file arguments are required.\"\n  echo \"Usage: $0 input_file output_file\"\n  exit 1\nfi\n\n\n# Set the number of parts to split the file into\nnum_parts=2\ndata_size=$(wc -c < \"$1\")\n\nsrcfile=\"$1\"\ndstfile=\"$2\"\n\n# Check if the bytes start with \\x7fELF\nif [[ $(hexdump -n 4 -e '4/1 \"%02x\"' $srcfile) != \"7f454c46\" ]]; then\n    echo \"The binary is not an ELF executable\"\n    exit 1\nfi\n\narch_hex=$(hexdump -s 18 -n 1 -e '\"%02x\"' $srcfile)\n\nif [[ \"$arch_hex\" == \"3e\" ]]; then\n    target=\"x86_64-linux-musl\"\n    arch=\"x64\"\nelif [[ \"$arch_hex\" == \"b7\" ]]; then\n    target=\"aarch64-linux-musl\"\n    arch=\"arm64\"\nelse\n    echo \"The binary is not an ARM64 or X86_64 ELF executable\"\n    exit 1\nfi\n\n\n# Create a temporary directory to store the parts\ntemp_folder=$(mktemp -d)\n\n# Split the file into parts and compress each part using lz4\nsplit -n ${num_parts} $srcfile ${temp_folder}/part_\n\ncompressed_data=\"\"\n\ninput_sizes=()\noutput_sizes=()\ntotal_input_size=0\ntotal_output_size=0\nworking_dir=$(pwd)\n\nfor file in ${temp_folder}/*; do\n    filename=$(basename $file)\n    echo \"Compressing $filename...\"\n    (cd $(dirname $file) && zstd --ultra -22 --no-check -f \"$filename\" -o \"${filename}.zst\")\n    output_size=$(wc -c < \"${file}\")\n    input_size=$(wc -c < \"${file}.zst\")\n    input_sizes+=($input_size)\n    output_sizes+=($output_size)\n    total_input_size=$((total_input_size + input_size))\n    total_output_size=$((total_output_size + output_size))\n\n    hex_data=$(hexdump -v -e '/1 \" %02x\"' \"${file}.zst\" | sed 's/ /\\\\\\\\x/g')\n\n    compressed_data=\"${compressed_data}${hex_data}\"\n\n    rm \"${file}\"\ndone\n\nfunction little_endian_hex()\n{\n    local hex_code=\"\"\n    local number\n\n    for number in \"$@\"; do\n        byte=$(printf \"%08x\" $number | sed -r 's/(..)(..)(..)(..)/\\4\\3\\2\\1/')\n        hex_code=\"${hex_code}${byte}\"\n    done\n\n    # Insert \\x separators between bytes\n    hex_code=$(echo \"$hex_code\" | sed 's/../\\\\x&/g')\n\n    echo \"$hex_code\"\n}\n\nINPUT_SIZES_STR=$(little_endian_hex ${input_sizes[@]})\nOUTPUT_SIZES_STR=$(little_endian_hex ${output_sizes[@]})\n\ncat <<EOF > ${temp_folder}/data.c\nconst char *data = \"$(printf \"\\\\\\x%02x\" $num_parts)${INPUT_SIZES_STR}${OUTPUT_SIZES_STR}$(printf \"$compressed_data\")\";\nEOF\n\ncp \"$1\" \"${1}.bak\"\ncp llrt/src/main.c $temp_folder/\n\necho \"Compiling...\"\n\noriginal_size=$(du -h $srcfile | cut -f1)\n\nzig cc -target $target -Wno-null-character -std=c99 -Wall -O3 -flto -s ${temp_folder}/main.c -o $dstfile -Ilib -Llib/${arch} -static -lzstd\n\nnew_size=$(du -h $dstfile | cut -f1)\n\necho \"Done. Compressed $original_size => $new_size\"\n\nrm -rf $temp_folder"
  },
  {
    "path": "package.json",
    "content": "{\n  \"workspaces\": [\n    \"./example/*\"\n  ],\n  \"license\": \"Apache-2.0\",\n  \"version\": \"0.5.1-beta\",\n  \"type\": \"module\",\n  \"private\": true,\n  \"prettier\": {\n    \"trailingComma\": \"es5\",\n    \"singleQuote\": false\n  },\n  \"scripts\": {\n    \"esbuild\": \"esbuild\",\n    \"update\": \"yarn upgrade-interactive --latest\",\n    \"reinstall\": \"rm -rf yarn.lock && rm -rf node_modules && yarn\",\n    \"test\": \"make test\"\n  },\n  \"side-effects\": false,\n  \"devDependencies\": {\n    \"@aws-sdk/client-acm\": \"3.991.0\",\n    \"@aws-sdk/client-amplify\": \"3.991.0\",\n    \"@aws-sdk/client-api-gateway\": \"3.991.0\",\n    \"@aws-sdk/client-apigatewayv2\": \"3.991.0\",\n    \"@aws-sdk/client-appconfig\": \"3.991.0\",\n    \"@aws-sdk/client-appconfigdata\": \"3.991.0\",\n    \"@aws-sdk/client-appsync\": \"3.991.0\",\n    \"@aws-sdk/client-athena\": \"3.991.0\",\n    \"@aws-sdk/client-auto-scaling\": \"3.991.0\",\n    \"@aws-sdk/client-batch\": \"3.991.0\",\n    \"@aws-sdk/client-bedrock\": \"3.991.0\",\n    \"@aws-sdk/client-bedrock-agent\": \"3.991.0\",\n    \"@aws-sdk/client-bedrock-agent-runtime\": \"3.991.0\",\n    \"@aws-sdk/client-bedrock-runtime\": \"3.991.0\",\n    \"@aws-sdk/client-cloudformation\": \"3.991.0\",\n    \"@aws-sdk/client-cloudwatch\": \"3.991.0\",\n    \"@aws-sdk/client-cloudwatch-events\": \"3.991.0\",\n    \"@aws-sdk/client-cloudwatch-logs\": \"3.991.0\",\n    \"@aws-sdk/client-cognito-identity\": \"3.991.0\",\n    \"@aws-sdk/client-cognito-identity-provider\": \"3.991.0\",\n    \"@aws-sdk/client-dynamodb\": \"3.991.0\",\n    \"@aws-sdk/client-dynamodb-streams\": \"3.991.0\",\n    \"@aws-sdk/client-ec2\": \"3.991.0\",\n    \"@aws-sdk/client-ecr\": \"3.991.0\",\n    \"@aws-sdk/client-ecs\": \"3.991.0\",\n    \"@aws-sdk/client-efs\": \"3.991.0\",\n    \"@aws-sdk/client-eks\": \"3.991.0\",\n    \"@aws-sdk/client-elastic-load-balancing-v2\": \"3.991.0\",\n    \"@aws-sdk/client-elasticache\": \"3.991.0\",\n    \"@aws-sdk/client-eventbridge\": \"3.991.0\",\n    \"@aws-sdk/client-firehose\": \"3.991.0\",\n    \"@aws-sdk/client-glue\": \"3.991.0\",\n    \"@aws-sdk/client-iam\": \"3.991.0\",\n    \"@aws-sdk/client-kinesis\": \"3.991.0\",\n    \"@aws-sdk/client-kms\": \"3.991.0\",\n    \"@aws-sdk/client-lambda\": \"3.991.0\",\n    \"@aws-sdk/client-location\": \"3.991.0\",\n    \"@aws-sdk/client-mediaconvert\": \"3.991.0\",\n    \"@aws-sdk/client-opensearch\": \"3.991.0\",\n    \"@aws-sdk/client-opensearchserverless\": \"3.991.0\",\n    \"@aws-sdk/client-polly\": \"3.991.0\",\n    \"@aws-sdk/client-rds\": \"3.991.0\",\n    \"@aws-sdk/client-rds-data\": \"3.991.0\",\n    \"@aws-sdk/client-rekognition\": \"3.991.0\",\n    \"@aws-sdk/client-s3\": \"3.991.0\",\n    \"@aws-sdk/client-scheduler\": \"3.991.0\",\n    \"@aws-sdk/client-secrets-manager\": \"3.991.0\",\n    \"@aws-sdk/client-service-catalog\": \"3.991.0\",\n    \"@aws-sdk/client-servicediscovery\": \"3.991.0\",\n    \"@aws-sdk/client-ses\": \"3.991.0\",\n    \"@aws-sdk/client-sesv2\": \"3.991.0\",\n    \"@aws-sdk/client-sfn\": \"3.991.0\",\n    \"@aws-sdk/client-sns\": \"3.991.0\",\n    \"@aws-sdk/client-sqs\": \"3.991.0\",\n    \"@aws-sdk/client-ssm\": \"3.991.0\",\n    \"@aws-sdk/client-sso\": \"3.991.0\",\n    \"@aws-sdk/client-sso-admin\": \"3.991.0\",\n    \"@aws-sdk/client-sso-oidc\": \"3.991.0\",\n    \"@aws-sdk/client-sts\": \"3.991.0\",\n    \"@aws-sdk/client-textract\": \"3.991.0\",\n    \"@aws-sdk/client-translate\": \"3.991.0\",\n    \"@aws-sdk/client-verifiedpermissions\": \"3.991.0\",\n    \"@aws-sdk/client-xray\": \"3.991.0\",\n    \"@aws-sdk/credential-providers\": \"3.991.0\",\n    \"@aws-sdk/lib-dynamodb\": \"3.991.0\",\n    \"@aws-sdk/lib-storage\": \"3.991.0\",\n    \"@aws-sdk/s3-presigned-post\": \"3.991.0\",\n    \"@aws-sdk/s3-request-presigner\": \"3.991.0\",\n    \"@jest/types\": \"30.2.0\",\n    \"@types/chai\": \"5.2.3\",\n    \"@types/jest\": \"30.0.0\",\n    \"@types/readable-stream\": \"4.0.23\",\n    \"esbuild\": \"0.27.3\",\n    \"esbuild-plugins-node-modules-polyfill\": \"1.8.1\",\n    \"prettier\": \"3.8.1\",\n    \"pretty-format\": \"30.2.0\",\n    \"pretty-quick\": \"4.2.2\",\n    \"pure-http\": \"4.0.2\",\n    \"readable-stream\": \"4.7.0\",\n    \"stream-browserify\": \"3.0.0\",\n    \"ts-node\": \"10.9.2\",\n    \"typescript\": \"5.9.3\",\n    \"vitest\": \"4.0.18\"\n  },\n  \"packageManager\": \"yarn@1.22.22\"\n}\n"
  },
  {
    "path": "rustfmt.toml",
    "content": "edition = \"2021\"\nfn_params_layout = \"Tall\"\nmatch_block_trailing_comma = true\n"
  },
  {
    "path": "sdk.cfg",
    "content": "# API Endpoint Definitions\n#\n# {NPM package name},{Client name},{Servic endpoint},{full SDK only}\n#\n# The meanings of each and how to look them up are as follows:\n#\n# 1. Classification\n# https://docs.aws.amazon.com/whitepapers/latest/aws-overview/amazon-web-services-cloud-platform.html\n#\n# 2. ClientName\n# https://www.npmjs.com/search?q=%40aws-sdk%2Fclient-\n# \n#    Case) @aws-sdk/client-sts\n#    [Import Section](https://www.npmjs.com/package/@aws-sdk/client-sts#getting-started)\n#\n#    Example:\n#    // ES6+ example\n#    import { STSClient, GetCallerIdentityCommand } from \"@aws-sdk/client-sts\";\n#               ^^^ <- This part except for the \"client\"\n#\n# 3. ServiceEndpoint\n# https://docs.aws.amazon.com/general/latest/gr/aws-service-information.html\n#\n#    Case) @aws-sdk/client-sts\n#    [Service endpoints Section](https://docs.aws.amazon.com/general/latest/gr/sts.html#sts_region)\n#\n#    Example:\n#    | Region Name    | Region    | Endpoint                    | Protocol |\n#    | -------------- | --------- | --------------------------- | -------- |\n#    | US East (Ohio) | us-east-2 | sts.us-east-2.amazonaws.com | HTTPS    |\n#                                    ^^^ <- String before \"region\"\n#\n#    If multiple endpoints are required, such as `states` and `sync-states` in @aws-sdk/client-sfn,\n#    multiple endpoints can be specified by making them an array.\n#\n# 4. fullSdkOnly\n#\n#    If you want to bundle only 'full-sdk', specify `1`.\n#    Specify `0` if you want to bundle for both 'std-sdk' and 'full-sdk'.\n#\n#    The combination of SDK_BUNDLE_MODE and fullSdkOnly automatically determines whether the bundle is eligible or not.\n#    Note that if SDK_BUNDLE_MODE is 'NONE', the above values are completely ignored and any SDKs are excluded from the bundle.\n\n# Analytics\nclient-athena,Athena,athena,1\nclient-firehose,Firehose,firehose,1\nclient-glue,Glue,glue,1\nclient-kinesis,Kinesis,kinesis,1\nclient-opensearch,OpenSearch,es,1\nclient-opensearchserverless,OpenSearchServerless,aoss,1\n\n# ApplicationIntegration\nclient-eventbridge,EventBridge,events,0\nclient-scheduler,Scheduler,scheduler,1\nclient-sfn,SFN,states,0\nclient-sns,SNS,sns,0\nclient-sqs,SQS,sqs,0\n\n# BusinessApplications\nclient-ses,SES,email,0\nclient-sesv2,SESv2,email,1\n\n# ComputeServices\nclient-auto-scaling,AutoScaling,autoscaling,1\nclient-batch,Batch,batch,1\nclient-ec2,EC2,ec2,1\nclient-lambda,Lambda,lambda,0\n\n# Containers\nclient-ecr,ECR,api.ecr,1\nclient-ecs,ECS,ecs,1\nclient-eks,EKS,eks,1\nclient-servicediscovery,ServiceDiscovery,discovery,1\n\n# Databases\nclient-dynamodb,DynamoDB,dynamodb,0\nclient-dynamodb-streams,DynamoDBStreams,streams.dynamodb,1\nclient-elasticache,ElastiCache,elasticache,1\nclient-rds,RDS,rds,1\nclient-rds-data,RDSData,rds-data,1\nlib-dynamodb,DynamoDBDocument,dynamodb,0\n\n# DeveloperTools\nclient-xray,XRay,xray,0\n\n# FrontendWebAndMobileServices\nclient-amplify,Amplify,amplify,1\nclient-appsync,AppSync,appsync,1\nclient-location,Location,geo,1\n\n# MachineLearningAndArtificialIntelligence\nclient-bedrock,Bedrock,bedrock,1\nclient-bedrock-agent,BedrockAgent,bedrock-agent,1\nclient-bedrock-runtime,BedrockRuntime,bedrock-runtime,1\nclient-bedrock-agent-runtime,BedrockAgentRuntime,bedrock-agent-runtime,1\nclient-polly,Polly,polly,1\nclient-rekognition,Rekognition,rekognition,1\nclient-textract,Textract,textract,1\nclient-translate,Translate,translate,1\n\n# ManagementAndGovernance\nclient-appconfig,AppConfig,appconfig,1\nclient-appconfigdata,AppConfigData,appconfigdata,1\nclient-cloudformation,CloudFormation,cloudformation,1\nclient-cloudwatch,CloudWatch,monitoring,1\nclient-cloudwatch-logs,CloudWatchLogs,logs,0\nclient-cloudwatch-events,CloudWatchEvents,events,0\nclient-service-catalog,ServiceCatalog,servicecatalog,1\nclient-ssm,SSM,ssm,0\n\n# Media\nclient-mediaconvert,MediaConvert,mediaconvert,1\n\n# NetworkingAndContentDelivery\nclient-api-gateway,APIGateway,apigateway,1\nclient-apigatewayv2,ApiGatewayV2,apigateway,1\nclient-elastic-load-balancing-v2,ElasticLoadBalancingV2,elasticloadbalancing,1\n\n# SecurityIdentityAndCompliance\nclient-acm,ACM,acm,1\nclient-cognito-identity,CognitoIdentity,cognito-identity,0\nclient-cognito-identity-provider,CognitoIdentityProvider,cognito-idp,0\nclient-iam,IAM,iam,1\nclient-kms,KMS,kms,0\nclient-secrets-manager,SecretsManager,secretsmanager,0\nclient-sso,SSO,identitystore,1\nclient-sso-admin,SSOAdmin,identitystore,1\nclient-sso-oidc,SSOOIDC,identitystore,1\nclient-sts,STS,sts,0\nclient-verifiedpermissions,VerifiedPermissions,verifiedpermissions,1\n\n# Storage\nclient-efs,EFS,elasticfilesystem,1\nclient-s3,S3,s3,0\nlib-storage,Upload,s3,0\n"
  },
  {
    "path": "shims/@aws-crypto/crc32.js",
    "content": "import { Crc32 as CryptoCrc32 } from \"node:crypto\";\n\nexport const Crc32 = CryptoCrc32;\n\nexport class AwsCrc32 {\n  #crc32 = new CryptoCrc32();\n\n  update(toHash) {\n    if (isEmptyData(toHash)) return;\n    this.#crc32.update(toHash);\n  }\n\n  async digest() {\n    return numToUint8(this.#crc32.digest());\n  }\n\n  reset() {\n    this.#crc32 = new CryptoCrc32();\n  }\n}\n\nfunction isEmptyData(data) {\n  if (typeof data === \"string\") {\n    return data.length === 0;\n  }\n  return data.byteLength === 0;\n}\n\nfunction numToUint8(num) {\n  return new Uint8Array([\n    (num & 0xff000000) >> 24,\n    (num & 0x00ff0000) >> 16,\n    (num & 0x0000ff00) >> 8,\n    num & 0x000000ff,\n  ]);\n}\n"
  },
  {
    "path": "shims/@aws-crypto/crc32c.js",
    "content": "import { Crc32c as CryptoCrc32c } from \"node:crypto\";\n\nexport const Crc32c = CryptoCrc32c;\n\nexport class AwsCrc32c {\n  #crc32c = new CryptoCrc32c();\n\n  update(toHash) {\n    if (isEmptyData(toHash)) return;\n    this.#crc32c.update(toHash);\n  }\n\n  async digest() {\n    return numToUint8(this.#crc32c.digest());\n  }\n\n  reset() {\n    this.#crc32c = new CryptoCrc32c();\n  }\n}\n\nfunction isEmptyData(data) {\n  if (typeof data === \"string\") {\n    return data.length === 0;\n  }\n  return data.byteLength === 0;\n}\n\nfunction numToUint8(num) {\n  return new Uint8Array([\n    (num & 0xff000000) >> 24,\n    (num & 0x00ff0000) >> 16,\n    (num & 0x0000ff00) >> 8,\n    num & 0x000000ff,\n  ]);\n}\n"
  },
  {
    "path": "shims/@aws-crypto/index.js",
    "content": "export { Sha256, Sha1, Crc32, Crc32c } from \"node:crypto\";\n// export { AwsCrc32 } from \"@aws-crypto/crc32\";\n// export { AwsCrc32c } from \"@aws-crypto/crc32c\";\n"
  },
  {
    "path": "shims/@aws-crypto/sha1-browser.js",
    "content": "export { Sha1 } from \"node:crypto\";\n"
  },
  {
    "path": "shims/@aws-crypto/sha256-browser.js",
    "content": "export { Sha256 } from \"node:crypto\";\n"
  },
  {
    "path": "shims/@smithy/abort-controller.js",
    "content": "// @smithy/abort-controller\n// Since a global object already exists, this module is not required.\n"
  },
  {
    "path": "shims/@smithy/split-stream.js",
    "content": "export async function splitStream(stream) {\n  //stream is blob here\n  const typedArray = await stream.bytes();\n  return [typedArray.subarray(0, 3000), typedArray];\n}\n"
  },
  {
    "path": "shims/@smithy/util-base64.js",
    "content": "export const fromBase64 = (input) => Buffer.from(input, \"base64\");\nexport const toBase64 = (input) => Buffer.from(input).toString(\"base64\");\n"
  },
  {
    "path": "shims/@smithy/util-hex-encoding.js",
    "content": "import { encode, decode } from \"llrt:hex\";\n\nexport const fromHex = decode;\nexport const toHex = encode;\n"
  },
  {
    "path": "shims/@smithy/util-utf8.js",
    "content": "const DECODER = new TextDecoder();\nconst ENCODER = new TextEncoder();\n\nexport const fromUtf8 = (input) => ENCODER.encode(input);\nexport const toUtf8 = (input) => DECODER.decode(input);\n\nexport const toUint8Array = (data) => {\n  if (typeof data === \"string\") {\n    return fromUtf8(data);\n  }\n  if (ArrayBuffer.isView(data)) {\n    return new Uint8Array(\n      data.buffer,\n      data.byteOffset,\n      data.byteLength / Uint8Array.BYTES_PER_ELEMENT\n    );\n  }\n  return new Uint8Array(data);\n};\n"
  },
  {
    "path": "shims/collect-stream-body.js",
    "content": "import { Uint8ArrayBlobAdapter } from \"@smithy/util-stream\";\nexport const collectBody = async (streamBody) =>\n  Uint8ArrayBlobAdapter.mutate(\n    streamBody instanceof Uint8Array\n      ? streamBody\n      : new Uint8Array(await streamBody.arrayBuffer())\n  );\n"
  },
  {
    "path": "shims/create-read-stream.js",
    "content": "export function createReadStreamOnBuffer(buffer) {\n  return buffer;\n}\n"
  },
  {
    "path": "shims/is-streaming.js",
    "content": "export const isStreaming = (body) => false;\n"
  },
  {
    "path": "shims/mnemonist/lru-cache.js",
    "content": "class LRUCache {\n  constructor(capacity = 10) {\n    this.capacity = capacity;\n    this.cache = new Map();\n  }\n\n  get(key) {\n    let item = this.cache.get(key);\n    if (item) {\n      // refresh key\n      this.cache.delete(key);\n      this.cache.set(key, item);\n    }\n    return item;\n  }\n\n  set(key, val) {\n    if (this.cache.has(key)) {\n      this.cache.delete(key);\n    } else if (this.cache.size == this.capacity) {\n      this.cache.delete(this.first());\n    }\n    this.cache.set(key, val);\n  }\n\n  has(key) {\n    return this.cache.has(key);\n  }\n\n  first() {\n    return this.cache.keys().next().value;\n  }\n\n  clear() {\n    this.cache.clear();\n  }\n}\n\nexport default LRUCache;\n"
  },
  {
    "path": "shims/sdk-stream-mixin.js",
    "content": "import { toBase64 } from \"@smithy/util-base64\";\nimport { toHex } from \"@smithy/util-hex-encoding\";\nimport { toUtf8 } from \"@smithy/util-utf8\";\n\nconst transformToWebStream = () => {\n  throw new Error(\"WebStream is not available for LLRT\");\n};\n\nasync function transformToByteArray() {\n  return this.bytes();\n}\n\nasync function transformToString(encoding) {\n  const blob = await this.bytes();\n  if (encoding === \"base64\") {\n    return toBase64(blob);\n  } else if (encoding === \"hex\") {\n    return toHex(blob);\n  }\n  return toUtf8(blob);\n}\n\nexport const sdkStreamMixin = (stream) =>\n  Object.assign(stream, {\n    transformToByteArray,\n    transformToString: transformToString,\n    transformToWebStream,\n  });\n"
  },
  {
    "path": "shims/stream-collector.js",
    "content": "export const streamCollector = async (stream) =>\n  new Uint8Array(await stream.arrayBuffer());\n"
  },
  {
    "path": "shims/string-hasher.js",
    "content": "import { toUint8Array } from \"@smithy/util-utf8\";\nexport const stringHasher = async (checksumAlgorithmFn, body) => {\n  const hash = new checksumAlgorithmFn();\n\n  if (body instanceof Blob) {\n    const arrayBuffer = await body.arrayBuffer();\n    hash.update(arrayBuffer);\n  } else {\n    hash.update(toUint8Array(body || \"\"));\n  }\n\n  return hash.digest();\n};\n"
  },
  {
    "path": "tests/e2e/IntegTestResourcesStack.template.yml",
    "content": "AWSTemplateFormatVersion: \"2010-09-09\"\nDescription: Resources needed for SDK integration test\nResources:\n  IntegTestIdentityPool:\n    Type: AWS::Cognito::IdentityPool\n    Properties:\n      AllowUnauthenticatedIdentities: true\n      CognitoIdentityProviders: []\n      IdentityPoolName: IntegTestIdentityPool\n    Metadata:\n      aws:cdk:path: IntegTestResourcesStack/IntegTestIdentityPool\n  IntegTestIdentityPoolUnauthRole85D387D0:\n    Type: AWS::IAM::Role\n    Properties:\n      AssumeRolePolicyDocument:\n        Statement:\n          - Action: sts:AssumeRoleWithWebIdentity\n            Effect: Allow\n            Principal:\n              Federated: cognito-identity.amazonaws.com\n            Condition:\n              StringEquals:\n                cognito-identity.amazonaws.com:aud:\n                  Ref: IntegTestIdentityPool\n              ForAnyValue:StringLike:\n                cognito-identity.amazonaws.com:amr: unauthenticated\n        Version: \"2012-10-17\"\n      ManagedPolicyArns:\n        - arn:aws:iam::aws:policy/AmazonCognitoReadOnly\n    Metadata:\n      aws:cdk:path: IntegTestResourcesStack/IntegTestIdentityPoolUnauthRole/Resource\n  AttachUnauthRoleToIdentityPool:\n    Type: AWS::Cognito::IdentityPoolRoleAttachment\n    Properties:\n      IdentityPoolId:\n        Ref: IntegTestIdentityPool\n      Roles:\n        unauthenticated:\n          Fn::GetAtt:\n            - IntegTestIdentityPoolUnauthRole85D387D0\n            - Arn\n    Metadata:\n      aws:cdk:path: IntegTestResourcesStack/AttachUnauthRoleToIdentityPool\n  IntegTestBucketA93771AE:\n    Type: AWS::S3::Bucket\n    Properties:\n      CorsConfiguration:\n        CorsRules:\n          - AllowedHeaders:\n              - \"*\"\n            AllowedMethods:\n              - GET\n              - PUT\n              - POST\n              - DELETE\n              - HEAD\n            AllowedOrigins:\n              - \"*\"\n            ExposedHeaders:\n              - ETag\n              - Date\n              - x-amz-request-id\n              - x-amz-id-2\n            MaxAge: 3000\n      BucketEncryption:\n        ServerSideEncryptionConfiguration:\n          - ServerSideEncryptionByDefault:\n              SSEAlgorithm: AES256\n      VersioningConfiguration:\n        Status: Enabled\n    UpdateReplacePolicy: Retain\n    DeletionPolicy: Retain\n    Metadata:\n      aws:cdk:path: IntegTestResourcesStack/IntegTestBucket/Resource\n  MultiRegionAccessPoint:\n    Type: AWS::S3::MultiRegionAccessPoint\n    Properties:\n      Name: v3-sdk-integration-test-001\n      Regions:\n        - Bucket:\n            Ref: IntegTestBucketA93771AE\nOutputs:\n  AwsSmokeTestBucket:\n    Value: !Ref IntegTestBucketA93771AE\n    Export:\n      Name: \"AwsSmokeTestBucket\"\n  AwsSmokeTestMrapArn:\n    Value: !Sub \"arn:aws:s3::${AWS::AccountId}:accesspoint/${MultiRegionAccessPoint.Alias}\"\n    Export:\n      Name: \"AwsSmokeTestMrapArn\"\n  AwsSmokeTestIdentityPoolId:\n    Value: !Ref IntegTestIdentityPool\n    Export:\n      Name: \"AwsSmokeTestIdentityPoolId\"\n"
  },
  {
    "path": "tests/e2e/README.md",
    "content": "## Introduction\n\nThis folder contains integration tests that can be run in the LLRT runtime or in a standard Node.js environment using [vitest](https://vitest.dev/). The tests are designed to be environment-agnostic so that behavior can be compared when running the same code in LLRT versus Node.js.\n\nBy leveraging vitest's integration with Typescript, these tests can easily be executed outside the LLRT runtime. This allows validation that the code functions the same in LLRT as it does in a typical Node.js runtime.\n\nThe goal is to have a suite of integration tests that provide confidence the code will work correctly regardless of whether LLRT or native Node.js is used as the runtime. Running the tests in different environments ensures compatibility and consistent behavior.\n\n## Integration test Prerequisites\n\nCertain resources need to be created to make sure the integration test has backend resources to test against. Follow steps bellow to create them and make them available through env variables:\n\n1. Deploy a CloudFormation stack called `LlrtReleaseIntegTestResourcesStack` using the provided template. This will create the necessary resources for the tests:\n\n   ```shell\n   aws cloudformation deploy --stack-name LLRTReleaseIntegTestResourcesStack --template-file ./IntegTestResourcesStack.template.yml --capabilities CAPABILITY_IAM\n   ```\n\n2. If you have `jq` [installed](https://jqlang.github.io/jq/), you can use the command below to export env variables for ressources that will be used during the E2E tests.\n\n   ```shell\n   $(aws cloudformation describe-stacks --stack-name LLRTReleaseIntegTestResourcesStack --query \"Stacks[*].Outputs[*].{OutputKey: OutputKey, OutputValue: OutputValue}\" | jq -r '.[0][] | \"export \\(.OutputKey|gsub(\"(?<x>(?!^)|\\b[a-zA-Z][a-z]*)(?<y>[A-Z][a-z]*|\\\\d+)\";\"\\(.x)_\\(.y)\")| ascii_upcase )=\\(.OutputValue)\"')\n   ```\n\n   If `jq` is not available, look at the CloudFormation `Outputs` and manually export the variables:\n\n   - AWS_SMOKE_TEST_BUCKET\n   - AWS_SMOKE_TEST_IDENTITY_POOL_ID\n   - AWS_SMOKE_TEST_MRAP_ARN\n\n3. Export your AWS credentials and Region:\n\n   ```shell\n   export AWS_ACCESS_KEY_ID=XXX\n   export AWS_SECRET_ACCESS_KEY=YYY\n   export AWS_REGION=ZZZ\n   ```\n\n4. Run the integration tests:\n\n   This will build and run all integration tests\n\n   ```shell\n   make test-ci\n   ```\n\n   Assuming you already have a binary built for LLRT, this will run a specific integration tests (e.g.: `s3.e2e.test.ts`)\n\n   ```shell\n   make bundle/js/%.js && target/debug/llrt  test s3.e2e.test\n   ```\n"
  },
  {
    "path": "tests/e2e/cognito_identity.e2e.test.ts",
    "content": "// From https://github.com/aws/aws-sdk-js-v3/blob/c8cb4499c6ad19e2b194860d548753f637671f8c/clients/client-cognito-identity/test/e2e/CognitoIdentity.ispec.ts#L6\n\nimport { expect } from \"chai\";\nimport { CognitoIdentity } from \"@aws-sdk/client-cognito-identity\";\n\nconst IdentityPoolId = process?.env?.AWS_SMOKE_TEST_IDENTITY_POOL_ID;\n\ndescribe(\"@aws-sdk/client-cognito-identity\", function () {\n  const unAuthClient = new CognitoIdentity({});\n\n  it(\"should successfully fetch Id and get credentials\", async () => {\n    // Test getId()\n    const getIdResult = await unAuthClient.getId({\n      IdentityPoolId,\n    });\n    expect(getIdResult.$metadata.httpStatusCode).to.equal(200);\n    expect(typeof getIdResult.IdentityId).to.equal(\"string\");\n\n    // Test getCredentialsForIdentity() with Id from above\n    const getCredentialsResult = await unAuthClient.getCredentialsForIdentity({\n      IdentityId: getIdResult.IdentityId,\n    });\n    expect(getCredentialsResult.$metadata.httpStatusCode).to.equal(200);\n    expect(typeof getCredentialsResult.Credentials?.AccessKeyId).to.equal(\n      \"string\"\n    );\n    expect(typeof getCredentialsResult.Credentials?.SecretKey).to.equal(\n      \"string\"\n    );\n  });\n});\n"
  },
  {
    "path": "tests/e2e/dynamodb.e2e.test.ts",
    "content": "// From https://github.com/aws/aws-sdk-js-v3/blob/4c7fe9cf598f7a919ec76114c5b548ceb814fa14/lib/lib-dynamodb/src/test/lib-dynamodb.e2e.spec.ts#L582\n\nimport {\n  BillingMode,\n  CreateTableCommandOutput,\n  DeleteItemCommandOutput,\n  DescribeTableCommandOutput,\n  DynamoDB,\n  GetItemCommandOutput,\n  waitUntilTableExists,\n} from \"@aws-sdk/client-dynamodb\";\nimport {\n  BatchExecuteStatementCommandOutput,\n  BatchGetCommandOutput,\n  BatchWriteCommandOutput,\n  DynamoDBDocument,\n  ExecuteStatementCommandOutput,\n  ExecuteTransactionCommandOutput,\n  GetCommandOutput,\n  NumberValue,\n  PutCommandOutput,\n  QueryCommandOutput,\n  ScanCommandOutput,\n  TransactGetCommandOutput,\n  TransactWriteCommandOutput,\n  UpdateCommandOutput,\n} from \"@aws-sdk/lib-dynamodb\";\n\n// expected running time: table creation (~20s) + operations 10s\n// vi.setTimeout(180000);\n\ndescribe(DynamoDBDocument.name, () => {\n  const dynamodb = new DynamoDB({ maxAttempts: 10 });\n  const doc = DynamoDBDocument.from(dynamodb, {\n    marshallOptions: {\n      convertTopLevelContainer: true,\n    },\n    unmarshallOptions: {\n      wrapNumbers: true,\n    },\n  });\n\n  function throwIfError(e: unknown) {\n    if (e instanceof Error) {\n      throw e;\n    }\n  }\n\n  // Tables will be dropped at the end of the test.\n  // For faster test development, remove this random suffix and\n  // don't delete the table in afterAll().\n  // The table will in that case be re-used.\n  const randId = (Math.random() + 1).toString(36).substring(2, 6);\n  const timestamp = (Date.now() / 1000) | 0;\n\n  const TableName = `js-sdk-dynamodb-test-${timestamp}-${randId}`;\n\n  const log = {\n    describe: null as null | DescribeTableCommandOutput,\n    create: null as null | CreateTableCommandOutput,\n    write: {} as Record<string, PutCommandOutput>,\n    read: {} as Record<string, GetCommandOutput>,\n    undefinedColumnWrite: null as null | PutCommandOutput,\n    undefinedColumnRead: null as null | GetCommandOutput,\n    batchWrite: null as null | BatchWriteCommandOutput,\n    batchRead: null as null | BatchGetCommandOutput,\n    transactWrite: null as null | TransactWriteCommandOutput,\n    transactRead: null as null | TransactGetCommandOutput,\n    executeTransaction: null as null | ExecuteTransactionCommandOutput,\n    executeTransactionReadBack: {} as Record<string, GetItemCommandOutput>,\n    executeStatement: {} as Record<string, ExecuteStatementCommandOutput>,\n    executeStatementReadBack: {} as Record<string, GetItemCommandOutput>,\n    batchExecuteStatement: null as null | BatchExecuteStatementCommandOutput,\n    batchExecuteStatementReadBack:\n      null as null | BatchExecuteStatementCommandOutput,\n    query: null as null | QueryCommandOutput,\n    scan: null as null | ScanCommandOutput,\n    update: {} as Record<string, UpdateCommandOutput>,\n    updateReadBack: {} as Record<string, GetCommandOutput>,\n    delete: {} as Record<string, DeleteItemCommandOutput>,\n  };\n\n  const data = {\n    null: null,\n    string: \"myString\",\n    number: NumberValue.from(1),\n    bigInt: NumberValue.from(\n      \"10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"\n    ),\n    bigNumber: NumberValue.from(\"3210000000000000000.0000000000000123\"),\n    boolean: true,\n    sSet: new Set([\"my\", \"string\", \"set\"]),\n    nSet: new Set([2, 3, 4].map(NumberValue.from)),\n    list: [\n      null,\n      \"myString\",\n      NumberValue.from(1),\n      true,\n      new Set([\"my\", \"string\", \"set\"]),\n      new Set([NumberValue.from(2), NumberValue.from(3), NumberValue.from(4)]),\n      new Set([\n        NumberValue.from(\"3210000000000000000.0000000000000123\"),\n        NumberValue.from(\"3210000000000000001.0000000000000123\"),\n        NumberValue.from(\"3210000000000000002.0000000000000123\"),\n      ]),\n      [\"listInList\", NumberValue.from(1), null],\n      {\n        mapInList: \"mapInList\",\n      },\n    ],\n    map: {\n      null: null,\n      string: \"myString\",\n      number: NumberValue.from(1),\n      boolean: true,\n      sSet: new Set([\"my\", \"string\", \"set\"]),\n      nSet: new Set([2, 3, 4].map(NumberValue.from)),\n      listInMap: [\"listInMap\", NumberValue.from(1), null],\n      mapInMap: { mapInMap: \"mapInMap\" },\n    },\n  };\n\n  const updateTransform = <T>(input: T): T => {\n    switch (typeof input) {\n      case \"object\":\n        if (input === null) {\n          return null as T;\n        }\n        if (Array.isArray(input)) {\n          return input.map(updateTransform) as T;\n        }\n        if (input instanceof Set) {\n          return new Set([...input].map(updateTransform)) as T;\n        }\n        if (input instanceof NumberValue) {\n          return NumberValue.from(input.toString()) as T;\n        }\n        return Object.entries(input).reduce((acc, [k, v]) => {\n          // @ts-ignore\n          acc[updateTransform(k)] = updateTransform(v);\n          return acc;\n        }, {}) as T;\n      case \"boolean\":\n        return !input as T;\n      case \"number\":\n        return (input + 1) as T;\n      case \"string\":\n        return (input + \"-x\") as T;\n    }\n    return input;\n  };\n\n  const passError = (e: any) => e;\n\n  beforeAll(async () => {\n    log.describe = await dynamodb\n      .describeTable({\n        TableName,\n      })\n      .catch((e) => {\n        return null;\n      });\n    if (!log.describe?.Table) {\n      log.create = await dynamodb\n        .createTable({\n          TableName,\n          AttributeDefinitions: [\n            {\n              AttributeName: \"id\",\n              AttributeType: \"S\",\n            },\n          ],\n          KeySchema: [\n            {\n              AttributeName: \"id\",\n              KeyType: \"HASH\",\n            },\n          ],\n          BillingMode: BillingMode.PAY_PER_REQUEST,\n        })\n        .catch(passError);\n      await waitUntilTableExists(\n        { client: dynamodb, maxWaitTime: 120 },\n        {\n          TableName,\n        }\n      );\n    }\n\n    for (const [id, value] of [[\"1\", data as any], ...Object.entries(data)]) {\n      log.write[id] = await doc\n        .put({\n          TableName,\n          Item: {\n            id,\n            data: value,\n          },\n        })\n        .catch(passError);\n\n      log.read[id] = await doc\n        .get({\n          ConsistentRead: true,\n          TableName,\n          Key: {\n            id,\n          },\n        })\n        .catch(passError);\n    }\n\n    log.batchWrite = await doc\n      .batchWrite({\n        RequestItems: {\n          [TableName]: [\n            ...Object.entries(data).map(([k, v]) => {\n              return {\n                PutRequest: {\n                  Item: {\n                    id: k + \"-batch\",\n                    data: v,\n                  },\n                },\n              };\n            }),\n          ],\n        },\n      })\n      .catch(passError);\n\n    log.batchRead = await doc\n      .batchGet({\n        RequestItems: {\n          [TableName]: {\n            Keys: [\n              ...Object.keys(data).map((key) => {\n                return { id: key + \"-batch\" };\n              }),\n            ],\n          },\n        },\n      })\n      .catch(passError);\n\n    log.transactWrite = await doc\n      .transactWrite({\n        TransactItems: [\n          ...Object.entries(data).map(([k, v]) => {\n            return {\n              Put: {\n                TableName,\n                Key: {\n                  id: k + \"-transact\",\n                },\n                Item: {\n                  id: k + \"-transact\",\n                  data: v,\n                },\n              },\n            };\n          }),\n        ],\n      })\n      .catch(passError);\n\n    log.transactRead = await doc\n      .transactGet({\n        TransactItems: [\n          ...Object.keys(data).map((k) => {\n            return {\n              Get: {\n                TableName,\n                Key: {\n                  id: k + \"-transact\",\n                },\n              },\n            };\n          }),\n        ],\n      })\n      .catch(passError);\n\n    log.executeTransaction = await doc\n      .executeTransaction({\n        TransactStatements: [\n          ...Object.entries(data).map(([k, v]) => {\n            return {\n              Statement: `INSERT INTO \"${TableName}\" value {'id':?,'data':?}`,\n              Parameters: [k + \"-exec-transact\", v],\n            };\n          }),\n        ],\n      })\n      .catch(passError);\n    for (const [k] of Object.entries(data)) {\n      log.executeTransactionReadBack[k] = await doc\n        .get({\n          ConsistentRead: true,\n          TableName,\n          Key: {\n            id: k + \"-exec-transact\",\n          },\n        })\n        .catch(passError);\n    }\n\n    for (const [k, v] of Object.entries(data)) {\n      log.executeStatement[k] = await doc\n        .executeStatement({\n          Statement: `INSERT INTO \"${TableName}\" value {'id':?,'data':?}`,\n          Parameters: [k + \"-statement\", v],\n        })\n        .catch(passError);\n    }\n    for (const [k] of Object.entries(data)) {\n      log.executeStatementReadBack[k] = await doc\n        .get({\n          ConsistentRead: true,\n          TableName,\n          Key: {\n            id: k + \"-statement\",\n          },\n        })\n        .catch(passError);\n    }\n\n    log.batchExecuteStatement = await doc\n      .batchExecuteStatement({\n        Statements: [\n          ...Object.entries(data).map(([k, v]) => {\n            return {\n              Statement: `INSERT INTO \"${TableName}\" value {'id':?,'data':?}`,\n              Parameters: [k + \"-batch-statement\", v],\n            };\n          }),\n        ],\n      })\n      .catch(passError);\n\n    log.batchExecuteStatementReadBack = await doc\n      .batchExecuteStatement({\n        Statements: [\n          ...Object.entries(data).map(([k, v]) => {\n            return {\n              Statement: `SELECT * FROM ${TableName} WHERE \"id\" = ?`,\n              Parameters: [k + \"-batch-statement\"],\n            };\n          }),\n        ],\n      })\n      .catch(passError);\n\n    log.query = await doc\n      .query({\n        TableName,\n        KeyConditionExpression: `id = :id`,\n        ExpressionAttributeValues: {\n          \":id\": \"map\",\n        },\n        ConsistentRead: true,\n      })\n      .catch(passError);\n\n    log.scan = await doc\n      .scan({\n        TableName,\n        FilterExpression: `#data = :data1 OR #data = :data2`,\n        ExpressionAttributeNames: {\n          \"#data\": \"data\",\n        },\n        ExpressionAttributeValues: {\n          \":data1\": data.list,\n          \":data2\": data.map,\n        },\n        ConsistentRead: true,\n      })\n      .catch(passError);\n\n    log.undefinedColumnWrite = await doc\n      .put({\n        TableName,\n        Item: {\n          id: \"undefinedColumns\",\n          A: \"A\",\n          B: undefined,\n          C: \"C\",\n          D: undefined,\n          E: \"E\",\n        },\n      })\n      .catch(passError);\n\n    log.undefinedColumnRead = await doc\n      .get({\n        TableName,\n        Key: {\n          id: \"undefinedColumns\",\n        },\n        ConsistentRead: true,\n      })\n      .catch(passError);\n\n    for (const [id, value] of [[\"1\", data as any], ...Object.entries(data)]) {\n      log.update[id] = await doc\n        .update({\n          TableName,\n          Key: {\n            id,\n          },\n          AttributeUpdates: {\n            data: {\n              Action: \"PUT\",\n              Value: updateTransform(value),\n            },\n          },\n        })\n        .catch(passError);\n\n      log.updateReadBack[id] = await doc\n        .get({\n          ConsistentRead: true,\n          TableName,\n          Key: {\n            id,\n          },\n        })\n        .catch(passError);\n\n      log.delete[id] = await (async () => {\n        for (const suffix of [\n          \"-batch\",\n          \"-transact\",\n          \"-exec-transact\",\n          \"-statement\",\n          \"-batch-statement\",\n        ]) {\n          doc\n            .delete({\n              TableName,\n              Key: {\n                id: id + suffix,\n              },\n            })\n            .catch(() => {});\n        }\n        return doc.delete({\n          TableName,\n          Key: { id },\n        });\n      })().catch(passError);\n    }\n  }, 60000);\n\n  afterAll(async () => {\n    await dynamodb.deleteTable({\n      TableName,\n    });\n  }, 30000);\n\n  describe(\"updateTransformFunction\", () => {\n    it(\"modifies all fields of an object\", () => {\n      expect(updateTransform(data)).toEqual({\n        \"null-x\": null,\n        \"string-x\": \"myString-x\",\n        \"number-x\": NumberValue.from(1),\n        \"bigInt-x\": NumberValue.from(\n          \"10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"\n        ),\n        \"bigNumber-x\": NumberValue.from(\"3210000000000000000.0000000000000123\"),\n        \"boolean-x\": false,\n        \"sSet-x\": new Set([\"my-x\", \"string-x\", \"set-x\"]),\n        \"nSet-x\": new Set([2, 3, 4].map(NumberValue.from)),\n        \"list-x\": [\n          null,\n          \"myString-x\",\n          NumberValue.from(1),\n          false,\n          new Set([\"my-x\", \"string-x\", \"set-x\"]),\n          new Set([2, 3, 4].map(NumberValue.from)),\n          new Set([\n            NumberValue.from(\"3210000000000000000.0000000000000123\"),\n            NumberValue.from(\"3210000000000000001.0000000000000123\"),\n            NumberValue.from(\"3210000000000000002.0000000000000123\"),\n          ]),\n          [\"listInList-x\", NumberValue.from(1), null],\n          { \"mapInList-x\": \"mapInList-x\" },\n        ],\n        \"map-x\": {\n          \"null-x\": null,\n          \"string-x\": \"myString-x\",\n          \"number-x\": NumberValue.from(1),\n          \"boolean-x\": false,\n          \"sSet-x\": new Set([\"my-x\", \"string-x\", \"set-x\"]),\n          \"nSet-x\": new Set([2, 3, 4].map(NumberValue.from)),\n          \"listInMap-x\": [\"listInMap-x\", NumberValue.from(1), null],\n          \"mapInMap-x\": { \"mapInMap-x\": \"mapInMap-x\" },\n        },\n      });\n    });\n  });\n\n  it(\"initializes using the static constructor\", async () => {\n    expect(doc).toBeInstanceOf(DynamoDBDocument);\n  });\n\n  it(`is using a random TableName=${TableName}`, async () => {\n    // to report the table name\n  });\n\n  it(\"describes the test table\", async () => {\n    if (log.describe) {\n      expect(log.describe?.Table?.TableName).toEqual(TableName);\n    }\n  });\n\n  it(\"creates the test table if it does not exist\", async () => {\n    if (log.describe) {\n      throwIfError(log.describe);\n      expect(log.describe?.Table?.TableName).toEqual(TableName);\n    } else {\n      throwIfError(log.create);\n      expect(log.create?.TableDescription?.TableName).toEqual(TableName);\n    }\n  });\n\n  it(\"ignores undefined column values for backwards compatibility\", async () => {\n    throwIfError(log.undefinedColumnWrite);\n\n    expect(log.undefinedColumnRead?.Item).toEqual({\n      id: \"undefinedColumns\",\n      A: \"A\",\n      C: \"C\",\n      E: \"E\",\n    });\n  });\n\n  it(\"can batch write\", async () => {\n    throwIfError(log.batchWrite);\n  });\n\n  it(\"can batch read\", async () => {\n    throwIfError(log.batchRead);\n    const results = log.batchRead?.Responses?.[TableName] ?? [];\n\n    for (const result of results) {\n      // @ts-ignore\n      expect(result.data).toEqual(data[result.id.replace(\"-batch\", \"\")]);\n    }\n  });\n\n  it(\"can transact write\", async () => {\n    throwIfError(log.transactWrite);\n  });\n\n  it(\"can transact read\", async () => {\n    throwIfError(log.transactRead);\n    const results = log.transactRead?.Responses ?? [];\n\n    for (const result of results) {\n      // @ts-ignore\n      expect(result.Item?.data).toEqual(\n        data[result.Item?.id.replace(\"-transact\", \"\")]\n      );\n    }\n  });\n\n  it(\"can execute transactions\", async () => {\n    throwIfError(log.executeTransaction);\n  });\n\n  it(\"can batch execute statements\", async () => {\n    throwIfError(log.batchExecuteStatement);\n\n    expect(log.batchExecuteStatementReadBack?.Responses).toBeInstanceOf(Array);\n    expect(\n      log.batchExecuteStatementReadBack?.Responses?.length\n    ).toBeGreaterThan(0);\n    for (const response of log.batchExecuteStatementReadBack?.Responses ?? []) {\n      // @ts-ignore\n      expect(response.Item?.data).toEqual(\n        data[response.Item?.id?.replace(\"-batch-statement\", \"\")]\n      );\n    }\n  });\n\n  it(\"can query\", async () => {\n    throwIfError(log.query);\n    expect(log.query?.Items).toContainEqual({\n      id: \"map\",\n      data: data.map,\n    });\n  });\n\n  it(\"can scan\", async () => {\n    throwIfError(log.scan);\n    expect(log.scan?.Items).toContainEqual({\n      id: \"map\",\n      data: data.map,\n    });\n\n    expect(log.scan?.Items).toContainEqual({\n      id: \"list\",\n      data: data.list,\n    });\n  });\n\n  for (const [key, value] of Object.entries(data)) {\n    it(`can write data of type ${key}`, async () => {\n      throwIfError(log.write[key]);\n      expect(log.write[key].$metadata).toBeDefined();\n    });\n\n    it(`can execute statement inserting type ${key}`, async () => {\n      const match = log.executeStatement[key];\n      expect(match).toBeDefined();\n\n      throwIfError(match);\n    });\n\n    it(`can read back data inserted via ExecuteStatement of type ${key}`, async () => {\n      throwIfError(log.executeStatementReadBack[key]);\n      expect(log.executeStatementReadBack[key].Item).toEqual({\n        id: key + \"-statement\",\n        data: value,\n      });\n    });\n\n    it(`can read back data inserted via ExecuteTransaction of type ${key}`, async () => {\n      throwIfError(log.executeTransactionReadBack[key]);\n      expect(log.executeTransactionReadBack[key].Item).toEqual({\n        id: key + \"-exec-transact\",\n        data: value,\n      });\n    });\n\n    it(`can read data of type ${key}`, async () => {\n      throwIfError(log.read[key]);\n      expect(log.read[key].Item).toEqual({\n        id: key,\n        data: value,\n      });\n    });\n\n    it(`can update data of type ${key}`, async () => {\n      throwIfError(log.updateReadBack[key]);\n      expect(log.updateReadBack[key].Item).toEqual({\n        id: key,\n        data: updateTransform(value),\n      });\n    });\n\n    it(`can delete data of type ${key}`, async () => {\n      throwIfError(log.delete[key]);\n      expect(log.delete[key].$metadata).toBeDefined();\n    });\n  }\n});\n"
  },
  {
    "path": "tests/e2e/s3.e2e.test.ts",
    "content": "// From https://github.com/aws/aws-sdk-js-v3/blob/89f97b5cea8052510471cdad69acced9f5be60d1/clients/client-s3/test/e2e/S3.e2e.spec.ts#L15\n\nimport { S3, SelectObjectContentEventStream } from \"@aws-sdk/client-s3\";\nconst Bucket = process?.env?.AWS_SMOKE_TEST_BUCKET;\nconst mrapArn = process?.env?.AWS_SMOKE_TEST_MRAP_ARN;\n\nlet Key = `${Date.now()}`;\n\ndescribe(\"@aws-sdk/client-s3\", () => {\n  const client = new S3();\n\n  // TODO Stream is not yet supported\n  describe.skip(\"PutObject\", () => {\n    beforeAll(() => {\n      Key = `${Date.now()}`;\n    });\n    afterAll(async () => {\n      await client.deleteObject({ Bucket, Key });\n    });\n    it(\"should succeed with Node.js readable stream body\", async () => {\n      const length = 10 * 1000; // 10KB\n      const chunkSize = 10;\n      const { Readable } = require(\"stream\");\n      let sizeLeft = length;\n      const inputStream = new Readable({\n        read() {\n          if (sizeLeft <= 0) {\n            this.push(null); //end stream;\n            return;\n          }\n          let chunk = \"\";\n          for (let i = 0; i < Math.min(sizeLeft, chunkSize); i++) {\n            chunk += \"x\";\n          }\n          this.push(chunk);\n          sizeLeft -= chunk.length;\n        },\n      });\n      inputStream.size = length; // This is required\n      const result = await client.putObject({\n        Bucket,\n        Key,\n        Body: inputStream,\n      });\n      expect(result.$metadata.httpStatusCode).toEqual(200);\n    });\n  });\n\n  describe(\"GetObject\", function () {\n    beforeAll(async () => {\n      Key = `${Date.now()}`;\n    });\n\n    afterAll(async () => {\n      await client.deleteObject({ Bucket, Key });\n    });\n\n    it(\"should succeed with valid body payload\", async () => {\n      // prepare the object.\n      const body = createBuffer(1024 * 1024);\n\n      try {\n        await client.putObject({ Bucket, Key, Body: body.text });\n      } catch (e) {\n        console.error(\"failed to put\");\n        throw e;\n      }\n\n      try {\n        // eslint-disable-next-line no-var\n        var result = await client.getObject({ Bucket, Key });\n        // or 'transformToByteArray()'\n        const text = await result.Body.transformToString();\n        expect(text).toEqual(body.text);\n      } catch (e) {\n        console.error(\"failed to get\");\n        throw e;\n      }\n\n      let actual = result.$metadata.httpStatusCode;\n      expect(actual).toEqual(200);\n    });\n  });\n\n  // TODO FB Open a bug\n  describe(\"ListObjects\", () => {\n    beforeAll(async () => {\n      Key = `${Date.now()}`;\n      await client.putObject({ Bucket, Key, Body: \"foo\" });\n    });\n    afterAll(async () => {\n      await client.deleteObject({ Bucket, Key });\n    });\n    it(\"should succeed with valid bucket\", async () => {\n      const result = await client.listObjects({\n        Bucket,\n      });\n      expect(result.$metadata.httpStatusCode).toEqual(200);\n      expect(result.Contents instanceof Array).toEqual(true);\n    });\n\n    it(\"should throw with invalid bucket\", async () => {\n      try {\n        await client.listObjects({ Bucket: \"invalid-bucket\" });\n        assert(false, \"Should throw an exception\");\n      } catch (ignored) {\n        console.log(\"Exception should be thrown\");\n      }\n    });\n  });\n\n  describe(\"MultipartUpload\", () => {\n    let UploadId: string;\n    let Etag: string;\n    const multipartObjectKey = `${Key}-multipart`;\n    beforeAll(() => {\n      Key = `${Date.now()}`;\n    });\n    afterEach(async () => {\n      if (UploadId) {\n        await client.abortMultipartUpload({\n          Bucket,\n          Key: multipartObjectKey,\n          UploadId,\n        });\n      }\n      await client.deleteObject({\n        Bucket,\n        Key: multipartObjectKey,\n      });\n    });\n\n    it(\"should successfully create, upload list and complete\", async () => {\n      //create multipart upload\n      const createResult = await client.createMultipartUpload({\n        Bucket,\n        Key: multipartObjectKey,\n      });\n      expect(createResult.$metadata.httpStatusCode).toEqual(200);\n      expect(typeof createResult.UploadId).toEqual(\"string\");\n      UploadId = createResult.UploadId as string;\n\n      //upload part\n      const uploadResult = await client.uploadPart({\n        Bucket,\n        Key: multipartObjectKey,\n        UploadId,\n        PartNumber: 1,\n        Body: createBuffer(1024).buffer,\n      });\n      expect(uploadResult.$metadata.httpStatusCode).toEqual(200);\n      expect(typeof uploadResult.ETag).toEqual(\"string\");\n      Etag = uploadResult.ETag as string;\n\n      //list parts\n      const listPartsResult = await client.listParts({\n        Bucket,\n        Key: multipartObjectKey,\n        UploadId,\n      });\n      expect(listPartsResult.$metadata.httpStatusCode).toEqual(200);\n      expect(listPartsResult.Parts?.length).toEqual(1);\n\n      console.error(\"====\", { a: listPartsResult.Parts?.[0].ETag, b: Etag });\n\n      expect(listPartsResult.Parts?.[0].ETag).toEqual(Etag);\n\n      //complete multipart upload // TODO FB bug here\n      const completeResult = await client.completeMultipartUpload({\n        Bucket,\n        Key: multipartObjectKey,\n        UploadId,\n        MultipartUpload: { Parts: [{ ETag: Etag, PartNumber: 1 }] },\n      });\n      expect(completeResult.$metadata.httpStatusCode).toEqual(200);\n\n      //validate the object is uploaded\n      const headResult = await client.headObject({\n        Bucket,\n        Key: multipartObjectKey,\n      });\n      expect(headResult.$metadata.httpStatusCode).toEqual(200);\n    });\n\n    it(\"should successfully create, abort, and list upload\", async () => {\n      //create multipart upload\n      const createResult = await client.createMultipartUpload({\n        Bucket,\n        Key: multipartObjectKey,\n      });\n      expect(createResult.$metadata.httpStatusCode).toEqual(200);\n      const toAbort = createResult.UploadId;\n      expect(typeof toAbort).toEqual(\"string\");\n\n      //abort multipart upload\n      const abortResult = await client.abortMultipartUpload({\n        Bucket,\n        Key: multipartObjectKey,\n        UploadId: toAbort,\n      });\n      expect(abortResult.$metadata.httpStatusCode).toEqual(204);\n\n      //validate multipart upload is aborted // TODO FB bug here\n      const listUploadsResult = await client.listMultipartUploads({\n        Bucket,\n      });\n      expect(listUploadsResult.$metadata.httpStatusCode).toEqual(200);\n      expect(\n        (listUploadsResult.Uploads || []).map((upload) => upload.UploadId)\n      ).not.toContain(toAbort);\n    });\n  });\n\n  // TODO Stream is not yet supported\n  describe.skip(\"selectObjectContent\", () => {\n    const csvFile = `user_name,age\njsrocks,13\nnode4life,22\nesfuture,29`;\n    beforeAll(async () => {\n      Key = `${Date.now()}`;\n      await client.putObject({ Bucket, Key, Body: csvFile });\n    });\n    afterAll(async () => {\n      await client.deleteObject({ Bucket, Key });\n    });\n    it(\"should succeed\", async () => {\n      const { Payload } = await client.selectObjectContent({\n        Bucket,\n        Key,\n        ExpressionType: \"SQL\",\n        Expression:\n          \"SELECT user_name FROM S3Object WHERE cast(age as int) > 20\",\n        InputSerialization: {\n          CSV: {\n            FileHeaderInfo: \"USE\",\n            RecordDelimiter: \"\\n\",\n            FieldDelimiter: \",\",\n          },\n        },\n        OutputSerialization: {\n          CSV: {},\n        },\n      });\n\n      const events: SelectObjectContentEventStream[] = [];\n      for await (const event of Payload!) {\n        events.push(event);\n      }\n      expect(events.length).toEqual(3);\n      expect(new TextDecoder().decode(events[0].Records?.Payload)).toEqual(\n        \"node4life\\nesfuture\\n\"\n      );\n      // expect(events[1].Stats?.Details).toBeDefined();\n      // expect(events[2].End).toBeDefined();\n    });\n  });\n\n  describe.skip(\"Multi-region access point\", () => {\n    // TODO FB\n    beforeAll(async () => {\n      Key = `${Date.now()}`;\n      await client.putObject({ Bucket: mrapArn, Key, Body: \"foo\" });\n    });\n    afterAll(async () => {\n      await client.deleteObject({ Bucket: mrapArn, Key });\n    });\n    it(\"should succeed with valid MRAP ARN\", async () => {\n      const result = await client.listObjects({\n        Bucket: mrapArn,\n      });\n      expect(result.$metadata.httpStatusCode).toEqual(200);\n      expect(result.Contents instanceof Array).toEqual(true);\n    });\n  });\n});\n\nexport const createBuffer = (bytes: number) => {\n  const byteArray = new Uint8Array(bytes).fill(0x78);\n  return {\n    buffer: byteArray,\n    text: new TextDecoder().decode(byteArray),\n  };\n};\n"
  },
  {
    "path": "tests/unit/assert.test.ts",
    "content": "import defaultImport from \"node:assert\";\nimport legacyImport from \"assert\";\n\nimport assert from \"node:assert\";\n\nit(\"node:assert should be the same as assert\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n\nconst { ok } = defaultImport;\n\ndescribe(`ok`, () => {\n  it(\"Should be returned 'undefined' (So it's not an error)\", () => {\n    expect(ok(true)).toBeUndefined(); //bool\n    expect(ok(1)).toBeUndefined(); // numeric\n    expect(ok(\"non-empty string\")).toBeUndefined(); // string\n    expect(ok([])).toBeUndefined(); // array\n    expect(ok({})).toBeUndefined(); // object\n    expect(ok(() => {})).toBeUndefined(); // function\n    expect(ok(123n)).toBeUndefined(); // bigint\n    expect(ok(Symbol())).toBeUndefined(); // symbol\n    expect(ok(new Error())).toBeUndefined(); // error\n    class AssertTestClass {}\n    expect(ok(AssertTestClass)).toBeUndefined(); // constructor\n  });\n\n  it(\"Should be returned exception\", () => {\n    const errMsg =\n      \"AssertionError: The expression was evaluated to a falsy value\";\n    expect(() => ok(false)).toThrow(errMsg);\n    expect(() => ok(0)).toThrow(errMsg);\n    expect(() => ok(\"\")).toThrow(errMsg);\n    expect(() => ok(null)).toThrow(errMsg);\n  });\n\n  it(\"should be returned as original error message\", () => {\n    const errMsg = \"Error: Value must be true\";\n    expect(() => ok(false, errMsg)).toThrow(errMsg);\n  });\n\n  it(\"should be returned as original error\", () => {\n    const errMsg = \"Error: This is error\";\n    expect(() => ok(false, Error(errMsg))).toThrow(errMsg);\n  });\n\n  it(\"Should be handled correctly even within functions\", () => {\n    const errMsg = \"Error: Value should be truthy\";\n    function checkValue(value) {\n      ok(value, errMsg);\n    }\n    expect(checkValue(true)).toBeUndefined();\n    expect(() => checkValue(false)).toThrow(errMsg);\n  });\n});\n\nit(\"Should be returned 'undefined' (So it's not an error)\", () => {\n  expect(assert(true)).toBeUndefined();\n  expect(assert(1)).toBeUndefined();\n  expect(assert(\"non-empty string\")).toBeUndefined();\n  expect(assert([])).toBeUndefined();\n  expect(assert({})).toBeUndefined();\n});\n"
  },
  {
    "path": "tests/unit/async_hooks.test.ts",
    "content": "import defaultImport from \"node:async_hooks\";\nimport legacyImport from \"async_hooks\";\n\nit(\"node:async_hooks should be the same as async_hooks\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n\nconst { createHook } = defaultImport;\n\nlet counters = {\n  init: 0,\n  before: 0,\n  after: 0,\n  promiseResolve: 0,\n  destroy: 0,\n};\n\ncreateHook({\n  init(asyncId, type, triggerAsyncId) {\n    counters.init++;\n  },\n  before(asyncId) {\n    counters.before++;\n  },\n  after(asyncId) {\n    counters.after++;\n  },\n  promiseResolve(asyncId) {\n    counters.promiseResolve++;\n  },\n  destroy(asyncId) {\n    counters.destroy++;\n  },\n}).enable();\n\nit(\"should track async operations\", async () => {\n  await new Promise((resolve) => setTimeout(resolve, 10));\n\n  // It detects asynchronous operations in all tests that run simultaneously,\n  // making it impossible to test them individually.\n  // Therefore, here we only check whether asynchronous operations can be tracked.\n  expect(counters.init).toBeGreaterThan(0);\n  expect(counters.before).toBeGreaterThan(0);\n  expect(counters.after).toBeGreaterThan(0);\n  expect(counters.promiseResolve).toBeGreaterThan(0);\n\n  // destroy callbacks require GC + event loop tick to fire reliably\n  __gc();\n  await new Promise((resolve) => setTimeout(resolve, 1));\n  expect(counters.destroy).toBeGreaterThan(0);\n});\n"
  },
  {
    "path": "tests/unit/asynchronous-processing-discipline.test.ts",
    "content": "const CWD = process.cwd();\n\nasync function waitAndExpectSequentialNumbers(tracked, delayMs) {\n  await new Promise((resolve) => {\n    setTimeout(() => {\n      expect(tracked).toEqual(\n        Array.from({ length: tracked.length }, (_, i) => i + 1)\n      );\n      resolve();\n    }, delayMs);\n  });\n}\n\ndescribe(\"Execution order of synchronous and asynchronous processes\", () => {\n  it(\"Synchronous operations have priority over microtasks.\", async () => {\n    const tracked = [];\n\n    queueMicrotask(() => tracked.push(2));\n    tracked.push(1);\n\n    await waitAndExpectSequentialNumbers(tracked, 10);\n  });\n\n  it(\"Synchronous operations have priority over macrotasks.\", async () => {\n    const tracked = [];\n\n    setTimeout(() => tracked.push(2));\n    tracked.push(1);\n\n    await waitAndExpectSequentialNumbers(tracked, 10);\n  });\n\n  it(\"Microtasks are executed in the order they are registered.\", async () => {\n    const tracked = [];\n\n    Promise.resolve().then(() => tracked.push(1));\n    queueMicrotask(() => tracked.push(2));\n\n    await waitAndExpectSequentialNumbers(tracked, 10);\n  });\n\n  it(\"When a microtask occurs within a microtask, it is placed at the end of the accumulated microtasks.\", async () => {\n    const tracked = [];\n\n    Promise.resolve().then(() => {\n      tracked.push(1);\n      queueMicrotask(() => tracked.push(3));\n    });\n    queueMicrotask(() => tracked.push(2));\n\n    await waitAndExpectSequentialNumbers(tracked, 10);\n  });\n\n  it(\"If a macrotask and a microtask are registered at the same time, the microtask will take priority.\", async () => {\n    const tracked = [];\n\n    setTimeout(() => tracked.push(3));\n    Promise.resolve().then(() => tracked.push(1));\n    queueMicrotask(() => tracked.push(2));\n\n    await waitAndExpectSequentialNumbers(tracked, 10);\n  });\n\n  it(\"Macro tasks with different scheduled firing times are executed in the order of their scheduled firing times.\", async () => {\n    const tracked = [];\n\n    setTimeout(() => tracked.push(3), 20);\n    setTimeout(() => tracked.push(2), 10);\n    setTimeout(() => tracked.push(1));\n\n    await waitAndExpectSequentialNumbers(tracked, 30);\n  });\n\n  it(\"If a microtask occurs within a macrotask, all microtasks are executed before the next macrotask is executed.\", async () => {\n    const tracked = [];\n\n    setTimeout(() => {\n      tracked.push(1);\n      queueMicrotask(() => tracked.push(2));\n      queueMicrotask(() => tracked.push(3));\n    });\n    setTimeout(() => tracked.push(4));\n\n    await waitAndExpectSequentialNumbers(tracked, 10);\n  });\n\n  it(\"When a new macrotask occurs among the macrotasks, it is placed at the end of the accumulated macrotasks.\", async () => {\n    const tracked = [];\n\n    setTimeout(() => {\n      tracked.push(1);\n      setTimeout(() => tracked.push(3));\n    });\n    setTimeout(() => tracked.push(2));\n\n    await waitAndExpectSequentialNumbers(tracked, 10);\n  });\n});\n\ndescribe(\"Asynchronous Microtask Function\", () => {\n  it(\"If an asynchronous microtask function does not contain an await, it is executed entirely at the time of function registration.\", async () => {\n    const tracked = [];\n\n    async function microTaskFunction() {\n      tracked.push(1);\n    }\n\n    microTaskFunction();\n    tracked.push(2);\n\n    await waitAndExpectSequentialNumbers(tracked, 10);\n  });\n\n  it(\"If an asynchronous microtask function contains an asynchronous operation without await, the subsequent operation will execute immediately because the asynchronous operation will not wait for completion.\", async () => {\n    const tracked = [];\n\n    async function microTaskFunction() {\n      Promise.resolve().then(() => tracked.push(3));\n      tracked.push(1);\n    }\n\n    microTaskFunction();\n    tracked.push(2);\n\n    await waitAndExpectSequentialNumbers(tracked, 10);\n  });\n\n  it(\"If an asynchronous microtask function contains an asynchronous operation with await, the subsequent operation will be executed after the asynchronous operation has finished.\", async () => {\n    const tracked = [];\n\n    async function microTaskFunction() {\n      await Promise.resolve().then(() => tracked.push(2));\n      tracked.push(3);\n    }\n\n    microTaskFunction();\n    tracked.push(1);\n\n    await waitAndExpectSequentialNumbers(tracked, 10);\n  });\n});\n\ndescribe(\"Asynchronous Require/Import\", () => {\n  it(\"When a require is executed synchronously within the main thread, the following statements are executed immediately after the module is loaded.\", async () => {\n    const tracked = [];\n\n    tracked.push(1);\n    require(`${CWD}/fixtures/empty.js`);\n    tracked.push(2);\n\n    await waitAndExpectSequentialNumbers(tracked, 10);\n  });\n\n  it(\"When require is placed inside a queueMicrotask, it executes after the current synchronous execution context finishes and before any scheduled macrotasks.\", async () => {\n    const tracked = [];\n\n    queueMicrotask(() => {\n      tracked.push(2);\n      require(`${CWD}/fixtures/empty.js`);\n      tracked.push(3);\n    });\n    queueMicrotask(() => tracked.push(4));\n\n    tracked.push(1);\n\n    await waitAndExpectSequentialNumbers(tracked, 10);\n  });\n\n  it(\"When require is placed inside a setTimeout, it executes after all synchronous code and all microtasks have been completed, following the macrotask scheduling.\", async () => {\n    const tracked = [];\n\n    setTimeout(() => {\n      tracked.push(3);\n      require(`${CWD}/fixtures/empty.js`);\n      tracked.push(4);\n    }, 0);\n    queueMicrotask(() => tracked.push(2));\n\n    tracked.push(1);\n\n    await waitAndExpectSequentialNumbers(tracked, 10);\n  });\n\n  it(\"When require is placed inside a Promise.then, it executes after the current synchronous execution context finishes but before any macrotasks, following the microtask scheduling rules.\", async () => {\n    const tracked = [];\n\n    Promise.resolve().then(() => {\n      tracked.push(2);\n      require(`${CWD}/fixtures/empty.js`);\n      tracked.push(3);\n    });\n    queueMicrotask(() => tracked.push(4));\n\n    tracked.push(1);\n\n    await waitAndExpectSequentialNumbers(tracked, 10);\n  });\n\n  it(\"When multiple queueMicrotask calls contain require, they execute in the order they were scheduled, immediately after all synchronous code, according to FIFO (first-in, first-out) microtask queue behavior.\", async () => {\n    const tracked = [];\n\n    queueMicrotask(() => {\n      tracked.push(2);\n      require(`${CWD}/fixtures/empty.js`);\n      tracked.push(3);\n    });\n    queueMicrotask(() => {\n      tracked.push(4);\n      require(`${CWD}/fixtures/empty.js`);\n      tracked.push(5);\n    });\n\n    tracked.push(1);\n\n    await waitAndExpectSequentialNumbers(tracked, 10);\n  });\n\n  it(\"When using await import(), the code following the await resumes only after all earlier queued microtasks have been executed, as await yields execution back to the event loop.\", async () => {\n    const tracked = [];\n\n    (async () => {\n      tracked.push(1);\n      await import(`${CWD}/fixtures/empty.js`);\n      tracked.push(4);\n    })();\n\n    queueMicrotask(() => tracked.push(3));\n    tracked.push(2);\n\n    await waitAndExpectSequentialNumbers(tracked, 20);\n  });\n});\n"
  },
  {
    "path": "tests/unit/buffer.test.ts",
    "content": "import defaultImport from \"node:buffer\";\nimport legacyImport from \"buffer\";\n\nit(\"node:buffer should be the same as buffer\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n\nconst { Buffer } = defaultImport;\n\ndescribe(\"Buffer.alloc\", () => {\n  it(\"should create a buffer with specified size and fill with zeros (default fill)\", () => {\n    const size = 10;\n    const buffer = Buffer.alloc(size);\n\n    expect(buffer.length).toEqual(size);\n\n    for (const byte of buffer) {\n      expect(byte).toEqual(0);\n    }\n  });\n\n  it(\"should create a buffer with specified size and fill with a string value\", () => {\n    const size = 8;\n    const fillString = \"abc\";\n    const buffer = Buffer.alloc(size, fillString);\n\n    expect(buffer.toString()).toEqual(\"abcabcab\");\n  });\n\n  it(\"should create a buffer with specified size and fill with an encoded string value\", () => {\n    const size = 8;\n    const fillString = \"616263\";\n    const buffer = Buffer.alloc(size, fillString, \"hex\");\n\n    expect(buffer.toString()).toEqual(\"abcabcab\");\n  });\n\n  it(\"should create a buffer with specified size and fill with a Buffer value\", () => {\n    const size = 6;\n    const fillBuffer = Buffer.from([1, 2, 3]);\n    const buffer = Buffer.alloc(size, fillBuffer);\n\n    expect(buffer).toStrictEqual(Buffer.from([1, 2, 3, 1, 2, 3]));\n  });\n\n  it(\"should create a buffer with specified size and fill with a Uint8Array value\", () => {\n    const size = 5;\n    const fillUint8Array = new Uint8Array([5, 10, 15]);\n    const buffer = Buffer.alloc(size, fillUint8Array);\n\n    expect(buffer).toStrictEqual(Buffer.from([5, 10, 15, 5, 10]));\n  });\n\n  it(\"should create a buffer with specified size and fill with an integer value\", () => {\n    const size = 4;\n    const fillInteger = 42;\n    const buffer = Buffer.alloc(size, fillInteger);\n\n    for (const byte of buffer) {\n      expect(byte).toEqual(fillInteger);\n    }\n  });\n\n  it(\"should throw an error when fill argument is invalid\", () => {\n    const size = 10;\n    let buffer = Buffer.alloc(size, true as any);\n    for (const byte of buffer) {\n      expect(byte).toEqual(0);\n    }\n  });\n});\n\ndescribe(\"Buffer.allocUnsafe\", () => {\n  it(\"should create a buffer of the specified size\", () => {\n    const size = 10;\n    const buffer = Buffer.allocUnsafe(size);\n\n    expect(buffer.length).toEqual(size);\n    for (const byte of buffer) {\n      expect(byte).toBeDefined();\n    }\n  });\n\n  it(\"should create an empty buffer when size is 0\", () => {\n    const size = 0;\n    const buffer = Buffer.allocUnsafe(size);\n\n    expect(buffer.length).toEqual(size);\n  });\n\n  it(\"should throw a TypeError when size is negative\", () => {\n    expect(() => {\n      const size = -1;\n      const buffer = Buffer.allocUnsafe(size);\n    }).toThrow(TypeError);\n  });\n});\n\ndescribe(\"Buffer.allocUnsafeSlow\", () => {\n  it(\"should create a buffer of the specified size\", () => {\n    const size = 10;\n    const buffer = Buffer.allocUnsafeSlow(size);\n\n    expect(buffer.length).toEqual(size);\n    for (const byte of buffer) {\n      expect(byte).toBeDefined();\n    }\n  });\n\n  it(\"should create an empty buffer when size is 0\", () => {\n    const size = 0;\n    const buffer = Buffer.allocUnsafeSlow(size);\n\n    expect(buffer.length).toEqual(size);\n  });\n\n  it(\"should throw a TypeError when size is negative\", () => {\n    expect(() => {\n      const size = -1;\n      const buffer = Buffer.allocUnsafeSlow(size);\n    }).toThrow(TypeError);\n  });\n});\n\ndescribe(\"Buffer.byteLength\", () => {\n  it(\"should return the correct byte length for ASCII string\", () => {\n    const length = Buffer.byteLength(\"Hello\");\n\n    expect(length).toEqual(5);\n  });\n\n  it(\"should return the correct byte length for UTF-8 string\", () => {\n    const length = Buffer.byteLength(\"👋\");\n\n    expect(length).toEqual(4);\n  });\n\n  it(\"should return the correct byte length for UTF-8 string\", () => {\n    const length = Buffer.byteLength(\"你好\");\n\n    expect(length).toEqual(6);\n  });\n\n  it(\"should return the correct byte length for a buffer\", () => {\n    const buffer = Buffer.from([1, 2, 3, 4, 5]);\n    const length = Buffer.byteLength(buffer);\n\n    expect(length).toEqual(5);\n  });\n\n  it(\"should return the correct byte length for a hex-encoded string\", () => {\n    const length = Buffer.byteLength(\"deadbeef\", \"hex\");\n\n    expect(length).toEqual(4);\n  });\n\n  it(\"should return the correct byte length for a base64-encoded string\", () => {\n    const length = Buffer.byteLength(\"SGVsbG8gV29ybGQ=\", \"base64\");\n\n    expect(length).toEqual(11);\n  });\n});\n\ndescribe(\"Buffer.concat\", () => {\n  it(\"should concatenate buffers\", () => {\n    const buffer1 = Buffer.from(\"Hello\");\n    const buffer2 = Buffer.from(\" \");\n    const buffer3 = Buffer.from(\"World\");\n    const resultBuffer = Buffer.concat([buffer1, buffer2, buffer3]);\n\n    expect(resultBuffer.toString()).toEqual(\"Hello World\");\n  });\n\n  it(\"should handle empty buffers in the array\", () => {\n    const buffer1 = Buffer.from(\"Hello\");\n    const buffer2 = Buffer.from(\"\");\n    const buffer3 = Buffer.from(\"World\");\n    const resultBuffer = Buffer.concat([buffer1, buffer2, buffer3]);\n\n    expect(resultBuffer.toString()).toEqual(\"HelloWorld\");\n  });\n\n  it(\"should handle an array with a single buffer\", () => {\n    const buffer = Buffer.from(\"SingleBuffer\");\n    const resultBuffer = Buffer.concat([buffer]);\n\n    expect(resultBuffer.toString()).toEqual(\"SingleBuffer\");\n  });\n\n  it(\"should handle an empty array of buffers\", () => {\n    const resultBuffer = Buffer.concat([]);\n\n    expect(resultBuffer.toString()).toEqual(\"\");\n  });\n\n  it(\"should throw an error when the list contains a non-buffer\", () => {\n    expect(() => {\n      const buffer1 = Buffer.from(\"Hello\");\n      const invalidBuffer = \"InvalidBuffer\";\n      Buffer.concat([buffer1, invalidBuffer as any]);\n    }).toThrow(TypeError);\n  });\n\n  it(\"should throw an error when the totalLength is too large\", () => {\n    expect(() => {\n      const buffer1 = Buffer.from(\"Hello\");\n      const buffer2 = Buffer.alloc(2 ** 32); // 1 GB buffer\n      Buffer.concat([buffer1, buffer2], 2 ** 33); // totalLength exceeding maximum allowed\n    }).toThrow(RangeError);\n  });\n\n  it(\"should concatenate buffers with specified totalLength\", () => {\n    const buffer1 = Buffer.from(\"123\");\n    const buffer2 = Buffer.from(\"4567\");\n    const buffer3 = Buffer.from(\"89\");\n    const resultBuffer = Buffer.concat([buffer1, buffer2, buffer3], 4);\n\n    expect(resultBuffer.toString()).toEqual(\"1234\");\n\n    const resultBuffer2 = Buffer.concat([buffer1, buffer2, buffer3], 3);\n\n    expect(resultBuffer2.toString()).toEqual(\"123\");\n  });\n\n  it(\"should throw an error when totalLength is less than the actual length of concatenated buffers\", () => {\n    const buffer1 = Buffer.from(\"Hello\");\n    const buffer2 = Buffer.from(\"World\");\n    const resultBuffer = Buffer.concat([buffer1, buffer2], 999);\n\n    expect(resultBuffer.toString()).toEqual(\"HelloWorld\");\n    expect(resultBuffer.length).toEqual(buffer1.length + buffer2.length);\n  });\n});\n\ndescribe(\"Buffer.from\", () => {\n  it(\"should create a buffer from a string with utf-8 encoding\", () => {\n    const input = \"Hello, world!\";\n    const buffer = Buffer.from(input, \"utf-8\");\n\n    expect(buffer.toString()).toEqual(input);\n  });\n\n  it(\"should create a buffer from an array of bytes\", () => {\n    const byteArray = [65, 66, 67, 68, 69]; // ASCII values of A, B, C, D, E\n    const buffer = Buffer.from(byteArray);\n\n    for (let i = 0; i < byteArray.length; i++) {\n      expect(buffer[i]).toEqual(byteArray[i]);\n    }\n  });\n\n  it(\"should create a buffer from a string with base64 encoding\", () => {\n    const input = \"SGVsbG8sIHdvcmxkIQ==\";\n    const buffer = Buffer.from(input, \"base64\");\n    expect(buffer.toString()).toEqual(\"Hello, world!\");\n\n    const input2 = \"SGVsbG8sIHdvcmxkIQ\";\n    const buffer2 = Buffer.from(input2, \"base64\");\n    expect(buffer2.toString()).toEqual(\"Hello, world!\");\n  });\n\n  it(\"should create a buffer from a string with base64 encoding that contains / or +\", () => {\n    const input = \"PD8+MTIz\";\n    const buffer = Buffer.from(input, \"base64\");\n    expect(buffer.toString()).toEqual(\"<?>123\");\n\n    const input3 = \"PD8/PjEyMw==\";\n    const buffer3 = Buffer.from(input3, \"base64\");\n    expect(buffer3.toString()).toEqual(\"<??>123\");\n  });\n\n  // https://en.wikipedia.org/wiki/Base64#URL_applications\n  it(\"should create a buffer from a string with URL safe base64 encoding that contains _ or -\", () => {\n    const input = \"PD8-MTIz\";\n    const buffer = Buffer.from(input, \"base64\");\n    expect(buffer.toString()).toEqual(\"<?>123\");\n\n    const input3 = \"PD8_PjEyMw\";\n    const buffer3 = Buffer.from(input3, \"base64\");\n    expect(buffer3.toString()).toEqual(\"<??>123\");\n  });\n\n  it(\"should create a buffer from a string with hex encoding\", () => {\n    const input = \"48656c6c6f2c20776f726c6421\";\n    const buffer = Buffer.from(input, \"hex\");\n\n    expect(buffer.toString()).toEqual(\"Hello, world!\");\n  });\n\n  it(\"should create a buffer from a single ASCII character in utf16le encoding\", () => {\n    // ASCII character 'A' (U+0041) = [0x41, 0x00] in utf16le\n    const input = \"A\";\n    const buffer = Buffer.from(input, \"utf16le\");\n    expect(buffer.length).toEqual(2);\n    expect(buffer[0]).toEqual(0x41);\n    expect(buffer[1]).toEqual(0x00);\n    expect(buffer.toString(\"utf16le\")).toEqual(input);\n  });\n\n  it(\"should create a buffer from multiple ASCII characters in utf16le encoding\", () => {\n    const input2 = \"Hello\";\n    const buffer2 = Buffer.from(input2, \"utf16le\");\n    expect(buffer2.length).toEqual(10); // 5 characters * 2 bytes\n    expect(buffer2.toString(\"utf16le\")).toEqual(input2);\n  });\n\n  it(\"should create a buffer from a Unicode BMP character in utf16le encoding\", () => {\n    // Unicode BMP character '中' (U+4E2D) = [0x2D, 0x4E] in utf16le\n    const input3 = \"中\";\n    const buffer3 = Buffer.from(input3, \"utf16le\");\n    expect(buffer3.length).toEqual(2);\n    expect(buffer3[0]).toEqual(0x2d);\n    expect(buffer3[1]).toEqual(0x4e);\n    expect(buffer3.toString(\"utf16le\")).toEqual(input3);\n  });\n\n  it(\"should create a buffer from an emoji (astral plane character) in utf16le encoding\", () => {\n    // Emoji '😀' (U+1F600) = surrogate pair [0xD83D, 0xDE00] = [0x3D, 0xD8, 0x00, 0xDE] in utf16le\n    const input4 = \"😀\";\n    const buffer4 = Buffer.from(input4, \"utf16le\");\n    expect(buffer4.length).toEqual(4);\n    expect(buffer4[0]).toEqual(0x3d);\n    expect(buffer4[1]).toEqual(0xd8);\n    expect(buffer4[2]).toEqual(0x00);\n    expect(buffer4[3]).toEqual(0xde);\n    expect(buffer4.toString(\"utf16le\")).toEqual(input4);\n  });\n\n  it(\"should fail to create a buffer from a portion of a string in utf16le encoding\", () => {\n    const input4 = \"🌍🌎\".slice(1);\n    expect(() => Buffer.from(input4, \"utf16le\")).toThrow(\n      \"Conversion from string failed\"\n    );\n  });\n\n  it(\"should create a buffer from a portion of an array with offset and length\", () => {\n    const byteArray = [65, 66, 67, 68, 69]; // ASCII values of A, B, C, D, E\n    const offset = 1;\n    const length = 3;\n\n    // @ts-ignore\n    const buffer = Buffer.from(byteArray, offset, length);\n\n    expect(buffer.length).toEqual(length);\n    for (let i = 0; i < length; i++) {\n      expect(buffer[i]).toEqual(byteArray[offset + i]);\n    }\n  });\n\n  it(\"should handle offset and length overflows\", () => {\n    const byteArray = [65, 66, 67, 68, 69]; // ASCII values of A, B, C, D, E\n    let length = 99;\n    let offset = 0;\n    // @ts-ignore\n    let buffer = Buffer.from(byteArray, offset, length);\n    expect(buffer.length).toEqual(byteArray.length);\n    for (let i = 0; i < length; i++) {\n      expect(buffer[i]).toEqual(byteArray[offset + i]);\n    }\n\n    // @ts-ignore\n    buffer = Buffer.from(byteArray, 99, 2);\n    expect(buffer.length).toEqual(0);\n\n    // @ts-ignore\n    buffer = Buffer.from(byteArray, 99, 999);\n    expect(buffer.length).toEqual(0);\n  });\n\n  it(\"should use same memory for sub arrays\", () => {\n    const typedArray = new Uint8Array([65, 66, 67, 68, 69]);\n\n    const a = Buffer.from(typedArray.buffer);\n    const b = Buffer.from(typedArray.subarray(1, 4));\n    const c = Buffer.from(a);\n\n    expect(a.buffer).toStrictEqual(b.buffer);\n    expect(a.toString()).toEqual(\"ABCDE\");\n    expect(b.toString()).toEqual(\"BCD\");\n    expect(c.toString()).toEqual(\"ABCDE\");\n\n    typedArray.set([70, 71], 1);\n\n    expect(a.toString()).toEqual(\"AFGDE\");\n    expect(b.toString()).toEqual(\"FGD\");\n    expect(c.toString()).toEqual(\"ABCDE\");\n  });\n});\n\ndescribe(\"Buffer.isBuffer\", () => {\n  it(\"should return true when the object being tested is an instance of Buffer\", () => {\n    const buffer = Buffer.from(\"Hello, world!\");\n\n    expect(Buffer.isBuffer(buffer)).toEqual(true);\n  });\n\n  it(\"should return false when the object being tested is not an instance of Buffer\", () => {\n    expect(Buffer.isBuffer(false)).toEqual(false);\n    expect(Buffer.isBuffer(undefined)).toEqual(false);\n    expect(Buffer.isBuffer(null)).toEqual(false);\n    expect(Buffer.isBuffer(\"Buffer\")).toEqual(false);\n    expect(Buffer.isBuffer(Buffer)).toEqual(false);\n  });\n});\n\ndescribe(\"Buffer.isEncoding\", () => {\n  it(\"should return true when input is a valid encoding name\", () => {\n    expect(Buffer.isEncoding(\"utf8\")).toEqual(true);\n    expect(Buffer.isEncoding(\"hex\")).toEqual(true);\n    expect(Buffer.isEncoding(\"base64\")).toEqual(true);\n  });\n\n  it(\"should return false when input is not a valid encoding name\", () => {\n    expect(Buffer.isEncoding(false as unknown as string)).toEqual(false);\n    expect(Buffer.isEncoding(undefined as unknown as string)).toEqual(false);\n    expect(Buffer.isEncoding(null as unknown as string)).toEqual(false);\n    expect(Buffer.isEncoding(\"utf8/8\")).toEqual(false);\n  });\n});\n\n// Test prototype methods\ndescribe(\"copy\", () => {\n  it(\"should copy the entire source buffer to the destination buffer\", () => {\n    const bufSrc = Buffer.from(\"abcdefghijklmnopqrstuvwxyz\");\n    const bufDest = Buffer.from(\"**************************\");\n    expect(bufSrc.copy(bufDest)).toEqual(26);\n    expect(bufDest.toString()).toEqual(\"abcdefghijklmnopqrstuvwxyz\");\n  });\n\n  it(\"should copy the entire source buffer starting from a specified offset in the destination buffer\", () => {\n    const bufSrc = Buffer.from(\"abcdefghijklmnopqrstuvwxyz\");\n    const bufDest = Buffer.from(\"**************************\");\n    expect(bufSrc.copy(bufDest, 5)).toEqual(21);\n    expect(bufDest.toString()).toEqual(\"*****abcdefghijklmnopqrstu\");\n  });\n\n  it(\"should copy a portion of the source buffer starting from a specified source offset to the destination buffer at a specified offset\", () => {\n    const bufSrc = Buffer.from(\"abcdefghijklmnopqrstuvwxyz\");\n    const bufDest = Buffer.from(\"**************************\");\n    expect(bufSrc.copy(bufDest, 5, 10)).toEqual(16);\n    expect(bufDest.toString()).toEqual(\"*****klmnopqrstuvwxyz*****\");\n  });\n\n  it(\"should copy a specific range of the source buffer to the destination buffer at a specified offset\", () => {\n    const bufSrc = Buffer.from(\"abcdefghijklmnopqrstuvwxyz\");\n    const bufDest = Buffer.from(\"**************************\");\n    expect(bufSrc.copy(bufDest, 5, 10, 15)).toEqual(5);\n    expect(bufDest.toString()).toEqual(\"*****klmno****************\");\n  });\n\n  it(\"should return 0 and not modify the destination buffer when the source start index is greater than the source end index\", () => {\n    const bufSrc = Buffer.from(\"abcdefghijklmnopqrstuvwxyz\");\n    const bufDest = Buffer.from(\"**************************\");\n    expect(bufSrc.copy(bufDest, 5, 10, 9)).toEqual(0);\n    expect(bufDest.toString()).toEqual(\"**************************\");\n  });\n});\n\ndescribe(\"subarray\", () => {\n  it(\"should create a subarray from a buffer with the specified start and end indices\", () => {\n    const buffer = Buffer.from(\"Hello, world!\");\n    const subBuffer = buffer.subarray(7, 12);\n\n    expect(subBuffer.toString()).toEqual(\"world\");\n  });\n\n  it(\"should return a subarray from the start index to the end of the buffer when end index is omitted\", () => {\n    const buffer = Buffer.from(\"Hello, world!\");\n    const subBuffer = buffer.subarray(7);\n\n    expect(subBuffer.toString()).toEqual(\"world!\");\n  });\n\n  it(\"should return an empty buffer when the start index equals the end index\", () => {\n    const buffer = Buffer.from(\"Hello, world!\");\n    const subBuffer = buffer.subarray(5, 5);\n\n    expect(subBuffer.length).toEqual(0);\n    expect(subBuffer.toString()).toEqual(\"\");\n  });\n\n  it(\"should create a subarray with the same content as the original buffer when start and end indices cover the entire buffer\", () => {\n    const buffer = Buffer.from(\"Hello, world!\");\n    const subBuffer = buffer.subarray(0, buffer.length);\n\n    expect(subBuffer.toString()).toEqual(\"Hello, world!\");\n    expect(subBuffer).not.toBe(buffer); // Should be a new buffer, not the original one\n  });\n\n  it(\"should handle negative start and end indices\", () => {\n    const buffer = Buffer.from(\"Hello, world!\");\n    const subBuffer = buffer.subarray(-6, -1);\n\n    expect(subBuffer.toString()).toEqual(\"world\");\n  });\n\n  it(\"should handle out-of-bounds start and end indices\", () => {\n    const buffer = Buffer.from(\"Hello, world!\");\n\n    const subBuffer1 = buffer.subarray(-100, 5);\n    expect(subBuffer1.toString()).toEqual(\"Hello\");\n\n    const subBuffer2 = buffer.subarray(0, 100);\n    expect(subBuffer2.toString()).toEqual(\"Hello, world!\");\n\n    const subBuffer3 = buffer.subarray(50, 100);\n    expect(subBuffer3.length).toEqual(0);\n  });\n\n  it(\"should share memory with the original buffer\", () => {\n    const buffer = Buffer.from(\"Hello, world!\");\n    const subBuffer = buffer.subarray(0, 5);\n\n    const lowerCaseH = \"h\".charCodeAt(0);\n    subBuffer[0] = lowerCaseH;\n    expect(buffer[0]).toEqual(lowerCaseH);\n    expect(subBuffer.toString()).toEqual(\"hello\");\n  });\n\n  it(\"should not throw errors when start and end are out of order, but should return an empty buffer\", () => {\n    const buffer = Buffer.from(\"Hello, world!\");\n    const subBuffer = buffer.subarray(10, 5);\n\n    expect(subBuffer.length).toEqual(0);\n    expect(subBuffer.toString()).toEqual(\"\");\n  });\n\n  it(\"should create subarray views that share memory with the original Buffer\", () => {\n    const origin = Buffer.from(\"Hello, World!\");\n    const sub = origin.subarray(7, 12);\n\n    expect(origin.toString()).toEqual(\"Hello, World!\");\n    expect(sub.toString()).toEqual(\"World\");\n\n    expect(origin.subarray(1, 3).toString()).toEqual(\"el\");\n    expect(sub.subarray(1, 3).toString()).toEqual(\"or\");\n  });\n});\n\ndescribe(\"toString\", () => {\n  it(\"should convert buffer to a string with utf-8 encoding\", () => {\n    const input = \"Hello, world!\";\n    const buffer = Buffer.from(input);\n\n    expect(buffer.toString(\"utf-8\")).toEqual(input);\n  });\n\n  it(\"should convert buffer to a string with base64 encoding\", () => {\n    const input = \"SGVsbG8sIHdvcmxkIQ==\";\n    const buffer = Buffer.from(input, \"base64\");\n\n    expect(buffer.toString(\"base64\")).toEqual(input);\n  });\n\n  it(\"should convert buffer to a string with hex encoding\", () => {\n    const input = \"48656c6c6f2c20776f726c6421\";\n    const buffer = Buffer.from(input, \"hex\");\n\n    expect(buffer.toString(\"hex\")).toEqual(input);\n  });\n\n  it(\"should convert buffer to hex string with hex encoding\", () => {\n    const buffer = Buffer.from(\"Hello\");\n    const hexString = buffer.toString(\"hex\");\n\n    expect(hexString).toEqual(\"48656c6c6f\");\n  });\n\n  it(\"should convert buffer to utf-8 string with start parameter\", () => {\n    const buffer = Buffer.from(\"Hello, world!\");\n    const result = buffer.toString(\"utf-8\", 7);\n\n    expect(result).toEqual(\"world!\");\n  });\n\n  it(\"should convert buffer to utf-8 string with start and end parameters\", () => {\n    const buffer = Buffer.from(\"Hello, world!\");\n    const result = buffer.toString(\"utf-8\", 7, 12);\n\n    expect(result).toEqual(\"world\");\n  });\n\n  it(\"should handle negative start parameter\", () => {\n    const buffer = Buffer.from(\"Hello, world!\");\n    const result = buffer.toString(\"utf-8\", -6);\n\n    expect(result).toEqual(\"Hello, world!\");\n  });\n\n  it(\"should handle negative end parameter\", () => {\n    const buffer = Buffer.from(\"Hello, world!\");\n    const result = buffer.toString(\"utf-8\", 0, -1);\n\n    expect(result).toEqual(\"\");\n  });\n\n  it(\"should handle both negative start and end parameters\", () => {\n    const buffer = Buffer.from(\"Hello, world!\");\n    const result = buffer.toString(\"utf-8\", -6, -1);\n\n    expect(result).toEqual(\"\");\n  });\n});\n\ndescribe(\"write\", () => {\n  it(\"should write a UTF-8 string into a buffer and return the correct byte length\", () => {\n    const buf1 = Buffer.alloc(15);\n    expect(buf1.write(\"こんにちは\", \"utf-8\")).toEqual(15); // \"こんにちは\" means 'hello' in japanese.\n    expect(buf1.toString(\"utf8\")).toEqual(\"こんにちは\");\n  });\n\n  it(\"should write a hex string into a buffer and correctly convert it to UTF-8\", () => {\n    const buf2 = Buffer.alloc(15);\n    expect(buf2.write(\"68656c6c6f\", \"hex\")).toEqual(5); // 68656c6c6f -> 'hello'\n    expect(buf2.toString(\"utf8\").substring(0, 5)).toEqual(\"hello\");\n  });\n\n  it(\"should write a UTF-8 string into a buffer with an explicit offset of 0\", () => {\n    const buf1 = Buffer.alloc(15);\n    expect(buf1.write(\"こんにちは\", 0, \"utf-8\")).toEqual(15);\n    expect(buf1.toString(\"utf8\")).toEqual(\"こんにちは\");\n  });\n\n  it(\"should write a hex string into a buffer with an explicit offset of 0\", () => {\n    const buf2 = Buffer.alloc(15);\n    expect(buf2.write(\"68656c6c6f\", 0, \"hex\")).toEqual(5);\n    expect(buf2.toString(\"utf8\").substring(0, 5)).toEqual(\"hello\");\n  });\n\n  it(\"should write a UTF-8 string at offset 12 and store only part of it\", () => {\n    const buf1 = Buffer.alloc(15);\n    expect(buf1.write(\"こんにちは\", 12, \"utf-8\")).toEqual(3);\n    expect(buf1.toString(\"utf8\").substring(12)).toEqual(\"こ\");\n  });\n\n  it(\"should write a hex string at offset 12 and store only part of it\", () => {\n    const buf2 = Buffer.alloc(15);\n    expect(buf2.write(\"68656c6c6f\", 12, \"hex\")).toEqual(3);\n    expect(buf2.toString(\"utf8\").substring(12)).toEqual(\"hel\");\n  });\n\n  it(\"should write only the first 3 bytes of a UTF-8 string and store a partial character\", () => {\n    const buf1 = Buffer.alloc(15);\n    expect(buf1.write(\"こんにちは\", 0, 3, \"utf-8\")).toEqual(3);\n    expect(buf1.toString(\"utf8\").substring(0, 1)).toEqual(\"こ\"); // Returning characters instead of bytes\n  });\n\n  it(\"should write only the first 3 bytes of a hex string and correctly store the data\", () => {\n    const buf2 = Buffer.alloc(15);\n    expect(buf2.write(\"68656c6c6f\", 0, 3, \"hex\")).toEqual(3);\n    expect(buf2.toString(\"utf8\").substring(0, 3)).toEqual(\"hel\");\n  });\n\n  it(\"should write a UTF-8 string at offset 9 with a length of 12 bytes and store part of it\", () => {\n    const buf1 = Buffer.alloc(15);\n    expect(buf1.write(\"こんにちは\", 9, 12, \"utf-8\")).toEqual(6);\n    expect(buf1.toString(\"utf8\").substring(9, 12)).toEqual(\"こん\");\n  });\n\n  it(\"should write a hex string at offset 9 with a length of 12 bytes and store part of it\", () => {\n    const buf2 = Buffer.alloc(15);\n    expect(buf2.write(\"68656c6c6f\", 9, 12, \"hex\")).toEqual(5);\n    expect(buf2.toString(\"utf8\").substring(9, 12)).toEqual(\"hel\");\n  });\n});\n\ndescribe(\"writeBigInt64BE\", () => {\n  it(\"should write a 64-bit BigInteger in big-endian format at the beginning of the buffer\", () => {\n    const buf = Buffer.alloc(16);\n    expect(buf.writeBigInt64BE(0x0102030405060708n)).toEqual(8);\n    expect(buf).toEqual(\n      Buffer.from([1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0])\n    );\n  });\n\n  it(\"should write a 64-bit BigInteger in big-endian format at the specified offset in the buffer\", () => {\n    const buf = Buffer.alloc(16);\n    expect(buf.writeBigInt64BE(0x0102030405060708n, 8)).toEqual(16);\n    expect(buf).toEqual(\n      Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8])\n    );\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(16);\n      buf.writeBigInt64BE(0x0102030405060708n, 9);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"writeBigInt64LE\", () => {\n  it(\"should write a 64-bit BigInteger in little-endian format at the beginning of the buffer\", () => {\n    const buf = Buffer.alloc(16);\n    expect(buf.writeBigInt64LE(0x0102030405060708n)).toEqual(8);\n    expect(buf).toEqual(\n      Buffer.from([8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0])\n    );\n  });\n\n  it(\"should write a 64-bit BigInteger in little-endian format at the specified offset in the buffer\", () => {\n    const buf = Buffer.alloc(16);\n    expect(buf.writeBigInt64LE(0x0102030405060708n, 8)).toEqual(16);\n    expect(buf).toEqual(\n      Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 8, 7, 6, 5, 4, 3, 2, 1])\n    );\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(16);\n      buf.writeBigInt64LE(0x0102030405060708n, 9);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"writeDoubleBE\", () => {\n  it(\"should write a 64-bit Double in big-endian format at the beginning of the buffer\", () => {\n    const buf = Buffer.alloc(16);\n    expect(buf.writeDoubleBE(123.456)).toEqual(8);\n    expect(buf).toEqual(\n      Buffer.from([64, 94, 221, 47, 26, 159, 190, 119, 0, 0, 0, 0, 0, 0, 0, 0])\n    );\n  });\n\n  it(\"should write a 64-bit Double in big-endian format at the specified offset in the buffer\", () => {\n    const buf = Buffer.alloc(16);\n    expect(buf.writeDoubleBE(123.456, 8)).toEqual(16);\n    expect(buf).toEqual(\n      Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 64, 94, 221, 47, 26, 159, 190, 119])\n    );\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(16);\n      buf.writeDoubleBE(123.456, 9);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"writeDoubleLE\", () => {\n  it(\"should write a 64-bit Double in little-endian format at the beginning of the buffer\", () => {\n    const buf = Buffer.alloc(16);\n    expect(buf.writeDoubleLE(123.456)).toEqual(8);\n    expect(buf).toEqual(\n      Buffer.from([119, 190, 159, 26, 47, 221, 94, 64, 0, 0, 0, 0, 0, 0, 0, 0])\n    );\n  });\n\n  it(\"should write a 64-bit Double in little-endian format at the specified offset in the buffer\", () => {\n    const buf = Buffer.alloc(16);\n    expect(buf.writeDoubleLE(123.456, 8)).toEqual(16);\n    expect(buf).toEqual(\n      Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 119, 190, 159, 26, 47, 221, 94, 64])\n    );\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(16);\n      buf.writeDoubleLE(123.456, 9);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"writeFloatBE\", () => {\n  it(\"should write a 32-bit Float in big-endian format at the beginning of the buffer\", () => {\n    const buf = Buffer.alloc(8);\n    expect(buf.writeFloatBE(0xcafebabe)).toEqual(4);\n    expect(buf).toEqual(Buffer.from([79, 74, 254, 187, 0, 0, 0, 0]));\n  });\n\n  it(\"should write a 32-bit Float in big-endian format at the specified offset in the buffer\", () => {\n    const buf = Buffer.alloc(8);\n    expect(buf.writeFloatBE(0xcafebabe, 4)).toEqual(8);\n    expect(buf).toEqual(Buffer.from([0, 0, 0, 0, 79, 74, 254, 187]));\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(8);\n      buf.writeFloatBE(0xcafebabe, 5);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"writeFloatLE\", () => {\n  it(\"should write a 32-bit Float in little-endian format at the beginning of the buffer\", () => {\n    const buf = Buffer.alloc(8);\n    expect(buf.writeFloatLE(0xcafebabe)).toEqual(4);\n    expect(buf).toEqual(Buffer.from([187, 254, 74, 79, 0, 0, 0, 0]));\n  });\n\n  it(\"should write a 32-bit Float in little-endian format at the specified offset in the buffer\", () => {\n    const buf = Buffer.alloc(8);\n    expect(buf.writeFloatLE(0xcafebabe, 4)).toEqual(8);\n    expect(buf).toEqual(Buffer.from([0, 0, 0, 0, 187, 254, 74, 79]));\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(8);\n      buf.writeFloatLE(0xcafebabe, 5);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"writeInt8\", () => {\n  it(\"should write a 8-bit integer at the beginning of the buffer\", () => {\n    const buf = Buffer.alloc(2);\n    expect(buf.writeInt8(0x01)).toEqual(1);\n    expect(buf).toEqual(Buffer.from([1, 0]));\n  });\n\n  it(\"should write a 8-bit integer at the specified offset in the buffer\", () => {\n    const buf = Buffer.alloc(2);\n    expect(buf.writeInt8(0x01, 1)).toEqual(2);\n    expect(buf).toEqual(Buffer.from([0, 1]));\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(2);\n      buf.writeInt8(0x01, 3);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"writeInt16BE\", () => {\n  it(\"should write a 16-bit integer in big-endian format at the beginning of the buffer\", () => {\n    const buf = Buffer.alloc(4);\n    expect(buf.writeInt16BE(0x0102)).toEqual(2);\n    expect(buf).toEqual(Buffer.from([1, 2, 0, 0]));\n  });\n\n  it(\"should write a 16-bit integer in big-endian format at the specified offset in the buffer\", () => {\n    const buf = Buffer.alloc(4);\n    expect(buf.writeInt16BE(0x0102, 2)).toEqual(4);\n    expect(buf).toEqual(Buffer.from([0, 0, 1, 2]));\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(4);\n      buf.writeInt16BE(0x0102, 3);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"writeInt16LE\", () => {\n  it(\"should write a 16-bit integer in little-endian format at the beginning of the buffer\", () => {\n    const buf = Buffer.alloc(4);\n    expect(buf.writeInt16LE(0x0102)).toEqual(2);\n    expect(buf).toEqual(Buffer.from([2, 1, 0, 0]));\n  });\n\n  it(\"should write a 16-bit integer in little-endian format at the specified offset in the buffer\", () => {\n    const buf = Buffer.alloc(4);\n    expect(buf.writeInt16LE(0x0102, 2)).toEqual(4);\n    expect(buf).toEqual(Buffer.from([0, 0, 2, 1]));\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(4);\n      buf.writeInt16LE(0x0102, 3);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"writeInt32BE\", () => {\n  it(\"should write a 32-bit integer in big-endian format at the beginning of the buffer\", () => {\n    const buf = Buffer.alloc(8);\n    expect(buf.writeInt32BE(0x01020304)).toEqual(4);\n    expect(buf).toEqual(Buffer.from([1, 2, 3, 4, 0, 0, 0, 0]));\n  });\n\n  it(\"should write a 32-bit integer in big-endian format at the specified offset in the buffer\", () => {\n    const buf = Buffer.alloc(8);\n    expect(buf.writeInt32BE(0x01020304, 4)).toEqual(8);\n    expect(buf).toEqual(Buffer.from([0, 0, 0, 0, 1, 2, 3, 4]));\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(8);\n      buf.writeInt32BE(0x01020304, 5);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"writeInt32LE\", () => {\n  it(\"should write a 32-bit integer in little-endian format at the beginning of the buffer\", () => {\n    const buf = Buffer.alloc(8);\n    expect(buf.writeInt32LE(0x05060708)).toEqual(4);\n    expect(buf).toEqual(Buffer.from([8, 7, 6, 5, 0, 0, 0, 0]));\n  });\n\n  it(\"should write a 32-bit integer in little-endian format at the specified offset in the buffer\", () => {\n    const buf = Buffer.alloc(8);\n    expect(buf.writeInt32LE(0x05060708, 4)).toEqual(8);\n    expect(buf).toEqual(Buffer.from([0, 0, 0, 0, 8, 7, 6, 5]));\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(8);\n      buf.writeInt32LE(0x05060708, 5);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"writeUInt8\", () => {\n  it(\"should write a 8-bit unsigned integer at the beginning of the buffer\", () => {\n    const buf = Buffer.alloc(2);\n    expect(buf.writeUInt8(2)).toEqual(1);\n    expect(buf).toEqual(Buffer.from([2, 0]));\n  });\n\n  it(\"should write a 8-bit unsigned integer at the specified offset in the buffer\", () => {\n    const buf = Buffer.alloc(4);\n    expect(buf.writeUInt8(0x3, 0)).toEqual(1);\n    expect(buf.writeUInt8(0x4, 1)).toEqual(2);\n    expect(buf.writeUInt8(0x23, 2)).toEqual(3);\n    expect(buf.writeUInt8(0x42, 3)).toEqual(4);\n    expect(buf).toEqual(Buffer.from([3, 4, 35, 66]));\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(2);\n      buf.writeInt8(0x01, 3);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"writeUInt16BE\", () => {\n  it(\"should write a 16-bit unsigned integer in big-endian format at the beginning of the buffer\", () => {\n    const buf = Buffer.alloc(4);\n    expect(buf.writeUInt16BE(0xdead)).toEqual(2);\n    expect(buf).toEqual(Buffer.from([222, 173, 0, 0]));\n  });\n\n  it(\"should write a 16-bit unsigned integer in big-endian format at the specified offset in the buffer\", () => {\n    const buf = Buffer.alloc(4);\n    expect(buf.writeUInt16BE(0xbeef, 2)).toEqual(4);\n    expect(buf).toEqual(Buffer.from([0, 0, 190, 239]));\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(4);\n      buf.writeUInt16BE(0x0102, 3);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"writeUInt16LE\", () => {\n  it(\"should write a 16-bit unsigned integer in little-endian format at the beginning of the buffer\", () => {\n    const buf = Buffer.alloc(4);\n    expect(buf.writeUInt16LE(0xdead)).toEqual(2);\n    expect(buf).toEqual(Buffer.from([173, 222, 0, 0]));\n  });\n\n  it(\"should write a 16-bit unsigned integer in little-endian format at the specified offset in the buffer\", () => {\n    const buf = Buffer.alloc(4);\n    expect(buf.writeUInt16LE(0xbeef, 2)).toEqual(4);\n    expect(buf).toEqual(Buffer.from([0, 0, 239, 190]));\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(4);\n      buf.writeUInt16LE(0x0304, 3);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"writeUInt32BE\", () => {\n  it(\"should write a 32-bit unsigned integer in big-endian format at the beginning of the buffer\", () => {\n    const buf = Buffer.alloc(8);\n    expect(buf.writeUInt32BE(0xfeedface)).toEqual(4);\n    expect(buf).toEqual(Buffer.from([254, 237, 250, 206, 0, 0, 0, 0]));\n  });\n\n  it(\"should write a 32-bit unsigned integer in big-endian format at the specified offset in the buffer\", () => {\n    const buf = Buffer.alloc(8);\n    expect(buf.writeUInt32BE(0xfeedface, 4)).toEqual(8);\n    expect(buf).toEqual(Buffer.from([0, 0, 0, 0, 254, 237, 250, 206]));\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(8);\n      buf.writeUInt32BE(0x01020304, 5);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"writeUInt32LE\", () => {\n  it(\"should write a 32-bit unsigned integer in little-endian format at the beginning of the buffer\", () => {\n    const buf = Buffer.alloc(8);\n    expect(buf.writeUInt32LE(0xfeedface)).toEqual(4);\n    expect(buf).toEqual(Buffer.from([206, 250, 237, 254, 0, 0, 0, 0]));\n  });\n\n  it(\"should write a 32-bit unsigned integer in little-endian format at the specified offset in the buffer\", () => {\n    const buf = Buffer.alloc(8);\n    expect(buf.writeUInt32LE(0x01020304, 4)).toEqual(8);\n    expect(buf).toEqual(Buffer.from([0, 0, 0, 0, 4, 3, 2, 1]));\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(8);\n      buf.writeUInt32LE(0x01020304, 5);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"readBigInt64BE\", () => {\n  it(\"should read a 64-bit signed BigInt in big-endian format from the beginning of the buffer\", () => {\n    const buf = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0]);\n    expect(buf.readBigInt64BE()).toEqual(0x0102030405060708n);\n  });\n\n  it(\"should read a 64-bit signed BigInt in big-endian format from the specified offset\", () => {\n    const buf = Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8]);\n    expect(buf.readBigInt64BE(8)).toEqual(0x0102030405060708n);\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(16);\n      buf.readBigInt64BE(9);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"readBigInt64LE\", () => {\n  it(\"should read a 64-bit signed BigInt in little-endian format from the beginning of the buffer\", () => {\n    const buf = Buffer.from([8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0]);\n    expect(buf.readBigInt64LE()).toEqual(0x0102030405060708n);\n  });\n\n  it(\"should read a 64-bit signed BigInt in little-endian format from the specified offset\", () => {\n    const buf = Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 8, 7, 6, 5, 4, 3, 2, 1]);\n    expect(buf.readBigInt64LE(8)).toEqual(0x0102030405060708n);\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(16);\n      buf.readBigInt64LE(9);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"readDoubleBE\", () => {\n  it(\"should read a 64-bit Double in big-endian format from the beginning of the buffer\", () => {\n    const buf = Buffer.from([\n      64, 94, 221, 47, 26, 159, 190, 119, 0, 0, 0, 0, 0, 0, 0, 0,\n    ]);\n    expect(buf.readDoubleBE()).toBeCloseTo(123.456);\n  });\n\n  it(\"should read a 64-bit Double in big-endian format from the specified offset\", () => {\n    const buf = Buffer.from([\n      0, 0, 0, 0, 0, 0, 0, 0, 64, 94, 221, 47, 26, 159, 190, 119,\n    ]);\n    expect(buf.readDoubleBE(8)).toBeCloseTo(123.456);\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(16);\n      buf.readDoubleBE(9);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"readDoubleLE\", () => {\n  it(\"should read a 64-bit Double in little-endian format from the beginning of the buffer\", () => {\n    const buf = Buffer.from([\n      119, 190, 159, 26, 47, 221, 94, 64, 0, 0, 0, 0, 0, 0, 0, 0,\n    ]);\n    expect(buf.readDoubleLE()).toBeCloseTo(123.456);\n  });\n\n  it(\"should read a 64-bit Double in little-endian format from the specified offset\", () => {\n    const buf = Buffer.from([\n      0, 0, 0, 0, 0, 0, 0, 0, 119, 190, 159, 26, 47, 221, 94, 64,\n    ]);\n    expect(buf.readDoubleLE(8)).toBeCloseTo(123.456);\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(16);\n      buf.readDoubleLE(9);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"readFloatBE\", () => {\n  it(\"should read a 32-bit Float in big-endian format from the beginning of the buffer\", () => {\n    const buf = Buffer.from([79, 74, 254, 187, 0, 0, 0, 0]);\n    expect(buf.readFloatBE()).toBeCloseTo(0xcafebabe, -4);\n  });\n\n  it(\"should read a 32-bit Float in big-endian format from the specified offset\", () => {\n    const buf = Buffer.from([0, 0, 0, 0, 79, 74, 254, 187]);\n    expect(buf.readFloatBE(4)).toBeCloseTo(0xcafebabe, -4);\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(8);\n      buf.readFloatBE(5);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"readFloatLE\", () => {\n  it(\"should read a 32-bit Float in little-endian format from the beginning of the buffer\", () => {\n    const buf = Buffer.from([187, 254, 74, 79, 0, 0, 0, 0]);\n    expect(buf.readFloatLE()).toBeCloseTo(0xcafebabe, -4);\n  });\n\n  it(\"should read a 32-bit Float in little-endian format from the specified offset\", () => {\n    const buf = Buffer.from([0, 0, 0, 0, 187, 254, 74, 79]);\n    expect(buf.readFloatLE(4)).toBeCloseTo(0xcafebabe, -4);\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(8);\n      buf.readFloatLE(5);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"readInt8\", () => {\n  it(\"should read a 8-bit integer from the beginning of the buffer\", () => {\n    const buf = Buffer.from([1, 0]);\n    expect(buf.readInt8()).toEqual(0x01);\n  });\n\n  it(\"should read a 8-bit integer from the specified offset\", () => {\n    const buf = Buffer.from([0, 1]);\n    expect(buf.readInt8(1)).toEqual(0x01);\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(2);\n      buf.readInt8(3);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"readInt16BE\", () => {\n  it(\"should read a 16-bit integer in big-endian format from the beginning of the buffer\", () => {\n    const buf = Buffer.from([1, 2, 0, 0]);\n    expect(buf.readInt16BE()).toEqual(0x0102);\n  });\n\n  it(\"should read a 16-bit integer in big-endian format from the specified offset\", () => {\n    const buf = Buffer.from([0, 0, 1, 2]);\n    expect(buf.readInt16BE(2)).toEqual(0x0102);\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(4);\n      buf.readInt16BE(3);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"readInt16LE\", () => {\n  it(\"should read a 16-bit integer in little-endian format from the beginning of the buffer\", () => {\n    const buf = Buffer.from([2, 1, 0, 0]);\n    expect(buf.readInt16LE()).toEqual(0x0102);\n  });\n\n  it(\"should read a 16-bit integer in little-endian format from the specified offset\", () => {\n    const buf = Buffer.from([0, 0, 2, 1]);\n    expect(buf.readInt16LE(2)).toEqual(0x0102);\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(4);\n      buf.readInt16LE(3);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"readInt32BE\", () => {\n  it(\"should read a 32-bit integer in big-endian format from the beginning of the buffer\", () => {\n    const buf = Buffer.from([1, 2, 3, 4, 0, 0, 0, 0]);\n    expect(buf.readInt32BE()).toEqual(0x01020304);\n  });\n\n  it(\"should read a 32-bit integer in big-endian format from the specified offset\", () => {\n    const buf = Buffer.from([0, 0, 0, 0, 1, 2, 3, 4]);\n    expect(buf.readInt32BE(4)).toEqual(0x01020304);\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(8);\n      buf.readInt32BE(5);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"readInt32LE\", () => {\n  it(\"should read a 32-bit integer in little-endian format from the beginning of the buffer\", () => {\n    const buf = Buffer.from([8, 7, 6, 5, 0, 0, 0, 0]);\n    expect(buf.readInt32LE()).toEqual(0x05060708);\n  });\n\n  it(\"should read a 32-bit integer in little-endian format from the specified offset\", () => {\n    const buf = Buffer.from([0, 0, 0, 0, 8, 7, 6, 5]);\n    expect(buf.readInt32LE(4)).toEqual(0x05060708);\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(8);\n      buf.readInt32LE(5);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"readUInt8\", () => {\n  it(\"should read an 8-bit unsigned integer from the beginning of the buffer\", () => {\n    const buf = Buffer.from([2, 0]);\n    expect(buf.readUInt8()).toEqual(2);\n  });\n\n  it(\"should read an 8-bit unsigned integer from the specified offset\", () => {\n    const buf = Buffer.from([3, 4, 35, 66]);\n    expect(buf.readUInt8(0)).toEqual(0x3);\n    expect(buf.readUInt8(1)).toEqual(0x4);\n    expect(buf.readUInt8(2)).toEqual(0x23);\n    expect(buf.readUInt8(3)).toEqual(0x42);\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(2);\n      buf.readUInt8(3);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"readUInt16BE\", () => {\n  it(\"should read a 16-bit unsigned integer in big-endian format from the beginning of the buffer\", () => {\n    const buf = Buffer.from([222, 173, 0, 0]);\n    expect(buf.readUInt16BE()).toEqual(0xdead);\n  });\n\n  it(\"should read a 16-bit unsigned integer in big-endian format from the specified offset\", () => {\n    const buf = Buffer.from([0, 0, 190, 239]);\n    expect(buf.readUInt16BE(2)).toEqual(0xbeef);\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(4);\n      buf.readUInt16BE(3);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"readUInt16LE\", () => {\n  it(\"should read a 16-bit unsigned integer in little-endian format from the beginning of the buffer\", () => {\n    const buf = Buffer.from([173, 222, 0, 0]);\n    expect(buf.readUInt16LE()).toEqual(0xdead);\n  });\n\n  it(\"should read a 16-bit unsigned integer in little-endian format from the specified offset\", () => {\n    const buf = Buffer.from([0, 0, 239, 190]);\n    expect(buf.readUInt16LE(2)).toEqual(0xbeef);\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(4);\n      buf.readUInt16LE(3);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"readUInt32BE\", () => {\n  it(\"should read a 32-bit unsigned integer in big-endian format from the beginning of the buffer\", () => {\n    const buf = Buffer.from([254, 237, 250, 206, 0, 0, 0, 0]);\n    expect(buf.readUInt32BE()).toEqual(0xfeedface);\n  });\n\n  it(\"should read a 32-bit unsigned integer in big-endian format from the specified offset\", () => {\n    const buf = Buffer.from([0, 0, 0, 0, 254, 237, 250, 206]);\n    expect(buf.readUInt32BE(4)).toEqual(0xfeedface);\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(8);\n      buf.readUInt32BE(5);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"readUInt32LE\", () => {\n  it(\"should read a 32-bit unsigned integer in little-endian format from the beginning of the buffer\", () => {\n    const buf = Buffer.from([206, 250, 237, 254, 0, 0, 0, 0]);\n    expect(buf.readUInt32LE()).toEqual(0xfeedface);\n  });\n\n  it(\"should read a 32-bit unsigned integer in little-endian format from the specified offset\", () => {\n    const buf = Buffer.from([0, 0, 0, 0, 4, 3, 2, 1]);\n    expect(buf.readUInt32LE(4)).toEqual(0x01020304);\n  });\n\n  it(\"should throw a RangeError if the offset is out of bounds\", () => {\n    expect(() => {\n      const buf = Buffer.alloc(8);\n      buf.readUInt32LE(5);\n    }).toThrow(RangeError);\n  });\n});\n\ndescribe(\"Blob class\", () => {\n  it(\"should construct a new Blob object with the provided data and options\", () => {\n    const blobData = [\"Hello, world!\"];\n    const blobOptions = { type: \"text/plain\" };\n    const blob = new Blob(blobData, blobOptions);\n\n    expect(blob.size).toEqual(blobData[0].length);\n    expect(blob.type).toEqual(blobOptions.type);\n  });\n\n  it(\"should create a Blob with default type if options.type is not provided\", () => {\n    const blobData = [\"Hello, world!\"];\n    const blob = new Blob(blobData);\n\n    expect(blob.size).toEqual(blobData[0].length);\n    expect(blob.type).toEqual(\"\");\n  });\n\n  it(\"should create a Blob with an empty array if no data is provided\", () => {\n    // @ts-ignore\n    const blob = new Blob();\n\n    expect(blob.size).toEqual(0);\n    expect(blob.type).toEqual(\"\");\n  });\n\n  it(\"should handle line endings properly\", async () => {\n    const text = \"This\\r\\n is a \\ntest\\r\\n string\";\n\n    // @ts-ignore\n    const blob = new Blob([text], {\n      // @ts-ignore\n      endings: \"native\",\n    });\n\n    expect(blob.type).toEqual(\"\");\n    if (process.platform != \"win32\") {\n      expect(blob.size < text.length).toBeTruthy();\n      expect(await blob.text()).toEqual(text.replace(/\\r\\n/g, \"\\n\"));\n    }\n  });\n\n  it(\"should return an ArrayBuffer with the arrayBuffer() method\", async () => {\n    const blobData = [\"Hello, world!\"];\n    const blob = new Blob(blobData, { type: \"text/plain\" });\n\n    const arrayBuffer = await blob.arrayBuffer();\n\n    expect(arrayBuffer).toBeInstanceOf(ArrayBuffer);\n  });\n\n  it(\"should return an Uint8Array with the bytes() method\", async () => {\n    const blobData = [\"Hello, world!\"];\n    const blob = new Blob(blobData, { type: \"text/plain\" });\n\n    const bytes = await blob.bytes();\n\n    expect(bytes).toBeInstanceOf(Uint8Array);\n  });\n\n  it(\"should return a DataView with the slice method\", () => {\n    const blobData = [\"Hello, world!\"];\n    const blob = new Blob(blobData, { type: \"text/plain\" });\n\n    const slicedBlob = blob.slice(0, 5, \"text/plain\");\n\n    expect(slicedBlob instanceof Blob).toBeTruthy();\n    expect(slicedBlob.size).toEqual(5);\n    expect(slicedBlob.type).toEqual(\"text/plain\");\n  });\n});\n\ndescribe(\"File class\", () => {\n  it(\"should construct a new File\", () => {\n    const file = new File([\"Hello, world!\"], \"hello.txt\", {\n      type: \"text/plain\",\n    });\n\n    expect(file.size).toBe(13);\n    expect(file.type).toBe(\"text/plain\");\n    expect(file.name).toBe(\"hello.txt\");\n  });\n\n  it(\"should return the correct lastModified date\", () => {\n    const fileWithDate = new File([], \"file.bin\", {\n      lastModified: new Date(Date.UTC(2017, 1, 1, 0, 0, 0, 0)).getTime(),\n    });\n    expect(fileWithDate.lastModified).toBe(1485907200000);\n  });\n\n  it(\"has a name\", () => {\n    const file = new File([\"file content\"], \"example.txt\");\n    expect(file.name).toBe(\"example.txt\");\n  });\n\n  it(\"has content\", () => {\n    const file = new File([\"file content\"], \"example.txt\");\n    expect(file.size).toBeGreaterThan(0);\n  });\n\n  it(\"has a size\", () => {\n    const file = new File([\"file content\"], \"example.txt\");\n    expect(file.size).toBeGreaterThan(0);\n  });\n\n  it(\"has a type\", () => {\n    const file = new File([\"file content\"], \"example.txt\", {\n      type: \"text/plain\",\n    });\n    expect(file.type).toBe(\"text/plain\");\n  });\n\n  it(\"has last modified date\", () => {\n    const file = new File([\"file content\"], \"example.txt\");\n    const now = new Date();\n    expect(file.lastModified * 0.9999).toBeLessThanOrEqual(now.getTime());\n  });\n\n  it(\"can slice file\", () => {\n    const file = new File([\"file content\"], \"example.txt\");\n    const slice = file.slice(0, 5);\n    expect(slice).toBeInstanceOf(Blob);\n    expect(slice.size).toBe(5);\n  });\n\n  it(\"can read file as text\", async () => {\n    const file = new File([\"file content\"], \"example.txt\");\n    const text = await file.text();\n    expect(text).toBe(\"file content\");\n  });\n\n  it(\"can read file as arrayBuffer\", async () => {\n    const file = new File([1, 2, 3, 4] as any, \"example.txt\");\n    const arrayBuffer = await file.arrayBuffer();\n    const uint8Array = new Uint8Array(arrayBuffer);\n    expect(Array.from(uint8Array)).toStrictEqual([49, 50, 51, 52]);\n    expect(uint8Array.length).toBe(4);\n  });\n\n  it(\"is an instance of Blob\", () => {\n    const file = new File([\"file content\"], \"example.txt\");\n    expect(file).toBeInstanceOf(Blob);\n  });\n});\n\ndescribe(\"atob\", () => {\n  it(\"should decode basic base64 strings\", () => {\n    expect(atob(\"aGVsbG8gd29ybGQ=\")).toBe(\"hello world\");\n    expect(atob(\"YWJj\")).toBe(\"abc\");\n    expect(atob(\"\")).toBe(\"\");\n  });\n\n  it(\"should handle base64 strings with padding\", () => {\n    expect(atob(\"YQ==\")).toBe(\"a\");\n    expect(atob(\"YWI=\")).toBe(\"ab\");\n    expect(atob(\"YWJj\")).toBe(\"abc\");\n  });\n\n  it(\"should correctly decode high bytes (128-255) as Latin-1 characters\", () => {\n    // Per WHATWG spec, atob returns a \"binary string\" where each character's\n    // code point is 0-255, directly representing one byte of data (Latin-1)\n\n    // Test byte 128 (0x80): base64 \"gA==\"\n    const decoded128 = atob(\"gA==\");\n    expect(decoded128.length).toBe(1);\n    expect(decoded128.charCodeAt(0)).toBe(128);\n\n    // Test byte 255 (0xFF): base64 \"/w==\"\n    const decoded255 = atob(\"/w==\");\n    expect(decoded255.length).toBe(1);\n    expect(decoded255.charCodeAt(0)).toBe(255);\n\n    // Test byte 192 (0xC0): base64 \"wA==\"\n    const decoded192 = atob(\"wA==\");\n    expect(decoded192.length).toBe(1);\n    expect(decoded192.charCodeAt(0)).toBe(192);\n  });\n\n  it(\"should correctly decode all bytes 0-255\", () => {\n    // Create a Uint8Array with all possible byte values\n    const allBytes = new Uint8Array(256);\n    for (let i = 0; i < 256; i++) {\n      allBytes[i] = i;\n    }\n\n    // Encode to base64 and decode with atob\n    const base64 = Buffer.from(allBytes).toString(\"base64\");\n    const decoded = atob(base64);\n\n    // Verify length and each byte\n    expect(decoded.length).toBe(256);\n    for (let i = 0; i < 256; i++) {\n      expect(decoded.charCodeAt(i)).toBe(i);\n    }\n  });\n\n  it(\"should produce same result as Buffer.from for binary data\", () => {\n    // This tests the fix for issue #966 - JWT signature decoding\n    const testCases = [\n      \"gA==\", // 0x80\n      \"/w==\", // 0xFF\n      \"wMDAwA==\", // multiple high bytes\n      \"AAECAwQFBgc=\", // mixed bytes\n    ];\n\n    for (const base64 of testCases) {\n      const atobResult = atob(base64);\n      const bufferResult = Buffer.from(base64, \"base64\");\n\n      expect(atobResult.length).toBe(bufferResult.length);\n      for (let i = 0; i < atobResult.length; i++) {\n        expect(atobResult.charCodeAt(i)).toBe(bufferResult[i]);\n      }\n    }\n  });\n});\n\ndescribe(\"btoa\", () => {\n  it(\"should encode basic strings to base64\", () => {\n    expect(btoa(\"hello world\")).toBe(\"aGVsbG8gd29ybGQ=\");\n    expect(btoa(\"abc\")).toBe(\"YWJj\");\n    expect(btoa(\"\")).toBe(\"\");\n  });\n\n  it(\"should handle strings that need padding\", () => {\n    expect(btoa(\"a\")).toBe(\"YQ==\");\n    expect(btoa(\"ab\")).toBe(\"YWI=\");\n    expect(btoa(\"abc\")).toBe(\"YWJj\");\n  });\n\n  it(\"should roundtrip with atob\", () => {\n    const testStrings = [\"hello\", \"test123\", \"a\", \"ab\", \"abc\"];\n    for (const str of testStrings) {\n      expect(atob(btoa(str))).toBe(str);\n    }\n  });\n\n  it(\"should correctly encode high bytes (128-255) as Latin-1 characters\", () => {\n    // Per WHATWG spec, btoa treats each character as a byte value 0-255\n    // NOT as UTF-8 encoded bytes\n\n    // Test byte 255 (0xFF): btoa(String.fromCharCode(255)) should give \"/w==\"\n    // If incorrectly UTF-8 encoded, it would give \"w78=\" (bytes 0xC3, 0xBF)\n    expect(btoa(String.fromCharCode(255))).toBe(\"/w==\");\n\n    // Test byte 128 (0x80): btoa(String.fromCharCode(128)) should give \"gA==\"\n    expect(btoa(String.fromCharCode(128))).toBe(\"gA==\");\n\n    // Test byte 192 (0xC0): btoa(String.fromCharCode(192)) should give \"wA==\"\n    expect(btoa(String.fromCharCode(192))).toBe(\"wA==\");\n  });\n\n  it(\"should roundtrip all bytes 0-255 with atob\", () => {\n    for (let i = 0; i <= 255; i++) {\n      const char = String.fromCharCode(i);\n      const encoded = btoa(char);\n      const decoded = atob(encoded);\n      expect(decoded.length).toBe(1);\n      expect(decoded.charCodeAt(0)).toBe(i);\n    }\n  });\n\n  it(\"should throw for characters with code point > 255\", () => {\n    // Euro sign (U+20AC)\n    expect(() => btoa(\"€\")).toThrow();\n\n    // Chinese character (U+4E2D)\n    expect(() => btoa(\"中\")).toThrow();\n\n    // Emoji (U+1F600, represented as surrogate pair)\n    expect(() => btoa(\"😀\")).toThrow();\n  });\n});\n"
  },
  {
    "path": "tests/unit/child_process.test.ts",
    "content": "import defaultImport from \"node:child_process\";\nimport legacyImport from \"child_process\";\n\nimport { platform } from \"node:os\";\nimport process from \"node:process\";\nconst IS_WINDOWS = platform() === \"win32\";\n\nit(\"node:child_process should be the same as child_process\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n\nconst { spawn } = defaultImport;\n\ndescribe(\"spawn\", () => {\n  it(\"should spawn a child process\", (done) => {\n    // Use cross-platform commands\n    const command = IS_WINDOWS ? \"cmd\" : \"ls\";\n    const args = IS_WINDOWS ? [\"/c\", \"dir\"] : [\"-l\"];\n    const child = spawn(command, args);\n    child.on(\"exit\", (code) => {\n      try {\n        expect(code).toEqual(0);\n        done();\n      } catch (error) {\n        done(error);\n      }\n    });\n  });\n  it(\"should spawn in a diffrent directory\", (done) => {\n    // Use cross-platform commands for getting current directory\n    const child = IS_WINDOWS\n      ? spawn(\"cmd\", [\"/c\", \"cd\"], { cwd: \"./tests\" })\n      : spawn(\"pwd\", { cwd: \"./tests\" });\n    let output = \"\";\n    child.stdout.on(\"data\", (data) => {\n      output += data.toString();\n    });\n\n    child.on(\"close\", (code) => {\n      try {\n        // Split by either / or \\ for cross-platform compatibility\n        const dir = output.trim().split(/[/\\\\]/).at(-1);\n        expect(dir).toEqual(\"tests\");\n        expect(code).toEqual(0);\n        done();\n      } catch (error) {\n        done(error);\n      }\n    });\n  });\n  it(\"should capture output from the child process\", (done) => {\n    const command = \"echo\";\n    const args = [\"Hello, World!\"];\n    const child = spawn(command, args);\n    let output = \"\";\n    child.stdout.on(\"data\", (data) => {\n      output += data.toString();\n    });\n\n    child.on(\"close\", (code) => {\n      try {\n        expect(output.trim()).toEqual(args[0]);\n        expect(code).toEqual(0);\n        done();\n      } catch (error) {\n        done(error);\n      }\n    });\n  });\n\n  it(\"should send input to the child process\", (done) => {\n    // Use cross-platform approach: Windows uses 'findstr .*' to echo all input, Unix uses 'cat'\n    const command = IS_WINDOWS ? \"findstr\" : \"cat\";\n    const args = IS_WINDOWS ? [\".*\"] : [];\n    const input = \"Hello, world!\";\n    const child = spawn(command, args);\n\n    child.stdin.write(input);\n    child.stdin.end();\n\n    let output = \"\";\n    child.stdout.on(\"data\", (data) => {\n      output += data.toString();\n    });\n\n    child.on(\"close\", (code) => {\n      try {\n        expect(code).toEqual(0);\n        expect(output.trim()).toEqual(input);\n        done();\n      } catch (error) {\n        done(error);\n      }\n    });\n  });\n\n  it(\"should handle errors from the child process\", (done) => {\n    if (process.env._VIRTUAL_ENV) {\n      //QEMU spawns nonexistent-command successfully\n      return done();\n    }\n    const command = \"nonexistent-command\";\n    const child = spawn(command);\n    child.on(\"error\", (err) => {\n      try {\n        expect(err).toBeTruthy();\n        done();\n      } catch (error) {\n        done(error);\n      }\n    });\n  });\n\n  it(\"should handle child process termination\", (done) => {\n    // Use cross-platform long-running command: Windows uses 'ping -n 999 localhost', Unix uses 'sleep 999'\n    const child = IS_WINDOWS\n      ? spawn(\"ping\", [\"-n\", \"999\", \"localhost\"])\n      : spawn(\"sleep\", [\"999\"]);\n\n    child.on(\"exit\", (code, signal) => {\n      try {\n        if (IS_WINDOWS) {\n          // LLRT on Windows returns exit code 1 when killed\n          expect(code).toEqual(1);\n        } else {\n          expect(code).toBeNull();\n        }\n        expect(signal).toEqual(\"SIGKILL\");\n        done();\n      } catch (error) {\n        done(error);\n      }\n    });\n\n    setTimeout(() => {\n      child.kill(\"SIGKILL\"); //SIGINT does not forward to children on Linux\n    }, 50);\n  });\n\n  it(\"should handle child process stdio inherit\", (done) => {\n    const child = spawn(\"echo\", [\"123\"], { stdio: \"inherit\" });\n    child.on(\"exit\", (code) => {\n      try {\n        expect(code).toEqual(0);\n        done();\n      } catch (error) {\n        done(error);\n      }\n    });\n  });\n  it(\"should handle child process stdio ignore\", (done) => {\n    const child = spawn(\"echo\", [\"123\"], { stdio: \"ignore\" });\n    child.on(\"exit\", (code) => {\n      try {\n        expect(code).toEqual(0);\n        done();\n      } catch (error) {\n        done(error);\n      }\n    });\n  });\n\n  it(\"should have a process exitCode\", async () => {\n    const testExitCode = async (\n      exitCodeValue: number | string,\n      expectedCode: number\n    ) => {\n      const proc = spawn(process.argv0, [\n        \"-e\",\n        `process.exitCode = ${exitCodeValue}`,\n      ]);\n      await new Promise<void>((resolve) => {\n        proc.on(\"exit\", (code) => {\n          expect(code).toEqual(expectedCode);\n          resolve();\n        });\n      });\n    };\n\n    await testExitCode(241212341, 181);\n    await testExitCode(-1, 255);\n    await testExitCode(1, 1);\n    await testExitCode(-1231231231, 1);\n    await testExitCode(266, 10);\n    await testExitCode(\"266\", 10);\n  });\n\n  // Skip on Windows - detached process behavior differs significantly\n  (IS_WINDOWS ? it.skip : it)(\n    \"should handle detached child process termination\",\n    (done) => {\n      const sleepCmd = \"spawn('sleep', ['999']\";\n\n      const parentProc = spawn(process.argv0, [\n        \"-e\",\n        `\n        import {spawn} from \"child_process\";\n        const child = ${sleepCmd}, {\n          detached: true,\n          stdio: 'ignore'\n        });\n        console.log(child.pid.toString());\n      `,\n      ]);\n\n      let detachedPidString = \"\";\n      parentProc.stdout.on(\"data\", (data) => {\n        detachedPidString += data.toString();\n        // Kill parent once we have the PID - parent would otherwise wait for detached child\n        parentProc.kill();\n      });\n\n      parentProc.on(\"error\", (err) => {\n        done(err);\n      });\n\n      parentProc.on(\"close\", () => {\n        try {\n          const detachedPid = parseInt(detachedPidString.trim());\n          expect(detachedPid).toBeGreaterThan(0);\n          // Verify detached process survived parent termination\n          const exists = process.kill(detachedPid, 0);\n          expect(exists).toBe(true);\n          // Clean up the detached process\n          process.kill(detachedPid, \"SIGKILL\");\n          done();\n        } catch (error) {\n          done(error);\n        }\n      });\n    }\n  );\n});\n"
  },
  {
    "path": "tests/unit/clone.test.ts",
    "content": "describe(\"structuredClone\", () => {\n  it(\"Clones a simple object\", () => {\n    const originalObject = { foo: \"bar\", num: 42 };\n    const clonedObject = structuredClone(originalObject);\n\n    expect(clonedObject).toStrictEqual(originalObject);\n    originalObject.foo += \"extra\";\n    expect(clonedObject).not.toStrictEqual(originalObject);\n  });\n\n  it(\"Clones an array\", () => {\n    const originalArray = [1, 2, 3, 4, 5];\n    const clonedArray = structuredClone(originalArray);\n    expect(clonedArray).toStrictEqual(originalArray);\n  });\n\n  it(\"Clones an array of objects\", () => {\n    let obj = { foo: \"bar\" };\n    const originalArray = [obj, obj, obj, obj, obj];\n    const clonedArray = structuredClone(originalArray);\n    expect(clonedArray).toStrictEqual(originalArray);\n    expect(clonedArray[0]).not.toBe(originalArray[0]);\n  });\n\n  it(\"Clones nested objects\", () => {\n    const originalObject = { foo: { bar: { baz: \"qux\" } } };\n    const clonedObject = structuredClone(originalObject);\n    expect(clonedObject).toStrictEqual(originalObject);\n  });\n\n  it(\"Handles circular references\", () => {\n    const originalObject: any = { foo: { bar: \"baz\", arr: [1, 2, 3] } };\n    originalObject.foo.circularRef = originalObject;\n    originalObject.foo.circularRef2 = originalObject;\n    originalObject.foo.circularRef3 = originalObject.foo;\n    originalObject.ref2 = originalObject;\n    const clonedObject = structuredClone(originalObject);\n    expect(clonedObject).toStrictEqual(originalObject);\n  });\n\n  it(\"Clones a Map\", () => {\n    const originalMap = new Map([\n      [\"key1\", \"value1\"],\n      [\"key2\", \"value2\"],\n    ]);\n    const clonedMap = structuredClone(originalMap);\n    expect(clonedMap).toStrictEqual(originalMap);\n  });\n\n  it(\"Clones a Set\", () => {\n    const originalSet = new Set([1, 2, 3, 4, 5]);\n    const clonedSet = structuredClone(originalSet);\n    expect(clonedSet).toStrictEqual(originalSet);\n  });\n\n  it(\"Clones a Date object\", () => {\n    const originalDate = new Date(\"2022-01-31T12:00:00Z\");\n    const clonedDate = structuredClone(originalDate);\n    expect(clonedDate.getTime()).toEqual(originalDate.getTime());\n  });\n\n  it(\"Clones a Buffer\", () => {\n    const buffer = Buffer.from(\"hello world\");\n    const clonedBuffer = structuredClone(buffer);\n    expect(clonedBuffer.buffer).toEqual(buffer.buffer);\n    buffer.set([1, 2, 3, 4, 5, 6, 7, 8]);\n    expect(clonedBuffer).not.toStrictEqual(buffer);\n  });\n\n  it(\"Handles transfer list\", () => {\n    const originalObject: any = { foo: { bar: \"baz\", arr: [1, 2, 3] } };\n    const clonedObject1 = structuredClone(originalObject);\n\n    expect(clonedObject1.foo.arr).not.toBe(originalObject.foo.arr);\n\n    const clonedObject2 = structuredClone(originalObject, {\n      transfer: [originalObject.foo.arr],\n    });\n    expect(clonedObject2.foo.arr).toEqual(originalObject.foo.arr);\n  });\n});\n"
  },
  {
    "path": "tests/unit/compile.test.ts",
    "content": "import fs from \"node:fs/promises\";\nimport { tmpdir, platform } from \"node:os\";\nimport { spawnCapture } from \"./test-utils\";\n\nconst IS_WINDOWS = platform() === \"win32\";\n\nconst compile = async (\n  filename: string,\n  outputFilename: string,\n  executable = false\n) => {\n  const args = [\"compile\", filename, outputFilename];\n  if (executable) {\n    args.push(\"--executable\");\n  }\n  const { code, stdout, stderr } = await spawnCapture(process.argv0, args);\n  return { stdout, stderr, status: code, signal: undefined };\n};\n\nconst run = async (filename: string) => {\n  const { code, stdout, stderr } = await spawnCapture(process.argv0, [\n    filename,\n  ]);\n  return { stdout, stderr, status: code };\n};\n\nconst runExecutable = async (filename: string) => {\n  const { code, stdout, stderr } = await spawnCapture(filename, []);\n  return { stdout, stderr, status: code };\n};\n\ndescribe(\"llrt compile\", async () => {\n  const tmpDir = await fs.mkdtemp(`${tmpdir()}/llrt-test-compile`);\n\n  it(\"can compile and run empty\", async () => {\n    const tmpOutput = `${tmpDir}/empty.lrt`;\n\n    const compileResult = await compile(\"fixtures/empty.js\", tmpOutput);\n\n    expect(compileResult.stderr).toEqual(\"\");\n    expect(compileResult.signal).toEqual(undefined);\n\n    const runResult = await run(tmpOutput);\n\n    expect(runResult.stdout).toEqual(\"\");\n    expect(runResult.stderr).toEqual(\"\");\n    expect(runResult.status).toEqual(0);\n  });\n\n  it(\"can compile and run console.log\", async () => {\n    const tmpOutput = `${tmpDir}/console.log.lrt`;\n\n    const compileResult = await compile(\"fixtures/hello.js\", tmpOutput);\n\n    expect(compileResult.stderr).toEqual(\"\");\n    expect(compileResult.signal).toEqual(undefined);\n\n    const runResult = await run(tmpOutput);\n\n    expect(runResult.stdout).toEqual(\"hello world!\\n\");\n    expect(runResult.stderr).toEqual(\"\");\n    expect(runResult.status).toEqual(0);\n  });\n\n  it(\"can compile and run throws\", async () => {\n    const tmpOutput = `${tmpDir}/throws.lrt`;\n\n    const compileResult = await compile(\"fixtures/throw.js\", tmpOutput);\n\n    expect(compileResult.stderr).toEqual(\"\");\n    expect(compileResult.signal).toEqual(undefined);\n\n    const runResult = await run(tmpOutput);\n\n    expect(runResult.stdout).toEqual(\"\");\n    expect(runResult.stderr).toEqual(\"42\\n\");\n    expect(runResult.status).toEqual(1);\n  });\n\n  it(\"can create a self-contained executable\", async () => {\n    // On Windows, executables need .exe extension\n    const tmpExe = IS_WINDOWS\n      ? `${tmpDir}/hello_exe.exe`\n      : `${tmpDir}/hello_exe`;\n\n    // Create a self-contained executable\n    const compileResult = await compile(\"fixtures/hello.js\", tmpExe, true);\n\n    expect(compileResult.stderr).toEqual(\"\");\n    expect(compileResult.signal).toEqual(undefined);\n\n    // Check that the file exists and is executable\n    const stat = await fs.stat(tmpExe);\n    expect(stat.isFile()).toBe(true);\n\n    if (IS_WINDOWS) {\n      // On Windows, verify the file has .exe extension (which makes it executable)\n      expect(tmpExe.endsWith(\".exe\")).toBe(true);\n    } else {\n      // On Unix, verify executable bits are set (0o111 is uga+x)\n      expect(!!(stat.mode & 0o111)).toBe(true);\n    }\n\n    // Verify the executable actually runs correctly on both platforms\n    const runResult = await runExecutable(tmpExe);\n    expect(runResult.stdout).toEqual(\"hello world!\\n\");\n    expect(runResult.status).toEqual(0);\n  });\n\n  afterAll(async () => {\n    await fs.rmdir(tmpDir, { recursive: true });\n  });\n});\n"
  },
  {
    "path": "tests/unit/console.test.ts",
    "content": "import defaultImport from \"node:console\";\nimport legacyImport from \"console\";\n\nimport * as timers from \"node:timers\";\nimport util from \"node:util\";\n\nit(\"node:console should be the same as console\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n\nconst { Console } = defaultImport;\n\nit(\"should format strings correctly\", () => {\n  expect(util.format(\"%s:%s\", \"foo\", \"bar\")).toEqual(\"foo:bar\");\n  expect(util.format(\"█\", \"foo\")).toEqual(\"█ foo\");\n  expect(util.format(1, 2, 3)).toEqual(\"1 2 3\");\n  expect(util.format(\"%% %s\")).toEqual(\"%% %s\");\n  expect(util.format(\"%s:%s\", \"foo\")).toEqual(\"foo:%s\");\n  expect(util.format(\"Hello %%, %s! How are you, %s?\", \"Alice\", \"Bob\")).toEqual(\n    \"Hello %, Alice! How are you, Bob?\"\n  );\n  expect(util.format(\"The %s %d %f. %i\", \"quick\", \"42\", \"3.14\", \"abc\")).toEqual(\n    \"The quick 42 3.14. NaN\"\n  );\n  expect(\n    util.format(\"Unmatched placeholders: %s %x %% %q\", \"one\", \"two\")\n  ).toEqual(\"Unmatched placeholders: one %x % %q two\");\n  expect(\n    util.format(\"Unmatched placeholders: %s\", \"one\", \"two\", \"three\")\n  ).toEqual(\"Unmatched placeholders: one two three\");\n\n  // Should not throw any exceptions\n  console.log(\"%s:%s\", \"foo\", \"bar\");\n});\n\nit(\"should log module\", () => {\n  let module = util.format(timers);\n\n  expect(module).toEqual(\n    `\n{\n  clearInterval: [function: (anonymous)],\n  clearTimeout: [function: (anonymous)],\n  default: {\n    setTimeout: [function: (anonymous)],\n    clearTimeout: [function: (anonymous)],\n    setInterval: [function: (anonymous)],\n    clearInterval: [function: (anonymous)],\n    setImmediate: [function: (anonymous)],\n    queueMicrotask: [function: (anonymous)]\n  },\n  queueMicrotask: [function: (anonymous)],\n  setImmediate: [function: (anonymous)],\n  setInterval: [function: (anonymous)],\n  setTimeout: [function: (anonymous)]\n}\n`.trim()\n  );\n});\nit(\"should log using console object\", () => {\n  const consoleObj = new Console({\n    stdout: process.stdout,\n    stderr: process.stderr,\n  });\n\n  // we check if the log does not throw an exception when called\n  consoleObj.log(\"log\");\n  consoleObj.debug(\"debug\");\n  consoleObj.info(\"info\");\n  consoleObj.assert(false, \"text for assertion should display\");\n  consoleObj.assert(true, \"This text should not be seen\");\n\n  consoleObj.warn(\"warn\");\n  consoleObj.error(\"error\");\n  consoleObj.trace(\"trace\");\n});\n\nit(\"should log complex object\", () => {\n  let date = new Date();\n\n  let func = () => {};\n  let ClassType = class Instance {};\n  let instance = new ClassType();\n\n  const obj = {\n    a: 1,\n    b: \"foo\",\n    c: {\n      d: date,\n      e: [2.2, true, [], {}],\n      f: {\n        g: 1,\n        h: 2,\n        i: 3,\n        j: {\n          k: {\n            l: \"foo\",\n          },\n          m: new Array(1000).fill(0),\n        },\n      },\n      n: [1, 2, 3],\n    },\n    o: {},\n    p: new (class {})(),\n    q: new (class Foo {})(),\n    r: () => {},\n    s: function () {},\n    t: function foo() {},\n    u: func,\n    v: instance,\n    x: ClassType,\n    y: null,\n    z: undefined,\n    1: Symbol.for(\"foo\"),\n    2: new Promise(() => {}),\n    3: {},\n    [3.14]: 1,\n    4: [1, 2, 3],\n    5: Promise.reject(1),\n    6: Promise.resolve(1),\n    abc: 123,\n  };\n\n  // Add a circular reference\n  obj.o = obj;\n\n  const stringObj = util.format(obj);\n\n  expect(stringObj).toEqual(\n    `\n{\n  '1': Symbol(foo),\n  '2': Promise { <pending> },\n  '3': {},\n  '4': [ 1, 2, 3 ],\n  '5': Promise {\n    <rejected> 1\n  },\n  '6': Promise {\n    1\n  },\n  a: 1,\n  b: \\'foo\\',\n  c: {\n    d: ${date.toISOString()},\n    e: [ 2.2, true, [], {} ],\n    f: { g: 1, h: 2, i: 3, j: { k: [Object], m: [Array] } },\n    n: [ 1, 2, 3 ]\n  },\n  o: [Circular],\n  p: {},\n  q: Foo {},\n  r: [function: r],\n  s: [function: s],\n  t: [function: foo],\n  u: [function: func],\n  v: Instance {},\n  x: [class: Instance],\n  y: null,\n  z: undefined,\n  '3.14': 1,\n  abc: 123\n}\n`.trim()\n  );\n});\n\nit(\"should log Proxy object\", () => {\n  const target = { a: 1, b: \"foo\" };\n  const proxy = new Proxy(target, {\n    set(t, p, v) {\n      t[p] = v;\n      return true;\n    },\n  });\n  expect(util.format(proxy)).toEqual(`{\\n  a: 1,\\n  b: 'foo'\\n}`);\n});\n\nit(\"should log Headers\", () => {\n  const headers = new Headers();\n  headers.append(\"foo\", \"bar\");\n  expect(util.format(headers)).toEqual(`Headers {\n  foo: 'bar'\n}`);\n});\n\nit(\"should handle broken utf8 surrogate pairs\", () => {\n  const s = \"🌍🌎🌏\";\n  expect(util.format(s)).toEqual(s);\n  expect(util.format(s.slice(1))).toEqual(\"�🌎🌏\");\n\n  // Test single emoji\n  expect(util.format(\"🌍\")).toEqual(\"🌍\");\n\n  // Test broken surrogate at end\n  expect(util.format(\"abc🌍\".slice(0, 4))).toEqual(\"abc�\");\n\n  // Test multiple broken surrogates\n  const broken = \"🌍\".slice(0, 1) + \"🌎\".slice(0, 1) + \"🌏\";\n  expect(util.format(broken)).toEqual(\"��🌏\");\n\n  // Test mixing regular chars and emojis\n  expect(util.format(\"a🌍b🌎c\")).toEqual(\"a🌍b🌎c\");\n  expect(util.format(\"a🌍b🌎c\".slice(2))).toEqual(\"�b🌎c\");\n});\n"
  },
  {
    "path": "tests/unit/crypto.subtle.test.ts",
    "content": "import type { webcrypto } from \"node:crypto\";\n\nconst DECODER = new TextDecoder();\nconst ENCODER = new TextEncoder();\nconst TEST_MESSAGE = \"This is test message.\";\nconst ENCODED_DATA = ENCODER.encode(TEST_MESSAGE);\n\n// Limited crypto providers (crypto-ring, crypto-graviola) only support digest\nconst LIMITED_CRYPTO = process.env.LLRT_LIMITED_CRYPTO === \"1\";\nconst fullCrypto = LIMITED_CRYPTO ? describe.skip : describe;\n\ndescribe(\"SubtleCrypto digest\", () => {\n  it(\"should calculate correctly SHA-1/256/384/512 digest\", async () => {\n    const parameters: [string, number[]][] = [\n      [\n        \"SHA-1\",\n        [\n          77, 178, 99, 24, 75, 24, 35, 67, 75, 116, 194, 145, 251, 77, 201, 158,\n          163, 128, 52, 146,\n        ],\n      ],\n      [\n        \"SHA-256\",\n        [\n          25, 251, 197, 98, 46, 227, 66, 238, 69, 151, 67, 175, 68, 184, 76,\n          182, 55, 172, 65, 183, 49, 68, 7, 196, 44, 100, 140, 80, 173, 34, 85,\n          162,\n        ],\n      ],\n      [\n        \"SHA-384\",\n        [\n          120, 197, 163, 25, 168, 231, 230, 188, 103, 31, 71, 249, 169, 230,\n          153, 177, 79, 131, 234, 88, 93, 74, 22, 71, 169, 225, 35, 40, 129,\n          238, 168, 107, 148, 105, 238, 23, 160, 190, 147, 195, 162, 135, 202,\n          230, 26, 130, 124, 245,\n        ],\n      ],\n      [\n        \"SHA-512\",\n        [\n          197, 205, 134, 50, 153, 136, 53, 103, 159, 209, 236, 27, 212, 147,\n          229, 162, 64, 1, 116, 206, 59, 187, 12, 223, 135, 121, 147, 143, 26,\n          203, 161, 238, 57, 27, 254, 202, 96, 207, 172, 168, 12, 47, 150, 164,\n          182, 235, 183, 159, 134, 226, 198, 183, 61, 128, 211, 133, 33, 12,\n          168, 19, 139, 120, 80, 145,\n        ],\n      ],\n    ];\n    for (const [name, digest] of parameters) {\n      const result = new Uint8Array(\n        await crypto.subtle.digest(name, ENCODED_DATA)\n      );\n\n      expect(result).toEqual(new Uint8Array(digest));\n    }\n  });\n});\n\nfullCrypto(\"SubtleCrypto generateKey/sign/verify\", () => {\n  // Common test parameters\n  const keyLengths = [128, 192, 256];\n  const hashAlgorithms = [\"SHA-1\", \"SHA-256\", \"SHA-384\", \"SHA-512\"];\n  const curves = [\"P-256\", \"P-384\"];\n  const rsaParams = {\n    modulusLength: 1024,\n    publicExponent: new Uint8Array([0x01, 0x00, 0x01]),\n  };\n\n  it(\"should be processing AES-CBC/AES-CTR/AES-GCM/AES-KW algorithm\", async () => {\n    const aesAlgorithms = [\"AES-CBC\", \"AES-CTR\", \"AES-GCM\"];\n    const aesUsages = [\"encrypt\", \"decrypt\", \"wrapKey\", \"unwrapKey\"];\n    const kwUsages = [\"wrapKey\", \"unwrapKey\"];\n\n    const parameters = aesAlgorithms.flatMap((name) =>\n      keyLengths.map((length) => ({\n        name,\n        length,\n        usages: name === \"AES-KW\" ? kwUsages : aesUsages,\n      }))\n    );\n    for (const t of parameters) {\n      const algorithm = { name: t.name, length: t.length };\n\n      const key = await crypto.subtle.generateKey(\n        algorithm,\n        false,\n        t.usages as webcrypto.KeyUsage[]\n      );\n\n      expect(key.algorithm.name).toEqual(algorithm.name);\n      expect((key.algorithm as any).length).toEqual(algorithm.length);\n      expect(key.extractable).toEqual(false);\n    }\n  });\n\n  it(\"should be processing HMAC algorithm\", async () => {\n    const parameters = hashAlgorithms.map((hash) => ({\n      name: \"HMAC\",\n      hash,\n      usages: [\"sign\", \"verify\"],\n    }));\n\n    for (const t of parameters) {\n      const algorithm = { name: t.name, hash: t.hash };\n\n      const key = (await crypto.subtle.generateKey(\n        algorithm,\n        false,\n        t.usages as webcrypto.KeyUsage[]\n      )) as webcrypto.CryptoKey;\n\n      expect(key.algorithm.name).toEqual(algorithm.name);\n      expect((key.algorithm as any).hash).toEqual({ name: algorithm.hash });\n      expect(key.extractable).toEqual(false);\n    }\n  });\n\n  it(\"should be processing ECDH/ECDSA algorithm\", async () => {\n    const parameters: {\n      name: string;\n      namedCurve: string;\n      usages: string[];\n      hash?: string;\n    }[] = [\n      ...curves.map((curve, i) => ({\n        name: \"ECDSA\",\n        namedCurve: curve,\n        usages: [\"sign\", \"verify\"],\n        hash: i === 0 ? \"SHA-256\" : \"SHA-384\",\n      })),\n      ...curves.map((curve) => ({\n        name: \"ECDH\",\n        namedCurve: curve,\n        usages: [\"deriveKey\", \"deriveBits\"],\n      })),\n    ];\n\n    for (const t of parameters) {\n      const algorithm = { name: t.name, namedCurve: t.namedCurve };\n\n      const { privateKey, publicKey } = await crypto.subtle.generateKey(\n        algorithm,\n        true,\n        t.usages as webcrypto.KeyUsage[]\n      );\n\n      const keyAlgorithm = privateKey.algorithm as any;\n\n      expect(keyAlgorithm.name).toEqual(algorithm.name);\n      expect(keyAlgorithm.namedCurve).toEqual(algorithm.namedCurve);\n      expect(privateKey.extractable).toEqual(true);\n      expect(publicKey.extractable).toEqual(true);\n\n      if (t.usages.includes(\"sign\")) {\n        const signature = await crypto.subtle.sign(\n          {\n            name: t.name,\n            hash: t.hash,\n          },\n          privateKey,\n          ENCODED_DATA\n        );\n        const isValid = await crypto.subtle.verify(\n          {\n            name: t.name,\n            hash: t.hash,\n          },\n          publicKey,\n          signature,\n          ENCODED_DATA\n        );\n\n        expect(isValid).toBeTruthy();\n      }\n    }\n  });\n\n  it(\"should be processing Ed25519 algorithm\", async () => {\n    const parameters = [\n      {\n        name: \"Ed25519\",\n        usages: [\"sign\", \"verify\"],\n      },\n    ];\n\n    for (const t of parameters) {\n      const algorithm = { name: t.name };\n\n      const { privateKey, publicKey } = (await crypto.subtle.generateKey(\n        algorithm,\n        true,\n        t.usages as webcrypto.KeyUsage[]\n      )) as webcrypto.CryptoKeyPair;\n\n      expect(privateKey.algorithm.name).toEqual(algorithm.name);\n      expect(privateKey.extractable).toEqual(true);\n      expect(publicKey.extractable).toEqual(true);\n\n      if (t.usages.includes(\"sign\")) {\n        const signature = await crypto.subtle.sign(\n          { name: t.name },\n          privateKey,\n          ENCODED_DATA\n        );\n        const isValid = await crypto.subtle.verify(\n          { name: t.name },\n          publicKey,\n          signature,\n          ENCODED_DATA\n        );\n\n        expect(isValid).toBeTruthy();\n      }\n    }\n  });\n\n  it(\"should be processing RSA-PSS/RSA-OAEP/RSASSA-PKCS1-v1_5 algorithm\", async () => {\n    const rsaAlgorithms = [\n      {\n        name: \"RSA-PSS\",\n        usages: [\"sign\", \"verify\"],\n      },\n      {\n        name: \"RSA-OAEP\",\n        usages: [\"encrypt\", \"decrypt\", \"wrapKey\", \"unwrapKey\"],\n      },\n      {\n        name: \"RSASSA-PKCS1-v1_5\",\n        usages: [\"sign\", \"verify\"],\n      },\n    ];\n\n    const parameters = rsaAlgorithms.flatMap((algo) =>\n      hashAlgorithms\n        .filter((h) => h !== \"SHA-1\")\n        .map((hash) => ({\n          ...algo,\n          ...rsaParams,\n          hash,\n        }))\n    );\n\n    for (const t of parameters) {\n      const algorithm = {\n        name: t.name,\n        modulusLength: t.modulusLength,\n        publicExponent: t.publicExponent,\n        hash: t.hash,\n      };\n\n      const { privateKey, publicKey } = await crypto.subtle.generateKey(\n        algorithm,\n        true,\n        t.usages as webcrypto.KeyUsage[]\n      );\n\n      const privateKeyAlgorithm = privateKey.algorithm as any;\n      const publicKeyAlgorithm = publicKey.algorithm as any;\n\n      expect(privateKey.algorithm.name).toEqual(t.name);\n      expect(privateKeyAlgorithm.hash).toEqual({ name: algorithm.hash });\n      expect(privateKey.extractable).toEqual(true);\n\n      expect(publicKey.algorithm.name).toEqual(algorithm.name);\n      expect(publicKeyAlgorithm.hash).toEqual({ name: algorithm.hash });\n      expect(publicKey.extractable).toEqual(true);\n\n      if (t.usages?.includes(\"sign\")) {\n        const signature = await crypto.subtle.sign(\n          { name: t.name, saltLength: 32 },\n          privateKey,\n          ENCODED_DATA\n        );\n        const isValid = await crypto.subtle.verify(\n          { name: t.name, saltLength: 32 },\n          publicKey,\n          signature,\n          ENCODED_DATA\n        );\n\n        expect(isValid).toBeTruthy();\n      }\n    }\n  }, 60000);\n});\n\nfullCrypto(\"SubtleCrypto generateKey/encrypt/decrypt\", () => {\n  // Common key lengths and usages for AES algorithms\n  const keyLengths = [128, 192, 256];\n  const commonUsages = [\"encrypt\", \"decrypt\", \"wrapKey\", \"unwrapKey\"];\n\n  it(\"should be processing AES-CBC algorithm\", async () => {\n    const parameters = keyLengths.map((length) => ({\n      name: \"AES-CBC\",\n      length,\n      iv: crypto.getRandomValues(new Uint8Array(16)),\n      usages: commonUsages,\n    }));\n\n    for (const t of parameters) {\n      const algorithm = { name: t.name, length: t.length };\n\n      const key = await crypto.subtle.generateKey(\n        algorithm,\n        false,\n        t.usages as webcrypto.KeyUsage[]\n      );\n\n      expect(key.algorithm.name).toEqual(algorithm.name);\n      expect((key.algorithm as any).length).toEqual(algorithm.length);\n      expect(key.extractable).toEqual(false);\n\n      if (t.usages.includes(\"encrypt\")) {\n        const encryptedData = await crypto.subtle.encrypt(\n          {\n            name: t.name,\n            iv: t.iv,\n          },\n          key,\n          ENCODED_DATA\n        );\n        const decryptedData = await crypto.subtle.decrypt(\n          {\n            name: t.name,\n            iv: t.iv,\n          },\n          key,\n          encryptedData\n        );\n\n        const result = DECODER.decode(decryptedData);\n        expect(result).toEqual(TEST_MESSAGE);\n      }\n    }\n  });\n\n  it(\"should be processing AES-CTR algorithm\", async () => {\n    const counterLengths = [32, 64, 128];\n    const parameters = keyLengths.flatMap((length) =>\n      counterLengths.map((counterLength) => ({\n        name: \"AES-CTR\",\n        length,\n        counter: crypto.getRandomValues(new Uint8Array(16)),\n        counterLength,\n        usages: commonUsages,\n      }))\n    );\n\n    for (const t of parameters) {\n      const algorithm = { name: t.name, length: t.length };\n\n      const key = await crypto.subtle.generateKey(\n        algorithm,\n        false,\n        t.usages as webcrypto.KeyUsage[]\n      );\n\n      const keyAlgorithm = key.algorithm as any;\n\n      expect(key.algorithm.name).toEqual(algorithm.name);\n      expect(keyAlgorithm.length).toEqual(algorithm.length);\n      expect(key.extractable).toEqual(false);\n\n      if (t.usages.includes(\"encrypt\")) {\n        const encryptedData = await crypto.subtle.encrypt(\n          {\n            name: t.name,\n            counter: t.counter,\n            length: t.counterLength,\n          },\n          key,\n          ENCODED_DATA\n        );\n        const decryptedData = await crypto.subtle.decrypt(\n          {\n            name: t.name,\n            counter: t.counter,\n            length: t.counterLength,\n          },\n          key,\n          encryptedData\n        );\n\n        const result = DECODER.decode(decryptedData);\n        expect(result).toEqual(TEST_MESSAGE);\n      }\n    }\n  });\n\n  it(\"should be processing AES-GCM algorithm\", async () => {\n    const parameters = keyLengths.map((length) => ({\n      name: \"AES-GCM\",\n      length,\n      iv: crypto.getRandomValues(new Uint8Array(12)),\n      usages: commonUsages,\n    }));\n\n    for (const t of parameters) {\n      const algorithm = { name: t.name, length: t.length };\n\n      const key = await crypto.subtle.generateKey(\n        algorithm,\n        false,\n        t.usages as webcrypto.KeyUsage[]\n      );\n\n      const keyAlgorithm = key.algorithm as any;\n\n      expect(key.algorithm.name).toEqual(algorithm.name);\n      expect(keyAlgorithm.length).toEqual(algorithm.length);\n      expect(key.extractable).toEqual(false);\n\n      if (t.usages.includes(\"encrypt\")) {\n        const encryptedData = await crypto.subtle.encrypt(\n          {\n            name: t.name,\n            iv: t.iv,\n          },\n          key,\n          ENCODED_DATA\n        );\n        const decryptedData = await crypto.subtle.decrypt(\n          {\n            name: t.name,\n            iv: t.iv,\n          },\n          key,\n          encryptedData\n        );\n\n        const result = DECODER.decode(decryptedData);\n        expect(result).toEqual(TEST_MESSAGE);\n      }\n    }\n  });\n\n  // Caveat: The current RSA implementation is too slow to complete the test within the time limit.\n  it(\"should be processing RSA-OAEP algorithm\", async () => {\n    const hashAlgorithms = [\"SHA-256\", \"SHA-384\", \"SHA-512\"];\n    const parameters = hashAlgorithms.map((hash) => ({\n      name: \"RSA-OAEP\",\n      modulusLength: 2048,\n      publicExponent: new Uint8Array([1, 0, 1]),\n      hash,\n      usages: commonUsages,\n    }));\n\n    for (const t of parameters) {\n      const algorithm = {\n        name: t.name,\n        modulusLength: t.modulusLength,\n        publicExponent: t.publicExponent,\n        hash: t.hash,\n      };\n\n      const { privateKey, publicKey } = (await crypto.subtle.generateKey(\n        algorithm,\n        true,\n        t.usages as webcrypto.KeyUsage[]\n      )) as unknown as webcrypto.CryptoKeyPair;\n\n      const privateKeyAlgorithm = privateKey.algorithm as any;\n      const publicKeyAlgorithm = publicKey.algorithm as any;\n\n      expect(privateKey.algorithm.name).toEqual(t.name);\n      expect(privateKeyAlgorithm.hash).toEqual({ name: algorithm.hash });\n      expect(privateKey.extractable).toEqual(true);\n\n      expect(publicKey.algorithm.name).toEqual(algorithm.name);\n      expect(publicKeyAlgorithm.hash).toEqual({ name: algorithm.hash });\n      expect(publicKey.extractable).toEqual(true);\n\n      if (t.usages.includes(\"encrypt\")) {\n        const encryptedData = await crypto.subtle.encrypt(\n          {\n            name: t.name,\n          },\n          publicKey,\n          ENCODED_DATA\n        );\n        const decryptedData = await crypto.subtle.decrypt(\n          {\n            name: t.name,\n          },\n          privateKey,\n          encryptedData\n        );\n\n        const result = DECODER.decode(decryptedData);\n        expect(result).toEqual(TEST_MESSAGE);\n      }\n    }\n  }, 60000);\n});\n\nfullCrypto(\"SubtleCrypto deriveBits/deriveKey\", () => {\n  it(\"should be processing ECDH algorithm\", async () => {\n    const keyLengths = [128, 192, 256];\n    const algorithms = [\"AES-CBC\", \"AES-CTR\", \"AES-GCM\"];\n\n    const namedCurves = [\"P-256\", \"P-384\"];\n\n    const derivedParams = algorithms.flatMap((name) =>\n      keyLengths.map((length) => ({\n        name,\n        length,\n      }))\n    );\n\n    for (const namedCurve of namedCurves) {\n      // 1. Generate Alice's key pair\n      const aliceKeyPair = await crypto.subtle.generateKey(\n        {\n          name: \"ECDH\",\n          namedCurve,\n        },\n        true, // whether the key is extractable (i.e. can be used in exportKey)\n        [\"deriveKey\", \"deriveBits\"] // can be any combination of \"deriveKey\" and \"deriveBits\"\n      );\n\n      // 2. Generate Bob's key pair\n      const bobKeyPair = await crypto.subtle.generateKey(\n        {\n          name: \"ECDH\",\n          namedCurve,\n        },\n        true,\n        [\"deriveKey\", \"deriveBits\"]\n      );\n\n      for (const derived of derivedParams) {\n        // 4. Alice derives a shared key using Bob's public key\n        const aliceDerivedKey = await crypto.subtle.deriveKey(\n          {\n            name: \"ECDH\",\n            public: bobKeyPair.publicKey,\n          },\n          aliceKeyPair.privateKey,\n          derived,\n          true, // The derived key is extractable\n          [\"encrypt\", \"decrypt\"] // You can specify operations that the derived key will be used for\n        );\n\n        const bobDerivedKey = await crypto.subtle.deriveKey(\n          {\n            name: \"ECDH\",\n            // public: aliceImportKey,\n            public: aliceKeyPair.publicKey,\n          },\n          bobKeyPair.privateKey,\n          derived,\n          true, // The derived key is extractable\n          [\"encrypt\", \"decrypt\"] // You can specify operations that the derived key will be used for\n        );\n\n        // To verify if both Alice and Bob have the same derived key, you can compare them\n        const aliceKeyBuffer = new Uint8Array(\n          await crypto.subtle.exportKey(\"raw\", aliceDerivedKey)\n        );\n        const bobKeyBuffer = new Uint8Array(\n          await crypto.subtle.exportKey(\"raw\", bobDerivedKey)\n        );\n\n        // Compare the raw key buffers to check if the derived keys are equal\n        expect(aliceKeyBuffer).toEqual(bobKeyBuffer);\n      }\n    }\n  });\n\n  it(\"should be processing HKDF algorithm\", async () => {\n    const hkdfSalt = new Uint8Array(16); // Salt value (can be random, but here it's set to all zeros)\n    const hkdfInfo = new TextEncoder().encode(\"HKDF info\"); // Info parameter, can be any label string\n\n    const keyLengths = [128, 192, 256];\n    const algorithms = [\"AES-CBC\", \"AES-CTR\", \"AES-GCM\"];\n    const hashAlgorithms = [\"SHA-1\", \"SHA-256\", \"SHA-384\", \"SHA-512\"];\n\n    const generatedParams = hashAlgorithms.map((hash) => ({\n      name: \"HKDF\",\n      salt: hkdfSalt,\n      info: hkdfInfo,\n      hash,\n    }));\n\n    const derivedParams = algorithms.flatMap((name) =>\n      keyLengths.map((length) => ({\n        name,\n        length,\n      }))\n    );\n\n    // 1. Generate Alice's key pair\n    const aliceKeyPair = await crypto.subtle.generateKey(\n      {\n        name: \"ECDH\",\n        namedCurve: \"P-256\",\n      },\n      true, // whether the key is extractable (i.e. can be used in exportKey)\n      [\"deriveKey\", \"deriveBits\"] // can be any combination of \"deriveKey\" and \"deriveBits\"\n    );\n\n    // 2. Generate Bob's key pair\n    const bobKeyPair = await crypto.subtle.generateKey(\n      {\n        name: \"ECDH\",\n        namedCurve: \"P-256\",\n      },\n      true,\n      [\"deriveKey\", \"deriveBits\"]\n    );\n\n    for (const generated of generatedParams) {\n      for (const derived of derivedParams) {\n        // 4. Alice derives a shared secret using Bob's public key\n        const aliceSharedSecret = await crypto.subtle.deriveBits(\n          {\n            name: \"ECDH\",\n            public: bobKeyPair.publicKey,\n          },\n          aliceKeyPair.privateKey,\n          256 // number of bits to derive\n        );\n\n        // 5. Convert Alice's derived secret to a key using HKDF\n        const aliceImportedKey = await crypto.subtle.importKey(\n          \"raw\",\n          aliceSharedSecret,\n          \"HKDF\",\n          false,\n          [\"deriveKey\"]\n        );\n\n        const aliceDerivedKey = await crypto.subtle.deriveKey(\n          generated,\n          aliceImportedKey,\n          derived,\n          true,\n          [\"encrypt\", \"decrypt\"]\n        );\n\n        const bobSharedSecret = await crypto.subtle.deriveBits(\n          {\n            name: \"ECDH\",\n            public: aliceKeyPair.publicKey,\n          },\n          bobKeyPair.privateKey,\n          256\n        );\n\n        // 8. Convert Bob's derived secret to a key using HKDF\n        const bobImportedKey = await crypto.subtle.importKey(\n          \"raw\",\n          bobSharedSecret,\n          \"HKDF\",\n          false,\n          [\"deriveKey\"]\n        );\n\n        const bobDerivedKey = await crypto.subtle.deriveKey(\n          generated,\n          bobImportedKey,\n          derived,\n          true,\n          [\"encrypt\", \"decrypt\"]\n        );\n\n        // 9. Verify if both derived keys are the same\n        const aliceKeyBuffer = new Uint8Array(\n          await crypto.subtle.exportKey(\"raw\", aliceDerivedKey)\n        );\n        const bobKeyBuffer = new Uint8Array(\n          await crypto.subtle.exportKey(\"raw\", bobDerivedKey)\n        );\n\n        // Compare the raw key buffers to check if the derived keys are equal\n        expect(aliceKeyBuffer).toEqual(bobKeyBuffer);\n      }\n    }\n  });\n\n  it(\"should be processing PBKDF2 algorithm\", async () => {\n    const pbkdf2Salt = new Uint8Array(16); // Salt value (can be random, but here it's set to all zeros)\n    const pbkdf2Iterations = 50; // Number of iterations for PBKDF2\n\n    const hashAlgorithms = [\"SHA-1\", \"SHA-256\", \"SHA-384\", \"SHA-512\"];\n    const generatedParams = hashAlgorithms.map((hash) => ({\n      name: \"PBKDF2\",\n      salt: pbkdf2Salt,\n      iterations: pbkdf2Iterations,\n      hash,\n    }));\n\n    const algorithms = [\"AES-CBC\", \"AES-CTR\", \"AES-GCM\"];\n    const keyLengths = [128, 192, 256];\n    const derivedParams = algorithms.flatMap((name) =>\n      keyLengths.map((length) => ({\n        name,\n        length,\n      }))\n    );\n    //.filter(({ name, length }) => !(name === \"AES-GCM\" && length > 128)); // Only include AES-GCM-128\n    // 1. Generate Alice's key pair\n    const aliceKeyPair = await crypto.subtle.generateKey(\n      {\n        name: \"ECDH\",\n        namedCurve: \"P-256\",\n      },\n      true, // whether the key is extractable (i.e. can be used in exportKey)\n      [\"deriveKey\", \"deriveBits\"] // can be any combination of \"deriveKey\" and \"deriveBits\"\n    );\n\n    // 2. Generate Bob's key pair\n    const bobKeyPair = await crypto.subtle.generateKey(\n      {\n        name: \"ECDH\",\n        namedCurve: \"P-256\",\n      },\n      true,\n      [\"deriveKey\", \"deriveBits\"]\n    );\n\n    for (const generated of generatedParams) {\n      for (const derived of derivedParams) {\n        // 4. Alice derives a shared secret using Bob's public key\n\n        const aliceSharedSecret = await crypto.subtle.deriveBits(\n          {\n            name: \"ECDH\",\n            // public: bobImportKey,\n            public: bobKeyPair.publicKey,\n          },\n          aliceKeyPair.privateKey,\n          256 // number of bits to derive\n        );\n\n        // Use PBKDF2 to generate a derived key from Alice's shared secret\n        const aliceFinalKey = await crypto.subtle.importKey(\n          \"raw\",\n          aliceSharedSecret,\n          \"PBKDF2\",\n          false,\n          [\"deriveKey\"]\n        );\n\n        const aliceDerivedKey = await crypto.subtle.deriveKey(\n          generated,\n          aliceFinalKey,\n          derived,\n          true,\n          [\"encrypt\", \"decrypt\"]\n        );\n\n        const bobSharedSecret = await crypto.subtle.deriveBits(\n          {\n            name: \"ECDH\",\n            public: aliceKeyPair.publicKey,\n          },\n          bobKeyPair.privateKey,\n          256\n        );\n\n        // 8. Convert Bob's derived secret to a key using PBKDF2\n        const bobFinalKey = await crypto.subtle.importKey(\n          \"raw\",\n          bobSharedSecret,\n          \"PBKDF2\",\n          false,\n          [\"deriveKey\"]\n        );\n\n        const bobDerivedKey = await crypto.subtle.deriveKey(\n          generated,\n          bobFinalKey,\n          derived,\n          true,\n          [\"encrypt\", \"decrypt\"]\n        );\n\n        // 9. Verify if both derived keys are the same\n        const aliceKeyBuffer = new Uint8Array(\n          await crypto.subtle.exportKey(\"raw\", aliceDerivedKey)\n        );\n        const bobKeyBuffer = new Uint8Array(\n          await crypto.subtle.exportKey(\"raw\", bobDerivedKey)\n        );\n\n        // Compare the raw key buffers to check if the derived keys are equal\n        expect(aliceKeyBuffer).toEqual(bobKeyBuffer);\n      }\n    }\n  });\n});\n\nfullCrypto(\"SubtileCrypto import/export\", () => {\n  it(\"should export and import keys\", async () => {\n    // Test different key algorithms and formats\n    // Define reusable constants\n    const SYMMETRIC_FORMATS: webcrypto.KeyFormat[] = [\"raw\", \"jwk\"];\n    const ASYMMETRIC_FORMATS: webcrypto.KeyFormat[] = [\"pkcs8\", \"spki\", \"jwk\"];\n    const HASH_ALGORITHMS = [\"SHA-1\", \"SHA-256\", \"SHA-384\", \"SHA-512\"];\n    const EC_CURVES = [\"P-256\", \"P-384\", \"P-521\"];\n    const AES_LENGTHS = [128, 192, 256];\n\n    const algorithms = [\n      // AES algorithms\n      ...[\"AES-CBC\", \"AES-GCM\", \"AES-CTR\"].flatMap((name) =>\n        AES_LENGTHS.map((length) => ({\n          generateParams: {\n            name,\n            length,\n          },\n          usages: [\"encrypt\", \"decrypt\"],\n          formats: SYMMETRIC_FORMATS,\n        }))\n      ),\n\n      // RSA algorithms\n      ...[\"RSASSA-PKCS1-v1_5\", \"RSA-PSS\", \"RSA-OAEP\"].flatMap((name) =>\n        HASH_ALGORITHMS.map((hash) => ({\n          generateParams: {\n            name,\n            modulusLength: 2048,\n            publicExponent: new Uint8Array([1, 0, 1]),\n            hash,\n          },\n          usages:\n            name === \"RSA-OAEP\" ? [\"encrypt\", \"decrypt\"] : [\"sign\", \"verify\"],\n          formats: ASYMMETRIC_FORMATS,\n        }))\n      ),\n\n      // EC algorithms\n      ...[\"ECDSA\", \"ECDH\"].flatMap((name) =>\n        EC_CURVES.map((namedCurve) => ({\n          generateParams: {\n            name,\n            namedCurve,\n          },\n          usages:\n            name === \"ECDH\" ? [\"deriveKey\", \"deriveBits\"] : [\"sign\", \"verify\"],\n          formats: ASYMMETRIC_FORMATS,\n        }))\n      ),\n\n      // HMAC\n      ...HASH_ALGORITHMS.map((hash) => ({\n        generateParams: {\n          name: \"HMAC\",\n          hash,\n        },\n        usages: [\"sign\", \"verify\"],\n        formats: SYMMETRIC_FORMATS,\n      })),\n    ];\n    for (const algorithm of algorithms) {\n      // Generate key\n      const key = (await crypto.subtle.generateKey(\n        algorithm.generateParams,\n        true,\n        algorithm.usages as webcrypto.KeyUsage[]\n      )) as webcrypto.CryptoKeyPair & webcrypto.CryptoKey;\n\n      // For asymmetric keys, test both public and private keys\n      const keys = algorithm.formats.includes(\"spki\")\n        ? [key.publicKey, key.privateKey]\n        : [key];\n\n      for (const k of keys) {\n        for (const format of algorithm.formats) {\n          if (k.type == \"public\" && format == \"pkcs8\") {\n            return;\n          }\n          if (k.type == \"private\" && format == \"spki\") {\n            return;\n          }\n          // Export key\n          const exported = (await crypto.subtle.exportKey(\n            format as any,\n            k\n          )) as any;\n\n          // Import key back\n          const imported = await crypto.subtle.importKey(\n            format as any,\n            exported,\n            algorithm.generateParams,\n            true,\n            algorithm.usages as webcrypto.KeyUsage[]\n          );\n\n          // Export both keys again to compare\n          const exportedOriginal = (await crypto.subtle.exportKey(\n            format as any,\n            k\n          )) as any;\n          const exportedImported = (await crypto.subtle.exportKey(\n            format as any,\n            imported\n          )) as any;\n\n          // Compare the exported keys\n          if (format === \"jwk\") {\n            expect(exportedImported).toEqual(exportedOriginal);\n          } else {\n            const originalBuffer = new Uint8Array(exportedOriginal);\n            const importedBuffer = new Uint8Array(exportedImported);\n            expect(importedBuffer).toEqual(originalBuffer);\n          }\n        }\n      }\n    }\n  }, 30000);\n});\n\nfullCrypto(\"SubtileCrypto wrap/unwrap\", () => {\n  it(\"should wrap and unwrap keys for all supported algorithms\", async () => {\n    // Test parameters\n    const HASH_ALGORITHMS = [\"SHA-1\", \"SHA-256\", \"SHA-384\", \"SHA-512\"];\n    const AES_LENGTHS = [128, 192, 256];\n    const EC_CURVES = [\"P-256\", \"P-384\", \"P-521\"];\n\n    // Wrapping algorithms\n    const wrappingAlgorithms = [\n      // AES-KW\n      ...AES_LENGTHS.map((length) => ({\n        name: \"AES-KW\",\n        generateParams: {\n          name: \"AES-KW\",\n          length,\n        },\n        wrapParams: {\n          name: \"AES-KW\",\n        },\n        usages: [\"wrapKey\", \"unwrapKey\"],\n      })),\n\n      // RSA-OAEP\n      // ...HASH_ALGORITHMS.slice(1).map((hash) => ({\n      //   name: \"RSA-OAEP\",\n      //   generateParams: {\n      //     name: \"RSA-OAEP\",\n      //     modulusLength: 4096,\n      //     publicExponent: new Uint8Array([1, 0, 1]),\n      //     hash,\n      //   },\n      //   wrapParams: {\n      //     name: \"RSA-OAEP\",\n      //   },\n      //   usages: [\"wrapKey\", \"unwrapKey\"],\n      // })),\n    ];\n\n    // Keys to be wrapped\n    const keysToWrap = [\n      // AES keys\n      ...[\"AES-CBC\", \"AES-GCM\", \"AES-CTR\"].flatMap((name) =>\n        AES_LENGTHS.map((length) => ({\n          generateParams: {\n            name,\n            length,\n          },\n          usages: [\"encrypt\", \"decrypt\"],\n        }))\n      ),\n\n      // HMAC keys\n      ...HASH_ALGORITHMS.map((hash) => ({\n        generateParams: {\n          name: \"HMAC\",\n          hash,\n        },\n        usages: [\"sign\", \"verify\"],\n      })),\n\n      // EC keys\n      ...[\"ECDSA\", \"ECDH\"].flatMap((name) =>\n        EC_CURVES.map((namedCurve) => ({\n          generateParams: {\n            name,\n            namedCurve,\n          },\n          usages:\n            name === \"ECDH\" ? [\"deriveKey\", \"deriveBits\"] : [\"sign\", \"verify\"],\n        }))\n      ),\n    ];\n\n    for (const wrappingAlg of wrappingAlgorithms) {\n      // Generate wrapping key pair for RSA-OAEP or single key for AES-KW\n      const wrappingKey = (await crypto.subtle.generateKey(\n        wrappingAlg.generateParams,\n        true,\n        wrappingAlg.usages as webcrypto.KeyUsage[]\n      )) as webcrypto.CryptoKeyPair & webcrypto.CryptoKey;\n\n      for (const keyToWrap of keysToWrap) {\n        // Generate key to be wrapped\n        const originalKey = (await crypto.subtle.generateKey(\n          keyToWrap.generateParams,\n          true,\n          keyToWrap.usages as webcrypto.KeyUsage[]\n        )) as webcrypto.CryptoKeyPair & webcrypto.CryptoKey;\n\n        // For asymmetric keys, test both public and private keys\n        const keysToTest = originalKey.publicKey\n          ? [originalKey.publicKey, originalKey.privateKey]\n          : [originalKey];\n        const usages = keysToTest.map((key) => key.usages);\n\n        for (const [i, keyToTest] of keysToTest.entries()) {\n          const wrappedKey = await crypto.subtle.wrapKey(\n            \"jwk\",\n            keyToTest,\n            wrappingAlg.name === \"RSA-OAEP\"\n              ? wrappingKey.publicKey\n              : wrappingKey,\n            wrappingAlg.wrapParams\n          );\n\n          // Unwrap the key\n          const unwrappedKey = await crypto.subtle.unwrapKey(\n            \"jwk\",\n            wrappedKey,\n            wrappingAlg.name === \"RSA-OAEP\"\n              ? wrappingKey.privateKey\n              : wrappingKey,\n            wrappingAlg.wrapParams,\n            keyToWrap.generateParams,\n            true,\n            usages[i]\n          );\n\n          // Export both keys to compare\n          const originalExported = await crypto.subtle.exportKey(\n            \"jwk\",\n            keyToTest\n          );\n          const unwrappedExported = await crypto.subtle.exportKey(\n            \"jwk\",\n            unwrappedKey\n          );\n\n          expect(originalExported).toEqual(unwrappedExported);\n        }\n      }\n    }\n  }, 30000);\n});\n"
  },
  {
    "path": "tests/unit/crypto.test.ts",
    "content": "import defaultImport from \"node:crypto\";\nimport legacyImport from \"crypto\";\n\nit(\"node:crypto should be the same as crypto\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n\nconst {\n  createHash,\n  createHmac,\n  randomBytes,\n  randomInt,\n  randomUUID,\n  randomFillSync,\n  randomFill,\n  getRandomValues,\n  webcrypto,\n} = defaultImport;\n\ndescribe(\"crypto object/module\", () => {\n  it(\"should have a createHash()\", () => {\n    expect(crypto.createHash).toBeDefined();\n    expect(createHash).toBeDefined();\n  });\n  it(\"should have a createHmac()\", () => {\n    expect(globalThis.crypto.createHmac).toBeDefined();\n    expect(createHmac).toBeDefined();\n  });\n  it(\"should have a randomBytes()\", () => {\n    expect(globalThis.crypto.randomBytes).toBeDefined();\n    expect(randomBytes).toBeDefined();\n  });\n  it(\"should have a randomInt()\", () => {\n    expect(globalThis.crypto.randomInt).toBeDefined();\n    expect(randomInt).toBeDefined();\n  });\n  it(\"should have a randomUUID()\", () => {\n    expect(globalThis.crypto.randomUUID).toBeDefined();\n    expect(randomUUID).toBeDefined();\n  });\n  it(\"should have a randomFillSync()\", () => {\n    expect(globalThis.crypto.randomFillSync).toBeDefined();\n    expect(randomFillSync).toBeDefined();\n  });\n  it(\"should have a randomFill()\", () => {\n    expect(globalThis.crypto.randomFill).toBeDefined();\n    expect(randomFill).toBeDefined();\n  });\n  it(\"should have a webcrypto and should be equal to globalThis.crypto\", () => {\n    expect(webcrypto).toBeDefined();\n    expect(webcrypto === globalThis.crypto).toBeTruthy();\n    expect(webcrypto).toStrictEqual(globalThis.crypto);\n  });\n});\n\ndescribe(\"Hashing\", () => {\n  it(\"should hash to sha256 with b64 encoding\", () => {\n    let hash = createHash(\"sha256\").update(\"message\").digest(\"base64\");\n    expect(hash).toEqual(\"q1MKE+RZFJgrefm34/uplM/R8/si9xzqGvvwK0YMbR0=\");\n  });\n\n  it(\"should hash to sha256 with hex encoding\", () => {\n    let hash = createHash(\"sha256\").update(\"message\").digest(\"hex\");\n    expect(hash).toEqual(\n      \"ab530a13e45914982b79f9b7e3fba994cfd1f3fb22f71cea1afbf02b460c6d1d\"\n    );\n  });\n\n  it(\"should hash to hmac-sha256 with b64 encoding\", () => {\n    let hash = createHmac(\"sha256\", \"key\").update(\"message\").digest(\"base64\");\n    expect(hash).toEqual(\"bp7ym3X//Ft6uuUn1Y/a2y/kLnIZARl2kXNDBl9Y7Uo=\");\n  });\n\n  it(\"should hash to hmac-sha256 with hex encoding\", () => {\n    let hash = createHmac(\"sha256\", \"key\").update(\"message\").digest(\"hex\");\n    expect(hash).toEqual(\n      \"6e9ef29b75fffc5b7abae527d58fdadb2fe42e7219011976917343065f58ed4a\"\n    );\n  });\n});\n\ndescribe(\"random\", () => {\n  it(\"should generate a random buffer synchronously using randomFillSync\", () => {\n    const buffer = randomFillSync(Buffer.alloc(16));\n    expect(buffer.length).toEqual(16);\n  });\n\n  it(\"should generate a random buffer asynchronously using randomFill\", (done) => {\n    randomFill(Buffer.alloc(16), (err, buffer) => {\n      expect(err).toBeNull();\n      expect(buffer.length).toEqual(16);\n      done();\n    });\n  });\n\n  it(\"should generate random bytes synchronously into a Uint8Array using randomFillSync\", () => {\n    const uint8Array = new Uint8Array(16);\n    randomFillSync(uint8Array);\n    expect(uint8Array.length).toEqual(16);\n    for (const byte of uint8Array) {\n      expect(byte >= 0 && byte <= 255).toBeTruthy();\n    }\n  });\n\n  it(\"should generate random bytes asynchronously into a DataView using randomFill\", (done) => {\n    const dataView = new DataView(new ArrayBuffer(32));\n    randomFill(dataView, (err, buffer) => {\n      expect(err).toBeNull();\n      expect(buffer.buffer).toEqual(dataView.buffer);\n      expect(dataView.byteLength).toEqual(32);\n      for (let i = 0; i < 32; i++) {\n        expect(\n          dataView.getUint8(i) >= 0 && dataView.getUint8(i) <= 255\n        ).toBeTruthy();\n      }\n      done();\n    });\n  });\n\n  it(\"should generate a random UUID using randomUUID\", () => {\n    const uuid = randomUUID();\n    expect(uuid.length).toEqual(36);\n    const uuidRegex =\n      /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;\n    expect(uuid).toMatch(uuidRegex);\n  });\n\n  it(\"should generate a random bytes buffer using randomBytes\", () => {\n    const buffer = randomBytes(16);\n    expect(buffer).toBeInstanceOf(Buffer);\n    expect(buffer.length).toEqual(16);\n  });\n\n  it(\"should generate a random int using randomInt\", () => {\n    // Do it 10 times, to make sure we respect min and max\n    for (const number of [...Array(10).keys()]) {\n      const randomInteger = randomInt(\n        Number.MAX_SAFE_INTEGER - 1,\n        Number.MAX_SAFE_INTEGER\n      );\n      expect(typeof randomInteger).toEqual(\"number\");\n      expect(Number.MAX_SAFE_INTEGER - 1).toEqual(randomInteger);\n      expect(typeof randomInteger).toEqual(\"number\");\n    }\n\n    // Do it 20 times to make sure we never get values outside the range\n    for (const number of [...Array(20).keys()]) {\n      const randomInteger = randomInt(0, 5);\n      expect(randomInteger).toBeLessThan(5);\n      expect(randomInteger).toBeGreaterThanOrEqual(0);\n    }\n  });\n\n  it(\"should generate random bytes synchronously into a Int8Array using getRandomValues\", () => {\n    const int8Array = new Int8Array(10);\n    getRandomValues(int8Array);\n    expect(int8Array.length).toEqual(10);\n    for (const byte of int8Array) {\n      expect(byte >= -0x80 && byte <= 0x7f).toBeTruthy();\n    }\n  });\n\n  it(\"should generate random bytes synchronously into a Uint8Array using getRandomValues\", () => {\n    const uint8Array = new Uint8Array(10);\n    getRandomValues(uint8Array);\n    expect(uint8Array.length).toEqual(10);\n    for (const byte of uint8Array) {\n      expect(byte >= 0x00 && byte <= 0xff).toBeTruthy();\n    }\n  });\n\n  it(\"should generate random bytes synchronously into a Uint8ClampedArray using getRandomValues\", () => {\n    const uint8ClampedArray = new Uint8ClampedArray(10);\n    getRandomValues(uint8ClampedArray);\n    expect(uint8ClampedArray.length).toEqual(10);\n    for (const byte of uint8ClampedArray) {\n      expect(byte >= 0x00 && byte <= 0xff).toBeTruthy();\n    }\n  });\n\n  it(\"should generate random bytes synchronously into a Int16Array using getRandomValues\", () => {\n    const int16Array = new Int16Array(10);\n    getRandomValues(int16Array);\n    expect(int16Array.length).toEqual(10);\n    for (const byte of int16Array) {\n      expect(byte >= -0x8000 && byte <= 0x7fff).toBeTruthy();\n    }\n  });\n\n  it(\"should generate random bytes synchronously into a Uint16Array using getRandomValues\", () => {\n    const uint16Array = new Uint16Array(10);\n    getRandomValues(uint16Array);\n    expect(uint16Array.length).toEqual(10);\n    for (const byte of uint16Array) {\n      expect(byte >= 0x0000 && byte <= 0xffff).toBeTruthy();\n    }\n  });\n\n  it(\"should generate random bytes synchronously into a Int32Array using getRandomValues\", () => {\n    const int32Array = new Int32Array(10);\n    getRandomValues(int32Array);\n    expect(int32Array.length).toEqual(10);\n    for (const byte of int32Array) {\n      expect(byte >= -0x80000000 && byte <= 0x7fffffff).toBeTruthy();\n    }\n  });\n\n  it(\"should generate random bytes synchronously into a Uint32Array using getRandomValues\", () => {\n    const uint32Array = new Uint32Array(10);\n    getRandomValues(uint32Array);\n    expect(uint32Array.length).toEqual(10);\n    for (const byte of uint32Array) {\n      expect(byte >= 0x00000000 && byte <= 0xffffffff).toBeTruthy();\n    }\n  });\n\n  it(\"should be an error, if it exceeds 65536 bytes\", () => {\n    const int8Array = new BigInt64Array(65536 / 8 + 1);\n    let errorMessage = \"\";\n    try {\n      getRandomValues(int8Array);\n    } catch (ex: any) {\n      errorMessage = ex.message;\n    }\n    expect(errorMessage).toEqual(\n      \"QuotaExceededError: The requested length exceeds 65,536 bytes\"\n    );\n  });\n});\n"
  },
  {
    "path": "tests/unit/date.test.ts",
    "content": "describe(\"Date.prototype.toLocaleString with timezone\", () => {\n  it(\"should support timeZone option\", () => {\n    const date = new Date(\"2022-03-02T15:45:34Z\");\n\n    const denver = date.toLocaleString(\"en-US\", { timeZone: \"America/Denver\" });\n    const tokyo = date.toLocaleString(\"en-US\", { timeZone: \"Asia/Tokyo\" });\n\n    // Denver should show 8:45 (UTC-7 in March)\n    expect(denver).toContain(\"8:45\");\n    // Tokyo should show March 3 (next day) 00:45 (UTC+9)\n    // CLDR en-US short date format is M/d/yy (no leading zeros)\n    expect(tokyo).toContain(\"3/3\");\n  });\n\n  it(\"should work without timezone option\", () => {\n    const date = new Date(\"2022-03-02T15:45:34Z\");\n    const result = date.toLocaleString();\n\n    expect(typeof result).toBe(\"string\");\n    expect(result.length).toBeGreaterThan(0);\n  });\n\n  it(\"should handle Invalid Date\", () => {\n    const date = new Date(\"invalid\");\n    const result = date.toLocaleString(\"en-US\", { timeZone: \"UTC\" });\n\n    expect(result).toBe(\"Invalid Date\");\n  });\n});\n"
  },
  {
    "path": "tests/unit/dgram.test.ts",
    "content": "import dgram from \"dgram\";\nimport defaultImport from \"node:dgram\";\n\ndescribe(\"dgram module\", () => {\n  it(\"node:dgram should be the same as dgram\", () => {\n    expect(defaultImport).toStrictEqual(dgram);\n  });\n\n  it(\"should export createSocket function\", () => {\n    expect(typeof dgram.createSocket).toBe(\"function\");\n  });\n\n  it(\"should export Socket class\", () => {\n    expect(typeof dgram.Socket).toBe(\"function\");\n  });\n\n  it(\"should create a UDP4 socket\", () => {\n    const socket = dgram.createSocket(\"udp4\");\n    expect(socket).toBeDefined();\n  });\n\n  it(\"should create a UDP6 socket\", () => {\n    const socket = dgram.createSocket(\"udp6\");\n    expect(socket).toBeDefined();\n  });\n\n  it(\"should create a socket with options object\", () => {\n    const socket = dgram.createSocket({ type: \"udp4\" });\n    expect(socket).toBeDefined();\n  });\n\n  it(\"should bind and close a socket\", async () => {\n    const socket = dgram.createSocket(\"udp4\");\n\n    await new Promise<void>((resolve) => {\n      socket.bind(() => {\n        resolve();\n      });\n    });\n\n    const address = socket.address();\n    expect(address).toBeDefined();\n    expect(address.port).toBeGreaterThan(0);\n    expect(address.family).toBe(\"IPv4\");\n\n    await new Promise<void>((resolve) => {\n      socket.close(() => {\n        resolve();\n      });\n    });\n  });\n\n  it(\"should send and receive messages\", async () => {\n    const server = dgram.createSocket(\"udp4\");\n    const client = dgram.createSocket(\"udp4\");\n\n    const testMessage = \"Hello, UDP!\";\n\n    await new Promise<void>((resolve, reject) => {\n      let messageReceived = false;\n\n      server.on(\"message\", (msg, rinfo) => {\n        try {\n          expect(msg.toString()).toBe(testMessage);\n          expect(rinfo.address).toBeDefined();\n          expect(rinfo.port).toBeGreaterThan(0);\n          expect(rinfo.family).toBe(\"IPv4\");\n          messageReceived = true;\n        } catch (err) {\n          reject(err);\n        }\n      });\n\n      server.on(\"listening\", () => {\n        const address = server.address();\n\n        client.send(testMessage, address.port, \"127.0.0.1\", (err) => {\n          if (err) {\n            reject(err);\n          }\n        });\n\n        // Wait a bit for message to arrive\n        setTimeout(() => {\n          try {\n            expect(messageReceived).toBe(true);\n            client.close();\n            server.close();\n            resolve();\n          } catch (err) {\n            reject(err);\n          }\n        }, 100);\n      });\n\n      server.on(\"error\", (err) => {\n        reject(err);\n      });\n\n      server.bind(0); // Bind to random port\n    });\n  }, 5000);\n\n  it(\"should emit listening event\", async () => {\n    const socket = dgram.createSocket(\"udp4\");\n\n    await new Promise<void>((resolve) => {\n      socket.on(\"listening\", () => {\n        const address = socket.address();\n        expect(address).toBeDefined();\n        socket.close();\n        resolve();\n      });\n\n      socket.bind(0);\n    });\n  });\n\n  it(\"should emit close event\", async () => {\n    const socket = dgram.createSocket(\"udp4\");\n\n    await new Promise<void>((resolve) => {\n      socket.on(\"close\", () => {\n        resolve();\n      });\n\n      socket.bind(() => {\n        socket.close();\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "tests/unit/dns.test.ts",
    "content": "import type dns from \"node:dns\";\n\nimport defaultImport from \"node:dns\";\nimport legacyImport from \"dns\";\n\nit(\"node:dns should be the same as dns\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n\nconst { lookup } = defaultImport;\n\n// Promise wrapper for dns.lookup\nconst dnsLookupAsync = (\n  hostname: string,\n  options?: number | dns.LookupOptions\n) =>\n  new Promise<dns.LookupAddress>((resolve, reject) => {\n    lookup(hostname, options as any, (err, address, family) => {\n      if (err) reject(err);\n      else resolve({ address, family });\n    });\n  });\n\ndescribe(\"lookup\", () => {\n  it(\"localhost name resolution should be possible (optionless)\", async () => {\n    const { address, family } = await dnsLookupAsync(\"localhost\");\n    expect(address === \"::1\" || address === \"127.0.0.1\").toBeTruthy();\n    expect(family === 4 || family === 6).toBeTruthy();\n  });\n\n  it(\"localhost name resolution should be possible (integer option)\", async () => {\n    const { address, family } = await dnsLookupAsync(\"localhost\", 4);\n    expect(address).toEqual(\"127.0.0.1\");\n    expect(family).toEqual(4);\n  });\n\n  it(\"localhost name resolution should be possible (record option)\", async () => {\n    const { address, family } = await dnsLookupAsync(\"localhost\", {\n      family: 4,\n    });\n    expect(address).toEqual(\"127.0.0.1\");\n    expect(family).toEqual(4);\n  });\n\n  if (process.platform !== \"linux\") {\n    it(\"Name resolution for localhost2 should result in an error (integer option)\", async () => {\n      await expect(dnsLookupAsync(\"localhost2\", 4)).rejects.toThrow(\"known\");\n    });\n\n    it(\"Name resolution for localhost2 should result in an error (optionless)\", async () => {\n      await expect(dnsLookupAsync(\"localhost2\")).rejects.toThrow(\"known\");\n    });\n\n    it(\"Name resolution for localhost2 should result in an error (record option)\", async () => {\n      await expect(dnsLookupAsync(\"localhost2\", { family: 4 })).rejects.toThrow(\n        \"known\"\n      );\n    });\n  }\n});\n"
  },
  {
    "path": "tests/unit/encoding.test.ts",
    "content": "import hex from \"llrt:hex\";\n\ndescribe(\"llrt:hex\", () => {\n  it(\"should encode/decode text\", () => {\n    let hello = \"hello\";\n    const encoded = new TextEncoder().encode(hello);\n    const decoded = new TextDecoder().decode(encoded);\n\n    expect(decoded).toEqual(hello);\n  });\n\n  it(\"should encode/decode hex\", () => {\n    const byteArray = new TextEncoder().encode(\"hello\");\n    const encoded = hex.encode(byteArray);\n\n    expect(encoded).toEqual(\"68656c6c6f\");\n  });\n});\n\ndescribe(\"atoa & btoa\", () => {\n  it(\"btoa/atob\", () => {\n    const text = \"Hello, world!\";\n    const encodedData = btoa(text);\n    expect(encodedData).toEqual(\"SGVsbG8sIHdvcmxkIQ==\");\n    const decodedData = atob(encodedData);\n    expect(decodedData).toEqual(text);\n  });\n});\n\ndescribe(\"TextDecoder\", () => {\n  it(\"should be able to decode UTF-16LE labels\", () => {\n    const ary_u8 = new Uint8Array([\n      0x48, 0x00, 0xac, 0x20, 0x6c, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x20, 0x00,\n      0x77, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x6c, 0x00, 0x64, 0x00, 0x21, 0x00,\n    ]);\n    const decoded = new TextDecoder(\"UTF-16LE\");\n    expect(decoded.encoding).toEqual(\"utf-16le\");\n    expect(decoded.decode(ary_u8)).toEqual(\"H€llo world!\");\n  });\n\n  it(\"should not be removed BOM\", () => {\n    const smile = \"😄\";\n    const bomPlusSmile = new Uint8Array([0xef, 0xbb, 0xbf, 240, 159, 152, 132]);\n    expect(new TextDecoder(\"utf8\").decode(bomPlusSmile)).toEqual(smile);\n\n    const decoded = new TextDecoder(\"utf8\", { ignoreBOM: true });\n    expect(decoded.encoding).toEqual(\"utf-8\");\n    expect(decoded.ignoreBOM).toBeTruthy();\n    const encoded = new TextEncoder().encode(decoded.decode(bomPlusSmile));\n    expect(encoded).toEqual(bomPlusSmile);\n  });\n\n  it(\"should be generated fatal error\", () => {\n    const illegalString = new Uint8Array([0xff, 0xfe, 0xfd]);\n    try {\n      const decoded = new TextDecoder(\"utf-8\", { fatal: true });\n      expect(decoded.fatal).toBeTruthy();\n      const a = decoded.decode(illegalString);\n    } catch (ex) {\n      expect(ex.message).toEqual(\n        \"invalid utf-8 sequence of 1 bytes from index 0\"\n      );\n    }\n  });\n\n  it(\"should be generated unsupported error\", () => {\n    try {\n      const decoded = new TextDecoder(\"nonexistent_label\");\n    } catch (ex) {\n      expect(ex.message).toEqual(\n        'The \"nonexistent_label\" encoding is not supported'\n      );\n    }\n  });\n});\n\ndescribe(\"TextEncoder\", () => {\n  it(\"should be able to encodeInto of surrogate pair character(Short Array)\", () => {\n    const hono = \"🔥\";\n    const encoded = new TextEncoder();\n\n    const u8Array3 = new Uint8Array(3);\n    const result3 = encoded.encodeInto(hono, u8Array3);\n    expect(result3.read).toEqual(0);\n    expect(result3.written).toEqual(0);\n    expect(u8Array3).toEqual(new Uint8Array([0, 0, 0]));\n  });\n\n  it(\"should be able to encodeInto of surrogate pair character(Equal Length Array)\", () => {\n    const hono = \"🔥\";\n    const encoded = new TextEncoder();\n\n    const u8Array4 = new Uint8Array(4);\n    const result4 = encoded.encodeInto(hono, u8Array4);\n    expect(result4.read).toEqual(2);\n    expect(result4.written).toEqual(4);\n    expect(u8Array4).toEqual(new Uint8Array([240, 159, 148, 165]));\n  });\n\n  it(\"should be able to encodeInto of surrogate pair character(Long Array)\", () => {\n    const hono = \"🔥\";\n    const encoded = new TextEncoder();\n\n    const u8Array5 = new Uint8Array(5);\n    const result5 = encoded.encodeInto(hono, u8Array5);\n    expect(result5.read).toEqual(2);\n    expect(result5.written).toEqual(4);\n    expect(u8Array5).toEqual(new Uint8Array([240, 159, 148, 165, 0]));\n  });\n\n  it(\"should be able to encodeInto and decode\", () => {\n    const hono = \"hono - [炎] means flame🔥 in Japanese\";\n    const encoded = new TextEncoder();\n\n    const u8Array40 = new Uint8Array(40);\n    const resultHono = encoded.encodeInto(hono, u8Array40);\n    expect(resultHono.read).toEqual(36);\n    expect(resultHono.written).toEqual(40);\n    expect(u8Array40).toEqual(\n      new Uint8Array([\n        104, 111, 110, 111, 32, 45, 32, 91, 231, 130, 142, 93, 32, 109, 101, 97,\n        110, 115, 32, 102, 108, 97, 109, 101, 240, 159, 148, 165, 32, 105, 110,\n        32, 74, 97, 112, 97, 110, 101, 115, 101,\n      ])\n    );\n    expect(new TextDecoder().decode(u8Array40)).toEqual(hono);\n  });\n});\n"
  },
  {
    "path": "tests/unit/events.test.ts",
    "content": "import defaultImport from \"node:events\";\nimport legacyImport from \"events\";\n\nit(\"node:events should be the same as events\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n\nconst sleep = (millis: number) => new Promise((cb) => setTimeout(cb, millis));\n\nconst { EventEmitter } = defaultImport;\n\ndescribe(\"EventEmitter\", () => {\n  it(\"should use custom EventEmitter\", () => {\n    let called = 0;\n    const symbolA = Symbol();\n    const symbolB = Symbol();\n    const symbolC = Symbol();\n    const callback = () => {\n      called++;\n    };\n\n    class MyEmitter extends EventEmitter {}\n    const myEmitter = new MyEmitter();\n    const myEmitter2 = new MyEmitter();\n\n    myEmitter.once(\"event\", function (a, b) {\n      expect(a).toEqual(\"a\");\n      expect(b).toEqual(\"b\");\n      // @ts-ignore\n      expect(this instanceof MyEmitter).toBeTruthy();\n      // @ts-ignore\n      expect(this === myEmitter).toBeTruthy();\n      // @ts-ignore\n      expect(this !== myEmitter2).toBeTruthy();\n      called++;\n    });\n\n    myEmitter.on(symbolA, callback);\n    myEmitter.on(symbolB, callback);\n    myEmitter.on(symbolC, callback);\n\n    myEmitter.emit(\"event\", \"a\", \"b\");\n    myEmitter.emit(symbolA);\n    myEmitter.emit(symbolB);\n    myEmitter.emit(symbolC);\n\n    expect(called).toEqual(4);\n    expect(myEmitter.eventNames()).toEqual([symbolA, symbolB, symbolC]);\n\n    myEmitter.off(symbolB, callback);\n\n    myEmitter.emit(\"event\", \"a\", \"b\");\n    myEmitter.emit(symbolA);\n    myEmitter.emit(symbolB);\n    myEmitter.emit(symbolC);\n\n    expect(called).toEqual(6);\n    expect(myEmitter.eventNames()).toEqual([symbolA, symbolC]);\n  });\n\n  it(\"should prepend event listeners\", async () => {\n    const myEmitter = new EventEmitter();\n\n    const eventsArray: string[] = [];\n\n    myEmitter.addListener(\"event\", () => {\n      eventsArray.push(\"added first\");\n    });\n    myEmitter.prependListener(\"event\", () => {\n      eventsArray.push(\"added to beginning\");\n    });\n    myEmitter.addListener(\"event\", () => {\n      eventsArray.push(\"last\");\n    });\n    myEmitter.prependListener(\"event\", () => {\n      eventsArray.push(\"even before that\");\n    });\n\n    myEmitter.emit(\"event\");\n\n    expect(eventsArray).toEqual([\n      \"even before that\",\n      \"added to beginning\",\n      \"added first\",\n      \"last\",\n    ]);\n  });\n\n  it(\"should handle crash in event handler\", () => {\n    const emitter = new EventEmitter();\n\n    emitter.on(\"data\", () => {\n      throw new Error(\"error\");\n    });\n\n    expect(() => {\n      emitter.emit(\"data\", 123);\n    }).toThrow();\n  });\n\n  it(\"should handle events emitted recursively\", (done) => {\n    const ee = new EventEmitter();\n\n    ee.on(\"test\", () => {\n      ee.emit(\"test2\");\n    });\n\n    ee.on(\"test2\", done);\n\n    ee.emit(\"test\");\n  });\n});\n\ndescribe(\"AbortSignal & AbortController\", () => {\n  it(\"should set abort reason on AbortSignal\", () => {\n    const abortController = new AbortController();\n    const signal = abortController.signal;\n\n    abortController.abort(\"cancelled\");\n\n    expect(signal.aborted).toEqual(true);\n    expect(signal.reason).toEqual(\"cancelled\");\n  });\n\n  it(\"should throw DomException on timeout\", async () => {\n    const signal = AbortSignal.timeout(5);\n    expect(signal.aborted).toBe(false);\n\n    await sleep(10);\n    expect(signal.aborted).toBe(true);\n    //@ts-ignore\n    expect(signal.reason).toBeInstanceOf(DOMException);\n    expect(signal.reason.name).toBe(\"TimeoutError\");\n  });\n\n  it(\"should abort if any signal is aborted asynchronously\", async () => {\n    let signal = AbortSignal.timeout(5);\n    let ctrl = new AbortController();\n    //@ts-ignore\n    let new_signal: AbortSignal = AbortSignal.any([signal, ctrl.signal]);\n\n    expect(new_signal.aborted).toBe(false);\n\n    await sleep(10);\n    expect(new_signal.aborted).toBe(true);\n  });\n\n  it(\"should only emit aborted once\", () => {\n    let ctrl = new AbortController();\n    let count = 0;\n    ctrl.signal.onabort = () => {\n      count++;\n    };\n    expect(ctrl.signal.onabort).toEqual(expect.any(Function));\n    ctrl.abort();\n    expect(ctrl.signal.onabort).toEqual(expect.any(Function)); //keep listener\n    ctrl.abort();\n    ctrl.abort();\n    expect(count).toBe(1);\n  });\n});\n\ndescribe(\"EventTarget\", () => {\n  it(\"should execute event listeners\", () => {\n    const myTarget = new EventTarget();\n\n    const eventsArray: string[] = [];\n\n    myTarget.addEventListener(\"event\", () => {\n      eventsArray.push(\"1st\");\n    });\n    myTarget.addEventListener(\n      \"event\",\n      () => {\n        eventsArray.push(\"2nd\");\n      },\n      { once: true }\n    );\n\n    myTarget.dispatchEvent(new CustomEvent(\"event\"));\n    expect(eventsArray).toEqual([\"1st\", \"2nd\"]);\n\n    myTarget.dispatchEvent(new CustomEvent(\"event\"));\n    expect(eventsArray).toEqual([\"1st\", \"2nd\", \"1st\"]);\n  });\n});\n\ndescribe(\"Event\", () => {\n  it(\"globalThis should have a Event\", () => {\n    const myEvent = new Event(\"test\");\n\n    expect(myEvent.type).toEqual(\"test\");\n    expect(myEvent.bubbles).toBeFalsy();\n    expect(myEvent.cancelable).toBeFalsy();\n    expect(myEvent.composed).toBeFalsy();\n  });\n  it(\"Event should have options\", () => {\n    const myEvent = new Event(\"test\", {\n      bubbles: true,\n      cancelable: true,\n      composed: true,\n    });\n\n    expect(myEvent.bubbles).toBeTruthy();\n    expect(myEvent.cancelable).toBeTruthy();\n    expect(myEvent.composed).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "tests/unit/exceptions.test.ts",
    "content": "describe(\"globalThis\", () => {\n  it(\"globalThis should have a DOMException\", () => {\n    expect(new globalThis.DOMException()).toBeDefined();\n  });\n  it(\"globalThis.DOMException() should have a message\", () => {\n    expect(new globalThis.DOMException().message).toBeDefined();\n  });\n  it(\"globalThis.DOMException() should have a name\", () => {\n    expect(new globalThis.DOMException().name).toBeDefined();\n  });\n  it(\"globalThis.DOMException() should have a stack\", () => {\n    expect(new globalThis.DOMException().stack).toBeDefined();\n  });\n  it(\"globalThis.DOMException() should have a toString()\", () => {\n    expect(new globalThis.DOMException().toString()).toBeDefined();\n  });\n});\n\ndescribe(\"DOMException()\", () => {\n  const e = new DOMException();\n\n  it(\"should have a message\", () => {\n    expect(e.message).toBeDefined();\n  });\n  it(\"message should be the initial value\", () => {\n    expect(e.message).toEqual(\"\");\n  });\n  it(\"should have a name\", () => {\n    expect(e.name).toBeDefined();\n  });\n  it(\"name should be the initial value\", () => {\n    expect(e.name).toEqual(\"Error\");\n  });\n  it(\"should have a stack\", () => {\n    expect(e.stack).toBeDefined();\n  });\n  it(\"should have a toString()\", () => {\n    expect(e.toString()).toBeDefined();\n  });\n  it(\"toString() should return the string 'Error'\", () => {\n    expect(e.toString()).toEqual(\"Error\");\n  });\n  it(\"message should be the same for thrown and caught exceptions\", () => {\n    try {\n      throw new DOMException();\n    } catch (ex) {\n      expect(ex.message).toEqual(\"\");\n    }\n  });\n  it(\"name should be the same for thrown and caught exceptions\", () => {\n    try {\n      throw new DOMException();\n    } catch (ex) {\n      expect(ex.name).toEqual(\"Error\");\n    }\n  });\n});\n\ndescribe(\"DOMException('abc')\", () => {\n  const e = new DOMException(\"abc\");\n\n  it(\"message should be the string 'abc'\", () => {\n    expect(e.message).toEqual(\"abc\");\n  });\n  it(\"name should be the initial value\", () => {\n    expect(e.name).toEqual(\"Error\");\n  });\n  it(\"toString() should return the string 'Error: abc'\", () => {\n    expect(e.toString()).toEqual(\"Error: abc\");\n  });\n  it(\"message should be the same for thrown and caught exceptions\", () => {\n    try {\n      throw new DOMException(\"abc\");\n    } catch (ex) {\n      expect(ex.message).toEqual(\"abc\");\n    }\n  });\n  it(\"name should be the same for thrown and caught exceptions\", () => {\n    try {\n      throw new DOMException(\"abc\");\n    } catch (ex) {\n      expect(ex.name).toEqual(\"Error\");\n    }\n  });\n});\n\ndescribe(\"DOMException('abc', 'def')\", () => {\n  const e = new DOMException(\"abc\", \"def\");\n\n  it(\"message should be the string 'abc'\", () => {\n    expect(e.message).toEqual(\"abc\");\n  });\n  it(\"name should be the string 'def'\", () => {\n    expect(e.name).toEqual(\"def\");\n  });\n  it(\"toString() should return the string 'def: abc'\", () => {\n    expect(e.toString()).toEqual(\"def: abc\");\n  });\n  it(\"message should be the same for thrown and caught exceptions\", () => {\n    try {\n      throw new DOMException(\"abc\", \"def\");\n    } catch (ex) {\n      expect(ex.message).toEqual(\"abc\");\n    }\n  });\n  it(\"name should be the same for thrown and caught exceptions\", () => {\n    try {\n      throw new DOMException(\"abc\", \"def\");\n    } catch (ex) {\n      expect(ex.name).toEqual(\"def\");\n    }\n  });\n});\n"
  },
  {
    "path": "tests/unit/executable.test.ts",
    "content": "import {\n  access,\n  constants,\n  mkdtemp,\n  readFile,\n  rm,\n  stat,\n  writeFile,\n} from \"node:fs/promises\";\nimport { platform, tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { spawnCapture } from \"./test-utils\";\n\nconst TIMEOUT = 30000;\nconst IS_WINDOWS = platform() === \"win32\";\n\nconst compile = async (\n  filename: string,\n  outputFilename: string\n): Promise<void> => {\n  const args = [\"compile\", filename, outputFilename, \"--executable\"];\n  const { code: compileResult } = await spawnCapture(process.argv0, args);\n  if (compileResult !== 0) {\n    throw new Error(`Compilation failed with exit code ${compileResult}`);\n  }\n};\n\nconst run = async (\n  filename: string,\n  args: string[] = []\n): Promise<{ code: number; output: string }> => {\n  const { code, stdout, stderr } = await spawnCapture(filename, args);\n  return { code, output: stdout + stderr };\n};\n\ndescribe(\"executable compilation\", () => {\n  let tmpDir: string;\n  let exePath: string;\n\n  const createTestScript = async (content: string): Promise<string> => {\n    const scriptPath = join(tmpDir, \"exe_test.js\");\n    await writeFile(scriptPath, content, \"utf8\");\n    return scriptPath;\n  };\n\n  beforeEach(async () => {\n    tmpDir = await mkdtemp(join(tmpdir(), \"llrt-test-compile\"));\n    exePath = join(tmpDir, \"exe_test\");\n  });\n\n  afterEach(async () => {\n    //await rm(tmpDir, { force: true, recursive: true });\n  });\n\n  it(\n    \"should compile JavaScript to a self-contained executable\",\n    async () => {\n      const scriptPath = await createTestScript(\n        \"console.log('test'); process.exit(0);\"\n      );\n\n      await compile(scriptPath, exePath);\n\n      const stats = await stat(exePath);\n\n      if (!stats.isFile()) {\n        throw new Error(\"Created file is not a regular file\");\n      }\n      if (stats.size <= 0) {\n        throw new Error(\"Created file is empty\");\n      }\n\n      if (!IS_WINDOWS) {\n        await access(exePath, constants.X_OK);\n      }\n      const { code: execResult, output } = await run(exePath);\n      if (output.trim() !== \"test\") {\n        throw new Error(`Expected output 'test', got '${output}'`);\n      }\n      if (execResult !== 0) {\n        throw new Error(`Expected exit code 0, got ${execResult}`);\n      }\n    },\n    TIMEOUT\n  );\n\n  it(\n    \"should result in the correct exit code\",\n    async () => {\n      const scriptPath = await createTestScript(\n        \"console.log('exiting'); process.exit(42);\"\n      );\n      await compile(scriptPath, exePath);\n\n      const { code: execResult, output } = await run(exePath);\n      if (output.trim() !== \"exiting\") {\n        throw new Error(`Expected output 'exiting', got '${output}'`);\n      }\n      if (execResult !== 42) {\n        throw new Error(`Expected exit code 42, got ${execResult}`);\n      }\n    },\n    TIMEOUT\n  );\n\n  it(\n    \"should result in the correct exit code passed via argument\",\n    async () => {\n      const scriptPath = await createTestScript(\n        \"console.log('arg:', process.argv[1]); process.exit(process.argv[1]);\"\n      );\n      await compile(scriptPath, exePath);\n\n      const { code: execResult, output } = await run(exePath, [\"1\"]);\n      if (output.trim() !== \"arg: 1\") {\n        throw new Error(`Expected output 'arg: 1', got '${output}'`);\n      }\n      if (execResult !== 1) {\n        throw new Error(`Expected exit code 1, got ${execResult}`);\n      }\n    },\n    TIMEOUT\n  );\n\n  it(\n    \"should log output from the executable\",\n    async () => {\n      const testOutput = \"test content\";\n      const scriptPath = await createTestScript(`\n        console.log('${testOutput}');\n      `);\n\n      await compile(scriptPath, exePath);\n\n      const { code: execResult, output } = await run(exePath);\n      if (execResult !== 0) {\n        throw new Error(`Expected exit code 0, got ${execResult}`);\n      }\n\n      if (output.trim() !== testOutput) {\n        throw new Error(\n          `Expected output to be '${testOutput}', but got '${output}'`\n        );\n      }\n    },\n    TIMEOUT\n  );\n});\n"
  },
  {
    "path": "tests/unit/fetch.formdata.test.ts",
    "content": "describe(\"FormData class\", () => {\n  it(\"should append and get string values\", () => {\n    const fd = new FormData();\n\n    fd.append(\"name\", \"Alice\");\n    fd.append(\"age\", \"30\");\n\n    expect(fd.get(\"name\")).toEqual(\"Alice\");\n    expect(fd.get(\"age\")).toEqual(\"30\");\n  });\n\n  it(\"should store Blob and File values correctly\", () => {\n    const fd = new FormData();\n\n    const blob = new Blob([\"hello\"], { type: \"text/plain\" });\n    const file = new File([\"123\"], \"test.txt\", { type: \"text/plain\" });\n\n    fd.append(\"blob\", blob);\n    fd.append(\"file\", file);\n\n    expect(fd.get(\"blob\")).toBeInstanceOf(Blob);\n    expect(fd.get(\"file\")).toBeInstanceOf(File);\n    expect(fd.get(\"file\").name).toEqual(\"test.txt\");\n  });\n\n  it(\"should overwrite existing keys when set() is used\", () => {\n    const fd = new FormData();\n\n    fd.append(\"color\", \"red\");\n    fd.set(\"color\", \"blue\");\n\n    expect(fd.get(\"color\")).toEqual(\"blue\");\n  });\n\n  it(\"should delete an entry when delete() is called\", () => {\n    const fd = new FormData();\n    fd.append(\"token\", \"abc123\");\n    expect(fd.has(\"token\")).toBeTruthy();\n\n    fd.delete(\"token\");\n    expect(fd.has(\"token\")).toBeFalsy();\n  });\n\n  it(\"should correctly report if a key exists using has()\", () => {\n    const fd = new FormData();\n    fd.append(\"flag\", \"true\");\n\n    expect(fd.has(\"flag\")).toBeTruthy();\n    expect(fd.has(\"missing\")).toBeFalsy();\n  });\n\n  it(\"should return all keys with keys()\", () => {\n    const fd = new FormData();\n    fd.append(\"a\", \"1\");\n    fd.append(\"b\", \"2\");\n\n    const keys = fd.keys();\n    expect(keys).toContain(\"a\");\n    expect(keys).toContain(\"b\");\n  });\n\n  it(\"should return all values with values()\", () => {\n    const fd = new FormData();\n    fd.append(\"a\", \"apple\");\n    fd.append(\"b\", \"banana\");\n\n    const values = fd.values();\n    expect(values).toContain(\"apple\");\n    expect(values).toContain(\"banana\");\n  });\n\n  it(\"should iterate entries() properly\", () => {\n    const fd = new FormData();\n    fd.append(\"x\", \"100\");\n    fd.append(\"y\", \"200\");\n\n    const collected = Array.from(fd.entries());\n    expect(collected).toEqual([\n      [\"x\", \"100\"],\n      [\"y\", \"200\"],\n    ]);\n  });\n\n  it(\"should call forEach() for all entries in order\", () => {\n    const fd = new FormData();\n    fd.append(\"a\", \"1\");\n    fd.append(\"b\", \"2\");\n\n    const result = [];\n    fd.forEach((value, key) => {\n      result.push([key, value]);\n    });\n\n    expect(result).toEqual([\n      [\"a\", \"1\"],\n      [\"b\", \"2\"],\n    ]);\n  });\n\n  it(\"should handle multiple values for the same key using append()\", () => {\n    const fd = new FormData();\n    fd.append(\"tag\", \"news\");\n    fd.append(\"tag\", \"tech\");\n\n    const all = fd.getAll(\"tag\");\n    expect(all).toEqual([\"news\", \"tech\"]);\n  });\n});\n"
  },
  {
    "path": "tests/unit/fetch.headers.test.ts",
    "content": "describe(\"Headers class\", () => {\n  it(\"should construct a new Headers object with the provided headers\", () => {\n    const headers = { \"content-type\": \"application/json\" };\n    const h = new Headers(headers);\n    expect(h.get(\"Content-Type\")).toEqual(headers[\"content-type\"]);\n  });\n\n  it(\"should add headers to the Headers object\", () => {\n    const h = new Headers();\n    h.set(\"Content-Type\", \"application/json\");\n    expect(h.get(\"Content-Type\")).toEqual(\"application/json\");\n  });\n\n  it(\"should overwrite headers in the Headers object\", () => {\n    const headers = { \"Content-Type\": \"application/json\" };\n    const h = new Headers(headers);\n    h.set(\"Content-Type\", \"text/plain\");\n    expect(h.get(\"Content-Type\")).toEqual(\"text/plain\");\n  });\n\n  it(\"should delete headers from the Headers object\", () => {\n    const headers = { \"Content-Type\": \"application/json\" };\n    const h = new Headers(headers);\n    h.delete(\"Content-Type\");\n    expect(h.get(\"Content-Type\")).toBeNull();\n  });\n\n  it(\"should return an iterator over the headers\", () => {\n    const headers = {\n      \"content-type\": \"application/json\",\n      authorization: \"Bearer 1234\",\n    };\n    const h = new Headers(headers);\n    h.append(\"set-cookie\", \"AAA=123; expires=Sun, 10-Nov-2024 12:29:35 GMT\");\n    h.append(\"set-cookie\", \"BBB=456; expires=Sun, 10-Nov-2024 12:29:35 GMT\");\n\n    const iterator = h.entries();\n    let next = iterator.next();\n    expect(next.value).toStrictEqual([\"authorization\", \"Bearer 1234\"]);\n    next = iterator.next();\n    expect(next.value).toStrictEqual([\"content-type\", \"application/json\"]);\n    next = iterator.next();\n    expect(next.value).toStrictEqual([\n      \"set-cookie\",\n      \"AAA=123; expires=Sun, 10-Nov-2024 12:29:35 GMT\",\n    ]);\n    next = iterator.next();\n    expect(next.value).toStrictEqual([\n      \"set-cookie\",\n      \"BBB=456; expires=Sun, 10-Nov-2024 12:29:35 GMT\",\n    ]);\n    next = iterator.next();\n    expect(next.value).toStrictEqual(undefined);\n  });\n\n  it(\"should iterate over the headers with forEach\", () => {\n    const headers = {\n      \"content-type\": \"application/json\",\n    };\n    const h = new Headers(headers);\n    h.forEach((value, key) => {\n      expect(key).toStrictEqual(\"content-type\");\n      expect(value).toStrictEqual(\"application/json\");\n    });\n  });\n\n  it(\"should be returned as array type of string\", () => {\n    const h = new Headers();\n    h.append(\"set-cookie\", \"AAA=123; expires=Sun, 10-Nov-2024 12:29:35 GMT\");\n    h.append(\"set-cookie\", \"BBB=456; expires=Sun, 10-Nov-2024 12:29:35 GMT\");\n    expect(h.getSetCookie()).toStrictEqual([\n      \"AAA=123; expires=Sun, 10-Nov-2024 12:29:35 GMT\",\n      \"BBB=456; expires=Sun, 10-Nov-2024 12:29:35 GMT\",\n    ]);\n  });\n\n  it(\"should be returned as a semicolon-delimited string\", () => {\n    const h = new Headers();\n    h.append(\"cookie\", \"AAA=123\");\n    h.append(\"cookie\", \"BBB=456\");\n    expect(h.get(\"cookie\")).toStrictEqual(\"AAA=123; BBB=456\");\n  });\n\n  it(\"should be returned as a comma-delimited string\", () => {\n    const h = new Headers();\n    h.append(\"accept-encoding\", \"zstd\");\n    h.append(\"accept-encoding\", \"br\");\n    expect(h.get(\"accept-encoding\")).toStrictEqual(\"zstd, br\");\n  });\n});\n"
  },
  {
    "path": "tests/unit/fetch.request.test.ts",
    "content": "describe(\"Request class\", () => {\n  it(\"should construct a new Request object with the provided URL\", () => {\n    const url = \"https://example.com\";\n    const request = new Request(url);\n    expect(request.url).toEqual(url);\n  });\n\n  it(\"should set the method to GET by default\", () => {\n    const request = new Request(\"https://example.com\");\n    expect(request.method).toEqual(\"GET\");\n  });\n\n  it(\"should set the mode to cors by default\", () => {\n    const request = new Request(\"https://example.com\");\n    expect(request.mode).toEqual(\"cors\");\n  });\n\n  it(\"should set the cache to no-store by default\", () => {\n    const request = new Request(\"https://example.com\");\n    expect(request.cache).toEqual(\"no-store\");\n  });\n\n  it(\"should set the bodyUsed to false by default\", () => {\n    const request = new Request(\"https://example.com\");\n    expect(request.bodyUsed).toBeFalsy();\n  });\n\n  it(\"should set the method to the provided value\", () => {\n    const method = \"POST\";\n    const request = new Request(\"https://example.com\", { method });\n    expect(request.method).toEqual(method);\n  });\n\n  it(\"should set the headers to an empty object by default\", () => {\n    const request = new Request(\"https://example.com\");\n    const headers = new Headers();\n    expect(request.headers.entries()).toEqual(headers.entries());\n  });\n\n  it(\"should set the headers to the provided value\", () => {\n    const headers = { \"Content-Type\": \"application/json\" };\n    const headerValue = new Headers(headers);\n    const request = new Request(\"https://example.com\", { headers });\n    expect(request.headers).toStrictEqual(headerValue);\n  });\n\n  it(\"should set the body to null by default\", () => {\n    const request = new Request(\"https://example.com\");\n    expect(request.body).toEqual(null);\n  });\n\n  it(\"should set the body to the provided value\", () => {\n    const body = \"hello world!\";\n    const request = new Request(\"https://example.com\", {\n      body,\n      method: \"POST\",\n    });\n    expect(request.body).toStrictEqual(body);\n    expect(request.bodyUsed).toBeFalsy();\n  });\n\n  it(\"should accept another request object as argument\", () => {\n    const oldRequest = new Request(\"https://example.com\", {\n      headers: { From: \"webmaster@example.org\" },\n    });\n    expect(oldRequest.headers.get(\"From\")).toEqual(\"webmaster@example.org\");\n    const newRequest = new Request(oldRequest, {\n      headers: { From: \"developer@example.org\" },\n    });\n    expect(newRequest.url).toEqual(\"https://example.com\");\n    expect(newRequest.headers.get(\"From\")).toEqual(\"developer@example.org\");\n  });\n\n  it(\"should accept a signal as an option\", () => {\n    const controller = new AbortController();\n    const request = new Request(\"http://localhost\", {\n      signal: controller.signal,\n    });\n    expect(request.signal).toEqual(controller.signal);\n  });\n\n  it(\"should accept null or undefined as signal options\", () => {\n    // @ts-ignore\n    const reqNull = new Request(\"http://localhost\", { signal: null });\n    expect(reqNull.signal).toBeUndefined();\n    // @ts-ignore\n    const reqUndef = new Request(\"http://localhost\", { signal: undefined });\n    expect(reqUndef.signal).toBeUndefined();\n  });\n\n  it(\"should fail if the signal option is not an object\", () => {\n    expect(() => {\n      // @ts-ignore\n      new Request(\"http://localhost\", { signal: \"type error\" });\n    }).toThrow(/property is not an AbortSignal/);\n  });\n\n  it(\"should fail if the signal option is not an valid object\", () => {\n    expect(() => {\n      new Request(\"http://localhost\", {\n        // @ts-ignore\n        signal: new Request(\"http://localhost\"),\n      });\n    }).toThrow(/property is not an AbortSignal/);\n  });\n\n  it(\"should return the provided body via text() and set bodyUsed to true\", async () => {\n    const body = \"Hello, world!\";\n    const request = new Request(\"http://localhost\", {\n      body: body,\n      method: \"POST\",\n    });\n    expect(request.bodyUsed).toBeFalsy();\n    expect(await request.text()).toStrictEqual(body);\n    expect(request.bodyUsed).toBeTruthy();\n  });\n\n  it(\"should set the body to a JSON object if a JSON object is provided\", async () => {\n    const jsonBody = { key: \"value\" };\n    const request = new Request(\"http://localhost\", {\n      body: JSON.stringify(jsonBody),\n      method: \"POST\",\n    });\n    expect(request.bodyUsed).toBeFalsy();\n    expect(await request.json()).toStrictEqual(jsonBody);\n    expect(request.bodyUsed).toBeTruthy();\n  });\n\n  it(\"should set the body to a bytes object if a bytes object is provided\", async () => {\n    const myArray = new Uint8Array([1, 2, 3]);\n    const request = new Request(\"http://localhost\", {\n      body: myArray,\n      method: \"POST\",\n    });\n    expect(request.bodyUsed).toBeFalsy();\n    expect(await request.bytes()).toStrictEqual(myArray);\n    expect(request.bodyUsed).toBeTruthy();\n  });\n\n  it(\"should set the body to a Blob if a Blob is provided\", async () => {\n    const blob = new Blob([\"Hello, world!\"], { type: \"text/plain\" });\n    const request = new Request(\"http://localhost\", {\n      body: blob,\n      method: \"POST\",\n    });\n    expect(request.bodyUsed).toBeFalsy();\n    const res = await request.blob();\n    expect(request.bodyUsed).toBeTruthy();\n    expect(res.size).toEqual(blob.size);\n    expect(res.type).toEqual(\"text/plain\");\n  });\n\n  it(\"should set the body to a Blob if Blob and content-type are provided\", async () => {\n    const blob = new Blob([\"Hello, world!\"], { type: \"text/html\" });\n    const request = new Request(\"http://localhost\", {\n      body: blob,\n      method: \"POST\",\n      headers: { \"content-type\": \"text/plain\" },\n    });\n    const res = await request.blob();\n    expect(res.size).toEqual(blob.size);\n    expect(res.type).toEqual(\"text/plain\");\n  });\n\n  it(\"should ignore request options which are not an object\", async () => {\n    const request = new Request(\"http://localhost\", undefined);\n    expect(request instanceof Request).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "tests/unit/fetch.response.test.ts",
    "content": "describe(\"Response class\", () => {\n  it(\"should construct a new Response object with default values\", () => {\n    const response = new Response();\n    expect(response.status).toEqual(200);\n    expect(response.statusText).toEqual(\"OK\");\n    expect(response.headers instanceof Headers).toBeTruthy();\n    expect(response.body).toEqual(undefined);\n    expect(response.redirected).toBeFalsy();\n  });\n\n  it(\"should set the status and statusText to the provided values\", () => {\n    const response = new Response(null, {\n      status: 404,\n      statusText: \"Not Found\",\n    });\n    expect(response.status).toEqual(404);\n    expect(response.statusText).toEqual(\"Not Found\");\n  });\n\n  it(\"should set the headers to the provided value\", () => {\n    const headers = new Headers({ \"Content-Type\": \"application/json\" });\n    const response = new Response(null, { headers });\n\n    expect(response.headers.get(\"Content-Type\")).toStrictEqual(\n      \"application/json\"\n    );\n  });\n\n  it(\"should set the body to the provided value\", async () => {\n    const body = \"Hello, world!\";\n    const response = new Response(body);\n    expect(response.bodyUsed).toBeFalsy();\n    expect(await response.text()).toStrictEqual(body);\n    expect(response.bodyUsed).toBeTruthy();\n  });\n\n  it(\"should set the body to a Blob if a Blob is provided\", async () => {\n    const blob = new Blob([\"Hello, world!\"], { type: \"text/plain\" });\n    const response = new Response(blob);\n    expect(response.bodyUsed).toBeFalsy();\n    expect(await response.text()).toEqual(\"Hello, world!\");\n    expect(response.bodyUsed).toBeTruthy();\n  });\n\n  it(\"should set the body to a JSON object if a JSON object is provided\", async () => {\n    const jsonBody = { key: \"value\" };\n    const response = new Response(JSON.stringify(jsonBody), {\n      headers: { \"Content-Type\": \"application/json\" },\n    });\n    expect(response.bodyUsed).toBeFalsy();\n    expect(await response.json()).toStrictEqual(jsonBody);\n    expect(response.bodyUsed).toBeTruthy();\n  });\n\n  it(\"should set the body to a bytes object if a bytes object is provided\", async () => {\n    const myArray = new Uint8Array([1, 2, 3]);\n    const response = new Response(myArray);\n    expect(response.bodyUsed).toBeFalsy();\n    expect(await response.bytes()).toStrictEqual(myArray);\n    expect(response.bodyUsed).toBeTruthy();\n  });\n\n  it(\"should clone the response with the clone() method\", () => {\n    const response = new Response(\"Original response\");\n    const clonedResponse = response.clone();\n    expect(response.body).toEqual(clonedResponse.body);\n    expect(response.url).toEqual(clonedResponse.url);\n    expect(response.status).toEqual(clonedResponse.status);\n    expect(response.statusText).toEqual(clonedResponse.statusText);\n    expect(response.headers).toEqual(clonedResponse.headers);\n    expect(response.type).toEqual(clonedResponse.type);\n    expect(response.ok).toEqual(clonedResponse.ok);\n    expect(response.bodyUsed).toEqual(clonedResponse.bodyUsed);\n    expect(response.redirected).toEqual(clonedResponse.redirected);\n  });\n\n  it(\"should create a Response object with an ok status for status codes in the range 200-299\", () => {\n    const response = new Response(\"Success\", { status: 204 });\n    expect(response.ok).toBeTruthy();\n  });\n\n  it(\"should create a Response object with not-ok status for status codes outside the range 200-299\", () => {\n    const response = new Response(\"Error\", { status: 404 });\n    expect(!response.ok).toBeTruthy();\n  });\n\n  it(\"should be returned specified values in error static function\", () => {\n    const response = Response.error();\n    expect(response.status).toEqual(0);\n    expect(response.statusText).toEqual(\"\");\n    expect(response.headers instanceof Headers).toBeTruthy();\n    expect(response.body).toEqual(undefined);\n    expect(response.type).toEqual(\"error\");\n  });\n\n  it(\"should be returned specified values in redirect static function called single param\", () => {\n    const redirectUrl = \"http://localhost/\";\n    //@ts-ignore\n    const response = Response.redirect(redirectUrl);\n    expect(response.status).toEqual(302);\n    expect(response.headers.get(\"location\")).toEqual(redirectUrl);\n  });\n\n  it(\"should be returned specified values in redirect static function called double param\", () => {\n    const redirectUrl = \"http://localhost/\";\n    const response = Response.redirect(redirectUrl, 301);\n    expect(response.status).toEqual(301);\n    expect(response.headers.get(\"location\")).toEqual(redirectUrl);\n  });\n\n  it(\"should be returned specified values in json static function called single param\", () => {\n    const jsonBody = { some: \"data\", more: \"information\" };\n    const response = Response.json(JSON.stringify(jsonBody));\n    expect(response.status).toEqual(200);\n    response.json().then((parsedJson) => {\n      expect(parsedJson).toStrictEqual(jsonBody);\n    });\n  });\n\n  it(\"should be returned specified values in json static function called double param\", () => {\n    const jsonBody = { some: \"data\", more: \"information\" };\n    const response = Response.json(JSON.stringify(jsonBody), {\n      status: 200,\n      statusText: \"SuperSmashingGreat!\",\n      headers: { \"Content-Type\": \"application/json\" },\n    });\n    expect(response.status).toEqual(200);\n    expect(response.statusText).toEqual(\"SuperSmashingGreat!\");\n    response.json().then((parsedJson) => {\n      expect(parsedJson).toStrictEqual(jsonBody);\n    });\n  });\n\n  it(\"returns JSON with 200 by default\", async () => {\n    const json = { message: \"pong\" };\n    const res = Response.json(json);\n\n    expect(res.status).toEqual(200);\n    expect(res.headers.get(\"content-type\")).toEqual(\n      \"application/json;charset=UTF-8\"\n    );\n    expect(await res.json()).toEqual(json);\n  });\n\n  it(\"serializes JSON body to text\", async () => {\n    const json = { message: \"pong\" };\n    const res = Response.json(json);\n\n    expect(res.status).toEqual(200);\n    expect(res.headers.get(\"content-type\")).toEqual(\n      \"application/json;charset=UTF-8\"\n    );\n    expect(await res.text()).toEqual(JSON.stringify(json));\n  });\n\n  it(\"supports custom status and statusText\", async () => {\n    const json = { some: \"data\", more: \"information\" };\n    const res = Response.json(json, {\n      status: 307,\n      statusText: \"Temporary Redirect\",\n    });\n    expect(res.status).toEqual(307);\n    expect(res.statusText).toEqual(\"Temporary Redirect\");\n    expect(res.headers.get(\"content-type\")).toEqual(\n      \"application/json;charset=UTF-8\"\n    );\n    expect(await res.text()).toEqual(JSON.stringify(json));\n  });\n});\n"
  },
  {
    "path": "tests/unit/fetch.test.ts",
    "content": "import net from \"node:net\";\nimport { platform } from \"node:os\";\nimport { spawnCapture } from \"./test-utils\";\n\nconst IS_WINDOWS = platform() === \"win32\";\n\nlet server: net.Server;\nlet url: string;\n\nconst { LLRT_LOG, ...TEST_ENV } = process.env;\n\nconst spawnAndCollectOutput = async (\n  deniedUrl: URL,\n  env: Record<string, string>\n) => {\n  const { stdout, stderr } = await spawnCapture(\n    process.argv[0],\n    [\n      \"-e\",\n      `fetch(\"${deniedUrl}\").catch(console.error).then(() => fetch(\"${url}\")).then(() => console.log(\"OK\"))`,\n    ],\n    { env: { ...TEST_ENV, ...env } }\n  );\n  return { stdout, stderr };\n};\n\nbeforeAll((done) => {\n  server = net.createServer((socket) => {\n    socket.on(\"error\", () => {}); //ignore errors as abort signals might cancel the socket\n    socket.on(\"data\", () => {\n      socket.write(\n        \"HTTP/1.1 200 OK\\r\\nContent-Type: text/html\\r\\n\\r\\n<html></html>\"\n      );\n      socket.end();\n    });\n  });\n\n  server.listen(() => {\n    const { address, port } = server.address()! as any as net.AddressInfo;\n    url = `http://${IS_WINDOWS ? \"localhost\" : address}:${port}`;\n    done();\n  });\n});\n\nafterAll(() => {\n  server?.close();\n});\n\ndescribe(\"fetch\", () => {\n  it(\"should fetch a website\", async () => {\n    const res = await fetch(url);\n\n    expect(res.status).toEqual(200);\n    expect(\n      res.headers.get(\"content-type\")?.startsWith(\"text/html\")\n    ).toBeTruthy();\n  });\n\n  it(\"should fetch a website with url and options\", async () => {\n    const options = {\n      method: \"GET\",\n      url,\n    };\n\n    const request = new Request(url);\n\n    const res = await fetch(request, options);\n    expect(res.status).toEqual(200);\n    expect(\n      res.headers.get(\"content-type\")?.startsWith(\"text/html\")\n    ).toBeTruthy();\n  });\n\n  it(\"should fetch a website with different resource options\", async () => {\n    let res = await fetch(new Request(url));\n    expect(res.status).toEqual(200);\n    expect(\n      res.headers.get(\"content-type\")?.startsWith(\"text/html\")\n    ).toBeTruthy();\n\n    res = await fetch(new URL(url));\n    expect(res.status).toEqual(200);\n    expect(\n      res.headers.get(\"content-type\")?.startsWith(\"text/html\")\n    ).toBeTruthy();\n\n    res = await fetch(\"\", { url } as any);\n    expect(res.status).toEqual(200);\n    expect(\n      res.headers.get(\"content-type\")?.startsWith(\"text/html\")\n    ).toBeTruthy();\n  });\n\n  it(\"should fetch a website in parallel\", async () => {\n    await Promise.all(new Array(10).fill(0).map(() => fetch(url)));\n  });\n\n  it(\"is not allowed to fetch\", async () => {\n    const deniedUrl = new URL(\"https://www.amazon.com\");\n    const { stdout, stderr } = await spawnAndCollectOutput(deniedUrl, {\n      LLRT_NET_DENY: \"amazon.com\",\n    });\n\n    expect(stderr.trim()).toEqual(`Error: URL denied: ${deniedUrl.hostname}`);\n    expect(stdout.trim()).toEqual(\"OK\");\n  });\n\n  it(\"is only allowed to fetch\", async () => {\n    const deniedUrl = new URL(\"https://www.amazon.com\");\n    const { stdout, stderr } = await spawnAndCollectOutput(deniedUrl, {\n      LLRT_NET_ALLOW: url,\n    });\n\n    expect(stderr.trim()).toEqual(\n      `Error: URL not allowed: ${deniedUrl.hostname}`\n    );\n    expect(stdout.trim()).toEqual(\"OK\");\n  });\n\n  it(\"should be abortable using signals\", async () => {\n    const abortController = new AbortController();\n    const res = fetch(url, { signal: abortController.signal });\n    abortController.abort();\n    try {\n      await res;\n    } catch (err: any) {\n      expect(err.name).toBe(\"AbortError\");\n    }\n  });\n  it(\"should be abortable using request signal\", async () => {\n    const abortController = new AbortController();\n    const req = new Request(url, { signal: abortController.signal });\n    abortController.abort(\"aborted\");\n    try {\n      await fetch(req);\n    } catch (err: any) {\n      expect(abortController.signal.reason).toBe(\"aborted\");\n    }\n  });\n  it(\"should be processing data-url\", async () => {\n    const s = \"hello\";\n    const base64 = Buffer.from(s).toString(\"base64\");\n    const dataURIPrefix = \"data:application/octet-stream;base64,\";\n    const url = dataURIPrefix + base64;\n    const resp = await fetch(url);\n    const buf = await resp.arrayBuffer();\n    const str = Buffer.from(buf).toString(\"ascii\");\n    expect(str).toEqual(s);\n  });\n});\n"
  },
  {
    "path": "tests/unit/fs.test.ts",
    "content": "import defaultImport from \"node:fs\";\nimport legacyImport from \"fs\";\n\nimport path from \"node:path\";\nimport os from \"node:os\";\nconst IS_WINDOWS = os.platform() === \"win32\";\n\nit(\"node:fs should be the same as fs\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n\nconst {\n  constants,\n  accessSync,\n  readdirSync,\n  readFileSync,\n  mkdtempSync,\n  mkdirSync,\n  renameSync,\n  rmSync,\n  rmdirSync,\n  statSync,\n  lstatSync,\n  symlinkSync,\n  writeFileSync,\n  promises,\n} = defaultImport;\n\nconst {\n  access,\n  mkdir,\n  mkdtemp,\n  readdir,\n  readFile,\n  rename,\n  rm,\n  rmdir,\n  lstat,\n  symlink,\n  writeFile,\n} = promises;\n\ndescribe(\"readdir\", () => {\n  it(\"should read a directory\", async () => {\n    const dir = await readdir(\".cargo\");\n    expect(dir).toEqual([\"config.toml\"]);\n  });\n\n  it(\"should read a directory with types\", async () => {\n    const dir = await readdir(\".cargo\", { withFileTypes: true });\n    expect(dir).toEqual([\n      {\n        name: \"config.toml\",\n        parentPath: \".cargo\",\n      },\n    ]);\n    expect(dir[0].isFile()).toBeTruthy();\n  });\n\n  it(\"should read a directory with types\", async () => {\n    const dir = await readdir(\".cargo/\", { withFileTypes: true });\n    expect(dir).toEqual([\n      {\n        name: \"config.toml\",\n        parentPath: \".cargo\",\n      },\n    ]);\n    expect(dir[0].isFile()).toBeTruthy();\n  });\n\n  it(\"should read a directory\", async () => {\n    const dir = await readdir(\".cargo\");\n    expect(dir).toEqual([\"config.toml\"]);\n  });\n\n  it(\"should read a directory with recursive\", async () => {\n    const dir = await readdir(\"fixtures/fs/readdir\", {\n      recursive: true,\n    });\n    const compare = (a: string, b: string) => (a >= b ? 1 : -1);\n    expect(dir.sort(compare)).toEqual(\n      [\n        IS_WINDOWS ? \"recursive\\\\readdir.js\" : \"recursive/readdir.js\",\n        \"recursive\",\n        \"readdir.js\",\n      ].sort(compare)\n    );\n  });\n});\n\ndescribe(\"readdirSync\", () => {\n  it(\"should read a directory synchronously\", () => {\n    const dir = readdirSync(\".cargo\");\n    expect(dir).toEqual([\"config.toml\"]);\n  });\n\n  it(\"should read a directory with types synchronously\", () => {\n    const dir = readdirSync(\".cargo\", {\n      withFileTypes: true,\n    });\n    expect(dir).toEqual([\n      {\n        name: \"config.toml\",\n        parentPath: \".cargo\",\n      },\n    ]);\n    expect(dir[0].isFile()).toBeTruthy();\n  });\n\n  it(\"should read a directory synchronously\", () => {\n    const dir = readdirSync(\".cargo\");\n    expect(dir).toEqual([\"config.toml\"]);\n  });\n\n  it(\"should read a directory with recursive synchronously\", () => {\n    const dir = readdirSync(\"fixtures/fs/readdir\", {\n      recursive: true,\n    });\n    const compare = (a: string | Buffer, b: string | Buffer): number =>\n      a >= b ? 1 : -1;\n    expect(dir.sort(compare)).toEqual(\n      [\n        IS_WINDOWS ? \"recursive\\\\readdir.js\" : \"recursive/readdir.js\",\n        \"recursive\",\n        \"readdir.js\",\n      ].sort(compare)\n    );\n  });\n});\n\ndescribe(\"readfile\", () => {\n  it(\"should read a file\", async () => {\n    const buf = await readFile(\"fixtures/hello.txt\");\n    const text = buf.toString();\n    const base64Text = buf.toString(\"base64\");\n    const hexText = buf.toString(\"hex\");\n\n    expect(buf).toBeInstanceOf(Buffer);\n    expect(buf).toBeInstanceOf(Uint8Array);\n    expect(text).toEqual(\"hello world!\");\n    expect(base64Text).toEqual(\"aGVsbG8gd29ybGQh\");\n    expect(hexText).toEqual(\"68656c6c6f20776f726c6421\");\n  });\n\n  it(\"should return a string when encoding is provided as option\", async () => {\n    const text = await readFile(\"fixtures/hello.txt\", {\n      encoding: \"utf-8\",\n    });\n    expect(typeof text).toEqual(\"string\");\n    expect(text).toEqual(\"hello world!\");\n  });\n\n  it(\"should return a string when encoding is provided as string\", async () => {\n    const text = await readFile(\"fixtures/hello.txt\", \"utf-8\");\n    expect(typeof text).toEqual(\"string\");\n    expect(text).toEqual(\"hello world!\");\n  });\n\n  it(\"should return a string when encoding is provided as string with different cases\", async () => {\n    // @ts-ignore\n    const text = await readFile(\"fixtures/hello.txt\", \"Utf-8\");\n    expect(typeof text).toEqual(\"string\");\n    expect(text).toEqual(\"hello world!\");\n  });\n});\n\ndescribe(\"readfileSync\", () => {\n  it(\"should read a file synchronously\", () => {\n    const buf = readFileSync(\"fixtures/hello.txt\");\n    const text = buf.toString();\n    const base64Text = buf.toString(\"base64\");\n    const hexText = buf.toString(\"hex\");\n\n    expect(buf).toBeInstanceOf(Buffer);\n    expect(buf).toBeInstanceOf(Uint8Array);\n    expect(text).toEqual(\"hello world!\");\n    expect(base64Text).toEqual(\"aGVsbG8gd29ybGQh\");\n    expect(hexText).toEqual(\"68656c6c6f20776f726c6421\");\n  });\n\n  it(\"should return a string when encoding is provided as option synchronously\", () => {\n    const text = readFileSync(\"fixtures/hello.txt\", {\n      encoding: \"utf-8\",\n    });\n    expect(typeof text).toEqual(\"string\");\n    expect(text).toEqual(\"hello world!\");\n  });\n\n  it(\"should return a string when encoding is provided as string synchronously\", () => {\n    const text = readFileSync(\"fixtures/hello.txt\", \"utf-8\");\n    expect(typeof text).toEqual(\"string\");\n    expect(text).toEqual(\"hello world!\");\n  });\n\n  it(\"should return a string when encoding is provided as string with different cases synchronously\", async () => {\n    // @ts-ignore\n    const text = readFileSync(\"fixtures/hello.txt\", \"Utf-8\");\n    expect(typeof text).toEqual(\"string\");\n    expect(text).toEqual(\"hello world!\");\n  });\n});\n\ndescribe(\"mkdtemp\", () => {\n  it(\"should create a temporary directory with a given prefix\", async () => {\n    // Create a temporary directory with the given prefix\n    const prefix = \"test-\";\n    const dirPath = await mkdtemp(path.join(os.tmpdir(), prefix));\n\n    // Check that the directory exists\n    const dirExists = await promises\n      .stat(dirPath)\n      .then(() => true)\n      .catch(() => false);\n    expect(dirExists).toBeTruthy();\n\n    // Check that the directory has the correct prefix\n    const dirPrefix = path.basename(dirPath).slice(0, prefix.length);\n    expect(dirPrefix).toEqual(prefix);\n\n    // Clean up the temporary directory\n    await rmdir(dirPath);\n  });\n});\n\ndescribe(\"mkdtempSync\", () => {\n  it(\"should create a temporary directory with a given prefix synchronously\", () => {\n    // Create a temporary directory with the given prefix\n    const prefix = \"test-\";\n    const dirPath = mkdtempSync(path.join(os.tmpdir(), prefix));\n\n    // Check that the directory exists\n    const dirExists = statSync(dirPath);\n    expect(dirExists).toBeTruthy();\n\n    // Check that the directory has the correct prefix\n    const dirPrefix = path.basename(dirPath).slice(0, prefix.length);\n    expect(dirPrefix).toEqual(prefix);\n\n    // Clean up the temporary directory\n    rmdirSync(dirPath);\n  });\n});\n\ndescribe(\"mkdir\", () => {\n  it(\"should create a directory with the given path\", async () => {\n    const dirPath = await mkdtemp(path.join(os.tmpdir(), \"test/test-\"));\n\n    //non recursive should reject\n    await expect(mkdir(dirPath)).rejects.toThrow(/dir/);\n\n    await mkdir(dirPath, { recursive: true });\n\n    // Check that the directory exists\n    const dirExists = await checkDirExists(dirPath);\n    expect(dirExists).toBeTruthy();\n\n    await rmdir(dirPath, { recursive: true });\n\n    await mkdir(`${dirPath}/./`, { recursive: true });\n\n    // Check that the directory exists\n    const dirExists2 = await checkDirExists(dirPath);\n    expect(dirExists2).toBeTruthy();\n\n    // Clean up the directory\n    await rmdir(dirPath, { recursive: true });\n  });\n});\n\ndescribe(\"mkdirSync\", () => {\n  it(\"should create a directory with the given path synchronously\", () => {\n    const dirPath = mkdtempSync(path.join(os.tmpdir(), \"test/test-\"));\n\n    //non recursive should reject\n    expect(() => mkdirSync(dirPath)).toThrow(\n      IS_WINDOWS ? /Can\\'t create dir/ : /[fF]ile.*exists/\n    );\n\n    mkdirSync(dirPath, { recursive: true });\n\n    // Check that the directory exists\n    const dirExists = statSync(dirPath);\n    expect(dirExists).toBeTruthy();\n\n    // Clean up the directory\n    rmdirSync(dirPath, { recursive: true });\n  });\n});\n\ndescribe(\"writeFile\", () => {\n  it(\"should write a file\", async () => {\n    const tmpDir = await mkdtemp(path.join(os.tmpdir(), \"test-\"));\n    const filePath = path.join(tmpDir, \"test\");\n    const fileContents = \"hello\";\n    await writeFile(filePath, fileContents);\n\n    const contents = (await readFile(filePath)).toString();\n\n    expect(fileContents).toEqual(contents);\n\n    await rmdir(tmpDir, { recursive: true });\n  });\n\n  if (!IS_WINDOWS) {\n    it(\"should write file with permissions\", async () => {\n      const tmpDir = await mkdtemp(path.join(os.tmpdir(), \"test-\"));\n      const filePath = path.join(tmpDir, \"test\");\n      const fileContents = \"hello\";\n      const mode = 0o644;\n      await writeFile(filePath, fileContents, { mode });\n\n      const stats = statSync(filePath);\n      expect(stats.mode & 0o777).toEqual(mode);\n\n      await rmdir(tmpDir, { recursive: true });\n    });\n  }\n});\n\ndescribe(\"writeFileSync\", () => {\n  it(\"should write a file\", () => {\n    const tmpDir = mkdtempSync(path.join(os.tmpdir(), \"test-\"));\n    const filePath = path.join(tmpDir, \"test\");\n    const fileContents = \"hello\";\n    writeFileSync(filePath, fileContents);\n\n    const contents = readFileSync(filePath).toString();\n\n    expect(fileContents).toEqual(contents);\n\n    rmdirSync(tmpDir, { recursive: true });\n  });\n\n  if (!IS_WINDOWS) {\n    it(\"should write file with permissions\", async () => {\n      const tmpDir = await mkdtemp(path.join(os.tmpdir(), \"test-\"));\n      const filePath = path.join(tmpDir, \"test\");\n      const fileContents = \"hello\";\n      const mode = 0o644;\n      writeFileSync(filePath, fileContents, { mode });\n\n      const stats = statSync(filePath);\n      expect(stats.mode & 0o777).toEqual(mode);\n\n      rmdirSync(tmpDir, { recursive: true });\n    });\n  }\n});\n\ndescribe(\"rm\", () => {\n  it(\"should delete file and directory\", async () => {\n    const tmpDir = await mkdtemp(path.join(os.tmpdir(), \"test-\"));\n    const filePath = path.join(tmpDir, \"test\");\n    const fileContents = \"hello\";\n    await writeFile(filePath, fileContents);\n\n    const contents = (await readFile(filePath)).toString();\n    expect(fileContents).toEqual(contents);\n\n    // Should delete file\n    await rm(filePath, { recursive: true });\n    await expect(access(filePath)).rejects.toThrow(\n      /[Nn]o such file or directory/\n    );\n\n    // Check dir still exists and then delete it\n    await access(tmpDir);\n    await rm(tmpDir, { recursive: true });\n    await expect(access(filePath)).rejects.toThrow(\n      /[Nn]o such file or directory/\n    );\n  });\n  it(\"should throw an error if file does not exists\", async () => {\n    const tmpDir = mkdtempSync(path.join(os.tmpdir(), \"test-\"));\n    const filePath = path.join(tmpDir, \"test\");\n\n    await expect(rm(filePath, {})).rejects.toThrow(\n      IS_WINDOWS ? /\\(os error 2\\)/ : /[Nn]o such file or directory/\n    );\n  });\n  it(\"should not throw an error if file does not exists and force is used\", async () => {\n    const tmpDir = await mkdtemp(path.join(os.tmpdir(), \"test-\"));\n    const filePath = path.join(tmpDir, \"test\");\n\n    await expect(access(filePath)).rejects.toThrow(\n      /[Nn]o such file or directory/\n    );\n\n    // Should not throw an exception since it does not exists\n    await rm(filePath, { force: true, recursive: true });\n  });\n});\ndescribe(\"rmSync\", () => {\n  it(\"should delete file and directory with rm synchronously\", async () => {\n    const tmpDir = mkdtempSync(path.join(os.tmpdir(), \"test-\"));\n    const filePath = path.join(tmpDir, \"test\");\n    const fileContents = \"hello\";\n    await writeFile(filePath, fileContents);\n\n    const contents = readFileSync(filePath).toString();\n\n    expect(fileContents).toEqual(contents);\n\n    // Should delete file\n    rmSync(filePath, { recursive: true });\n    expect(() => accessSync(filePath)).toThrow(/[Nn]o such file or directory/);\n\n    // Check dir still exists and then delete it\n    accessSync(tmpDir);\n    rmSync(tmpDir, { recursive: true });\n    expect(() => accessSync(tmpDir)).toThrow(/[Nn]o such file or directory/);\n  });\n  it(\"should throw an error if file does not exists with rm synchronously\", async () => {\n    const tmpDir = mkdtempSync(path.join(os.tmpdir(), \"test-\"));\n    const filePath = path.join(tmpDir, \"test\");\n\n    expect(() => rmSync(filePath, {})).toThrow(\n      IS_WINDOWS ? /\\(os error 2\\)/ : /[Nn]o such file or directory/\n    );\n  });\n  it(\"should not throw an error if file does not exists and force is used with rm synchronously\", async () => {\n    const tmpDir = mkdtempSync(path.join(os.tmpdir(), \"test-\"));\n    const filePath = path.join(tmpDir, \"test\");\n\n    expect(() => accessSync(filePath)).toThrow(/[Nn]o such file or directory/);\n\n    // Should not throw an exception since it does not exists\n    rmSync(filePath, { force: true, recursive: true });\n  });\n});\n\ndescribe(\"access\", () => {\n  it(\"should access a file\", async () => {\n    const filePath = \"fixtures/hello.txt\";\n    await access(filePath);\n  });\n\n  it(\"should handle execute permission check\", async () => {\n    const filePath = \"fixtures/hello.txt\";\n    if (IS_WINDOWS) {\n      // On Windows, X_OK doesn't check Unix-style execute bits\n      // Windows determines executability by file extension, so X_OK typically succeeds\n      await access(filePath, constants.X_OK);\n    } else {\n      // On Unix, X_OK throws for files without execute permission\n      await expect(access(filePath, constants.X_OK)).rejects.toThrow(\n        /[pP]ermission denied/\n      );\n    }\n  });\n\n  it(\"should throw if not exists\", async () => {\n    const filePath = \"fixtures/nothing\";\n    await expect(access(filePath)).rejects.toThrow(\n      /[nN]o such file or directory/\n    );\n  });\n\n  it(\"should access a file\", async () => {\n    const filePath = \"fixtures/hello.txt\";\n    await access(filePath);\n  });\n});\n\ndescribe(\"accessSync\", () => {\n  it(\"should access a file synchronously\", () => {\n    const filePath = \"fixtures/hello.txt\";\n    accessSync(filePath);\n  });\n\n  it(\"should handle execute permission check synchronously\", () => {\n    const filePath = \"fixtures/hello.txt\";\n    if (IS_WINDOWS) {\n      // On Windows, X_OK doesn't check Unix-style execute bits\n      // Windows determines executability by file extension, so X_OK typically succeeds\n      accessSync(filePath, constants.X_OK);\n    } else {\n      // On Unix, X_OK throws for files without execute permission\n      expect(() => accessSync(filePath, constants.X_OK)).toThrow(\n        /[pP]ermission denied/\n      );\n    }\n  });\n\n  it(\"should throw if not exists synchronously\", () => {\n    const filePath = \"fixtures/nothing\";\n    expect(() => accessSync(filePath)).toThrow(/[Nn]o such file or directory/);\n  });\n});\n\ndescribe(\"rename\", () => {\n  it(\"should rename a directory\", async () => {\n    const tmpDir = await mkdtemp(path.join(os.tmpdir(), \"test-\"));\n    const oldPath = path.join(tmpDir, \"old\");\n    const newPath = path.join(tmpDir, \"new\");\n\n    await mkdir(oldPath);\n    await rename(oldPath, newPath);\n\n    const oldDirExists = await checkDirExists(oldPath);\n    const newDirExists = await checkDirExists(newPath);\n\n    expect(oldDirExists).toBeFalsy();\n    expect(newDirExists).toBeTruthy();\n\n    // Cleanup\n    await rmdir(tmpDir, { recursive: true });\n  });\n\n  it(\"should throw error if source doesn't exist\", async () => {\n    const tmpDir = await mkdtemp(path.join(os.tmpdir(), \"test-\"));\n    const oldPath = path.join(tmpDir, \"nonexistent\");\n    const newPath = path.join(tmpDir, \"new\");\n\n    await expect(rename(oldPath, newPath)).rejects.toThrow(\n      IS_WINDOWS ? /Can't rename/ : /[Nn]o such file or directory/\n    );\n\n    await rmdir(tmpDir, { recursive: true });\n  });\n});\n\ndescribe(\"renameSync\", () => {\n  it(\"should rename a directory synchronously\", () => {\n    const tmpDir = mkdtempSync(path.join(os.tmpdir(), \"test-\"));\n    const oldPath = path.join(tmpDir, \"old\");\n    const newPath = path.join(tmpDir, \"new\");\n\n    mkdirSync(oldPath);\n    renameSync(oldPath, newPath);\n\n    // Check if old path doesn't exist (should throw)\n    // Windows gives \"Can't stat\" error instead of \"no such file or directory\"\n    expect(() => statSync(oldPath)).toThrow(\n      IS_WINDOWS ? /Can't stat/ : /[Nn]o such file or directory/\n    );\n\n    // Check if new path exists and is a directory\n    const newDirStat = statSync(newPath);\n    expect(newDirStat.isDirectory()).toBeTruthy();\n\n    // Cleanup\n    rmdirSync(tmpDir, { recursive: true });\n  });\n\n  it(\"should throw error if source doesn't exist synchronously\", () => {\n    const tmpDir = mkdtempSync(path.join(os.tmpdir(), \"test-\"));\n    const oldPath = path.join(tmpDir, \"nonexistent\");\n    const newPath = path.join(tmpDir, \"new\");\n\n    expect(() => renameSync(oldPath, newPath)).toThrow(\n      IS_WINDOWS ? /Can't rename/ : /[Nn]o such file or directory/\n    );\n\n    rmdirSync(tmpDir, { recursive: true });\n  });\n});\n\ndescribe(\"symlink\", () => {\n  it(\"should create a symlink\", async () => {\n    const tmpDir = mkdtempSync(path.join(os.tmpdir(), \"test-\"));\n    const filePath = path.join(tmpDir, \"file\");\n    const linkPath = path.join(tmpDir, \"link\");\n\n    const expectedContent = \"hello world\";\n    await writeFile(filePath, expectedContent);\n    await symlink(filePath, linkPath);\n\n    // Check if new path exists and is a symlink\n    const linkStat = await lstat(linkPath);\n    expect(linkStat.isSymbolicLink()).toBeTruthy();\n\n    // Verify symlink works by reading content through it\n    const content = await readFile(linkPath, \"utf-8\");\n    expect(content).toBe(expectedContent);\n\n    // Cleanup\n    rmdirSync(tmpDir, { recursive: true });\n  });\n});\n\ndescribe(\"symlinkSync\", () => {\n  it(\"should create a symlink synchronously\", () => {\n    const tmpDir = mkdtempSync(path.join(os.tmpdir(), \"test-\"));\n    const filePath = path.join(tmpDir, \"file\");\n    const linkPath = path.join(tmpDir, \"link\");\n\n    const expectedContent = \"hello world\";\n    writeFileSync(filePath, expectedContent);\n    symlinkSync(filePath, linkPath);\n\n    // Check if new path exists and is a symlink\n    const linkStat = lstatSync(linkPath);\n    expect(linkStat.isSymbolicLink()).toBeTruthy();\n\n    // Verify symlink works by reading content through it\n    const content = readFileSync(linkPath, \"utf-8\");\n    expect(content).toBe(expectedContent);\n\n    // Cleanup\n    rmdirSync(tmpDir, { recursive: true });\n  });\n});\n\n// Helper function to check if directory exists\nconst checkDirExists = async (dirPath: string) => {\n  return await promises\n    .stat(dirPath)\n    .then(() => true)\n    .catch(() => false);\n};\n"
  },
  {
    "path": "tests/unit/import.test.ts",
    "content": "const CWD = process.cwd();\n\ndescribe(\"import\", () => {\n  it(\"should import a js file (absolute path)\", async () => {\n    const mod = await import(`${CWD}/fixtures/hello.js`);\n\n    expect(mod.hello).toEqual(\"hello world!\");\n  });\n\n  it(\"should import a json file (absolute path)\", async () => {\n    const mod = await import(`${CWD}/package.json`);\n\n    expect(mod.default.private).toEqual(true);\n  });\n\n  it(\"should import a js file (relative path)\", async () => {\n    const mod = await import(\"../../fixtures/hello.js\");\n\n    expect(mod.hello).toEqual(\"hello world!\");\n  });\n\n  it(\"should import a json file (relative path)\", async () => {\n    const mod = await import(\"../../fixtures/package.json\");\n\n    expect(mod.default.private).toEqual(true);\n  });\n\n  it(\"should import a json file (path unspecified)\", async () => {\n    const mod = await import(\"package.json\");\n\n    expect(mod.default.private).toEqual(true);\n  });\n\n  it(\"should have import.meta.url\", async () => {\n    const url = import.meta.url;\n    // Verify import.meta.url structure without depending on CWD\n    // (test can be run from any directory)\n    expect(url.startsWith(\"file://\")).toEqual(true);\n    // Normalize path separators for cross-platform compatibility\n    const normalizedUrl = url.replaceAll(\"\\\\\", \"/\");\n    expect(\n      normalizedUrl.endsWith(\"/bundle/js/__tests__/unit/import.test.js\")\n    ).toEqual(true);\n  });\n});\n"
  },
  {
    "path": "tests/unit/intl.test.ts",
    "content": "describe(\"Intl.supportedValuesOf\", () => {\n  it(\"should return an array\", () => {\n    const zones = Intl.supportedValuesOf(\"timeZone\");\n    expect(Array.isArray(zones)).toBe(true);\n  });\n\n  it(\"should contain common timezones\", () => {\n    const zones = Intl.supportedValuesOf(\"timeZone\");\n    expect(zones).toContain(\"America/New_York\");\n    expect(zones).toContain(\"America/Los_Angeles\");\n    expect(zones).toContain(\"America/Denver\");\n    expect(zones).toContain(\"Europe/London\");\n    expect(zones).toContain(\"Europe/Paris\");\n    expect(zones).toContain(\"Asia/Tokyo\");\n    expect(zones).toContain(\"UTC\");\n  });\n\n  it(\"should return many timezones\", () => {\n    const zones = Intl.supportedValuesOf(\"timeZone\");\n    expect(zones.length).toBeGreaterThan(400);\n  });\n});\n\ndescribe(\"Intl.DateTimeFormat\", () => {\n  describe(\"basic functionality\", () => {\n    it(\"should be defined globally\", () => {\n      expect(typeof Intl).toBe(\"object\");\n      expect(typeof Intl.DateTimeFormat).toBe(\"function\");\n    });\n\n    it(\"should have correct Symbol.toStringTag\", () => {\n      const formatter = new Intl.DateTimeFormat(\"en-US\");\n      expect(formatter[Symbol.toStringTag]).toBe(\"Intl.DateTimeFormat\");\n    });\n  });\n\n  describe(\"formatToParts\", () => {\n    it(\"should return an array of parts\", () => {\n      const formatter = new Intl.DateTimeFormat(\"en-US\", {\n        timeZone: \"UTC\",\n        year: \"numeric\",\n        month: \"2-digit\",\n        day: \"2-digit\",\n      });\n      const date = new Date(\"2022-03-02T15:45:34Z\");\n      const parts = formatter.formatToParts(date);\n\n      expect(Array.isArray(parts)).toBe(true);\n      expect(parts.length).toBeGreaterThan(0);\n    });\n\n    it(\"should format date in specified timezone\", () => {\n      const formatter = new Intl.DateTimeFormat(\"en-US\", {\n        timeZone: \"America/Denver\",\n        hour12: false,\n        year: \"numeric\",\n        month: \"2-digit\",\n        day: \"2-digit\",\n        hour: \"2-digit\",\n        minute: \"2-digit\",\n        second: \"2-digit\",\n      });\n      // March 2, 2022 15:45:34 UTC = March 2, 2022 08:45:34 Denver (MST -7)\n      const date = new Date(\"2022-03-02T15:45:34Z\");\n      const parts = formatter.formatToParts(date);\n\n      const hourPart = parts.find((p: any) => p.type === \"hour\");\n      expect(hourPart?.value).toBe(\"08\");\n    });\n\n    it(\"should handle DST correctly\", () => {\n      const formatter = new Intl.DateTimeFormat(\"en-US\", {\n        timeZone: \"America/Denver\",\n        hour12: false,\n        hour: \"2-digit\",\n      });\n\n      // June 15, 2024 - DST is in effect (MDT -6)\n      const summerDate = new Date(\"2024-06-15T18:00:00Z\");\n      const summerParts = formatter.formatToParts(summerDate);\n      const summerHour = summerParts.find((p: any) => p.type === \"hour\");\n      expect(summerHour?.value).toBe(\"12\"); // 18 UTC - 6 = 12\n\n      // January 15, 2024 - No DST (MST -7)\n      const winterDate = new Date(\"2024-01-15T18:00:00Z\");\n      const winterParts = formatter.formatToParts(winterDate);\n      const winterHour = winterParts.find((p: any) => p.type === \"hour\");\n      expect(winterHour?.value).toBe(\"11\"); // 18 UTC - 7 = 11\n    });\n  });\n\n  describe(\"format\", () => {\n    it(\"should return a formatted string\", () => {\n      const formatter = new Intl.DateTimeFormat(\"en-US\", {\n        timeZone: \"UTC\",\n        year: \"numeric\",\n        month: \"2-digit\",\n        day: \"2-digit\",\n      });\n      const date = new Date(\"2022-03-02T15:45:34Z\");\n      const result = formatter.format(date);\n\n      expect(typeof result).toBe(\"string\");\n      expect(result).toContain(\"03\");\n      expect(result).toContain(\"02\");\n      expect(result).toContain(\"2022\");\n    });\n  });\n\n  describe(\"resolvedOptions\", () => {\n    it(\"should return resolved options\", () => {\n      const formatter = new Intl.DateTimeFormat(\"en-US\", {\n        timeZone: \"America/Denver\",\n        year: \"numeric\",\n        month: \"2-digit\",\n      });\n      const options = formatter.resolvedOptions();\n\n      expect(options.timeZone).toBe(\"America/Denver\");\n      expect(options.locale).toBe(\"en-US\");\n      expect(options.year).toBe(\"numeric\");\n      expect(options.month).toBe(\"2-digit\");\n    });\n\n    it(\"should default to system timezone when not specified\", () => {\n      const formatter = new Intl.DateTimeFormat(\"en-US\");\n      const options = formatter.resolvedOptions();\n\n      expect(typeof options.timeZone).toBe(\"string\");\n      expect(options.timeZone.length).toBeGreaterThan(0);\n    });\n  });\n});\n"
  },
  {
    "path": "tests/unit/jest-expect.test.ts",
    "content": "/*\nMIT License\n\nCopyright (c) 2021-Present Anthony Fu <https://github.com/antfu>\nCopyright (c) 2021-Present Matias Capeletto <https://github.com/patak-dev>\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// Extracted and modified from Vitest:  https://github.com/vitest-dev/vitest/blob/7a31a1ae4223aed3adf260e63ac3b3f7fab3c9d7/test/core/test/jest-expect.test.ts\n/*\nclass TestError extends Error {}\n\ndescribe(\"jest-expect\", () => {\n  it(\"basic\", () => {\n    expect(1).toBe(1);\n    expect(null).toBeNull();\n    expect(1).not.toBeNull();\n    expect(null).toBeDefined();\n    expect(undefined).not.toBeDefined();\n    expect(undefined).toBeUndefined();\n    expect(null).not.toBeUndefined();\n    expect([]).toBeTruthy();\n    expect(0).toBeFalsy();\n    expect(\"Hello\").toMatch(/llo/);\n    expect(\"Hello\").toMatch(\"llo\");\n    expect(\"Hello\").toContain(\"llo\");\n    expect([\"Hello\"]).toContain(\"Hello\");\n    expect([{ text: \"Hello\" }]).toContainEqual({ text: \"Hello\" });\n    expect([{ text: \"Bye\" }]).not.toContainEqual({ text: \"Hello\" });\n    expect(1).toBeGreaterThan(0);\n\n    expect(new Date(0)).toEqual(new Date(0));\n    expect(new Date(\"inValId\")).toEqual(new Date(\"inValId\"));\n\n    expect(new Error(\"message\")).toEqual(new Error(\"message\"));\n    expect(new Error(\"message\")).not.toEqual(new Error(\"different message\"));\n\n    expect(new URL(\"https://example.org\")).toEqual(\n      new URL(\"https://example.org\")\n    );\n    expect(new URL(\"https://example.org\")).not.toEqual(\n      new URL(\"https://different-example.org\")\n    );\n    expect(new URL(\"https://example.org?query=value\")).toEqual(\n      new URL(\"https://example.org?query=value\")\n    );\n    expect(new URL(\"https://example.org?query=one\")).not.toEqual(\n      new URL(\"https://example.org?query=two\")\n    );\n    expect(\n      new URL(\n        \"https://subdomain.example.org/path?query=value#fragment-identifier\"\n      )\n    ).toEqual(\n      new URL(\n        \"https://subdomain.example.org/path?query=value#fragment-identifier\"\n      )\n    );\n    expect(\n      new URL(\n        \"https://subdomain.example.org/path?query=value#fragment-identifier\"\n      )\n    ).not.toEqual(\n      new URL(\n        \"https://subdomain.example.org/path?query=value#different-fragment-identifier\"\n      )\n    );\n    expect(new URL(\"https://example.org/path\")).toEqual(\n      new URL(\"/path\", \"https://example.org\")\n    );\n    expect(new URL(\"https://example.org/path\")).not.toEqual(\n      new URL(\"/path\", \"https://example.com\")\n    );\n\n    expect(BigInt(1)).toBeGreaterThan(BigInt(0));\n    expect(1).toBeGreaterThan(BigInt(0));\n    expect(BigInt(1)).toBeGreaterThan(0);\n\n    expect(1).toBeGreaterThanOrEqual(1);\n    expect(1).toBeGreaterThanOrEqual(0);\n\n    expect(BigInt(1)).toBeGreaterThanOrEqual(BigInt(1));\n    expect(BigInt(1)).toBeGreaterThanOrEqual(BigInt(0));\n    expect(BigInt(1)).toBeGreaterThanOrEqual(1);\n    expect(1).toBeGreaterThanOrEqual(BigInt(1));\n\n    expect(0).toBeLessThan(1);\n    expect(BigInt(0)).toBeLessThan(BigInt(1));\n    expect(BigInt(0)).toBeLessThan(1);\n\n    expect(1).toBeLessThanOrEqual(1);\n    expect(0).toBeLessThanOrEqual(1);\n    expect(BigInt(1)).toBeLessThanOrEqual(BigInt(1));\n    expect(BigInt(0)).toBeLessThanOrEqual(BigInt(1));\n    expect(BigInt(1)).toBeLessThanOrEqual(1);\n    expect(1).toBeLessThanOrEqual(BigInt(1));\n\n    expect(() => {\n      throw new Error(\"this is the error message\");\n    }).toThrow(\"this is the error message\");\n    expect(() => {}).not.toThrow();\n    expect(() => {\n      throw new TestError(\"error\");\n    }).toThrow(TestError);\n    const err = new Error(\"hello world\");\n    expect(() => {\n      throw err;\n    }).toThrow(err);\n    expect(() => {\n      throw new Error(\"message\");\n    }).toThrow(\n      expect.objectContaining({\n        message: expect.stringContaining(\"mes\"),\n      })\n    );\n    expect([1, 2, 3]).toHaveLength(3);\n    expect(\"abc\").toHaveLength(3);\n    expect(\"\").not.toHaveLength(5);\n    expect({ length: 3 }).toHaveLength(3);\n    expect(0.2 + 0.1).not.toBe(0.3);\n    expect(0.2 + 0.1).toBeCloseTo(0.3, 5);\n    expect(0.2 + 0.1).not.toBeCloseTo(0.3, 100); // expect.closeTo will fail in chai\n  });\n\n  it(\"asymmetric matchers (jest style)\", () => {\n    expect({ foo: \"bar\" }).toEqual({ foo: expect.stringContaining(\"ba\") });\n    expect(\"bar\").toEqual(expect.stringContaining(\"ba\"));\n    expect([\"bar\"]).toEqual([expect.stringContaining(\"ba\")]);\n    expect(new Set([\"bar\"])).toEqual(new Set([expect.stringContaining(\"ba\")]));\n    expect(new Set([\"bar\"])).not.toEqual(\n      new Set([expect.stringContaining(\"zoo\")])\n    );\n\n    expect({ foo: \"bar\" }).not.toEqual({ foo: expect.stringContaining(\"zoo\") });\n    expect(\"bar\").not.toEqual(expect.stringContaining(\"zoo\"));\n    expect([\"bar\"]).not.toEqual([expect.stringContaining(\"zoo\")]);\n\n    expect({ foo: \"bar\", bar: \"foo\", hi: \"hello\" }).toEqual({\n      foo: expect.stringContaining(\"ba\"),\n      bar: expect.stringContaining(\"fo\"),\n      hi: \"hello\",\n    });\n    expect(0).toEqual(expect.anything());\n    expect({}).toEqual(expect.anything());\n    expect(\"string\").toEqual(expect.anything());\n    expect(null).not.toEqual(expect.anything());\n    expect(undefined).not.toEqual(expect.anything());\n    expect({ a: 0, b: 0 }).toEqual(expect.objectContaining({ a: 0 }));\n    expect({ a: 0, b: 0 }).not.toEqual(expect.objectContaining({ z: 0 }));\n    expect(0).toEqual(expect.any(Number));\n    expect(\"string\").toEqual(expect.any(String));\n    expect(\"string\").not.toEqual(expect.any(Number));\n\n    expect([\"Bob\", \"Eve\"]).toEqual(expect.arrayContaining([\"Bob\"]));\n    expect([\"Bob\", \"Eve\"]).not.toEqual(expect.arrayContaining([\"Mohammad\"]));\n\n    expect([{ name: \"Bob\" }, { name: \"Eve\" }]).toEqual(\n      expect.arrayContaining<{ name: string }>([{ name: \"Bob\" }])\n    );\n    expect([{ name: \"Bob\" }, { name: \"Eve\" }]).not.toEqual(\n      expect.arrayContaining<{ name: string }>([{ name: \"Mohammad\" }])\n    );\n\n    expect(\"Mohammad\").toEqual(expect.stringMatching(/Moh/));\n    expect(\"Mohammad\").not.toEqual(expect.stringMatching(/jack/));\n    expect({\n      sum: 0.1 + 0.2,\n    }).toEqual({\n      sum: expect.closeTo(0.3, 5),\n    });\n\n    expect({\n      sum: 0.1 + 0.2,\n    }).not.toEqual({\n      sum: expect.closeTo(0.4, 5),\n    });\n\n    expect({\n      sum: 0.1 + 0.2,\n    }).toEqual({\n      // @ts-ignore\n      sum: expect.not.closeTo(0.4, 5),\n    });\n  });\n\n  it(\"asymmetric matchers negate\", () => {\n    expect(\"bar\").toEqual(expect.not.stringContaining(\"zoo\"));\n    expect(\"bar\").toEqual(expect.not.stringMatching(/zoo/));\n    expect({ bar: \"zoo\" }).toEqual(expect.not.objectContaining({ zoo: \"bar\" }));\n    expect([\"Bob\", \"Eve\"]).toEqual(expect.not.arrayContaining([\"Steve\"]));\n  });\n\n  it(\"object\", () => {\n    expect({}).toEqual({});\n    expect({ apples: 13 }).toEqual({ apples: 13 });\n    expect({}).toStrictEqual({});\n    expect({}).not.toBe({});\n\n    const foo = {};\n    const complex = {\n      \"0\": \"zero\",\n      foo: 1,\n      \"foo.bar[0]\": \"baz\",\n      \"a-b\": true,\n      \"a-b-1.0.0\": true,\n      bar: {\n        foo: \"foo\",\n        bar: 100,\n        arr: [\"first\", { zoo: \"monkey\" }],\n      },\n    };\n\n    expect(foo).toBe(foo);\n    expect(foo).toStrictEqual(foo);\n    expect(complex).toMatchObject({});\n    expect(complex).toMatchObject({ foo: 1 });\n    expect([complex]).toMatchObject([{ foo: 1 }]);\n    expect(complex).not.toMatchObject({ foo: 2 });\n    expect(complex).toMatchObject({ bar: { bar: 100 } });\n    expect(complex).toMatchObject({ foo: expect.any(Number) });\n\n    expect(complex).toHaveProperty(\"a-b\");\n    expect(complex).toHaveProperty(\"a-b-1.0.0\");\n    expect(complex).toHaveProperty(\"0\");\n    expect(complex).toHaveProperty(\"0\", \"zero\");\n    expect(complex).toHaveProperty([\"0\"]);\n    expect(complex).toHaveProperty([\"0\"], \"zero\");\n    expect(complex).toHaveProperty([0]);\n    expect(complex).toHaveProperty([0], \"zero\");\n    expect(complex).toHaveProperty(\"foo\");\n    expect(complex).toHaveProperty(\"foo\", 1);\n    expect(complex).toHaveProperty(\"bar.foo\", \"foo\");\n    expect(complex).toHaveProperty(\"bar.arr[0]\");\n    expect(complex).toHaveProperty(\"bar.arr[1].zoo\", \"monkey\");\n    expect(complex).toHaveProperty(\"bar.arr.0\");\n    expect(complex).toHaveProperty([\"bar\", \"arr\", \"0\"]);\n    expect(complex).toHaveProperty([\"bar\", \"arr\", \"0\"], \"first\");\n    expect(complex).toHaveProperty([\"bar\", \"arr\", 0]);\n    expect(complex).toHaveProperty([\"bar\", \"arr\", 0], \"first\");\n    expect(complex).toHaveProperty(\"bar.arr.1.zoo\", \"monkey\");\n    expect(complex).toHaveProperty([\"bar\", \"arr\", \"1\", \"zoo\"], \"monkey\");\n    expect(complex).toHaveProperty([\"foo.bar[0]\"], \"baz\");\n\n    expect(complex).toHaveProperty(\"foo\", expect.any(Number));\n    expect(complex).toHaveProperty(\"bar\", expect.any(Object));\n    expect(complex).toHaveProperty(\"bar.arr\", expect.any(Array));\n    expect(complex).toHaveProperty(\"bar.arr.0\", expect.anything());\n\n    expect(() => {\n      expect(complex).toHaveProperty(\"some-unknown-property\");\n    }).toThrowError();\n\n    expect(() => {\n      expect(complex).toHaveProperty(\"a-b\", false);\n    }).toThrowError();\n\n    expect(() => {\n      const x = { a: { b: { c: 1 } } };\n      const y = { a: { b: { c: 2 } } };\n      Object.freeze(x.a);\n      expect(x).toEqual(y);\n    }).toThrowError();\n  });\n\n  // https://jestjs.io/docs/expect#tostrictequalvalue\n\n  class LaCroix {\n    constructor(public flavor: any) {}\n  }\n\n  describe(\"the La Croix cans on my desk\", () => {\n    it(\"are not semantically the same\", () => {\n      expect(new LaCroix(\"lemon\")).toEqual({ flavor: \"lemon\" });\n      expect(new LaCroix(\"lemon\")).not.toStrictEqual({ flavor: \"lemon\" });\n    });\n  });\n\n  it(\"array\", () => {\n    expect([]).toEqual([]);\n    expect([]).not.toBe([]);\n    expect([]).toStrictEqual([]);\n\n    const foo: any[] = [];\n\n    expect(foo).toBe(foo);\n    expect(foo).toStrictEqual(foo);\n\n    const complex = [\n      {\n        foo: 1,\n        bar: { foo: \"foo\", bar: 100, arr: [\"first\", { zoo: \"monkey\" }] },\n      },\n    ];\n    expect(complex).toStrictEqual([\n      {\n        foo: 1,\n        bar: { foo: \"foo\", bar: 100, arr: [\"first\", { zoo: \"monkey\" }] },\n      },\n    ]);\n  });\n\n  describe(\"toThrow\", () => {\n    it(\"error wasn't thrown\", () => {\n      expect(() => {\n        expect(() => {}).toThrow(Error);\n      }).toThrow();\n    });\n\n    it(\"async wasn't awaited\", () => {\n      expect(() => {\n        expect(async () => {}).toThrow(Error);\n      }).toThrow();\n    });\n  });\n});\n\ndescribe(\".toStrictEqual()\", () => {\n  class TestClassA {\n    constructor(\n      public a: any,\n      public b: any\n    ) {}\n  }\n\n  class TestClassB {\n    constructor(\n      public a: any,\n      public b: any\n    ) {}\n  }\n\n  const TestClassC = class Child extends TestClassA {\n    constructor(a: any, b: any) {\n      super(a, b);\n    }\n  };\n\n  const TestClassD = class Child extends TestClassB {\n    constructor(a: any, b: any) {\n      super(a, b);\n    }\n  };\n\n  it(\"does not ignore keys with undefined values\", () => {\n    expect({\n      a: undefined,\n      b: 2,\n    }).not.toStrictEqual({ b: 2 });\n  });\n\n  it(\"does not ignore keys with undefined values inside an array\", () => {\n    expect([{ a: undefined }]).not.toStrictEqual([{}]);\n  });\n\n  it(\"does not ignore keys with undefined values deep inside an object\", () => {\n    expect([{ a: [{ a: undefined }] }]).not.toStrictEqual([{ a: [{}] }]);\n  });\n\n  it(\"does not consider holes as undefined in sparse arrays\", () => {\n    expect([, , , 1, , ,]).not.toStrictEqual([, , , 1, undefined, ,]);\n  });\n\n  it(\"passes when comparing same type\", () => {\n    expect({\n      test: new TestClassA(1, 2),\n    }).toStrictEqual({ test: new TestClassA(1, 2) });\n  });\n\n  it(\"does not pass for different types\", () => {\n    expect({\n      test: new TestClassA(1, 2),\n    }).not.toStrictEqual({ test: new TestClassB(1, 2) });\n  });\n\n  it(\"does not simply compare constructor names\", () => {\n    const c = new TestClassC(1, 2);\n    const d = new TestClassD(1, 2);\n    expect(c.constructor.name).toEqual(d.constructor.name);\n    expect({ test: c }).not.toStrictEqual({ test: d });\n  });\n\n  it(\"passes for matching sparse arrays\", () => {\n    expect([, 1]).toStrictEqual([, 1]);\n  });\n\n  it(\"does not pass when sparseness of arrays do not match\", () => {\n    expect([, 1]).not.toStrictEqual([undefined, 1]);\n    expect([undefined, 1]).not.toStrictEqual([, 1]);\n    expect([, , , 1]).not.toStrictEqual([, 1]);\n  });\n\n  it(\"does not pass when equally sparse arrays have different values\", () => {\n    expect([, 1]).not.toStrictEqual([, 2]);\n  });\n\n  it(\"does not pass when ArrayBuffers are not equal\", () => {\n    expect(Uint8Array.from([1, 2]).buffer).not.toStrictEqual(\n      Uint8Array.from([0, 0]).buffer\n    );\n    expect(Uint8Array.from([2, 1]).buffer).not.toStrictEqual(\n      Uint8Array.from([2, 2]).buffer\n    );\n    expect(Uint8Array.from([]).buffer).not.toStrictEqual(\n      Uint8Array.from([1]).buffer\n    );\n  });\n\n  it(\"passes for matching buffers\", () => {\n    expect(Uint8Array.from([1]).buffer).toStrictEqual(\n      Uint8Array.from([1]).buffer\n    );\n    expect(Uint8Array.from([]).buffer).toStrictEqual(\n      Uint8Array.from([]).buffer\n    );\n    expect(Uint8Array.from([9, 3]).buffer).toStrictEqual(\n      Uint8Array.from([9, 3]).buffer\n    );\n  });\n\n  it(\"does not pass for DataView\", () => {\n    expect(new DataView(Uint8Array.from([1, 2, 3]).buffer)).not.toStrictEqual(\n      new DataView(Uint8Array.from([3, 2, 1]).buffer)\n    );\n\n    expect(new DataView(Uint16Array.from([1, 2]).buffer)).not.toStrictEqual(\n      new DataView(Uint16Array.from([2, 1]).buffer)\n    );\n  });\n\n  it(\"passes for matching DataView\", () => {\n    expect(new DataView(Uint8Array.from([1, 2, 3]).buffer)).toStrictEqual(\n      new DataView(Uint8Array.from([1, 2, 3]).buffer)\n    );\n    expect(new DataView(Uint8Array.from([]).buffer)).toStrictEqual(\n      new DataView(Uint8Array.from([]).buffer)\n    );\n  });\n});\n\ndescribe(\"toBeTypeOf()\", () => {\n  it(\"pass with typeof\", () => {\n    [\n      [1n, \"bigint\"],\n      [true, \"boolean\"],\n      [false, \"boolean\"],\n      [(() => {}) as () => void, \"function\"],\n      [function () {} as () => void, \"function\"],\n      [1, \"number\"],\n      [Number.POSITIVE_INFINITY, \"number\"],\n      [Number.NaN, \"number\"],\n      [0, \"number\"],\n      [{}, \"object\"],\n      [[], \"object\"],\n      [null, \"object\"],\n      [\"\", \"string\"],\n      [\"test\", \"string\"],\n      [Symbol(\"test\"), \"symbol\"],\n      [undefined, \"undefined\"],\n    ].forEach((value) => {\n      // @ts-ignore\n      expect(value[0]).toBeTypeOf(value[1]);\n    });\n  });\n  it(\"pass with negotiation\", () => {\n    // @ts-ignore\n    expect(\"test\").not.toBeTypeOf(\"number\");\n  });\n});\n\ndescribe(\"toSatisfy()\", () => {\n  const isOdd = (value: number) => value % 2 !== 0;\n\n  it(\"pass with 0\", () => {\n    // @ts-ignore\n    expect(1).toSatisfy(isOdd);\n  });\n\n  it(\"pass with negotiation\", () => {\n    // @ts-ignore\n    expect(2).not.toSatisfy(isOdd);\n  });\n});\n\nit(\"timeout\", () => new Promise((resolve) => setTimeout(resolve, 0)));\n*/\ndescribe(\"beforeEach\", () => {\n  let value: string;\n  beforeEach(() => {\n    value = \"beforeEach\";\n  });\n\n  it(\"should have value\", () => {\n    expect(value).toEqual(\"beforeEach\");\n  });\n\n  describe(\"nested beforeEach\", () => {\n    beforeEach(() => {\n      value += \" nested\";\n    });\n\n    it(\"should have aggregated value\", () => {\n      expect(value).toEqual(\"beforeEach nested\");\n    });\n  });\n\n  describe(\"nested describe without beforeEach\", () => {\n    it(\"should have value\", () => {\n      expect(value).toEqual(\"beforeEach\");\n    });\n  });\n});\n\ndescribe(\"afterEach\", () => {\n  let value: string;\n  afterEach(() => {\n    value = \"afterEach\";\n  });\n\n  afterAll(() => {\n    expect(value).toContain(\"afterEach\");\n  });\n\n  it(\"should have value\", () => {\n    // do nothing\n  });\n\n  describe(\"nested describe without afterEach\", () => {\n    afterAll(() => {\n      expect(value).toEqual(\"afterEach\");\n    });\n\n    it(\"should have value\", () => {\n      // do nothing\n    });\n  });\n\n  describe(\"nested afterEach\", () => {\n    afterEach(() => {\n      value += \" nested\";\n    });\n\n    afterAll(() => {\n      expect(value).toEqual(\"afterEach nested\");\n    });\n\n    it(\"should have aggregated value\", () => {\n      // do nothing\n    });\n  });\n});\n"
  },
  {
    "path": "tests/unit/json.test.ts",
    "content": "describe(\"JSON Parsing\", () => {\n  it(\"should parse valid JSON\", () => {\n    const parsedData = JSON.parse('{\"key\": \"value\"}');\n    expect(parsedData).toStrictEqual({ key: \"value\" });\n  });\n\n  it(\"should handle invalid JSON\", () => {\n    const invalidJsonString = '{key: \"value\"}';\n    expect(() => {\n      JSON.parse(invalidJsonString);\n    }).toThrow();\n\n    const emptyJsonString = \"\";\n    expect(() => {\n      JSON.parse(emptyJsonString);\n    }).toThrow();\n  });\n\n  it(\"should parse JSON with nested structures\", () => {\n    const parsedData = JSON.parse(\n      '{\"name\": \"John\", \"age\": 25, \"address\": {\"city\": \"New York\", \"zip\": \"10001\"}}'\n    );\n    expect(parsedData).toStrictEqual({\n      name: \"John\",\n      age: 25,\n      address: { city: \"New York\", zip: \"10001\" },\n    });\n  });\n\n  it(\"should parse JSON with arrays\", () => {\n    const parsedData = JSON.parse('[1, 2, 3, {\"key\": \"value\"}]');\n    expect(parsedData).toStrictEqual([1, 2, 3, { key: \"value\" }]);\n  });\n\n  it(\"should parse JSON with boolean values\", () => {\n    const parsedData = JSON.parse('{\"isTrue\": true, \"isFalse\": false}');\n    expect(parsedData).toStrictEqual({ isTrue: true, isFalse: false });\n  });\n\n  it(\"should parse JSON with null values\", () => {\n    const parsedData = JSON.parse('{\"nullableValue\": null}');\n    expect(parsedData).toStrictEqual({ nullableValue: null });\n  });\n\n  it(\"should parse JSON with large int value\", () => {\n    const parsedData = JSON.parse('{\"bigInt\": 888888888888888888}');\n    expect(parsedData).toStrictEqual({ bigInt: 888888888888888888 });\n  });\n\n  it(\"should parse JSON with special characters\", () => {\n    const specialChars = \"!@#$%^&*()_+-={}[]|;:,.<>?/\";\n    const parsedData = JSON.parse(`{\"specialChars\": \"${specialChars}\"}`);\n    expect(parsedData).toStrictEqual({ specialChars });\n  });\n});\n\ndescribe(\"JSON Stringified\", () => {\n  it(\"should stringify JSON\", () => {\n    const data = { key: \"value\", age: 25 };\n    const jsonString = JSON.stringify(data);\n    const parsedData = JSON.parse(jsonString);\n    expect(parsedData).toStrictEqual(data);\n  });\n\n  it(\"should handle toJSON method on regular objects\", () => {\n    const objWithToJSON = {\n      key: \"value\",\n      age: 25,\n      toJSON() {\n        return { customKey: this.key.toUpperCase(), customAge: this.age * 2 };\n      },\n    };\n\n    const parsedData = JSON.parse(JSON.stringify(objWithToJSON));\n    expect(parsedData).toStrictEqual({ customKey: \"VALUE\", customAge: 50 });\n  });\n\n  it(\"should print floats without fractions as integers\", () => {\n    const jsonString = JSON.stringify({ value: 1.0 });\n    expect(jsonString).toEqual('{\"value\":1}');\n  });\n\n  it(\"should print very large numbers as floats with scientific notation\", () => {\n    const jsonString = JSON.stringify({\n      value: 999999999999999999999999999999,\n    });\n    expect(jsonString).toEqual('{\"value\":1e30}');\n  });\n\n  it(\"should stringify and parse recursive JSON with self-referencing structures\", () => {\n    const recursiveData: any = {\n      key: \"value\",\n      nested: {\n        age: 25,\n        inner: null, // self-reference\n      },\n    };\n\n    recursiveData.nested.inner = recursiveData; // create self-reference\n\n    expect(() => {\n      JSON.stringify(recursiveData);\n    }).toThrow();\n  });\n\n  it(\"Should stringify an object with default spacing\", () => {\n    const data = {\n      key: \"value\",\n      bool: true,\n      num: 42,\n      arr: [1, 2, 3],\n      nested: {\n        level1: {\n          level2: {\n            level3: \"nestedValue\",\n          },\n        },\n      },\n    };\n    const jsonString = JSON.stringify(data, null, 4);\n    const expectedJsonString = `{\n    \"key\": \"value\",\n    \"bool\": true,\n    \"num\": 42,\n    \"arr\": [\n        1,\n        2,\n        3\n    ],\n    \"nested\": {\n        \"level1\": {\n            \"level2\": {\n                \"level3\": \"nestedValue\"\n            }\n        }\n    }\n}`;\n    expect(jsonString).toEqual(expectedJsonString);\n  });\n\n  // Test JSON stringifying with custom spacing as a string\n  it(\"Should stringify an object with default custom spacing\", () => {\n    const data = {\n      key: \"value\",\n      bool: false,\n      num: 3.14,\n      arr: [\"apple\", \"banana\", \"cherry\"],\n      nested: {\n        level1: {\n          level2: {\n            level3: \"nestedValue\",\n          },\n        },\n      },\n    };\n    const jsonString = JSON.stringify(data, null, \"   \");\n    const expectedJsonString = `{\n   \"key\": \"value\",\n   \"bool\": false,\n   \"num\": 3.14,\n   \"arr\": [\n      \"apple\",\n      \"banana\",\n      \"cherry\"\n   ],\n   \"nested\": {\n      \"level1\": {\n         \"level2\": {\n            \"level3\": \"nestedValue\"\n         }\n      }\n   }\n}`;\n    expect(jsonString).toEqual(expectedJsonString);\n  });\n\n  // Test JSON stringifying with replacer as a function\n  it(\"Should stringify an object with a replacer function\", () => {\n    const data = { key: \"value\", secret: \"hidden\" };\n    const replacerFunction = (key: string, value: any) =>\n      key === \"secret\" ? undefined : value;\n    const jsonString = JSON.stringify(data, replacerFunction, 2);\n    expect(jsonString).toEqual('{\\n  \"key\": \"value\"\\n}');\n  });\n\n  // Test more complex JSON structure\n  it(\"Should stringify a complex object with custom spacing and replacer\", () => {\n    const date = new Date();\n    class Foo {\n      prop = 1;\n    }\n    const complexData = {\n      key: \"value\",\n      date,\n      nested: {\n        array: [1, 2, 3],\n        obj: { a: \"apple\", b: \"banana\" },\n        foo: new Foo(),\n        arrowFn: () => {},\n        fn: function () {},\n        namedFn: function namedFn() {},\n      },\n    };\n\n    const replacerFunction = (key: string, value: any) =>\n      typeof value === \"string\" ? value.toUpperCase() : value;\n\n    const jsonString = JSON.stringify(complexData, replacerFunction, 4);\n\n    const expectedJsonString = `{\n    \"key\": \"VALUE\",\n    \"date\": \"${date.toJSON()}\",\n    \"nested\": {\n        \"array\": [\n            1,\n            2,\n            3\n        ],\n        \"obj\": {\n            \"a\": \"APPLE\",\n            \"b\": \"BANANA\"\n        },\n        \"foo\": {\n            \"prop\": 1\n        }\n    }\n}`;\n\n    expect(jsonString).toEqual(expectedJsonString);\n  });\n\n  it(\"should stringify objects with undefined values\", () => {\n    const valueStart = {\n      a: undefined,\n      b: \"123\",\n      c: \"123\",\n    };\n    expect(JSON.stringify(valueStart)).toEqual(`{\"b\":\"123\",\"c\":\"123\"}`);\n\n    const jsonStartIndented = JSON.stringify(valueStart, null, \"   \");\n    const expectedJsonStartString = `{\n   \"b\": \"123\",\n   \"c\": \"123\"\n}`;\n    expect(jsonStartIndented).toEqual(expectedJsonStartString);\n\n    const valueMiddle = {\n      a: \"123\",\n      b: undefined,\n      c: \"123\",\n    };\n    expect(JSON.stringify(valueMiddle)).toEqual(`{\"a\":\"123\",\"c\":\"123\"}`);\n\n    const jsonMiddleIndented = JSON.stringify(valueMiddle, null, \"   \");\n    const expectedJsonMiddleString = `{\n   \"a\": \"123\",\n   \"c\": \"123\"\n}`;\n    expect(jsonMiddleIndented).toEqual(expectedJsonMiddleString);\n\n    const valueEnd = {\n      a: \"123\",\n      b: \"123\",\n      c: undefined,\n    };\n    expect(JSON.stringify(valueEnd)).toEqual(`{\"a\":\"123\",\"b\":\"123\"}`);\n\n    const jsonEndIndented = JSON.stringify(valueEnd, null, \"   \");\n    const expectedJsonEndString = `{\n   \"a\": \"123\",\n   \"b\": \"123\"\n}`;\n    expect(jsonEndIndented).toEqual(expectedJsonEndString);\n\n    const valueMixed = JSON.stringify({\n      a: \"123\",\n      b: undefined,\n      c: undefined,\n      d: \"123\",\n      e: undefined,\n      f: \"123\",\n      g: \"123\",\n      h: undefined,\n      i: undefined,\n    });\n\n    expect(valueMixed).toEqual(`{\"a\":\"123\",\"d\":\"123\",\"f\":\"123\",\"g\":\"123\"}`);\n  });\n\n  it(\"should stringify arrays with undefined values\", () => {\n    const valueStart = [undefined, \"123\", \"123\"];\n    expect(JSON.stringify(valueStart)).toEqual(`[null,\"123\",\"123\"]`);\n\n    const valueMiddle = [\"123\", undefined, \"123\"];\n    expect(JSON.stringify(valueMiddle)).toEqual(`[\"123\",null,\"123\"]`);\n\n    const valueEnd = [\"123\", \"123\", undefined];\n    expect(JSON.stringify(valueEnd)).toEqual(`[\"123\",\"123\",null]`);\n  });\n\n  it(\"should stringify and remove objects that are not valid json\", () => {\n    const now = new Date();\n    const dateString = now.toJSON();\n    const data = {\n      a: \"123\",\n      b: undefined,\n      c: () => {\n        return \"123\";\n      },\n      d: RegExp(\"apa\"),\n      e: now,\n    };\n    expect(JSON.stringify(data)).toEqual(\n      `{\"a\":\"123\",\"d\":{},\"e\":\"${dateString}\"}`\n    );\n  });\n\n  it(\"should stringify an exception\", () => {\n    const exception = new Error(\"error\");\n    expect(JSON.stringify(exception)).toEqual(\"{}\");\n  });\n\n  it(\"should throw an Error when stringify BigInt\", () => {\n    expect(() =>\n      JSON.stringify({\n        v: 1n,\n      })\n    ).toThrow(/Do not know how to serialize a BigInt/);\n  });\n\n  it(\"should allow replacer that returns new non-primitive objects\", () => {\n    const json = JSON.stringify({ key: \"value\" });\n\n    const obj = {\n      simple: \"text\",\n      nested: json,\n    };\n\n    const replacer = (key: any, value: any) => {\n      try {\n        return typeof value === \"string\" ? JSON.parse(value) : value;\n      } catch {\n        return value;\n      }\n    };\n\n    const result = JSON.stringify(obj, replacer);\n    expect(result).toEqual('{\"simple\":\"text\",\"nested\":{\"key\":\"value\"}}');\n  });\n\n  it(\"should escape broken surrogate pairs and other strange text\", () => {\n    const text =\n      \"[A-Za-z\\u00c0-\\u00d6\\u00d8-\\u00f6\\u00f8-\\u02b8\\u0300-\\u0590\\u0900-\\u1fff\\u200e\\u2c00-\\ud801\\ud804-\\ud839\\ud83c-\\udbff\\uf900-\\ufb1c\\ufe00-\\ufe6f\\ufefd-\\uffff]\";\n\n    const json = JSON.stringify(text);\n    expect(json).toEqual(`\"${text}\"`);\n  });\n});\n"
  },
  {
    "path": "tests/unit/llrt.qjs.test.ts",
    "content": "import { ComputeMemoryUsage } from \"llrt:qjs\";\n\ndescribe(\"ComputeMemoryUsage\", () => {\n  it(\"should exist function and should be available\", () => {\n    const usage = ComputeMemoryUsage();\n\n    expect(usage.malloc_size).toBeGreaterThanOrEqual(0);\n    expect(usage.malloc_limit).toBeGreaterThanOrEqual(0);\n    expect(usage.memory_used_size).toBeGreaterThanOrEqual(0);\n    expect(usage.malloc_count).toBeGreaterThanOrEqual(0);\n    expect(usage.memory_used_count).toBeGreaterThanOrEqual(0);\n    expect(usage.atom_count).toBeGreaterThanOrEqual(0);\n    expect(usage.atom_size).toBeGreaterThanOrEqual(0);\n    expect(usage.str_count).toBeGreaterThanOrEqual(0);\n    expect(usage.str_size).toBeGreaterThanOrEqual(0);\n    expect(usage.obj_count).toBeGreaterThanOrEqual(0);\n    expect(usage.obj_size).toBeGreaterThanOrEqual(0);\n    expect(usage.prop_count).toBeGreaterThanOrEqual(0);\n    expect(usage.prop_size).toBeGreaterThanOrEqual(0);\n    expect(usage.shape_count).toBeGreaterThanOrEqual(0);\n    expect(usage.shape_size).toBeGreaterThanOrEqual(0);\n    expect(usage.js_func_count).toBeGreaterThanOrEqual(0);\n    expect(usage.js_func_size).toBeGreaterThanOrEqual(0);\n    expect(usage.js_func_code_size).toBeGreaterThanOrEqual(0);\n    expect(usage.js_func_pc2line_count).toBeGreaterThanOrEqual(0);\n    expect(usage.js_func_pc2line_size).toBeGreaterThanOrEqual(0);\n    expect(usage.c_func_count).toBeGreaterThanOrEqual(0);\n    expect(usage.array_count).toBeGreaterThanOrEqual(0);\n    expect(usage.fast_array_count).toBeGreaterThanOrEqual(0);\n    expect(usage.fast_array_elements).toBeGreaterThanOrEqual(0);\n    expect(usage.binary_object_count).toBeGreaterThanOrEqual(0);\n    expect(usage.binary_object_size).toBeGreaterThanOrEqual(0);\n  });\n});\n"
  },
  {
    "path": "tests/unit/llrt.xml.test.ts",
    "content": "import { XMLParser, XmlText, XmlNode } from \"llrt:xml\";\n\ndescribe(\"XMLParser options and handling\", () => {\n  it(\"should parse xml\", () => {\n    const xmlString =\n      '<root><person occupation=\"programmer\">John</person></root>';\n    const expectedResult = {\n      root: { person: \"John\" },\n    };\n    const parser = new XMLParser();\n    const result = parser.parse(xmlString);\n    expect(result).toStrictEqual(expectedResult);\n  });\n\n  it(\"should apply attributeValueProcessor\", () => {\n    const xmlString =\n      '<root><person occupation=\"programmer\">John</person></root>';\n    const expectedResult = {\n      root: { person: { _attr_occupation: \"PROGRAMMER\", name: \"John\" } },\n    };\n    const parser = new XMLParser({\n      ignoreAttributes: false,\n      attributeNamePrefix: \"_attr_\",\n      textNodeName: \"name\",\n      attributeValueProcessor: (_, val) => val.toUpperCase(),\n    });\n    const result = parser.parse(xmlString);\n    expect(result).toStrictEqual(expectedResult);\n  });\n\n  it(\"should apply tagValueProcessor\", () => {\n    const xmlString = \"<root><name><![CDATA[John]]></name></root>\";\n    const expectedResult = {\n      root: {\n        name: \"JOHN\",\n      },\n    };\n    const parser = new XMLParser({\n      tagValueProcessor: (_, val) => val.toUpperCase(),\n    });\n    const result = parser.parse(xmlString);\n    expect(result).toStrictEqual(expectedResult);\n  });\n\n  it('should handle attributeNamePrefix with default \"@\"', () => {\n    const xmlString = '<root><person first_name=\"John\" /></root>';\n    const expectedResult = {\n      root: {\n        person: {\n          \"@_first_name\": \"John\",\n        },\n      },\n    };\n    const parser = new XMLParser({\n      ignoreAttributes: false,\n    });\n    const result = parser.parse(xmlString);\n    expect(result).toStrictEqual(expectedResult);\n  });\n\n  it(\"should handle custom attributeNamePrefix\", () => {\n    const xmlString = '<root><person first_name=\"John\" /></root>';\n    const expectedResult = {\n      root: {\n        person: {\n          \"#first_name\": \"John\",\n        },\n      },\n    };\n    const parser = new XMLParser({\n      attributeNamePrefix: \"#\",\n      ignoreAttributes: false,\n    });\n    const result = parser.parse(xmlString);\n    expect(result).toStrictEqual(expectedResult);\n  });\n\n  it(\"should handle siblings with the same tag name as an array\", () => {\n    const xmlString =\n      \"<root><person>John</person><person>Alice</person></root>\";\n    const expectedResult = {\n      root: {\n        person: [\"John\", \"Alice\"],\n      },\n    };\n    const parser = new XMLParser();\n    const result = parser.parse(xmlString);\n    expect(result).toStrictEqual(expectedResult);\n  });\n\n  it(\"should handle empty tag attributes\", () => {\n    const xmlString = '<root><person name=\"John\"/></root>';\n    const expectedResult = {\n      root: {\n        person: {\n          \"@_name\": \"John\",\n        },\n      },\n    };\n    const parser = new XMLParser({ ignoreAttributes: false });\n    const result = parser.parse(xmlString);\n    expect(result).toStrictEqual(expectedResult);\n  });\n\n  it(\"should handle attributes and text content for sibling arrays\", () => {\n    const xmlString =\n      '<root><person name=\"John\">Developer</person><person name=\"Alice\">Designer</person></root>';\n    const expectedResult = {\n      root: {\n        person: [\n          { \"@_name\": \"John\", \"#text\": \"Developer\" },\n          { \"@_name\": \"Alice\", \"#text\": \"Designer\" },\n        ],\n      },\n    };\n    const parser = new XMLParser({\n      ignoreAttributes: false,\n    });\n    const result = parser.parse(xmlString);\n    expect(result).toStrictEqual(expectedResult);\n  });\n\n  it(\"should handle attributes and text content for sibling arrays for empty tags\", () => {\n    const xmlString =\n      '<root><person name=\"John\"/><person name=\"Alice\"/></root>';\n    const expectedResult = {\n      root: { person: [{ \"@_name\": \"John\" }, { \"@_name\": \"Alice\" }] },\n    };\n    const parser = new XMLParser({\n      ignoreAttributes: false,\n    });\n    const result = parser.parse(xmlString);\n    expect(result).toStrictEqual(expectedResult);\n  });\n\n  it(\"should handle empty child tags\", () => {\n    const xmlString = \"<data><prefix></prefix><name></name><empty/></data>\";\n    const expectedResult = {\n      data: { prefix: \"\", name: \"\", empty: \"\" },\n    };\n    const parser = new XMLParser({\n      ignoreAttributes: false,\n    });\n    const result = parser.parse(xmlString);\n    expect(result).toStrictEqual(expectedResult);\n  });\n\n  it(\"should handle attributes and text content for sibling arrays\", () => {\n    const xmlString =\n      '<root><person>John</person><person role=\"Designer\">Alice</person></root>';\n    const expectedResult = {\n      root: { person: [\"John\", { \"@_role\": \"Designer\", \"#text\": \"Alice\" }] },\n    };\n    const parser = new XMLParser({\n      ignoreAttributes: false,\n    });\n    const result = parser.parse(xmlString);\n    expect(result).toStrictEqual(expectedResult);\n  });\n  it(\"should handle attributes and text content for different objects and siblings\", () => {\n    const xmlString =\n      \"<root><person>John</person><person>Alice</person><group>Developers</group></root>\";\n    const expectedResult = {\n      root: {\n        person: [\"John\", \"Alice\"],\n        group: \"Developers\",\n      },\n    };\n    const parser = new XMLParser({\n      ignoreAttributes: false,\n    });\n    const result = parser.parse(xmlString);\n    expect(result).toStrictEqual(expectedResult);\n  });\n\n  it(\"Will escape ref\", () => {\n    const xmlString =\n      '<?xml version=\"1.0\" encoding=\"UTF-8\"?><ListPartsResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><ETag>&quot;7265f4d211b56873a381d321f586e4a9&quot;</ETag><data>Hello&#10;world!</data></ListPartsResult>';\n    const expectedResult = {\n      ListPartsResult: {\n        \"@_xmlns\": \"http://s3.amazonaws.com/doc/2006-03-01/\",\n        ETag: '\"7265f4d211b56873a381d321f586e4a9\"',\n        data: \"Hello\\nworld!\",\n      },\n    };\n    const parser = new XMLParser({\n      ignoreAttributes: false,\n    });\n    parser.addEntity(\"#10\", \"\\n\");\n    const result = parser.parse(xmlString);\n\n    expect(result).toStrictEqual(expectedResult);\n  });\n});\n\ndescribe(\"XML Builder\", () => {\n  it(\"Can create XmlText with escaped values\", () => {\n    let xml = new XmlText(\"<john>doe</john>\").toString();\n\n    expect(xml).toEqual(\"&lt;john&gt;doe&lt;/john&gt;\");\n  });\n\n  it(\"Can build XML with empty tag\", () => {\n    let xml = new XmlNode(\"data\").toString();\n\n    expect(xml).toEqual(\"<data/>\");\n  });\n\n  it(\"Can build XML with child\", () => {\n    let xml = new XmlNode(\"data\", [\"example\"]).toString();\n\n    expect(xml).toEqual(\"<data>example</data>\");\n  });\n\n  it(\"Can build XML with nested child\", () => {\n    let xml = new XmlNode(\"root\", [\"example\"]);\n\n    const node = XmlNode.of(\"expression\", \"foo\").withName(\"expression\");\n    const node2 = XmlNode.of(\"expression2\", \"bar\").withName(\"expression\");\n    xml.addChildNode(node);\n    node.addChildNode(node2);\n\n    expect(xml.toString()).toEqual(\n      \"<root>example<expression>foo<expression>bar</expression></expression></root>\"\n    );\n  });\n\n  it(\"Can build XML with deeply nested child\", () => {\n    let xml = new XmlNode(\"root\");\n    const node = XmlNode.of(\"level1\");\n    const node2 = XmlNode.of(\"level2\");\n    const node3 = XmlNode.of(\"level3\", \"foobar\");\n    xml.addChildNode(node);\n    node.addChildNode(node2);\n    node2.addChildNode(node3);\n\n    expect(xml.toString()).toEqual(\n      \"<root><level1><level2><level3>foobar</level3></level2></level1></root>\"\n    );\n  });\n\n  it(\"Can build XML with attributes\", () => {\n    let xml = XmlNode.of(\"root\")\n      .addAttribute(\"example\", \"data\")\n      .addAttribute(\"example2\", \"data2\")\n      .addAttribute(\"example3\", \"data3\")\n      .removeAttribute(\"example3\");\n\n    expect(xml.toString()).toEqual('<root example=\"data\" example2=\"data2\"/>');\n  });\n});\n"
  },
  {
    "path": "tests/unit/module.test.ts",
    "content": "import defaultImport from \"node:module\";\nimport legacyImport from \"module\";\n\nit(\"node:module should be the same as module\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n\nconst { createRequire } = defaultImport;\n\nit(\"should resolve 'node:module via createRequire()\", () => {\n  const __require = createRequire(import.meta.url);\n  expect(__require(\"node:module\").createRequire).toBeDefined();\n});\n"
  },
  {
    "path": "tests/unit/navigator.test.ts",
    "content": "describe(\"navigator.userAgent\", () => {\n  it('should start with \"llrt \"', () => {\n    expect(navigator.userAgent.startsWith(\"llrt \")).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "tests/unit/net.test.ts",
    "content": "import defaultImport from \"node:net\";\nimport legacyImport from \"net\";\n\nit(\"node:net should be the same as net\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n"
  },
  {
    "path": "tests/unit/numbers.test.ts",
    "content": "describe(\"Number to base conversion within 32-bit range\", () => {\n  const testCases = [\n    { num: 0, radix: 2, expected: \"0\" },\n    { num: 1, radix: 2, expected: \"1\" },\n    { num: -1, radix: 2, expected: \"-1\" },\n    { num: NaN, radix: 2, expected: \"NaN\" },\n    { num: Infinity, radix: 2, expected: \"Infinity\" },\n\n    { num: 255, radix: 16, expected: \"ff\" },\n    { num: -255, radix: 16, expected: \"-ff\" },\n    { num: NaN, radix: 16, expected: \"NaN\" },\n    { num: Infinity, radix: 16, expected: \"Infinity\" },\n\n    { num: 1023, radix: 8, expected: \"1777\" },\n    { num: -1023, radix: 8, expected: \"-1777\" },\n    { num: NaN, radix: 8, expected: \"NaN\" },\n    { num: Infinity, radix: 8, expected: \"Infinity\" },\n\n    { num: 123456789, radix: 10, expected: \"123456789\" },\n    { num: -123456789, radix: 10, expected: \"-123456789\" },\n    { num: 12345.6789, radix: 10, expected: \"12345.6789\" },\n    { num: -12345.6789, radix: 10, expected: \"-12345.6789\" },\n    { num: NaN, radix: 10, expected: \"NaN\" },\n    { num: Infinity, radix: 10, expected: \"Infinity\" },\n    { num: -Infinity, radix: 10, expected: \"-Infinity\" },\n\n    { num: 2147483647, radix: 16, expected: \"7fffffff\" }, // max 32bit signed\n    { num: -2147483648, radix: 16, expected: \"-80000000\" }, // min 32bit signed\n    { num: 12345.6789, radix: 16, expected: \"3039.adcc63f14\" },\n    { num: -12345.6789, radix: 16, expected: \"-3039.adcc63f14\" },\n    { num: NaN, radix: 16, expected: \"NaN\" },\n    { num: Infinity, radix: 16, expected: \"Infinity\" },\n    { num: -Infinity, radix: 16, expected: \"-Infinity\" },\n\n    { num: 100, radix: 36, expected: \"2s\" },\n    { num: -100, radix: 36, expected: \"-2s\" },\n    { num: NaN, radix: 36, expected: \"NaN\" },\n    { num: Infinity, radix: 36, expected: \"Infinity\" },\n\n    { num: new Number(0), radix: undefined, expected: \"0\" },\n    { num: new Number(42), radix: undefined, expected: \"42\" },\n  ];\n\n  testCases.forEach(({ num, radix, expected }) => {\n    it(`num=${num} radix=${radix} => ${expected}`, () => {\n      const actual = num.toString(radix);\n      expect(actual).toBe(expected);\n    });\n  });\n});\n\ndescribe(\"Number to base conversion over 32-bit range\", () => {\n  const num = 1749475325433;\n\n  it(\"should convert number to binary (base-2)\", () => {\n    expect(num.toString(2)).toEqual(\n      \"11001011101010100110110101111010111111001\"\n    );\n  });\n\n  it(\"should convert number to octal (base-8)\", () => {\n    expect(num.toString(8)).toEqual(\"31352466572771\");\n  });\n\n  it(\"should convert number to decimal (base-10)\", () => {\n    expect(num.toString(10)).toEqual(\"1749475325433\");\n  });\n\n  it(\"should convert number to hexadecimal (base-16)\", () => {\n    expect(num.toString(16)).toEqual(\"19754daf5f9\");\n  });\n\n  it(\"should convert number to base-20\", () => {\n    expect(num.toString(20)).toEqual(\"386fb0fdbd\");\n  });\n\n  it(\"should convert number to base-26\", () => {\n    expect(num.toString(26)).toEqual(\"89l74gagh\");\n  });\n\n  it(\"should convert number to base-32\", () => {\n    expect(num.toString(32)).toEqual(\"1itadltfp\");\n  });\n\n  it(\"should convert number to base-36\", () => {\n    expect(num.toString(36)).toEqual(\"mbp4fshl\");\n  });\n});\n"
  },
  {
    "path": "tests/unit/os.test.ts",
    "content": "import defaultImport from \"node:os\";\nimport legacyImport from \"os\";\n\nit(\"node:os should be the same as os\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n"
  },
  {
    "path": "tests/unit/path.test.ts",
    "content": "import defaultImport from \"node:path\";\nimport legacyImport from \"path\";\n\nimport path from \"node:path\";\nimport { platform } from \"node:os\";\nconst IS_WINDOWS = platform() === \"win32\";\n\nit(\"node:path should be the same as path\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n\nconst {\n  basename,\n  dirname,\n  extname,\n  format,\n  parse,\n  join,\n  resolve,\n  normalize,\n  isAbsolute,\n  relative,\n} = defaultImport;\n\nconst normalizeSeparator = (string: string) => {\n  return string.replaceAll(\"\\\\\", path.sep).replaceAll(\"/\", path.sep);\n};\n\n//relative depends on cwd if any argument is relative\nconst calculateRelativeDepth = (from: string, to: string) => {\n  const fromParts = path.resolve(from).split(path.sep);\n  const toParts = path.resolve(to).split(path.sep);\n\n  //find the first index where the paths differ\n  let i = 0;\n  while (\n    i < fromParts.length &&\n    i < toParts.length &&\n    fromParts[i] === toParts[i]\n  ) {\n    i++;\n  }\n\n  //calculate how many '../' are needed from \"from\" to reach common base directory\n  const upLevels = fromParts.length - i;\n  const downPath = toParts.slice(i).join(path.sep);\n\n  //return the correct number of '../' segments followed by the remaining \"to\" path\n  return `${`..${path.sep}`.repeat(upLevels)}${downPath}`;\n};\n\ndescribe(\"basename\", () => {\n  it(\"should return the last portion of a path\", () => {\n    expect(basename(\"C:/foo/bar/baz.txt\")).toEqual(\"baz.txt\");\n    expect(basename(\"/foo/bar/baz.txt\")).toEqual(\"baz.txt\");\n    expect(basename(\"/foo/bar/baz.txt\", \".txt\")).toEqual(\"baz\");\n    expect(basename(\"/foo/bar/baz/\")).toEqual(\"baz\");\n    expect(basename(\"/foo/bar/baz\")).toEqual(\"baz\");\n    expect(basename(\"baz.txt\")).toEqual(\"baz.txt\");\n    expect(basename(\"/foo/bar/\")).toEqual(\"bar\");\n    expect(basename(\"/foo/bar\")).toEqual(\"bar\");\n    expect(basename(\"/foo/\")).toEqual(\"foo\");\n    expect(basename(\"/foo\")).toEqual(\"foo\");\n    expect(basename(\"/\")).toEqual(\"\");\n    expect(basename(\"\")).toEqual(\"\");\n  });\n});\n\ndescribe(\"dirname\", () => {\n  it(\"should return the directory path of a given path\", () => {\n    // dirname preserves the separator style from the input\n    expect(dirname(\"/foo/bar/baz.txt\")).toEqual(\"/foo/bar\");\n    expect(dirname(\"/foo/bar/baz/\")).toEqual(\"/foo/bar\");\n    expect(dirname(\"/foo/bar/baz\")).toEqual(\"/foo/bar\");\n    expect(dirname(\"/foo/bar/\")).toEqual(\"/foo\");\n    expect(dirname(\"/foo/bar\")).toEqual(\"/foo\");\n    expect(dirname(\"/foo/\")).toEqual(\"/\");\n    expect(dirname(\"/foo\")).toEqual(\"/\");\n    expect(dirname(\"/\")).toEqual(\"/\");\n    expect(dirname(\"baz.txt\")).toEqual(\".\");\n    expect(dirname(\"\")).toEqual(\".\");\n    if (IS_WINDOWS) {\n      expect(dirname(\"C:\\\\foo\\\\bar\\\\baz.txt\")).toEqual(\"C:\\\\foo\\\\bar\");\n      expect(dirname(\"C:\\\\foo\\\\bar\")).toEqual(\"C:\\\\foo\");\n      expect(dirname(\"C:\\\\foo\")).toEqual(\"C:\\\\\");\n      expect(dirname(\"C:\\\\\")).toEqual(\"C:\\\\\");\n    }\n  });\n});\n\ndescribe(\"extname\", () => {\n  it(\"should return the extension of a given path\", () => {\n    expect(extname(\"/foo/bar/baz.txt\")).toEqual(\".txt\");\n    expect(extname(\"/foo/bar/baz.tar.gz\")).toEqual(\".gz\");\n    expect(extname(\"/foo/bar/baz.\")).toEqual(\".\");\n    expect(extname(\"/foo/bar/baz\")).toEqual(\"\");\n    expect(extname(\"baz.txt\")).toEqual(\".txt\");\n    expect(extname(\"baz.tar.gz\")).toEqual(\".gz\");\n    expect(extname(\"baz.\")).toEqual(\".\");\n    expect(extname(\"baz\")).toEqual(\"\");\n    expect(extname(\".baz\")).toEqual(\"\");\n    expect(extname(\"\")).toEqual(\"\");\n  });\n});\n\ndescribe(\"format\", () => {\n  it(\"should return a path string from an object\", () => {\n    const pathObj1 = {\n      root: path.sep,\n      dir: normalizeSeparator(\"/foo/bar\"),\n      base: \"baz.txt\",\n      ext: \".txt\",\n      name: \"baz\",\n    };\n    const pathObj2 = {\n      dir: normalizeSeparator(\"/foo/bar\"),\n      base: \"baz.txt\",\n    };\n    const pathObj3 = {\n      root: path.sep,\n      base: \"baz.txt\",\n    };\n    const pathObj4 = {\n      name: \"baz\",\n    };\n    expect(format(pathObj1)).toEqual(normalizeSeparator(\"/foo/bar/baz.txt\"));\n    expect(format(pathObj2)).toEqual(normalizeSeparator(\"/foo/bar/baz.txt\"));\n    expect(format(pathObj3)).toEqual(normalizeSeparator(\"/baz.txt\"));\n    expect(format(pathObj4)).toEqual(normalizeSeparator(\"baz\"));\n  });\n});\n\ndescribe(\"parse\", () => {\n  it(\"should return an object from a path string\", () => {\n    const pathStr1 = normalizeSeparator(\"/foo/bar/baz.txt\");\n    const pathStr2 = normalizeSeparator(\"/foo/bar/baz/\");\n    const pathStr3 = normalizeSeparator(\"baz.txt\");\n    const pathStr4 = normalizeSeparator(\"/foo/bar/baz.tar.gz\");\n\n    const pathObj1 = {\n      root: path.sep,\n      dir: normalizeSeparator(\"/foo/bar\"),\n      base: \"baz.txt\",\n      ext: \".txt\",\n      name: \"baz\",\n    };\n    const pathObj2 = {\n      root: path.sep,\n      dir: normalizeSeparator(\"/foo/bar\"),\n      base: \"baz\",\n      ext: \"\",\n      name: \"baz\",\n    };\n    const pathObj3 = {\n      root: \"\",\n      dir: \"\",\n      base: \"baz.txt\",\n      ext: \".txt\",\n      name: \"baz\",\n    };\n    const pathObj4 = {\n      root: path.sep,\n      dir: normalizeSeparator(\"/foo/bar\"),\n      base: \"baz.tar.gz\",\n      ext: \".gz\",\n      name: \"baz.tar\",\n    };\n    expect(parse(pathStr1)).toStrictEqual(pathObj1);\n    expect(parse(pathStr2)).toStrictEqual(pathObj2);\n    expect(parse(pathStr3)).toStrictEqual(pathObj3);\n    expect(parse(pathStr4)).toStrictEqual(pathObj4);\n  });\n});\n\ndescribe(\"join\", () => {\n  it(\"should concatenate path segments and normalize the resulting path\", () => {\n    expect(join(\"/foo\", \"bar\", \"baz/asdf\", \"quux\", \"..\")).toEqual(\n      normalizeSeparator(\"/foo/bar/baz/asdf\")\n    );\n    expect(join(\"/foo\", \"bar\", \"baz\", \"/asdf\", \"quux\")).toEqual(\n      normalizeSeparator(\"/foo/bar/baz/asdf/quux\")\n    );\n    expect(join(\"/\", \"foo\", \"bar\", \"baz\", \"../asdf\", \"quux\")).toEqual(\n      normalizeSeparator(\"/foo/bar/asdf/quux\")\n    );\n  });\n});\n\ndescribe(\"resolve\", () => {\n  it(\"should resolve a sequence of paths and return an absolute path\", () => {\n    // On Windows, paths starting with \"/\" are relative to the current drive\n    // So resolve(\"/foo/bar\") returns \"D:\\foo\\bar\" if current drive is D:\n    const drivePrefix = IS_WINDOWS ? process.cwd().slice(0, 2) : \"\";\n\n    expect(resolve(\"/foo/bar\", \"./baz\")).toEqual(\n      drivePrefix + normalizeSeparator(\"/foo/bar/baz\")\n    );\n    expect(resolve(\"/foo/bar\", \"/tmp/file/\")).toEqual(\n      drivePrefix + normalizeSeparator(\"/tmp/file\")\n    );\n\n    expect(resolve(\"wwwroot\", \"static_files/png/\", \"../gif/image.gif\")).toEqual(\n      join(process.cwd(), \"wwwroot\", \"static_files\", \"gif\", \"image.gif\")\n    );\n  });\n});\n\ndescribe(\"normalize\", () => {\n  it(\"should normalize a path string\", () => {\n    expect(normalize(\"/foo/bar//baz/asdf/quux/..\")).toEqual(\n      normalizeSeparator(\"/foo/bar/baz/asdf\")\n    );\n    expect(normalize(\"foo/bar//baz/asdf/quux/..\")).toEqual(\n      normalizeSeparator(\"foo/bar/baz/asdf\")\n    );\n    expect(normalize(\"foo/bar/../baz/asdf\")).toEqual(\n      normalizeSeparator(\"foo/baz/asdf\")\n    );\n  });\n});\n\ndescribe(\"isAbsolute\", () => {\n  it(\"should determine if a path is absolute\", () => {\n    if (IS_WINDOWS) {\n      expect(isAbsolute(\"C:\\\\foo\\\\bar\\\\baz\")).toEqual(true);\n      expect(isAbsolute(\"\\\\\\\\server\\\\share\")).toEqual(true); // UNC path\n      expect(isAbsolute(\"\\\\foo\\\\bar\\\\baz\")).toEqual(true); // Root-relative path is absolute on Windows\n      expect(isAbsolute(\"foo\\\\bar\\\\baz\")).toEqual(false);\n      expect(isAbsolute(\"C:\\\\\")).toEqual(true);\n      expect(isAbsolute(\".\")).toEqual(false);\n    } else {\n      expect(isAbsolute(\"/foo/bar/baz\")).toEqual(true);\n      expect(isAbsolute(\"////foo/bar/baz\")).toEqual(true);\n      expect(isAbsolute(\"foo/bar/baz\")).toEqual(false);\n      expect(isAbsolute(\"/\")).toEqual(true);\n      expect(isAbsolute(\".\")).toEqual(false);\n    }\n  });\n});\n\ndescribe(\"relative\", () => {\n  it(\"should return the relative path between two absolute directories\", () => {\n    const from = normalizeSeparator(\"/Users/test/dir1\");\n    const to = normalizeSeparator(\"/Users/test/dir2\");\n    const result = relative(from, to);\n    expect(result).toBe(normalizeSeparator(\"../dir2\"));\n  });\n\n  it(\"should return the relative path between nested absolute directories\", () => {\n    const from = normalizeSeparator(\"dir1/subdir1\");\n    const to = normalizeSeparator(\"dir2/subdir2\");\n    const result = relative(from, to);\n    expect(result).toBe(normalizeSeparator(\"../../dir2/subdir2\"));\n  });\n\n  it(\"should return '.' for the same absolute directory\", () => {\n    const from = normalizeSeparator(\"/Users/test/dir1\");\n    const to = normalizeSeparator(\"/Users/test/dir1\");\n    const result = relative(from, to);\n    expect(result).toBe(\"\");\n  });\n\n  it(\"should return the relative path between two non-absolute directories\", () => {\n    const from = normalizeSeparator(\"dir1/subdir1\");\n    const to = normalizeSeparator(\"dir2/subdir2\");\n    const result = relative(from, to);\n    expect(result).toBe(normalizeSeparator(\"../../dir2/subdir2\"));\n  });\n\n  it(\"should return the relative path with one non-absolute directory\", () => {\n    if (IS_WINDOWS) {\n      const from = \"dir1\\\\subdir1\";\n      const to = \"C:\\\\Users\\\\test\\\\dir2\\\\subdir2\";\n      const expected = calculateRelativeDepth(from, to);\n      const result = relative(from, to);\n      expect(result).toBe(expected);\n    } else {\n      const from = \"dir1/subdir1\";\n      const to = \"/Users/test/dir2/subdir2\";\n      const expected = calculateRelativeDepth(from, to);\n      const result = relative(from, to);\n      expect(result).toBe(expected);\n    }\n  });\n\n  it('should return the relative path when \"to\" is a non-absolute file', () => {\n    const from = normalizeSeparator(\"dir1\");\n    const to = normalizeSeparator(\"dir2/file.txt\");\n\n    const expected = calculateRelativeDepth(from, to);\n    const result = relative(from, to);\n\n    expect(result).toBe(expected);\n  });\n\n  it('should return the relative path when \"from\" is a non-absolute file', () => {\n    const from = normalizeSeparator(\"dir1/file.txt\");\n    const to = normalizeSeparator(\"dir2\");\n\n    const expected = calculateRelativeDepth(from, to);\n    const result = relative(from, to);\n\n    expect(result).toBe(expected);\n  });\n\n  it('should return the relative path when both \"from\" and \"to\" are non-absolute files', () => {\n    const from = normalizeSeparator(\"dir1/file1.txt\");\n    const to = normalizeSeparator(\"dir2/file2.txt\");\n\n    const expected = calculateRelativeDepth(from, to);\n    const result = relative(from, to);\n\n    expect(result).toBe(expected);\n  });\n\n  it(\"should return the relative path between non-absolute and absolute paths\", () => {\n    if (IS_WINDOWS) {\n      const from = \"dir1\";\n      const to = \"C:\\\\Users\\\\test\\\\dir2\\\\file.txt\";\n      const expected = calculateRelativeDepth(from, to);\n      const result = relative(from, to);\n      expect(result).toBe(expected);\n    } else {\n      const from = \"dir1\";\n      const to = \"/Users/test/dir2/file.txt\";\n      const expected = calculateRelativeDepth(from, to);\n      const result = relative(from, to);\n      expect(result).toBe(expected);\n    }\n  });\n});\n"
  },
  {
    "path": "tests/unit/perf_hooks.test.ts",
    "content": "import defaultImport from \"node:perf_hooks\";\nimport legacyImport from \"perf_hooks\";\n\nit(\"node:perf_hooks should be the same as perf_hooks\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n\nconst { performance } = defaultImport;\n\nit(\"performance should be the same as globalThis.performance\", () => {\n  expect(performance).toStrictEqual(globalThis.performance);\n});\n"
  },
  {
    "path": "tests/unit/performance.test.ts",
    "content": "describe(\"performance.timeOrigin\", () => {\n  it(\"should have a positive value\", () => {\n    expect(Number(performance.timeOrigin)).toBeGreaterThanOrEqual(0);\n  });\n});\n\ndescribe(\"performance.now()\", () => {\n  it(\"should have a positive value\", () => {\n    expect(Number(performance.now())).toBeGreaterThanOrEqual(0);\n  });\n  it(\"should be a monotonic clock\", () => {\n    const before = performance.now();\n    const after = performance.now();\n    expect(Number(after)).toBeGreaterThanOrEqual(Number(before));\n  });\n\n  describe(\"performance.toJSON()\", () => {\n    it(\"performance.toJSON().timeOrigin should have a positive value\", () => {\n      //@ts-ignore\n      expect(Number(performance.toJSON().timeOrigin)).toBeGreaterThanOrEqual(0);\n    });\n    it(\"performance.toJSON().timeOrigin should match performance.timeOrigin\", () => {\n      //@ts-ignore\n      expect(performance.toJSON().timeOrigin).toEqual(performance.timeOrigin);\n    });\n  });\n});\n"
  },
  {
    "path": "tests/unit/process.test.ts",
    "content": "import process from \"node:process\";\n\nimport defaultImport from \"node:process\";\nimport legacyImport from \"process\";\n\nit(\"node:process should be the same as process\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n\nconst {\n  env,\n  cwd,\n  argv0,\n  argv,\n  platform,\n  arch,\n  hrtime,\n  release,\n  version,\n  versions,\n  exit,\n} = defaultImport;\n\nit(\"should have a process env\", () => {\n  expect(env).toEqual(process.env);\n});\n\nit(\"should have a process cwd\", () => {\n  expect(cwd()).toEqual(process.cwd());\n});\n\nit(\"should have a process argv0\", () => {\n  expect(argv0).toEqual(process.argv0);\n});\n\nit(\"should have a process argv\", () => {\n  expect(argv).toEqual(process.argv);\n});\n\nit(\"should have a process platform\", () => {\n  expect(platform).toEqual(process.platform);\n});\n\nit(\"should have a process arch\", () => {\n  expect(arch).toEqual(process.arch);\n});\n\nit(\"should have a process hrtime\", () => {\n  expect(hrtime.bigint() > 0).toBeTruthy();\n});\n\nit(\"should have a process release\", () => {\n  expect(release).toEqual(process.release);\n});\n\nit(\"should have a process version\", () => {\n  expect(version).toEqual(process.version);\n});\n\nit(\"should have a process versions\", () => {\n  expect(versions).toEqual(process.versions);\n});\n\nit(\"should have a process exit\", () => {\n  expect(exit).toEqual(process.exit);\n});\n"
  },
  {
    "path": "tests/unit/require.test.ts",
    "content": "const _require = require; //used to preserve require during bundling/minification\nconst CWD = process.cwd();\nimport { spawn } from \"node:child_process\";\nimport { spawnCapture } from \"./test-utils\";\n\nimport { platform } from \"node:os\";\nconst IS_WINDOWS = platform() === \"win32\";\n\nit(\"should require a file (absolute path)\", () => {\n  const { hello } = _require(`${CWD}/fixtures/hello.js`);\n\n  expect(hello).toEqual(\"hello world!\");\n});\n\nit(\"should require a json file (absolute path)\", () => {\n  const a = _require(`${CWD}/package.json`);\n\n  expect(a.private).toEqual(true);\n});\n\nit(\"should require a js file (relative path)\", () => {\n  const { hello } = _require(\"../../../../fixtures/hello.js\");\n\n  expect(hello).toEqual(\"hello world!\");\n});\n\nit(\"should require a json file (relative path)\", () => {\n  const a = _require(\"../../../../fixtures/package.json\");\n\n  expect(a.private).toEqual(true);\n});\n\nit(\"should require a json file (path unspecified)\", () => {\n  const a = _require(\"package.json\");\n\n  expect(a.private).toEqual(true);\n});\n\nit(\"should require a file (file schema)\", () => {\n  const { hello } = _require(`file://${CWD}/fixtures/hello.js`);\n\n  expect(hello).toEqual(\"hello world!\");\n});\n\nit(\"should require a json file (file schema)\", () => {\n  const a = _require(`file://${CWD}/package.json`);\n\n  expect(a.private).toEqual(true);\n});\n\nit(\"should return same module when require multiple files\", () => {\n  const { hello: hello1 } = _require(`${CWD}/fixtures/hello.js`);\n  const { hello: hello2 } = _require(`${CWD}/fixtures/hello.js`);\n  const { hello: hello3 } = _require(`${CWD}/fixtures/hello.js`);\n\n  expect(hello1).toEqual(hello2);\n  expect(hello1).toEqual(hello3);\n});\n\nit(\"should handle cyclic requires\", () => {\n  const a = _require(`${CWD}/fixtures/a.js`);\n  const b = _require(`${CWD}/fixtures/b.js`);\n\n  expect(a.done).toEqual(b.done);\n});\n\nit(\"should handle cjs requires\", () => {\n  const a = _require(`${CWD}/fixtures/import.cjs`);\n\n  expect(a.c).toEqual(\"c\");\n});\n\nit(\"should handle cjs requires\", () => {\n  const a = _require(`${CWD}/fixtures/prop-export.cjs`);\n\n  expect(a.prop).toEqual(\"a\");\n});\n\nit(\"should be able to use node module with prefix `node:` with require\", () => {\n  let { Console } = require(\"node:console\");\n  const consoleObj = new Console({\n    stdout: process.stdout,\n    stderr: process.stderr,\n  });\n\n  // we check if the log does not throw an exception when called\n  consoleObj.log(\"log\");\n  consoleObj.debug(\"debug\");\n  consoleObj.info(\"info\");\n  consoleObj.assert(false, \"text for assertion should display\");\n  consoleObj.assert(true, \"This text should not be seen\");\n\n  consoleObj.warn(\"warn\");\n  consoleObj.error(\"error\");\n  consoleObj.trace(\"trace\");\n});\n\nit(\"should be able to import exported functions\", () => {\n  const importedFunction = _require(`${CWD}/fixtures/export-function.cjs`);\n  expect(importedFunction()).toBe(\"hello world!\");\n});\n\nit(\"should return same value for multiple require statements\", () => {\n  const filename = `${CWD}/fixtures/prop-export.cjs`;\n  const a = _require(filename);\n  const b = _require(filename);\n  expect(a).toStrictEqual(b);\n});\n\nit(\"should return all props\", () => {\n  const a = _require(`${CWD}/fixtures/define-property-export.cjs`);\n  expect(a.__esModule).toBe(true);\n});\n\nit(\"should import cjs modules using import statement\", async () => {\n  const filename = `${CWD}/fixtures/prop-export.cjs`;\n  const a = await import(filename);\n  const b = await import(filename);\n  const c = _require(filename);\n  expect(a).toStrictEqual(b);\n  expect(a.default).toStrictEqual(c);\n  expect(b.default).toStrictEqual(c);\n});\n\nit(\"should handle inner referenced exports\", () => {\n  const a = _require(`${CWD}/fixtures/referenced-exports.cjs`);\n  expect(a.cat()).toBe(\"str\");\n  expect(a.length()).toBe(1);\n});\n\nif (!IS_WINDOWS) {\n  it(\"should handle named exports from CJS imports\", (cb) => {\n    spawn(process.argv0, [\n      \"-e\",\n      `import {cat} from \"${CWD}/fixtures/referenced-exports.cjs\"`,\n    ]).on(\"close\", (code) => {\n      expect(code).toBe(0);\n      cb();\n    });\n  });\n}\n\nit(\"require builtin modules\", () => {\n  _require(\"path\");\n});\n\nit(\"require `debug` module element\", () => {\n  _require(`${CWD}/fixtures/test_modules/test-debug.js`);\n});\n\nit(\"require `lodash.merge` module element\", () => {\n  _require(`${CWD}/fixtures/test_modules/test-lodash.merge.js`);\n});\n\nit(\"require `uuid` module element\", () => {\n  _require(`${CWD}/fixtures/test_modules/test-uuid.js`);\n});\n\nit(\"require `react-dom` module element\", () => {\n  _require(`${CWD}/fixtures/test_modules/test-react-dom.js`);\n});\n\nit(\"require `@aws-lambda-powertools` module element\", () => {\n  _require(\n    `${CWD}/fixtures/test_modules/test-aws-lambda-powertools-jmespath.js`\n  );\n});\n\nit(\"require `hono/utils/url` module element\", () => {\n  _require(`${CWD}/fixtures/test_modules/test-elem-hono.js`);\n});\n\nit(\"regression testing for issue #903\", () => {\n  expect(() => _require(`${CWD}/fixtures/test903/foo.mjs`)).toThrow(\n    /Error resolving module /\n  );\n});\n\nit(\"regression testing for issue #1245\", () => {\n  _require(`${CWD}/fixtures/test1245/main/foo.js`);\n});\n\n//create a test that spawns a subprocess and executes require.mjs from fixtures and captures stdout\nit(\"should handle blocking requires\", async () => {\n  const { code, stdout } = await spawnCapture(process.argv0, [\n    `${CWD}/fixtures/require.mjs`,\n  ]);\n  expect(code).toBe(0);\n  expect(stdout).toBe(\n    [\"1\", \"2\", \"3\", \"4\", \"5\", \"hello world!\", \"6\", \"\"].join(\"\\n\")\n  );\n});\n"
  },
  {
    "path": "tests/unit/socket.test.ts",
    "content": "import net from \"node:net\";\n\ndescribe(\"createServer and connect\", () => {\n  it(\"should create a server and connect to it\", (done) => {\n    const server = net.createServer();\n    server.listen(() => {\n      const client = net.connect((server.address() as any).port, () => {\n        client.end(() => {\n          server.close(done);\n        });\n      });\n    });\n  });\n\n  it(\"should handle data transfer between server and client\", (done) => {\n    const message = \"Hello from client\";\n    const server = net.createServer((socket) => {\n      socket.on(\"data\", (data) => {\n        expect(data.toString()).toEqual(message);\n        socket.write(data);\n      });\n    });\n    server.listen(() => {\n      const client = net.connect((server.address() as any).port, () => {\n        client.write(message);\n        client.on(\"data\", (data) => {\n          expect(data.toString()).toEqual(message);\n          client.end(() => {\n            server.close(done);\n          });\n        });\n      });\n    });\n  });\n\n  it(\"should handle data from server first\", (done) => {\n    const message = \"Hello from client\";\n    const server = net.createServer((socket) => {\n      socket.write(message);\n    });\n    server.listen(() => {\n      const client = net.connect((server.address() as any).port, () => {\n        client.on(\"data\", (data) => {\n          expect(data.toString()).toEqual(message);\n          client.end(() => {\n            server.close(done);\n          });\n        });\n      });\n    });\n  });\n});\n\ndescribe(\"error handling\", () => {\n  it(\"should handle connection error\", (done) => {\n    // Bind and immediately close a server to get a guaranteed-refused port\n    const tmp = net.createServer();\n    tmp.listen(0, () => {\n      const port = (tmp.address() as any).port;\n      tmp.close(() => {\n        const client = net\n          .connect(port, \"127.0.0.1\")\n          .on(\"error\", (error) => {\n            expect(error).toBeInstanceOf(Error);\n            client.destroy();\n            done();\n          });\n      });\n    });\n  });\n\n  it(\"should handle server destroy\", (done) => {\n    const server = net.createServer((socket) => {\n      socket.on(\"data\", () => {\n        socket.destroy();\n      });\n    });\n\n    server.listen(() => {\n      const client = net.connect((server.address() as any).port, () => {\n        client.write(\"hello\");\n      });\n      client.on(\"close\", () => {\n        client.end();\n        server.close(done);\n      });\n    });\n  });\n\n  it(\"should handle client destroy\", (done) => {\n    let closedResolve: () => void;\n    const closePromise = new Promise<void>((resolve) => {\n      closedResolve = resolve;\n    });\n    const server = net.createServer(async (socket) => {\n      await closePromise;\n      setTimeout(() => {\n        socket.write(\"hello\", (err) => {\n          expect(err).toBeTruthy();\n          server.close();\n          done();\n        });\n      }, 5);\n    });\n\n    server.listen(() => {\n      const client = net.connect((server.address() as any).port, () => {\n        client.destroy();\n        client.on(\"close\", closedResolve);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "tests/unit/stream.test.ts",
    "content": "import defaultImport from \"node:stream\";\nimport legacyImport from \"stream\";\n\nit(\"node:stream should be the same as stream\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n"
  },
  {
    "path": "tests/unit/string_decoder.test.ts",
    "content": "import defaultImport from \"node:string_decoder\";\nimport legacyImport from \"string_decoder\";\n\nit(\"node:string_decoder should be the same as string_decoder\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n\nconst { StringDecoder } = defaultImport;\n\n// Taken from https://github.com/nodejs/node/blob/ea9be1787203c3186c35a1a90d7d1109aa5ea1c3/test/parallel/test-string-decoder.js\ndescribe(\"basic\", () => {\n  // testDecode verifies that StringDecoder will correctly decode the given input\n  // buffer with the given encoding to the expected output. It will attempt all\n  // possible ways to write() the input buffer, see writeSequences(). The\n  // singleSequence allows for easy debugging of a specific sequence which is\n  // useful in case of testDecode failures.\n  function testDecode(\n    encoding: BufferEncoding,\n    input: Buffer,\n    expected: string,\n    singleSequence?: Array<Array<number>>\n  ) {\n    let sequences;\n    if (!singleSequence) {\n      sequences = writeSequences(input.length);\n    } else {\n      sequences = [singleSequence];\n    }\n    sequences.forEach((sequence) => {\n      const decoder = new StringDecoder(encoding);\n      let output = \"\";\n      sequence.forEach((write) => {\n        output += decoder.write(input.slice(write[0], write[1]));\n      });\n      output += decoder.end();\n      expect(output).toEqual(expected);\n    });\n  }\n\n  // writeSequences returns an array of arrays that describes all possible ways a\n  // buffer of the given length could be split up and passed to sequential write\n  // calls.\n  //\n  // e.G. writeSequences(3) will return: [\n  //   [ [ 0, 3 ] ],\n  //   [ [ 0, 2 ], [ 2, 3 ] ],\n  //   [ [ 0, 1 ], [ 1, 3 ] ],\n  //   [ [ 0, 1 ], [ 1, 2 ], [ 2, 3 ] ]\n  // ]\n  function writeSequences(\n    length: number,\n    start?: number,\n    sequence?: Array<Array<number>>\n  ): Array<Array<Array<number>>> {\n    if (start === undefined) {\n      start = 0;\n      sequence = [];\n    } else if (start === length) {\n      return [sequence!];\n    }\n    let sequences: Array<Array<Array<number>>> = [];\n    for (let end = length; end > start; end--) {\n      const subSequence = sequence!.concat([[start, end]]);\n      const subSequences = writeSequences(length, end, subSequence);\n      sequences = sequences.concat(subSequences);\n    }\n    return sequences;\n  }\n\n  it(\"utf8\", () => {\n    testDecode(\"utf-8\", Buffer.from(\"$\", \"utf-8\"), \"$\");\n    testDecode(\"utf-8\", Buffer.from(\"¢\", \"utf-8\"), \"¢\");\n    testDecode(\"utf-8\", Buffer.from(\"€\", \"utf-8\"), \"€\");\n    testDecode(\"utf-8\", Buffer.from(\"𤭢\", \"utf-8\"), \"𤭢\");\n    // A mixed ascii and non-ascii string\n    // testDecode stolen from deps/v8/testDecode/cctest/testDecode-strings.cc\n    // U+02E4 -> CB A4\n    // U+0064 -> 64\n    // U+12E4 -> E1 8B A4\n    // U+0030 -> 30\n    // U+3045 -> E3 81 85\n    testDecode(\n      \"utf-8\",\n      Buffer.from([0xcb, 0xa4, 0x64, 0xe1, 0x8b, 0xa4, 0x30, 0xe3, 0x81, 0x85]),\n      \"\\u02e4\\u0064\\u12e4\\u0030\\u3045\"\n    );\n\n    // Some invalid input, known to have caused trouble with chunking\n    // in https://github.com/nodejs/node/pull/7310#issuecomment-226445923\n    // 00: |00000000 ASCII\n    // 41: |01000001 ASCII\n    // B8: 10|111000 continuation\n    // CC: 110|01100 two-byte head\n    // E2: 1110|0010 three-byte head\n    // F0: 11110|000 four-byte head\n    // F1: 11110|001'another four-byte head\n    // FB: 111110|11 \"five-byte head\", not UTF-8\n    testDecode(\"utf-8\", Buffer.from(\"C9B5A941\", \"hex\"), \"\\u0275\\ufffdA\");\n    testDecode(\"utf-8\", Buffer.from(\"E2\", \"hex\"), \"\\ufffd\");\n    testDecode(\"utf-8\", Buffer.from(\"E241\", \"hex\"), \"\\ufffdA\");\n    testDecode(\"utf-8\", Buffer.from(\"CCCCB8\", \"hex\"), \"\\ufffd\\u0338\");\n    testDecode(\"utf-8\", Buffer.from(\"F0B841\", \"hex\"), \"\\ufffdA\");\n    testDecode(\"utf-8\", Buffer.from(\"F1CCB8\", \"hex\"), \"\\ufffd\\u0338\");\n    testDecode(\"utf-8\", Buffer.from(\"F0FB00\", \"hex\"), \"\\ufffd\\ufffd\\0\");\n    testDecode(\"utf-8\", Buffer.from(\"CCE2B8B8\", \"hex\"), \"\\ufffd\\u2e38\");\n    testDecode(\"utf-8\", Buffer.from(\"E2B8CCB8\", \"hex\"), \"\\ufffd\\u0338\");\n    testDecode(\n      \"utf-8\",\n      Buffer.from(\"E2FBCC01\", \"hex\"),\n      \"\\ufffd\\ufffd\\ufffd\\u0001\"\n    );\n    testDecode(\"utf-8\", Buffer.from(\"CCB8CDB9\", \"hex\"), \"\\u0338\\u0379\");\n    testDecode(\n      \"utf-8\",\n      Buffer.from(\"EDA0B5EDB08D\", \"hex\"),\n      \"\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\"\n    );\n  });\n\n  it(\"utf8 end\", () => {\n    let decoder = new StringDecoder(\"utf8\");\n    expect(decoder.write(Buffer.from(\"E18B\", \"hex\"))).toEqual(\"\");\n    expect(decoder.end()).toEqual(\"\\ufffd\");\n\n    decoder = new StringDecoder(\"utf8\");\n    expect(decoder.write(Buffer.from(\"\\ufffd\"))).toEqual(\"\\ufffd\");\n    expect(decoder.end()).toEqual(\"\");\n\n    decoder = new StringDecoder(\"utf8\");\n    expect(decoder.write(Buffer.from(\"\\ufffd\\ufffd\\ufffd\"))).toEqual(\n      \"\\ufffd\\ufffd\\ufffd\"\n    );\n    expect(decoder.end()).toEqual(\"\");\n\n    decoder = new StringDecoder(\"utf8\");\n    expect(decoder.write(Buffer.from(\"EFBFBDE2\", \"hex\"))).toEqual(\"\\ufffd\");\n    expect(decoder.end()).toEqual(\"\\ufffd\");\n\n    decoder = new StringDecoder(\"utf8\");\n    expect(decoder.write(Buffer.from(\"F1\", \"hex\"))).toEqual(\"\");\n    expect(decoder.write(Buffer.from(\"41F2\", \"hex\"))).toEqual(\"\\ufffdA\");\n    expect(decoder.end()).toEqual(\"\\ufffd\");\n  });\n\n  it(\"utf8 regression\", () => {\n    // Regression tests for https://github.com/nodejs/node/issues/22626\n    // (not enough replacement chars when having seen more than one byte of an\n    // incomplete multibyte characters).\n    let decoder = new StringDecoder(\"utf8\");\n    expect(decoder.write(Buffer.from(\"f69b\", \"hex\"))).toEqual(\"\");\n    expect(decoder.write(Buffer.from(\"d1\", \"hex\"))).toEqual(\"\\ufffd\\ufffd\");\n    expect(decoder.end()).toEqual(\"\\ufffd\");\n    expect(decoder.write(Buffer.from(\"f4\", \"hex\"))).toEqual(\"\");\n    expect(decoder.write(Buffer.from(\"bde5\", \"hex\"))).toEqual(\"\\ufffd\\ufffd\");\n    expect(decoder.end()).toEqual(\"\\ufffd\");\n  });\n\n  it(\"utf16le\", () => {\n    // BUG: See https://github.com/quickjs-ng/quickjs/issues/992\n    // testDecode(\"ucs2\", Buffer.from(\"ababc\", \"utf16le\"), \"ababc\");\n    testDecode(\"utf16le\", Buffer.from(\"3DD84DDC\", \"hex\"), \"\\ud83d\\udc4d\"); // thumbs up\n  });\n\n  it(\"utf16le surrogate\", () => {\n    let decoder = new StringDecoder(\"utf16le\");\n    expect(decoder.write(Buffer.from(\"3DD8\", \"hex\"))).toEqual(\"\");\n    expect(decoder.write(Buffer.from(\"4D\", \"hex\"))).toEqual(\"\");\n    expect(decoder.write(Buffer.from(\"DC\", \"hex\"))).toEqual(\"\\ud83d\\udc4d\");\n    expect(decoder.end()).toEqual(\"\");\n\n    decoder = new StringDecoder(\"utf16le\");\n    expect(decoder.write(Buffer.from(\"3DD8\", \"hex\"))).toEqual(\"\");\n    expect(decoder.end()).toEqual(\"\\uFFFD\");\n\n    decoder = new StringDecoder(\"utf16le\");\n    expect(decoder.write(Buffer.from(\"3DD8\", \"hex\"))).toEqual(\"\");\n    expect(decoder.write(Buffer.from(\"4D\", \"hex\"))).toEqual(\"\");\n    expect(decoder.end()).toEqual(\"\\uFFFD\");\n\n    decoder = new StringDecoder(\"utf16le\");\n    expect(decoder.write(Buffer.from(\"3DD84D\", \"hex\"))).toEqual(\"\");\n    expect(decoder.end()).toEqual(\"\\ufffd\");\n  });\n\n  it(\"utf16le regression\", () => {\n    // Regression test for https://github.com/nodejs/node/issues/22358\n    // (unaligned UTF-16 access).\n    let decoder = new StringDecoder(\"utf16le\");\n    expect(decoder.write(Buffer.alloc(1))).toEqual(\"\");\n    expect(decoder.write(Buffer.alloc(20))).toEqual(\"\\0\".repeat(10));\n    expect(decoder.write(Buffer.alloc(48))).toEqual(\"\\0\".repeat(24));\n    expect(decoder.end()).toEqual(\"\");\n  });\n\n  it(\"throws\", () => {\n    expect(() => new StringDecoder(\"test\" as any)).toThrow(\n      expect.objectContaining({\n        name: \"TypeError\",\n        message: \"Unknown encoding: test\",\n      })\n    );\n  });\n});\n\n// Taken from https://github.com/nodejs/node/blob/ea9be1787203c3186c35a1a90d7d1109aa5ea1c3/test/parallel/test-string-decoder-end.js\ndescribe(\"end\", () => {\n  const bufs = [\"☃💩\", \"asdf\"].map((b) => Buffer.from(b));\n\n  function testEnd(\n    encoding: BufferEncoding,\n    incomplete: Uint8Array,\n    next: Uint8Array,\n    expected: string\n  ) {\n    let res = \"\";\n    const s = new StringDecoder(encoding);\n    res += s.write(incomplete);\n    res += s.end();\n    res += s.write(next);\n    res += s.end();\n\n    expect(res).toEqual(expected);\n  }\n\n  function testEncoding(encoding: BufferEncoding) {\n    bufs.forEach((buf) => {\n      testBuf(encoding, buf);\n    });\n  }\n\n  function testBuf(encoding: BufferEncoding, buf: Buffer) {\n    // Write one byte at a time.\n    let s = new StringDecoder(encoding);\n    let res1 = \"\";\n    for (let i = 0; i < buf.length; i++) {\n      res1 += s.write(buf.slice(i, i + 1));\n    }\n    res1 += s.end();\n\n    // Write the whole buffer at once.\n    let res2 = \"\";\n    s = new StringDecoder(encoding);\n    res2 += s.write(buf);\n    res2 += s.end();\n\n    // .toString() on the buffer\n    const res3 = buf.toString(encoding);\n\n    // One byte at a time should match toString\n    expect(res1).toEqual(res3);\n    // All bytes at once should match toString\n    expect(res2).toEqual(res3);\n  }\n\n  it(\"encodings\", () => {\n    const encodings: BufferEncoding[] = [\"base64\", \"hex\", \"utf8\", \"utf16le\"];\n    encodings.forEach(testEncoding);\n  });\n\n  it(\"utf8\", () => {\n    testEnd(\"utf8\", Buffer.of(0xe2), Buffer.of(0x61), \"\\uFFFDa\");\n    testEnd(\"utf8\", Buffer.of(0xe2), Buffer.of(0x82), \"\\uFFFD\\uFFFD\");\n    testEnd(\"utf8\", Buffer.of(0xe2), Buffer.of(0xe2), \"\\uFFFD\\uFFFD\");\n    testEnd(\"utf8\", Buffer.of(0xe2, 0x82), Buffer.of(0x61), \"\\uFFFDa\");\n    testEnd(\"utf8\", Buffer.of(0xe2, 0x82), Buffer.of(0xac), \"\\uFFFD\\uFFFD\");\n    testEnd(\"utf8\", Buffer.of(0xe2, 0x82), Buffer.of(0xe2), \"\\uFFFD\\uFFFD\");\n    testEnd(\"utf8\", Buffer.of(0xe2, 0x82, 0xac), Buffer.of(0x61), \"€a\");\n  });\n\n  it(\"utf16le\", () => {\n    testEnd(\"utf16le\", Buffer.of(0x3d), Buffer.of(0x61, 0x00), \"a\");\n    testEnd(\"utf16le\", Buffer.of(0x3d), Buffer.of(0xd8, 0x4d, 0xdc), \"\\u4DD8\");\n    testEnd(\"utf16le\", Buffer.of(0x3d, 0xd8), Buffer.of(), \"\\uFFFD\");\n    testEnd(\"utf16le\", Buffer.of(0x3d, 0xd8), Buffer.of(0x61, 0x00), \"\\uFFFDa\");\n    testEnd(\n      \"utf16le\",\n      Buffer.of(0x3d, 0xd8),\n      Buffer.of(0x4d, 0xdc),\n      \"\\uFFFD\\uFFFD\"\n    );\n    testEnd(\"utf16le\", Buffer.of(0x3d, 0xd8, 0x4d), Buffer.of(), \"\\uFFFD\");\n    testEnd(\n      \"utf16le\",\n      Buffer.of(0x3d, 0xd8, 0x4d),\n      Buffer.of(0x61, 0x00),\n      \"\\uFFFDa\"\n    );\n    testEnd(\"utf16le\", Buffer.of(0x3d, 0xd8, 0x4d), Buffer.of(0xdc), \"\\uFFFD\");\n    testEnd(\n      \"utf16le\",\n      Buffer.of(0x3d, 0xd8, 0x4d, 0xdc),\n      Buffer.of(0x61, 0x00),\n      \"👍a\"\n    );\n  });\n\n  it(\"base64\", () => {\n    testEnd(\"base64\", Buffer.of(0x61), Buffer.of(), \"YQ==\");\n    testEnd(\"base64\", Buffer.of(0x61), Buffer.of(0x61), \"YQ==YQ==\");\n    testEnd(\"base64\", Buffer.of(0x61, 0x61), Buffer.of(), \"YWE=\");\n    testEnd(\"base64\", Buffer.of(0x61, 0x61), Buffer.of(0x61), \"YWE=YQ==\");\n    testEnd(\"base64\", Buffer.of(0x61, 0x61, 0x61), Buffer.of(), \"YWFh\");\n    testEnd(\"base64\", Buffer.of(0x61, 0x61, 0x61), Buffer.of(0x61), \"YWFhYQ==\");\n  });\n});\n"
  },
  {
    "path": "tests/unit/symbol-to-string-tag.test.ts",
    "content": "const LIMITED_CRYPTO = process.env.LLRT_LIMITED_CRYPTO === \"1\";\n\ndescribe(\"Symbol.toStringTag\", () => {\n  describe(\"URL module\", () => {\n    it(\"URL should have correct Symbol.toStringTag\", () => {\n      const url = new URL(\"https://example.com\");\n      expect(url[Symbol.toStringTag]).toBe(\"URL\");\n      expect(Object.prototype.toString.call(url)).toBe(\"[object URL]\");\n    });\n\n    it(\"URLSearchParams should have correct Symbol.toStringTag\", () => {\n      const params = new URLSearchParams(\"foo=bar\");\n      expect(params[Symbol.toStringTag]).toBe(\"URLSearchParams\");\n      expect(Object.prototype.toString.call(params)).toBe(\n        \"[object URLSearchParams]\"\n      );\n    });\n  });\n\n  describe(\"Encoding\", () => {\n    it(\"TextEncoder should have correct Symbol.toStringTag\", () => {\n      const encoder = new TextEncoder();\n      expect(encoder[Symbol.toStringTag]).toBe(\"TextEncoder\");\n      expect(Object.prototype.toString.call(encoder)).toBe(\n        \"[object TextEncoder]\"\n      );\n    });\n\n    it(\"TextDecoder should have correct Symbol.toStringTag\", () => {\n      const decoder = new TextDecoder();\n      expect(decoder[Symbol.toStringTag]).toBe(\"TextDecoder\");\n      expect(Object.prototype.toString.call(decoder)).toBe(\n        \"[object TextDecoder]\"\n      );\n    });\n  });\n\n  describe(\"Abort API\", () => {\n    it(\"AbortController should have correct Symbol.toStringTag\", () => {\n      const controller = new AbortController();\n      expect(controller[Symbol.toStringTag]).toBe(\"AbortController\");\n      expect(Object.prototype.toString.call(controller)).toBe(\n        \"[object AbortController]\"\n      );\n    });\n\n    it(\"AbortSignal should have correct Symbol.toStringTag\", () => {\n      const controller = new AbortController();\n      const signal = controller.signal;\n      expect(signal[Symbol.toStringTag]).toBe(\"AbortSignal\");\n      expect(Object.prototype.toString.call(signal)).toBe(\n        \"[object AbortSignal]\"\n      );\n    });\n  });\n\n  describe(\"Fetch API\", () => {\n    it(\"Headers should have correct Symbol.toStringTag\", () => {\n      const headers = new Headers();\n      expect(headers[Symbol.toStringTag]).toBe(\"Headers\");\n      expect(Object.prototype.toString.call(headers)).toBe(\"[object Headers]\");\n    });\n\n    it(\"Request should have correct Symbol.toStringTag\", () => {\n      const request = new Request(\"https://example.com\");\n      expect(request[Symbol.toStringTag]).toBe(\"Request\");\n      expect(Object.prototype.toString.call(request)).toBe(\"[object Request]\");\n    });\n\n    it(\"Response should have correct Symbol.toStringTag\", () => {\n      const response = new Response();\n      expect(response[Symbol.toStringTag]).toBe(\"Response\");\n      expect(Object.prototype.toString.call(response)).toBe(\n        \"[object Response]\"\n      );\n    });\n\n    it(\"FormData should have correct Symbol.toStringTag\", () => {\n      const formData = new FormData();\n      expect(formData[Symbol.toStringTag]).toBe(\"FormData\");\n      expect(Object.prototype.toString.call(formData)).toBe(\n        \"[object FormData]\"\n      );\n    });\n  });\n\n  describe(\"Blob API\", () => {\n    it(\"Blob should have correct Symbol.toStringTag\", () => {\n      const blob = new Blob([\"test\"]);\n      expect(blob[Symbol.toStringTag]).toBe(\"Blob\");\n      expect(Object.prototype.toString.call(blob)).toBe(\"[object Blob]\");\n    });\n\n    it(\"File should have correct Symbol.toStringTag\", () => {\n      const file = new File([\"test\"], \"test.txt\");\n      expect(file[Symbol.toStringTag]).toBe(\"File\");\n      expect(Object.prototype.toString.call(file)).toBe(\"[object File]\");\n    });\n  });\n\n  describe(\"Crypto API\", () => {\n    it(\"Crypto should have correct Symbol.toStringTag\", () => {\n      expect(crypto[Symbol.toStringTag]).toBe(\"Crypto\");\n      expect(Object.prototype.toString.call(crypto)).toBe(\"[object Crypto]\");\n    });\n\n    it(\"SubtleCrypto should have correct Symbol.toStringTag\", () => {\n      expect(crypto.subtle[Symbol.toStringTag]).toBe(\"SubtleCrypto\");\n      expect(Object.prototype.toString.call(crypto.subtle)).toBe(\n        \"[object SubtleCrypto]\"\n      );\n    });\n\n    it(\"CryptoKey should have correct Symbol.toStringTag\", async () => {\n      if (LIMITED_CRYPTO) return;\n      const key = await crypto.subtle.generateKey(\n        { name: \"HMAC\", hash: \"SHA-256\" },\n        false,\n        [\"sign\", \"verify\"]\n      );\n      expect(key[Symbol.toStringTag]).toBe(\"CryptoKey\");\n      expect(Object.prototype.toString.call(key)).toBe(\"[object CryptoKey]\");\n    });\n  });\n\n  describe(\"Exceptions\", () => {\n    it(\"DOMException should have correct Symbol.toStringTag\", () => {\n      const exception = new DOMException(\"test\", \"TestError\");\n      expect(exception[Symbol.toStringTag]).toBe(\"DOMException\");\n      expect(Object.prototype.toString.call(exception)).toBe(\n        \"[object DOMException]\"\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "tests/unit/temporal.duration.test.ts",
    "content": "describe(\"Constructor\", () => {\n  describe(\"Temporal.Duration()\", () => {\n    it(\"Using Temporal.Duration()\", () => {\n      const d = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);\n      expect(d.toString()).toBe(\"P1Y2M3W4DT5H6M7.00800901S\");\n    });\n  });\n});\n\ndescribe(\"Static methods\", () => {\n  describe(\"Temporal.Duration.compare()\", () => {\n    it(\"Using Temporal.Instant.compare()\", () => {\n      const d1 = Temporal.Duration.from({ hours: 1, minutes: 30 });\n      const d2 = Temporal.Duration.from({ minutes: 100 });\n      expect(Temporal.Duration.compare(d1, d2)).toBe(-1);\n\n      const d3 = Temporal.Duration.from({ hours: 2 });\n      const d4 = Temporal.Duration.from({ minutes: 110 });\n      expect(Temporal.Duration.compare(d3, d4)).toBe(1);\n\n      const d5 = Temporal.Duration.from({ hours: 1, minutes: 30 });\n      const d6 = Temporal.Duration.from({ seconds: 5400 });\n      expect(Temporal.Duration.compare(d5, d6)).toBe(0);\n    });\n\n    it(\"Comparing calendar durations\", () => {\n      const d1 = Temporal.Duration.from({ days: 31 });\n      const d2 = Temporal.Duration.from({ months: 1 });\n\n      expect(\n        Temporal.Duration.compare(d1, d2, {\n          relativeTo: Temporal.PlainDate.from(\"2021-01-01\"), // ISO 8601 calendar\n        })\n      ).toBe(0);\n\n      expect(\n        Temporal.Duration.compare(d1, d2, {\n          relativeTo: Temporal.PlainDate.from(\"2021-02-01\"), // ISO 8601 calendar\n        })\n      ).toBe(1);\n    });\n  });\n\n  describe(\"Temporal.Duration.from()\", () => {\n    it(\"Creating a duration from an object\", () => {\n      const d1 = Temporal.Duration.from({ hours: 1, minutes: 30 });\n      expect(d1.toString()).toBe(\"PT1H30M\");\n\n      const d2 = Temporal.Duration.from({ months: 1, days: 2 });\n      expect(d2.toString()).toBe(\"P1M2D\");\n\n      // Uncommon because unbalanced, but valid\n      const unbalanced = Temporal.Duration.from({\n        hours: 100,\n        minutes: 100,\n        seconds: 100,\n      });\n      expect(unbalanced.toString()).toBe(\"PT100H100M100S\");\n\n      const neg = Temporal.Duration.from({ hours: -1, minutes: -30 });\n      expect(neg.toString()).toBe(\"-PT1H30M\");\n    });\n\n    it(\"Creating a duration from a string\", () => {\n      const d = Temporal.Duration.from(\"P1Y2M3W4DT5H6M7.00800901S\");\n      expect(d.hours).toBe(5);\n    });\n\n    it(\"Creating a duration from another duration\", () => {\n      const d1 = Temporal.Duration.from({ hours: 1, minutes: 30 });\n      const d2 = Temporal.Duration.from(d1);\n      expect(d2.toString()).toBe(\"PT1H30M\");\n    });\n  });\n});\n\ndescribe(\"Instance methods\", () => {\n  describe(\"Temporal.Duration.prototype.abs()\", () => {\n    it(\"Using abs()\", () => {\n      const d1 = Temporal.Duration.from({ hours: 1, minutes: 30 });\n      const d2 = Temporal.Duration.from({ hours: -1, minutes: -30 });\n\n      expect(d1.abs().toString()).toBe(\"PT1H30M\");\n      expect(d2.abs().toString()).toBe(\"PT1H30M\");\n    });\n  });\n\n  describe(\"Temporal.Duration.prototype.add()\", () => {\n    it(\"Using add()\", () => {\n      const d1 = Temporal.Duration.from({ hours: 1, minutes: 30 });\n      const d2 = Temporal.Duration.from({ hours: -1, minutes: -20 });\n\n      const d3 = d1.add(d2);\n      expect(d3.toString()).toBe(\"PT10M\");\n    });\n\n    it(\"Adding calendar durations\", () => {\n      const d1 = Temporal.Duration.from({ days: 1 });\n      const d2 = Temporal.Duration.from({ months: 1 });\n\n      expect(() => {\n        d1.add(d2); // RangeError: for calendar duration arithmetic, use date arithmetic relative to a starting point\n      }).toThrow();\n\n      const start = Temporal.PlainDateTime.from(\"2022-01-01T00:00\"); // ISO 8601 calendar\n      const result = start.add(d1).add(d2).since(start);\n      expect(result.toString()).toBe(\"P32D\");\n    });\n  });\n\n  describe(\"Temporal.Duration.prototype.negated()\", () => {\n    it(\"Using negated()\", () => {\n      const d1 = Temporal.Duration.from({ hours: 1, minutes: 30 });\n      const d2 = Temporal.Duration.from({ hours: -1, minutes: -30 });\n\n      expect(d1.negated().toString()).toBe(\"-PT1H30M\");\n      expect(d2.negated().toString()).toBe(\"PT1H30M\");\n    });\n  });\n\n  describe(\"Temporal.Duration.prototype.round()\", () => {\n    it(\"Rounding off small units\", () => {\n      const duration = Temporal.Duration.from({\n        hours: 1,\n        minutes: 30,\n        seconds: 15,\n      });\n      const roundedDuration = duration.round(\"minutes\");\n      expect(roundedDuration.toString()).toBe(\"PT1H30M\");\n    });\n\n    it(\"Avoiding larger units\", () => {\n      const duration = Temporal.Duration.from({\n        days: 3,\n        hours: 1,\n        minutes: 41,\n        seconds: 5,\n      });\n      const roundedDuration = duration.round({ largestUnit: \"hours\" });\n      // expect(\n      //   `Time spent on this problem: ${roundedDuration.toLocaleString(\"en-US\", { style: \"digital\" })}`,\n      // );\n      // Time spent on this problem: 73:41:05\n      expect(roundedDuration.toString()).toBe(\"PT73H41M5S\");\n    });\n\n    it(\"Rounding to a whole number of hours\", () => {\n      const duration = Temporal.Duration.from({\n        days: 1,\n        hours: 1,\n        minutes: 30,\n      });\n      const roundedDuration = duration.round({\n        largestUnit: \"hours\",\n        smallestUnit: \"hours\",\n        roundingMode: \"floor\",\n      });\n      expect(roundedDuration.hours).toBe(25);\n    });\n\n    it(\"Rounding by 15-minute increments\", () => {\n      const duration = Temporal.Duration.from({ hours: 1, minutes: 17 });\n      const roundedDuration = duration.round({\n        smallestUnit: \"minutes\",\n        roundingIncrement: 15,\n      });\n      // expect(\n      //   `The queue will take approximately ${roundedDuration.toLocaleString(\"en-US\")}`,\n      // );\n      // The queue will take approximately 1 hr, 15 min\n      expect(roundedDuration.toString()).toBe(\"PT1H15M\");\n    });\n\n    it(\"Resolving calendar durations\", () => {\n      const duration = Temporal.Duration.from({ months: 1, days: 1, hours: 1 });\n      const roundedDuration = duration.round({\n        largestUnit: \"days\",\n        smallestUnit: \"days\",\n        relativeTo: Temporal.PlainDateTime.from(\"2022-01-01\"),\n      });\n      expect(roundedDuration.toString()).toBe(\"P32D\");\n    });\n  });\n\n  describe(\"Temporal.Duration.prototype.subtract()\", () => {\n    it(\"Using subtract()\", () => {\n      const d1 = Temporal.Duration.from({ hours: 1, minutes: 30 });\n      const d2 = Temporal.Duration.from({ hours: -1, minutes: -20 });\n\n      const d3 = d1.subtract(d2);\n      expect(d3.toString()).toBe(\"PT2H50M\");\n    });\n  });\n\n  describe(\"Temporal.Duration.prototype.toJSON()\", () => {\n    it(\"Using toJSON()\", () => {\n      const duration = Temporal.Duration.from({\n        hours: 1,\n        minutes: 30,\n        seconds: 15,\n      });\n      const durationStr = duration.toJSON();\n      expect(durationStr).toBe(\"PT1H30M15S\");\n      const d2 = Temporal.Duration.from(durationStr);\n    });\n\n    it(\"JSON serialization and parsing\", () => {\n      const duration = Temporal.Duration.from({\n        hours: 1,\n        minutes: 30,\n        seconds: 15,\n      });\n      const jsonStr = JSON.stringify({ data: duration });\n      expect(jsonStr).toBe('{\"data\":\"PT1H30M15S\"}');\n      const obj = JSON.parse(jsonStr, (key, value) => {\n        if (key === \"data\") {\n          return Temporal.Duration.from(value);\n        }\n        return value;\n      });\n    });\n  });\n\n  describe(\"Temporal.Duration.prototype.toString()\", () => {\n    it(\"Using toString()\", () => {\n      const duration = Temporal.Duration.from({\n        hours: 1,\n        minutes: 30,\n        seconds: 15,\n      });\n      expect(duration.toString()).toBe(\"PT1H30M15S\");\n\n      // Stringification implicitly calls toString()\n      expect(`${duration}`).toBe(\"PT1H30M15S\");\n    });\n  });\n\n  describe(\"Temporal.Duration.prototype.total()\", () => {\n    it(\"Using total()\", () => {\n      const d = Temporal.Duration.from({ hours: 1, minutes: 30 });\n\n      expect(d.total(\"minutes\")).toBe(90);\n      expect(d.total(\"hours\")).toBe(1.5);\n    });\n\n    it(\"Total of a calendar duration\", () => {\n      const d = Temporal.Duration.from({ months: 1 });\n\n      expect(\n        d.total({\n          unit: \"days\",\n          relativeTo: Temporal.PlainDate.from(\"2021-01-01\"),\n        })\n      ).toBe(31);\n    });\n  });\n\n  describe(\"Temporal.Duration.prototype.valueOf()\", () => {\n    it(\"Arithmetic and comparison operations on Temporal.Duration\", () => {\n      const duration1 = Temporal.Duration.from({ seconds: 3 });\n      const duration2 = Temporal.Duration.from({ minutes: 1 });\n      expect(() => {\n        duration1 > duration2; // TypeError: can't convert Duration to primitive type\n      }).toThrow();\n      expect(duration1.total(\"seconds\") > duration2.total(\"seconds\")).toBe(\n        false\n      );\n      expect(Temporal.Duration.compare(duration1, duration2)).toBe(-1);\n\n      expect(() => {\n        duration1 + duration2; // TypeError: can't convert Duration to primitive type\n      }).toThrow();\n      expect(duration1.total(\"seconds\") + duration2.total(\"seconds\")).toBe(63);\n      expect(duration1.add(duration2).toString()).toBe(\"PT1M3S\");\n    });\n  });\n\n  describe(\"Temporal.Duration.prototype.with()\", () => {\n    it(\"Using with()\", () => {\n      function balanceMinutes(duration) {\n        const { hours, minutes } = duration;\n        const totalMinutes = hours * 60 + minutes;\n        const balancedMinutes = totalMinutes % 60;\n        const balancedHours = (totalMinutes - balancedMinutes) / 60;\n        return duration.with({\n          hours: balancedHours,\n          minutes: balancedMinutes,\n        });\n      }\n\n      const d1 = Temporal.Duration.from({\n        hours: 100,\n        minutes: 100,\n        seconds: 100,\n      });\n      const d2 = balanceMinutes(d1);\n      expect(d2.hours).toBe(101);\n      expect(d2.minutes).toBe(40);\n      expect(d2.seconds).toBe(100);\n    });\n  });\n});\n\ndescribe(\"Instance properties\", () => {\n  it(\"should have correct property values for weeks and all components\", () => {\n    const dur = Temporal.Duration.from({ weeks: 2, days: 3, hours: 5 });\n    expect(dur.weeks).toBe(2);\n    expect(dur.days).toBe(3);\n    expect(dur.hours).toBe(5);\n  });\n\n  it(\"should report the correct sign for durations\", () => {\n    const pos = Temporal.Duration.from({ hours: 5 });\n    expect(pos.sign).toBe(1);\n\n    const neg = pos.negated();\n    expect(neg.sign).toBe(-1);\n\n    const zero = Temporal.Duration.from(\"PT0S\");\n    expect(zero.sign).toBe(0);\n  });\n\n  it(\"has correct toStringTag\", () => {\n    const dur = Temporal.Duration.from(\"PT0S\");\n    expect(Object.prototype.toString.call(dur)).toBe(\n      \"[object Temporal.Duration]\"\n    );\n  });\n});\n"
  },
  {
    "path": "tests/unit/temporal.instant.test.ts",
    "content": "describe(\"Constructor\", () => {\n  describe(\"Temporal.Instant()\", () => {\n    it(\"Using Temporal.Instant()\", () => {\n      const instant = new Temporal.Instant(0n);\n      expect(instant.toString()).toBe(\"1970-01-01T00:00:00Z\");\n      const vostok1Liftoff = new Temporal.Instant(-275248380000000000n);\n      expect(vostok1Liftoff.toString()).toBe(\"1961-04-12T06:07:00Z\");\n      const sts1Liftoff = new Temporal.Instant(355924804000000000n);\n      expect(sts1Liftoff.toString()).toBe(\"1981-04-12T12:00:04Z\");\n    });\n  });\n});\n\ndescribe(\"Static methods\", () => {\n  describe(\"Temporal.Instant.compare()\", () => {\n    it(\"Using Temporal.Instant.compare()\", () => {\n      const instant1 = Temporal.Instant.from(\"2021-08-01T12:34:56Z\");\n      const instant2 = Temporal.Instant.from(\"2021-08-01T12:34:56Z\");\n\n      expect(Temporal.Instant.compare(instant1, instant2)).toBe(0);\n\n      const instant3 = Temporal.Instant.from(\"2021-08-01T13:34:56Z\");\n      expect(Temporal.Instant.compare(instant1, instant3)).toBe(-1);\n    });\n\n    it(\"Sorting an array of instants\", () => {\n      const instants = [\n        Temporal.Instant.from(\"2021-08-01T12:34:56Z\"),\n        Temporal.Instant.from(\"2021-08-01T12:34:56+01:00\"),\n        Temporal.Instant.from(\"2021-08-01T12:34:56-01:00\"),\n      ];\n\n      instants.sort(Temporal.Instant.compare);\n      expect(instants.map((instant) => instant.toString())).toStrictEqual([\n        \"2021-08-01T11:34:56Z\",\n        \"2021-08-01T12:34:56Z\",\n        \"2021-08-01T13:34:56Z\",\n      ]);\n    });\n  });\n\n  describe(\"Temporal.Instant.from()\", () => {\n    it(\"Creating an instant from a string\", () => {\n      const instant = Temporal.Instant.from(\"1970-01-01T00Z\");\n      expect(instant.toString()).toBe(\"1970-01-01T00:00:00Z\");\n\n      const instant2 = Temporal.Instant.from(\"1970-01-01T00+08:00\");\n      expect(instant2.toString()).toBe(\"1969-12-31T16:00:00Z\");\n\n      // America/New_York is UTC-5 in January 1970, not UTC+8\n      const instant3 = Temporal.Instant.from(\n        \"1970-01-01T00+08:00[America/New_York]\"\n      );\n      expect(instant3.toString()).toBe(\"1969-12-31T16:00:00Z\");\n    });\n\n    it(\"Creating an instant from another instant\", () => {\n      const instant = Temporal.Instant.from(\"1970-01-01T00Z\");\n      const instant2 = Temporal.Instant.from(instant);\n      expect(instant2.toString()).toBe(\"1970-01-01T00:00:00Z\");\n    });\n  });\n\n  describe(\"Temporal.Instant.fromEpochMilliseconds()\", () => {\n    it(\"Using Temporal.Instant.fromEpochMilliseconds()\", () => {\n      const instant = Temporal.Instant.fromEpochMilliseconds(0);\n      expect(instant.toString()).toBe(\"1970-01-01T00:00:00Z\");\n      const vostok1Liftoff =\n        Temporal.Instant.fromEpochMilliseconds(-275248380000);\n      expect(vostok1Liftoff.toString()).toBe(\"1961-04-12T06:07:00Z\");\n      const sts1Liftoff = Temporal.Instant.fromEpochMilliseconds(355924804000);\n      expect(sts1Liftoff.toString()).toBe(\"1981-04-12T12:00:04Z\");\n    });\n  });\n\n  describe(\"Temporal.Instant.fromEpochNanoseconds()\", () => {\n    it(\"Using Temporal.Instant.fromEpochNanoseconds()\", () => {\n      const instant = Temporal.Instant.fromEpochNanoseconds(0n);\n      expect(instant.toString()).toBe(\"1970-01-01T00:00:00Z\");\n      const vostok1Liftoff =\n        Temporal.Instant.fromEpochNanoseconds(-275248380000000000n);\n      expect(vostok1Liftoff.toString()).toBe(\"1961-04-12T06:07:00Z\");\n      const sts1Liftoff =\n        Temporal.Instant.fromEpochNanoseconds(355924804000000000n);\n      expect(sts1Liftoff.toString()).toBe(\"1981-04-12T12:00:04Z\");\n    });\n  });\n});\n\ndescribe(\"Instance methods\", () => {\n  describe(\"Temporal.Instant.prototype.add()\", () => {\n    it(\"Adding a Temporal.Duration\", () => {\n      const instant = Temporal.Instant.fromEpochMilliseconds(0);\n      const duration = Temporal.Duration.from(\"PT1S\");\n      const newInstant = instant.add(duration);\n      expect(newInstant.epochMilliseconds).toBe(1000);\n    });\n\n    it(\"Adding an object or a string\", () => {\n      const instant = Temporal.Instant.fromEpochMilliseconds(0);\n      const newInstant = instant.add({ seconds: 1 });\n      expect(newInstant.epochMilliseconds).toBe(1000);\n\n      const newInstant2 = instant.add(\"PT1S\");\n      expect(newInstant2.epochMilliseconds).toBe(1000);\n    });\n\n    it(\"Adding a calendar duration\", () => {\n      const instant = Temporal.Instant.fromEpochMilliseconds(1730610000000);\n      const duration = Temporal.Duration.from({ days: 1 });\n\n      // This instant is 2024-11-03T01:00:00-04:00[America/New_York],\n      // which is a DST transition day in the US.\n      const instant2 = instant\n        .toZonedDateTimeISO(\"America/New_York\")\n        .add(duration)\n        .toInstant();\n      expect(instant2.epochMilliseconds).toBe(1730700000000);\n\n      // The same instant is not a DST transition day in Paris.\n      const instant3 = instant\n        .toZonedDateTimeISO(\"Europe/Paris\")\n        .add(duration)\n        .toInstant();\n      expect(instant3.epochMilliseconds).toBe(1730696400000);\n    });\n  });\n\n  describe(\"Temporal.Instant.prototype.equals()\", () => {\n    it(\"Using equals()\", () => {\n      const instant1 = Temporal.Instant.from(\"2021-08-01T12:34:56Z\");\n      const instant2 = Temporal.Instant.fromEpochMilliseconds(1627821296000);\n      expect(instant1.equals(instant2)).toBe(true);\n    });\n  });\n\n  describe(\"Temporal.Instant.prototype.round()\", () => {\n    it(\"Rounding off small units\", () => {\n      const instant = Temporal.Instant.fromEpochMilliseconds(1000);\n      const roundedInstant = instant.round(\"second\");\n      expect(roundedInstant.epochMilliseconds).toBe(1000);\n\n      const instant2 = instant.round(\"minute\");\n      expect(instant2.epochMilliseconds).toBe(0);\n    });\n  });\n\n  describe(\"Temporal.Instant.prototype.since()\", () => {\n    it.skip(\"Using since()\", () => {\n      const lastUpdated = Temporal.Instant.fromEpochMilliseconds(1735235418000);\n      const now = Temporal.Now.instant();\n      const duration = now.since(lastUpdated, { smallestUnit: \"minute\" });\n      console.log(`Last updated ${duration.toLocaleString(\"en-US\")} ago`);\n    });\n\n    it.skip(\"Balancing the resulting duration\", () => {\n      const lastUpdated = Temporal.Instant.fromEpochMilliseconds(1735235418000);\n      const now = Temporal.Now.instant();\n      const duration = now.since(lastUpdated, { smallestUnit: \"minutes\" });\n      const roundedDuration = duration.round({\n        largestUnit: \"years\",\n        // Use the ISO calendar; you can convert to another calendar using\n        // withCalendar()\n        relativeTo: now.toZonedDateTimeISO(\"UTC\"),\n      });\n      console.log(\n        `Last updated ${roundedDuration.toLocaleString(\"en-US\")} ago`\n      );\n    });\n\n    it(\"since() returns correct duration\", () => {\n      const insta = Temporal.Instant.fromEpochMilliseconds(5000);\n      const instb = Temporal.Instant.fromEpochMilliseconds(2000);\n\n      const d = insta.since(instb);\n\n      expect(d.years).toBe(0);\n      expect(d.months).toBe(0);\n      expect(d.days).toBe(0);\n      expect(d.hours).toBe(0);\n      expect(d.minutes).toBe(0);\n      expect(d.seconds).toBe(3);\n      expect(d.milliseconds).toBe(0);\n      expect(d.microseconds).toBe(0);\n      expect(d.nanoseconds).toBe(0);\n    });\n  });\n\n  describe(\"Temporal.Instant.prototype.subtract()\", () => {\n    it(\"Subtracting a Temporal.Duration\", () => {\n      const instant = Temporal.Instant.fromEpochMilliseconds(1000);\n      const duration = Temporal.Duration.from(\"PT1S\"); // One-second duration\n      const newInstant = instant.subtract(duration);\n      expect(newInstant.epochMilliseconds).toBe(0);\n    });\n  });\n\n  describe(\"Temporal.Instant.prototype.toJSON()\", () => {\n    it(\"Using toJSON()\", () => {\n      const instant = Temporal.Instant.fromEpochMilliseconds(1627821296000);\n      const instantStr = instant.toJSON();\n      expect(instantStr).toBe(\"2021-08-01T12:34:56Z\");\n      const _ = Temporal.Instant.from(instantStr);\n    });\n  });\n\n  describe(\"Temporal.Instant.prototype.toString()\", () => {\n    it(\"Using toString()\", () => {\n      const instant = Temporal.Instant.fromEpochMilliseconds(1627814412345);\n      // expect(instant.toString()).toBe(\"2021-08-01T10:40:12.345Z\"); // TODO: Expected value\n      expect(instant.toString()).toBe(\"2021-08-01T10:40:12.344999936Z\");\n    });\n  });\n\n  describe(\"Temporal.Instant.prototype.toZonedDateTimeISO()\", () => {\n    it(\"Using toZonedDateTimeISO()\", () => {\n      const instant = Temporal.Instant.from(\"2021-08-01T12:34:56.123456789Z\");\n      const zonedDateTime = instant.toZonedDateTimeISO(\"America/New_York\");\n      expect(zonedDateTime.toString()).toBe(\n        \"2021-08-01T08:34:56.123456789-04:00[America/New_York]\"\n      );\n\n      const localDateTime = instant.toZonedDateTimeISO(\n        Temporal.Now.timeZoneId()\n      );\n      console.log(localDateTime.toString()); // This instant in your timezone\n    });\n  });\n\n  describe(\"Temporal.Instant.prototype.until()\", () => {\n    it.skip(\"Using until()\", () => {\n      const launch = Temporal.Instant.fromEpochMilliseconds(2051222400000);\n      const now = Temporal.Now.instant();\n      const duration = now.until(launch, { smallestUnit: \"minutes\" });\n      console.log(\n        `It will be ${duration.toLocaleString(\"en-US\")} until the launch`\n      );\n    });\n\n    it(\"until() returns correct duration\", () => {\n      const insta = Temporal.Instant.fromEpochMilliseconds(1000);\n      const instb = Temporal.Instant.fromEpochMilliseconds(4000);\n\n      const d = insta.until(instb);\n\n      expect(d.years).toBe(0);\n      expect(d.months).toBe(0);\n      expect(d.days).toBe(0);\n      expect(d.hours).toBe(0);\n      expect(d.minutes).toBe(0);\n      expect(d.seconds).toBe(3);\n      expect(d.milliseconds).toBe(0);\n      expect(d.microseconds).toBe(0);\n      expect(d.nanoseconds).toBe(0);\n    });\n  });\n\n  describe(\"Temporal.Instant.prototype.valueOf()\", () => {\n    it(\"Arithmetic and comparison operations on Temporal.Instant\", () => {\n      const instant1 = Temporal.Instant.fromEpochMilliseconds(0);\n      const instant2 = Temporal.Instant.fromEpochMilliseconds(1000);\n      expect(() => {\n        instant1 > instant2; // TypeError: can't convert Instant to primitive type\n      }).toThrow();\n      expect(instant1.epochNanoseconds > instant2.epochNanoseconds).toBe(false);\n      expect(Temporal.Instant.compare(instant1, instant2)).toBe(-1);\n\n      expect(() => {\n        instant2 - instant1; // TypeError: can't convert Instant to primitive type\n      }).toThrow();\n      expect(instant2.since(instant1).toString()).toBe(\"PT1S\");\n    });\n  });\n});\n\ndescribe(\"Instance properties\", () => {\n  const inst = Temporal.Instant.fromEpochMilliseconds(1_609_459_260_000);\n\n  it(\"reports epochMilliseconds and epochNanoseconds\", () => {\n    expect(typeof inst.epochMilliseconds).toBe(\"number\");\n    expect(inst.epochMilliseconds).toBe(1609459260000);\n    expect(typeof inst.epochNanoseconds).toBe(\"bigint\");\n    expect(inst.epochNanoseconds).toBe(1609459260000000000n);\n  });\n\n  it(\"has correct toStringTag\", () => {\n    expect(Object.prototype.toString.call(inst)).toBe(\n      \"[object Temporal.Instant]\"\n    );\n  });\n});\n"
  },
  {
    "path": "tests/unit/temporal.now.test.ts",
    "content": "describe(\"Temporal.Now\", () => {\n  describe(\"arithmetic methods\", () => {\n    it(\"instant() returns a Temporal.Instant\", () => {\n      const inst = Temporal.Now.instant();\n      expect(inst).toBeInstanceOf(Temporal.Instant);\n    });\n\n    it(\"plainDateISO() returns a Temporal.PlainDate\", () => {\n      const obj = Temporal.Now.plainDateISO();\n      expect(obj).toBeInstanceOf(Temporal.PlainDate);\n    });\n\n    it(\"plainDateTimeISO() returns a Temporal.PlainDateTime\", () => {\n      const obj = Temporal.Now.plainDateTimeISO();\n      expect(obj).toBeInstanceOf(Temporal.PlainDateTime);\n    });\n\n    it(\"plainTimeISO() returns a Temporal.PlainTime\", () => {\n      const obj = Temporal.Now.plainTimeISO();\n      expect(obj).toBeInstanceOf(Temporal.PlainTime);\n    });\n\n    it(\"zonedDateTimeISO() returns a Temporal.ZonedDateTime\", () => {\n      const obj = Temporal.Now.zonedDateTimeISO();\n      expect(obj).toBeInstanceOf(Temporal.ZonedDateTime);\n    });\n  });\n\n  describe(\"properties\", () => {\n    it(\"has correct toStringTag\", () => {\n      expect(Object.prototype.toString.call(Temporal.Now)).toBe(\n        \"[object Temporal.Now]\"\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "tests/unit/temporal.plaindate.test.ts",
    "content": "describe(\"Temporal.PlainDate\", () => {\n  describe(\"creation and parsing\", () => {\n    it(\"can be created from an RFC 9557 string\", () => {\n      const pd1 = Temporal.PlainDate.from(\"2021-08-19\");\n      expect(pd1.toString()).toContain(\"2021-08-19\");\n    });\n\n    it(\"can be created from an own object\", () => {\n      const pd1 = Temporal.PlainDate.from(\"2021-08-19\");\n      const pd2 = Temporal.PlainDate.from(pd1);\n      expect(pd1).toEqual(pd2);\n    });\n\n    it(\"can be created from an object containing properties\", () => {\n      const pd1 = Temporal.PlainDate.from({ year: 2006, month: 8, day: 24 });\n      expect(pd1.toString()).toEqual(\"2006-08-24\");\n    });\n  });\n\n  describe(\"arithmetic methods\", () => {\n    const pd1 = Temporal.PlainDate.from(\"2020-01-01\");\n    const pd2 = Temporal.PlainDate.from(\"2020-01-02\");\n\n    it(\"add() advances the date\", () => {\n      const later = pd1.add({ days: 1 });\n      expect(later.day).toBe(2);\n    });\n\n    it(\"compare() method works for two PlainDate objects\", () => {\n      expect(Temporal.PlainDate.compare(pd1, pd2)).toBe(-1);\n      expect(Temporal.PlainDate.compare(pd2, pd1)).toBe(1);\n      expect(Temporal.PlainDate.compare(pd1, pd1)).toBe(0);\n    });\n\n    it(\"equals() verifies if two PlainDate are equal\", () => {\n      const same = Temporal.PlainDate.from(\"2020-01-01\");\n      expect(pd1.equals(same)).toBe(true);\n    });\n\n    it(\"since() returns correct duration\", () => {\n      const d = pd2.since(pd1);\n\n      expect(d.sign).toBe(1);\n      expect(d.years).toBe(0);\n      expect(d.months).toBe(0);\n      expect(d.days).toBe(1);\n    });\n\n    it(\"subtract() decrements by a duration\", () => {\n      const earlier = pd2.subtract({ days: 1 });\n      expect(earlier.day).toBeLessThan(pd2.day);\n    });\n\n    it(\"toPlainDateTime() returns a Temporal.PlainDateTime\", () => {\n      const pdate1 = pd1.toPlainDateTime();\n      expect(pdate1).toBeInstanceOf(Temporal.PlainDateTime);\n      expect(pdate1.toString()).toBe(\"2020-01-01T00:00:00\");\n\n      const pdate2 = pd1.toPlainDateTime(\"12:34:56\");\n      expect(pdate2.toString()).toBe(\"2020-01-01T12:34:56\");\n\n      const pt = Temporal.PlainTime.from(\"12:34:56\");\n      const pd3 = pd1.toPlainDateTime(pt);\n      expect(pd3.toString()).toBe(\"2020-01-01T12:34:56\");\n    });\n\n    it(\"toZonedDateTime() returns a Temporal.ZonedDateTime\", () => {\n      const pdt1 = pd1.toZonedDateTime(\"Asia/Tokyo\");\n      expect(pdt1).toBeInstanceOf(Temporal.ZonedDateTime);\n      expect(pdt1.toString()).toBe(\"2020-01-01T00:00:00+09:00[Asia/Tokyo]\");\n\n      const pdt2 = pd1.toZonedDateTime({ timeZone: \"Asia/Tokyo\" });\n      expect(pdt2.toString()).toBe(\"2020-01-01T00:00:00+09:00[Asia/Tokyo]\");\n\n      const pdt3 = pd1.toZonedDateTime({\n        timeZone: \"Asia/Tokyo\",\n        plainTime: \"12:34:56\",\n      });\n      expect(pdt3.toString()).toBe(\"2020-01-01T12:34:56+09:00[Asia/Tokyo]\");\n\n      const pt = Temporal.PlainTime.from(\"12:34:56\");\n      const pdt4 = pd1.toZonedDateTime({\n        timeZone: \"Asia/Tokyo\",\n        plainTime: pt,\n      });\n      expect(pdt4.toString()).toBe(\"2020-01-01T12:34:56+09:00[Asia/Tokyo]\");\n    });\n\n    it(\"toString() returns an ISO string representation\", () => {\n      const str = pd1.toString();\n      expect(typeof str).toBe(\"string\");\n      expect(str).toBe(\"2020-01-01\");\n    });\n\n    it(\"until() returns correct duration\", () => {\n      const d = pd1.until(pd2);\n\n      expect(d.sign).toBe(1);\n      expect(d.years).toBe(0);\n      expect(d.months).toBe(0);\n      expect(d.days).toBe(1);\n    });\n\n    it(\"valueOf() throws a TypeError\", () => {\n      expect(() => {\n        // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n        +pd1;\n      }).toThrow();\n    });\n\n    it(\"with() method returns a new PlainDate with updated fields\", () => {\n      const updated = pd1.with({ day: 15 });\n      expect(updated.day).toBe(15);\n      expect(updated.month).toBe(pd1.month);\n    });\n  });\n\n  describe(\"properties\", () => {\n    const pdt = Temporal.PlainDate.from(\"2020-01-01\");\n\n    it(\"should have correct date and time properties\", () => {\n      expect(pdt.year).toBe(2020);\n      expect(pdt.month).toBe(1);\n      expect(pdt.day).toBe(1);\n      expect(pdt.dayOfYear).toBe(1);\n      expect(pdt.daysInMonth).toBe(31);\n      expect(pdt.daysInYear).toBe(366);\n      expect(pdt.inLeapYear).toBe(true);\n    });\n\n    it(\"has correct toStringTag\", () => {\n      expect(Object.prototype.toString.call(pdt)).toBe(\n        \"[object Temporal.PlainDate]\"\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "tests/unit/temporal.plaindatetime.test.ts",
    "content": "describe(\"Temporal.PlainDateTime\", () => {\n  describe(\"creation and parsing\", () => {\n    it(\"can be created from an RFC 9557 string\", () => {\n      const pdt = Temporal.PlainDateTime.from(\"2021-08-19T17:01:00\");\n      expect(pdt.toString()).toContain(\"2021-08-19T17:01:00\");\n    });\n\n    it(\"can be created from an own object\", () => {\n      const pdt1 = Temporal.PlainDateTime.from(\"2021-08-19T17:01:00\");\n      const pdt2 = Temporal.PlainDateTime.from(pdt1);\n      expect(pdt1).toEqual(pdt2);\n    });\n\n    it(\"can be created from an object containing properties\", () => {\n      let pdt = Temporal.PlainDateTime.from({\n        year: 1995,\n        month: 12,\n        day: 7,\n        hour: 15,\n      });\n\n      expect(pdt.toString()).toEqual(\"1995-12-07T15:00:00\");\n    });\n  });\n\n  describe(\"arithmetic methods\", () => {\n    const pdt1 = Temporal.PlainDateTime.from(\"2020-01-01T12:00:00\");\n    const pdt2 = Temporal.PlainDateTime.from(\"2020-01-02T12:00:00\");\n\n    it(\"add() advances the date/time\", () => {\n      const later = pdt1.add({ days: 1 });\n      expect(later.day).toBe(2);\n    });\n\n    it(\"compare() method works for two PlainDateTime objects\", () => {\n      expect(Temporal.PlainDateTime.compare(pdt1, pdt2)).toBe(-1);\n      expect(Temporal.PlainDateTime.compare(pdt2, pdt1)).toBe(1);\n      expect(Temporal.PlainDateTime.compare(pdt1, pdt1)).toBe(0);\n    });\n\n    it(\"equals() verifies if two PlainDateTime are equal\", () => {\n      const same = Temporal.PlainDateTime.from(\"2020-01-01T12:00:00\");\n      expect(pdt1.equals(same)).toBe(true);\n    });\n\n    it(\"round() supports various forms, roundingMode, and roundingIncrement\", () => {\n      const zFrac = pdt1.add({ milliseconds: 500 });\n      const rounded = zFrac.round({ smallestUnit: \"second\" });\n      expect(rounded.second).toBe(1);\n\n      const truncated = zFrac.round({\n        smallestUnit: \"second\",\n        roundingMode: \"trunc\",\n      });\n      expect(truncated.second).toBe(0);\n\n      const zMulti = pdt1.add({ minutes: 7, seconds: 15 });\n      const str = zMulti.round(\"minute\");\n      expect(str.minute).toBe(7);\n      expect(str.second).toBe(0);\n\n      const inc = zMulti.round({\n        smallestUnit: \"minute\",\n        roundingIncrement: 15,\n      });\n      expect(inc.minute).toBe(0);\n\n      const incHour = zMulti.round({\n        smallestUnit: \"hour\",\n        roundingIncrement: 2,\n      });\n      expect(incHour.hour).toBe(12);\n    });\n\n    it(\"since() returns correct duration\", () => {\n      const d = pdt2.since(pdt1);\n\n      expect(d.sign).toBe(1);\n      expect(d.years).toBe(0);\n      expect(d.months).toBe(0);\n      expect(d.days).toBe(1);\n      expect(d.hours).toBe(0);\n      expect(d.minutes).toBe(0);\n      expect(d.seconds).toBe(0);\n      expect(d.milliseconds).toBe(0);\n      expect(d.microseconds).toBe(0);\n      expect(d.nanoseconds).toBe(0);\n    });\n\n    it(\"subtract() decrements by a duration\", () => {\n      const earlier = pdt1.subtract({ hours: 1 });\n      expect(earlier.hour).toBeLessThan(pdt1.hour);\n    });\n\n    it(\"toPlainDate() returns a Temporal.PlainDate\", () => {\n      const pd1 = pdt1.toPlainDate();\n      expect(pd1).toBeInstanceOf(Temporal.PlainDate);\n      expect(pd1.toString()).toBe(\"2020-01-01\");\n    });\n\n    it(\"toPlainTime() returns a Temporal.PlainTime\", () => {\n      const pt1 = pdt1.toPlainTime();\n      expect(pt1).toBeInstanceOf(Temporal.PlainTime);\n      expect(pt1.toString()).toBe(\"12:00:00\");\n    });\n\n    it(\"toString() returns an ISO string representation\", () => {\n      const str = pdt1.toString();\n      expect(typeof str).toBe(\"string\");\n      expect(str).toBe(\"2020-01-01T12:00:00\");\n    });\n\n    it(\"until() returns correct duration\", () => {\n      const d = pdt1.until(pdt2);\n\n      expect(d.sign).toBe(1);\n      expect(d.years).toBe(0);\n      expect(d.months).toBe(0);\n      expect(d.days).toBe(1);\n      expect(d.hours).toBe(0);\n      expect(d.minutes).toBe(0);\n      expect(d.seconds).toBe(0);\n      expect(d.milliseconds).toBe(0);\n      expect(d.microseconds).toBe(0);\n      expect(d.nanoseconds).toBe(0);\n    });\n\n    it(\"valueOf() throws a TypeError\", () => {\n      expect(() => {\n        // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n        +pdt1;\n      }).toThrow();\n    });\n\n    it(\"with() method returns a new PlainDateTime with updated fields\", () => {\n      const updated = pdt1.with({ day: 15 });\n      expect(updated.day).toBe(15);\n      expect(updated.month).toBe(pdt1.month);\n    });\n  });\n\n  describe(\"properties\", () => {\n    const pdt = Temporal.PlainDateTime.from(\"2020-01-01T12:00:00\");\n\n    it(\"should have correct date and time properties\", () => {\n      expect(pdt.year).toBe(2020);\n      expect(pdt.month).toBe(1);\n      expect(pdt.day).toBe(1);\n      expect(pdt.hour).toBe(12);\n      expect(pdt.minute).toBe(0);\n      expect(pdt.second).toBe(0);\n      expect(pdt.millisecond).toBe(0);\n      expect(pdt.microsecond).toBe(0);\n      expect(pdt.nanosecond).toBe(0);\n\n      expect(pdt.dayOfYear).toBe(1);\n      expect(pdt.daysInMonth).toBe(31);\n      expect(pdt.daysInYear).toBe(366);\n      expect(pdt.inLeapYear).toBe(true);\n    });\n\n    it(\"has correct toStringTag\", () => {\n      expect(Object.prototype.toString.call(pdt)).toBe(\n        \"[object Temporal.PlainDateTime]\"\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "tests/unit/temporal.plaintime.test.ts",
    "content": "describe(\"Temporal.PlainTime\", () => {\n  describe(\"creation and parsing\", () => {\n    it(\"can be created from an RFC 9557 string\", () => {\n      const pt = Temporal.PlainTime.from(\"17:01:00\");\n      expect(pt.toString()).toContain(\"17:01:00\");\n    });\n\n    it(\"can be created from an own object\", () => {\n      const pt1 = Temporal.PlainTime.from(\"17:01:00\");\n      const pt2 = Temporal.PlainTime.from(pt1);\n      expect(pt1).toEqual(pt2);\n    });\n\n    it(\"can be created from an object containing properties\", () => {\n      let time = Temporal.PlainTime.from({\n        hour: 19,\n        minute: 39,\n        second: 9,\n        millisecond: 68,\n        microsecond: 346,\n        nanosecond: 205,\n      });\n      expect(time.toString()).toEqual(\"19:39:09.068346205\");\n    });\n  });\n\n  describe(\"arithmetic methods\", () => {\n    const pt1 = Temporal.PlainTime.from(\"12:00:00\");\n    const pt2 = Temporal.PlainTime.from(\"12:00:01\");\n\n    it(\"add() advances the time\", () => {\n      const later = pt1.add({ hours: 1 });\n      expect(later.hour).toBe(13);\n    });\n\n    it(\"compare() method works for two PlainTime objects\", () => {\n      expect(Temporal.PlainTime.compare(pt1, pt2)).toBe(-1);\n      expect(Temporal.PlainTime.compare(pt2, pt1)).toBe(1);\n      expect(Temporal.PlainTime.compare(pt1, pt1)).toBe(0);\n    });\n\n    it(\"equals() verifies if two PlainTime are equal\", () => {\n      const same = Temporal.PlainTime.from(\"12:00:00\");\n      expect(pt1.equals(same)).toBe(true);\n    });\n\n    it(\"round() supports various forms, roundingMode, and roundingIncrement\", () => {\n      const zFrac = pt1.add({ milliseconds: 500 });\n      const rounded = zFrac.round({ smallestUnit: \"second\" });\n      expect(rounded.second).toBe(1);\n\n      const truncated = zFrac.round({\n        smallestUnit: \"second\",\n        roundingMode: \"trunc\",\n      });\n      expect(truncated.second).toBe(0);\n\n      const zMulti = pt1.add({ minutes: 7, seconds: 15 });\n      const str = zMulti.round(\"minute\");\n      expect(str.minute).toBe(7);\n      expect(str.second).toBe(0);\n\n      const inc = zMulti.round({\n        smallestUnit: \"minute\",\n        roundingIncrement: 15,\n      });\n      expect(inc.minute).toBe(0);\n\n      const incHour = zMulti.round({\n        smallestUnit: \"hour\",\n        roundingIncrement: 2,\n      });\n      expect(incHour.hour).toBe(12);\n    });\n\n    it(\"since() returns correct duration\", () => {\n      const d = pt2.since(pt1);\n\n      expect(d.sign).toBe(1);\n      expect(d.hours).toBe(0);\n      expect(d.minutes).toBe(0);\n      expect(d.seconds).toBe(1);\n      expect(d.milliseconds).toBe(0);\n      expect(d.microseconds).toBe(0);\n      expect(d.nanoseconds).toBe(0);\n    });\n\n    it(\"subtract() decrements by a duration\", () => {\n      const earlier = pt1.subtract({ hours: 1 });\n      expect(earlier.hour).toBeLessThan(pt1.hour);\n    });\n\n    it(\"toString() returns an ISO string representation\", () => {\n      const str = pt1.toString();\n      expect(typeof str).toBe(\"string\");\n      expect(str).toBe(\"12:00:00\");\n    });\n\n    it(\"until() returns correct duration\", () => {\n      const d = pt1.until(pt2);\n\n      expect(d.sign).toBe(1);\n      expect(d.hours).toBe(0);\n      expect(d.minutes).toBe(0);\n      expect(d.seconds).toBe(1);\n      expect(d.milliseconds).toBe(0);\n      expect(d.microseconds).toBe(0);\n      expect(d.nanoseconds).toBe(0);\n    });\n\n    it(\"valueOf() throws a TypeError\", () => {\n      expect(() => {\n        // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n        +pt1;\n      }).toThrow();\n    });\n\n    it(\"with() method returns a new PlainTime with updated fields\", () => {\n      const updated = pt1.with({ hour: 15 });\n      expect(updated.hour).toBe(15);\n    });\n  });\n\n  describe(\"properties\", () => {\n    const pt = Temporal.PlainTime.from(\"12:00:00\");\n\n    it(\"should have correct date and time properties\", () => {\n      expect(pt.hour).toBe(12);\n      expect(pt.minute).toBe(0);\n      expect(pt.second).toBe(0);\n      expect(pt.millisecond).toBe(0);\n      expect(pt.microsecond).toBe(0);\n      expect(pt.nanosecond).toBe(0);\n    });\n\n    it(\"has correct toStringTag\", () => {\n      expect(Object.prototype.toString.call(pt)).toBe(\n        \"[object Temporal.PlainTime]\"\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "tests/unit/temporal.zoneddatetime.test.ts",
    "content": "describe(\"Constructor\", () => {\n  describe(\"Temporal.ZonedDateTime()\", () => {\n    it(\"Using Temporal.ZonedDateTime()\", () => {\n      const zdt = new Temporal.ZonedDateTime(0n, \"America/New_York\");\n      expect(zdt.toString()).toBe(\n        \"1969-12-31T19:00:00-05:00[America/New_York]\"\n      );\n    });\n  });\n});\n\ndescribe(\"Static methods\", () => {\n  describe(\"Temporal.ZonedDateTime.compare()\", () => {\n    it(\"Using Temporal.ZonedDateTime.compare()\", () => {\n      const dt1 = Temporal.ZonedDateTime.from(\n        \"2021-08-01T01:00:00[Europe/London]\"\n      );\n      const dt2 = Temporal.ZonedDateTime.from(\n        \"2021-08-02T00:00:00[Europe/London]\"\n      );\n      expect(Temporal.ZonedDateTime.compare(dt1, dt2)).toBe(-1);\n\n      const dt3 = Temporal.ZonedDateTime.from(\n        \"2021-08-01T00:00:00[Europe/London]\"\n      );\n      expect(Temporal.ZonedDateTime.compare(dt1, dt3)).toBe(1);\n    });\n\n    it(\"Sorting an array of date-times #1\", () => {\n      const dateTimes = [\n        Temporal.ZonedDateTime.from(\"2021-08-01T00:00:00[America/New_York]\"),\n        Temporal.ZonedDateTime.from(\"2021-08-01T00:00:00[Asia/Hong_Kong]\"),\n        Temporal.ZonedDateTime.from(\"2021-08-01T00:00:00[Europe/London]\"),\n      ];\n\n      dateTimes.sort(Temporal.ZonedDateTime.compare);\n      expect(dateTimes.map((d) => d.toString())).toStrictEqual([\n        \"2021-08-01T00:00:00+08:00[Asia/Hong_Kong]\",\n        \"2021-08-01T00:00:00+01:00[Europe/London]\",\n        \"2021-08-01T00:00:00-04:00[America/New_York]\",\n      ]);\n    });\n\n    it(\"Sorting an array of date-times #2\", () => {\n      const dateTimes = [\n        Temporal.ZonedDateTime.from(\"2021-08-01T00:00:00[America/New_York]\"),\n        Temporal.ZonedDateTime.from(\"2021-08-01T00:00:00[Asia/Hong_Kong]\"),\n        Temporal.ZonedDateTime.from(\"2021-08-01T00:00:00[Europe/London]\"),\n      ];\n\n      dateTimes.sort((a, b) =>\n        Temporal.PlainDateTime.compare(a.toPlainDateTime(), b.toPlainDateTime())\n      );\n      expect(dateTimes.map((d) => d.toString())).toStrictEqual([\n        \"2021-08-01T00:00:00-04:00[America/New_York]\",\n        \"2021-08-01T00:00:00+08:00[Asia/Hong_Kong]\",\n        \"2021-08-01T00:00:00+01:00[Europe/London]\",\n      ]);\n    });\n  });\n\n  describe(\"Temporal.ZonedDateTime.from()\", () => {\n    it(\"Creating a ZonedDateTime from an object\", () => {\n      // Year + month + day + hour + minute + second\n      const zdt = Temporal.ZonedDateTime.from({\n        timeZone: \"America/New_York\",\n        year: 2021,\n        month: 7,\n        day: 1,\n        hour: 12,\n        minute: 34,\n        second: 56,\n      });\n      expect(zdt.toString()).toBe(\n        \"2021-07-01T12:34:56-04:00[America/New_York]\"\n      );\n    });\n\n    it(\"Creating a ZonedDateTime from a string\", () => {\n      // const zdt = Temporal.ZonedDateTime.from(\n      //   \"2021-07-01T12:34:56-04:00[America/New_York]\",\n      // );\n      // expect(zdt.toLocaleString()); // \"7/1/2021, 12:34:56 PM EDT\" (assuming en-US locale)\n\n      // Time given as UTC, and converted to local\n      const zdt2 = Temporal.ZonedDateTime.from(\n        \"2021-07-01T12:34:56Z[America/New_York]\"\n      );\n      expect(zdt2.toString()).toBe(\n        \"2021-07-01T08:34:56-04:00[America/New_York]\"\n      );\n    });\n\n    it(\"Creating a ZonedDateTime from an ISO 8601 / RFC 3339 string\", () => {\n      const isoString = \"2021-07-01T12:34:56+02:00\";\n      const instant = Temporal.Instant.from(isoString);\n      const zdt = instant.toZonedDateTimeISO(\"America/New_York\");\n      expect(zdt.toString()).toBe(\n        \"2021-07-01T06:34:56-04:00[America/New_York]\"\n      );\n    });\n\n    it(\"Local time disambiguation\", () => {\n      const localTimeNotExist = \"2024-03-10T02:05:00[America/New_York]\";\n      // For non-existent times, \"compatible\" is equivalent to \"later\"\n      const zdt = Temporal.ZonedDateTime.from(localTimeNotExist);\n      expect(zdt.toString()).toBe(\n        \"2024-03-10T03:05:00-04:00[America/New_York]\"\n      );\n\n      // const zdt2 = Temporal.ZonedDateTime.from(localTimeNotExist, {\n      //   disambiguation: \"earlier\",\n      // });\n      // expect(zdt2.toString()).toBe(\"2024-03-10T01:05:00-05:00[America/New_York]\");\n\n      const localTimeAmbiguous = \"2024-11-03T01:05:00[America/New_York]\";\n      // For ambiguous times, \"compatible\" is equivalent to \"earlier\"\n      const zdt3 = Temporal.ZonedDateTime.from(localTimeAmbiguous);\n      expect(zdt3.toString()).toBe(\n        \"2024-11-03T01:05:00-04:00[America/New_York]\"\n      );\n\n      // const zdt4 = Temporal.ZonedDateTime.from(localTimeAmbiguous, {\n      //   disambiguation: \"later\",\n      // });\n      // expect(zdt4.toString()).toBe(\"2024-11-03T01:05:00-05:00[America/New_York]\");\n    });\n  });\n});\n\ndescribe(\"Temporal.ZonedDateTime\", () => {\n  describe(\"creation and parsing\", () => {\n    it(\"can be created from an RFC 9557 string\", () => {\n      const zdt1 = Temporal.ZonedDateTime.from(\n        \"2021-08-19T17:01:00+01:00[Europe/London]\"\n      );\n      expect(zdt1.toString()).toContain(\n        \"2021-08-19T17:01:00+01:00[Europe/London]\"\n      );\n    });\n\n    it(\"can be created from an own object\", () => {\n      const zdt1 = Temporal.ZonedDateTime.from(\n        \"2021-08-19T17:01:00+01:00[Europe/London]\"\n      );\n      const zdt2 = Temporal.ZonedDateTime.from(zdt1);\n      expect(zdt1).toEqual(zdt2);\n    });\n\n    it(\"can be created from an object containing properties\", () => {\n      const zdt1 = Temporal.ZonedDateTime.from({\n        timeZone: \"America/Los_Angeles\",\n        year: 1995,\n        month: 12,\n        day: 7,\n        hour: 3,\n        minute: 24,\n        second: 30,\n        millisecond: 0,\n        microsecond: 3,\n        nanosecond: 500,\n      });\n      expect(zdt1.toString()).toEqual(\n        \"1995-12-07T03:24:30.0000035-08:00[America/Los_Angeles]\"\n      );\n    });\n  });\n\n  describe(\"arithmetic methods\", () => {\n    const zdt1 = Temporal.ZonedDateTime.from(\"2020-01-01T12:00:00+00:00[UTC]\");\n    const zdt2 = Temporal.ZonedDateTime.from(\"2020-01-02T12:00:00+00:00[UTC]\");\n\n    it(\"add() advances the date/time\", () => {\n      const later = zdt1.add({ days: 1 });\n      expect(later.day).toBe(2);\n    });\n\n    it(\"compare() method works for two ZonedDateTime objects\", () => {\n      expect(Temporal.ZonedDateTime.compare(zdt1, zdt2)).toBe(-1);\n      expect(Temporal.ZonedDateTime.compare(zdt2, zdt1)).toBe(1);\n      expect(Temporal.ZonedDateTime.compare(zdt1, zdt1)).toBe(0);\n    });\n\n    it(\"equals() verifies if two ZonedDateTime are equal\", () => {\n      const same = Temporal.ZonedDateTime.from(\"2020-01-01T12:00:00[UTC]\");\n      expect(zdt1.equals(same)).toBe(true);\n    });\n\n    it(\"getTimeZoneTransition() returns the next and previous timezone offset transitions\", () => {\n      const dt = Temporal.ZonedDateTime.from(\n        \"2024-01-01T00-05:00[America/New_York]\"\n      );\n      const transition = dt.getTimeZoneTransition(\"next\");\n      expect(transition.toString()).toBe(\n        \"2024-03-10T03:00:00-04:00[America/New_York]\"\n      );\n\n      const transition2 = transition.getTimeZoneTransition(\"next\");\n      expect(transition2.toString()).toBe(\n        \"2024-11-03T01:00:00-05:00[America/New_York]\"\n      );\n\n      const transition3 = dt.getTimeZoneTransition(\"previous\");\n      expect(transition3.toString()).toBe(\n        \"2023-11-05T01:00:00-05:00[America/New_York]\"\n      );\n\n      const dt2 = Temporal.ZonedDateTime.from(\"2024-01-01T00Z[UTC]\");\n      expect(dt2.getTimeZoneTransition(\"next\")).toBe(null);\n    });\n\n    it(\"round() supports various forms, roundingMode, and roundingIncrement\", () => {\n      const zFrac = zdt1.add({ milliseconds: 500 });\n      const rounded = zFrac.round({ smallestUnit: \"second\" });\n      expect(rounded.second).toBe(1);\n      expect(rounded.offset).toBe(\"+00:00\");\n      expect(rounded.timeZoneId).toBe(\"UTC\");\n\n      const truncated = zFrac.round({\n        smallestUnit: \"second\",\n        roundingMode: \"trunc\",\n      });\n      expect(truncated.second).toBe(0);\n\n      const zMulti = zdt1.add({ minutes: 7, seconds: 15 });\n      const str = zMulti.round(\"minute\");\n      expect(str.minute).toBe(7);\n      expect(str.second).toBe(0);\n\n      const inc = zMulti.round({\n        smallestUnit: \"minute\",\n        roundingIncrement: 15,\n      });\n      expect(inc.minute).toBe(0);\n\n      const incHour = zMulti.round({\n        smallestUnit: \"hour\",\n        roundingIncrement: 2,\n      });\n      expect(incHour.hour).toBe(12);\n    });\n\n    it(\"since() returns correct duration\", () => {\n      const d = zdt2.since(zdt1);\n\n      expect(d.sign).toBe(1);\n      expect(d.years).toBe(0);\n      expect(d.months).toBe(0);\n      expect(d.days).toBe(0);\n      expect(d.hours).toBe(24);\n      expect(d.minutes).toBe(0);\n      expect(d.seconds).toBe(0);\n      expect(d.milliseconds).toBe(0);\n      expect(d.microseconds).toBe(0);\n      expect(d.nanoseconds).toBe(0);\n    });\n\n    it(\"subtract() decrements by a duration\", () => {\n      const earlier = zdt1.subtract({ hours: 1 });\n      expect(earlier.hour).toBeLessThan(zdt1.hour);\n    });\n\n    it(\"toInstant() returns a Temporal.Instant\", () => {\n      const inst = zdt1.toInstant();\n      expect(inst).toBeInstanceOf(Temporal.Instant);\n    });\n\n    it(\"toPlainDate() returns a Temporal.PlainDate\", () => {\n      const pd1 = zdt1.toPlainDate();\n      expect(pd1).toBeInstanceOf(Temporal.PlainDate);\n      expect(pd1.toString()).toBe(\"2020-01-01\");\n    });\n\n    it(\"toPlainDateTime() returns a Temporal.PlainDateTime\", () => {\n      const pdt1 = zdt1.toPlainDateTime();\n      expect(pdt1).toBeInstanceOf(Temporal.PlainDateTime);\n      expect(pdt1.toString()).toBe(\"2020-01-01T12:00:00\");\n    });\n\n    it(\"toPlainTime() returns a Temporal.PlainTime\", () => {\n      const pt1 = zdt1.toPlainTime();\n      expect(pt1).toBeInstanceOf(Temporal.PlainTime);\n      expect(pt1.toString()).toBe(\"12:00:00\");\n    });\n\n    it(\"toString() returns an ISO string representation\", () => {\n      const str = zdt1.toString();\n      expect(typeof str).toBe(\"string\");\n      expect(str).toBe(\"2020-01-01T12:00:00+00:00[UTC]\");\n    });\n\n    it(\"until() returns correct duration\", () => {\n      const d = zdt1.until(zdt2);\n\n      expect(d.sign).toBe(1);\n      expect(d.years).toBe(0);\n      expect(d.months).toBe(0);\n      expect(d.days).toBe(0);\n      expect(d.hours).toBe(24);\n      expect(d.minutes).toBe(0);\n      expect(d.seconds).toBe(0);\n      expect(d.milliseconds).toBe(0);\n      expect(d.microseconds).toBe(0);\n      expect(d.nanoseconds).toBe(0);\n    });\n\n    it(\"valueOf() throws a TypeError\", () => {\n      expect(() => {\n        // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n        +zdt1;\n      }).toThrow();\n    });\n\n    it(\"with() method returns a new ZonedDateTime with updated fields\", () => {\n      const updated = zdt1.with({ day: 15 });\n      expect(updated.day).toBe(15);\n      expect(updated.month).toBe(zdt1.month);\n    });\n\n    it(\"withTimeZone() method returns a new ZonedDateTime with replaceing timezone\", () => {\n      const updated = zdt1.withTimeZone(\"Asia/Tokyo\");\n      expect(updated.toString()).toBe(\"2020-01-01T21:00:00+09:00[Asia/Tokyo]\");\n    });\n  });\n\n  describe(\"properties\", () => {\n    const zdt = Temporal.ZonedDateTime.from(\"2020-01-01T12:00:00[UTC]\");\n\n    it(\"should have correct date and time properties\", () => {\n      expect(zdt.year).toBe(2020);\n      expect(zdt.month).toBe(1);\n      expect(zdt.day).toBe(1);\n      expect(zdt.hour).toBe(12);\n      expect(zdt.minute).toBe(0);\n      expect(zdt.second).toBe(0);\n      expect(zdt.millisecond).toBe(0);\n      expect(zdt.offset).toBe(\"+00:00\");\n\n      expect(typeof zdt.epochMilliseconds).toBe(\"number\");\n      expect(zdt.epochMilliseconds).toBeGreaterThan(0);\n      expect(typeof zdt.epochNanoseconds).toBe(\"bigint\");\n      expect(zdt.epochNanoseconds).toBeGreaterThan(0n);\n\n      expect(zdt.dayOfYear).toBe(1);\n      expect(zdt.daysInMonth).toBe(31);\n      expect(zdt.daysInYear).toBe(366);\n      expect(zdt.inLeapYear).toBe(true);\n    });\n\n    it(\"has correct toStringTag\", () => {\n      expect(Object.prototype.toString.call(zdt)).toBe(\n        \"[object Temporal.ZonedDateTime]\"\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "tests/unit/test-utils.ts",
    "content": "import { spawn } from \"node:child_process\";\n\nexport const spawnCapture = (\n  cmd: string,\n  args: string[] = [],\n  options?: { env?: Record<string, string> }\n): Promise<{ code: number; stdout: string; stderr: string }> =>\n  new Promise((resolve, reject) => {\n    let stdout = \"\";\n    let stderr = \"\";\n    const child = spawn(cmd, args, options);\n    child.stdout.on(\"data\", (data) => {\n      stdout += data.toString();\n    });\n    child.stderr.on(\"data\", (data) => {\n      stderr += data.toString();\n    });\n    child.on(\"close\", (code) => resolve({ code: code ?? -1, stdout, stderr }));\n    child.on(\"error\", reject);\n  });\n"
  },
  {
    "path": "tests/unit/timers.test.ts",
    "content": "import defaultImport from \"node:timers\";\nimport legacyImport from \"timers\";\n\nit(\"node:perf_hooks should be the same as perf_hooks\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n\nconst { setTimeout } = defaultImport;\n\nit(\"should set timeout\", async () => {\n  const start = Date.now();\n  await new Promise((resolve) => {\n    setTimeout(resolve, 10);\n  });\n  const end = Date.now();\n  expect(end - start >= 10).toBeTruthy();\n});\n\nit(\"should set nested timeout\", (done) => {\n  setTimeout(() => {\n    setTimeout(done, 10);\n  }, 10);\n});\n\nit(\"should clear timeout\", async () => {\n  const start = Date.now();\n  let status = \"\";\n  await new Promise<void>((resolve) => {\n    const timeout = setTimeout(() => {\n      status = \"not-cleared\";\n      resolve();\n    }, 5);\n\n    setTimeout(() => {\n      status = \"cleared\";\n      resolve();\n    }, 10);\n\n    clearTimeout(timeout);\n  });\n  const end = Date.now();\n\n  expect(end - start >= 10).toBeTruthy();\n  expect(status).toEqual(\"cleared\");\n});\n\nit(\"should set interval\", async () => {\n  const start = Date.now();\n  let count = 1;\n  await new Promise<void>((resolve) => {\n    const interval = setInterval(() => {\n      if (count > 4) {\n        clearInterval(interval);\n        return resolve();\n      }\n      count++;\n    }, 5);\n  });\n  const end = Date.now();\n  expect(end - start >= 10).toBeTruthy();\n  expect(count).toEqual(5);\n});\n\nit(\"should clear interval\", async () => {\n  const start = Date.now();\n  let count = 1;\n  await new Promise<void>((resolve) => {\n    let interval = setInterval(() => {\n      if (count == 2) {\n        clearInterval(interval);\n        return;\n      }\n      count++;\n    }, 5);\n    setTimeout(resolve, 20);\n  });\n  const end = Date.now();\n  expect(end - start > 10).toBeTruthy();\n  expect(count).toEqual(2);\n});\n\nit(\"should accept any parameter to clear timeout\", () => {\n  expect(() => {\n    clearTimeout(null as any);\n    clearTimeout(\"\" as any);\n    clearTimeout(true as any);\n    clearTimeout({});\n  }).not.toThrow();\n});\n\nit(\"should import timers\", () => {\n  expect(setTimeout).toStrictEqual(globalThis.setTimeout);\n});\n\nit(\"delay is optional\", async () => {\n  const start = Date.now();\n  await new Promise((resolve) => {\n    setTimeout(resolve);\n  });\n  const end = Date.now();\n  expect(end - start >= 0).toBeTruthy();\n});\n\nit(\"delay can be negative.\", async () => {\n  const start = Date.now();\n  await new Promise((resolve) => {\n    setTimeout(resolve, -1);\n  });\n  const end = Date.now();\n  expect(end - start >= 0).toBeTruthy();\n});\n"
  },
  {
    "path": "tests/unit/tty.test.ts",
    "content": "import defaultImport from \"node:tty\";\nimport legacyImport from \"tty\";\n\nit(\"node:tty should be the same as tty\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n"
  },
  {
    "path": "tests/unit/url.test.ts",
    "content": "import defaultImport from \"node:url\";\nimport legacyImport from \"url\";\n\nimport { platform } from \"node:os\";\nconst IS_WINDOWS = platform() === \"win32\";\n\nit(\"node:url should be the same as url\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n\nconst {\n  format,\n  URL,\n  URLSearchParams,\n  urlToHttpOptions,\n  domainToUnicode,\n  domainToASCII,\n  fileURLToPath,\n  pathToFileURL,\n} = defaultImport;\n\ndescribe(\"URL module import\", () => {\n  it(\"global URL and imported URL are equal\", () => {\n    const testUrl = \"https://www.example.com\";\n    const moduleUrl = new URL(testUrl);\n    const globalUrl = new globalThis.URL(testUrl);\n    expect(moduleUrl).toEqual(globalUrl);\n  });\n  it(\"global URLSearchParams and imported URLSearchParams are equal\", () => {\n    const paramsString = \"topic=api&a=1&a=2&a=3\";\n    const moduleSearchParams = new URLSearchParams(paramsString);\n    const globalSearchParams = new globalThis.URLSearchParams(paramsString);\n    expect(moduleSearchParams).toEqual(globalSearchParams);\n  });\n  describe(\"import { URL } from 'url';\", () => {\n    it(\"should parse a url hostname\", () => {\n      const testUrl = new URL(\"https://www.example.com\");\n      expect(testUrl.protocol).toEqual(\"https:\");\n      expect(testUrl.host).toEqual(\"www.example.com\");\n      expect(testUrl.hostname).toEqual(\"www.example.com\");\n    });\n    it(\"toString method works\", () => {\n      const testUrl = new URL(\"/base\", \"https://www.example.com\");\n      expect(testUrl.toString()).toEqual(\"https://www.example.com/base\");\n    });\n    it(\"canParse method works\", () => {\n      const validCanParse = URL.canParse(\"https://www.example.com\");\n      const invalidCanParse = URL.canParse(\"not_valid\");\n      expect(validCanParse).toEqual(true);\n      expect(invalidCanParse).toEqual(false);\n      expect(URL.canParse(\"/foo\", \"https://example.org/\")).toEqual(true);\n    });\n  });\n\n  describe(\"import { URLSearchParams } from 'url';\", () => {\n    it(\"supports URLSearchParams basic API\", () => {\n      const paramsString = \"topic=api&a=1&a=2&a=3\";\n      const searchParams = new URLSearchParams(paramsString);\n      expect(searchParams.size).toEqual(4);\n      searchParams.append(\"foo\", \"bar\");\n      expect(searchParams.size).toEqual(5);\n      expect(searchParams.has(\"topic\")).toBeTruthy();\n      expect(searchParams.has(\"foo\")).toBeTruthy();\n      searchParams.delete(\"foo\");\n      expect(searchParams.size).toEqual(4);\n      expect(searchParams.has(\"foo\")).toBeFalsy();\n      expect(searchParams.get(\"topic\")).toEqual(\"api\");\n      expect(searchParams.getAll(\"a\")).toEqual([\"1\", \"2\", \"3\"]);\n      searchParams.set(\"topic\", \"node\");\n      expect(searchParams.size).toEqual(4);\n      expect(searchParams.get(\"topic\")).toEqual(\"node\");\n    });\n  });\n});\n\ndescribe(\"URL class\", () => {\n  it(\"should parse a valid URL\", () => {\n    const url = new URL(\"https://www.example.com\");\n    expect(url.protocol).toEqual(\"https:\");\n    expect(url.hostname).toEqual(\"www.example.com\");\n  });\n\n  it(\"should create a copy of a valid URL\", () => {\n    const url: any = new URL(\"https://www.example.com\");\n    const url2 = new URL(url);\n    expect(url).toEqual(url2);\n    expect(url).not.toBe(url2);\n  });\n\n  it(\"should to append base to a url\", () => {\n    const url = new URL(\"/base\", \"https://www.example.com\");\n    expect(url.toString()).toEqual(\"https://www.example.com/base\");\n  });\n\n  it(\"should throw an error for an invalid URL\", () => {\n    expect(() => {\n      new URL(\"not-a-url\");\n    }).toThrow(/Invalid URL/);\n  });\n\n  it(\"should return the URL as a string\", () => {\n    const url = new URL(\"https://www.example.com\");\n    expect(url.toString()).toEqual(\"https://www.example.com/\");\n  });\n\n  it(\"should parse query parameters\", () => {\n    const url = new URL(\"https://www.example.com/?foo=bar&baz=qux\");\n    expect(url.searchParams.get(\"foo\")).toEqual(\"bar\");\n    expect(url.searchParams.get(\"baz\")).toEqual(\"qux\");\n  });\n\n  it(\"should be able to set and get port\", () => {\n    let url: any = new URL(\"https://www.example.com\");\n    url.port = \"1234\";\n    expect(url.toString()).toEqual(\"https://www.example.com:1234/\");\n    url.port = 5678;\n    expect(url.toString()).toEqual(\"https://www.example.com:5678/\");\n\n    url = new URL(\"https://www.example.com:443/route/example\");\n    expect(url.port).toEqual(\"\");\n    expect(url.toString()).toEqual(\"https://www.example.com/route/example\");\n\n    url.port = 21;\n    expect(url.toString()).toEqual(\"https://www.example.com:21/route/example\");\n\n    url.protocol = \"ftp\";\n    expect(url.toString()).toEqual(\"ftp://www.example.com/route/example\");\n\n    url.protocol = \"http\";\n    url.port = 80;\n    expect(url.toString()).toEqual(\"http://www.example.com/route/example\");\n  });\n\n  it(\"should modify query parameters\", () => {\n    const url = new URL(\"https://www.example.com/?foo=bar&baz=qux\");\n    url.searchParams.set(\"foo\", \"new-value\");\n    expect(url.toString()).toEqual(\n      \"https://www.example.com/?foo=new-value&baz=qux\"\n    );\n  });\n  it(\"should parse username and password\", () => {\n    const url = new URL(\n      \"https://anonymous:flabada@developer.mozilla.org/en-US/docs/Web/API/URL/username\"\n    );\n    expect(url.username).toEqual(\"anonymous\");\n    expect(url.password).toEqual(\"flabada\");\n  });\n  it(\"should provide parse/canParse util\", () => {\n    const validUrl = \"https://www.example.com/\";\n    const invalidUrl = \"not_a_valid_url\";\n    expect(URL.parse(validUrl).href).toEqual(validUrl);\n    expect(URL.canParse(validUrl)).toEqual(true);\n    expect(URL.parse(invalidUrl)).toBeNull();\n    expect(URL.canParse(invalidUrl)).toEqual(false);\n  });\n  it(\"parse/canParse works for relative urls\", () => {\n    expect(URL.parse(\"/foo\", \"https://example.org/\").href).toEqual(\n      \"https://example.org/foo\"\n    );\n    expect(URL.canParse(\"/foo\", \"https://example.org/\")).toEqual(true);\n  });\n});\n\ndescribe(\"URLSearchParams class\", () => {\n  it(\"constructor from array\", () => {\n    //@ts-ignore\n    const searchParams = new URLSearchParams([[\"topic\", [\"api\", \"1234\"]]]);\n    expect(searchParams.get(\"topic\")).toBe(\"api,1234\");\n  });\n\n  it(\"constructor from object\", () => {\n    const paramsObject = { foo: \"1\", bar: \"2\" };\n    const searchParams = new URLSearchParams(paramsObject);\n    expect(searchParams.get(\"foo\")).toBe(\"1\");\n    expect(searchParams.get(\"bar\")).toBe(\"2\");\n  });\n\n  it(\"constructor from iterator\", () => {\n    const paramsArray = [\n      [\"foo\", \"1\"],\n      [\"bar\", \"2\"],\n    ];\n    const paramsIterator = paramsArray[Symbol.iterator]();\n    //@ts-ignore\n    const searchParams = new URLSearchParams(paramsIterator);\n    expect(searchParams.get(\"foo\")).toBe(\"1\");\n    expect(searchParams.get(\"bar\")).toBe(\"2\");\n  });\n\n  it(\"constructor from string with special characters\", () => {\n    const paramsString = \"topic=api&category=coding%20skills\";\n    const searchParams = new URLSearchParams(paramsString);\n    expect(searchParams.get(\"topic\")).toBe(\"api\");\n    expect(searchParams.get(\"category\")).toBe(\"coding skills\");\n  });\n\n  it(\"constructor from URLSearchParams object\", () => {\n    const existingParamsString = \"topic=api\";\n    const existingSearchParams = new URLSearchParams(existingParamsString);\n    const newSearchParams = new URLSearchParams(existingSearchParams);\n    expect(newSearchParams.get(\"topic\")).toBe(\"api\");\n  });\n\n  it(\"should have a parameter if it exists\", () => {\n    const paramsString = \"?topic=api&a=1&a=2&a=3\";\n    const searchParams = new URLSearchParams(paramsString);\n    expect(searchParams.has(\"topic\")).toBeTruthy();\n  });\n\n  it(\"should not have a parameter if it doesn't exist\", () => {\n    const paramsString = \"topic=api&a=1&a=2&a=3\";\n    const searchParams = new URLSearchParams(paramsString);\n    expect(!searchParams.has(\"foo\")).toBeTruthy();\n  });\n\n  it(\"should return the value of the parameter if it exists\", () => {\n    const paramsString = \"topic=api&a=1&a=2&a=3\";\n    const searchParams = new URLSearchParams(paramsString);\n    expect(searchParams.get(\"topic\") === \"api\").toBeTruthy();\n  });\n\n  it(\"should return null if the parameter doesn't exist\", () => {\n    const paramsString = \"topic=api&a=1&a=2&a=3\";\n    const searchParams = new URLSearchParams(paramsString);\n    expect(searchParams.get(\"foo\")).toBeNull();\n  });\n\n  it(\"should return an array of all values of the parameter if it exists\", () => {\n    const paramsString = \"topic=api&a=1&a=2&a=3\";\n    const searchParams = new URLSearchParams(paramsString);\n    expect(searchParams.getAll(\"a\")).toEqual([\"1\", \"2\", \"3\"]);\n  });\n\n  it(\"should return an empty array if the parameter doesn't exist\", () => {\n    const paramsString = \"topic=api&a=1&a=2&a=3\";\n    const searchParams = new URLSearchParams(paramsString);\n    expect(searchParams.getAll(\"foo\")).toEqual([]);\n  });\n\n  it(\"should add the parameter to the end of the query string\", () => {\n    const paramsString = \"topic=api&a=1&a=2&a=3\";\n    const searchParams = new URLSearchParams(paramsString);\n    searchParams.append(\"topic\", \"webdev\");\n    expect(searchParams.toString()).toEqual(\n      \"topic=api&a=1&a=2&a=3&topic=webdev\"\n    );\n  });\n\n  it(\"should replace all values of the parameter with the given value\", () => {\n    const paramsString = \"topic=api&a=1&a=2&a=3\";\n    const searchParams = new URLSearchParams(paramsString);\n    searchParams.set(\"topic\", \"More webdev\");\n    expect(searchParams.toString()).toEqual(\"topic=More+webdev&a=1&a=2&a=3\");\n  });\n\n  it(\"should set value even if not existing\", () => {\n    const searchParams = new URLSearchParams(\"?bar=baz\");\n    searchParams.set(\"foo\", \"bar\");\n    expect(searchParams.toString()).toEqual(\"bar=baz&foo=bar\");\n  });\n\n  it(\"should remove the parameter from the query string\", () => {\n    const paramsString = \"topic=api&a=1&a=2&a=3\";\n    const searchParams = new URLSearchParams(paramsString);\n    searchParams.delete(\"topic\");\n    expect(searchParams.toString()).toEqual(\"a=1&a=2&a=3\");\n  });\n\n  it(\"should iterate over all parameters in the query string\", () => {\n    const paramsString = \"topic=api&a=1&a=2&a=3\";\n    const searchParams = new URLSearchParams(paramsString);\n    let arr: [string, string][] = [];\n    for (const p of searchParams) {\n      arr.push(p);\n    }\n    expect(arr).toEqual([\n      [\"topic\", \"api\"],\n      [\"a\", \"1\"],\n      [\"a\", \"2\"],\n      [\"a\", \"3\"],\n    ]);\n  });\n\n  it(\"should for_each all parameters in the query string\", () => {\n    const paramsString = \"topic=api&a=1&a=2&a=3\";\n    const searchParams = new URLSearchParams(paramsString);\n    let arr: [string, string][] = [];\n    searchParams.forEach((value, key) => {\n      arr.push([key, value]);\n    });\n    expect(arr).toEqual([\n      [\"topic\", \"api\"],\n      [\"a\", \"1\"],\n      [\"a\", \"2\"],\n      [\"a\", \"3\"],\n    ]);\n  });\n\n  it(\"should get key parameters in the query string\", () => {\n    const paramsString = \"key1=value1&key2=value2\";\n    const searchParams = new URLSearchParams(paramsString);\n    let keys = \"\";\n    for (const key of searchParams.keys()) {\n      keys = keys + key;\n    }\n    expect(keys).toEqual(\"key1key2\");\n  });\n\n  it(\"should get value parameters in the query string\", () => {\n    const paramsString = \"key1=value1&key2=value2\";\n    const searchParams = new URLSearchParams(paramsString);\n    let values = \"\";\n    for (const value of searchParams.values()) {\n      values = values + value;\n    }\n    expect(values).toEqual(\"value1value2\");\n  });\n});\n\ndescribe(\"URL Utility Functions\", () => {\n  it(\"converts URL object to http options with urlToHttpOptions\", () => {\n    const url = new URL(\n      \"https://user:password@example.com:8080/path/to/file?param1=value1&param2=value2#fragment\"\n    );\n    const options = urlToHttpOptions(url);\n\n    expect(options).toEqual({\n      protocol: \"https:\",\n      hostname: \"example.com\",\n      hash: \"fragment\",\n      search: \"?param1=value1&param2=value2\",\n      pathname: \"/path/to/file\",\n      path: \"/path/to/file?param1=value1&param2=value2\",\n      href: \"https://user:password@example.com:8080/path/to/file?param1=value1&param2=value2#fragment\",\n      auth: \"user:password\",\n      port: \"8080\",\n    });\n  });\n\n  it(\"handles URL without credentials or port with urlToHttpOptions\", () => {\n    const url = new URL(\"http://example.com/path/to/file\");\n    const options = urlToHttpOptions(url);\n\n    expect(options).toEqual({\n      protocol: \"http:\",\n      hostname: \"example.com\",\n      pathname: \"/path/to/file\",\n      path: \"/path/to/file\",\n      href: \"http://example.com/path/to/file\",\n    });\n  });\n\n  it(\"converts punycode domain to unicode with domainToUnicode\", () => {\n    const unicodeDomain = domainToUnicode(\"xn--d1mi3b5c.com\");\n    expect(unicodeDomain).toBe(\"㶠㶤㷀㶱.com\");\n  });\n\n  it(\"handles already unicode domain with domainToUnicode\", () => {\n    const unicodeDomain = domainToUnicode(\"example.com\");\n    expect(unicodeDomain).toBe(\"example.com\");\n  });\n\n  it(\"converts unicode domain to punycode with domainToASCII\", () => {\n    const asciiDomain = domainToASCII(\"example.com\");\n    expect(asciiDomain).toBe(\"example.com\"); // No conversion needed\n  });\n\n  it(\"converts non-ASCII domain to punycode with domainToASCII\", () => {\n    const asciiDomain = domainToASCII(\"مثال.com\");\n\n    expect(asciiDomain).toBe(\"xn--mgbh0fb.com\");\n  });\n\n  it(\"converts file URL to system path with fileURLToPath\", () => {\n    const url = new URL(\"file:///path/to/file.txt\");\n    const path = fileURLToPath(url);\n\n    expect(path).toBe(\"/path/to/file.txt\"); // Platform specific path handling might differ\n  });\n\n  it(\"converts system path to file URL with pathToFileURL\", () => {\n    if (IS_WINDOWS) {\n      const url = pathToFileURL(\"C:/path/to/file.txt\");\n      expect(url.href).toBe(\"file:///C:/path/to/file.txt\");\n    } else {\n      const url = pathToFileURL(\"/path/to/file.txt\");\n      expect(url.href).toBe(\"file:///path/to/file.txt\"); // Platform specific path handling might differ\n    }\n  });\n\n  it(\"formats URL object into a string with format\", () => {\n    const url = new URL(\"https://a:b@測試?abc#foo\");\n\n    expect(url.href).toBe(\"https://a:b@xn--g6w251d/?abc#foo\");\n\n    expect(format(url, { fragment: false, unicode: true, auth: false })).toBe(\n      \"https://測試/?abc\"\n    );\n  });\n});\n"
  },
  {
    "path": "tests/unit/util.test.ts",
    "content": "import defaultImport from \"node:util\";\nimport legacyImport from \"util\";\n\nimport { EventEmitter } from \"node:events\";\n\nit(\"node:util should be the same as util\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n\nconst { inherits } = defaultImport;\n\ndescribe(\"inherits\", () => {\n  it(\"should be inheritable parent classes\", () => {\n    function MyStream() {\n      EventEmitter.call(this);\n    }\n\n    inherits(MyStream, EventEmitter);\n\n    const stream = new MyStream();\n\n    expect(stream instanceof EventEmitter).toBeTruthy();\n    expect(MyStream.super_).toEqual(EventEmitter);\n  });\n});\n"
  },
  {
    "path": "tests/unit/zlib.test.ts",
    "content": "import defaultImport from \"node:zlib\";\nimport legacyImport from \"zlib\";\n\nconst data = \"Hello LLRT!!\";\n\nit(\"node:zlib should be the same as zlib\", () => {\n  expect(defaultImport).toStrictEqual(legacyImport);\n});\n\nconst {\n  deflate,\n  inflate,\n  deflateSync,\n  inflateSync,\n  deflateRaw,\n  inflateRaw,\n  deflateRawSync,\n  inflateRawSync,\n  gzip,\n  gunzip,\n  gzipSync,\n  gunzipSync,\n  brotliCompress,\n  brotliDecompress,\n  brotliCompressSync,\n  brotliDecompressSync,\n  zstdCompress,\n  zstdDecompress,\n  zstdCompressSync,\n  zstdDecompressSync,\n} = defaultImport;\n\ndescribe(\"deflate/inflate\", () => {\n  it(\"deflate/inflate\", (done) => {\n    deflate(data, (err, compressed) => {\n      inflate(compressed, (err, decompressed) => {\n        expect(data).toEqual(decompressed.toString());\n        done();\n      });\n    });\n  });\n  it(\"deflateSync/inflateSync\", () => {\n    const compressed = deflateSync(data);\n    const decompressed = inflateSync(compressed);\n    expect(data).toEqual(decompressed.toString());\n  });\n});\n\ndescribe(\"deflateRaw/inflateRaw\", () => {\n  it(\"deflateRaw/inflateRaw\", (done) => {\n    deflateRaw(data, (err, compressed) => {\n      inflateRaw(compressed, (err, decompressed) => {\n        expect(data).toEqual(decompressed.toString());\n        done();\n      });\n    });\n  });\n  it(\"deflateRawSync/inflateRawSync\", () => {\n    const compressed = deflateRawSync(data);\n    const decompressed = inflateRawSync(compressed);\n    expect(data).toEqual(decompressed.toString());\n  });\n});\n\ndescribe(\"gzip/gunzip\", () => {\n  it(\"gzip/gunzip\", (done) => {\n    gzip(data, (err, compressed) => {\n      gunzip(compressed, (err, decompressed) => {\n        expect(data).toEqual(decompressed.toString());\n        done();\n      });\n    });\n  });\n  it(\"gzipSync/gunzipSync\", () => {\n    const compressed = gzipSync(data);\n    const decompressed = gunzipSync(compressed);\n    expect(data).toEqual(decompressed.toString());\n  });\n});\n\ndescribe(\"brotli\", () => {\n  it(\"brotliCompress/brotliDecompress\", (done) => {\n    brotliCompress(data, (err, compressed) => {\n      brotliDecompress(compressed, (err, decompressed) => {\n        expect(data).toEqual(decompressed.toString());\n        done();\n      });\n    });\n  });\n  it(\"brotliCompressSync/brotliDecompressSync\", () => {\n    const compressed = brotliCompressSync(data);\n    const decompressed = brotliDecompressSync(compressed);\n    expect(data).toEqual(decompressed.toString());\n  });\n});\n\ndescribe(\"zstandard\", () => {\n  it(\"zstdCompress/zstdDecompress\", (done) => {\n    zstdCompress(data, (err, compressed) => {\n      zstdDecompress(compressed, (err, decompressed) => {\n        expect(data).toEqual(decompressed.toString());\n        done();\n      });\n    });\n  });\n  it(\"zstdCompressSync/zstdDecompressSync\", () => {\n    const compressed = zstdCompressSync(data);\n    const decompressed = zstdDecompressSync(compressed);\n    expect(data).toEqual(decompressed.toString());\n  });\n});\n"
  },
  {
    "path": "tests/wpt/FileAPI/support/Blob.js",
    "content": "export default function (self) {\n  \"use strict\";\n\n  self.test_blob = (fn, expectations) => {\n    var expected = expectations.expected,\n      type = expectations.type,\n      desc = expectations.desc;\n\n    promise_test(async (t) => {\n      var blob = fn();\n      assert_true(blob instanceof Blob);\n      assert_false(blob instanceof File);\n      assert_equals(blob.type, type);\n      assert_equals(blob.size, expected.length);\n\n      const text = await blob.text();\n      assert_equals(text, expected);\n    }, desc);\n  };\n\n  self.test_blob_binary = (fn, expectations) => {\n    var expected = expectations.expected,\n      type = expectations.type,\n      desc = expectations.desc;\n\n    promise_test(async (t) => {\n      var blob = fn();\n      assert_true(blob instanceof Blob);\n      assert_false(blob instanceof File);\n      assert_equals(blob.type, type);\n      assert_equals(blob.size, expected.length);\n\n      const ab = await blob.arrayBuffer();\n      assert_true(ab instanceof ArrayBuffer, \"Result should be an ArrayBuffer\");\n      assert_array_equals(new Uint8Array(ab), expected);\n    }, desc);\n  };\n\n  // Assert that two TypedArray objects have the same byte values\n  self.assert_equals_typed_array = (array1, array2) => {\n    const [view1, view2] = [array1, array2].map((array) => {\n      self.assert_true(\n        array.buffer instanceof ArrayBuffer,\n        \"Expect input ArrayBuffers to contain field `buffer`\"\n      );\n      return new DataView(array.buffer, array.byteOffset, array.byteLength);\n    });\n\n    self.assert_equals(\n      view1.byteLength,\n      view2.byteLength,\n      \"Expect both arrays to be of the same byte length\"\n    );\n\n    const byteLength = view1.byteLength;\n\n    for (let i = 0; i < byteLength; ++i) {\n      self.assert_equals(\n        view1.getUint8(i),\n        view2.getUint8(i),\n        `Expect byte at buffer position ${i} to be equal`\n      );\n    }\n  };\n}\n"
  },
  {
    "path": "tests/wpt/FileAPI/support/send-file-formdata-helper.js",
    "content": "export default function (self) {\n  \"use strict\";\n\n  const kTestChars = \"ABC~‾¥≈¤･・•∙·☼★星🌟星★☼·∙•・･¤≈¥‾~XYZ\";\n\n  // formDataPostFileUploadTest - verifies multipart upload structure and\n  // numeric character reference replacement for filenames, field names,\n  // and field values using FormData and fetch().\n  //\n  // Uses /fetch/api/resources/echo-content.py to echo the upload\n  // POST (unlike in send-file-form-helper.js, here we expect all\n  // multipart/form-data request bodies to be UTF-8, so we don't need to\n  // escape controls and non-ASCII bytes).\n  //\n  // Fields in the parameter object:\n  //\n  // - fileNameSource: purely explanatory and gives a clue about which\n  //   character encoding is the source for the non-7-bit-ASCII parts of\n  //   the fileBaseName, or Unicode if no smaller-than-Unicode source\n  //   contains all the characters. Used in the test name.\n  // - fileBaseName: the not-necessarily-just-7-bit-ASCII file basename\n  //   used for the constructed test file. Used in the test name.\n  const formDataPostFileUploadTest = ({ fileNameSource, fileBaseName }) => {\n    promise_test(async (testCase) => {\n      const formData = new FormData();\n      let file = new Blob([kTestChars], { type: \"text/plain\" });\n      try {\n        // Switch to File in browsers that allow this\n        file = new File([file], fileBaseName, { type: file.type });\n      } catch (ignoredException) {}\n\n      // Used to verify that the browser agrees with the test about\n      // field value replacement and encoding independently of file system\n      // idiosyncracies.\n      formData.append(\"filename\", fileBaseName);\n\n      // Same, but with name and value reversed to ensure field names\n      // get the same treatment.\n      formData.append(fileBaseName, \"filename\");\n\n      formData.append(\"file\", file, fileBaseName);\n\n      const formDataText = await (\n        await fetch(`/fetch/api/resources/echo-content.py`, {\n          method: \"POST\",\n          body: formData,\n        })\n      ).text();\n      const formDataLines = formDataText.split(\"\\r\\n\");\n      if (formDataLines.length && !formDataLines[formDataLines.length - 1]) {\n        --formDataLines.length;\n      }\n      assert_greater_than(\n        formDataLines.length,\n        2,\n        `${fileBaseName}: multipart form data must have at least 3 lines: ${JSON.stringify(\n          formDataText\n        )}`\n      );\n      const boundary = formDataLines[0];\n      assert_equals(\n        formDataLines[formDataLines.length - 1],\n        boundary + \"--\",\n        `${fileBaseName}: multipart form data must end with ${boundary}--: ${JSON.stringify(\n          formDataText\n        )}`\n      );\n\n      const asValue = fileBaseName.replace(/\\r\\n?|\\n/g, \"\\r\\n\");\n      const asName = asValue.replace(/[\\r\\n\"]/g, encodeURIComponent);\n      const asFilename = fileBaseName.replace(/[\\r\\n\"]/g, encodeURIComponent);\n      const expectedText = [\n        boundary,\n        'Content-Disposition: form-data; name=\"filename\"',\n        \"\",\n        asValue,\n        boundary,\n        `Content-Disposition: form-data; name=\"${asName}\"`,\n        \"\",\n        \"filename\",\n        boundary,\n        `Content-Disposition: form-data; name=\"file\"; ` +\n          `filename=\"${asFilename}\"`,\n        \"Content-Type: text/plain\",\n        \"\",\n        kTestChars,\n        boundary + \"--\",\n      ].join(\"\\r\\n\");\n\n      assert_true(\n        formDataText.startsWith(expectedText),\n        `Unexpected multipart-shaped form data received:\\n${formDataText}\\nExpected:\\n${expectedText}`\n      );\n    }, `Upload ${fileBaseName} (${fileNameSource}) in fetch with FormData`);\n  };\n  self.formDataPostFileUploadTest = formDataPostFileUploadTest;\n}\n"
  },
  {
    "path": "tests/wpt/FileAPI.blob.test.ts",
    "content": "import { runTestDynamic } from \"./FileAPI.harness.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst SKIP_FILES = [\n  \"Blob-constructor.any.js\", // ReferenceError: promise_test is not defined\n  \"Blob-slice.any.js\", // ReferenceError: promise_test is not defined\n];\n\nconst __filename = fileURLToPath(import.meta.url);\nconst basename = path.basename(__filename);\nconst subDir = basename\n  .replace(/\\.test\\.[jt]s$/, \"\")\n  .split(\".\")\n  .join(path.sep);\n\nconst CWD = process.cwd();\nconst baseDir = path.join(CWD, \"wpt\");\nconst targetDir = path.join(baseDir, subDir);\n\nconst testFiles = fs\n  .readdirSync(targetDir)\n  .filter((file) => file.endsWith(\".any.js\"));\n\ndescribe(subDir, () => {\n  for (const file of testFiles) {\n    if (!SKIP_FILES.includes(file)) {\n      it(`should pass ${file} tests`, (done) => {\n        const filePath = path.join(targetDir, file);\n        const sourceCode = fs.readFileSync(filePath, \"utf8\");\n        runTestDynamic(sourceCode, done);\n      });\n    }\n  }\n});\n"
  },
  {
    "path": "tests/wpt/FileAPI.file.test.ts",
    "content": "import { runTestDynamic } from \"./FileAPI.harness.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst SKIP_FILES = [\n  \"send-file-formdata-controls.any.js\", // ReferenceError: promise_test is not defined\n  \"send-file-formdata-punctuation.any.js\", // ReferenceError: promise_test is not defined\n  \"send-file-formdata-utf-8.any.js\", // ReferenceError: promise_test is not defined\n  \"send-file-formdata.any.js\", // ReferenceError: promise_test is not defined\n];\n\nconst __filename = fileURLToPath(import.meta.url);\nconst basename = path.basename(__filename);\nconst subDir = basename\n  .replace(/\\.test\\.[jt]s$/, \"\")\n  .split(\".\")\n  .join(path.sep);\n\nconst CWD = process.cwd();\nconst baseDir = path.join(CWD, \"wpt\");\nconst targetDir = path.join(baseDir, subDir);\n\nconst testFiles = fs\n  .readdirSync(targetDir)\n  .filter((file) => file.endsWith(\".any.js\"));\n\ndescribe(subDir, () => {\n  for (const file of testFiles) {\n    if (!SKIP_FILES.includes(file)) {\n      it(`should pass ${file} tests`, (done) => {\n        const filePath = path.join(targetDir, file);\n        const sourceCode = fs.readFileSync(filePath, \"utf8\");\n        runTestDynamic(sourceCode, done);\n      });\n    }\n  }\n});\n"
  },
  {
    "path": "tests/wpt/FileAPI.harness.js",
    "content": "import resourcesIdlharness from \"./resources/idlharness.js\";\nimport resourcesTestharness from \"./resources/testharness.js\";\n\nimport commonGc from \"./common/gc.js\";\nimport commonSubsetTests from \"./common/subset-tests.js\";\n\nimport encodings from \"./encoding/resources/encodings.js\";\n\nimport fileApiBlob from \"./FileAPI/support/Blob.js\";\nimport sendFileFormdataHelper from \"./FileAPI/support/send-file-formdata-helper.js\";\n\nexport const runTestDynamic = (testSource, done) => {\n  const context = {\n    createBuffer: (type, length) => new self[type](length),\n    encodings_table: encodings,\n    setTimeout: setTimeout,\n    DOMException: DOMException,\n    location: {},\n  };\n\n  resourcesIdlharness(context);\n  resourcesTestharness(context);\n\n  commonGc(context);\n  commonSubsetTests(context);\n\n  fileApiBlob(context);\n  sendFileFormdataHelper(context);\n\n  context.setup({\n    explicit_done: true,\n    debug: process.env.DEBUG !== undefined,\n  });\n\n  globalThis.gc = globalThis.__gc;\n\n  context.add_completion_callback((tests, status, assertions) => {\n    if (\n      tests.filter(\n        ({ name, status }) => !(name === \"Loading data...\" && status === 0)\n      ).length === 0\n    ) {\n      done(new Error(\"No tests were executed!\"));\n    }\n    const failure = tests.find((test) => test.status !== 0);\n    if (failure) {\n      const message = `[${failure.name}] ${failure.message || String(failure)}`;\n      done(message);\n      return;\n    }\n    done();\n  });\n\n  wrapTestSuite(testSource)(context);\n\n  context.done();\n};\n\nfunction wrapTestSuite(sourceCode) {\n  return new Function(\n    \"context\",\n    `\n      with (context) {\n        ${sourceCode}\n      }\n    `\n  );\n}\n"
  },
  {
    "path": "tests/wpt/README.md",
    "content": "## web-platform-tests\n\nA subset of the [web-platform-tests](https://github.com/web-platform-tests/wpt)\nare executed against modules that should provide compatibility with existing\nstandards such as the [WHATWG URL standard](https://url.spec.whatwg.org/) for\n`URL` and `URLSearchParams`.\n\n### Running WPTs\n\nLLRT includes built-in support for running web-platform-tests using a simplified workflow. To get started:\n\n1. **Change sparse-checkout mode** (only once)\n\n```sh\ngit sparse-checkout init --no-cone\n```\n\n2. **Update sparse-checkout information** (only once)\n\n```sh\nmake init-wpt\n```\n\n3. **Load as a submodule** (only once)\n\n```sh\ngit submodule add --force -b master https://github.com/web-platform-tests/wpt wpt\n```\n\n4. **Update the local revision** (when the remote is updated)\n\n```sh\nmake update-wpt\n```\n\n5. **Run the WPT server**\n\n```sh\n./wpt/wpt serve\n```\n\n> [!IMPORTANT]\n> The first time you do this, you will need to add the hostname required by wpt to hosts. For more information, please refer to the URL below.\n> https://web-platform-tests.org/running-tests/from-local-system.html#hosts-file-setup\n\n6. **Run the WPTs**\n\n```sh\nmake test-wpt\n```\n\n7. **Organizing the results of the WPT**\n\n```sh\nmake tidyup-wpt\n```\n"
  },
  {
    "path": "tests/wpt/WebCryptoAPI.derive_bits_keys.test.ts",
    "content": "import { runTestDynamic } from \"./WebCryptoAPI.harness.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst SKIP_FILES = [\n  \"argon2.tentative.https.any.js\", // ReferenceError: define_tests is not defined\n  \"cfrg_curves_bits_curve25519.https.any.js\", // ReferenceError: define_tests_25519 is not defined\n  \"cfrg_curves_bits_curve448.https.any.js\", // ReferenceError: define_tests_448 is not defined\n  \"cfrg_curves_bits_curve448.tentative.https.any.js\", // ReferenceError: define_tests_448 is not defined\n  \"cfrg_curves_keys_curve25519.https.any.js\", // ReferenceError: define_tests_25519 is not defined\n  \"cfrg_curves_keys_curve448.https.any.js\", // ReferenceError: define_tests_448 is not defined\n  \"cfrg_curves_keys_curve448.tentative.https.any.js\", // ReferenceError: define_tests_448 is not defined\n  \"derive_key_and_encrypt.https.any.js\", // ReferenceError: define_tests is not defined\n  \"derived_bits_length.https.any.js\", // ReferenceError: define_tests is not defined\n  \"ecdh_bits.https.any.js\", // ReferenceError: define_tests is not defined\n  \"ecdh_keys.https.any.js\", // ReferenceError: define_tests is not defined\n  \"hkdf.https.any.js\", // ReferenceError: define_tests is not defined\n  \"pbkdf2.https.any.js\", // ReferenceError: define_tests is not defined\n];\n\nconst __filename = fileURLToPath(import.meta.url);\nconst basename = path.basename(__filename);\nconst subDir = basename\n  .replace(/\\.test\\.[jt]s$/, \"\")\n  .split(\".\")\n  .join(path.sep);\n\nconst CWD = process.cwd();\nconst baseDir = path.join(CWD, \"wpt\");\nconst targetDir = path.join(baseDir, subDir);\n\nconst testFiles = fs\n  .readdirSync(targetDir)\n  .filter((file) => file.endsWith(\".any.js\"));\n\ndescribe(subDir, () => {\n  for (const file of testFiles) {\n    if (!SKIP_FILES.includes(file)) {\n      it(`should pass ${file} tests`, (done) => {\n        const filePath = path.join(targetDir, file);\n        const sourceCode = fs.readFileSync(filePath, \"utf8\");\n        runTestDynamic(sourceCode, done);\n      });\n    }\n  }\n});\n"
  },
  {
    "path": "tests/wpt/WebCryptoAPI.digest.test.ts",
    "content": "import { runTestDynamic } from \"./WebCryptoAPI.harness.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst SKIP_FILES = [];\n\nconst __filename = fileURLToPath(import.meta.url);\nconst basename = path.basename(__filename);\nconst subDir = basename\n  .replace(/\\.test\\.[jt]s$/, \"\")\n  .split(\".\")\n  .join(path.sep);\n\nconst CWD = process.cwd();\nconst baseDir = path.join(CWD, \"wpt\");\nconst targetDir = path.join(baseDir, subDir);\n\nconst testFiles = fs\n  .readdirSync(targetDir)\n  .filter((file) => file.endsWith(\".any.js\"));\n\ndescribe(subDir, () => {\n  for (const file of testFiles) {\n    if (!SKIP_FILES.includes(file)) {\n      it(`should pass ${file} tests`, (done) => {\n        const filePath = path.join(targetDir, file);\n        const sourceCode = fs.readFileSync(filePath, \"utf8\");\n        runTestDynamic(sourceCode, done);\n      });\n    }\n  }\n});\n"
  },
  {
    "path": "tests/wpt/WebCryptoAPI.harness.js",
    "content": "import encodings from \"./encoding/resources/encodings.js\";\n\nimport commonGc from \"./common/gc.js\";\nimport commonSubsetTests from \"./common/subset-tests.js\";\n\nimport resourcesIdlharness from \"./resources/idlharness.js\";\nimport resourcesTestharness from \"./resources/testharness.js\";\n\nimport encodingDecodingHelpers from \"./encoding/resources/decoding-helpers.js\";\n\nexport const runTest = (test, done) => {\n  //\n  // Set up the test harness\n  //\n\n  // Create a new test context\n  const context = {\n    // The test harness uses common/sab.js which uses WebAssembly which doesn't\n    // work, so we can just create buffers the usual way\n    createBuffer: (type, length) => new self[type](length),\n    encodings_table: encodings,\n    setTimeout: setTimeout,\n    DOMException: DOMException,\n    // Some tests require location to be defined\n    location: {},\n  };\n\n  // Initialize the test harness in the context\n  commonGc(context);\n  commonSubsetTests(context);\n\n  resourcesIdlharness(context);\n  resourcesTestharness(context);\n\n  encodingDecodingHelpers(context);\n\n  // Configure the test harness\n  context.setup({\n    explicit_done: true,\n    debug: process.env.DEBUG !== undefined,\n  });\n\n  globalThis.gc = globalThis.__gc;\n\n  context.add_completion_callback((tests, status, assertions) => {\n    // Check that tests were actually executed not including the optional step\n    // that loads test data\n    if (\n      tests.filter(\n        ({ name, status }) => !(name === \"Loading data...\" && status === 0)\n      ).length === 0\n    ) {\n      done(new Error(\"No tests were executed!\"));\n    }\n    const failure = tests.find((test) => test.status !== 0);\n    if (failure) {\n      const message = `[${failure.name}] ${failure.message || String(failure)}`;\n      done(message);\n      return;\n    }\n    done();\n  });\n\n  test(context);\n\n  context.done();\n};\n\nexport const runTestDynamic = (testSource, done) => {\n  const context = {\n    createBuffer: (type, length) => new self[type](length),\n    encodings_table: encodings,\n    setTimeout: setTimeout,\n    DOMException: DOMException,\n    location: {},\n  };\n\n  commonGc(context);\n  commonSubsetTests(context);\n\n  resourcesIdlharness(context);\n  resourcesTestharness(context);\n\n  encodingDecodingHelpers(context);\n\n  context.setup({\n    explicit_done: true,\n    debug: process.env.DEBUG !== undefined,\n  });\n\n  globalThis.gc = globalThis.__gc;\n\n  context.add_completion_callback((tests, status, assertions) => {\n    if (\n      tests.filter(\n        ({ name, status }) => !(name === \"Loading data...\" && status === 0)\n      ).length === 0\n    ) {\n      done(new Error(\"No tests were executed!\"));\n    }\n    const failure = tests.find((test) => test.status !== 0);\n    if (failure) {\n      const message = `[${failure.name}] ${failure.message || String(failure)}`;\n      done(message);\n      return;\n    }\n    done();\n  });\n\n  wrapTestSuite(testSource)(context);\n\n  context.done();\n};\n\nfunction wrapTestSuite(sourceCode) {\n  return new Function(\n    \"context\",\n    `\n      with (context) {\n        ${sourceCode}\n      }\n    `\n  );\n}\n"
  },
  {
    "path": "tests/wpt/WebCryptoAPI.test.ts",
    "content": "import { runTestDynamic } from \"./WebCryptoAPI.harness.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst SKIP_FILES = [\n  \"getRandomValues.any.js\", // It's Slowly...\n  \"idlharness.https.any.js\", // ReferenceError: idl_test is not defined\n];\n\nconst __filename = fileURLToPath(import.meta.url);\nconst basename = path.basename(__filename);\nconst subDir = basename\n  .replace(/\\.test\\.[jt]s$/, \"\")\n  .split(\".\")\n  .join(path.sep);\n\nconst CWD = process.cwd();\nconst baseDir = path.join(CWD, \"wpt\");\nconst targetDir = path.join(baseDir, subDir);\n\nconst testFiles = fs\n  .readdirSync(targetDir)\n  .filter((file) => file.endsWith(\".any.js\"));\n\ndescribe(subDir, () => {\n  for (const file of testFiles) {\n    if (!SKIP_FILES.includes(file)) {\n      it(`should pass ${file} tests`, (done) => {\n        const filePath = path.join(targetDir, file);\n        const sourceCode = fs.readFileSync(filePath, \"utf8\");\n        runTestDynamic(sourceCode, done);\n      });\n    }\n  }\n});\n"
  },
  {
    "path": "tests/wpt/common/gc.js",
    "content": "export default function ({}) {\n/**\n * Does a best-effort attempt at invoking garbage collection. Attempts to use\n * the standardized `TestUtils.gc()` function, but falls back to other\n * environment-specific nonstandard functions, with a final result of just\n * creating a lot of garbage (in which case you will get a console warning).\n *\n * This should generally only be used to attempt to trigger bugs and crashes\n * inside tests, i.e. cases where if garbage collection happened, then this\n * should not trigger some misbehavior. You cannot rely on garbage collection\n * successfully trigger, or that any particular unreachable object will be\n * collected.\n *\n * @returns {Promise<undefined>} A promise you should await to ensure garbage\n * collection has had a chance to complete.\n */\nself.garbageCollect = async () => {\n  // https://testutils.spec.whatwg.org/#the-testutils-namespace\n  if (self.TestUtils?.gc) {\n    return TestUtils.gc();\n  }\n\n  // Use --expose_gc for V8 (and Node.js)\n  // to pass this flag at chrome launch use: --js-flags=\"--expose-gc\"\n  // Exposed in SpiderMonkey shell as well\n  if (self.gc) {\n    return self.gc();\n  }\n\n  // Present in some WebKit development environments\n  if (self.GCController) {\n    return GCController.collect();\n  }\n\n  console.warn(\n    \"Tests are running without the ability to do manual garbage collection. \" +\n      \"They will still work, but coverage will be suboptimal.\"\n  );\n\n  for (var i = 0; i < 1000; i++) {\n    gcRec(10);\n  }\n\n  function gcRec(n) {\n    if (n < 1) {\n      return {};\n    }\n\n    let temp = { i: \"ab\" + i + i / 100000 };\n    temp += \"foo\";\n\n    gcRec(n - 1);\n  }\n};\n}\n"
  },
  {
    "path": "tests/wpt/common/get-host-info.sub.js",
    "content": "export default function (self) {\n  (function () {\n    /**\n     * Host information for cross-origin tests.\n     * @returns {Object} with properties for different host information.\n     */\n    function get_host_info() {\n      var HTTP_PORT = \"{{ports[http][0]}}\";\n      var HTTP_PORT2 = \"{{ports[http][1]}}\";\n      var HTTPS_PORT = \"{{ports[https][0]}}\";\n      var HTTPS_PORT2 = \"{{ports[https][1]}}\";\n      var PROTOCOL = self.location.protocol;\n      var IS_HTTPS = PROTOCOL == \"https:\";\n      var PORT = IS_HTTPS ? HTTPS_PORT : HTTP_PORT;\n      var PORT2 = IS_HTTPS ? HTTPS_PORT2 : HTTP_PORT2;\n      var HTTP_PORT_ELIDED = HTTP_PORT == \"80\" ? \"\" : \":\" + HTTP_PORT;\n      var HTTP_PORT2_ELIDED = HTTP_PORT2 == \"80\" ? \"\" : \":\" + HTTP_PORT2;\n      var HTTPS_PORT_ELIDED = HTTPS_PORT == \"443\" ? \"\" : \":\" + HTTPS_PORT;\n      var PORT_ELIDED = IS_HTTPS ? HTTPS_PORT_ELIDED : HTTP_PORT_ELIDED;\n      var ORIGINAL_HOST = \"{{host}}\";\n      var REMOTE_HOST =\n        ORIGINAL_HOST === \"localhost\" ? \"127.0.0.1\" : \"www1.\" + ORIGINAL_HOST;\n      var OTHER_HOST = \"{{domains[www2]}}\";\n      var NOTSAMESITE_HOST =\n        ORIGINAL_HOST === \"localhost\" ? \"127.0.0.1\" : \"{{hosts[alt][]}}\";\n\n      return {\n        HTTP_PORT: HTTP_PORT,\n        HTTP_PORT2: HTTP_PORT2,\n        HTTPS_PORT: HTTPS_PORT,\n        HTTPS_PORT2: HTTPS_PORT2,\n        PORT: PORT,\n        PORT2: PORT2,\n        ORIGINAL_HOST: ORIGINAL_HOST,\n        REMOTE_HOST: REMOTE_HOST,\n        NOTSAMESITE_HOST,\n\n        ORIGIN: PROTOCOL + \"//\" + ORIGINAL_HOST + PORT_ELIDED,\n        HTTP_ORIGIN: \"http://\" + ORIGINAL_HOST + HTTP_PORT_ELIDED,\n        HTTPS_ORIGIN: \"https://\" + ORIGINAL_HOST + HTTPS_PORT_ELIDED,\n        HTTPS_ORIGIN_WITH_CREDS:\n          \"https://foo:bar@\" + ORIGINAL_HOST + HTTPS_PORT_ELIDED,\n        HTTP_ORIGIN_WITH_DIFFERENT_PORT:\n          \"http://\" + ORIGINAL_HOST + HTTP_PORT2_ELIDED,\n        REMOTE_ORIGIN: PROTOCOL + \"//\" + REMOTE_HOST + PORT_ELIDED,\n        OTHER_ORIGIN: PROTOCOL + \"//\" + OTHER_HOST + PORT_ELIDED,\n        HTTP_REMOTE_ORIGIN: \"http://\" + REMOTE_HOST + HTTP_PORT_ELIDED,\n        HTTP_NOTSAMESITE_ORIGIN:\n          \"http://\" + NOTSAMESITE_HOST + HTTP_PORT_ELIDED,\n        HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT:\n          \"http://\" + REMOTE_HOST + HTTP_PORT2_ELIDED,\n        HTTPS_REMOTE_ORIGIN: \"https://\" + REMOTE_HOST + HTTPS_PORT_ELIDED,\n        HTTPS_REMOTE_ORIGIN_WITH_CREDS:\n          \"https://foo:bar@\" + REMOTE_HOST + HTTPS_PORT_ELIDED,\n        HTTPS_NOTSAMESITE_ORIGIN:\n          \"https://\" + NOTSAMESITE_HOST + HTTPS_PORT_ELIDED,\n        UNAUTHENTICATED_ORIGIN: \"http://\" + OTHER_HOST + HTTP_PORT_ELIDED,\n        AUTHENTICATED_ORIGIN: \"https://\" + OTHER_HOST + HTTPS_PORT_ELIDED,\n      };\n    }\n\n    /**\n     * When a default port is used, location.port returns the empty string.\n     * This function attempts to provide an exact port, assuming we are running under wptserve.\n     * @param {*} loc - can be Location/<a>/<area>/URL, but assumes http/https only.\n     * @returns {string} The port number.\n     */\n    function get_port(loc) {\n      if (loc.port) {\n        return loc.port;\n      }\n      return loc.protocol === \"https:\" ? \"443\" : \"80\";\n    }\n    self.get_host_info = get_host_info;\n    self.get_port = get_port;\n  })();\n}\n"
  },
  {
    "path": "tests/wpt/common/subset-tests.js",
    "content": "export default function (self) {\nconst location = self.location;\n\n(function () {\n  var subTestStart = 0;\n  var subTestEnd = Infinity;\n  var match;\n  if (location.search) {\n    match = /(?:^\\?|&)(\\d+)-(\\d+|last)(?:&|$)/.exec(location.search);\n    if (match) {\n      subTestStart = parseInt(match[1], 10);\n      if (match[2] !== \"last\") {\n        subTestEnd = parseInt(match[2], 10);\n      }\n    }\n    // Below is utility code to generate <meta> for copy/paste into tests.\n    // Sample usage:\n    // test.html?split=1000\n    match = /(?:^\\?|&)split=(\\d+)(?:&|$)/.exec(location.search);\n    if (match) {\n      var testsPerVariant = parseInt(match[1], 10);\n      add_completion_callback((tests) => {\n        var total = tests.length;\n        var template = '<meta name=\"variant\" content=\"?%s-%s\">';\n        var metas = [];\n        for (\n          var i = 1;\n          i < total - testsPerVariant;\n          i = i + testsPerVariant\n        ) {\n          metas.push(\n            template.replace(\"%s\", i).replace(\"%s\", i + testsPerVariant - 1)\n          );\n        }\n        metas.push(template.replace(\"%s\", i).replace(\"%s\", \"last\"));\n        var pre = document.createElement(\"pre\");\n        pre.textContent = metas.join(\"\\n\");\n        document.body.insertBefore(pre, document.body.firstChild);\n        document.getSelection().selectAllChildren(pre);\n      });\n    }\n  }\n  /**\n   * Check if `currentSubTest` is in the subset specified in the URL.\n   * @param {number} currentSubTest\n   * @returns {boolean}\n   */\n  function shouldRunSubTest(currentSubTest) {\n    return currentSubTest >= subTestStart && currentSubTest <= subTestEnd;\n  }\n  var currentSubTest = 0;\n  /**\n   * Only test a subset of tests with, e.g., `?1-10` in the URL.\n   * Can be used together with `<meta name=\"variant\" content=\"...\">`\n   * Sample usage:\n   * for (const test of tests) {\n   *   subsetTest(async_test, test.fn, test.name);\n   * }\n   */\n  function subsetTest(testFunc, ...args) {\n    currentSubTest++;\n    if (shouldRunSubTest(currentSubTest)) {\n      return testFunc(...args);\n    }\n    return null;\n  }\n  self.shouldRunSubTest = shouldRunSubTest;\n  self.subsetTest = subsetTest;\n})();\n}\n"
  },
  {
    "path": "tests/wpt/console.harness.js",
    "content": "import resourcesIdlharness from \"./resources/idlharness.js\";\nimport resourcesTestharness from \"./resources/testharness.js\";\n\nimport commonGc from \"./common/gc.js\";\nimport commonSubsetTests from \"./common/subset-tests.js\";\n\nimport encodings from \"./encoding/resources/encodings.js\";\n\nexport const runTestDynamic = (testSource, done) => {\n  const context = {\n    createBuffer: (type, length) => new self[type](length),\n    encodings_table: encodings,\n    setTimeout: setTimeout,\n    DOMException: DOMException,\n    location: {},\n  };\n\n  resourcesIdlharness(context);\n  resourcesTestharness(context);\n\n  commonGc(context);\n  commonSubsetTests(context);\n\n  context.setup({\n    explicit_done: true,\n    debug: process.env.DEBUG !== undefined,\n  });\n\n  globalThis.gc = globalThis.__gc;\n\n  context.add_completion_callback((tests, status, assertions) => {\n    if (\n      tests.filter(\n        ({ name, status }) => !(name === \"Loading data...\" && status === 0)\n      ).length === 0\n    ) {\n      done(new Error(\"No tests were executed!\"));\n    }\n    const failure = tests.find((test) => test.status !== 0);\n    if (failure) {\n      const message = `[${failure.name}] ${failure.message || String(failure)}`;\n      done(message);\n      return;\n    }\n    done();\n  });\n\n  wrapTestSuite(testSource)(context);\n\n  context.done();\n};\n\nfunction wrapTestSuite(sourceCode) {\n  return new Function(\n    \"context\",\n    `\n      with (context) {\n        ${sourceCode}\n      }\n    `\n  );\n}\n"
  },
  {
    "path": "tests/wpt/console.test.ts",
    "content": "import { runTestDynamic } from \"./console.harness.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst SKIP_FILES = [\n  \"console-log-symbol.any.js\", // Error: Test timed out after 5000ms\n  \"idlharness.any.js\", // ReferenceError: idl_test is not defined\n];\n\nconst __filename = fileURLToPath(import.meta.url);\nconst basename = path.basename(__filename);\nconst subDir = basename\n  .replace(/\\.test\\.[jt]s$/, \"\")\n  .split(\".\")\n  .join(path.sep);\n\nconst CWD = process.cwd();\nconst baseDir = path.join(CWD, \"wpt\");\nconst targetDir = path.join(baseDir, subDir);\n\nconst testFiles = fs\n  .readdirSync(targetDir)\n  .filter((file) => file.endsWith(\".any.js\"));\n\ndescribe(subDir, () => {\n  for (const file of testFiles) {\n    if (!SKIP_FILES.includes(file)) {\n      it(`should pass ${file} tests`, (done) => {\n        const filePath = path.join(targetDir, file);\n        const sourceCode = fs.readFileSync(filePath, \"utf8\");\n        runTestDynamic(sourceCode, done);\n      });\n    }\n  }\n});\n"
  },
  {
    "path": "tests/wpt/encoding/resources/decoding-helpers.js",
    "content": "export default function (self) {\n  // Decode an URL encoded string, using XHR and data: URL. Returns a Promise.\n  function decode(label, url_encoded_string) {\n    return new Promise((resolve, reject) => {\n      const req = new XMLHttpRequest();\n      req.open(\"GET\", `data:text/plain,${url_encoded_string}`);\n      req.overrideMimeType(`text/plain; charset=\"${label}\"`);\n      req.send();\n      req.onload = () => resolve(req.responseText);\n      req.onerror = () => reject(new Error(req.statusText));\n    });\n  }\n\n  // Convert code units in a decoded string into: \"U+0001/U+0002/...'\n  function to_code_units(string) {\n    return string\n      .split(\"\")\n      .map((unit) => unit.charCodeAt(0))\n      .map(\n        (code) => \"U+\" + (\"0000\" + code.toString(16).toUpperCase()).slice(-4)\n      )\n      .join(\"/\");\n  }\n\n  function decode_test(\n    label,\n    url_encoded_input,\n    expected_code_units,\n    description\n  ) {\n    promise_test(() => {\n      return decode(label, url_encoded_input)\n        .then((decoded) => to_code_units(decoded))\n        .then((actual) => {\n          assert_equals(actual, expected_code_units, `Decoding with ${label}`);\n        });\n    }, description);\n  }\n\n  self.decode_test = decode_test;\n}\n"
  },
  {
    "path": "tests/wpt/encoding/resources/encodings.js",
    "content": "// Straight from https://encoding.spec.whatwg.org/encodings.json\nconst encodings_table =\n[\n  {\n    \"encodings\": [\n      {\n        \"labels\": [\n          \"unicode-1-1-utf-8\",\n          \"unicode11utf8\",\n          \"unicode20utf8\",\n          \"utf-8\",\n          \"utf8\",\n          \"x-unicode20utf8\"\n        ],\n        \"name\": \"UTF-8\"\n      }\n    ],\n    \"heading\": \"The Encoding\"\n  },\n  {\n    \"encodings\": [\n      // {\n      //   \"labels\": [\n      //     \"866\",\n      //     \"cp866\",\n      //     \"csibm866\",\n      //     \"ibm866\"\n      //   ],\n      //   \"name\": \"IBM866\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"csisolatin2\",\n      //     \"iso-8859-2\",\n      //     \"iso-ir-101\",\n      //     \"iso8859-2\",\n      //     \"iso88592\",\n      //     \"iso_8859-2\",\n      //     \"iso_8859-2:1987\",\n      //     \"l2\",\n      //     \"latin2\"\n      //   ],\n      //   \"name\": \"ISO-8859-2\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"csisolatin3\",\n      //     \"iso-8859-3\",\n      //     \"iso-ir-109\",\n      //     \"iso8859-3\",\n      //     \"iso88593\",\n      //     \"iso_8859-3\",\n      //     \"iso_8859-3:1988\",\n      //     \"l3\",\n      //     \"latin3\"\n      //   ],\n      //   \"name\": \"ISO-8859-3\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"csisolatin4\",\n      //     \"iso-8859-4\",\n      //     \"iso-ir-110\",\n      //     \"iso8859-4\",\n      //     \"iso88594\",\n      //     \"iso_8859-4\",\n      //     \"iso_8859-4:1988\",\n      //     \"l4\",\n      //     \"latin4\"\n      //   ],\n      //   \"name\": \"ISO-8859-4\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"csisolatincyrillic\",\n      //     \"cyrillic\",\n      //     \"iso-8859-5\",\n      //     \"iso-ir-144\",\n      //     \"iso8859-5\",\n      //     \"iso88595\",\n      //     \"iso_8859-5\",\n      //     \"iso_8859-5:1988\"\n      //   ],\n      //   \"name\": \"ISO-8859-5\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"arabic\",\n      //     \"asmo-708\",\n      //     \"csiso88596e\",\n      //     \"csiso88596i\",\n      //     \"csisolatinarabic\",\n      //     \"ecma-114\",\n      //     \"iso-8859-6\",\n      //     \"iso-8859-6-e\",\n      //     \"iso-8859-6-i\",\n      //     \"iso-ir-127\",\n      //     \"iso8859-6\",\n      //     \"iso88596\",\n      //     \"iso_8859-6\",\n      //     \"iso_8859-6:1987\"\n      //   ],\n      //   \"name\": \"ISO-8859-6\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"csisolatingreek\",\n      //     \"ecma-118\",\n      //     \"elot_928\",\n      //     \"greek\",\n      //     \"greek8\",\n      //     \"iso-8859-7\",\n      //     \"iso-ir-126\",\n      //     \"iso8859-7\",\n      //     \"iso88597\",\n      //     \"iso_8859-7\",\n      //     \"iso_8859-7:1987\",\n      //     \"sun_eu_greek\"\n      //   ],\n      //   \"name\": \"ISO-8859-7\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"csiso88598e\",\n      //     \"csisolatinhebrew\",\n      //     \"hebrew\",\n      //     \"iso-8859-8\",\n      //     \"iso-8859-8-e\",\n      //     \"iso-ir-138\",\n      //     \"iso8859-8\",\n      //     \"iso88598\",\n      //     \"iso_8859-8\",\n      //     \"iso_8859-8:1988\",\n      //     \"visual\"\n      //   ],\n      //   \"name\": \"ISO-8859-8\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"csiso88598i\",\n      //     \"iso-8859-8-i\",\n      //     \"logical\"\n      //   ],\n      //   \"name\": \"ISO-8859-8-I\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"csisolatin6\",\n      //     \"iso-8859-10\",\n      //     \"iso-ir-157\",\n      //     \"iso8859-10\",\n      //     \"iso885910\",\n      //     \"l6\",\n      //     \"latin6\"\n      //   ],\n      //   \"name\": \"ISO-8859-10\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"iso-8859-13\",\n      //     \"iso8859-13\",\n      //     \"iso885913\"\n      //   ],\n      //   \"name\": \"ISO-8859-13\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"iso-8859-14\",\n      //     \"iso8859-14\",\n      //     \"iso885914\"\n      //   ],\n      //   \"name\": \"ISO-8859-14\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"csisolatin9\",\n      //     \"iso-8859-15\",\n      //     \"iso8859-15\",\n      //     \"iso885915\",\n      //     \"iso_8859-15\",\n      //     \"l9\"\n      //   ],\n      //   \"name\": \"ISO-8859-15\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"iso-8859-16\"\n      //   ],\n      //   \"name\": \"ISO-8859-16\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"cskoi8r\",\n      //     \"koi\",\n      //     \"koi8\",\n      //     \"koi8-r\",\n      //     \"koi8_r\"\n      //   ],\n      //   \"name\": \"KOI8-R\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"koi8-ru\",\n      //     \"koi8-u\"\n      //   ],\n      //   \"name\": \"KOI8-U\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"csmacintosh\",\n      //     \"mac\",\n      //     \"macintosh\",\n      //     \"x-mac-roman\"\n      //   ],\n      //   \"name\": \"macintosh\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"dos-874\",\n      //     \"iso-8859-11\",\n      //     \"iso8859-11\",\n      //     \"iso885911\",\n      //     \"tis-620\",\n      //     \"windows-874\"\n      //   ],\n      //   \"name\": \"windows-874\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"cp1250\",\n      //     \"windows-1250\",\n      //     \"x-cp1250\"\n      //   ],\n      //   \"name\": \"windows-1250\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"cp1251\",\n      //     \"windows-1251\",\n      //     \"x-cp1251\"\n      //   ],\n      //   \"name\": \"windows-1251\"\n      // },\n      {\n        \"labels\": [\n          \"ansi_x3.4-1968\",\n          \"ascii\",\n          \"cp1252\",\n          \"cp819\",\n          \"csisolatin1\",\n          \"ibm819\",\n          \"iso-8859-1\",\n          \"iso-ir-100\",\n          \"iso8859-1\",\n          \"iso88591\",\n          \"iso_8859-1\",\n          \"iso_8859-1:1987\",\n          \"l1\",\n          \"latin1\",\n          \"us-ascii\",\n          \"windows-1252\",\n          \"x-cp1252\"\n        ],\n        \"name\": \"windows-1252\"\n      },\n      // {\n      //   \"labels\": [\n      //     \"cp1253\",\n      //     \"windows-1253\",\n      //     \"x-cp1253\"\n      //   ],\n      //   \"name\": \"windows-1253\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"cp1254\",\n      //     \"csisolatin5\",\n      //     \"iso-8859-9\",\n      //     \"iso-ir-148\",\n      //     \"iso8859-9\",\n      //     \"iso88599\",\n      //     \"iso_8859-9\",\n      //     \"iso_8859-9:1989\",\n      //     \"l5\",\n      //     \"latin5\",\n      //     \"windows-1254\",\n      //     \"x-cp1254\"\n      //   ],\n      //   \"name\": \"windows-1254\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"cp1255\",\n      //     \"windows-1255\",\n      //     \"x-cp1255\"\n      //   ],\n      //   \"name\": \"windows-1255\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"cp1256\",\n      //     \"windows-1256\",\n      //     \"x-cp1256\"\n      //   ],\n      //   \"name\": \"windows-1256\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"cp1257\",\n      //     \"windows-1257\",\n      //     \"x-cp1257\"\n      //   ],\n      //   \"name\": \"windows-1257\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"cp1258\",\n      //     \"windows-1258\",\n      //     \"x-cp1258\"\n      //   ],\n      //   \"name\": \"windows-1258\"\n      // },\n      // {\n      //   \"labels\": [\n      //     \"x-mac-cyrillic\",\n      //     \"x-mac-ukrainian\"\n      //   ],\n      //   \"name\": \"x-mac-cyrillic\"\n      // }\n    ],\n    \"heading\": \"Legacy single-byte encodings\"\n  },\n  // {\n  //   \"encodings\": [\n  //     {\n  //       \"labels\": [\n  //         \"chinese\",\n  //         \"csgb2312\",\n  //         \"csiso58gb231280\",\n  //         \"gb2312\",\n  //         \"gb_2312\",\n  //         \"gb_2312-80\",\n  //         \"gbk\",\n  //         \"iso-ir-58\",\n  //         \"x-gbk\"\n  //       ],\n  //       \"name\": \"GBK\"\n  //     },\n  //     {\n  //       \"labels\": [\n  //         \"gb18030\"\n  //       ],\n  //       \"name\": \"gb18030\"\n  //     }\n  //   ],\n  //   \"heading\": \"Legacy multi-byte Chinese (simplified) encodings\"\n  // },\n  // {\n  //   \"encodings\": [\n  //     {\n  //       \"labels\": [\n  //         \"big5\",\n  //         \"big5-hkscs\",\n  //         \"cn-big5\",\n  //         \"csbig5\",\n  //         \"x-x-big5\"\n  //       ],\n  //       \"name\": \"Big5\"\n  //     }\n  //   ],\n  //   \"heading\": \"Legacy multi-byte Chinese (traditional) encodings\"\n  // },\n  // {\n  //   \"encodings\": [\n  //     {\n  //       \"labels\": [\n  //         \"cseucpkdfmtjapanese\",\n  //         \"euc-jp\",\n  //         \"x-euc-jp\"\n  //       ],\n  //       \"name\": \"EUC-JP\"\n  //     },\n  //     {\n  //       \"labels\": [\n  //         \"csiso2022jp\",\n  //         \"iso-2022-jp\"\n  //       ],\n  //       \"name\": \"ISO-2022-JP\"\n  //     },\n  //     {\n  //       \"labels\": [\n  //         \"csshiftjis\",\n  //         \"ms932\",\n  //         \"ms_kanji\",\n  //         \"shift-jis\",\n  //         \"shift_jis\",\n  //         \"sjis\",\n  //         \"windows-31j\",\n  //         \"x-sjis\"\n  //       ],\n  //       \"name\": \"Shift_JIS\"\n  //     }\n  //   ],\n  //   \"heading\": \"Legacy multi-byte Japanese encodings\"\n  // },\n  // {\n  //   \"encodings\": [\n  //     {\n  //       \"labels\": [\n  //         \"cseuckr\",\n  //         \"csksc56011987\",\n  //         \"euc-kr\",\n  //         \"iso-ir-149\",\n  //         \"korean\",\n  //         \"ks_c_5601-1987\",\n  //         \"ks_c_5601-1989\",\n  //         \"ksc5601\",\n  //         \"ksc_5601\",\n  //         \"windows-949\"\n  //       ],\n  //       \"name\": \"EUC-KR\"\n  //     }\n  //   ],\n  //   \"heading\": \"Legacy multi-byte Korean encodings\"\n  // },\n  {\n    \"encodings\": [\n      {\n        \"labels\": [\n          \"csiso2022kr\",\n          \"hz-gb-2312\",\n          \"iso-2022-cn\",\n          \"iso-2022-cn-ext\",\n          \"iso-2022-kr\",\n          \"replacement\"\n        ],\n        \"name\": \"replacement\"\n      },\n      {\n        \"labels\": [\n          \"unicodefffe\",\n          \"utf-16be\"\n        ],\n        \"name\": \"UTF-16BE\"\n      },\n      {\n        \"labels\": [\n          \"csunicode\",\n          \"iso-10646-ucs-2\",\n          \"ucs-2\",\n          \"unicode\",\n          \"unicodefeff\",\n          \"utf-16\",\n          \"utf-16le\"\n        ],\n        \"name\": \"UTF-16LE\"\n      },\n      // {\n      //   \"labels\": [\n      //     \"x-user-defined\"\n      //   ],\n      //   \"name\": \"x-user-defined\"\n      // }\n    ],\n    \"heading\": \"Legacy miscellaneous encodings\"\n  }\n]\n;\nexport default encodings_table;\n"
  },
  {
    "path": "tests/wpt/encoding.harness.js",
    "content": "import resourcesIdlharness from \"./resources/idlharness.js\";\nimport resourcesTestharness from \"./resources/testharness.js\";\n\nimport commonGc from \"./common/gc.js\";\nimport commonSubsetTests from \"./common/subset-tests.js\";\n\nimport encodings from \"./encoding/resources/encodings.js\";\nimport encodingDecodingHelpers from \"./encoding/resources/decoding-helpers.js\";\n\nexport const runTestDynamic = (testSource, done) => {\n  const context = {\n    createBuffer: (type, length) => new self[type](length),\n    encodings_table: encodings,\n    setTimeout: setTimeout,\n    DOMException: DOMException,\n    location: {},\n  };\n\n  resourcesIdlharness(context);\n  resourcesTestharness(context);\n\n  commonGc(context);\n  commonSubsetTests(context);\n\n  encodingDecodingHelpers(context);\n\n  context.setup({\n    explicit_done: true,\n    debug: process.env.DEBUG !== undefined,\n  });\n\n  globalThis.gc = globalThis.__gc;\n\n  context.add_completion_callback((tests, status, assertions) => {\n    if (\n      tests.filter(\n        ({ name, status }) => !(name === \"Loading data...\" && status === 0)\n      ).length === 0\n    ) {\n      done(new Error(\"No tests were executed!\"));\n    }\n    const failure = tests.find((test) => test.status !== 0);\n    if (failure) {\n      const message = `[${failure.name}] ${failure.message || String(failure)}`;\n      done(message);\n      return;\n    }\n    done();\n  });\n\n  wrapTestSuite(testSource)(context);\n\n  context.done();\n};\n\nfunction wrapTestSuite(sourceCode) {\n  return new Function(\n    \"context\",\n    `\n      with (context) {\n        ${sourceCode}\n      }\n    `\n  );\n}\n"
  },
  {
    "path": "tests/wpt/encoding.test.ts",
    "content": "import { runTestDynamic } from \"./encoding.harness.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst SKIP_FILES = [\n  \"idlharness.any.js\", // ReferenceError: idl_test is not defined\n  \"iso-2022-jp-decoder.any.js\", // The \"iso-2022-jp\" encoding is not supported\n  \"replacement-encodings.any.js\", // ReferenceError: promise_test is not defined\n  \"unsupported-encodings.any.js\", // ReferenceError: promise_test is not defined\n];\n\nconst __filename = fileURLToPath(import.meta.url);\nconst basename = path.basename(__filename);\nconst subDir = basename\n  .replace(/\\.test\\.[jt]s$/, \"\")\n  .split(\".\")\n  .join(path.sep);\n\nconst CWD = process.cwd();\nconst baseDir = path.join(CWD, \"wpt\");\nconst targetDir = path.join(baseDir, subDir);\n\nconst testFiles = fs\n  .readdirSync(targetDir)\n  .filter((file) => file.endsWith(\".any.js\"));\n\ndescribe(subDir, () => {\n  for (const file of testFiles) {\n    if (!SKIP_FILES.includes(file)) {\n      it(`should pass ${file} tests`, (done) => {\n        const filePath = path.join(targetDir, file);\n        const sourceCode = fs.readFileSync(filePath, \"utf8\");\n        runTestDynamic(sourceCode, done);\n      });\n    }\n  }\n});\n"
  },
  {
    "path": "tests/wpt/fetch/api/cors/resources/not-cors-safelisted.json",
    "content": "[\n  [\"accept\", \"\\\"\"],\n  [\n    \"accept\",\n    \"012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678\"\n  ],\n  [\"accept-language\", \"\\u0001\"],\n  [\"accept-language\", \"@\"],\n  [\"authorization\", \"basics\"],\n  [\"content-language\", \"\\u0001\"],\n  [\"content-language\", \"@\"],\n  [\"content-type\", \"text/html\"],\n  [\n    \"content-type\",\n    \"text/plain; long=0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901\"\n  ],\n  [\"range\", \"bytes 0-\"],\n  [\"test\", \"hi\"]\n]\n"
  },
  {
    "path": "tests/wpt/fetch/api/request/request-cache.js",
    "content": "export default function (self) {\n  /**\n   * Each test is run twice: once using etag/If-None-Match and once with\n   * date/If-Modified-Since.  Each test run gets its own URL and randomized\n   * content and operates independently.\n   *\n   * The test steps are run with request_cache.length fetch requests issued\n   * and their immediate results sanity-checked.  The cache.py server script\n   * stashes an entry containing any If-None-Match, If-Modified-Since, Pragma,\n   * and Cache-Control observed headers for each request it receives.  When\n   * the test fetches have run, this state is retrieved from cache.py and the\n   * expected_* lists are checked, including their length.\n   *\n   * This means that if a request_* fetch is expected to hit the cache and not\n   * touch the network, then there will be no entry for it in the expect_*\n   * lists.  AKA (request_cache.length - expected_validation_headers.length)\n   * should equal the number of cache hits that didn't touch the network.\n   *\n   * Test dictionary keys:\n   * - state: required string that determines whether the Expires response for\n   *   the fetched document should be set in the future (\"fresh\") or past\n   *   (\"stale\").\n   * - vary: optional string to be passed to the server for it to quote back\n   *   in a Vary header on the response to us.\n   * - cache_control: optional string to be passed to the server for it to\n   *   quote back in a Cache-Control header on the response to us.\n   * - redirect: optional string \"same-origin\" or \"cross-origin\".  If\n   *   provided, the server will issue an absolute redirect to the script on\n   *   the same or a different origin, as appropriate.  The redirected\n   *   location is the script with the redirect parameter removed, so the\n   *   content/state/etc. will be as if you hadn't specified a redirect.\n   * - request_cache: required array of cache modes to use (via `cache`).\n   * - request_headers: optional array of explicit fetch `headers` arguments.\n   *   If provided, the server will log an empty dictionary for each request\n   *   instead of the request headers it would normally log.\n   * - response: optional array of specialized response handling.  Right now,\n   *   \"error\" array entries indicate a network error response is expected\n   *   which will reject with a TypeError.\n   * - expected_validation_headers: required boolean array indicating whether\n   *   the server should have seen an If-None-Match/If-Modified-Since header\n   *   in the request.\n   * - expected_no_cache_headers: required boolean array indicating whether\n   *   the server should have seen Pragma/Cache-control:no-cache headers in\n   *   the request.\n   * - expected_max_age_headers: optional boolean array indicating whether\n   *   the server should have seen a Cache-Control:max-age=0 header in the\n   *   request.\n   */\n\n  var now = new Date();\n  self.now = now;\n\n  function base_path() {\n    return location.pathname.replace(/\\/[^\\/]*$/, \"/\");\n  }\n  self.base_path = base_path;\n\n  function make_url(uuid, id, value, content, info) {\n    var dates = {\n      fresh: new Date(\n        now.getFullYear() + 1,\n        now.getMonth(),\n        now.getDay()\n      ).toGMTString(),\n      stale: new Date(\n        now.getFullYear() - 1,\n        now.getMonth(),\n        now.getDay()\n      ).toGMTString(),\n    };\n    var vary = \"\";\n    if (\"vary\" in info) {\n      vary = \"&vary=\" + info.vary;\n    }\n    var cache_control = \"\";\n    if (\"cache_control\" in info) {\n      cache_control = \"&cache_control=\" + info.cache_control;\n    }\n    var redirect = \"\";\n\n    var ignore_request_headers = \"\";\n    if (\"request_headers\" in info) {\n      // Ignore the request headers that we send since they may be synthesized by the test.\n      ignore_request_headers = \"&ignore\";\n    }\n    var url_sans_redirect =\n      \"resources/cache.py?token=\" +\n      uuid +\n      \"&content=\" +\n      content +\n      \"&\" +\n      id +\n      \"=\" +\n      value +\n      \"&expires=\" +\n      dates[info.state] +\n      vary +\n      cache_control +\n      ignore_request_headers;\n    // If there's a redirect, the target is the script without any redirect at\n    // either the same domain or a different domain.\n    if (\"redirect\" in info) {\n      var host_info = get_host_info();\n      var origin;\n      switch (info.redirect) {\n        case \"same-origin\":\n          origin = host_info[\"HTTP_ORIGIN\"];\n          break;\n        case \"cross-origin\":\n          origin = host_info[\"HTTP_REMOTE_ORIGIN\"];\n          break;\n      }\n      var redirected_url = origin + base_path() + url_sans_redirect;\n      return (\n        url_sans_redirect + \"&redirect=\" + encodeURIComponent(redirected_url)\n      );\n    } else {\n      return url_sans_redirect;\n    }\n  }\n  self.make_url = make_url;\n\n  function expected_status(type, identifier, init) {\n    if (\n      type == \"date\" &&\n      init.headers &&\n      init.headers[\"If-Modified-Since\"] == identifier\n    ) {\n      // The server will respond with a 304 in this case.\n      return [304, \"Not Modified\"];\n    }\n    return [200, \"OK\"];\n  }\n  self.expected_status = expected_status;\n\n  function expected_response_text(type, identifier, init, content) {\n    if (\n      type == \"date\" &&\n      init.headers &&\n      init.headers[\"If-Modified-Since\"] == identifier\n    ) {\n      // The server will respond with a 304 in this case.\n      return \"\";\n    }\n    return content;\n  }\n  self.expected_response_text = expected_response_text;\n\n  function server_state(uuid) {\n    return fetch(\"resources/cache.py?querystate&token=\" + uuid)\n      .then(function (response) {\n        return response.text();\n      })\n      .then(function (text) {\n        // null will be returned if the server never received any requests\n        // for the given uuid.  Normalize that to an empty list consistent\n        // with our representation.\n        return JSON.parse(text) || [];\n      });\n  }\n  self.server_state = server_state;\n\n  function make_test(type, info) {\n    return function (test) {\n      var uuid = token();\n      var identifier = type == \"tag\" ? Math.random() : now.toGMTString();\n      var content = Math.random().toString();\n      var url = make_url(uuid, type, identifier, content, info);\n      var fetch_functions = [];\n      for (var i = 0; i < info.request_cache.length; ++i) {\n        fetch_functions.push(function (idx) {\n          var init = { cache: info.request_cache[idx] };\n          if (\"request_headers\" in info) {\n            init.headers = info.request_headers[idx];\n          }\n          if (init.cache === \"only-if-cached\") {\n            // only-if-cached requires we use same-origin mode.\n            init.mode = \"same-origin\";\n          }\n          return fetch(url, init)\n            .then(function (response) {\n              if (\"response\" in info && info.response[idx] === \"error\") {\n                assert_true(false, \"fetch should have been an error\");\n                return;\n              }\n              assert_array_equals(\n                [response.status, response.statusText],\n                expected_status(type, identifier, init)\n              );\n              return response.text();\n            })\n            .then(\n              function (text) {\n                assert_equals(\n                  text,\n                  expected_response_text(type, identifier, init, content)\n                );\n              },\n              function (reason) {\n                if (\"response\" in info && info.response[idx] === \"error\") {\n                  assert_throws_js(TypeError, function () {\n                    throw reason;\n                  });\n                } else {\n                  throw reason;\n                }\n              }\n            );\n        });\n      }\n      var i = 0;\n      function run_next_step() {\n        if (fetch_functions.length) {\n          return fetch_functions.shift()(i++).then(run_next_step);\n        } else {\n          return Promise.resolve();\n        }\n      }\n      return run_next_step()\n        .then(function () {\n          // Now, query the server state\n          return server_state(uuid);\n        })\n        .then(function (state) {\n          var expectedState = [];\n          info.expected_validation_headers.forEach(function (validate) {\n            if (validate) {\n              if (type == \"tag\") {\n                expectedState.push({ \"If-None-Match\": '\"' + identifier + '\"' });\n              } else {\n                expectedState.push({ \"If-Modified-Since\": identifier });\n              }\n            } else {\n              expectedState.push({});\n            }\n          });\n          for (var i = 0; i < info.expected_no_cache_headers.length; ++i) {\n            if (info.expected_no_cache_headers[i]) {\n              expectedState[i][\"Pragma\"] = \"no-cache\";\n              expectedState[i][\"Cache-Control\"] = \"no-cache\";\n            }\n          }\n          if (\"expected_max_age_headers\" in info) {\n            for (var i = 0; i < info.expected_max_age_headers.length; ++i) {\n              if (info.expected_max_age_headers[i]) {\n                expectedState[i][\"Cache-Control\"] = \"max-age=0\";\n              }\n            }\n          }\n          assert_equals(state.length, expectedState.length);\n          for (var i = 0; i < state.length; ++i) {\n            for (var header in state[i]) {\n              assert_equals(state[i][header], expectedState[i][header]);\n              delete expectedState[i][header];\n            }\n            for (var header in expectedState[i]) {\n              assert_false(header in state[i]);\n            }\n          }\n        });\n    };\n  }\n  self.make_test = make_test;\n\n  function run_tests(tests) {\n    tests.forEach(function (info) {\n      promise_test(\n        make_test(\"tag\", info),\n        info.name + \" with Etag and \" + info.state + \" response\"\n      );\n      promise_test(\n        make_test(\"date\", info),\n        info.name + \" with Last-Modified and \" + info.state + \" response\"\n      );\n    });\n  }\n  self.run_tests = run_tests;\n}\n"
  },
  {
    "path": "tests/wpt/fetch/api/request/request-error.js",
    "content": "export default function (self) {\n  const badRequestArgTests = [\n    {\n      args: [\"\", { window: \"http://test.url\" }],\n      testName: \"RequestInit's window is not null\",\n    },\n    {\n      args: [\"http://:not a valid URL\"],\n      testName: \"Input URL is not valid\",\n    },\n    {\n      args: [\"http://user:pass@test.url\"],\n      testName: \"Input URL has credentials\",\n    },\n    {\n      args: [\"\", { mode: \"navigate\" }],\n      testName: \"RequestInit's mode is navigate\",\n    },\n    {\n      args: [\"\", { referrer: \"http://:not a valid URL\" }],\n      testName: \"RequestInit's referrer is invalid\",\n    },\n    {\n      args: [\"\", { method: \"IN VALID\" }],\n      testName: \"RequestInit's method is invalid\",\n    },\n    {\n      args: [\"\", { method: \"TRACE\" }],\n      testName: \"RequestInit's method is forbidden\",\n    },\n    {\n      args: [\"\", { mode: \"no-cors\", method: \"PUT\" }],\n      testName: \"RequestInit's mode is no-cors and method is not simple\",\n    },\n    {\n      args: [\"\", { mode: \"cors\", cache: \"only-if-cached\" }],\n      testName:\n        \"RequestInit's cache mode is only-if-cached and mode is not same-origin\",\n    },\n    {\n      args: [\"test\", { cache: \"only-if-cached\", mode: \"cors\" }],\n      testName: \"Request with cache mode: only-if-cached and fetch mode cors\",\n    },\n    {\n      args: [\"test\", { cache: \"only-if-cached\", mode: \"no-cors\" }],\n      testName:\n        \"Request with cache mode: only-if-cached and fetch mode no-cors\",\n    },\n  ];\n\n  badRequestArgTests.push(\n    ...[\"referrerPolicy\", \"mode\", \"credentials\", \"cache\", \"redirect\"].map(\n      (optionProp) => {\n        const options = {};\n        options[optionProp] = \"BAD\";\n        return {\n          args: [\"\", options],\n          testName: `Bad ${optionProp} init parameter value`,\n        };\n      }\n    )\n  );\n  self.badRequestArgTests = badRequestArgTests;\n}\n"
  },
  {
    "path": "tests/wpt/fetch/api/resources/data.json",
    "content": "{ \"key\": \"value\" }\n"
  },
  {
    "path": "tests/wpt/fetch/api/resources/keepalive-helper.js",
    "content": "export default function (self) {\n  // Utility functions to help testing keepalive requests.\n\n  // Returns a URL to an iframe that loads a keepalive URL on iframe loaded.\n  //\n  // The keepalive URL points to a target that stores `token`. The token will then\n  // be posted back on iframe loaded to the parent document.\n  // `method` defaults to GET.\n  // `frameOrigin` to specify the origin of the iframe to load. If not set,\n  // default to a different site origin.\n  // `requestOrigin` to specify the origin of the fetch request target.\n  // `sendOn` to specify the name of the event when the keepalive request should\n  // be sent instead of the default 'load'.\n  // `mode` to specify the fetch request's CORS mode.\n  // `disallowCrossOrigin` to ask the iframe to set up a server that disallows\n  // cross origin requests.\n  function getKeepAliveIframeUrl(\n    token,\n    method,\n    {\n      frameOrigin = \"DEFAULT\",\n      requestOrigin = \"\",\n      sendOn = \"load\",\n      mode = \"cors\",\n      disallowCrossOrigin = false,\n    } = {}\n  ) {\n    const https = location.protocol.startsWith(\"https\");\n    frameOrigin =\n      frameOrigin === \"DEFAULT\"\n        ? get_host_info()[\n            https ? \"HTTPS_NOTSAMESITE_ORIGIN\" : \"HTTP_NOTSAMESITE_ORIGIN\"\n          ]\n        : frameOrigin;\n    return (\n      `${frameOrigin}/fetch/api/resources/keepalive-iframe.html?` +\n      `token=${token}&` +\n      `method=${method}&` +\n      `sendOn=${sendOn}&` +\n      `mode=${mode}&` +\n      (disallowCrossOrigin ? `disallowCrossOrigin=1&` : ``) +\n      `origin=${requestOrigin}`\n    );\n  }\n  self.getKeepAliveIframeUrl = getKeepAliveIframeUrl;\n\n  // Returns a different-site URL to an iframe that loads a keepalive URL.\n  //\n  // By default, the keepalive URL points to a target that redirects to another\n  // same-origin destination storing `token`. The token will then be posted back\n  // to parent document.\n  //\n  // The URL redirects can be customized from `origin1` to `origin2` if provided.\n  // Sets `withPreflight` to true to get URL enabling preflight.\n  function getKeepAliveAndRedirectIframeUrl(\n    token,\n    origin1,\n    origin2,\n    withPreflight\n  ) {\n    const https = location.protocol.startsWith(\"https\");\n    const frameOrigin =\n      get_host_info()[\n        https ? \"HTTPS_NOTSAMESITE_ORIGIN\" : \"HTTP_NOTSAMESITE_ORIGIN\"\n      ];\n    return (\n      `${frameOrigin}/fetch/api/resources/keepalive-redirect-iframe.html?` +\n      `token=${token}&` +\n      `origin1=${origin1}&` +\n      `origin2=${origin2}&` +\n      (withPreflight ? `with-headers` : ``)\n    );\n  }\n\n  async function iframeLoaded(iframe) {\n    return new Promise((resolve) => iframe.addEventListener(\"load\", resolve));\n  }\n\n  // Obtains the token from the message posted by iframe after loading\n  // `getKeepAliveAndRedirectIframeUrl()`.\n  async function getTokenFromMessage() {\n    return new Promise((resolve) => {\n      window.addEventListener(\n        \"message\",\n        (event) => {\n          resolve(event.data);\n        },\n        { once: true }\n      );\n    });\n  }\n\n  // Tells if `token` has been stored in the server.\n  async function queryToken(token) {\n    const response = await fetch(`../resources/stash-take.py?key=${token}`);\n    const json = await response.json();\n    return json;\n  }\n\n  // A helper to assert the existence of `token` that should have been stored in\n  // the server by fetching ../resources/stash-put.py.\n  //\n  // This function simply wait for a custom amount of time before trying to\n  // retrieve `token` from the server.\n  // `expectTokenExist` tells if `token` should be present or not.\n  //\n  // NOTE:\n  // In order to parallelize the work, we are going to have an async_test\n  // for the rest of the work. Note that we want the serialized behavior\n  // for the steps so far, so we don't want to make the entire test case\n  // an async_test.\n  function assertStashedTokenAsync(\n    testName,\n    token,\n    { expectTokenExist = true } = {}\n  ) {\n    async_test((test) => {\n      new Promise((resolve) => test.step_timeout(resolve, 3000 /*ms*/))\n        .then(\n          test.step_func(() => {\n            return queryToken(token);\n          })\n        )\n        .then(\n          test.step_func((result) => {\n            if (expectTokenExist) {\n              assert_equals(result, \"on\", `token should be on (stashed).`);\n              test.done();\n            } else {\n              assert_not_equals(\n                result,\n                \"on\",\n                `token should not be on (stashed).`\n              );\n              return Promise.reject(`Failed to retrieve token from server`);\n            }\n          })\n        )\n        .catch(\n          test.step_func((e) => {\n            if (expectTokenExist) {\n              test.unreached_func(e);\n            } else {\n              test.done();\n            }\n          })\n        );\n    }, testName);\n  }\n\n  /**\n   * In an iframe, and in `load` event handler, test to fetch a keepalive URL that\n   * involves in redirect to another URL.\n   *\n   * `unloadIframe` to unload the iframe before verifying stashed token to\n   * simulate the situation that unloads after fetching. Note that this test is\n   * different from `keepaliveRedirectInUnloadTest()` in that the latter\n   * performs fetch() call directly in `unload` event handler, while this test\n   * does it in `load`.\n   */\n  function keepaliveRedirectTest(\n    desc,\n    {\n      origin1 = \"\",\n      origin2 = \"\",\n      withPreflight = false,\n      unloadIframe = false,\n      expectFetchSucceed = true,\n    } = {}\n  ) {\n    desc =\n      `[keepalive][iframe][load] ${desc}` +\n      (unloadIframe ? \" [unload at end]\" : \"\");\n    promise_test(async (test) => {\n      const tokenToStash = token();\n      const iframe = document.createElement(\"iframe\");\n      iframe.src = getKeepAliveAndRedirectIframeUrl(\n        tokenToStash,\n        origin1,\n        origin2,\n        withPreflight\n      );\n      document.body.appendChild(iframe);\n      await iframeLoaded(iframe);\n      assert_equals(await getTokenFromMessage(), tokenToStash);\n      if (unloadIframe) {\n        iframe.remove();\n      }\n\n      assertStashedTokenAsync(desc, tokenToStash, {\n        expectTokenExist: expectFetchSucceed,\n      });\n    }, `${desc}; setting up`);\n  }\n  self.keepaliveRedirectTest = keepaliveRedirectTest;\n\n  /**\n   * Opens a different site window, and in `unload` event handler, test to fetch\n   * a keepalive URL that involves in redirect to another URL.\n   */\n  function keepaliveRedirectInUnloadTest(\n    desc,\n    {\n      origin1 = \"\",\n      origin2 = \"\",\n      url2 = \"\",\n      withPreflight = false,\n      expectFetchSucceed = true,\n    } = {}\n  ) {\n    desc = `[keepalive][new window][unload] ${desc}`;\n\n    promise_test(async (test) => {\n      const targetUrl =\n        `${HTTP_NOTSAMESITE_ORIGIN}/fetch/api/resources/keepalive-redirect-window.html?` +\n        `origin1=${origin1}&` +\n        `origin2=${origin2}&` +\n        `url2=${url2}&` +\n        (withPreflight ? `with-headers` : ``);\n      const w = window.open(targetUrl);\n      const token = await getTokenFromMessage();\n      w.close();\n\n      assertStashedTokenAsync(desc, token, {\n        expectTokenExist: expectFetchSucceed,\n      });\n    }, `${desc}; setting up`);\n  }\n  self.keepaliveRedirectInUnloadTest = keepaliveRedirectInUnloadTest;\n\n  /**\n   * utility to create pending keepalive fetch requests\n   * The pending request state is achieved by ensuring the server (trickle.py) does not\n   * immediately respond to the fetch requests.\n   * The response delay is set as a url parameter.\n   */\n\n  function createPendingKeepAliveRequest(delay, remote = false) {\n    // trickle.py is a script that can make a delayed response to the client request\n    const trickleRemoteURL =\n      get_host_info().HTTPS_REMOTE_ORIGIN +\n      \"/fetch/api/resources/trickle.py?count=1&ms=\";\n    const trickleLocalURL =\n      get_host_info().HTTP_ORIGIN +\n      \"/fetch/api/resources/trickle.py?count=1&ms=\";\n    url = remote ? trickleRemoteURL : trickleLocalURL;\n\n    const body = \"*\".repeat(10);\n    return fetch(url + delay, { keepalive: true, body, method: \"POST\" })\n      .then((res) => {\n        return res.text();\n      })\n      .then(() => {\n        return new Promise((resolve) => step_timeout(resolve, 1));\n      })\n      .catch((error) => {\n        return Promise.reject(error);\n      });\n  }\n  self.createPendingKeepAliveRequest = createPendingKeepAliveRequest;\n}\n"
  },
  {
    "path": "tests/wpt/fetch/api/resources/keepalive-worker.js",
    "content": "export default function (self) {\n  /**\n   * Script that sends keepalive\n   * fetch request and terminates immediately.\n   * The request URL is passed as a parameter to this worker\n   */\n  function sendFetchRequest() {\n    // Parse the query parameter from the worker's script URL\n    const urlString = self.location.search.replace(\"?param=\", \"\");\n    postMessage(\"started\");\n    fetch(`${urlString}`, { keepalive: true });\n  }\n\n  sendFetchRequest();\n  // Terminate the worker\n  self.close();\n}\n"
  },
  {
    "path": "tests/wpt/fetch/api/resources/sw-intercept-abort.js",
    "content": "export default function (self) {\n  async function messageClient(clientId, message) {\n    const client = await clients.get(clientId);\n    client.postMessage(message);\n  }\n\n  addEventListener(\"fetch\", (event) => {\n    let resolve;\n    const promise = new Promise((r) => (resolve = r));\n\n    function onAborted() {\n      messageClient(event.clientId, event.request.signal.reason);\n      resolve();\n    }\n\n    messageClient(event.clientId, \"fetch event has arrived\");\n\n    event.respondWith(promise.then(() => new Response(\"hello\")));\n    event.request.signal.addEventListener(\"abort\", onAborted);\n  });\n}\n"
  },
  {
    "path": "tests/wpt/fetch/api/resources/sw-intercept.js",
    "content": "export default function (self) {\n  async function broadcast(msg) {\n    for (const client of await clients.matchAll()) {\n      client.postMessage(msg);\n    }\n  }\n\n  addEventListener(\"fetch\", (event) => {\n    event.waitUntil(broadcast(event.request.url));\n    event.respondWith(fetch(event.request));\n  });\n}\n"
  },
  {
    "path": "tests/wpt/fetch/api/resources/utils.js",
    "content": "export default function (self) {\n  var RESOURCES_DIR = \"../resources/\";\n\n  function dirname(path) {\n    if (typeof path !== \"string\") {\n      return \"\";\n    }\n    return path.replace(/\\/[^\\/]*$/, \"/\");\n  }\n  self.dirname = dirname;\n\n  function checkRequest(request, ExpectedValuesDict) {\n    for (var attribute in ExpectedValuesDict) {\n      switch (attribute) {\n        case \"headers\":\n          for (var key in ExpectedValuesDict[\"headers\"].keys()) {\n            self.assert_equals(\n              request[\"headers\"].get(key),\n              ExpectedValuesDict[\"headers\"].get(key),\n              \"Check headers attribute has \" +\n                key +\n                \":\" +\n                ExpectedValuesDict[\"headers\"].get(key)\n            );\n          }\n          break;\n\n        case \"body\":\n          //for checking body's content, a dedicated asyncronous/promise test should be used\n          self.assert_true(\n            request[\"headers\"].has(\"Content-Type\"),\n            \"Check request has body using Content-Type header\"\n          );\n          break;\n\n        case \"method\":\n        case \"referrer\":\n        case \"referrerPolicy\":\n        case \"credentials\":\n        case \"cache\":\n        case \"redirect\":\n        case \"integrity\":\n        case \"url\":\n        case \"destination\":\n          self.assert_equals(\n            request[attribute],\n            ExpectedValuesDict[attribute],\n            \"Check \" + attribute + \" attribute\"\n          );\n          break;\n\n        default:\n          break;\n      }\n    }\n  }\n  self.checkRequest = checkRequest;\n\n  function stringToArray(str) {\n    var array = new Uint8Array(str.length);\n    for (var i = 0, strLen = str.length; i < strLen; i++)\n      array[i] = str.charCodeAt(i);\n    return array;\n  }\n  self.stringToArray = stringToArray;\n\n  function encode_utf8(str) {\n    if (self.TextEncoder) return new TextEncoder().encode(str);\n    return stringToArray(unescape(encodeURIComponent(str)));\n  }\n  self.encode_utf8 = encode_utf8;\n\n  function validateBufferFromString(buffer, expectedValue, message) {\n    return self.assert_array_equals(\n      new Uint8Array(buffer !== undefined ? buffer : []),\n      stringToArray(expectedValue),\n      message\n    );\n  }\n  self.validateBufferFromString = validateBufferFromString;\n\n  function validateStreamFromString(\n    reader,\n    expectedValue,\n    retrievedArrayBuffer\n  ) {\n    // Passing Uint8Array for byte streams; non-byte streams will simply ignore it\n    return reader.read(new Uint8Array(64)).then(function (data) {\n      if (!data.done) {\n        self.assert_true(\n          data.value instanceof Uint8Array,\n          \"Fetch ReadableStream chunks should be Uint8Array\"\n        );\n        var newBuffer;\n        if (retrievedArrayBuffer) {\n          newBuffer = new Uint8Array(\n            data.value.length + retrievedArrayBuffer.length\n          );\n          newBuffer.set(retrievedArrayBuffer, 0);\n          newBuffer.set(data.value, retrievedArrayBuffer.length);\n        } else {\n          newBuffer = data.value;\n        }\n        return validateStreamFromString(reader, expectedValue, newBuffer);\n      }\n      validateBufferFromString(\n        retrievedArrayBuffer,\n        expectedValue,\n        \"Retrieve and verify stream\"\n      );\n    });\n  }\n  self.validateStreamFromString = validateStreamFromString;\n\n  function validateStreamFromPartialString(\n    reader,\n    expectedValue,\n    retrievedArrayBuffer\n  ) {\n    // Passing Uint8Array for byte streams; non-byte streams will simply ignore it\n    return reader.read(new Uint8Array(64)).then(function (data) {\n      if (!data.done) {\n        self.assert_true(\n          data.value instanceof Uint8Array,\n          \"Fetch ReadableStream chunks should be Uint8Array\"\n        );\n        var newBuffer;\n        if (retrievedArrayBuffer) {\n          newBuffer = new Uint8Array(\n            data.value.length + retrievedArrayBuffer.length\n          );\n          newBuffer.set(retrievedArrayBuffer, 0);\n          newBuffer.set(data.value, retrievedArrayBuffer.length);\n        } else {\n          newBuffer = data.value;\n        }\n        return validateStreamFromPartialString(\n          reader,\n          expectedValue,\n          newBuffer\n        );\n      }\n\n      var string = new TextDecoder(\"utf-8\").decode(retrievedArrayBuffer);\n      return self.assert_true(\n        string.search(expectedValue) != -1,\n        \"Retrieve and verify stream\"\n      );\n    });\n  }\n  self.validateStreamFromPartialString = validateStreamFromPartialString;\n\n  // From streams tests\n  function delay(milliseconds) {\n    return new Promise(function (resolve) {\n      step_timeout(resolve, milliseconds);\n    });\n  }\n  self.delay = delay;\n\n  function requestForbiddenHeaders(desc, forbiddenHeaders) {\n    var url = RESOURCES_DIR + \"inspect-headers.py\";\n    var requestInit = { headers: forbiddenHeaders };\n    var urlParameters = \"?headers=\" + Object.keys(forbiddenHeaders).join(\"|\");\n\n    promise_test(function (test) {\n      return fetch(url + urlParameters, requestInit).then(function (resp) {\n        self.assert_equals(resp.status, 200, \"HTTP status is 200\");\n        self.assert_equals(resp.type, \"basic\", \"Response's type is basic\");\n        for (var header in forbiddenHeaders)\n          self.assert_not_equals(\n            resp.headers.get(\"x-request-\" + header),\n            forbiddenHeaders[header],\n            header + \" does not have the value we defined\"\n          );\n      });\n    }, desc);\n  }\n  self.requestForbiddenHeaders = requestForbiddenHeaders;\n}\n"
  },
  {
    "path": "tests/wpt/fetch.api.abort.test.ts",
    "content": "import { runTestDynamic } from \"./fetch.harness.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst SKIP_FILES = [\n  \"cache.https.any.js\", // ReferenceError: caches is not defined\n  \"general.any.js\", // Error: Timeout after 5000ms\n];\n\nconst __filename = fileURLToPath(import.meta.url);\nconst basename = path.basename(__filename);\nconst subDir = basename\n  .replace(/\\.test\\.[jt]s$/, \"\")\n  .split(\".\")\n  .join(path.sep);\n\nconst CWD = process.cwd();\nconst baseDir = path.join(CWD, \"wpt\");\nconst targetDir = path.join(baseDir, subDir);\n\nconst testFiles = fs\n  .readdirSync(targetDir)\n  .filter((file) => file.endsWith(\".any.js\"));\n\ndescribe(subDir, () => {\n  for (const file of testFiles) {\n    if (!SKIP_FILES.includes(file)) {\n      it(`should pass ${file} tests`, (done) => {\n        const filePath = path.join(targetDir, file);\n        const sourceCode = fs.readFileSync(filePath, \"utf8\");\n        runTestDynamic(sourceCode, baseDir, done);\n      });\n    }\n  }\n});\n"
  },
  {
    "path": "tests/wpt/fetch.api.basic.test.ts",
    "content": "import { runTestDynamic } from \"./fetch.harness.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst SKIP_FILES = [\n  \"request-forbidden-headers.any.js\", // ReferenceError: promise_test is not defined\n  \"request-private-network-headers.tentative.any.js\", // ReferenceError: promise_test is not defined\n  \"request-referrer.any.js\", // TypeError: cannot read property 'href' of undefined\n  \"request-upload.h2.any.js\",\n  \"scheme-blob.sub.any.js\", // TypeError: not a function\n];\n\nconst __filename = fileURLToPath(import.meta.url);\nconst basename = path.basename(__filename);\nconst subDir = basename\n  .replace(/\\.test\\.[jt]s$/, \"\")\n  .split(\".\")\n  .join(path.sep);\n\nconst CWD = process.cwd();\nconst baseDir = path.join(CWD, \"wpt\");\nconst targetDir = path.join(baseDir, subDir);\n\nconst testFiles = fs\n  .readdirSync(targetDir)\n  .filter((file) => file.endsWith(\".any.js\"));\n\ndescribe(subDir, () => {\n  for (const file of testFiles) {\n    if (!SKIP_FILES.includes(file)) {\n      it(`should pass ${file} tests`, (done) => {\n        const filePath = path.join(targetDir, file);\n        const sourceCode = fs.readFileSync(filePath, \"utf8\");\n        runTestDynamic(sourceCode, baseDir, done);\n      });\n    }\n  }\n});\n"
  },
  {
    "path": "tests/wpt/fetch.api.body.test.ts",
    "content": "import { runTestDynamic } from \"./fetch.harness.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst SKIP_FILES = [];\n\nconst __filename = fileURLToPath(import.meta.url);\nconst basename = path.basename(__filename);\nconst subDir = basename\n  .replace(/\\.test\\.[jt]s$/, \"\")\n  .split(\".\")\n  .join(path.sep);\n\nconst CWD = process.cwd();\nconst baseDir = path.join(CWD, \"wpt\");\nconst targetDir = path.join(baseDir, subDir);\n\nconst testFiles = fs\n  .readdirSync(targetDir)\n  .filter((file) => file.endsWith(\".any.js\"));\n\ndescribe(subDir, () => {\n  for (const file of testFiles) {\n    if (!SKIP_FILES.includes(file)) {\n      it(`should pass ${file} tests`, (done) => {\n        const filePath = path.join(targetDir, file);\n        const sourceCode = fs.readFileSync(filePath, \"utf8\");\n        runTestDynamic(sourceCode, baseDir, done);\n      });\n    }\n  }\n});\n"
  },
  {
    "path": "tests/wpt/fetch.api.headers.test.ts",
    "content": "import { runTestDynamic } from \"./fetch.harness.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst SKIP_FILES = [\n  \"header-values-normalize.any.js\", // TypeError: cannot read property 'isWorker' of undefined\n  \"header-values.any.js\", // TypeError: cannot read property 'isWorker' of undefined\n];\n\nconst __filename = fileURLToPath(import.meta.url);\nconst basename = path.basename(__filename);\nconst subDir = basename\n  .replace(/\\.test\\.[jt]s$/, \"\")\n  .split(\".\")\n  .join(path.sep);\n\nconst CWD = process.cwd();\nconst baseDir = path.join(CWD, \"wpt\");\nconst targetDir = path.join(baseDir, subDir);\n\nconst testFiles = fs\n  .readdirSync(targetDir)\n  .filter((file) => file.endsWith(\".any.js\"));\n\ndescribe(subDir, () => {\n  for (const file of testFiles) {\n    if (!SKIP_FILES.includes(file)) {\n      it(`should pass ${file} tests`, (done) => {\n        const filePath = path.join(targetDir, file);\n        const sourceCode = fs.readFileSync(filePath, \"utf8\");\n        runTestDynamic(sourceCode, baseDir, done);\n      });\n    }\n  }\n});\n"
  },
  {
    "path": "tests/wpt/fetch.api.request.test.ts",
    "content": "import { runTestDynamic } from \"./fetch.harness.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst SKIP_FILES = [\n  \"request-cache-default-conditional.any.js\", // ReferenceError: promise_test is not defined\n  \"request-cache-default.any.js\", // ReferenceError: promise_test is not defined\n  \"request-cache-force-cache.any.js\", // ReferenceError: promise_test is not defined\n  \"request-cache-no-cache.any.js\", // ReferenceError: promise_test is not defined\n  \"request-cache-no-store.any.js\", // ReferenceError: promise_test is not defined\n  \"request-cache-only-if-cached.any.js\", // ReferenceError: promise_test is not defined\n  \"request-cache-reload.any.js\", // ReferenceError: promise_test is not defined\n];\n\nconst __filename = fileURLToPath(import.meta.url);\nconst basename = path.basename(__filename);\nconst subDir = basename\n  .replace(/\\.test\\.[jt]s$/, \"\")\n  .split(\".\")\n  .join(path.sep);\n\nconst CWD = process.cwd();\nconst baseDir = path.join(CWD, \"wpt\");\nconst targetDir = path.join(baseDir, subDir);\n\nconst testFiles = fs\n  .readdirSync(targetDir)\n  .filter((file) => file.endsWith(\".any.js\"));\n\ndescribe(subDir, () => {\n  for (const file of testFiles) {\n    if (!SKIP_FILES.includes(file)) {\n      it(`should pass ${file} tests`, (done) => {\n        const filePath = path.join(targetDir, file);\n        const sourceCode = fs.readFileSync(filePath, \"utf8\");\n        runTestDynamic(sourceCode, baseDir, done);\n      });\n    }\n  }\n});\n"
  },
  {
    "path": "tests/wpt/fetch.api.response.test.ts",
    "content": "import { runTestDynamic } from \"./fetch.harness.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst SKIP_FILES = [\n  \"response-blob-realm.any.js\", // requires Window\n  \"response-clone.any.js\", // Error: Timeout after 5000ms\n];\n\nconst __filename = fileURLToPath(import.meta.url);\nconst basename = path.basename(__filename);\nconst subDir = basename\n  .replace(/\\.test\\.[jt]s$/, \"\")\n  .split(\".\")\n  .join(path.sep);\n\nconst CWD = process.cwd();\nconst baseDir = path.join(CWD, \"wpt\");\nconst targetDir = path.join(baseDir, subDir);\n\nconst testFiles = fs\n  .readdirSync(targetDir)\n  .filter((file) => file.endsWith(\".any.js\"));\n\ndescribe(subDir, () => {\n  for (const file of testFiles) {\n    if (!SKIP_FILES.includes(file)) {\n      it(`should pass ${file} tests`, (done) => {\n        const filePath = path.join(targetDir, file);\n        const sourceCode = fs.readFileSync(filePath, \"utf8\");\n        runTestDynamic(sourceCode, baseDir, done);\n      });\n    }\n  }\n});\n"
  },
  {
    "path": "tests/wpt/fetch.harness.js",
    "content": "import resourcesIdlharness from \"./resources/idlharness.js\";\nimport resourcesTestharness from \"./resources/testharness.js\";\n\nimport commonGc from \"./common/gc.js\";\nimport commonSubsetTests from \"./common/subset-tests.js\";\nimport getHostInfoSub from \"./common/get-host-info.sub.js\";\n\nimport encodings from \"./encoding/resources/encodings.js\";\n\nimport fetchKeepaliveHelper from \"./fetch/api/resources/keepalive-helper.js\";\nimport fetchKeepaliveWorker from \"./fetch/api/resources/keepalive-worker.js\";\nimport fetchSwInterceptAbort from \"./fetch/api/resources/sw-intercept-abort.js\";\nimport fetchSwIntercept from \"./fetch/api/resources/sw-intercept.js\";\nimport fetchUtils from \"./fetch/api/resources/utils.js\";\nimport fetchRequestRequestCache from \"./fetch/api/request/request-cache.js\";\nimport fetchRequestRequestError from \"./fetch/api/request/request-error.js\";\n\nexport const runTestDynamic = (testSource, baseDir, done) => {\n  globalThis._fetch = globalThis.fetch;\n\n  const context = {\n    createBuffer: (type, length) => new self[type](length),\n    encodings_table: encodings,\n    setTimeout: setTimeout,\n    DOMException: DOMException,\n    location: {\n      href: \"http://web-platform.test:8000/fetch/api/resources/\",\n      origin: \"http://web-platform.test\",\n      protocol: \"http:\",\n      host: \"web-platform.test\",\n      hostname: \"web-platform.test\",\n      port: \"8000\",\n      pathname: \"/fetch/api/resources/\",\n      search: \"\",\n      hash: \"\",\n    },\n    RESOURCES_DIR: \"http://web-platform.test:8000/fetch/api/resources/\",\n\n    fetch: (url, option) => {\n      let data;\n      switch (url) {\n        case \"../cors/resources/not-cors-safelisted.json\":\n          data = require(\n            baseDir + \"/fetch/api/cors/resources/not-cors-safelisted.json\"\n          );\n          break;\n        case \"../resources/data.json\":\n          data = require(baseDir + \"/fetch/api/resources/data.json\");\n          break;\n        default:\n          let absolute_url = url;\n          if (url.startsWith(\"../\")) {\n            absolute_url =\n              \"http://web-platform.test:8000/fetch/api/resources/\" + url;\n          }\n          return _fetch(absolute_url, option);\n      }\n      return Promise.resolve({\n        json: () => Promise.resolve(data),\n      });\n    },\n  };\n\n  resourcesIdlharness(context);\n  resourcesTestharness(context);\n\n  commonGc(context);\n  commonSubsetTests(context);\n  getHostInfoSub(context);\n\n  fetchKeepaliveHelper(context);\n  // fetchKeepaliveWorker(context);\n  // fetchSwInterceptAbort(context);\n  // fetchSwIntercept(context);\n  fetchUtils(context);\n  fetchRequestRequestCache(context);\n  fetchRequestRequestError(context);\n\n  context.setup({\n    explicit_done: true,\n    debug: process.env.DEBUG !== undefined,\n  });\n\n  globalThis.gc = globalThis.__gc;\n\n  context.add_completion_callback((tests, status, assertions) => {\n    if (\n      tests.filter(\n        ({ name, status }) => !(name === \"Loading data...\" && status === 0)\n      ).length === 0\n    ) {\n      done(new Error(\"No tests were executed!\"));\n    }\n    const failure = tests.find((test) => test.status !== 0);\n    if (failure) {\n      const message = `[${failure.name}] ${failure.message || String(failure)}`;\n      done(message);\n      return;\n    }\n    done();\n  });\n\n  wrapTestSuite(testSource)(context);\n\n  context.done();\n};\n\nfunction wrapTestSuite(sourceCode) {\n  return new Function(\n    \"context\",\n    `\n      with (context) {\n        ${sourceCode}\n      }\n    `\n  );\n}\n"
  },
  {
    "path": "tests/wpt/hr-time.harness.js",
    "content": "import resourcesIdlharness from \"./resources/idlharness.js\";\nimport resourcesTestharness from \"./resources/testharness.js\";\n\nimport commonGc from \"./common/gc.js\";\nimport commonSubsetTests from \"./common/subset-tests.js\";\n\nimport encodings from \"./encoding/resources/encodings.js\";\n\nexport const runTestDynamic = (testSource, done) => {\n  const context = {\n    createBuffer: (type, length) => new self[type](length),\n    encodings_table: encodings,\n    setTimeout: setTimeout,\n    DOMException: DOMException,\n    location: {},\n  };\n\n  resourcesIdlharness(context);\n  resourcesTestharness(context);\n\n  commonGc(context);\n  commonSubsetTests(context);\n\n  context.setup({\n    explicit_done: true,\n    debug: process.env.DEBUG !== undefined,\n  });\n\n  globalThis.gc = globalThis.__gc;\n\n  context.add_completion_callback((tests, status, assertions) => {\n    if (\n      tests.filter(\n        ({ name, status }) => !(name === \"Loading data...\" && status === 0)\n      ).length === 0\n    ) {\n      done(new Error(\"No tests were executed!\"));\n    }\n    const failure = tests.find((test) => test.status !== 0);\n    if (failure) {\n      const message = `[${failure.name}] ${failure.message || String(failure)}`;\n      done(message);\n      return;\n    }\n    done();\n  });\n\n  wrapTestSuite(testSource)(context);\n\n  context.done();\n};\n\nfunction wrapTestSuite(sourceCode) {\n  return new Function(\n    \"context\",\n    `\n      with (context) {\n        ${sourceCode}\n      }\n    `\n  );\n}\n"
  },
  {
    "path": "tests/wpt/hr-time.test.ts",
    "content": "import { runTestDynamic } from \"./hr-time.harness.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst SKIP_FILES = [\n  \"idlharness.any.js\", // ReferenceError: idl_test is not defined\n];\n\nconst __filename = fileURLToPath(import.meta.url);\nconst basename = path.basename(__filename);\nconst subDir = basename\n  .replace(/\\.test\\.[jt]s$/, \"\")\n  .split(\".\")\n  .join(path.sep);\n\nconst CWD = process.cwd();\nconst baseDir = path.join(CWD, \"wpt\");\nconst targetDir = path.join(baseDir, subDir);\n\nconst testFiles = fs\n  .readdirSync(targetDir)\n  .filter((file) => file.endsWith(\".any.js\"));\n\ndescribe(subDir, () => {\n  for (const file of testFiles) {\n    if (!SKIP_FILES.includes(file)) {\n      it(`should pass ${file} tests`, (done) => {\n        const filePath = path.join(targetDir, file);\n        const sourceCode = fs.readFileSync(filePath, \"utf8\");\n        runTestDynamic(sourceCode, done);\n      });\n    }\n  }\n});\n"
  },
  {
    "path": "tests/wpt/resources/idlharness.js",
    "content": "/* For user documentation see docs/_writing-tests/idlharness.md */\n\n/**\n * Notes for people who want to edit this file (not just use it as a library):\n *\n * Most of the interesting stuff happens in the derived classes of IdlObject,\n * especially IdlInterface.  The entry point for all IdlObjects is .test(),\n * which is called by IdlArray.test().  An IdlObject is conceptually just\n * \"thing we want to run tests on\", and an IdlArray is an array of IdlObjects\n * with some additional data thrown in.\n *\n * The object model is based on what WebIDLParser.js produces, which is in turn\n * based on its pegjs grammar.  If you want to figure out what properties an\n * object will have from WebIDLParser.js, the best way is to look at the\n * grammar:\n *\n *   https://github.com/darobin/webidl.js/blob/master/lib/grammar.peg\n *\n * So for instance:\n *\n *   // interface definition\n *   interface\n *       =   extAttrs:extendedAttributeList? S? \"interface\" S name:identifier w herit:ifInheritance? w \"{\" w mem:ifMember* w \"}\" w \";\" w\n *           { return { type: \"interface\", name: name, inheritance: herit, members: mem, extAttrs: extAttrs }; }\n *\n * This means that an \"interface\" object will have a .type property equal to\n * the string \"interface\", a .name property equal to the identifier that the\n * parser found, an .inheritance property equal to either null or the result of\n * the \"ifInheritance\" production found elsewhere in the grammar, and so on.\n * After each grammatical production is a JavaScript function in curly braces\n * that gets called with suitable arguments and returns some JavaScript value.\n *\n * (Note that the version of WebIDLParser.js we use might sometimes be\n * out-of-date or forked.)\n *\n * The members and methods of the classes defined by this file are all at least\n * briefly documented, hopefully.\n */\nexport default function (self) {\n  (function () {\n    \"use strict\";\n    // Support subsetTestByKey from /common/subset-tests-by-key.js, but make it optional\n    if (!(\"subsetTestByKey\" in self)) {\n      self.subsetTestByKey = function (key, callback, ...args) {\n        return callback(...args);\n      };\n      self.shouldRunSubTest = () => true;\n    }\n    /// Helpers ///\n    function constValue(cnt) {\n      if (cnt.type === \"null\") return null;\n      if (cnt.type === \"NaN\") return NaN;\n      if (cnt.type === \"Infinity\") return cnt.negative ? -Infinity : Infinity;\n      if (cnt.type === \"number\") return +cnt.value;\n      return cnt.value;\n    }\n\n    function minOverloadLength(overloads) {\n      // \"The value of the Function object’s “length” property is\n      // a Number determined as follows:\n      // \". . .\n      // \"Return the length of the shortest argument list of the\n      // entries in S.\"\n      if (!overloads.length) {\n        return 0;\n      }\n\n      return overloads\n        .map(function (attr) {\n          return attr.arguments\n            ? attr.arguments.filter(function (arg) {\n                return !arg.optional && !arg.variadic;\n              }).length\n            : 0;\n        })\n        .reduce(function (m, n) {\n          return Math.min(m, n);\n        });\n    }\n\n    // A helper to get the global of a Function object.  This is needed to determine\n    // which global exceptions the function throws will come from.\n    function globalOf(func) {\n      try {\n        // Use the fact that .constructor for a Function object is normally the\n        // Function constructor, which can be used to mint a new function in the\n        // right global.\n        return func.constructor(\"return this;\")();\n      } catch (e) {}\n      // If the above fails, because someone gave us a non-function, or a function\n      // with a weird proto chain or weird .constructor property, just fall back\n      // to 'self'.\n      return self;\n    }\n\n    // https://esdiscuss.org/topic/isconstructor#content-11\n    function isConstructor(o) {\n      try {\n        new new Proxy(o, { construct: () => ({}) })();\n        return true;\n      } catch (e) {\n        return false;\n      }\n    }\n\n    function throwOrReject(a_test, operation, fn, obj, args, message, cb) {\n      if (operation.idlType.generic !== \"Promise\") {\n        assert_throws_js(\n          globalOf(fn).TypeError,\n          function () {\n            fn.apply(obj, args);\n          },\n          message\n        );\n        cb();\n      } else {\n        try {\n          promise_rejects_js(\n            a_test,\n            TypeError,\n            fn.apply(obj, args),\n            message\n          ).then(cb, cb);\n        } catch (e) {\n          a_test.step(function () {\n            assert_unreached('Throws \"' + e + '\" instead of rejecting promise');\n            cb();\n          });\n        }\n      }\n    }\n\n    function awaitNCallbacks(n, cb, ctx) {\n      var counter = 0;\n      return function () {\n        counter++;\n        if (counter >= n) {\n          cb();\n        }\n      };\n    }\n\n    /// IdlHarnessError ///\n    // Entry point\n    const IdlHarnessError = function (message) {\n      /**\n       * Message to be printed as the error's toString invocation.\n       */\n      this.message = message;\n    };\n\n    IdlHarnessError.prototype = Object.create(Error.prototype);\n\n    IdlHarnessError.prototype.toString = function () {\n      return this.message;\n    };\n\n    /// IdlArray ///\n    // Entry point\n    const IdlArray = function () {\n      /**\n       * A map from strings to the corresponding named IdlObject, such as\n       * IdlInterface or IdlException.  These are the things that test() will run\n       * tests on.\n       */\n      this.members = {};\n\n      /**\n       * A map from strings to arrays of strings.  The keys are interface or\n       * exception names, and are expected to also exist as keys in this.members\n       * (otherwise they'll be ignored).  This is populated by add_objects() --\n       * see documentation at the start of the file.  The actual tests will be\n       * run by calling this.members[name].test_object(obj) for each obj in\n       * this.objects[name].  obj is a string that will be eval'd to produce a\n       * JavaScript value, which is supposed to be an object implementing the\n       * given IdlObject (interface, exception, etc.).\n       */\n      this.objects = {};\n\n      /**\n       * When adding multiple collections of IDLs one at a time, an earlier one\n       * might contain a partial interface or includes statement that depends\n       * on a later one.  Save these up and handle them right before we run\n       * tests.\n       *\n       * Both this.partials and this.includes will be the objects as parsed by\n       * WebIDLParser.js, not wrapped in IdlInterface or similar.\n       */\n      this.partials = [];\n      this.includes = [];\n\n      /**\n       * Record of skipped IDL items, in case we later realize that they are a\n       * dependency (to retroactively process them).\n       */\n      this.skipped = new Map();\n    };\n\n    IdlArray.prototype.add_idls = function (raw_idls, options) {\n      /** Entry point.  See documentation at beginning of file. */\n      this.internal_add_idls(WebIDL2.parse(raw_idls), options);\n    };\n\n    IdlArray.prototype.add_untested_idls = function (raw_idls, options) {\n      /** Entry point.  See documentation at beginning of file. */\n      var parsed_idls = WebIDL2.parse(raw_idls);\n      this.mark_as_untested(parsed_idls);\n      this.internal_add_idls(parsed_idls, options);\n    };\n\n    IdlArray.prototype.mark_as_untested = function (parsed_idls) {\n      for (var i = 0; i < parsed_idls.length; i++) {\n        parsed_idls[i].untested = true;\n        if (\"members\" in parsed_idls[i]) {\n          for (var j = 0; j < parsed_idls[i].members.length; j++) {\n            parsed_idls[i].members[j].untested = true;\n          }\n        }\n      }\n    };\n\n    IdlArray.prototype.is_excluded_by_options = function (name, options) {\n      return (\n        options &&\n        ((options.except && options.except.includes(name)) ||\n          (options.only && !options.only.includes(name)))\n      );\n    };\n\n    IdlArray.prototype.add_dependency_idls = function (raw_idls, options) {\n      return this.internal_add_dependency_idls(\n        WebIDL2.parse(raw_idls),\n        options\n      );\n    };\n\n    IdlArray.prototype.internal_add_dependency_idls = function (\n      parsed_idls,\n      options\n    ) {\n      const new_options = { only: [] };\n\n      const all_deps = new Set();\n      Object.values(this.members).forEach((v) => {\n        if (v.base) {\n          all_deps.add(v.base);\n        }\n      });\n      // Add both 'A' and 'B' for each 'A includes B' entry.\n      this.includes.forEach((i) => {\n        all_deps.add(i.target);\n        all_deps.add(i.includes);\n      });\n      this.partials.forEach((p) => all_deps.add(p.name));\n      // Add 'TypeOfType' for each \"typedef TypeOfType MyType;\" entry.\n      Object.entries(this.members).forEach(([k, v]) => {\n        if (v instanceof IdlTypedef) {\n          let defs = v.idlType.union\n            ? v.idlType.idlType.map((t) => t.idlType)\n            : [v.idlType.idlType];\n          defs.forEach((d) => all_deps.add(d));\n        }\n      });\n\n      // Add the attribute idlTypes of all the nested members of idls.\n      const attrDeps = (parsedIdls) => {\n        return parsedIdls.reduce((deps, parsed) => {\n          if (parsed.members) {\n            for (const attr of Object.values(parsed.members).filter(\n              (m) => m.type === \"attribute\"\n            )) {\n              let attrType = attr.idlType;\n              // Check for generic members (e.g. FrozenArray<MyType>)\n              if (attrType.generic) {\n                deps.add(attrType.generic);\n                attrType = attrType.idlType;\n              }\n              deps.add(attrType.idlType);\n            }\n          }\n          if (parsed.base in this.members) {\n            attrDeps([this.members[parsed.base]]).forEach((dep) =>\n              deps.add(dep)\n            );\n          }\n          return deps;\n        }, new Set());\n      };\n\n      const testedMembers = Object.values(this.members).filter(\n        (m) => !m.untested && m.members\n      );\n      attrDeps(testedMembers).forEach((dep) => all_deps.add(dep));\n\n      const testedPartials = this.partials.filter(\n        (m) => !m.untested && m.members\n      );\n      attrDeps(testedPartials).forEach((dep) => all_deps.add(dep));\n\n      if (options && options.except && options.only) {\n        throw new IdlHarnessError(\n          \"The only and except options can't be used together.\"\n        );\n      }\n\n      const defined_or_untested = (name) => {\n        // NOTE: Deps are untested, so we're lenient, and skip re-encountered definitions.\n        // e.g. for 'idl' containing A:B, B:C, C:D\n        //      array.add_idls(idl, {only: ['A','B']}).\n        //      array.add_dependency_idls(idl);\n        // B would be encountered as tested, and encountered as a dep, so we ignore.\n        return (\n          name in this.members || this.is_excluded_by_options(name, options)\n        );\n      };\n      // Maps name -> [parsed_idl, ...]\n      const process = function (parsed) {\n        var deps = [];\n        if (parsed.name) {\n          deps.push(parsed.name);\n        } else if (parsed.type === \"includes\") {\n          deps.push(parsed.target);\n          deps.push(parsed.includes);\n        }\n\n        deps = deps.filter(\n          function (name) {\n            if (\n              !name ||\n              (name === parsed.name && defined_or_untested(name)) ||\n              !all_deps.has(name)\n            ) {\n              // Flag as skipped, if it's not already processed, so we can\n              // come back to it later if we retrospectively call it a dep.\n              if (name && !(name in this.members)) {\n                this.skipped.has(name)\n                  ? this.skipped.get(name).push(parsed)\n                  : this.skipped.set(name, [parsed]);\n              }\n              return false;\n            }\n            return true;\n          }.bind(this)\n        );\n\n        deps.forEach(\n          function (name) {\n            if (!new_options.only.includes(name)) {\n              new_options.only.push(name);\n            }\n\n            const follow_up = new Set();\n            for (const dep_type of [\"inheritance\", \"includes\"]) {\n              if (parsed[dep_type]) {\n                const inheriting = parsed[dep_type];\n                const inheritor = parsed.name || parsed.target;\n                const deps = [inheriting];\n                // For A includes B, we can ignore A, unless B (or some of its\n                // members) is being tested.\n                if (\n                  dep_type !== \"includes\" ||\n                  (inheriting in this.members &&\n                    !this.members[inheriting].untested) ||\n                  this.partials.some(function (p) {\n                    return p.name === inheriting;\n                  })\n                ) {\n                  deps.push(inheritor);\n                }\n                for (const dep of deps) {\n                  if (!new_options.only.includes(dep)) {\n                    new_options.only.push(dep);\n                  }\n                  all_deps.add(dep);\n                  follow_up.add(dep);\n                }\n              }\n            }\n\n            for (const deferred of follow_up) {\n              if (this.skipped.has(deferred)) {\n                const next = this.skipped.get(deferred);\n                this.skipped.delete(deferred);\n                next.forEach(process);\n              }\n            }\n          }.bind(this)\n        );\n      }.bind(this);\n\n      for (let parsed of parsed_idls) {\n        process(parsed);\n      }\n\n      this.mark_as_untested(parsed_idls);\n\n      if (new_options.only.length) {\n        this.internal_add_idls(parsed_idls, new_options);\n      }\n    };\n\n    IdlArray.prototype.internal_add_idls = function (parsed_idls, options) {\n      /**\n       * Internal helper called by add_idls() and add_untested_idls().\n       *\n       * parsed_idls is an array of objects that come from WebIDLParser.js's\n       * \"definitions\" production.  The add_untested_idls() entry point\n       * additionally sets an .untested property on each object (and its\n       * .members) so that they'll be skipped by test() -- they'll only be\n       * used for base interfaces of tested interfaces, return types, etc.\n       *\n       * options is a dictionary that can have an only or except member which are\n       * arrays. If only is given then only members, partials and interface\n       * targets listed will be added, and if except is given only those that\n       * aren't listed will be added. Only one of only and except can be used.\n       */\n\n      if (options && options.only && options.except) {\n        throw new IdlHarnessError(\n          \"The only and except options can't be used together.\"\n        );\n      }\n\n      var should_skip = (name) => {\n        return this.is_excluded_by_options(name, options);\n      };\n\n      parsed_idls.forEach(\n        function (parsed_idl) {\n          var partial_types = [\n            \"interface\",\n            \"interface mixin\",\n            \"dictionary\",\n            \"namespace\",\n          ];\n          if (parsed_idl.partial && partial_types.includes(parsed_idl.type)) {\n            if (should_skip(parsed_idl.name)) {\n              return;\n            }\n            this.partials.push(parsed_idl);\n            return;\n          }\n\n          if (parsed_idl.type == \"includes\") {\n            if (should_skip(parsed_idl.target)) {\n              return;\n            }\n            this.includes.push(parsed_idl);\n            return;\n          }\n\n          parsed_idl.array = this;\n          if (should_skip(parsed_idl.name)) {\n            return;\n          }\n          if (parsed_idl.name in this.members) {\n            throw new IdlHarnessError(\n              \"Duplicate identifier \" + parsed_idl.name\n            );\n          }\n\n          switch (parsed_idl.type) {\n            case \"interface\":\n              this.members[parsed_idl.name] = new IdlInterface(\n                parsed_idl,\n                /* is_callback = */ false,\n                /* is_mixin = */ false\n              );\n              break;\n\n            case \"interface mixin\":\n              this.members[parsed_idl.name] = new IdlInterface(\n                parsed_idl,\n                /* is_callback = */ false,\n                /* is_mixin = */ true\n              );\n              break;\n\n            case \"dictionary\":\n              // Nothing to test, but we need the dictionary info around for type\n              // checks\n              this.members[parsed_idl.name] = new IdlDictionary(parsed_idl);\n              break;\n\n            case \"typedef\":\n              this.members[parsed_idl.name] = new IdlTypedef(parsed_idl);\n              break;\n\n            case \"callback\":\n              this.members[parsed_idl.name] = new IdlCallback(parsed_idl);\n              break;\n\n            case \"enum\":\n              this.members[parsed_idl.name] = new IdlEnum(parsed_idl);\n              break;\n\n            case \"callback interface\":\n              this.members[parsed_idl.name] = new IdlInterface(\n                parsed_idl,\n                /* is_callback = */ true,\n                /* is_mixin = */ false\n              );\n              break;\n\n            case \"namespace\":\n              this.members[parsed_idl.name] = new IdlNamespace(parsed_idl);\n              break;\n\n            default:\n              throw (\n                parsed_idl.name + \": \" + parsed_idl.type + \" not yet supported\"\n              );\n          }\n        }.bind(this)\n      );\n    };\n\n    IdlArray.prototype.add_objects = function (dict) {\n      /** Entry point.  See documentation at beginning of file. */\n      for (var k in dict) {\n        if (k in this.objects) {\n          this.objects[k] = this.objects[k].concat(dict[k]);\n        } else {\n          this.objects[k] = dict[k];\n        }\n      }\n    };\n\n    IdlArray.prototype.prevent_multiple_testing = function (name) {\n      /** Entry point.  See documentation at beginning of file. */\n      this.members[name].prevent_multiple_testing = true;\n    };\n\n    IdlArray.prototype.is_json_type = function (type) {\n      /**\n       * Checks whether type is a JSON type as per\n       * https://webidl.spec.whatwg.org/#dfn-json-types\n       */\n\n      var idlType = type.idlType;\n\n      if (type.generic == \"Promise\") {\n        return false;\n      }\n\n      //  nullable and annotated types don't need to be handled separately,\n      //  as webidl2 doesn't represent them wrapped-up (as they're described\n      //  in WebIDL).\n\n      // union and record types\n      if (type.union || type.generic == \"record\") {\n        return idlType.every(this.is_json_type, this);\n      }\n\n      // sequence types\n      if (type.generic == \"sequence\" || type.generic == \"FrozenArray\") {\n        return this.is_json_type(idlType[0]);\n      }\n\n      if (typeof idlType != \"string\") {\n        throw new Error(\"Unexpected type \" + JSON.stringify(idlType));\n      }\n\n      switch (idlType) {\n        //  Numeric types\n        case \"byte\":\n        case \"octet\":\n        case \"short\":\n        case \"unsigned short\":\n        case \"long\":\n        case \"unsigned long\":\n        case \"long long\":\n        case \"unsigned long long\":\n        case \"float\":\n        case \"double\":\n        case \"unrestricted float\":\n        case \"unrestricted double\":\n        // boolean\n        case \"boolean\":\n        // string types\n        case \"DOMString\":\n        case \"ByteString\":\n        case \"USVString\":\n        // object type\n        case \"object\":\n          return true;\n        case \"Error\":\n        case \"DOMException\":\n        case \"Int8Array\":\n        case \"Int16Array\":\n        case \"Int32Array\":\n        case \"Uint8Array\":\n        case \"Uint16Array\":\n        case \"Uint32Array\":\n        case \"Uint8ClampedArray\":\n        case \"BigInt64Array\":\n        case \"BigUint64Array\":\n        case \"Float16Array\":\n        case \"Float32Array\":\n        case \"Float64Array\":\n        case \"ArrayBuffer\":\n        case \"DataView\":\n        case \"any\":\n          return false;\n        default:\n          var thing = this.members[idlType];\n          if (!thing) {\n            throw new Error(\"Type \" + idlType + \" not found\");\n          }\n          if (thing instanceof IdlEnum) {\n            return true;\n          }\n\n          if (thing instanceof IdlTypedef) {\n            return this.is_json_type(thing.idlType);\n          }\n\n          //  dictionaries where all of their members are JSON types\n          if (thing instanceof IdlDictionary) {\n            const map = new Map();\n            for (const dict of thing.get_reverse_inheritance_stack()) {\n              for (const m of dict.members) {\n                map.set(m.name, m.idlType);\n              }\n            }\n            return Array.from(map.values()).every(this.is_json_type, this);\n          }\n\n          //  interface types that have a toJSON operation declared on themselves or\n          //  one of their inherited interfaces.\n          if (thing instanceof IdlInterface) {\n            var base;\n            while (thing) {\n              if (thing.has_to_json_regular_operation()) {\n                return true;\n              }\n              var mixins = this.includes[thing.name];\n              if (mixins) {\n                mixins = mixins.map(function (id) {\n                  var mixin = this.members[id];\n                  if (!mixin) {\n                    throw new Error(\n                      \"Interface \" +\n                        id +\n                        \" not found (implemented by \" +\n                        thing.name +\n                        \")\"\n                    );\n                  }\n                  return mixin;\n                }, this);\n                if (\n                  mixins.some(function (m) {\n                    return m.has_to_json_regular_operation();\n                  })\n                ) {\n                  return true;\n                }\n              }\n              if (!thing.base) {\n                return false;\n              }\n              base = this.members[thing.base];\n              if (!base) {\n                throw new Error(\n                  \"Interface \" +\n                    thing.base +\n                    \" not found (inherited by \" +\n                    thing.name +\n                    \")\"\n                );\n              }\n              thing = base;\n            }\n            return false;\n          }\n          return false;\n      }\n    };\n\n    function exposure_set(object, default_set) {\n      var exposed =\n        object.extAttrs && object.extAttrs.filter((a) => a.name === \"Exposed\");\n      if (exposed && exposed.length > 1) {\n        throw new IdlHarnessError(\n          `Multiple 'Exposed' extended attributes on ${object.name}`\n        );\n      }\n\n      let result = default_set || [\"Window\"];\n      if (result && !(result instanceof Set)) {\n        result = new Set(result);\n      }\n      if (exposed && exposed.length) {\n        const { rhs } = exposed[0];\n        // Could be a list or a string.\n        const set =\n          rhs.type === \"*\"\n            ? [\"*\"]\n            : rhs.type === \"identifier-list\"\n              ? rhs.value.map((id) => id.value)\n              : [rhs.value];\n        result = new Set(set);\n      }\n      if (result && result.has(\"*\")) {\n        return \"*\";\n      }\n      if (result && result.has(\"Worker\")) {\n        result.delete(\"Worker\");\n        result.add(\"DedicatedWorker\");\n        result.add(\"ServiceWorker\");\n        result.add(\"SharedWorker\");\n      }\n      return result;\n    }\n\n    function exposed_in(globals) {\n      if (globals === \"*\") {\n        return true;\n      }\n      if (\"Window\" in self) {\n        return globals.has(\"Window\");\n      }\n      if (\n        \"DedicatedWorkerGlobalScope\" in self &&\n        self instanceof DedicatedWorkerGlobalScope\n      ) {\n        return globals.has(\"DedicatedWorker\");\n      }\n      if (\n        \"SharedWorkerGlobalScope\" in self &&\n        self instanceof SharedWorkerGlobalScope\n      ) {\n        return globals.has(\"SharedWorker\");\n      }\n      if (\n        \"ServiceWorkerGlobalScope\" in self &&\n        self instanceof ServiceWorkerGlobalScope\n      ) {\n        return globals.has(\"ServiceWorker\");\n      }\n      if (Object.getPrototypeOf(self) === Object.prototype) {\n        // ShadowRealm - only exposed with `\"*\"`.\n        return false;\n      }\n      throw new IdlHarnessError(\"Unexpected global object\");\n    }\n\n    /**\n     * Asserts that the given error message is thrown for the given function.\n     * @param {string|IdlHarnessError} error Expected Error message.\n     * @param {Function} idlArrayFunc Function operating on an IdlArray that should throw.\n     */\n    IdlArray.prototype.assert_throws = function (error, idlArrayFunc) {\n      try {\n        idlArrayFunc.call(this, this);\n      } catch (e) {\n        if (e instanceof AssertionError) {\n          throw e;\n        }\n        // Assertions for behaviour of the idlharness.js engine.\n        if (error instanceof IdlHarnessError) {\n          error = error.message;\n        }\n        if (e.message !== error) {\n          throw new IdlHarnessError(\n            `${idlArrayFunc} threw \"${e}\", not the expected IdlHarnessError \"${error}\"`\n          );\n        }\n        return;\n      }\n      throw new IdlHarnessError(\n        `${idlArrayFunc} did not throw the expected IdlHarnessError`\n      );\n    };\n\n    IdlArray.prototype.test = function () {\n      /** Entry point.  See documentation at beginning of file. */\n\n      // First merge in all partial definitions and interface mixins.\n      this.merge_partials();\n      this.merge_mixins();\n\n      // Assert B defined for A : B\n      for (const member of Object.values(this.members).filter((m) => m.base)) {\n        const lhs = member.name;\n        const rhs = member.base;\n        if (!(rhs in this.members))\n          throw new IdlHarnessError(\n            `${lhs} inherits ${rhs}, but ${rhs} is undefined.`\n          );\n        const lhs_is_interface = this.members[lhs] instanceof IdlInterface;\n        const rhs_is_interface = this.members[rhs] instanceof IdlInterface;\n        if (rhs_is_interface != lhs_is_interface) {\n          if (!lhs_is_interface)\n            throw new IdlHarnessError(\n              `${lhs} inherits ${rhs}, but ${lhs} is not an interface.`\n            );\n          if (!rhs_is_interface)\n            throw new IdlHarnessError(\n              `${lhs} inherits ${rhs}, but ${rhs} is not an interface.`\n            );\n        }\n        // Check for circular dependencies.\n        member.get_reverse_inheritance_stack();\n      }\n\n      Object.getOwnPropertyNames(this.members).forEach(\n        function (memberName) {\n          var member = this.members[memberName];\n          if (!(member instanceof IdlInterface)) {\n            return;\n          }\n\n          var globals = exposure_set(member);\n          member.exposed = exposed_in(globals);\n          member.exposureSet = globals;\n        }.bind(this)\n      );\n\n      // Now run test() on every member, and test_object() for every object.\n      for (var name in this.members) {\n        this.members[name].test();\n        if (name in this.objects) {\n          const objects = this.objects[name];\n          if (!objects || !Array.isArray(objects)) {\n            throw new IdlHarnessError(\n              `Invalid or empty objects for member ${name}`\n            );\n          }\n          objects.forEach(\n            function (str) {\n              if (\n                !this.members[name] ||\n                !(this.members[name] instanceof IdlInterface)\n              ) {\n                throw new IdlHarnessError(`Invalid object member name ${name}`);\n              }\n              this.members[name].test_object(str);\n            }.bind(this)\n          );\n        }\n      }\n    };\n\n    IdlArray.prototype.merge_partials = function () {\n      const testedPartials = new Map();\n      this.partials.forEach(\n        function (parsed_idl) {\n          const originalExists =\n            parsed_idl.name in this.members &&\n            (this.members[parsed_idl.name] instanceof IdlInterface ||\n              this.members[parsed_idl.name] instanceof IdlDictionary ||\n              this.members[parsed_idl.name] instanceof IdlNamespace);\n\n          // Ensure unique test name in case of multiple partials.\n          let partialTestName = parsed_idl.name;\n          let partialTestCount = 1;\n          if (testedPartials.has(parsed_idl.name)) {\n            partialTestCount += testedPartials.get(parsed_idl.name);\n            partialTestName = `${partialTestName}[${partialTestCount}]`;\n          }\n          testedPartials.set(parsed_idl.name, partialTestCount);\n\n          if (!parsed_idl.untested) {\n            test(\n              function () {\n                assert_true(\n                  originalExists,\n                  `Original ${parsed_idl.type} should be defined`\n                );\n\n                var expected;\n                switch (parsed_idl.type) {\n                  case \"dictionary\":\n                    expected = IdlDictionary;\n                    break;\n                  case \"namespace\":\n                    expected = IdlNamespace;\n                    break;\n                  case \"interface\":\n                  case \"interface mixin\":\n                  default:\n                    expected = IdlInterface;\n                    break;\n                }\n                assert_true(\n                  expected.prototype.isPrototypeOf(\n                    this.members[parsed_idl.name]\n                  ),\n                  `Original ${parsed_idl.name} definition should have type ${parsed_idl.type}`\n                );\n              }.bind(this),\n              `Partial ${parsed_idl.type} ${partialTestName}: original ${parsed_idl.type} defined`\n            );\n          }\n          if (!originalExists) {\n            // Not good.. but keep calm and carry on.\n            return;\n          }\n\n          if (parsed_idl.extAttrs) {\n            // Special-case \"Exposed\". Must be a subset of original interface's exposure.\n            // Exposed on a partial is the equivalent of having the same Exposed on all nested members.\n            // See https://github.com/heycam/webidl/issues/154 for discrepency between Exposed and\n            // other extended attributes on partial interfaces.\n            const exposureAttr = parsed_idl.extAttrs.find(\n              (a) => a.name === \"Exposed\"\n            );\n            if (exposureAttr) {\n              if (!parsed_idl.untested) {\n                test(\n                  function () {\n                    const partialExposure = exposure_set(parsed_idl);\n                    const memberExposure = exposure_set(\n                      this.members[parsed_idl.name]\n                    );\n                    if (memberExposure === \"*\") {\n                      return;\n                    }\n                    if (partialExposure === \"*\") {\n                      throw new IdlHarnessError(\n                        `Partial ${parsed_idl.name} ${parsed_idl.type} is exposed everywhere, the original ${parsed_idl.type} is not.`\n                      );\n                    }\n                    partialExposure.forEach((name) => {\n                      if (!memberExposure || !memberExposure.has(name)) {\n                        throw new IdlHarnessError(\n                          `Partial ${parsed_idl.name} ${parsed_idl.type} is exposed to '${name}', the original ${parsed_idl.type} is not.`\n                        );\n                      }\n                    });\n                  }.bind(this),\n                  `Partial ${parsed_idl.type} ${partialTestName}: valid exposure set`\n                );\n              }\n              parsed_idl.members.forEach(\n                function (member) {\n                  member.extAttrs.push(exposureAttr);\n                }.bind(this)\n              );\n            }\n\n            parsed_idl.extAttrs.forEach(\n              function (extAttr) {\n                // \"Exposed\" already handled above.\n                if (extAttr.name === \"Exposed\") {\n                  return;\n                }\n                this.members[parsed_idl.name].extAttrs.push(extAttr);\n              }.bind(this)\n            );\n          }\n          if (parsed_idl.members.length) {\n            test(\n              function () {\n                var clash = parsed_idl.members.find(\n                  function (member) {\n                    return this.members[parsed_idl.name].members.find(\n                      function (m) {\n                        return this.are_duplicate_members(m, member);\n                      }.bind(this)\n                    );\n                  }.bind(this)\n                );\n                parsed_idl.members.forEach(\n                  function (member) {\n                    this.members[parsed_idl.name].members.push(\n                      new IdlInterfaceMember(member)\n                    );\n                  }.bind(this)\n                );\n                assert_true(\n                  !clash,\n                  \"member \" + (clash && clash.name) + \" is unique\"\n                );\n              }.bind(this),\n              `Partial ${parsed_idl.type} ${partialTestName}: member names are unique`\n            );\n          }\n        }.bind(this)\n      );\n      this.partials = [];\n    };\n\n    IdlArray.prototype.merge_mixins = function () {\n      for (const parsed_idl of this.includes) {\n        const lhs = parsed_idl.target;\n        const rhs = parsed_idl.includes;\n\n        var errStr = lhs + \" includes \" + rhs + \", but \";\n        if (!(lhs in this.members)) throw errStr + lhs + \" is undefined.\";\n        if (!(this.members[lhs] instanceof IdlInterface))\n          throw errStr + lhs + \" is not an interface.\";\n        if (!(rhs in this.members)) throw errStr + rhs + \" is undefined.\";\n        if (!(this.members[rhs] instanceof IdlInterface))\n          throw errStr + rhs + \" is not an interface.\";\n\n        if (this.members[rhs].members.length) {\n          test(\n            function () {\n              var clash = this.members[rhs].members.find(\n                function (member) {\n                  return this.members[lhs].members.find(\n                    function (m) {\n                      return this.are_duplicate_members(m, member);\n                    }.bind(this)\n                  );\n                }.bind(this)\n              );\n              this.members[rhs].members.forEach(\n                function (member) {\n                  assert_true(\n                    this.members[lhs].members.every(\n                      (m) => !this.are_duplicate_members(m, member)\n                    ),\n                    \"member \" + member.name + \" is unique\"\n                  );\n                  this.members[lhs].members.push(\n                    new IdlInterfaceMember(member)\n                  );\n                }.bind(this)\n              );\n              assert_true(\n                !clash,\n                \"member \" + (clash && clash.name) + \" is unique\"\n              );\n            }.bind(this),\n            lhs + \" includes \" + rhs + \": member names are unique\"\n          );\n        }\n      }\n      this.includes = [];\n    };\n\n    IdlArray.prototype.are_duplicate_members = function (m1, m2) {\n      if (m1.name !== m2.name) {\n        return false;\n      }\n      if (\n        m1.type === \"operation\" &&\n        m2.type === \"operation\" &&\n        m1.arguments.length !== m2.arguments.length\n      ) {\n        // Method overload. TODO: Deep comparison of arguments.\n        return false;\n      }\n      return true;\n    };\n\n    IdlArray.prototype.assert_type_is = function (value, type) {\n      if (\n        type.idlType in this.members &&\n        this.members[type.idlType] instanceof IdlTypedef\n      ) {\n        this.assert_type_is(value, this.members[type.idlType].idlType);\n        return;\n      }\n\n      if (type.nullable && value === null) {\n        // This is fine\n        return;\n      }\n\n      if (type.union) {\n        for (var i = 0; i < type.idlType.length; i++) {\n          try {\n            this.assert_type_is(value, type.idlType[i]);\n            // No AssertionError, so we match one type in the union\n            return;\n          } catch (e) {\n            if (e instanceof AssertionError) {\n              // We didn't match this type, let's try some others\n              continue;\n            }\n            throw e;\n          }\n        }\n        // TODO: Is there a nice way to list the union's types in the message?\n        assert_true(\n          false,\n          \"Attribute has value \" +\n            format_value(value) +\n            \" which doesn't match any of the types in the union\"\n        );\n      }\n\n      /**\n       * Helper function that tests that value is an instance of type according\n       * to the rules of WebIDL.  value is any JavaScript value, and type is an\n       * object produced by WebIDLParser.js' \"type\" production.  That production\n       * is fairly elaborate due to the complexity of WebIDL's types, so it's\n       * best to look at the grammar to figure out what properties it might have.\n       */\n      if (type.idlType == \"any\") {\n        // No assertions to make\n        return;\n      }\n\n      if (type.array) {\n        // TODO: not supported yet\n        return;\n      }\n\n      if (type.generic === \"sequence\" || type.generic == \"ObservableArray\") {\n        assert_true(Array.isArray(value), \"should be an Array\");\n        if (!value.length) {\n          // Nothing we can do.\n          return;\n        }\n        this.assert_type_is(value[0], type.idlType[0]);\n        return;\n      }\n\n      if (type.generic === \"Promise\") {\n        assert_true(\n          \"then\" in value,\n          \"Attribute with a Promise type should have a then property\"\n        );\n        // TODO: Ideally, we would check on project fulfillment\n        // that we get the right type\n        // but that would require making the type check async\n        return;\n      }\n\n      if (type.generic === \"FrozenArray\") {\n        assert_true(Array.isArray(value), \"Value should be array\");\n        assert_true(Object.isFrozen(value), \"Value should be frozen\");\n        if (!value.length) {\n          // Nothing we can do.\n          return;\n        }\n        this.assert_type_is(value[0], type.idlType[0]);\n        return;\n      }\n\n      type = Array.isArray(type.idlType) ? type.idlType[0] : type.idlType;\n\n      switch (type) {\n        case \"undefined\":\n          assert_equals(value, undefined);\n          return;\n\n        case \"boolean\":\n          assert_equals(typeof value, \"boolean\");\n          return;\n\n        case \"byte\":\n          assert_equals(typeof value, \"number\");\n          assert_equals(value, Math.floor(value), \"should be an integer\");\n          assert_true(\n            -128 <= value && value <= 127,\n            \"byte \" + value + \" should be in range [-128, 127]\"\n          );\n          return;\n\n        case \"octet\":\n          assert_equals(typeof value, \"number\");\n          assert_equals(value, Math.floor(value), \"should be an integer\");\n          assert_true(\n            0 <= value && value <= 255,\n            \"octet \" + value + \" should be in range [0, 255]\"\n          );\n          return;\n\n        case \"short\":\n          assert_equals(typeof value, \"number\");\n          assert_equals(value, Math.floor(value), \"should be an integer\");\n          assert_true(\n            -32768 <= value && value <= 32767,\n            \"short \" + value + \" should be in range [-32768, 32767]\"\n          );\n          return;\n\n        case \"unsigned short\":\n          assert_equals(typeof value, \"number\");\n          assert_equals(value, Math.floor(value), \"should be an integer\");\n          assert_true(\n            0 <= value && value <= 65535,\n            \"unsigned short \" + value + \" should be in range [0, 65535]\"\n          );\n          return;\n\n        case \"long\":\n          assert_equals(typeof value, \"number\");\n          assert_equals(value, Math.floor(value), \"should be an integer\");\n          assert_true(\n            -2147483648 <= value && value <= 2147483647,\n            \"long \" + value + \" should be in range [-2147483648, 2147483647]\"\n          );\n          return;\n\n        case \"unsigned long\":\n          assert_equals(typeof value, \"number\");\n          assert_equals(value, Math.floor(value), \"should be an integer\");\n          assert_true(\n            0 <= value && value <= 4294967295,\n            \"unsigned long \" + value + \" should be in range [0, 4294967295]\"\n          );\n          return;\n\n        case \"long long\":\n          assert_equals(typeof value, \"number\");\n          return;\n\n        case \"unsigned long long\":\n        case \"DOMTimeStamp\":\n          assert_equals(typeof value, \"number\");\n          assert_true(0 <= value, \"unsigned long long should be positive\");\n          return;\n\n        case \"float\":\n          assert_equals(typeof value, \"number\");\n          assert_equals(\n            value,\n            Math.fround(value),\n            \"float rounded to 32-bit float should be itself\"\n          );\n          assert_not_equals(value, Infinity);\n          assert_not_equals(value, -Infinity);\n          assert_not_equals(value, NaN);\n          return;\n\n        case \"DOMHighResTimeStamp\":\n        case \"double\":\n          assert_equals(typeof value, \"number\");\n          assert_not_equals(value, Infinity);\n          assert_not_equals(value, -Infinity);\n          assert_not_equals(value, NaN);\n          return;\n\n        case \"unrestricted float\":\n          assert_equals(typeof value, \"number\");\n          assert_equals(\n            value,\n            Math.fround(value),\n            \"unrestricted float rounded to 32-bit float should be itself\"\n          );\n          return;\n\n        case \"unrestricted double\":\n          assert_equals(typeof value, \"number\");\n          return;\n\n        case \"DOMString\":\n          assert_equals(typeof value, \"string\");\n          return;\n\n        case \"ByteString\":\n          assert_equals(typeof value, \"string\");\n          assert_regexp_match(value, /^[\\x00-\\x7F]*$/);\n          return;\n\n        case \"USVString\":\n          assert_equals(typeof value, \"string\");\n          assert_regexp_match(\n            value,\n            /^([\\x00-\\ud7ff\\ue000-\\uffff]|[\\ud800-\\udbff][\\udc00-\\udfff])*$/\n          );\n          return;\n\n        case \"ArrayBufferView\":\n          assert_true(ArrayBuffer.isView(value));\n          return;\n\n        case \"object\":\n          assert_in_array(\n            typeof value,\n            [\"object\", \"function\"],\n            \"wrong type: not object or function\"\n          );\n          return;\n      }\n\n      // This is a catch-all for any IDL type name which follows JS class\n      // semantics. This includes some non-interface IDL types (e.g. Int8Array,\n      // Function, ...), as well as any interface types that are not in the IDL\n      // that is fed to the harness. If an IDL type does not follow JS class\n      // semantics then it should go in the switch statement above. If an IDL\n      // type needs full checking, then the test should include it in the IDL it\n      // feeds to the harness.\n      if (!(type in this.members)) {\n        assert_true(value instanceof self[type], \"wrong type: not a \" + type);\n        return;\n      }\n\n      if (this.members[type] instanceof IdlInterface) {\n        // We don't want to run the full\n        // IdlInterface.prototype.test_instance_of, because that could result\n        // in an infinite loop.  TODO: This means we don't have tests for\n        // LegacyNoInterfaceObject interfaces, and we also can't test objects\n        // that come from another self.\n        assert_in_array(\n          typeof value,\n          [\"object\", \"function\"],\n          \"wrong type: not object or function\"\n        );\n        if (\n          value instanceof Object &&\n          !this.members[type].has_extended_attribute(\n            \"LegacyNoInterfaceObject\"\n          ) &&\n          type in self\n        ) {\n          assert_true(value instanceof self[type], \"instanceof \" + type);\n        }\n      } else if (this.members[type] instanceof IdlEnum) {\n        assert_equals(typeof value, \"string\");\n      } else if (this.members[type] instanceof IdlDictionary) {\n        // TODO: Test when we actually have something to test this on\n      } else if (this.members[type] instanceof IdlCallback) {\n        assert_equals(typeof value, \"function\");\n      } else {\n        throw new IdlHarnessError(\n          \"Type \" + type + \" isn't an interface, callback or dictionary\"\n        );\n      }\n    };\n\n    /// IdlObject ///\n    function IdlObject() {}\n    IdlObject.prototype.test = function () {\n      /**\n       * By default, this does nothing, so no actual tests are run for IdlObjects\n       * that don't define any (e.g., IdlDictionary at the time of this writing).\n       */\n    };\n\n    IdlObject.prototype.has_extended_attribute = function (name) {\n      /**\n       * This is only meaningful for things that support extended attributes,\n       * such as interfaces, exceptions, and members.\n       */\n      return this.extAttrs.some(function (o) {\n        return o.name == name;\n      });\n    };\n\n    /// IdlDictionary ///\n    // Used for IdlArray.prototype.assert_type_is\n    function IdlDictionary(obj) {\n      /**\n       * obj is an object produced by the WebIDLParser.js \"dictionary\"\n       * production.\n       */\n\n      /** Self-explanatory. */\n      this.name = obj.name;\n\n      /** A back-reference to our IdlArray. */\n      this.array = obj.array;\n\n      /** An array of objects produced by the \"dictionaryMember\" production. */\n      this.members = obj.members;\n\n      /**\n       * The name (as a string) of the dictionary type we inherit from, or null\n       * if there is none.\n       */\n      this.base = obj.inheritance;\n    }\n\n    IdlDictionary.prototype = Object.create(IdlObject.prototype);\n\n    IdlDictionary.prototype.get_reverse_inheritance_stack = function () {\n      return IdlInterface.prototype.get_reverse_inheritance_stack.call(this);\n    };\n\n    /// IdlInterface ///\n    function IdlInterface(obj, is_callback, is_mixin) {\n      /**\n       * obj is an object produced by the WebIDLParser.js \"interface\" production.\n       */\n\n      /** Self-explanatory. */\n      this.name = obj.name;\n\n      /** A back-reference to our IdlArray. */\n      this.array = obj.array;\n\n      /**\n       * An indicator of whether we should run tests on the interface object and\n       * interface prototype object. Tests on members are controlled by .untested\n       * on each member, not this.\n       */\n      this.untested = obj.untested;\n\n      /** An array of objects produced by the \"ExtAttr\" production. */\n      this.extAttrs = obj.extAttrs;\n\n      /** An array of IdlInterfaceMembers. */\n      this.members = obj.members.map(function (m) {\n        return new IdlInterfaceMember(m);\n      });\n      if (this.has_extended_attribute(\"LegacyUnforgeable\")) {\n        this.members\n          .filter(function (m) {\n            return (\n              m.special !== \"static\" &&\n              (m.type == \"attribute\" || m.type == \"operation\")\n            );\n          })\n          .forEach(function (m) {\n            return (m.isUnforgeable = true);\n          });\n      }\n\n      /**\n       * The name (as a string) of the type we inherit from, or null if there is\n       * none.\n       */\n      this.base = obj.inheritance;\n\n      this._is_callback = is_callback;\n      this._is_mixin = is_mixin;\n    }\n    IdlInterface.prototype = Object.create(IdlObject.prototype);\n    IdlInterface.prototype.is_callback = function () {\n      return this._is_callback;\n    };\n\n    IdlInterface.prototype.is_mixin = function () {\n      return this._is_mixin;\n    };\n\n    IdlInterface.prototype.has_constants = function () {\n      return this.members.some(function (member) {\n        return member.type === \"const\";\n      });\n    };\n\n    IdlInterface.prototype.get_unscopables = function () {\n      return this.members.filter(function (member) {\n        return member.isUnscopable;\n      });\n    };\n\n    IdlInterface.prototype.is_global = function () {\n      return this.extAttrs.some(function (attribute) {\n        return attribute.name === \"Global\";\n      });\n    };\n\n    /**\n     * Value of the LegacyNamespace extended attribute, if any.\n     *\n     * https://webidl.spec.whatwg.org/#LegacyNamespace\n     */\n    IdlInterface.prototype.get_legacy_namespace = function () {\n      var legacyNamespace = this.extAttrs.find(function (attribute) {\n        return attribute.name === \"LegacyNamespace\";\n      });\n      return legacyNamespace ? legacyNamespace.rhs.value : undefined;\n    };\n\n    IdlInterface.prototype.get_interface_object_owner = function () {\n      var legacyNamespace = this.get_legacy_namespace();\n      return legacyNamespace ? self[legacyNamespace] : self;\n    };\n\n    IdlInterface.prototype.should_have_interface_object = function () {\n      // \"For every interface that is exposed in a given ECMAScript global\n      // environment and:\n      // * is a callback interface that has constants declared on it, or\n      // * is a non-callback interface that is not declared with the\n      //   [LegacyNoInterfaceObject] extended attribute,\n      // a corresponding property MUST exist on the ECMAScript global object.\n\n      return this.is_callback()\n        ? this.has_constants()\n        : !this.has_extended_attribute(\"LegacyNoInterfaceObject\");\n    };\n\n    IdlInterface.prototype.assert_interface_object_exists = function () {\n      var owner = this.get_legacy_namespace() || \"self\";\n      assert_own_property(\n        self[owner],\n        this.name,\n        owner + \" does not have own property \" + format_value(this.name)\n      );\n    };\n\n    IdlInterface.prototype.get_interface_object = function () {\n      if (!this.should_have_interface_object()) {\n        var reason = this.is_callback()\n          ? \"lack of declared constants\"\n          : \"declared [LegacyNoInterfaceObject] attribute\";\n        throw new IdlHarnessError(\n          this.name + \" has no interface object due to \" + reason\n        );\n      }\n\n      return this.get_interface_object_owner()[this.name];\n    };\n\n    IdlInterface.prototype.get_qualified_name = function () {\n      // https://webidl.spec.whatwg.org/#qualified-name\n      var legacyNamespace = this.get_legacy_namespace();\n      if (legacyNamespace) {\n        return legacyNamespace + \".\" + this.name;\n      }\n      return this.name;\n    };\n\n    IdlInterface.prototype.has_to_json_regular_operation = function () {\n      return this.members.some(function (m) {\n        return m.is_to_json_regular_operation();\n      });\n    };\n\n    IdlInterface.prototype.has_default_to_json_regular_operation = function () {\n      return this.members.some(function (m) {\n        return (\n          m.is_to_json_regular_operation() &&\n          m.has_extended_attribute(\"Default\")\n        );\n      });\n    };\n\n    /**\n     * Implementation of https://webidl.spec.whatwg.org/#create-an-inheritance-stack\n     * with the order reversed.\n     *\n     * The order is reversed so that the base class comes first in the list, because\n     * this is what all call sites need.\n     *\n     * So given:\n     *\n     *   A : B {};\n     *   B : C {};\n     *   C {};\n     *\n     * then A.get_reverse_inheritance_stack() returns [C, B, A],\n     * and B.get_reverse_inheritance_stack() returns [C, B].\n     *\n     * Note: as dictionary inheritance is expressed identically by the AST,\n     * this works just as well for getting a stack of inherited dictionaries.\n     */\n    IdlInterface.prototype.get_reverse_inheritance_stack = function () {\n      const stack = [this];\n      let idl_interface = this;\n      while (idl_interface.base) {\n        const base = this.array.members[idl_interface.base];\n        if (!base) {\n          throw new Error(\n            idl_interface.type +\n              \" \" +\n              idl_interface.base +\n              \" not found (inherited by \" +\n              idl_interface.name +\n              \")\"\n          );\n        } else if (stack.indexOf(base) > -1) {\n          stack.unshift(base);\n          const dep_chain = stack.map((i) => i.name).join(\",\");\n          throw new IdlHarnessError(\n            `${this.name} has a circular dependency: ${dep_chain}`\n          );\n        }\n        idl_interface = base;\n        stack.unshift(idl_interface);\n      }\n      return stack;\n    };\n\n    /**\n     * Implementation of\n     * https://webidl.spec.whatwg.org/#default-tojson-operation\n     * for testing purposes.\n     *\n     * Collects the IDL types of the attributes that meet the criteria\n     * for inclusion in the default toJSON operation for easy\n     * comparison with actual value\n     */\n    IdlInterface.prototype.default_to_json_operation = function () {\n      const map = new Map();\n      let isDefault = false;\n      for (const I of this.get_reverse_inheritance_stack()) {\n        if (I.has_default_to_json_regular_operation()) {\n          isDefault = true;\n          for (const m of I.members) {\n            if (\n              m.special !== \"static\" &&\n              m.type == \"attribute\" &&\n              I.array.is_json_type(m.idlType)\n            ) {\n              map.set(m.name, m.idlType);\n            }\n          }\n        } else if (I.has_to_json_regular_operation()) {\n          isDefault = false;\n        }\n      }\n      return isDefault ? map : null;\n    };\n\n    IdlInterface.prototype.test = function () {\n      if (\n        this.has_extended_attribute(\"LegacyNoInterfaceObject\") ||\n        this.is_mixin()\n      ) {\n        // No tests to do without an instance.  TODO: We should still be able\n        // to run tests on the prototype object, if we obtain one through some\n        // other means.\n        return;\n      }\n\n      // If the interface object is not exposed, only test that. Members can't be\n      // tested either, but objects could still be tested in |test_object|.\n      if (!this.exposed) {\n        if (!this.untested) {\n          subsetTestByKey(\n            this.name,\n            test,\n            function () {\n              assert_false(this.name in self);\n            }.bind(this),\n            this.name +\n              \" interface: existence and properties of interface object\"\n          );\n        }\n        return;\n      }\n\n      if (!this.untested) {\n        // First test things to do with the exception/interface object and\n        // exception/interface prototype object.\n        this.test_self();\n      }\n      // Then test things to do with its members (constants, fields, attributes,\n      // operations, . . .).  These are run even if .untested is true, because\n      // members might themselves be marked as .untested.  This might happen to\n      // interfaces if the interface itself is untested but a partial interface\n      // that extends it is tested -- then the interface itself and its initial\n      // members will be marked as untested, but the members added by the partial\n      // interface are still tested.\n      this.test_members();\n    };\n\n    IdlInterface.prototype.constructors = function () {\n      return this.members.filter(function (m) {\n        return m.type == \"constructor\";\n      });\n    };\n\n    IdlInterface.prototype.test_self = function () {\n      subsetTestByKey(\n        this.name,\n        test,\n        function () {\n          if (!this.should_have_interface_object()) {\n            return;\n          }\n\n          // The name of the property is the identifier of the interface, and its\n          // value is an object called the interface object.\n          // The property has the attributes { [[Writable]]: true,\n          // [[Enumerable]]: false, [[Configurable]]: true }.\"\n          // TODO: Should we test here that the property is actually writable\n          // etc., or trust getOwnPropertyDescriptor?\n          this.assert_interface_object_exists();\n          var desc = Object.getOwnPropertyDescriptor(\n            this.get_interface_object_owner(),\n            this.name\n          );\n          assert_false(\n            \"get\" in desc,\n            \"self's property \" +\n              format_value(this.name) +\n              \" should not have a getter\"\n          );\n          assert_false(\n            \"set\" in desc,\n            \"self's property \" +\n              format_value(this.name) +\n              \" should not have a setter\"\n          );\n          assert_true(\n            desc.writable,\n            \"self's property \" + format_value(this.name) + \" should be writable\"\n          );\n          assert_false(\n            desc.enumerable,\n            \"self's property \" +\n              format_value(this.name) +\n              \" should not be enumerable\"\n          );\n          assert_true(\n            desc.configurable,\n            \"self's property \" +\n              format_value(this.name) +\n              \" should be configurable\"\n          );\n\n          if (this.is_callback()) {\n            // \"The internal [[Prototype]] property of an interface object for\n            // a callback interface must be the Function.prototype object.\"\n            assert_equals(\n              Object.getPrototypeOf(this.get_interface_object()),\n              Function.prototype,\n              \"prototype of self's property \" +\n                format_value(this.name) +\n                \" is not Object.prototype\"\n            );\n\n            return;\n          }\n\n          // \"The interface object for a given non-callback interface is a\n          // function object.\"\n          // \"If an object is defined to be a function object, then it has\n          // characteristics as follows:\"\n\n          // Its [[Prototype]] internal property is otherwise specified (see\n          // below).\n\n          // \"* Its [[Get]] internal property is set as described in ECMA-262\n          //    section 9.1.8.\"\n          // Not much to test for this.\n\n          // \"* Its [[Construct]] internal property is set as described in\n          //    ECMA-262 section 19.2.2.3.\"\n\n          // \"* Its @@hasInstance property is set as described in ECMA-262\n          //    section 19.2.3.8, unless otherwise specified.\"\n          // TODO\n\n          // ES6 (rev 30) 19.1.3.6:\n          // \"Else, if O has a [[Call]] internal method, then let builtinTag be\n          // \"Function\".\"\n          assert_class_string(\n            this.get_interface_object(),\n            \"Function\",\n            \"class string of \" + this.name\n          );\n\n          // \"The [[Prototype]] internal property of an interface object for a\n          // non-callback interface is determined as follows:\"\n          var prototype = Object.getPrototypeOf(this.get_interface_object());\n          if (this.base) {\n            // \"* If the interface inherits from some other interface, the\n            //    value of [[Prototype]] is the interface object for that other\n            //    interface.\"\n            var inherited_interface = this.array.members[this.base];\n            if (\n              !inherited_interface.has_extended_attribute(\n                \"LegacyNoInterfaceObject\"\n              )\n            ) {\n              inherited_interface.assert_interface_object_exists();\n              assert_equals(\n                prototype,\n                inherited_interface.get_interface_object(),\n                \"prototype of \" + this.name + \" is not \" + this.base\n              );\n            }\n          } else {\n            // \"If the interface doesn't inherit from any other interface, the\n            // value of [[Prototype]] is %FunctionPrototype% ([ECMA-262],\n            // section 6.1.7.4).\"\n            assert_equals(\n              prototype,\n              Function.prototype,\n              \"prototype of self's property \" +\n                format_value(this.name) +\n                \" is not Function.prototype\"\n            );\n          }\n\n          // Always test for [[Construct]]:\n          // https://github.com/heycam/webidl/issues/698\n          assert_true(\n            isConstructor(this.get_interface_object()),\n            \"interface object must pass IsConstructor check\"\n          );\n\n          var interface_object = this.get_interface_object();\n          assert_throws_js(\n            globalOf(interface_object).TypeError,\n            function () {\n              interface_object();\n            },\n            \"interface object didn't throw TypeError when called as a function\"\n          );\n\n          if (!this.constructors().length) {\n            assert_throws_js(\n              globalOf(interface_object).TypeError,\n              function () {\n                new interface_object();\n              },\n              \"interface object didn't throw TypeError when called as a constructor\"\n            );\n          }\n        }.bind(this),\n        this.name + \" interface: existence and properties of interface object\"\n      );\n\n      if (this.should_have_interface_object() && !this.is_callback()) {\n        subsetTestByKey(\n          this.name,\n          test,\n          function () {\n            // This function tests WebIDL as of 2014-10-25.\n            // https://webidl.spec.whatwg.org/#es-interface-call\n\n            this.assert_interface_object_exists();\n\n            // \"Interface objects for non-callback interfaces MUST have a\n            // property named “length” with attributes { [[Writable]]: false,\n            // [[Enumerable]]: false, [[Configurable]]: true } whose value is\n            // a Number.\"\n            assert_own_property(this.get_interface_object(), \"length\");\n            var desc = Object.getOwnPropertyDescriptor(\n              this.get_interface_object(),\n              \"length\"\n            );\n            assert_false(\n              \"get\" in desc,\n              this.name + \".length should not have a getter\"\n            );\n            assert_false(\n              \"set\" in desc,\n              this.name + \".length should not have a setter\"\n            );\n            assert_false(\n              desc.writable,\n              this.name + \".length should not be writable\"\n            );\n            assert_false(\n              desc.enumerable,\n              this.name + \".length should not be enumerable\"\n            );\n            assert_true(\n              desc.configurable,\n              this.name + \".length should be configurable\"\n            );\n\n            var constructors = this.constructors();\n            var expected_length = minOverloadLength(constructors);\n            assert_equals(\n              this.get_interface_object().length,\n              expected_length,\n              \"wrong value for \" + this.name + \".length\"\n            );\n          }.bind(this),\n          this.name + \" interface object length\"\n        );\n      }\n\n      if (this.should_have_interface_object()) {\n        subsetTestByKey(\n          this.name,\n          test,\n          function () {\n            // This function tests WebIDL as of 2015-11-17.\n            // https://webidl.spec.whatwg.org/#interface-object\n\n            this.assert_interface_object_exists();\n\n            // \"All interface objects must have a property named “name” with\n            // attributes { [[Writable]]: false, [[Enumerable]]: false,\n            // [[Configurable]]: true } whose value is the identifier of the\n            // corresponding interface.\"\n\n            assert_own_property(this.get_interface_object(), \"name\");\n            var desc = Object.getOwnPropertyDescriptor(\n              this.get_interface_object(),\n              \"name\"\n            );\n            assert_false(\n              \"get\" in desc,\n              this.name + \".name should not have a getter\"\n            );\n            assert_false(\n              \"set\" in desc,\n              this.name + \".name should not have a setter\"\n            );\n            assert_false(\n              desc.writable,\n              this.name + \".name should not be writable\"\n            );\n            assert_false(\n              desc.enumerable,\n              this.name + \".name should not be enumerable\"\n            );\n            assert_true(\n              desc.configurable,\n              this.name + \".name should be configurable\"\n            );\n            assert_equals(\n              this.get_interface_object().name,\n              this.name,\n              \"wrong value for \" + this.name + \".name\"\n            );\n          }.bind(this),\n          this.name + \" interface object name\"\n        );\n      }\n\n      if (this.has_extended_attribute(\"LegacyWindowAlias\")) {\n        subsetTestByKey(\n          this.name,\n          test,\n          function () {\n            var aliasAttrs = this.extAttrs.filter(function (o) {\n              return o.name === \"LegacyWindowAlias\";\n            });\n            if (aliasAttrs.length > 1) {\n              throw new IdlHarnessError(\n                \"Invalid IDL: multiple LegacyWindowAlias extended attributes on \" +\n                  this.name\n              );\n            }\n            if (this.is_callback()) {\n              throw new IdlHarnessError(\n                \"Invalid IDL: LegacyWindowAlias extended attribute on non-interface \" +\n                  this.name\n              );\n            }\n            if (!(this.exposureSet === \"*\" || this.exposureSet.has(\"Window\"))) {\n              throw new IdlHarnessError(\n                \"Invalid IDL: LegacyWindowAlias extended attribute on \" +\n                  this.name +\n                  \" which is not exposed in Window\"\n              );\n            }\n            // TODO: when testing of [LegacyNoInterfaceObject] interfaces is supported,\n            // check that it's not specified together with LegacyWindowAlias.\n\n            // TODO: maybe check that [LegacyWindowAlias] is not specified on a partial interface.\n\n            var rhs = aliasAttrs[0].rhs;\n            if (!rhs) {\n              throw new IdlHarnessError(\n                \"Invalid IDL: LegacyWindowAlias extended attribute on \" +\n                  this.name +\n                  \" without identifier\"\n              );\n            }\n            var aliases;\n            if (rhs.type === \"identifier-list\") {\n              aliases = rhs.value.map((id) => id.value);\n            } else {\n              // rhs.type === identifier\n              aliases = [rhs.value];\n            }\n\n            // OK now actually check the aliases...\n            var alias;\n            if (\n              exposed_in(exposure_set(this, this.exposureSet)) &&\n              \"document\" in self\n            ) {\n              for (alias of aliases) {\n                assert_true(alias in self, alias + \" should exist\");\n                assert_equals(\n                  self[alias],\n                  this.get_interface_object(),\n                  \"self.\" +\n                    alias +\n                    \" should be the same value as self.\" +\n                    this.get_qualified_name()\n                );\n                var desc = Object.getOwnPropertyDescriptor(self, alias);\n                assert_equals(\n                  desc.value,\n                  this.get_interface_object(),\n                  \"wrong value in \" + alias + \" property descriptor\"\n                );\n                assert_true(desc.writable, alias + \" should be writable\");\n                assert_false(\n                  desc.enumerable,\n                  alias + \" should not be enumerable\"\n                );\n                assert_true(\n                  desc.configurable,\n                  alias + \" should be configurable\"\n                );\n                assert_false(\n                  \"get\" in desc,\n                  alias + \" should not have a getter\"\n                );\n                assert_false(\n                  \"set\" in desc,\n                  alias + \" should not have a setter\"\n                );\n              }\n            } else {\n              for (alias of aliases) {\n                assert_false(alias in self, alias + \" should not exist\");\n              }\n            }\n          }.bind(this),\n          this.name + \" interface: legacy window alias\"\n        );\n      }\n\n      if (this.has_extended_attribute(\"LegacyFactoryFunction\")) {\n        var constructors = this.extAttrs.filter(function (attr) {\n          return attr.name == \"LegacyFactoryFunction\";\n        });\n        if (constructors.length !== 1) {\n          throw new IdlHarnessError(\n            \"Internal error: missing support for multiple LegacyFactoryFunction extended attributes\"\n          );\n        }\n        var constructor = constructors[0];\n        var min_length = minOverloadLength([constructor]);\n\n        subsetTestByKey(\n          this.name,\n          test,\n          function () {\n            // This function tests WebIDL as of 2019-01-14.\n\n            // \"for every [LegacyFactoryFunction] extended attribute on an exposed\n            // interface, a corresponding property must exist on the ECMAScript\n            // global object. The name of the property is the\n            // [LegacyFactoryFunction]'s identifier, and its value is an object\n            // called a named constructor, ... . The property has the attributes\n            // { [[Writable]]: true, [[Enumerable]]: false,\n            // [[Configurable]]: true }.\"\n            var name = constructor.rhs.value;\n            assert_own_property(self, name);\n            var desc = Object.getOwnPropertyDescriptor(self, name);\n            assert_equals(\n              desc.value,\n              self[name],\n              \"wrong value in \" + name + \" property descriptor\"\n            );\n            assert_true(desc.writable, name + \" should be writable\");\n            assert_false(desc.enumerable, name + \" should not be enumerable\");\n            assert_true(desc.configurable, name + \" should be configurable\");\n            assert_false(\"get\" in desc, name + \" should not have a getter\");\n            assert_false(\"set\" in desc, name + \" should not have a setter\");\n          }.bind(this),\n          this.name + \" interface: named constructor\"\n        );\n\n        subsetTestByKey(\n          this.name,\n          test,\n          function () {\n            // This function tests WebIDL as of 2019-01-14.\n\n            // \"2. Let F be ! CreateBuiltinFunction(realm, steps,\n            //     realm.[[Intrinsics]].[[%FunctionPrototype%]]).\"\n            var name = constructor.rhs.value;\n            var value = self[name];\n            assert_equals(\n              typeof value,\n              \"function\",\n              \"type of value in \" + name + \" property descriptor\"\n            );\n            assert_not_equals(\n              value,\n              this.get_interface_object(),\n              \"wrong value in \" + name + \" property descriptor\"\n            );\n            assert_equals(\n              Object.getPrototypeOf(value),\n              Function.prototype,\n              \"wrong value for \" + name + \"'s prototype\"\n            );\n          }.bind(this),\n          this.name + \" interface: named constructor object\"\n        );\n\n        subsetTestByKey(\n          this.name,\n          test,\n          function () {\n            // This function tests WebIDL as of 2019-01-14.\n\n            // \"7. Let proto be the interface prototype object of interface I\n            //     in realm.\n            // \"8. Perform ! DefinePropertyOrThrow(F, \"prototype\",\n            //     PropertyDescriptor{\n            //         [[Value]]: proto, [[Writable]]: false,\n            //         [[Enumerable]]: false, [[Configurable]]: false\n            //     }).\"\n            var name = constructor.rhs.value;\n            var expected = this.get_interface_object().prototype;\n            var desc = Object.getOwnPropertyDescriptor(self[name], \"prototype\");\n            assert_equals(\n              desc.value,\n              expected,\n              \"wrong value for \" + name + \".prototype\"\n            );\n            assert_false(desc.writable, \"prototype should not be writable\");\n            assert_false(desc.enumerable, \"prototype should not be enumerable\");\n            assert_false(\n              desc.configurable,\n              \"prototype should not be configurable\"\n            );\n            assert_false(\"get\" in desc, \"prototype should not have a getter\");\n            assert_false(\"set\" in desc, \"prototype should not have a setter\");\n          }.bind(this),\n          this.name + \" interface: named constructor prototype property\"\n        );\n\n        subsetTestByKey(\n          this.name,\n          test,\n          function () {\n            // This function tests WebIDL as of 2019-01-14.\n\n            // \"3. Perform ! SetFunctionName(F, id).\"\n            var name = constructor.rhs.value;\n            var desc = Object.getOwnPropertyDescriptor(self[name], \"name\");\n            assert_equals(\n              desc.value,\n              name,\n              \"wrong value for \" + name + \".name\"\n            );\n            assert_false(desc.writable, \"name should not be writable\");\n            assert_false(desc.enumerable, \"name should not be enumerable\");\n            assert_true(desc.configurable, \"name should be configurable\");\n            assert_false(\"get\" in desc, \"name should not have a getter\");\n            assert_false(\"set\" in desc, \"name should not have a setter\");\n          }.bind(this),\n          this.name + \" interface: named constructor name\"\n        );\n\n        subsetTestByKey(\n          this.name,\n          test,\n          function () {\n            // This function tests WebIDL as of 2019-01-14.\n\n            // \"4. Initialize S to the effective overload set for constructors\n            //     with identifier id on interface I and with argument count 0.\n            // \"5. Let length be the length of the shortest argument list of\n            //     the entries in S.\n            // \"6. Perform ! SetFunctionLength(F, length).\"\n            var name = constructor.rhs.value;\n            var desc = Object.getOwnPropertyDescriptor(self[name], \"length\");\n            assert_equals(\n              desc.value,\n              min_length,\n              \"wrong value for \" + name + \".length\"\n            );\n            assert_false(desc.writable, \"length should not be writable\");\n            assert_false(desc.enumerable, \"length should not be enumerable\");\n            assert_true(desc.configurable, \"length should be configurable\");\n            assert_false(\"get\" in desc, \"length should not have a getter\");\n            assert_false(\"set\" in desc, \"length should not have a setter\");\n          }.bind(this),\n          this.name + \" interface: named constructor length\"\n        );\n\n        subsetTestByKey(\n          this.name,\n          test,\n          function () {\n            // This function tests WebIDL as of 2019-01-14.\n\n            // \"1. Let steps be the following steps:\n            // \"    1. If NewTarget is undefined, then throw a TypeError.\"\n            var name = constructor.rhs.value;\n            var args = constructor.arguments.map(function (arg) {\n              return create_suitable_object(arg.idlType);\n            });\n            assert_throws_js(\n              globalOf(self[name]).TypeError,\n              function () {\n                self[name](...args);\n              }.bind(this)\n            );\n          }.bind(this),\n          this.name + \" interface: named constructor without 'new'\"\n        );\n      }\n\n      subsetTestByKey(\n        this.name,\n        test,\n        function () {\n          // This function tests WebIDL as of 2015-01-21.\n          // https://webidl.spec.whatwg.org/#interface-object\n\n          if (!this.should_have_interface_object()) {\n            return;\n          }\n\n          this.assert_interface_object_exists();\n\n          if (this.is_callback()) {\n            assert_false(\n              \"prototype\" in this.get_interface_object(),\n              this.name + ' should not have a \"prototype\" property'\n            );\n            return;\n          }\n\n          // \"An interface object for a non-callback interface must have a\n          // property named “prototype” with attributes { [[Writable]]: false,\n          // [[Enumerable]]: false, [[Configurable]]: false } whose value is an\n          // object called the interface prototype object. This object has\n          // properties that correspond to the regular attributes and regular\n          // operations defined on the interface, and is described in more detail\n          // in section 4.5.4 below.\"\n          assert_own_property(\n            this.get_interface_object(),\n            \"prototype\",\n            'interface \"' +\n              this.name +\n              '\" does not have own property \"prototype\"'\n          );\n          var desc = Object.getOwnPropertyDescriptor(\n            this.get_interface_object(),\n            \"prototype\"\n          );\n          assert_false(\n            \"get\" in desc,\n            this.name + \".prototype should not have a getter\"\n          );\n          assert_false(\n            \"set\" in desc,\n            this.name + \".prototype should not have a setter\"\n          );\n          assert_false(\n            desc.writable,\n            this.name + \".prototype should not be writable\"\n          );\n          assert_false(\n            desc.enumerable,\n            this.name + \".prototype should not be enumerable\"\n          );\n          assert_false(\n            desc.configurable,\n            this.name + \".prototype should not be configurable\"\n          );\n\n          // Next, test that the [[Prototype]] of the interface prototype object\n          // is correct. (This is made somewhat difficult by the existence of\n          // [LegacyNoInterfaceObject].)\n          // TODO: Aryeh thinks there's at least other place in this file where\n          //       we try to figure out if an interface prototype object is\n          //       correct. Consolidate that code.\n\n          // \"The interface prototype object for a given interface A must have an\n          // internal [[Prototype]] property whose value is returned from the\n          // following steps:\n          // \"If A is declared with the [Global] extended\n          // attribute, and A supports named properties, then return the named\n          // properties object for A, as defined in §3.6.4 Named properties\n          // object.\n          // \"Otherwise, if A is declared to inherit from another interface, then\n          // return the interface prototype object for the inherited interface.\n          // \"Otherwise, return %ObjectPrototype%.\n          //\n          // \"In the ECMAScript binding, the DOMException type has some additional\n          // requirements:\n          //\n          //     \"Unlike normal interface types, the interface prototype object\n          //     for DOMException must have as its [[Prototype]] the intrinsic\n          //     object %ErrorPrototype%.\"\n          //\n          if (this.name === \"Window\") {\n            assert_class_string(\n              Object.getPrototypeOf(this.get_interface_object().prototype),\n              \"WindowProperties\",\n              \"Class name for prototype of Window\" +\n                '.prototype is not \"WindowProperties\"'\n            );\n          } else {\n            var inherit_interface, inherit_interface_interface_object;\n            if (this.base) {\n              inherit_interface = this.base;\n              var parent = this.array.members[inherit_interface];\n              if (!parent.has_extended_attribute(\"LegacyNoInterfaceObject\")) {\n                parent.assert_interface_object_exists();\n                inherit_interface_interface_object =\n                  parent.get_interface_object();\n              }\n            } else if (this.name === \"DOMException\") {\n              inherit_interface = \"Error\";\n              inherit_interface_interface_object = self.Error;\n            } else {\n              inherit_interface = \"Object\";\n              inherit_interface_interface_object = self.Object;\n            }\n            if (inherit_interface_interface_object) {\n              assert_not_equals(\n                inherit_interface_interface_object,\n                undefined,\n                \"should inherit from \" +\n                  inherit_interface +\n                  \", but there is no such property\"\n              );\n              assert_own_property(\n                inherit_interface_interface_object,\n                \"prototype\",\n                \"should inherit from \" +\n                  inherit_interface +\n                  ', but that object has no \"prototype\" property'\n              );\n              assert_equals(\n                Object.getPrototypeOf(this.get_interface_object().prototype),\n                inherit_interface_interface_object.prototype,\n                \"prototype of \" +\n                  this.name +\n                  \".prototype is not \" +\n                  inherit_interface +\n                  \".prototype\"\n              );\n            } else {\n              // We can't test that we get the correct object, because this is the\n              // only way to get our hands on it. We only test that its class\n              // string, at least, is correct.\n              assert_class_string(\n                Object.getPrototypeOf(this.get_interface_object().prototype),\n                inherit_interface + \"Prototype\",\n                \"Class name for prototype of \" +\n                  this.name +\n                  '.prototype is not \"' +\n                  inherit_interface +\n                  'Prototype\"'\n              );\n            }\n          }\n\n          // \"The class string of an interface prototype object is the\n          // concatenation of the interface’s qualified identifier and the string\n          // “Prototype”.\"\n\n          // Skip these tests for now due to a specification issue about\n          // prototype name.\n          // https://www.w3.org/Bugs/Public/show_bug.cgi?id=28244\n\n          // assert_class_string(this.get_interface_object().prototype, this.get_qualified_name() + \"Prototype\",\n          //                     \"class string of \" + this.name + \".prototype\");\n\n          // String() should end up calling {}.toString if nothing defines a\n          // stringifier.\n          if (!this.has_stringifier()) {\n            // assert_equals(String(this.get_interface_object().prototype), \"[object \" + this.get_qualified_name() + \"Prototype]\",\n            //         \"String(\" + this.name + \".prototype)\");\n          }\n        }.bind(this),\n        this.name +\n          \" interface: existence and properties of interface prototype object\"\n      );\n\n      // \"If the interface is declared with the [Global]\n      // extended attribute, or the interface is in the set of inherited\n      // interfaces for any other interface that is declared with one of these\n      // attributes, then the interface prototype object must be an immutable\n      // prototype exotic object.\"\n      // https://webidl.spec.whatwg.org/#interface-prototype-object\n      if (this.is_global()) {\n        this.test_immutable_prototype(\n          \"interface prototype object\",\n          this.get_interface_object().prototype\n        );\n      }\n\n      subsetTestByKey(\n        this.name,\n        test,\n        function () {\n          if (!this.should_have_interface_object()) {\n            return;\n          }\n\n          this.assert_interface_object_exists();\n\n          if (this.is_callback()) {\n            assert_false(\n              \"prototype\" in this.get_interface_object(),\n              this.name + ' should not have a \"prototype\" property'\n            );\n            return;\n          }\n\n          assert_own_property(\n            this.get_interface_object(),\n            \"prototype\",\n            'interface \"' +\n              this.name +\n              '\" does not have own property \"prototype\"'\n          );\n\n          // \"If the [LegacyNoInterfaceObject] extended attribute was not specified\n          // on the interface, then the interface prototype object must also have a\n          // property named “constructor” with attributes { [[Writable]]: true,\n          // [[Enumerable]]: false, [[Configurable]]: true } whose value is a\n          // reference to the interface object for the interface.\"\n          assert_own_property(\n            this.get_interface_object().prototype,\n            \"constructor\",\n            this.name + '.prototype does not have own property \"constructor\"'\n          );\n          var desc = Object.getOwnPropertyDescriptor(\n            this.get_interface_object().prototype,\n            \"constructor\"\n          );\n          assert_false(\n            \"get\" in desc,\n            this.name + \".prototype.constructor should not have a getter\"\n          );\n          assert_false(\n            \"set\" in desc,\n            this.name + \".prototype.constructor should not have a setter\"\n          );\n          assert_true(\n            desc.writable,\n            this.name + \".prototype.constructor should be writable\"\n          );\n          assert_false(\n            desc.enumerable,\n            this.name + \".prototype.constructor should not be enumerable\"\n          );\n          assert_true(\n            desc.configurable,\n            this.name + \".prototype.constructor should be configurable\"\n          );\n          assert_equals(\n            this.get_interface_object().prototype.constructor,\n            this.get_interface_object(),\n            this.name +\n              \".prototype.constructor is not the same object as \" +\n              this.name\n          );\n        }.bind(this),\n        this.name +\n          ' interface: existence and properties of interface prototype object\\'s \"constructor\" property'\n      );\n\n      subsetTestByKey(\n        this.name,\n        test,\n        function () {\n          if (!this.should_have_interface_object()) {\n            return;\n          }\n\n          this.assert_interface_object_exists();\n\n          if (this.is_callback()) {\n            assert_false(\n              \"prototype\" in this.get_interface_object(),\n              this.name + ' should not have a \"prototype\" property'\n            );\n            return;\n          }\n\n          assert_own_property(\n            this.get_interface_object(),\n            \"prototype\",\n            'interface \"' +\n              this.name +\n              '\" does not have own property \"prototype\"'\n          );\n\n          // If the interface has any member declared with the [Unscopable] extended\n          // attribute, then there must be a property on the interface prototype object\n          // whose name is the @@unscopables symbol, which has the attributes\n          // { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true },\n          // and whose value is an object created as follows...\n          var unscopables = this.get_unscopables().map((m) => m.name);\n          var proto = this.get_interface_object().prototype;\n          if (unscopables.length != 0) {\n            assert_own_property(\n              proto,\n              Symbol.unscopables,\n              this.name + \".prototype should have an @@unscopables property\"\n            );\n            var desc = Object.getOwnPropertyDescriptor(\n              proto,\n              Symbol.unscopables\n            );\n            assert_false(\n              \"get\" in desc,\n              this.name +\n                \".prototype[Symbol.unscopables] should not have a getter\"\n            );\n            assert_false(\n              \"set\" in desc,\n              this.name +\n                \".prototype[Symbol.unscopables] should not have a setter\"\n            );\n            assert_false(\n              desc.writable,\n              this.name +\n                \".prototype[Symbol.unscopables] should not be writable\"\n            );\n            assert_false(\n              desc.enumerable,\n              this.name +\n                \".prototype[Symbol.unscopables] should not be enumerable\"\n            );\n            assert_true(\n              desc.configurable,\n              this.name +\n                \".prototype[Symbol.unscopables] should be configurable\"\n            );\n            assert_equals(\n              desc.value,\n              proto[Symbol.unscopables],\n              this.name +\n                \".prototype[Symbol.unscopables] should be in the descriptor\"\n            );\n            assert_equals(\n              typeof desc.value,\n              \"object\",\n              this.name + \".prototype[Symbol.unscopables] should be an object\"\n            );\n            assert_equals(\n              Object.getPrototypeOf(desc.value),\n              null,\n              this.name +\n                \".prototype[Symbol.unscopables] should have a null prototype\"\n            );\n            assert_equals(\n              Object.getOwnPropertySymbols(desc.value).length,\n              0,\n              this.name +\n                \".prototype[Symbol.unscopables] should have the right number of symbol-named properties\"\n            );\n\n            // Check that we do not have _extra_ unscopables.  Checking that we\n            // have all the ones we should will happen in the per-member tests.\n            var observed = Object.getOwnPropertyNames(desc.value);\n            for (var prop of observed) {\n              assert_not_equals(\n                unscopables.indexOf(prop),\n                -1,\n                this.name +\n                  '.prototype[Symbol.unscopables] has unexpected property \"' +\n                  prop +\n                  '\"'\n              );\n            }\n          } else {\n            assert_equals(\n              Object.getOwnPropertyDescriptor(\n                this.get_interface_object().prototype,\n                Symbol.unscopables\n              ),\n              undefined,\n              this.name + \".prototype should not have @@unscopables\"\n            );\n          }\n        }.bind(this),\n        this.name +\n          \" interface: existence and properties of interface prototype object's @@unscopables property\"\n      );\n    };\n\n    IdlInterface.prototype.test_immutable_prototype = function (type, obj) {\n      if (typeof Object.setPrototypeOf !== \"function\") {\n        return;\n      }\n\n      subsetTestByKey(\n        this.name,\n        test,\n        function (t) {\n          var originalValue = Object.getPrototypeOf(obj);\n          var newValue = Object.create(null);\n\n          t.add_cleanup(function () {\n            try {\n              Object.setPrototypeOf(obj, originalValue);\n            } catch (err) {}\n          });\n\n          assert_throws_js(TypeError, function () {\n            Object.setPrototypeOf(obj, newValue);\n          });\n\n          assert_equals(\n            Object.getPrototypeOf(obj),\n            originalValue,\n            \"original value not modified\"\n          );\n        }.bind(this),\n        this.name +\n          \" interface: internal [[SetPrototypeOf]] method \" +\n          \"of \" +\n          type +\n          \" - setting to a new value via Object.setPrototypeOf \" +\n          \"should throw a TypeError\"\n      );\n\n      subsetTestByKey(\n        this.name,\n        test,\n        function (t) {\n          var originalValue = Object.getPrototypeOf(obj);\n          var newValue = Object.create(null);\n\n          t.add_cleanup(function () {\n            let setter = Object.getOwnPropertyDescriptor(\n              Object.prototype,\n              \"__proto__\"\n            ).set;\n\n            try {\n              setter.call(obj, originalValue);\n            } catch (err) {}\n          });\n\n          // We need to find the actual setter for the '__proto__' property, so we\n          // can determine the right global for it.  Walk up the prototype chain\n          // looking for that property until we find it.\n          let setter;\n          {\n            let cur = obj;\n            while (cur) {\n              const desc = Object.getOwnPropertyDescriptor(cur, \"__proto__\");\n              if (desc) {\n                setter = desc.set;\n                break;\n              }\n              cur = Object.getPrototypeOf(cur);\n            }\n          }\n          assert_throws_js(globalOf(setter).TypeError, function () {\n            obj.__proto__ = newValue;\n          });\n\n          assert_equals(\n            Object.getPrototypeOf(obj),\n            originalValue,\n            \"original value not modified\"\n          );\n        }.bind(this),\n        this.name +\n          \" interface: internal [[SetPrototypeOf]] method \" +\n          \"of \" +\n          type +\n          \" - setting to a new value via __proto__ \" +\n          \"should throw a TypeError\"\n      );\n\n      subsetTestByKey(\n        this.name,\n        test,\n        function (t) {\n          var originalValue = Object.getPrototypeOf(obj);\n          var newValue = Object.create(null);\n\n          t.add_cleanup(function () {\n            try {\n              Reflect.setPrototypeOf(obj, originalValue);\n            } catch (err) {}\n          });\n\n          assert_false(Reflect.setPrototypeOf(obj, newValue));\n\n          assert_equals(\n            Object.getPrototypeOf(obj),\n            originalValue,\n            \"original value not modified\"\n          );\n        }.bind(this),\n        this.name +\n          \" interface: internal [[SetPrototypeOf]] method \" +\n          \"of \" +\n          type +\n          \" - setting to a new value via Reflect.setPrototypeOf \" +\n          \"should return false\"\n      );\n\n      subsetTestByKey(\n        this.name,\n        test,\n        function () {\n          var originalValue = Object.getPrototypeOf(obj);\n\n          Object.setPrototypeOf(obj, originalValue);\n        }.bind(this),\n        this.name +\n          \" interface: internal [[SetPrototypeOf]] method \" +\n          \"of \" +\n          type +\n          \" - setting to its original value via Object.setPrototypeOf \" +\n          \"should not throw\"\n      );\n\n      subsetTestByKey(\n        this.name,\n        test,\n        function () {\n          var originalValue = Object.getPrototypeOf(obj);\n\n          obj.__proto__ = originalValue;\n        }.bind(this),\n        this.name +\n          \" interface: internal [[SetPrototypeOf]] method \" +\n          \"of \" +\n          type +\n          \" - setting to its original value via __proto__ \" +\n          \"should not throw\"\n      );\n\n      subsetTestByKey(\n        this.name,\n        test,\n        function () {\n          var originalValue = Object.getPrototypeOf(obj);\n\n          assert_true(Reflect.setPrototypeOf(obj, originalValue));\n        }.bind(this),\n        this.name +\n          \" interface: internal [[SetPrototypeOf]] method \" +\n          \"of \" +\n          type +\n          \" - setting to its original value via Reflect.setPrototypeOf \" +\n          \"should return true\"\n      );\n    };\n\n    IdlInterface.prototype.test_member_const = function (member) {\n      if (!this.has_constants()) {\n        throw new IdlHarnessError(\n          \"Internal error: test_member_const called without any constants\"\n        );\n      }\n\n      subsetTestByKey(\n        this.name,\n        test,\n        function () {\n          this.assert_interface_object_exists();\n\n          // \"For each constant defined on an interface A, there must be\n          // a corresponding property on the interface object, if it\n          // exists.\"\n          assert_own_property(this.get_interface_object(), member.name);\n          // \"The value of the property is that which is obtained by\n          // converting the constant’s IDL value to an ECMAScript\n          // value.\"\n          assert_equals(\n            this.get_interface_object()[member.name],\n            constValue(member.value),\n            \"property has wrong value\"\n          );\n          // \"The property has attributes { [[Writable]]: false,\n          // [[Enumerable]]: true, [[Configurable]]: false }.\"\n          var desc = Object.getOwnPropertyDescriptor(\n            this.get_interface_object(),\n            member.name\n          );\n          assert_false(\"get\" in desc, \"property should not have a getter\");\n          assert_false(\"set\" in desc, \"property should not have a setter\");\n          assert_false(desc.writable, \"property should not be writable\");\n          assert_true(desc.enumerable, \"property should be enumerable\");\n          assert_false(\n            desc.configurable,\n            \"property should not be configurable\"\n          );\n        }.bind(this),\n        this.name +\n          \" interface: constant \" +\n          member.name +\n          \" on interface object\"\n      );\n\n      // \"In addition, a property with the same characteristics must\n      // exist on the interface prototype object.\"\n      subsetTestByKey(\n        this.name,\n        test,\n        function () {\n          this.assert_interface_object_exists();\n\n          if (this.is_callback()) {\n            assert_false(\n              \"prototype\" in this.get_interface_object(),\n              this.name + ' should not have a \"prototype\" property'\n            );\n            return;\n          }\n\n          assert_own_property(\n            this.get_interface_object(),\n            \"prototype\",\n            'interface \"' +\n              this.name +\n              '\" does not have own property \"prototype\"'\n          );\n\n          assert_own_property(\n            this.get_interface_object().prototype,\n            member.name\n          );\n          assert_equals(\n            this.get_interface_object().prototype[member.name],\n            constValue(member.value),\n            \"property has wrong value\"\n          );\n          var desc = Object.getOwnPropertyDescriptor(\n            this.get_interface_object(),\n            member.name\n          );\n          assert_false(\"get\" in desc, \"property should not have a getter\");\n          assert_false(\"set\" in desc, \"property should not have a setter\");\n          assert_false(desc.writable, \"property should not be writable\");\n          assert_true(desc.enumerable, \"property should be enumerable\");\n          assert_false(\n            desc.configurable,\n            \"property should not be configurable\"\n          );\n        }.bind(this),\n        this.name +\n          \" interface: constant \" +\n          member.name +\n          \" on interface prototype object\"\n      );\n    };\n\n    IdlInterface.prototype.test_member_attribute = function (member) {\n      if (!shouldRunSubTest(this.name)) {\n        return;\n      }\n      var a_test = subsetTestByKey(\n        this.name,\n        async_test,\n        this.name + \" interface: attribute \" + member.name\n      );\n      a_test.step(\n        function () {\n          if (!this.should_have_interface_object()) {\n            a_test.done();\n            return;\n          }\n\n          this.assert_interface_object_exists();\n          assert_own_property(\n            this.get_interface_object(),\n            \"prototype\",\n            'interface \"' +\n              this.name +\n              '\" does not have own property \"prototype\"'\n          );\n\n          if (member.special === \"static\") {\n            assert_own_property(\n              this.get_interface_object(),\n              member.name,\n              \"The interface object must have a property \" +\n                format_value(member.name)\n            );\n            a_test.done();\n            return;\n          }\n\n          this.do_member_unscopable_asserts(member);\n\n          if (this.is_global()) {\n            assert_own_property(\n              self,\n              member.name,\n              \"The global object must have a property \" +\n                format_value(member.name)\n            );\n            assert_false(\n              member.name in this.get_interface_object().prototype,\n              \"The prototype object should not have a property \" +\n                format_value(member.name)\n            );\n\n            var getter = Object.getOwnPropertyDescriptor(self, member.name).get;\n            assert_equals(\n              typeof getter,\n              \"function\",\n              format_value(member.name) + \" must have a getter\"\n            );\n\n            // Try/catch around the get here, since it can legitimately throw.\n            // If it does, we obviously can't check for equality with direct\n            // invocation of the getter.\n            var gotValue;\n            var propVal;\n            try {\n              propVal = self[member.name];\n              gotValue = true;\n            } catch (e) {\n              gotValue = false;\n            }\n            if (gotValue) {\n              assert_equals(\n                propVal,\n                getter.call(undefined),\n                \"Gets on a global should not require an explicit this\"\n              );\n            }\n\n            // do_interface_attribute_asserts must be the last thing we do,\n            // since it will call done() on a_test.\n            this.do_interface_attribute_asserts(self, member, a_test);\n          } else {\n            assert_true(\n              member.name in this.get_interface_object().prototype,\n              \"The prototype object must have a property \" +\n                format_value(member.name)\n            );\n\n            if (!member.has_extended_attribute(\"LegacyLenientThis\")) {\n              if (member.idlType.generic !== \"Promise\") {\n                // this.get_interface_object() returns a thing in our global\n                assert_throws_js(\n                  TypeError,\n                  function () {\n                    this.get_interface_object().prototype[member.name];\n                  }.bind(this),\n                  \"getting property on prototype object must throw TypeError\"\n                );\n                // do_interface_attribute_asserts must be the last thing we\n                // do, since it will call done() on a_test.\n                this.do_interface_attribute_asserts(\n                  this.get_interface_object().prototype,\n                  member,\n                  a_test\n                );\n              } else {\n                promise_rejects_js(\n                  a_test,\n                  TypeError,\n                  this.get_interface_object().prototype[member.name]\n                ).then(\n                  a_test.step_func(\n                    function () {\n                      // do_interface_attribute_asserts must be the last\n                      // thing we do, since it will call done() on a_test.\n                      this.do_interface_attribute_asserts(\n                        this.get_interface_object().prototype,\n                        member,\n                        a_test\n                      );\n                    }.bind(this)\n                  )\n                );\n              }\n            } else {\n              assert_equals(\n                this.get_interface_object().prototype[member.name],\n                undefined,\n                \"getting property on prototype object must return undefined\"\n              );\n              // do_interface_attribute_asserts must be the last thing we do,\n              // since it will call done() on a_test.\n              this.do_interface_attribute_asserts(\n                this.get_interface_object().prototype,\n                member,\n                a_test\n              );\n            }\n          }\n        }.bind(this)\n      );\n    };\n\n    IdlInterface.prototype.test_member_operation = function (member) {\n      if (!shouldRunSubTest(this.name)) {\n        return;\n      }\n      var a_test = subsetTestByKey(\n        this.name,\n        async_test,\n        this.name + \" interface: operation \" + member\n      );\n      a_test.step(\n        function () {\n          // This function tests WebIDL as of 2015-12-29.\n          // https://webidl.spec.whatwg.org/#es-operations\n\n          if (!this.should_have_interface_object()) {\n            a_test.done();\n            return;\n          }\n\n          this.assert_interface_object_exists();\n\n          if (this.is_callback()) {\n            assert_false(\n              \"prototype\" in this.get_interface_object(),\n              this.name + ' should not have a \"prototype\" property'\n            );\n            a_test.done();\n            return;\n          }\n\n          assert_own_property(\n            this.get_interface_object(),\n            \"prototype\",\n            'interface \"' +\n              this.name +\n              '\" does not have own property \"prototype\"'\n          );\n\n          // \"For each unique identifier of an exposed operation defined on the\n          // interface, there must exist a corresponding property, unless the\n          // effective overload set for that identifier and operation and with an\n          // argument count of 0 has no entries.\"\n\n          // TODO: Consider [Exposed].\n\n          // \"The location of the property is determined as follows:\"\n          var memberHolderObject;\n          // \"* If the operation is static, then the property exists on the\n          //    interface object.\"\n          if (member.special === \"static\") {\n            assert_own_property(\n              this.get_interface_object(),\n              member.name,\n              \"interface object missing static operation\"\n            );\n            memberHolderObject = this.get_interface_object();\n            // \"* Otherwise, [...] if the interface was declared with the [Global]\n            //    extended attribute, then the property exists\n            //    on every object that implements the interface.\"\n          } else if (this.is_global()) {\n            assert_own_property(\n              self,\n              member.name,\n              \"global object missing non-static operation\"\n            );\n            memberHolderObject = self;\n            // \"* Otherwise, the property exists solely on the interface’s\n            //    interface prototype object.\"\n          } else {\n            assert_own_property(\n              this.get_interface_object().prototype,\n              member.name,\n              \"interface prototype object missing non-static operation\"\n            );\n            memberHolderObject = this.get_interface_object().prototype;\n          }\n          this.do_member_unscopable_asserts(member);\n          this.do_member_operation_asserts(memberHolderObject, member, a_test);\n        }.bind(this)\n      );\n    };\n\n    IdlInterface.prototype.do_member_unscopable_asserts = function (member) {\n      // Check that if the member is unscopable then it's in the\n      // @@unscopables object properly.\n      if (!member.isUnscopable) {\n        return;\n      }\n\n      var unscopables =\n        this.get_interface_object().prototype[Symbol.unscopables];\n      var prop = member.name;\n      var propDesc = Object.getOwnPropertyDescriptor(unscopables, prop);\n      assert_equals(\n        typeof propDesc,\n        \"object\",\n        this.name + \".prototype[Symbol.unscopables].\" + prop + \" must exist\"\n      );\n      assert_false(\n        \"get\" in propDesc,\n        this.name +\n          \".prototype[Symbol.unscopables].\" +\n          prop +\n          \" must have no getter\"\n      );\n      assert_false(\n        \"set\" in propDesc,\n        this.name +\n          \".prototype[Symbol.unscopables].\" +\n          prop +\n          \" must have no setter\"\n      );\n      assert_true(\n        propDesc.writable,\n        this.name +\n          \".prototype[Symbol.unscopables].\" +\n          prop +\n          \" must be writable\"\n      );\n      assert_true(\n        propDesc.enumerable,\n        this.name +\n          \".prototype[Symbol.unscopables].\" +\n          prop +\n          \" must be enumerable\"\n      );\n      assert_true(\n        propDesc.configurable,\n        this.name +\n          \".prototype[Symbol.unscopables].\" +\n          prop +\n          \" must be configurable\"\n      );\n      assert_equals(\n        propDesc.value,\n        true,\n        this.name +\n          \".prototype[Symbol.unscopables].\" +\n          prop +\n          \" must have the value `true`\"\n      );\n    };\n\n    IdlInterface.prototype.do_member_operation_asserts = function (\n      memberHolderObject,\n      member,\n      a_test\n    ) {\n      var done = a_test.done.bind(a_test);\n      var operationUnforgeable = member.isUnforgeable;\n      var desc = Object.getOwnPropertyDescriptor(\n        memberHolderObject,\n        member.name\n      );\n      // \"The property has attributes { [[Writable]]: B,\n      // [[Enumerable]]: true, [[Configurable]]: B }, where B is false if the\n      // operation is unforgeable on the interface, and true otherwise\".\n      assert_false(\"get\" in desc, \"property should not have a getter\");\n      assert_false(\"set\" in desc, \"property should not have a setter\");\n      assert_equals(\n        desc.writable,\n        !operationUnforgeable,\n        \"property should be writable if and only if not unforgeable\"\n      );\n      assert_true(desc.enumerable, \"property should be enumerable\");\n      assert_equals(\n        desc.configurable,\n        !operationUnforgeable,\n        \"property should be configurable if and only if not unforgeable\"\n      );\n      // \"The value of the property is a Function object whose\n      // behavior is as follows . . .\"\n      assert_equals(\n        typeof memberHolderObject[member.name],\n        \"function\",\n        \"property must be a function\"\n      );\n\n      const operationOverloads = this.members.filter(function (m) {\n        return (\n          m.type == \"operation\" &&\n          m.name == member.name &&\n          (m.special === \"static\") === (member.special === \"static\")\n        );\n      });\n      assert_equals(\n        memberHolderObject[member.name].length,\n        minOverloadLength(operationOverloads),\n        \"property has wrong .length\"\n      );\n      assert_equals(\n        memberHolderObject[member.name].name,\n        member.name,\n        \"property has wrong .name\"\n      );\n\n      // Make some suitable arguments\n      var args = member.arguments.map(function (arg) {\n        return create_suitable_object(arg.idlType);\n      });\n\n      // \"Let O be a value determined as follows:\n      // \". . .\n      // \"Otherwise, throw a TypeError.\"\n      // This should be hit if the operation is not static, there is\n      // no [ImplicitThis] attribute, and the this value is null.\n      //\n      // TODO: We currently ignore the [ImplicitThis] case.  Except we manually\n      // check for globals, since otherwise we'll invoke window.close().  And we\n      // have to skip this test for anything that on the proto chain of \"self\",\n      // since that does in fact have implicit-this behavior.\n      if (member.special !== \"static\") {\n        var cb;\n        if (\n          !this.is_global() &&\n          memberHolderObject[member.name] != self[member.name]\n        ) {\n          cb = awaitNCallbacks(2, done);\n          throwOrReject(\n            a_test,\n            member,\n            memberHolderObject[member.name],\n            null,\n            args,\n            \"calling operation with this = null didn't throw TypeError\",\n            cb\n          );\n        } else {\n          cb = awaitNCallbacks(1, done);\n        }\n\n        // \". . . If O is not null and is also not a platform object\n        // that implements interface I, throw a TypeError.\"\n        //\n        // TODO: Test a platform object that implements some other\n        // interface.  (Have to be sure to get inheritance right.)\n        throwOrReject(\n          a_test,\n          member,\n          memberHolderObject[member.name],\n          {},\n          args,\n          \"calling operation with this = {} didn't throw TypeError\",\n          cb\n        );\n      } else {\n        done();\n      }\n    };\n\n    IdlInterface.prototype.test_to_json_operation = function (\n      desc,\n      memberHolderObject,\n      member\n    ) {\n      var instanceName =\n        (memberHolderObject && memberHolderObject.constructor.name) ||\n        member.name + \" object\";\n      if (member.has_extended_attribute(\"Default\")) {\n        subsetTestByKey(\n          this.name,\n          test,\n          function () {\n            var map = this.default_to_json_operation();\n            var json = memberHolderObject.toJSON();\n            map.forEach(function (type, k) {\n              assert_true(\n                k in json,\n                \"property \" +\n                  JSON.stringify(k) +\n                  \" should be present in the output of \" +\n                  this.name +\n                  \".prototype.toJSON()\"\n              );\n              var descriptor = Object.getOwnPropertyDescriptor(json, k);\n              assert_true(\n                descriptor.writable,\n                \"property \" + k + \" should be writable\"\n              );\n              assert_true(\n                descriptor.configurable,\n                \"property \" + k + \" should be configurable\"\n              );\n              assert_true(\n                descriptor.enumerable,\n                \"property \" + k + \" should be enumerable\"\n              );\n              this.array.assert_type_is(json[k], type);\n              delete json[k];\n            }, this);\n          }.bind(this),\n          this.name + \" interface: default toJSON operation on \" + desc\n        );\n      } else {\n        subsetTestByKey(\n          this.name,\n          test,\n          function () {\n            assert_true(\n              this.array.is_json_type(member.idlType),\n              JSON.stringify(member.idlType) +\n                \" is not an appropriate return value for the toJSON operation of \" +\n                instanceName\n            );\n            this.array.assert_type_is(\n              memberHolderObject.toJSON(),\n              member.idlType\n            );\n          }.bind(this),\n          this.name + \" interface: toJSON operation on \" + desc\n        );\n      }\n    };\n\n    IdlInterface.prototype.test_member_maplike = function (member) {\n      subsetTestByKey(\n        this.name,\n        test,\n        () => {\n          const proto = this.get_interface_object().prototype;\n\n          const methods = [\n            [\"entries\", 0],\n            [\"keys\", 0],\n            [\"values\", 0],\n            [\"forEach\", 1],\n            [\"get\", 1],\n            [\"has\", 1],\n          ];\n          if (!member.readonly) {\n            methods.push([\"set\", 2], [\"delete\", 1], [\"clear\", 0]);\n          }\n\n          for (const [name, length] of methods) {\n            const desc = Object.getOwnPropertyDescriptor(proto, name);\n            assert_equals(\n              typeof desc.value,\n              \"function\",\n              `${name} should be a function`\n            );\n            assert_equals(desc.enumerable, true, `${name} enumerable`);\n            assert_equals(desc.configurable, true, `${name} configurable`);\n            assert_equals(desc.writable, true, `${name} writable`);\n            assert_equals(\n              desc.value.length,\n              length,\n              `${name} function object length should be ${length}`\n            );\n            assert_equals(\n              desc.value.name,\n              name,\n              `${name} function object should have the right name`\n            );\n          }\n\n          const iteratorDesc = Object.getOwnPropertyDescriptor(\n            proto,\n            Symbol.iterator\n          );\n          assert_equals(\n            iteratorDesc.value,\n            proto.entries,\n            `@@iterator should equal entries`\n          );\n          assert_equals(\n            iteratorDesc.enumerable,\n            false,\n            `@@iterator enumerable`\n          );\n          assert_equals(\n            iteratorDesc.configurable,\n            true,\n            `@@iterator configurable`\n          );\n          assert_equals(iteratorDesc.writable, true, `@@iterator writable`);\n\n          const sizeDesc = Object.getOwnPropertyDescriptor(proto, \"size\");\n          assert_equals(\n            typeof sizeDesc.get,\n            \"function\",\n            `size getter should be a function`\n          );\n          assert_equals(\n            sizeDesc.set,\n            undefined,\n            `size should not have a setter`\n          );\n          assert_equals(sizeDesc.enumerable, true, `size enumerable`);\n          assert_equals(sizeDesc.configurable, true, `size configurable`);\n          assert_equals(sizeDesc.get.length, 0, `size getter length`);\n          assert_equals(sizeDesc.get.name, \"get size\", `size getter name`);\n        },\n        `${this.name} interface: maplike<${member.idlType.map((t) => t.idlType).join(\", \")}>`\n      );\n    };\n\n    IdlInterface.prototype.test_member_setlike = function (member) {\n      subsetTestByKey(\n        this.name,\n        test,\n        () => {\n          const proto = this.get_interface_object().prototype;\n\n          const methods = [\n            [\"entries\", 0],\n            [\"keys\", 0],\n            [\"values\", 0],\n            [\"forEach\", 1],\n            [\"has\", 1],\n          ];\n          if (!member.readonly) {\n            methods.push([\"add\", 1], [\"delete\", 1], [\"clear\", 0]);\n          }\n\n          for (const [name, length] of methods) {\n            const desc = Object.getOwnPropertyDescriptor(proto, name);\n            assert_equals(\n              typeof desc.value,\n              \"function\",\n              `${name} should be a function`\n            );\n            assert_equals(desc.enumerable, true, `${name} enumerable`);\n            assert_equals(desc.configurable, true, `${name} configurable`);\n            assert_equals(desc.writable, true, `${name} writable`);\n            assert_equals(\n              desc.value.length,\n              length,\n              `${name} function object length should be ${length}`\n            );\n            assert_equals(\n              desc.value.name,\n              name,\n              `${name} function object should have the right name`\n            );\n          }\n\n          const iteratorDesc = Object.getOwnPropertyDescriptor(\n            proto,\n            Symbol.iterator\n          );\n          assert_equals(\n            iteratorDesc.value,\n            proto.values,\n            `@@iterator should equal values`\n          );\n          assert_equals(\n            iteratorDesc.enumerable,\n            false,\n            `@@iterator enumerable`\n          );\n          assert_equals(\n            iteratorDesc.configurable,\n            true,\n            `@@iterator configurable`\n          );\n          assert_equals(iteratorDesc.writable, true, `@@iterator writable`);\n\n          const sizeDesc = Object.getOwnPropertyDescriptor(proto, \"size\");\n          assert_equals(\n            typeof sizeDesc.get,\n            \"function\",\n            `size getter should be a function`\n          );\n          assert_equals(\n            sizeDesc.set,\n            undefined,\n            `size should not have a setter`\n          );\n          assert_equals(sizeDesc.enumerable, true, `size enumerable`);\n          assert_equals(sizeDesc.configurable, true, `size configurable`);\n          assert_equals(sizeDesc.get.length, 0, `size getter length`);\n          assert_equals(sizeDesc.get.name, \"get size\", `size getter name`);\n        },\n        `${this.name} interface: setlike<${member.idlType.map((t) => t.idlType).join(\", \")}>`\n      );\n    };\n\n    IdlInterface.prototype.test_member_iterable = function (member) {\n      subsetTestByKey(\n        this.name,\n        test,\n        () => {\n          const isPairIterator = member.idlType.length === 2;\n          const proto = this.get_interface_object().prototype;\n\n          const methods = [\n            [\"entries\", 0],\n            [\"keys\", 0],\n            [\"values\", 0],\n            [\"forEach\", 1],\n          ];\n\n          for (const [name, length] of methods) {\n            const desc = Object.getOwnPropertyDescriptor(proto, name);\n            assert_equals(\n              typeof desc.value,\n              \"function\",\n              `${name} should be a function`\n            );\n            assert_equals(desc.enumerable, true, `${name} enumerable`);\n            assert_equals(desc.configurable, true, `${name} configurable`);\n            assert_equals(desc.writable, true, `${name} writable`);\n            assert_equals(\n              desc.value.length,\n              length,\n              `${name} function object length should be ${length}`\n            );\n            assert_equals(\n              desc.value.name,\n              name,\n              `${name} function object should have the right name`\n            );\n\n            if (!isPairIterator) {\n              assert_equals(\n                desc.value,\n                Array.prototype[name],\n                `${name} equality with Array.prototype version`\n              );\n            }\n          }\n\n          const iteratorDesc = Object.getOwnPropertyDescriptor(\n            proto,\n            Symbol.iterator\n          );\n          assert_equals(\n            iteratorDesc.enumerable,\n            false,\n            `@@iterator enumerable`\n          );\n          assert_equals(\n            iteratorDesc.configurable,\n            true,\n            `@@iterator configurable`\n          );\n          assert_equals(iteratorDesc.writable, true, `@@iterator writable`);\n\n          if (isPairIterator) {\n            assert_equals(\n              iteratorDesc.value,\n              proto.entries,\n              `@@iterator equality with entries`\n            );\n          } else {\n            assert_equals(\n              iteratorDesc.value,\n              Array.prototype[Symbol.iterator],\n              `@@iterator equality with Array.prototype version`\n            );\n          }\n        },\n        `${this.name} interface: iterable<${member.idlType.map((t) => t.idlType).join(\", \")}>`\n      );\n    };\n\n    IdlInterface.prototype.test_member_async_iterable = function (member) {\n      subsetTestByKey(\n        this.name,\n        test,\n        () => {\n          const isPairIterator = member.idlType.length === 2;\n          const proto = this.get_interface_object().prototype;\n\n          // Note that although the spec allows arguments, which will be passed to the @@asyncIterator\n          // method (which is either values or entries), those arguments must always be optional. So\n          // length of 0 is still correct for values and entries.\n          const methods = [[\"values\", 0]];\n\n          if (isPairIterator) {\n            methods.push([\"entries\", 0], [\"keys\", 0]);\n          }\n\n          for (const [name, length] of methods) {\n            const desc = Object.getOwnPropertyDescriptor(proto, name);\n            assert_equals(\n              typeof desc.value,\n              \"function\",\n              `${name} should be a function`\n            );\n            assert_equals(desc.enumerable, true, `${name} enumerable`);\n            assert_equals(desc.configurable, true, `${name} configurable`);\n            assert_equals(desc.writable, true, `${name} writable`);\n            assert_equals(\n              desc.value.length,\n              length,\n              `${name} function object length should be ${length}`\n            );\n            assert_equals(\n              desc.value.name,\n              name,\n              `${name} function object should have the right name`\n            );\n          }\n\n          const iteratorDesc = Object.getOwnPropertyDescriptor(\n            proto,\n            Symbol.asyncIterator\n          );\n          assert_equals(\n            iteratorDesc.enumerable,\n            false,\n            `@@iterator enumerable`\n          );\n          assert_equals(\n            iteratorDesc.configurable,\n            true,\n            `@@iterator configurable`\n          );\n          assert_equals(iteratorDesc.writable, true, `@@iterator writable`);\n\n          if (isPairIterator) {\n            assert_equals(\n              iteratorDesc.value,\n              proto.entries,\n              `@@iterator equality with entries`\n            );\n          } else {\n            assert_equals(\n              iteratorDesc.value,\n              proto.values,\n              `@@iterator equality with values`\n            );\n          }\n        },\n        `${this.name} interface: async iterable<${member.idlType.map((t) => t.idlType).join(\", \")}>`\n      );\n    };\n\n    IdlInterface.prototype.test_member_stringifier = function (member) {\n      subsetTestByKey(\n        this.name,\n        test,\n        function () {\n          if (!this.should_have_interface_object()) {\n            return;\n          }\n\n          this.assert_interface_object_exists();\n\n          if (this.is_callback()) {\n            assert_false(\n              \"prototype\" in this.get_interface_object(),\n              this.name + ' should not have a \"prototype\" property'\n            );\n            return;\n          }\n\n          assert_own_property(\n            this.get_interface_object(),\n            \"prototype\",\n            'interface \"' +\n              this.name +\n              '\" does not have own property \"prototype\"'\n          );\n\n          // \". . . the property exists on the interface prototype object.\"\n          var interfacePrototypeObject = this.get_interface_object().prototype;\n          assert_own_property(\n            interfacePrototypeObject,\n            \"toString\",\n            \"interface prototype object missing non-static operation\"\n          );\n\n          var stringifierUnforgeable = member.isUnforgeable;\n          var desc = Object.getOwnPropertyDescriptor(\n            interfacePrototypeObject,\n            \"toString\"\n          );\n          // \"The property has attributes { [[Writable]]: B,\n          // [[Enumerable]]: true, [[Configurable]]: B }, where B is false if the\n          // stringifier is unforgeable on the interface, and true otherwise.\"\n          assert_false(\"get\" in desc, \"property should not have a getter\");\n          assert_false(\"set\" in desc, \"property should not have a setter\");\n          assert_equals(\n            desc.writable,\n            !stringifierUnforgeable,\n            \"property should be writable if and only if not unforgeable\"\n          );\n          assert_true(desc.enumerable, \"property should be enumerable\");\n          assert_equals(\n            desc.configurable,\n            !stringifierUnforgeable,\n            \"property should be configurable if and only if not unforgeable\"\n          );\n          // \"The value of the property is a Function object, which behaves as\n          // follows . . .\"\n          assert_equals(\n            typeof interfacePrototypeObject.toString,\n            \"function\",\n            \"property must be a function\"\n          );\n          // \"The value of the Function object’s “length” property is the Number\n          // value 0.\"\n          assert_equals(\n            interfacePrototypeObject.toString.length,\n            0,\n            \"property has wrong .length\"\n          );\n\n          // \"Let O be the result of calling ToObject on the this value.\"\n          assert_throws_js(\n            globalOf(interfacePrototypeObject.toString).TypeError,\n            function () {\n              interfacePrototypeObject.toString.apply(null, []);\n            },\n            \"calling stringifier with this = null didn't throw TypeError\"\n          );\n\n          // \"If O is not an object that implements the interface on which the\n          // stringifier was declared, then throw a TypeError.\"\n          //\n          // TODO: Test a platform object that implements some other\n          // interface.  (Have to be sure to get inheritance right.)\n          assert_throws_js(\n            globalOf(interfacePrototypeObject.toString).TypeError,\n            function () {\n              interfacePrototypeObject.toString.apply({}, []);\n            },\n            \"calling stringifier with this = {} didn't throw TypeError\"\n          );\n        }.bind(this),\n        this.name + \" interface: stringifier\"\n      );\n    };\n\n    IdlInterface.prototype.test_members = function () {\n      var unexposed_members = new Set();\n      for (var i = 0; i < this.members.length; i++) {\n        var member = this.members[i];\n        if (member.untested) {\n          continue;\n        }\n\n        if (!exposed_in(exposure_set(member, this.exposureSet))) {\n          if (!unexposed_members.has(member.name)) {\n            unexposed_members.add(member.name);\n            subsetTestByKey(\n              this.name,\n              test,\n              function () {\n                // It's not exposed, so we shouldn't find it anywhere.\n                assert_false(\n                  member.name in this.get_interface_object(),\n                  \"The interface object must not have a property \" +\n                    format_value(member.name)\n                );\n                assert_false(\n                  member.name in this.get_interface_object().prototype,\n                  \"The prototype object must not have a property \" +\n                    format_value(member.name)\n                );\n              }.bind(this),\n              this.name + \" interface: member \" + member.name\n            );\n          }\n          continue;\n        }\n\n        switch (member.type) {\n          case \"const\":\n            this.test_member_const(member);\n            break;\n\n          case \"attribute\":\n            // For unforgeable attributes, we do the checks in\n            // test_interface_of instead.\n            if (!member.isUnforgeable) {\n              this.test_member_attribute(member);\n            }\n            if (member.special === \"stringifier\") {\n              this.test_member_stringifier(member);\n            }\n            break;\n\n          case \"operation\":\n            // TODO: Need to correctly handle multiple operations with the same\n            // identifier.\n            // For unforgeable operations, we do the checks in\n            // test_interface_of instead.\n            if (member.name) {\n              if (!member.isUnforgeable) {\n                this.test_member_operation(member);\n              }\n            } else if (member.special === \"stringifier\") {\n              this.test_member_stringifier(member);\n            }\n            break;\n\n          case \"iterable\":\n            if (member.async) {\n              this.test_member_async_iterable(member);\n            } else {\n              this.test_member_iterable(member);\n            }\n            break;\n          case \"maplike\":\n            this.test_member_maplike(member);\n            break;\n          case \"setlike\":\n            this.test_member_setlike(member);\n            break;\n          default:\n            // TODO: check more member types.\n            break;\n        }\n      }\n    };\n\n    IdlInterface.prototype.test_object = function (desc) {\n      var obj,\n        exception = null;\n      try {\n        obj = eval(desc);\n      } catch (e) {\n        exception = e;\n      }\n\n      var expected_typeof;\n      if (this.name == \"HTMLAllCollection\") {\n        // Result of [[IsHTMLDDA]] slot\n        expected_typeof = \"undefined\";\n      } else {\n        expected_typeof = \"object\";\n      }\n\n      if (this.is_callback()) {\n        assert_equals(\n          exception,\n          null,\n          \"Unexpected exception when evaluating object\"\n        );\n        assert_equals(typeof obj, expected_typeof, \"wrong typeof object\");\n      } else {\n        this.test_primary_interface_of(desc, obj, exception, expected_typeof);\n\n        var current_interface = this;\n        while (current_interface) {\n          if (!(current_interface.name in this.array.members)) {\n            throw new IdlHarnessError(\n              \"Interface \" +\n                current_interface.name +\n                \" not found (inherited by \" +\n                this.name +\n                \")\"\n            );\n          }\n          if (\n            current_interface.prevent_multiple_testing &&\n            current_interface.already_tested\n          ) {\n            return;\n          }\n          current_interface.test_interface_of(\n            desc,\n            obj,\n            exception,\n            expected_typeof\n          );\n          current_interface = this.array.members[current_interface.base];\n        }\n      }\n    };\n\n    IdlInterface.prototype.test_primary_interface_of = function (\n      desc,\n      obj,\n      exception,\n      expected_typeof\n    ) {\n      // Only the object itself, not its members, are tested here, so if the\n      // interface is untested, there is nothing to do.\n      if (this.untested) {\n        return;\n      }\n\n      // \"The internal [[SetPrototypeOf]] method of every platform object that\n      // implements an interface with the [Global] extended\n      // attribute must execute the same algorithm as is defined for the\n      // [[SetPrototypeOf]] internal method of an immutable prototype exotic\n      // object.\"\n      // https://webidl.spec.whatwg.org/#platform-object-setprototypeof\n      if (this.is_global()) {\n        this.test_immutable_prototype(\"global platform object\", obj);\n      }\n\n      // We can't easily test that its prototype is correct if there's no\n      // interface object, or the object is from a different global environment\n      // (not instanceof Object).  TODO: test in this case that its prototype at\n      // least looks correct, even if we can't test that it's actually correct.\n      if (\n        this.should_have_interface_object() &&\n        (typeof obj != expected_typeof || obj instanceof Object)\n      ) {\n        subsetTestByKey(\n          this.name,\n          test,\n          function () {\n            assert_equals(\n              exception,\n              null,\n              \"Unexpected exception when evaluating object\"\n            );\n            assert_equals(typeof obj, expected_typeof, \"wrong typeof object\");\n            this.assert_interface_object_exists();\n            assert_own_property(\n              this.get_interface_object(),\n              \"prototype\",\n              'interface \"' +\n                this.name +\n                '\" does not have own property \"prototype\"'\n            );\n\n            // \"The value of the internal [[Prototype]] property of the\n            // platform object is the interface prototype object of the primary\n            // interface from the platform object’s associated global\n            // environment.\"\n            assert_equals(\n              Object.getPrototypeOf(obj),\n              this.get_interface_object().prototype,\n              desc + \"'s prototype is not \" + this.name + \".prototype\"\n            );\n          }.bind(this),\n          this.name + \" must be primary interface of \" + desc\n        );\n      }\n\n      // \"The class string of a platform object that implements one or more\n      // interfaces must be the qualified name of the primary interface of the\n      // platform object.\"\n      subsetTestByKey(\n        this.name,\n        test,\n        function () {\n          assert_equals(\n            exception,\n            null,\n            \"Unexpected exception when evaluating object\"\n          );\n          assert_equals(typeof obj, expected_typeof, \"wrong typeof object\");\n          assert_class_string(\n            obj,\n            this.get_qualified_name(),\n            \"class string of \" + desc\n          );\n          if (!this.has_stringifier()) {\n            assert_equals(\n              String(obj),\n              \"[object \" + this.get_qualified_name() + \"]\",\n              \"String(\" + desc + \")\"\n            );\n          }\n        }.bind(this),\n        \"Stringification of \" + desc\n      );\n    };\n\n    IdlInterface.prototype.test_interface_of = function (\n      desc,\n      obj,\n      exception,\n      expected_typeof\n    ) {\n      // TODO: Indexed and named properties, more checks on interface members\n      this.already_tested = true;\n      if (!shouldRunSubTest(this.name)) {\n        return;\n      }\n\n      var unexposed_properties = new Set();\n      for (var i = 0; i < this.members.length; i++) {\n        var member = this.members[i];\n        if (member.untested) {\n          continue;\n        }\n        if (!exposed_in(exposure_set(member, this.exposureSet))) {\n          if (!unexposed_properties.has(member.name)) {\n            unexposed_properties.add(member.name);\n            subsetTestByKey(\n              this.name,\n              test,\n              function () {\n                assert_equals(\n                  exception,\n                  null,\n                  \"Unexpected exception when evaluating object\"\n                );\n                assert_false(member.name in obj);\n              }.bind(this),\n              this.name +\n                \" interface: \" +\n                desc +\n                ' must not have property \"' +\n                member.name +\n                '\"'\n            );\n          }\n          continue;\n        }\n        if (member.type == \"attribute\" && member.isUnforgeable) {\n          var a_test = subsetTestByKey(\n            this.name,\n            async_test,\n            this.name +\n              \" interface: \" +\n              desc +\n              ' must have own property \"' +\n              member.name +\n              '\"'\n          );\n          a_test.step(\n            function () {\n              assert_equals(\n                exception,\n                null,\n                \"Unexpected exception when evaluating object\"\n              );\n              assert_equals(typeof obj, expected_typeof, \"wrong typeof object\");\n              // Call do_interface_attribute_asserts last, since it will call a_test.done()\n              this.do_interface_attribute_asserts(obj, member, a_test);\n            }.bind(this)\n          );\n        } else if (\n          member.type == \"operation\" &&\n          member.name &&\n          member.isUnforgeable\n        ) {\n          var a_test = subsetTestByKey(\n            this.name,\n            async_test,\n            this.name +\n              \" interface: \" +\n              desc +\n              ' must have own property \"' +\n              member.name +\n              '\"'\n          );\n          a_test.step(\n            function () {\n              assert_equals(\n                exception,\n                null,\n                \"Unexpected exception when evaluating object\"\n              );\n              assert_equals(typeof obj, expected_typeof, \"wrong typeof object\");\n              assert_own_property(\n                obj,\n                member.name,\n                \"Doesn't have the unforgeable operation property\"\n              );\n              this.do_member_operation_asserts(obj, member, a_test);\n            }.bind(this)\n          );\n        } else if (\n          (member.type == \"const\" ||\n            member.type == \"attribute\" ||\n            member.type == \"operation\") &&\n          member.name\n        ) {\n          subsetTestByKey(\n            this.name,\n            test,\n            function () {\n              assert_equals(\n                exception,\n                null,\n                \"Unexpected exception when evaluating object\"\n              );\n              assert_equals(typeof obj, expected_typeof, \"wrong typeof object\");\n              if (member.special !== \"static\") {\n                if (!this.is_global()) {\n                  assert_inherits(obj, member.name);\n                } else {\n                  assert_own_property(obj, member.name);\n                }\n\n                if (member.type == \"const\") {\n                  assert_equals(obj[member.name], constValue(member.value));\n                }\n                if (member.type == \"attribute\") {\n                  // Attributes are accessor properties, so they might\n                  // legitimately throw an exception rather than returning\n                  // anything.\n                  var property,\n                    thrown = false;\n                  try {\n                    property = obj[member.name];\n                  } catch (e) {\n                    thrown = true;\n                  }\n                  if (!thrown) {\n                    if (this.name == \"Document\" && member.name == \"all\") {\n                      // Result of [[IsHTMLDDA]] slot\n                      assert_equals(typeof property, \"undefined\");\n                    } else {\n                      this.array.assert_type_is(property, member.idlType);\n                    }\n                  }\n                }\n                if (member.type == \"operation\") {\n                  assert_equals(typeof obj[member.name], \"function\");\n                }\n              }\n            }.bind(this),\n            this.name +\n              \" interface: \" +\n              desc +\n              ' must inherit property \"' +\n              member +\n              '\" with the proper type'\n          );\n        }\n        // TODO: This is wrong if there are multiple operations with the same\n        // identifier.\n        // TODO: Test passing arguments of the wrong type.\n        if (\n          member.type == \"operation\" &&\n          member.name &&\n          member.arguments.length\n        ) {\n          var description =\n            this.name +\n            \" interface: calling \" +\n            member +\n            \" on \" +\n            desc +\n            \" with too few arguments must throw TypeError\";\n          var a_test = subsetTestByKey(this.name, async_test, description);\n          a_test.step(\n            function () {\n              assert_equals(\n                exception,\n                null,\n                \"Unexpected exception when evaluating object\"\n              );\n              assert_equals(typeof obj, expected_typeof, \"wrong typeof object\");\n              var fn;\n              if (member.special !== \"static\") {\n                if (!this.is_global() && !member.isUnforgeable) {\n                  assert_inherits(obj, member.name);\n                } else {\n                  assert_own_property(obj, member.name);\n                }\n                fn = obj[member.name];\n              } else {\n                assert_own_property(\n                  obj.constructor,\n                  member.name,\n                  \"interface object must have static operation as own property\"\n                );\n                fn = obj.constructor[member.name];\n              }\n\n              var minLength = minOverloadLength(\n                this.members.filter(function (m) {\n                  return m.type == \"operation\" && m.name == member.name;\n                })\n              );\n              var args = [];\n              var cb = awaitNCallbacks(minLength, a_test.done.bind(a_test));\n              for (var i = 0; i < minLength; i++) {\n                throwOrReject(\n                  a_test,\n                  member,\n                  fn,\n                  obj,\n                  args,\n                  \"Called with \" + i + \" arguments\",\n                  cb\n                );\n\n                args.push(create_suitable_object(member.arguments[i].idlType));\n              }\n              if (minLength === 0) {\n                cb();\n              }\n            }.bind(this)\n          );\n        }\n\n        if (member.is_to_json_regular_operation()) {\n          this.test_to_json_operation(desc, obj, member);\n        }\n      }\n    };\n\n    IdlInterface.prototype.has_stringifier = function () {\n      if (this.name === \"DOMException\") {\n        // toString is inherited from Error, so don't assume we have the\n        // default stringifer\n        return true;\n      }\n      if (\n        this.members.some(function (member) {\n          return member.special === \"stringifier\";\n        })\n      ) {\n        return true;\n      }\n      if (this.base && this.array.members[this.base].has_stringifier()) {\n        return true;\n      }\n      return false;\n    };\n\n    IdlInterface.prototype.do_interface_attribute_asserts = function (\n      obj,\n      member,\n      a_test\n    ) {\n      // This function tests WebIDL as of 2015-01-27.\n      // TODO: Consider [Exposed].\n\n      // This is called by test_member_attribute() with the prototype as obj if\n      // it is not a global, and the global otherwise, and by test_interface_of()\n      // with the object as obj.\n\n      var pendingPromises = [];\n\n      // \"The name of the property is the identifier of the attribute.\"\n      assert_own_property(obj, member.name);\n\n      // \"The property has attributes { [[Get]]: G, [[Set]]: S, [[Enumerable]]:\n      // true, [[Configurable]]: configurable }, where:\n      // \"configurable is false if the attribute was declared with the\n      // [LegacyUnforgeable] extended attribute and true otherwise;\n      // \"G is the attribute getter, defined below; and\n      // \"S is the attribute setter, also defined below.\"\n      var desc = Object.getOwnPropertyDescriptor(obj, member.name);\n      assert_false(\n        \"value\" in desc,\n        'property descriptor should not have a \"value\" field'\n      );\n      assert_false(\n        \"writable\" in desc,\n        'property descriptor should not have a \"writable\" field'\n      );\n      assert_true(desc.enumerable, \"property should be enumerable\");\n      if (member.isUnforgeable) {\n        assert_false(\n          desc.configurable,\n          \"[LegacyUnforgeable] property must not be configurable\"\n        );\n      } else {\n        assert_true(desc.configurable, \"property must be configurable\");\n      }\n\n      // \"The attribute getter is a Function object whose behavior when invoked\n      // is as follows:\"\n      assert_equals(typeof desc.get, \"function\", \"getter must be Function\");\n\n      // \"If the attribute is a regular attribute, then:\"\n      if (member.special !== \"static\") {\n        // \"If O is not a platform object that implements I, then:\n        // \"If the attribute was specified with the [LegacyLenientThis] extended\n        // attribute, then return undefined.\n        // \"Otherwise, throw a TypeError.\"\n        if (!member.has_extended_attribute(\"LegacyLenientThis\")) {\n          if (member.idlType.generic !== \"Promise\") {\n            assert_throws_js(\n              globalOf(desc.get).TypeError,\n              function () {\n                desc.get.call({});\n              }.bind(this),\n              \"calling getter on wrong object type must throw TypeError\"\n            );\n          } else {\n            pendingPromises.push(\n              promise_rejects_js(\n                a_test,\n                TypeError,\n                desc.get.call({}),\n                \"calling getter on wrong object type must reject the return promise with TypeError\"\n              )\n            );\n          }\n        } else {\n          assert_equals(\n            desc.get.call({}),\n            undefined,\n            \"calling getter on wrong object type must return undefined\"\n          );\n        }\n      }\n\n      // \"The value of the Function object’s “length” property is the Number\n      // value 0.\"\n      assert_equals(desc.get.length, 0, \"getter length must be 0\");\n\n      // \"Let name be the string \"get \" prepended to attribute’s identifier.\"\n      // \"Perform ! SetFunctionName(F, name).\"\n      assert_equals(\n        desc.get.name,\n        \"get \" + member.name,\n        \"getter must have the name 'get \" + member.name + \"'\"\n      );\n\n      // TODO: Test calling setter on the interface prototype (should throw\n      // TypeError in most cases).\n      if (\n        member.readonly &&\n        !member.has_extended_attribute(\"LegacyLenientSetter\") &&\n        !member.has_extended_attribute(\"PutForwards\") &&\n        !member.has_extended_attribute(\"Replaceable\")\n      ) {\n        // \"The attribute setter is undefined if the attribute is declared\n        // readonly and has neither a [PutForwards] nor a [Replaceable]\n        // extended attribute declared on it.\"\n        assert_equals(\n          desc.set,\n          undefined,\n          \"setter must be undefined for readonly attributes\"\n        );\n      } else {\n        // \"Otherwise, it is a Function object whose behavior when\n        // invoked is as follows:\"\n        assert_equals(\n          typeof desc.set,\n          \"function\",\n          \"setter must be function for PutForwards, Replaceable, or non-readonly attributes\"\n        );\n\n        // \"If the attribute is a regular attribute, then:\"\n        if (member.special !== \"static\") {\n          // \"If /validThis/ is false and the attribute was not specified\n          // with the [LegacyLenientThis] extended attribute, then throw a\n          // TypeError.\"\n          // \"If the attribute is declared with a [Replaceable] extended\n          // attribute, then: ...\"\n          // \"If validThis is false, then return.\"\n          if (!member.has_extended_attribute(\"LegacyLenientThis\")) {\n            assert_throws_js(\n              globalOf(desc.set).TypeError,\n              function () {\n                desc.set.call({});\n              }.bind(this),\n              \"calling setter on wrong object type must throw TypeError\"\n            );\n          } else {\n            assert_equals(\n              desc.set.call({}),\n              undefined,\n              \"calling setter on wrong object type must return undefined\"\n            );\n          }\n        }\n\n        // \"The value of the Function object’s “length” property is the Number\n        // value 1.\"\n        assert_equals(desc.set.length, 1, \"setter length must be 1\");\n\n        // \"Let name be the string \"set \" prepended to id.\"\n        // \"Perform ! SetFunctionName(F, name).\"\n        assert_equals(\n          desc.set.name,\n          \"set \" + member.name,\n          \"The attribute setter must have the name 'set \" + member.name + \"'\"\n        );\n      }\n\n      Promise.all(pendingPromises).then(a_test.done.bind(a_test));\n    };\n\n    /// IdlInterfaceMember ///\n    function IdlInterfaceMember(obj) {\n      /**\n       * obj is an object produced by the WebIDLParser.js \"ifMember\" production.\n       * We just forward all properties to this object without modification,\n       * except for special extAttrs handling.\n       */\n      for (var k in obj.toJSON()) {\n        this[k] = obj[k];\n      }\n      if (!(\"extAttrs\" in this)) {\n        this.extAttrs = [];\n      }\n\n      this.isUnforgeable = this.has_extended_attribute(\"LegacyUnforgeable\");\n      this.isUnscopable = this.has_extended_attribute(\"Unscopable\");\n    }\n\n    IdlInterfaceMember.prototype = Object.create(IdlObject.prototype);\n\n    IdlInterfaceMember.prototype.toJSON = function () {\n      return this;\n    };\n\n    IdlInterfaceMember.prototype.is_to_json_regular_operation = function () {\n      return (\n        this.type == \"operation\" &&\n        this.special !== \"static\" &&\n        this.name == \"toJSON\"\n      );\n    };\n\n    IdlInterfaceMember.prototype.toString = function () {\n      function formatType(type) {\n        var result;\n        if (type.generic) {\n          result =\n            type.generic + \"<\" + type.idlType.map(formatType).join(\", \") + \">\";\n        } else if (type.union) {\n          result = \"(\" + type.subtype.map(formatType).join(\" or \") + \")\";\n        } else {\n          result = type.idlType;\n        }\n        if (type.nullable) {\n          result += \"?\";\n        }\n        return result;\n      }\n\n      if (this.type === \"operation\") {\n        var args = this.arguments\n          .map(function (m) {\n            return [\n              m.optional ? \"optional \" : \"\",\n              formatType(m.idlType),\n              m.variadic ? \"...\" : \"\",\n            ].join(\"\");\n          })\n          .join(\", \");\n        return this.name + \"(\" + args + \")\";\n      }\n\n      return this.name;\n    };\n\n    /// Internal helper functions ///\n    function create_suitable_object(type) {\n      /**\n       * type is an object produced by the WebIDLParser.js \"type\" production.  We\n       * return a JavaScript value that matches the type, if we can figure out\n       * how.\n       */\n      if (type.nullable) {\n        return null;\n      }\n      switch (type.idlType) {\n        case \"any\":\n        case \"boolean\":\n          return true;\n\n        case \"byte\":\n        case \"octet\":\n        case \"short\":\n        case \"unsigned short\":\n        case \"long\":\n        case \"unsigned long\":\n        case \"long long\":\n        case \"unsigned long long\":\n        case \"float\":\n        case \"double\":\n        case \"unrestricted float\":\n        case \"unrestricted double\":\n          return 7;\n\n        case \"DOMString\":\n        case \"ByteString\":\n        case \"USVString\":\n          return \"foo\";\n\n        case \"object\":\n          return { a: \"b\" };\n\n        case \"Node\":\n          return document.createTextNode(\"abc\");\n      }\n      return null;\n    }\n\n    /// IdlEnum ///\n    // Used for IdlArray.prototype.assert_type_is\n    function IdlEnum(obj) {\n      /**\n       * obj is an object produced by the WebIDLParser.js \"dictionary\"\n       * production.\n       */\n\n      /** Self-explanatory. */\n      this.name = obj.name;\n\n      /** An array of values produced by the \"enum\" production. */\n      this.values = obj.values;\n    }\n\n    IdlEnum.prototype = Object.create(IdlObject.prototype);\n\n    /// IdlCallback ///\n    // Used for IdlArray.prototype.assert_type_is\n    function IdlCallback(obj) {\n      /**\n       * obj is an object produced by the WebIDLParser.js \"callback\"\n       * production.\n       */\n\n      /** Self-explanatory. */\n      this.name = obj.name;\n\n      /** Arguments for the callback. */\n      this.arguments = obj.arguments;\n    }\n\n    IdlCallback.prototype = Object.create(IdlObject.prototype);\n\n    /// IdlTypedef ///\n    // Used for IdlArray.prototype.assert_type_is\n    function IdlTypedef(obj) {\n      /**\n       * obj is an object produced by the WebIDLParser.js \"typedef\"\n       * production.\n       */\n\n      /** Self-explanatory. */\n      this.name = obj.name;\n\n      /** The idlType that we are supposed to be typedeffing to. */\n      this.idlType = obj.idlType;\n    }\n\n    IdlTypedef.prototype = Object.create(IdlObject.prototype);\n\n    /// IdlNamespace ///\n    function IdlNamespace(obj) {\n      this.name = obj.name;\n      this.extAttrs = obj.extAttrs;\n      this.untested = obj.untested;\n      /** A back-reference to our IdlArray. */\n      this.array = obj.array;\n\n      /** An array of IdlInterfaceMembers. */\n      this.members = obj.members.map((m) => new IdlInterfaceMember(m));\n    }\n\n    IdlNamespace.prototype = Object.create(IdlObject.prototype);\n\n    IdlNamespace.prototype.do_member_operation_asserts = function (\n      memberHolderObject,\n      member,\n      a_test\n    ) {\n      var desc = Object.getOwnPropertyDescriptor(\n        memberHolderObject,\n        member.name\n      );\n\n      assert_false(\"get\" in desc, \"property should not have a getter\");\n      assert_false(\"set\" in desc, \"property should not have a setter\");\n      assert_equals(\n        desc.writable,\n        !member.isUnforgeable,\n        \"property should be writable if and only if not unforgeable\"\n      );\n      assert_true(desc.enumerable, \"property should be enumerable\");\n      assert_equals(\n        desc.configurable,\n        !member.isUnforgeable,\n        \"property should be configurable if and only if not unforgeable\"\n      );\n\n      assert_equals(\n        typeof memberHolderObject[member.name],\n        \"function\",\n        \"property must be a function\"\n      );\n\n      assert_equals(\n        memberHolderObject[member.name].length,\n        minOverloadLength(\n          this.members.filter(function (m) {\n            return m.type == \"operation\" && m.name == member.name;\n          })\n        ),\n        \"operation has wrong .length\"\n      );\n      a_test.done();\n    };\n\n    IdlNamespace.prototype.test_member_operation = function (member) {\n      if (!shouldRunSubTest(this.name)) {\n        return;\n      }\n      var a_test = subsetTestByKey(\n        this.name,\n        async_test,\n        this.name + \" namespace: operation \" + member\n      );\n      a_test.step(\n        function () {\n          assert_own_property(\n            self[this.name],\n            member.name,\n            \"namespace object missing operation \" + format_value(member.name)\n          );\n\n          this.do_member_operation_asserts(self[this.name], member, a_test);\n        }.bind(this)\n      );\n    };\n\n    IdlNamespace.prototype.test_member_attribute = function (member) {\n      if (!shouldRunSubTest(this.name)) {\n        return;\n      }\n      var a_test = subsetTestByKey(\n        this.name,\n        async_test,\n        this.name + \" namespace: attribute \" + member.name\n      );\n      a_test.step(\n        function () {\n          assert_own_property(\n            self[this.name],\n            member.name,\n            this.name + \" does not have property \" + format_value(member.name)\n          );\n\n          var desc = Object.getOwnPropertyDescriptor(\n            self[this.name],\n            member.name\n          );\n          assert_equals(\n            desc.set,\n            undefined,\n            \"setter must be undefined for namespace members\"\n          );\n          a_test.done();\n        }.bind(this)\n      );\n    };\n\n    IdlNamespace.prototype.test_self = function () {\n      /**\n       * TODO(lukebjerring): Assert:\n       * - \"Note that unlike interfaces or dictionaries, namespaces do not create types.\"\n       */\n\n      subsetTestByKey(\n        this.name,\n        test,\n        () => {\n          assert_true(\n            this.extAttrs.every(\n              (o) => o.name === \"Exposed\" || o.name === \"SecureContext\"\n            ),\n            \"Only the [Exposed] and [SecureContext] extended attributes are applicable to namespaces\"\n          );\n          assert_true(\n            this.has_extended_attribute(\"Exposed\"),\n            \"Namespaces must be annotated with the [Exposed] extended attribute\"\n          );\n        },\n        `${this.name} namespace: extended attributes`\n      );\n\n      const namespaceObject = self[this.name];\n\n      subsetTestByKey(\n        this.name,\n        test,\n        () => {\n          const desc = Object.getOwnPropertyDescriptor(self, this.name);\n          assert_equals(\n            desc.value,\n            namespaceObject,\n            `wrong value for ${this.name} namespace object`\n          );\n          assert_true(desc.writable, \"namespace object should be writable\");\n          assert_false(\n            desc.enumerable,\n            \"namespace object should not be enumerable\"\n          );\n          assert_true(\n            desc.configurable,\n            \"namespace object should be configurable\"\n          );\n          assert_false(\n            \"get\" in desc,\n            \"namespace object should not have a getter\"\n          );\n          assert_false(\n            \"set\" in desc,\n            \"namespace object should not have a setter\"\n          );\n        },\n        `${this.name} namespace: property descriptor`\n      );\n\n      subsetTestByKey(\n        this.name,\n        test,\n        () => {\n          assert_true(Object.isExtensible(namespaceObject));\n        },\n        `${this.name} namespace: [[Extensible]] is true`\n      );\n\n      subsetTestByKey(\n        this.name,\n        test,\n        () => {\n          assert_true(namespaceObject instanceof Object);\n\n          if (this.name === \"console\") {\n            // https://console.spec.whatwg.org/#console-namespace\n            const namespacePrototype = Object.getPrototypeOf(namespaceObject);\n            assert_equals(Reflect.ownKeys(namespacePrototype).length, 0);\n            assert_equals(\n              Object.getPrototypeOf(namespacePrototype),\n              Object.prototype\n            );\n          } else {\n            assert_equals(\n              Object.getPrototypeOf(namespaceObject),\n              Object.prototype\n            );\n          }\n        },\n        `${this.name} namespace: [[Prototype]] is Object.prototype`\n      );\n\n      subsetTestByKey(\n        this.name,\n        test,\n        () => {\n          assert_equals(typeof namespaceObject, \"object\");\n        },\n        `${this.name} namespace: typeof is \"object\"`\n      );\n\n      subsetTestByKey(\n        this.name,\n        test,\n        () => {\n          assert_equals(\n            Object.getOwnPropertyDescriptor(namespaceObject, \"length\"),\n            undefined,\n            \"length property must be undefined\"\n          );\n        },\n        `${this.name} namespace: has no length property`\n      );\n\n      subsetTestByKey(\n        this.name,\n        test,\n        () => {\n          assert_equals(\n            Object.getOwnPropertyDescriptor(namespaceObject, \"name\"),\n            undefined,\n            \"name property must be undefined\"\n          );\n        },\n        `${this.name} namespace: has no name property`\n      );\n    };\n\n    IdlNamespace.prototype.test = function () {\n      if (!this.untested) {\n        this.test_self();\n      }\n\n      for (const v of Object.values(this.members)) {\n        switch (v.type) {\n          case \"operation\":\n            this.test_member_operation(v);\n            break;\n\n          case \"attribute\":\n            this.test_member_attribute(v);\n            break;\n\n          default:\n            throw (\n              \"Invalid namespace member \" +\n              v.name +\n              \": \" +\n              v.type +\n              \" not supported\"\n            );\n        }\n      }\n    };\n  })();\n}\n\n/**\n * idl_test is a promise_test wrapper that handles the fetching of the IDL,\n * avoiding repetitive boilerplate.\n *\n * @param {String[]} srcs Spec name(s) for source idl files (fetched from\n *      /interfaces/{name}.idl).\n * @param {String[]} deps Spec name(s) for dependency idl files (fetched\n *      from /interfaces/{name}.idl). Order is important - dependencies from\n *      each source will only be included if they're already know to be a\n *      dependency (i.e. have already been seen).\n * @param {Function} setup_func Function for extra setup of the idl_array, such\n *      as adding objects. Do not call idl_array.test() in the setup; it is\n *      called by this function (idl_test).\n */\nfunction idl_test(srcs, deps, idl_setup_func) {\n  return promise_test(function (t) {\n    var idl_array = new IdlArray();\n    var setup_error = null;\n    const validationIgnored = [\n      \"constructor-member\",\n      \"dict-arg-default\",\n      \"require-exposed\",\n    ];\n    return Promise.all(srcs.concat(deps).map(fetch_spec))\n      .then(function (results) {\n        const astArray = results.map((result) =>\n          WebIDL2.parse(result.idl, { sourceName: result.spec })\n        );\n        test(() => {\n          const validations = WebIDL2.validate(astArray).filter(\n            (v) => !validationIgnored.includes(v.ruleName)\n          );\n          if (validations.length) {\n            const message = validations.map((v) => v.message).join(\"\\n\\n\");\n            throw new Error(message);\n          }\n        }, \"idl_test validation\");\n        for (var i = 0; i < srcs.length; i++) {\n          idl_array.internal_add_idls(astArray[i]);\n        }\n        for (var i = srcs.length; i < srcs.length + deps.length; i++) {\n          idl_array.internal_add_dependency_idls(astArray[i]);\n        }\n      })\n      .then(function () {\n        if (idl_setup_func) {\n          return idl_setup_func(idl_array, t);\n        }\n      })\n      .catch(function (e) {\n        setup_error = e || \"IDL setup failed.\";\n      })\n      .then(function () {\n        var error = setup_error;\n        try {\n          idl_array.test(); // Test what we can.\n        } catch (e) {\n          // If testing fails hard here, the original setup error\n          // is more likely to be the real cause.\n          error = error || e;\n        }\n        if (error) {\n          throw error;\n        }\n      });\n  }, \"idl_test setup\");\n}\n\n/**\n * fetch_spec is a shorthand for a Promise that fetches the spec's content.\n */\nfunction fetch_spec(spec) {\n  var url = \"/interfaces/\" + spec + \".idl\";\n  return fetch(url)\n    .then(function (r) {\n      if (!r.ok) {\n        throw new IdlHarnessError(\"Error fetching \" + url + \".\");\n      }\n      return r.text();\n    })\n    .then((idl) => ({ spec, idl }));\n}\n// vim: set expandtab shiftwidth=4 tabstop=4 foldmarker=@{,@} foldmethod=marker:\n"
  },
  {
    "path": "tests/wpt/resources/testharness.js",
    "content": "/*global self*/\n/*jshint latedef: nofunc*/\n\n/* Documentation: https://web-platform-tests.org/writing-tests/testharness-api.html\n * (../docs/_writing-tests/testharness-api.md) */\n\nexport default function (self) {\n  const location = self.location;\n\n  (function (global_scope) {\n    // default timeout is 10 seconds, test can override if needed\n    var settings = {\n      output: true,\n      harness_timeout: {\n        normal: 10000,\n        long: 60000,\n      },\n      test_timeout: null,\n      message_events: [\"start\", \"test_state\", \"result\", \"completion\"],\n      debug: false,\n    };\n\n    var xhtml_ns = \"http://www.w3.org/1999/xhtml\";\n\n    /*\n     * TestEnvironment is an abstraction for the environment in which the test\n     * harness is used. Each implementation of a test environment has to provide\n     * the following interface:\n     *\n     * interface TestEnvironment {\n     *   // Invoked after the global 'tests' object has been created and it's\n     *   // safe to call add_*_callback() to register event handlers.\n     *   void on_tests_ready();\n     *\n     *   // Invoked after setup() has been called to notify the test environment\n     *   // of changes to the test harness properties.\n     *   void on_new_harness_properties(object properties);\n     *\n     *   // Should return a new unique default test name.\n     *   DOMString next_default_test_name();\n     *\n     *   // Should return the test harness timeout duration in milliseconds.\n     *   float test_timeout();\n     * };\n     */\n\n    /*\n     * A test environment with a DOM. The global object is 'window'. By default\n     * test results are displayed in a table. Any parent windows receive\n     * callbacks or messages via postMessage() when test events occur. See\n     * apisample11.html and apisample12.html.\n     */\n    function WindowTestEnvironment() {\n      this.name_counter = 0;\n      this.window_cache = null;\n      this.output_handler = null;\n      this.all_loaded = false;\n      var this_obj = this;\n      this.message_events = [];\n      this.dispatched_messages = [];\n\n      this.message_functions = {\n        start: [\n          add_start_callback,\n          remove_start_callback,\n          function (properties) {\n            this_obj._dispatch(\"start_callback\", [properties], {\n              type: \"start\",\n              properties: properties,\n            });\n          },\n        ],\n\n        test_state: [\n          add_test_state_callback,\n          remove_test_state_callback,\n          function (test) {\n            this_obj._dispatch(\"test_state_callback\", [test], {\n              type: \"test_state\",\n              test: test.structured_clone(),\n            });\n          },\n        ],\n        result: [\n          add_result_callback,\n          remove_result_callback,\n          function (test) {\n            this_obj.output_handler.show_status();\n            this_obj._dispatch(\"result_callback\", [test], {\n              type: \"result\",\n              test: test.structured_clone(),\n            });\n          },\n        ],\n        completion: [\n          add_completion_callback,\n          remove_completion_callback,\n          function (tests, harness_status, asserts) {\n            var cloned_tests = map(tests, function (test) {\n              return test.structured_clone();\n            });\n            this_obj._dispatch(\"completion_callback\", [tests, harness_status], {\n              type: \"complete\",\n              tests: cloned_tests,\n              status: harness_status.structured_clone(),\n              asserts: asserts.map((assert) => assert.structured_clone()),\n            });\n          },\n        ],\n      };\n\n      on_event(window, \"load\", function () {\n        setTimeout(() => {\n          this_obj.all_loaded = true;\n          if (tests.all_done()) {\n            tests.complete();\n          }\n        }, 0);\n      });\n\n      on_event(window, \"message\", function (event) {\n        if (event.data && event.data.type === \"getmessages\" && event.source) {\n          // A window can post \"getmessages\" to receive a duplicate of every\n          // message posted by this environment so far. This allows subscribers\n          // from fetch_tests_from_window to 'catch up' to the current state of\n          // this environment.\n          for (var i = 0; i < this_obj.dispatched_messages.length; ++i) {\n            event.source.postMessage(this_obj.dispatched_messages[i], \"*\");\n          }\n        }\n      });\n    }\n\n    WindowTestEnvironment.prototype._dispatch = function (\n      selector,\n      callback_args,\n      message_arg\n    ) {\n      this.dispatched_messages.push(message_arg);\n      this._forEach_windows(function (w, same_origin) {\n        if (same_origin) {\n          try {\n            var has_selector = selector in w;\n          } catch (e) {\n            // If document.domain was set at some point same_origin can be\n            // wrong and the above will fail.\n            has_selector = false;\n          }\n          if (has_selector) {\n            try {\n              w[selector].apply(undefined, callback_args);\n            } catch (e) {}\n          }\n        }\n        if (w !== self) {\n          w.postMessage(message_arg, \"*\");\n        }\n      });\n    };\n\n    WindowTestEnvironment.prototype._forEach_windows = function (callback) {\n      // Iterate over the windows [self ... top, opener]. The callback is passed\n      // two objects, the first one is the window object itself, the second one\n      // is a boolean indicating whether or not it's on the same origin as the\n      // current window.\n      var cache = this.window_cache;\n      if (!cache) {\n        cache = [[self, true]];\n        var w = self;\n        var i = 0;\n        var so;\n        while (w != w.parent) {\n          w = w.parent;\n          so = is_same_origin(w);\n          cache.push([w, so]);\n          i++;\n        }\n        w = window.opener;\n        if (w) {\n          cache.push([w, is_same_origin(w)]);\n        }\n        this.window_cache = cache;\n      }\n\n      forEach(cache, function (a) {\n        callback.apply(null, a);\n      });\n    };\n\n    WindowTestEnvironment.prototype.on_tests_ready = function () {\n      var output = new Output();\n      this.output_handler = output;\n\n      var this_obj = this;\n\n      add_start_callback(function (properties) {\n        this_obj.output_handler.init(properties);\n      });\n\n      add_test_state_callback(function (test) {\n        this_obj.output_handler.show_status();\n      });\n\n      add_result_callback(function (test) {\n        this_obj.output_handler.show_status();\n      });\n\n      add_completion_callback(function (tests, harness_status, asserts_run) {\n        this_obj.output_handler.show_results(\n          tests,\n          harness_status,\n          asserts_run\n        );\n      });\n      this.setup_messages(settings.message_events);\n    };\n\n    WindowTestEnvironment.prototype.setup_messages = function (new_events) {\n      var this_obj = this;\n      forEach(settings.message_events, function (x) {\n        var current_dispatch = this_obj.message_events.indexOf(x) !== -1;\n        var new_dispatch = new_events.indexOf(x) !== -1;\n        if (!current_dispatch && new_dispatch) {\n          this_obj.message_functions[x][0](this_obj.message_functions[x][2]);\n        } else if (current_dispatch && !new_dispatch) {\n          this_obj.message_functions[x][1](this_obj.message_functions[x][2]);\n        }\n      });\n      this.message_events = new_events;\n    };\n\n    WindowTestEnvironment.prototype.next_default_test_name = function () {\n      var suffix = this.name_counter > 0 ? \" \" + this.name_counter : \"\";\n      this.name_counter++;\n      return get_title() + suffix;\n    };\n\n    WindowTestEnvironment.prototype.on_new_harness_properties = function (\n      properties\n    ) {\n      this.output_handler.setup(properties);\n      if (properties.hasOwnProperty(\"message_events\")) {\n        this.setup_messages(properties.message_events);\n      }\n    };\n\n    WindowTestEnvironment.prototype.add_on_loaded_callback = function (\n      callback\n    ) {\n      on_event(window, \"load\", callback);\n    };\n\n    WindowTestEnvironment.prototype.test_timeout = function () {\n      var metas = document.getElementsByTagName(\"meta\");\n      for (var i = 0; i < metas.length; i++) {\n        if (metas[i].name == \"timeout\") {\n          if (metas[i].content == \"long\") {\n            return settings.harness_timeout.long;\n          }\n          break;\n        }\n      }\n      return settings.harness_timeout.normal;\n    };\n\n    /*\n     * Base TestEnvironment implementation for a generic web worker.\n     *\n     * Workers accumulate test results. One or more clients can connect and\n     * retrieve results from a worker at any time.\n     *\n     * WorkerTestEnvironment supports communicating with a client via a\n     * MessagePort.  The mechanism for determining the appropriate MessagePort\n     * for communicating with a client depends on the type of worker and is\n     * implemented by the various specializations of WorkerTestEnvironment\n     * below.\n     *\n     * A client document using testharness can use fetch_tests_from_worker() to\n     * retrieve results from a worker. See apisample16.html.\n     */\n    function WorkerTestEnvironment() {\n      this.name_counter = 0;\n      this.all_loaded = true;\n      this.message_list = [];\n      this.message_ports = [];\n    }\n\n    WorkerTestEnvironment.prototype._dispatch = function (message) {\n      this.message_list.push(message);\n      for (var i = 0; i < this.message_ports.length; ++i) {\n        this.message_ports[i].postMessage(message);\n      }\n    };\n\n    // The only requirement is that port has a postMessage() method. It doesn't\n    // have to be an instance of a MessagePort, and often isn't.\n    WorkerTestEnvironment.prototype._add_message_port = function (port) {\n      this.message_ports.push(port);\n      for (var i = 0; i < this.message_list.length; ++i) {\n        port.postMessage(this.message_list[i]);\n      }\n    };\n\n    WorkerTestEnvironment.prototype.next_default_test_name = function () {\n      var suffix = this.name_counter > 0 ? \" \" + this.name_counter : \"\";\n      this.name_counter++;\n      return get_title() + suffix;\n    };\n\n    WorkerTestEnvironment.prototype.on_new_harness_properties = function () {};\n\n    WorkerTestEnvironment.prototype.on_tests_ready = function () {\n      var this_obj = this;\n      add_start_callback(function (properties) {\n        this_obj._dispatch({\n          type: \"start\",\n          properties: properties,\n        });\n      });\n      add_test_state_callback(function (test) {\n        this_obj._dispatch({\n          type: \"test_state\",\n          test: test.structured_clone(),\n        });\n      });\n      add_result_callback(function (test) {\n        this_obj._dispatch({\n          type: \"result\",\n          test: test.structured_clone(),\n        });\n      });\n      add_completion_callback(function (tests, harness_status, asserts) {\n        this_obj._dispatch({\n          type: \"complete\",\n          tests: map(tests, function (test) {\n            return test.structured_clone();\n          }),\n          status: harness_status.structured_clone(),\n          asserts: asserts.map((assert) => assert.structured_clone()),\n        });\n      });\n    };\n\n    WorkerTestEnvironment.prototype.add_on_loaded_callback = function () {};\n\n    WorkerTestEnvironment.prototype.test_timeout = function () {\n      // Tests running in a worker don't have a default timeout. I.e. all\n      // worker tests behave as if settings.explicit_timeout is true.\n      return null;\n    };\n\n    /*\n     * Dedicated web workers.\n     * https://html.spec.whatwg.org/multipage/workers.html#dedicatedworkerglobalscope\n     *\n     * This class is used as the test_environment when testharness is running\n     * inside a dedicated worker.\n     */\n    function DedicatedWorkerTestEnvironment() {\n      WorkerTestEnvironment.call(this);\n      // self is an instance of DedicatedWorkerGlobalScope which exposes\n      // a postMessage() method for communicating via the message channel\n      // established when the worker is created.\n      this._add_message_port(self);\n    }\n    DedicatedWorkerTestEnvironment.prototype = Object.create(\n      WorkerTestEnvironment.prototype\n    );\n\n    DedicatedWorkerTestEnvironment.prototype.on_tests_ready = function () {\n      WorkerTestEnvironment.prototype.on_tests_ready.call(this);\n      // In the absence of an onload notification, we a require dedicated\n      // workers to explicitly signal when the tests are done.\n      tests.wait_for_finish = true;\n    };\n\n    /*\n     * Shared web workers.\n     * https://html.spec.whatwg.org/multipage/workers.html#sharedworkerglobalscope\n     *\n     * This class is used as the test_environment when testharness is running\n     * inside a shared web worker.\n     */\n    function SharedWorkerTestEnvironment() {\n      WorkerTestEnvironment.call(this);\n      var this_obj = this;\n      // Shared workers receive message ports via the 'onconnect' event for\n      // each connection.\n      self.addEventListener(\n        \"connect\",\n        function (message_event) {\n          this_obj._add_message_port(message_event.source);\n        },\n        false\n      );\n    }\n    SharedWorkerTestEnvironment.prototype = Object.create(\n      WorkerTestEnvironment.prototype\n    );\n\n    SharedWorkerTestEnvironment.prototype.on_tests_ready = function () {\n      WorkerTestEnvironment.prototype.on_tests_ready.call(this);\n      // In the absence of an onload notification, we a require shared\n      // workers to explicitly signal when the tests are done.\n      tests.wait_for_finish = true;\n    };\n\n    /*\n     * Service workers.\n     * http://www.w3.org/TR/service-workers/\n     *\n     * This class is used as the test_environment when testharness is running\n     * inside a service worker.\n     */\n    function ServiceWorkerTestEnvironment() {\n      WorkerTestEnvironment.call(this);\n      this.all_loaded = false;\n      this.on_loaded_callback = null;\n      var this_obj = this;\n      self.addEventListener(\n        \"message\",\n        function (event) {\n          if (event.data && event.data.type && event.data.type === \"connect\") {\n            this_obj._add_message_port(event.source);\n          }\n        },\n        false\n      );\n\n      // The oninstall event is received after the service worker script and\n      // all imported scripts have been fetched and executed. It's the\n      // equivalent of an onload event for a document. All tests should have\n      // been added by the time this event is received, thus it's not\n      // necessary to wait until the onactivate event. However, tests for\n      // installed service workers need another event which is equivalent to\n      // the onload event because oninstall is fired only on installation. The\n      // onmessage event is used for that purpose since tests using\n      // testharness.js should ask the result to its service worker by\n      // PostMessage. If the onmessage event is triggered on the service\n      // worker's context, that means the worker's script has been evaluated.\n      on_event(self, \"install\", on_all_loaded);\n      on_event(self, \"message\", on_all_loaded);\n      function on_all_loaded() {\n        if (this_obj.all_loaded) return;\n        this_obj.all_loaded = true;\n        if (this_obj.on_loaded_callback) {\n          this_obj.on_loaded_callback();\n        }\n      }\n    }\n\n    ServiceWorkerTestEnvironment.prototype = Object.create(\n      WorkerTestEnvironment.prototype\n    );\n\n    ServiceWorkerTestEnvironment.prototype.add_on_loaded_callback = function (\n      callback\n    ) {\n      if (this.all_loaded) {\n        callback();\n      } else {\n        this.on_loaded_callback = callback;\n      }\n    };\n\n    /*\n     * Shadow realms.\n     * https://github.com/tc39/proposal-shadowrealm\n     *\n     * This class is used as the test_environment when testharness is running\n     * inside a shadow realm.\n     */\n    function ShadowRealmTestEnvironment() {\n      WorkerTestEnvironment.call(this);\n      this.all_loaded = false;\n      this.on_loaded_callback = null;\n    }\n\n    ShadowRealmTestEnvironment.prototype = Object.create(\n      WorkerTestEnvironment.prototype\n    );\n\n    /**\n     * Signal to the test environment that the tests are ready and the on-loaded\n     * callback should be run.\n     *\n     * Shadow realms are not *really* a DOM context: they have no `onload` or similar\n     * event for us to use to set up the test environment; so, instead, this method\n     * is manually triggered from the incubating realm\n     *\n     * @param {Function} message_destination - a function that receives JSON-serializable\n     * data to send to the incubating realm, in the same format as used by RemoteContext\n     */\n    ShadowRealmTestEnvironment.prototype.begin = function (\n      message_destination\n    ) {\n      if (this.all_loaded) {\n        throw new Error(\n          \"Tried to start a shadow realm test environment after it has already started\"\n        );\n      }\n      var fakeMessagePort = {};\n      fakeMessagePort.postMessage = message_destination;\n      this._add_message_port(fakeMessagePort);\n      this.all_loaded = true;\n      if (this.on_loaded_callback) {\n        this.on_loaded_callback();\n      }\n    };\n\n    ShadowRealmTestEnvironment.prototype.add_on_loaded_callback = function (\n      callback\n    ) {\n      if (this.all_loaded) {\n        callback();\n      } else {\n        this.on_loaded_callback = callback;\n      }\n    };\n\n    /*\n     * JavaScript shells.\n     *\n     * This class is used as the test_environment when testharness is running\n     * inside a JavaScript shell.\n     */\n    function ShellTestEnvironment() {\n      this.name_counter = 0;\n      this.all_loaded = false;\n      this.on_loaded_callback = null;\n      Promise.resolve().then(\n        function () {\n          this.all_loaded = true;\n          if (this.on_loaded_callback) {\n            this.on_loaded_callback();\n          }\n        }.bind(this)\n      );\n      this.message_list = [];\n      this.message_ports = [];\n    }\n\n    ShellTestEnvironment.prototype.next_default_test_name = function () {\n      var suffix = this.name_counter > 0 ? \" \" + this.name_counter : \"\";\n      this.name_counter++;\n      return get_title() + suffix;\n    };\n\n    ShellTestEnvironment.prototype.on_new_harness_properties = function () {};\n\n    ShellTestEnvironment.prototype.on_tests_ready = function () {};\n\n    ShellTestEnvironment.prototype.add_on_loaded_callback = function (\n      callback\n    ) {\n      if (this.all_loaded) {\n        callback();\n      } else {\n        this.on_loaded_callback = callback;\n      }\n    };\n\n    ShellTestEnvironment.prototype.test_timeout = function () {\n      // Tests running in a shell don't have a default timeout, so behave as\n      // if settings.explicit_timeout is true.\n      return null;\n    };\n\n    function create_test_environment() {\n      if (\"document\" in global_scope) {\n        return new WindowTestEnvironment();\n      }\n      if (\n        \"DedicatedWorkerGlobalScope\" in global_scope &&\n        global_scope instanceof DedicatedWorkerGlobalScope\n      ) {\n        return new DedicatedWorkerTestEnvironment();\n      }\n      if (\n        \"SharedWorkerGlobalScope\" in global_scope &&\n        global_scope instanceof SharedWorkerGlobalScope\n      ) {\n        return new SharedWorkerTestEnvironment();\n      }\n      if (\n        \"ServiceWorkerGlobalScope\" in global_scope &&\n        global_scope instanceof ServiceWorkerGlobalScope\n      ) {\n        return new ServiceWorkerTestEnvironment();\n      }\n      if (\n        \"WorkerGlobalScope\" in global_scope &&\n        global_scope instanceof WorkerGlobalScope\n      ) {\n        return new DedicatedWorkerTestEnvironment();\n      }\n      /* Shadow realm global objects are _ordinary_ objects (i.e. their prototype is\n       * Object) so we don't have a nice `instanceof` test to use; instead, we\n       * check if the there is a GLOBAL.isShadowRealm() property\n       * on the global object. that was set by the test harness when it\n       * created the ShadowRealm.\n       */\n      if (global_scope.GLOBAL && global_scope.GLOBAL.isShadowRealm()) {\n        return new ShadowRealmTestEnvironment();\n      }\n\n      return new ShellTestEnvironment();\n    }\n\n    var test_environment = create_test_environment();\n\n    function is_shared_worker(worker) {\n      return \"SharedWorker\" in global_scope && worker instanceof SharedWorker;\n    }\n\n    function is_service_worker(worker) {\n      // The worker object may be from another execution context,\n      // so do not use instanceof here.\n      return (\n        \"ServiceWorker\" in global_scope &&\n        Object.prototype.toString.call(worker) == \"[object ServiceWorker]\"\n      );\n    }\n\n    var seen_func_name = Object.create(null);\n\n    function get_test_name(func, name) {\n      if (name) {\n        return name;\n      }\n\n      if (func) {\n        var func_code = func.toString();\n\n        // Try and match with brackets, but fallback to matching without\n        var arrow = func_code.match(/^\\(\\)\\s*=>\\s*(?:{(.*)}\\s*|(.*))$/);\n\n        // Check for JS line separators\n        if (arrow !== null && !/[\\u000A\\u000D\\u2028\\u2029]/.test(func_code)) {\n          var trimmed = (arrow[1] !== undefined ? arrow[1] : arrow[2]).trim();\n          // drop trailing ; if there's no earlier ones\n          trimmed = trimmed.replace(/^([^;]*)(;\\s*)+$/, \"$1\");\n\n          if (trimmed) {\n            let name = trimmed;\n            if (seen_func_name[trimmed]) {\n              // This subtest name already exists, so add a suffix.\n              name += \" \" + seen_func_name[trimmed];\n            } else {\n              seen_func_name[trimmed] = 0;\n            }\n            seen_func_name[trimmed] += 1;\n            return name;\n          }\n        }\n      }\n\n      return test_environment.next_default_test_name();\n    }\n\n    /**\n     * @callback TestFunction\n     * @param {Test} test - The test currnetly being run.\n     * @param {Any[]} args - Additional args to pass to function.\n     *\n     */\n\n    /**\n     * Create a synchronous test\n     *\n     * @param {TestFunction} func - Test function. This is executed\n     * immediately. If it returns without error, the test status is\n     * set to ``PASS``. If it throws an :js:class:`AssertionError`, or\n     * any other exception, the test status is set to ``FAIL``\n     * (typically from an `assert` function).\n     * @param {String} name - Test name. This must be unique in a\n     * given file and must be invariant between runs.\n     */\n    function test(func, name, properties) {\n      if (tests.promise_setup_called) {\n        tests.status.status = tests.status.ERROR;\n        tests.status.message = \"`test` invoked after `promise_setup`\";\n        tests.complete();\n      }\n      var test_name = get_test_name(func, name);\n      var test_obj = new Test(test_name, properties);\n      var value = test_obj.step(func, test_obj, test_obj);\n\n      if (value !== undefined) {\n        var msg =\n          'Test named \"' +\n          test_name +\n          '\" passed a function to `test` that returned a value.';\n\n        try {\n          if (value && typeof value.then === \"function\") {\n            msg +=\n              \" Consider using `promise_test` instead when \" +\n              \"using Promises or async/await.\";\n          }\n        } catch (err) {}\n\n        tests.status.status = tests.status.ERROR;\n        tests.status.message = msg;\n      }\n\n      if (test_obj.phase === test_obj.phases.STARTED) {\n        test_obj.done();\n      }\n    }\n\n    /**\n     * Create an asynchronous test\n     *\n     * @param {TestFunction|string} funcOrName - Initial step function\n     * to call immediately with the test name as an argument (if any),\n     * or name of the test.\n     * @param {String} name - Test name (if a test function was\n     * provided). This must be unique in a given file and must be\n     * invariant between runs.\n     * @returns {Test} An object representing the ongoing test.\n     */\n    function async_test(func, name, properties) {\n      if (tests.promise_setup_called) {\n        tests.status.status = tests.status.ERROR;\n        tests.status.message = \"`async_test` invoked after `promise_setup`\";\n        tests.complete();\n      }\n      if (typeof func !== \"function\") {\n        properties = name;\n        name = func;\n        func = null;\n      }\n      var test_name = get_test_name(func, name);\n      var test_obj = new Test(test_name, properties);\n      if (func) {\n        var value = test_obj.step(func, test_obj, test_obj);\n\n        // Test authors sometimes return values to async_test, expecting us\n        // to handle the value somehow. Make doing so a harness error to be\n        // clear this is invalid, and point authors to promise_test if it\n        // may be appropriate.\n        //\n        // Note that we only perform this check on the initial function\n        // passed to async_test, not on any later steps - we haven't seen a\n        // consistent problem with those (and it's harder to check).\n        if (value !== undefined) {\n          var msg =\n            'Test named \"' +\n            test_name +\n            '\" passed a function to `async_test` that returned a value.';\n\n          try {\n            if (value && typeof value.then === \"function\") {\n              msg +=\n                \" Consider using `promise_test` instead when \" +\n                \"using Promises or async/await.\";\n            }\n          } catch (err) {}\n\n          tests.set_status(tests.status.ERROR, msg);\n          tests.complete();\n        }\n      }\n      return test_obj;\n    }\n\n    /**\n     * Create a promise test.\n     *\n     * Promise tests are tests which are represented by a promise\n     * object. If the promise is fulfilled the test passes, if it's\n     * rejected the test fails, otherwise the test passes.\n     *\n     * @param {TestFunction} func - Test function. This must return a\n     * promise. The test is automatically marked as complete once the\n     * promise settles.\n     * @param {String} name - Test name. This must be unique in a\n     * given file and must be invariant between runs.\n     */\n    function promise_test(func, name, properties) {\n      if (typeof func !== \"function\") {\n        properties = name;\n        name = func;\n        func = null;\n      }\n      var test_name = get_test_name(func, name);\n      var test = new Test(test_name, properties);\n      test._is_promise_test = true;\n\n      // If there is no promise tests queue make one.\n      if (!tests.promise_tests) {\n        tests.promise_tests = Promise.resolve();\n      }\n      tests.promise_tests = tests.promise_tests.then(function () {\n        return new Promise(function (resolve) {\n          var promise = test.step(func, test, test);\n\n          test.step(function () {\n            assert(\n              !!promise,\n              \"promise_test\",\n              null,\n              \"test body must return a 'thenable' object (received ${value})\",\n              { value: promise }\n            );\n            assert(\n              typeof promise.then === \"function\",\n              \"promise_test\",\n              null,\n              \"test body must return a 'thenable' object (received an object with no `then` method)\",\n              null\n            );\n          });\n\n          // Test authors may use the `step` method within a\n          // `promise_test` even though this reflects a mixture of\n          // asynchronous control flow paradigms. The \"done\" callback\n          // should be registered prior to the resolution of the\n          // user-provided Promise to avoid timeouts in cases where the\n          // Promise does not settle but a `step` function has thrown an\n          // error.\n          add_test_done_callback(test, resolve);\n\n          Promise.resolve(promise)\n            .catch(\n              test.step_func(function (value) {\n                if (value instanceof AssertionError) {\n                  throw value;\n                }\n                assert(\n                  false,\n                  \"promise_test\",\n                  null,\n                  \"Unhandled rejection with value: ${value}\",\n                  { value: value }\n                );\n              })\n            )\n            .then(function () {\n              test.done();\n            });\n        });\n      });\n    }\n\n    /**\n     * Make a copy of a Promise in the current realm.\n     *\n     * @param {Promise} promise the given promise that may be from a different\n     *                          realm\n     * @returns {Promise}\n     *\n     * An arbitrary promise provided by the caller may have originated\n     * in another frame that have since navigated away, rendering the\n     * frame's document inactive. Such a promise cannot be used with\n     * `await` or Promise.resolve(), as microtasks associated with it\n     * may be prevented from being run. See `issue\n     * 5319<https://github.com/whatwg/html/issues/5319>`_ for a\n     * particular case.\n     *\n     * In functions we define here, there is an expectation from the caller\n     * that the promise is from the current realm, that can always be used with\n     * `await`, etc. We therefore create a new promise in this realm that\n     * inherit the value and status from the given promise.\n     */\n\n    function bring_promise_to_current_realm(promise) {\n      return new Promise(promise.then.bind(promise));\n    }\n\n    /**\n     * Assert that a Promise is rejected with the right ECMAScript exception.\n     *\n     * @param {Test} test - the `Test` to use for the assertion.\n     * @param {Function} constructor - The expected exception constructor.\n     * @param {Promise} promise - The promise that's expected to\n     * reject with the given exception.\n     * @param {string} [description] Error message to add to assert in case of\n     *                               failure.\n     */\n    function promise_rejects_js(test, constructor, promise, description) {\n      return bring_promise_to_current_realm(promise)\n        .then(test.unreached_func(\"Should have rejected: \" + description))\n        .catch(function (e) {\n          assert_throws_js_impl(\n            constructor,\n            function () {\n              throw e;\n            },\n            description,\n            \"promise_rejects_js\"\n          );\n        });\n    }\n\n    /**\n     * Assert that a Promise is rejected with the right DOMException.\n     *\n     * For the remaining arguments, there are two ways of calling\n     * promise_rejects_dom:\n     *\n     * 1) If the DOMException is expected to come from the current global, the\n     * third argument should be the promise expected to reject, and a fourth,\n     * optional, argument is the assertion description.\n     *\n     * 2) If the DOMException is expected to come from some other global, the\n     * third argument should be the DOMException constructor from that global,\n     * the fourth argument the promise expected to reject, and the fifth,\n     * optional, argument the assertion description.\n     *\n     * @param {Test} test - the `Test` to use for the assertion.\n     * @param {number|string} type - See documentation for\n     * `assert_throws_dom <#assert_throws_dom>`_.\n     * @param {Function} promiseOrConstructor - Either the constructor\n     * for the expected exception (if the exception comes from another\n     * global), or the promise that's expected to reject (if the\n     * exception comes from the current global).\n     * @param {Function|string} descriptionOrPromise - Either the\n     * promise that's expected to reject (if the exception comes from\n     * another global), or the optional description of the condition\n     * being tested (if the exception comes from the current global).\n     * @param {string} [description] - Description of the condition\n     * being tested (if the exception comes from another global).\n     *\n     */\n    function promise_rejects_dom(\n      test,\n      type,\n      promiseOrConstructor,\n      descriptionOrPromise,\n      maybeDescription\n    ) {\n      let constructor, promise, description;\n      if (\n        typeof promiseOrConstructor === \"function\" &&\n        promiseOrConstructor.name === \"DOMException\"\n      ) {\n        constructor = promiseOrConstructor;\n        promise = descriptionOrPromise;\n        description = maybeDescription;\n      } else {\n        constructor = self.DOMException;\n        promise = promiseOrConstructor;\n        description = descriptionOrPromise;\n        assert(\n          maybeDescription === undefined,\n          \"Too many args passed to no-constructor version of promise_rejects_dom, or accidentally explicitly passed undefined\"\n        );\n      }\n      return bring_promise_to_current_realm(promise)\n        .then(test.unreached_func(\"Should have rejected: \" + description))\n        .catch(function (e) {\n          assert_throws_dom_impl(\n            type,\n            function () {\n              throw e;\n            },\n            description,\n            \"promise_rejects_dom\",\n            constructor\n          );\n        });\n    }\n\n    /**\n     * Assert that a Promise is rejected with the provided value.\n     *\n     * @param {Test} test - the `Test` to use for the assertion.\n     * @param {Any} exception - The expected value of the rejected promise.\n     * @param {Promise} promise - The promise that's expected to\n     * reject.\n     * @param {string} [description] Error message to add to assert in case of\n     *                               failure.\n     */\n    function promise_rejects_exactly(test, exception, promise, description) {\n      return bring_promise_to_current_realm(promise)\n        .then(test.unreached_func(\"Should have rejected: \" + description))\n        .catch(function (e) {\n          assert_throws_exactly_impl(\n            exception,\n            function () {\n              throw e;\n            },\n            description,\n            \"promise_rejects_exactly\"\n          );\n        });\n    }\n\n    /**\n     * Allow DOM events to be handled using Promises.\n     *\n     * This can make it a lot easier to test a very specific series of events,\n     * including ensuring that unexpected events are not fired at any point.\n     *\n     * `EventWatcher` will assert if an event occurs while there is no `wait_for`\n     * created Promise waiting to be fulfilled, or if the event is of a different type\n     * to the type currently expected. This ensures that only the events that are\n     * expected occur, in the correct order, and with the correct timing.\n     *\n     * @constructor\n     * @param {Test} test - The `Test` to use for the assertion.\n     * @param {EventTarget} watchedNode - The target expected to receive the events.\n     * @param {string[]} eventTypes - List of events to watch for.\n     * @param {Promise} timeoutPromise - Promise that will cause the\n     * test to be set to `TIMEOUT` once fulfilled.\n     *\n     */\n    function EventWatcher(test, watchedNode, eventTypes, timeoutPromise) {\n      if (typeof eventTypes == \"string\") {\n        eventTypes = [eventTypes];\n      }\n\n      var waitingFor = null;\n\n      // This is null unless we are recording all events, in which case it\n      // will be an Array object.\n      var recordedEvents = null;\n\n      var eventHandler = test.step_func(function (evt) {\n        assert_true(\n          !!waitingFor,\n          \"Not expecting event, but got \" + evt.type + \" event\"\n        );\n        assert_equals(\n          evt.type,\n          waitingFor.types[0],\n          \"Expected \" +\n            waitingFor.types[0] +\n            \" event, but got \" +\n            evt.type +\n            \" event instead\"\n        );\n\n        if (Array.isArray(recordedEvents)) {\n          recordedEvents.push(evt);\n        }\n\n        if (waitingFor.types.length > 1) {\n          // Pop first event from array\n          waitingFor.types.shift();\n          return;\n        }\n        // We need to null out waitingFor before calling the resolve function\n        // since the Promise's resolve handlers may call wait_for() which will\n        // need to set waitingFor.\n        var resolveFunc = waitingFor.resolve;\n        waitingFor = null;\n        // Likewise, we should reset the state of recordedEvents.\n        var result = recordedEvents || evt;\n        recordedEvents = null;\n        resolveFunc(result);\n      });\n\n      for (var i = 0; i < eventTypes.length; i++) {\n        watchedNode.addEventListener(eventTypes[i], eventHandler, false);\n      }\n\n      /**\n       * Returns a Promise that will resolve after the specified event or\n       * series of events has occurred.\n       *\n       * @param {Object} options An optional options object. If the 'record' property\n       *                 on this object has the value 'all', when the Promise\n       *                 returned by this function is resolved,  *all* Event\n       *                 objects that were waited for will be returned as an\n       *                 array.\n       *\n       * @example\n       * const watcher = new EventWatcher(t, div, [ 'animationstart',\n       *                                            'animationiteration',\n       *                                            'animationend' ]);\n       * return watcher.wait_for([ 'animationstart', 'animationend' ],\n       *                         { record: 'all' }).then(evts => {\n       *   assert_equals(evts[0].elapsedTime, 0.0);\n       *   assert_equals(evts[1].elapsedTime, 2.0);\n       * });\n       */\n      this.wait_for = function (types, options) {\n        if (waitingFor) {\n          return Promise.reject(\"Already waiting for an event or events\");\n        }\n        if (typeof types == \"string\") {\n          types = [types];\n        }\n        if (options && options.record && options.record === \"all\") {\n          recordedEvents = [];\n        }\n        return new Promise(function (resolve, reject) {\n          var timeout = test.step_func(function () {\n            // If the timeout fires after the events have been received\n            // or during a subsequent call to wait_for, ignore it.\n            if (!waitingFor || waitingFor.resolve !== resolve) return;\n\n            // This should always fail, otherwise we should have\n            // resolved the promise.\n            assert_true(\n              waitingFor.types.length == 0,\n              \"Timed out waiting for \" + waitingFor.types.join(\", \")\n            );\n            var result = recordedEvents;\n            recordedEvents = null;\n            var resolveFunc = waitingFor.resolve;\n            waitingFor = null;\n            resolveFunc(result);\n          });\n\n          if (timeoutPromise) {\n            timeoutPromise().then(timeout);\n          }\n\n          waitingFor = {\n            types: types,\n            resolve: resolve,\n            reject: reject,\n          };\n        });\n      };\n\n      /**\n       * Stop listening for events\n       */\n      function stop_watching() {\n        for (var i = 0; i < eventTypes.length; i++) {\n          watchedNode.removeEventListener(eventTypes[i], eventHandler, false);\n        }\n      }\n\n      test._add_cleanup(stop_watching);\n\n      return this;\n    }\n    expose(EventWatcher, \"EventWatcher\");\n\n    /**\n     * @typedef {Object} SettingsObject\n     * @property {bool} single_test - Use the single-page-test\n     * mode. In this mode the Document represents a single\n     * `async_test`. Asserts may be used directly without requiring\n     * `Test.step` or similar wrappers, and any exceptions set the\n     * status of the test rather than the status of the harness.\n     * @property {bool} allow_uncaught_exception - don't treat an\n     * uncaught exception as an error; needed when e.g. testing the\n     * `window.onerror` handler.\n     * @property {boolean} explicit_done - Wait for a call to `done()`\n     * before declaring all tests complete (this is always true for\n     * single-page tests).\n     * @property hide_test_state - hide the test state output while\n     * the test is running; This is helpful when the output of the test state\n     * may interfere the test results.\n     * @property {bool} explicit_timeout - disable file timeout; only\n     * stop waiting for results when the `timeout()` function is\n     * called This should typically only be set for manual tests, or\n     * by a test runner that providees its own timeout mechanism.\n     * @property {number} timeout_multiplier - Multiplier to apply to\n     * per-test timeouts. This should only be set by a test runner.\n     * @property {Document} output_document - The document to which\n     * results should be logged. By default this is the current\n     * document but could be an ancestor document in some cases e.g. a\n     * SVG test loaded in an HTML wrapper\n     *\n     */\n\n    /**\n     * Configure the harness\n     *\n     * @param {Function|SettingsObject} funcOrProperties - Either a\n     * setup function to run, or a set of properties. If this is a\n     * function that function is run synchronously. Any exception in\n     * the function will set the overall harness status to `ERROR`.\n     * @param {SettingsObject} maybeProperties - An object containing\n     * the settings to use, if the first argument is a function.\n     *\n     */\n    function setup(func_or_properties, maybe_properties) {\n      var func = null;\n      var properties = {};\n      if (arguments.length === 2) {\n        func = func_or_properties;\n        properties = maybe_properties;\n      } else if (func_or_properties instanceof Function) {\n        func = func_or_properties;\n      } else {\n        properties = func_or_properties;\n      }\n      tests.setup(func, properties);\n      test_environment.on_new_harness_properties(properties);\n    }\n\n    /**\n     * Configure the harness, waiting for a promise to resolve\n     * before running any `promise_test` tests.\n     *\n     * @param {Function} func - Function returning a promise that's\n     * run synchronously. Promise tests are not run until after this\n     * function has resolved.\n     * @param {SettingsObject} [properties] - An object containing\n     * the harness settings to use.\n     *\n     */\n    function promise_setup(func, properties = {}) {\n      if (typeof func !== \"function\") {\n        tests.set_status(\n          tests.status.ERROR,\n          \"promise_test invoked without a function\"\n        );\n        tests.complete();\n        return;\n      }\n      tests.promise_setup_called = true;\n\n      if (!tests.promise_tests) {\n        tests.promise_tests = Promise.resolve();\n      }\n\n      tests.promise_tests = tests.promise_tests\n        .then(function () {\n          var result;\n\n          tests.setup(null, properties);\n          result = func();\n          test_environment.on_new_harness_properties(properties);\n\n          if (!result || typeof result.then !== \"function\") {\n            throw \"Non-thenable returned by function passed to `promise_setup`\";\n          }\n          return result;\n        })\n        .catch(function (e) {\n          tests.set_status(tests.status.ERROR, String(e), e && e.stack);\n          tests.complete();\n        });\n    }\n\n    /**\n     * Mark test loading as complete.\n     *\n     * Typically this function is called implicitly on page load; it's\n     * only necessary for users to call this when either the\n     * ``explicit_done`` or ``single_page`` properties have been set\n     * via the :js:func:`setup` function.\n     *\n     * For single page tests this marks the test as complete and sets its status.\n     * For other tests, this marks test loading as complete, but doesn't affect ongoing tests.\n     */\n    function done() {\n      if (tests.tests.length === 0) {\n        // `done` is invoked after handling uncaught exceptions, so if the\n        // harness status is already set, the corresponding message is more\n        // descriptive than the generic message defined here.\n        if (tests.status.status === null) {\n          tests.status.status = tests.status.ERROR;\n          tests.status.message =\n            \"done() was called without first defining any tests\";\n        }\n\n        tests.complete();\n        return;\n      }\n      if (tests.file_is_test) {\n        // file is test files never have asynchronous cleanup logic,\n        // meaning the fully-synchronous `done` function can be used here.\n        tests.tests[0].done();\n      }\n      tests.end_wait();\n    }\n\n    /**\n     * @deprecated generate a list of tests from a function and list of arguments\n     *\n     * This is deprecated because it runs all the tests outside of the test functions\n     * and as a result any test throwing an exception will result in no tests being\n     * run. In almost all cases, you should simply call test within the loop you would\n     * use to generate the parameter list array.\n     *\n     * @param {Function} func - The function that will be called for each generated tests.\n     * @param {Any[][]} args - An array of arrays. Each nested array\n     * has the structure `[testName, ...testArgs]`. For each of these nested arrays\n     * array, a test is generated with name `testName` and test function equivalent to\n     * `func(..testArgs)`.\n     */\n    function generate_tests(func, args, properties) {\n      forEach(args, function (x, i) {\n        var name = x[0];\n        test(\n          function () {\n            func.apply(this, x.slice(1));\n          },\n          name,\n          Array.isArray(properties) ? properties[i] : properties\n        );\n      });\n    }\n\n    /**\n     * @deprecated\n     *\n     * Register a function as a DOM event listener to the\n     * given object for the event bubbling phase.\n     *\n     * @param {EventTarget} object - Event target\n     * @param {string} event - Event name\n     * @param {Function} callback - Event handler.\n     */\n    function on_event(object, event, callback) {\n      object.addEventListener(event, callback, false);\n    }\n\n    // Internal helper function to provide timeout-like functionality in\n    // environments where there is no setTimeout(). (No timeout ID or\n    // clearTimeout().)\n    function fake_set_timeout(callback, delay) {\n      var p = Promise.resolve();\n      var start = Date.now();\n      var end = start + delay;\n      function check() {\n        if (end - Date.now() > 0) {\n          p.then(check);\n        } else {\n          callback();\n        }\n      }\n      p.then(check);\n    }\n\n    /**\n     * Global version of :js:func:`Test.step_timeout` for use in single page tests.\n     *\n     * @param {Function} func - Function to run after the timeout\n     * @param {number} timeout - Time in ms to wait before running the\n     * test step. The actual wait time is ``timeout`` x\n     * ``timeout_multiplier``.\n     */\n    function step_timeout(func, timeout) {\n      var outer_this = this;\n      var args = Array.prototype.slice.call(arguments, 2);\n      var local_set_timeout =\n        typeof global_scope.setTimeout === \"undefined\"\n          ? fake_set_timeout\n          : setTimeout;\n      return local_set_timeout(function () {\n        func.apply(outer_this, args);\n      }, timeout * tests.timeout_multiplier);\n    }\n\n    expose(test, \"test\");\n    expose(async_test, \"async_test\");\n    expose(promise_test, \"promise_test\");\n    expose(promise_rejects_js, \"promise_rejects_js\");\n    expose(promise_rejects_dom, \"promise_rejects_dom\");\n    expose(promise_rejects_exactly, \"promise_rejects_exactly\");\n    expose(generate_tests, \"generate_tests\");\n    expose(setup, \"setup\");\n    expose(promise_setup, \"promise_setup\");\n    expose(done, \"done\");\n    expose(on_event, \"on_event\");\n    expose(step_timeout, \"step_timeout\");\n\n    /*\n     * Return a string truncated to the given length, with ... added at the end\n     * if it was longer.\n     */\n    function truncate(s, len) {\n      if (s.length > len) {\n        return s.substring(0, len - 3) + \"...\";\n      }\n      return s;\n    }\n\n    /*\n     * Return true if object is probably a Node object.\n     */\n    function is_node(object) {\n      // I use duck-typing instead of instanceof, because\n      // instanceof doesn't work if the node is from another window (like an\n      // iframe's contentWindow):\n      // http://www.w3.org/Bugs/Public/show_bug.cgi?id=12295\n      try {\n        var has_node_properties =\n          \"nodeType\" in object &&\n          \"nodeName\" in object &&\n          \"nodeValue\" in object &&\n          \"childNodes\" in object;\n      } catch (e) {\n        // We're probably cross-origin, which means we aren't a node\n        return false;\n      }\n\n      if (has_node_properties) {\n        try {\n          object.nodeType;\n        } catch (e) {\n          // The object is probably Node.prototype or another prototype\n          // object that inherits from it, and not a Node instance.\n          return false;\n        }\n        return true;\n      }\n      return false;\n    }\n\n    var replacements = {\n      0: \"0\",\n      1: \"x01\",\n      2: \"x02\",\n      3: \"x03\",\n      4: \"x04\",\n      5: \"x05\",\n      6: \"x06\",\n      7: \"x07\",\n      8: \"b\",\n      9: \"t\",\n      10: \"n\",\n      11: \"v\",\n      12: \"f\",\n      13: \"r\",\n      14: \"x0e\",\n      15: \"x0f\",\n      16: \"x10\",\n      17: \"x11\",\n      18: \"x12\",\n      19: \"x13\",\n      20: \"x14\",\n      21: \"x15\",\n      22: \"x16\",\n      23: \"x17\",\n      24: \"x18\",\n      25: \"x19\",\n      26: \"x1a\",\n      27: \"x1b\",\n      28: \"x1c\",\n      29: \"x1d\",\n      30: \"x1e\",\n      31: \"x1f\",\n      \"0xfffd\": \"ufffd\",\n      \"0xfffe\": \"ufffe\",\n      \"0xffff\": \"uffff\",\n    };\n\n    /**\n     * Convert a value to a nice, human-readable string\n     *\n     * When many JavaScript Object values are coerced to a String, the\n     * resulting value will be ``\"[object Object]\"``. This obscures\n     * helpful information, making the coerced value unsuitable for\n     * use in assertion messages, test names, and debugging\n     * statements. `format_value` produces more distinctive string\n     * representations of many kinds of objects, including arrays and\n     * the more important DOM Node types. It also translates String\n     * values containing control characters to include human-readable\n     * representations.\n     *\n     * @example\n     * // \"Document node with 2 children\"\n     * format_value(document);\n     * @example\n     * // \"\\\"foo\\\\uffffbar\\\"\"\n     * format_value(\"foo\\uffffbar\");\n     * @example\n     * // \"[-0, Infinity]\"\n     * format_value([-0, Infinity]);\n     * @param {Any} val - The value to convert to a string.\n     * @returns {string} - A string representation of ``val``, optimised for human readability.\n     */\n    function format_value(val, seen) {\n      if (!seen) {\n        seen = [];\n      }\n      if (typeof val === \"object\" && val !== null) {\n        if (seen.indexOf(val) >= 0) {\n          return \"[...]\";\n        }\n        seen.push(val);\n      }\n      if (Array.isArray(val)) {\n        let output = \"[\";\n        if (val.beginEllipsis !== undefined) {\n          output += \"…, \";\n        }\n        output += val\n          .map(function (x) {\n            return format_value(x, seen);\n          })\n          .join(\", \");\n        if (val.endEllipsis !== undefined) {\n          output += \", …\";\n        }\n        return output + \"]\";\n      }\n\n      switch (typeof val) {\n        case \"string\":\n          val = val.replace(/\\\\/g, \"\\\\\\\\\");\n          for (var p in replacements) {\n            var replace = \"\\\\\" + replacements[p];\n            val = val.replace(RegExp(String.fromCharCode(p), \"g\"), replace);\n          }\n          return '\"' + val.replace(/\"/g, '\\\\\"') + '\"';\n        case \"boolean\":\n        case \"undefined\":\n          return String(val);\n        case \"number\":\n          // In JavaScript, -0 === 0 and String(-0) == \"0\", so we have to\n          // special-case.\n          if (val === -0 && 1 / val === -Infinity) {\n            return \"-0\";\n          }\n          return String(val);\n        case \"object\":\n          if (val === null) {\n            return \"null\";\n          }\n\n          // Special-case Node objects, since those come up a lot in my tests.  I\n          // ignore namespaces.\n          if (is_node(val)) {\n            switch (val.nodeType) {\n              case Node.ELEMENT_NODE:\n                var ret = \"<\" + val.localName;\n                for (var i = 0; i < val.attributes.length; i++) {\n                  ret +=\n                    \" \" +\n                    val.attributes[i].name +\n                    '=\"' +\n                    val.attributes[i].value +\n                    '\"';\n                }\n                ret += \">\" + val.innerHTML + \"</\" + val.localName + \">\";\n                return \"Element node \" + truncate(ret, 60);\n              case Node.TEXT_NODE:\n                return 'Text node \"' + truncate(val.data, 60) + '\"';\n              case Node.PROCESSING_INSTRUCTION_NODE:\n                return (\n                  \"ProcessingInstruction node with target \" +\n                  format_value(truncate(val.target, 60)) +\n                  \" and data \" +\n                  format_value(truncate(val.data, 60))\n                );\n              case Node.COMMENT_NODE:\n                return \"Comment node <!--\" + truncate(val.data, 60) + \"-->\";\n              case Node.DOCUMENT_NODE:\n                return (\n                  \"Document node with \" +\n                  val.childNodes.length +\n                  (val.childNodes.length == 1 ? \" child\" : \" children\")\n                );\n              case Node.DOCUMENT_TYPE_NODE:\n                return \"DocumentType node\";\n              case Node.DOCUMENT_FRAGMENT_NODE:\n                return (\n                  \"DocumentFragment node with \" +\n                  val.childNodes.length +\n                  (val.childNodes.length == 1 ? \" child\" : \" children\")\n                );\n              default:\n                return \"Node object of unknown type\";\n            }\n          }\n\n        /* falls through */\n        default:\n          try {\n            return typeof val + ' \"' + truncate(String(val), 1000) + '\"';\n          } catch (e) {\n            return (\n              \"[stringifying object threw \" +\n              String(e) +\n              \" with type \" +\n              String(typeof e) +\n              \"]\"\n            );\n          }\n      }\n    }\n    expose(format_value, \"format_value\");\n\n    /*\n     * Assertions\n     */\n\n    function expose_assert(f, name) {\n      function assert_wrapper(...args) {\n        let status = Test.statuses.TIMEOUT;\n        let stack = null;\n        let new_assert_index = null;\n        try {\n          if (settings.debug) {\n            console.debug(\n              \"ASSERT\",\n              name,\n              tests.current_test && tests.current_test.name,\n              args\n            );\n          }\n          if (tests.output) {\n            tests.set_assert(name, args);\n            // Remember the newly pushed assert's index, because `apply`\n            // below might push new asserts.\n            new_assert_index = tests.asserts_run.length - 1;\n          }\n          const rv = f.apply(undefined, args);\n          status = Test.statuses.PASS;\n          return rv;\n        } catch (e) {\n          status = Test.statuses.FAIL;\n          stack = e.stack ? e.stack : null;\n          throw e;\n        } finally {\n          if (tests.output && !stack) {\n            stack = get_stack();\n          }\n          if (tests.output) {\n            tests.set_assert_status(new_assert_index, status, stack);\n          }\n        }\n      }\n      expose(assert_wrapper, name);\n    }\n\n    /**\n     * Assert that ``actual`` is strictly true\n     *\n     * @param {Any} actual - Value that is asserted to be true\n     * @param {string} [description] - Description of the condition being tested\n     */\n    function assert_true(actual, description) {\n      assert(\n        actual === true,\n        \"assert_true\",\n        description,\n        \"expected true got ${actual}\",\n        { actual: actual }\n      );\n    }\n    expose_assert(assert_true, \"assert_true\");\n\n    /**\n     * Assert that ``actual`` is strictly false\n     *\n     * @param {Any} actual - Value that is asserted to be false\n     * @param {string} [description] - Description of the condition being tested\n     */\n    function assert_false(actual, description) {\n      assert(\n        actual === false,\n        \"assert_false\",\n        description,\n        \"expected false got ${actual}\",\n        { actual: actual }\n      );\n    }\n    expose_assert(assert_false, \"assert_false\");\n\n    function same_value(x, y) {\n      if (y !== y) {\n        //NaN case\n        return x !== x;\n      }\n      if (x === 0 && y === 0) {\n        //Distinguish +0 and -0\n        return 1 / x === 1 / y;\n      }\n      return x === y;\n    }\n\n    /**\n     * Assert that ``actual`` is the same value as ``expected``.\n     *\n     * For objects this compares by object identity; for primitives\n     * this distinguishes between 0 and -0, and has correct handling\n     * of NaN.\n     *\n     * @param {Any} actual - Test value.\n     * @param {Any} expected - Expected value.\n     * @param {string} [description] - Description of the condition being tested.\n     */\n    function assert_equals(actual, expected, description) {\n      /*\n       * Test if two primitives are equal or two objects\n       * are the same object\n       */\n      if (typeof actual != typeof expected) {\n        assert(\n          false,\n          \"assert_equals\",\n          description,\n          \"expected (\" +\n            typeof expected +\n            \") ${expected} but got (\" +\n            typeof actual +\n            \") ${actual}\",\n          { expected: expected, actual: actual }\n        );\n        return;\n      }\n      assert(\n        same_value(actual, expected),\n        \"assert_equals\",\n        description,\n        \"expected ${expected} but got ${actual}\",\n        { expected: expected, actual: actual }\n      );\n    }\n    expose_assert(assert_equals, \"assert_equals\");\n\n    /**\n     * Assert that ``actual`` is not the same value as ``expected``.\n     *\n     * Comparison is as for :js:func:`assert_equals`.\n     *\n     * @param {Any} actual - Test value.\n     * @param {Any} expected - The value ``actual`` is expected to be different to.\n     * @param {string} [description] - Description of the condition being tested.\n     */\n    function assert_not_equals(actual, expected, description) {\n      assert(\n        !same_value(actual, expected),\n        \"assert_not_equals\",\n        description,\n        \"got disallowed value ${actual}\",\n        { actual: actual }\n      );\n    }\n    expose_assert(assert_not_equals, \"assert_not_equals\");\n\n    /**\n     * Assert that ``expected`` is an array and ``actual`` is one of the members.\n     * This is implemented using ``indexOf``, so doesn't handle NaN or ±0 correctly.\n     *\n     * @param {Any} actual - Test value.\n     * @param {Array} expected - An array that ``actual`` is expected to\n     * be a member of.\n     * @param {string} [description] - Description of the condition being tested.\n     */\n    function assert_in_array(actual, expected, description) {\n      assert(\n        expected.indexOf(actual) != -1,\n        \"assert_in_array\",\n        description,\n        \"value ${actual} not in array ${expected}\",\n        { actual: actual, expected: expected }\n      );\n    }\n    expose_assert(assert_in_array, \"assert_in_array\");\n\n    // This function was deprecated in July of 2015.\n    // See https://github.com/web-platform-tests/wpt/issues/2033\n    /**\n     * @deprecated\n     * Recursively compare two objects for equality.\n     *\n     * See `Issue 2033\n     * <https://github.com/web-platform-tests/wpt/issues/2033>`_ for\n     * more information.\n     *\n     * @param {Object} actual - Test value.\n     * @param {Object} expected - Expected value.\n     * @param {string} [description] - Description of the condition being tested.\n     */\n    function assert_object_equals(actual, expected, description) {\n      assert(\n        typeof actual === \"object\" && actual !== null,\n        \"assert_object_equals\",\n        description,\n        \"value is ${actual}, expected object\",\n        { actual: actual }\n      );\n      //This needs to be improved a great deal\n      function check_equal(actual, expected, stack) {\n        stack.push(actual);\n\n        var p;\n        for (p in actual) {\n          assert(\n            expected.hasOwnProperty(p),\n            \"assert_object_equals\",\n            description,\n            \"unexpected property ${p}\",\n            { p: p }\n          );\n\n          if (typeof actual[p] === \"object\" && actual[p] !== null) {\n            if (stack.indexOf(actual[p]) === -1) {\n              check_equal(actual[p], expected[p], stack);\n            }\n          } else {\n            assert(\n              same_value(actual[p], expected[p]),\n              \"assert_object_equals\",\n              description,\n              \"property ${p} expected ${expected} got ${actual}\",\n              { p: p, expected: expected[p], actual: actual[p] }\n            );\n          }\n        }\n        for (p in expected) {\n          assert(\n            actual.hasOwnProperty(p),\n            \"assert_object_equals\",\n            description,\n            \"expected property ${p} missing\",\n            { p: p }\n          );\n        }\n        stack.pop();\n      }\n      check_equal(actual, expected, []);\n    }\n    expose_assert(assert_object_equals, \"assert_object_equals\");\n\n    /**\n     * Assert that ``actual`` and ``expected`` are both arrays, and that the array properties of\n     * ``actual`` and ``expected`` are all the same value (as for :js:func:`assert_equals`).\n     *\n     * @param {Array} actual - Test array.\n     * @param {Array} expected - Array that is expected to contain the same values as ``actual``.\n     * @param {string} [description] - Description of the condition being tested.\n     */\n    function assert_array_equals(actual, expected, description) {\n      const max_array_length = 20;\n      function shorten_array(arr, offset = 0) {\n        // Make \", …\" only show up when it would likely reduce the length, not accounting for\n        // fonts.\n        if (arr.length < max_array_length + 2) {\n          return arr;\n        }\n        // By default we want half the elements after the offset and half before\n        // But if that takes us past the end of the array, we have more before, and\n        // if it takes us before the start we have more after.\n        const length_after_offset = Math.floor(max_array_length / 2);\n        let upper_bound = Math.min(length_after_offset + offset, arr.length);\n        const lower_bound = Math.max(upper_bound - max_array_length, 0);\n\n        if (lower_bound === 0) {\n          upper_bound = max_array_length;\n        }\n\n        const output = arr.slice(lower_bound, upper_bound);\n        if (lower_bound > 0) {\n          output.beginEllipsis = true;\n        }\n        if (upper_bound < arr.length) {\n          output.endEllipsis = true;\n        }\n        return output;\n      }\n\n      assert(\n        typeof actual === \"object\" && actual !== null && \"length\" in actual,\n        \"assert_array_equals\",\n        description,\n        \"value is ${actual}, expected array\",\n        { actual: actual }\n      );\n      assert(\n        actual.length === expected.length,\n        \"assert_array_equals\",\n        description,\n        \"lengths differ, expected array ${expected} length ${expectedLength}, got ${actual} length ${actualLength}\",\n        {\n          expected: shorten_array(expected, expected.length - 1),\n          expectedLength: expected.length,\n          actual: shorten_array(actual, actual.length - 1),\n          actualLength: actual.length,\n        }\n      );\n\n      for (var i = 0; i < actual.length; i++) {\n        assert(\n          actual.hasOwnProperty(i) === expected.hasOwnProperty(i),\n          \"assert_array_equals\",\n          description,\n          \"expected property ${i} to be ${expected} but was ${actual} (expected array ${arrayExpected} got ${arrayActual})\",\n          {\n            i: i,\n            expected: expected.hasOwnProperty(i) ? \"present\" : \"missing\",\n            actual: actual.hasOwnProperty(i) ? \"present\" : \"missing\",\n            arrayExpected: shorten_array(expected, i),\n            arrayActual: shorten_array(actual, i),\n          }\n        );\n        assert(\n          same_value(expected[i], actual[i]),\n          \"assert_array_equals\",\n          description,\n          \"expected property ${i} to be ${expected} but got ${actual} (expected array ${arrayExpected} got ${arrayActual})\",\n          {\n            i: i,\n            expected: expected[i],\n            actual: actual[i],\n            arrayExpected: shorten_array(expected, i),\n            arrayActual: shorten_array(actual, i),\n          }\n        );\n      }\n    }\n    expose_assert(assert_array_equals, \"assert_array_equals\");\n\n    /**\n     * Assert that each array property in ``actual`` is a number within\n     * ± `epsilon` of the corresponding property in `expected`.\n     *\n     * @param {Array} actual - Array of test values.\n     * @param {Array} expected - Array of values expected to be close to the values in ``actual``.\n     * @param {number} epsilon - Magnitude of allowed difference\n     * between each value in ``actual`` and ``expected``.\n     * @param {string} [description] - Description of the condition being tested.\n     */\n    function assert_array_approx_equals(\n      actual,\n      expected,\n      epsilon,\n      description\n    ) {\n      /*\n       * Test if two primitive arrays are equal within +/- epsilon\n       */\n      assert(\n        actual.length === expected.length,\n        \"assert_array_approx_equals\",\n        description,\n        \"lengths differ, expected ${expected} got ${actual}\",\n        { expected: expected.length, actual: actual.length }\n      );\n\n      for (var i = 0; i < actual.length; i++) {\n        assert(\n          actual.hasOwnProperty(i) === expected.hasOwnProperty(i),\n          \"assert_array_approx_equals\",\n          description,\n          \"property ${i}, property expected to be ${expected} but was ${actual}\",\n          {\n            i: i,\n            expected: expected.hasOwnProperty(i) ? \"present\" : \"missing\",\n            actual: actual.hasOwnProperty(i) ? \"present\" : \"missing\",\n          }\n        );\n        assert(\n          typeof actual[i] === \"number\",\n          \"assert_array_approx_equals\",\n          description,\n          \"property ${i}, expected a number but got a ${type_actual}\",\n          { i: i, type_actual: typeof actual[i] }\n        );\n        assert(\n          Math.abs(actual[i] - expected[i]) <= epsilon,\n          \"assert_array_approx_equals\",\n          description,\n          \"property ${i}, expected ${expected} +/- ${epsilon}, expected ${expected} but got ${actual}\",\n          { i: i, expected: expected[i], actual: actual[i], epsilon: epsilon }\n        );\n      }\n    }\n    expose_assert(assert_array_approx_equals, \"assert_array_approx_equals\");\n\n    /**\n     * Assert that ``actual`` is within ± ``epsilon`` of ``expected``.\n     *\n     * @param {number} actual - Test value.\n     * @param {number} expected - Value number is expected to be close to.\n     * @param {number} epsilon - Magnitude of allowed difference between ``actual`` and ``expected``.\n     * @param {string} [description] - Description of the condition being tested.\n     */\n    function assert_approx_equals(actual, expected, epsilon, description) {\n      /*\n       * Test if two primitive numbers are equal within +/- epsilon\n       */\n      assert(\n        typeof actual === \"number\",\n        \"assert_approx_equals\",\n        description,\n        \"expected a number but got a ${type_actual}\",\n        { type_actual: typeof actual }\n      );\n\n      // The epsilon math below does not place nice with NaN and Infinity\n      // But in this case Infinity = Infinity and NaN = NaN\n      if (isFinite(actual) || isFinite(expected)) {\n        assert(\n          Math.abs(actual - expected) <= epsilon,\n          \"assert_approx_equals\",\n          description,\n          \"expected ${expected} +/- ${epsilon} but got ${actual}\",\n          { expected: expected, actual: actual, epsilon: epsilon }\n        );\n      } else {\n        assert_equals(actual, expected);\n      }\n    }\n    expose_assert(assert_approx_equals, \"assert_approx_equals\");\n\n    /**\n     * Assert that ``actual`` is a number less than ``expected``.\n     *\n     * @param {number} actual - Test value.\n     * @param {number} expected - Number that ``actual`` must be less than.\n     * @param {string} [description] - Description of the condition being tested.\n     */\n    function assert_less_than(actual, expected, description) {\n      /*\n       * Test if a primitive number is less than another\n       */\n      assert(\n        typeof actual === \"number\",\n        \"assert_less_than\",\n        description,\n        \"expected a number but got a ${type_actual}\",\n        { type_actual: typeof actual }\n      );\n\n      assert(\n        actual < expected,\n        \"assert_less_than\",\n        description,\n        \"expected a number less than ${expected} but got ${actual}\",\n        { expected: expected, actual: actual }\n      );\n    }\n    expose_assert(assert_less_than, \"assert_less_than\");\n\n    /**\n     * Assert that ``actual`` is a number greater than ``expected``.\n     *\n     * @param {number} actual - Test value.\n     * @param {number} expected - Number that ``actual`` must be greater than.\n     * @param {string} [description] - Description of the condition being tested.\n     */\n    function assert_greater_than(actual, expected, description) {\n      /*\n       * Test if a primitive number is greater than another\n       */\n      assert(\n        typeof actual === \"number\",\n        \"assert_greater_than\",\n        description,\n        \"expected a number but got a ${type_actual}\",\n        { type_actual: typeof actual }\n      );\n\n      assert(\n        actual > expected,\n        \"assert_greater_than\",\n        description,\n        \"expected a number greater than ${expected} but got ${actual}\",\n        { expected: expected, actual: actual }\n      );\n    }\n    expose_assert(assert_greater_than, \"assert_greater_than\");\n\n    /**\n     * Assert that ``actual`` is a number greater than ``lower`` and less\n     * than ``upper`` but not equal to either.\n     *\n     * @param {number} actual - Test value.\n     * @param {number} lower - Number that ``actual`` must be greater than.\n     * @param {number} upper - Number that ``actual`` must be less than.\n     * @param {string} [description] - Description of the condition being tested.\n     */\n    function assert_between_exclusive(actual, lower, upper, description) {\n      /*\n       * Test if a primitive number is between two others\n       */\n      assert(\n        typeof actual === \"number\",\n        \"assert_between_exclusive\",\n        description,\n        \"expected a number but got a ${type_actual}\",\n        { type_actual: typeof actual }\n      );\n\n      assert(\n        actual > lower && actual < upper,\n        \"assert_between_exclusive\",\n        description,\n        \"expected a number greater than ${lower} \" +\n          \"and less than ${upper} but got ${actual}\",\n        { lower: lower, upper: upper, actual: actual }\n      );\n    }\n    expose_assert(assert_between_exclusive, \"assert_between_exclusive\");\n\n    /**\n     * Assert that ``actual`` is a number less than or equal to ``expected``.\n     *\n     * @param {number} actual - Test value.\n     * @param {number} expected - Number that ``actual`` must be less\n     * than or equal to.\n     * @param {string} [description] - Description of the condition being tested.\n     */\n    function assert_less_than_equal(actual, expected, description) {\n      /*\n       * Test if a primitive number is less than or equal to another\n       */\n      assert(\n        typeof actual === \"number\",\n        \"assert_less_than_equal\",\n        description,\n        \"expected a number but got a ${type_actual}\",\n        { type_actual: typeof actual }\n      );\n\n      assert(\n        actual <= expected,\n        \"assert_less_than_equal\",\n        description,\n        \"expected a number less than or equal to ${expected} but got ${actual}\",\n        { expected: expected, actual: actual }\n      );\n    }\n    expose_assert(assert_less_than_equal, \"assert_less_than_equal\");\n\n    /**\n     * Assert that ``actual`` is a number greater than or equal to ``expected``.\n     *\n     * @param {number} actual - Test value.\n     * @param {number} expected - Number that ``actual`` must be greater\n     * than or equal to.\n     * @param {string} [description] - Description of the condition being tested.\n     */\n    function assert_greater_than_equal(actual, expected, description) {\n      /*\n       * Test if a primitive number is greater than or equal to another\n       */\n      assert(\n        typeof actual === \"number\",\n        \"assert_greater_than_equal\",\n        description,\n        \"expected a number but got a ${type_actual}\",\n        { type_actual: typeof actual }\n      );\n\n      assert(\n        actual >= expected,\n        \"assert_greater_than_equal\",\n        description,\n        \"expected a number greater than or equal to ${expected} but got ${actual}\",\n        { expected: expected, actual: actual }\n      );\n    }\n    expose_assert(assert_greater_than_equal, \"assert_greater_than_equal\");\n\n    /**\n     * Assert that ``actual`` is a number greater than or equal to ``lower`` and less\n     * than or equal to ``upper``.\n     *\n     * @param {number} actual - Test value.\n     * @param {number} lower - Number that ``actual`` must be greater than or equal to.\n     * @param {number} upper - Number that ``actual`` must be less than or equal to.\n     * @param {string} [description] - Description of the condition being tested.\n     */\n    function assert_between_inclusive(actual, lower, upper, description) {\n      /*\n       * Test if a primitive number is between to two others or equal to either of them\n       */\n      assert(\n        typeof actual === \"number\",\n        \"assert_between_inclusive\",\n        description,\n        \"expected a number but got a ${type_actual}\",\n        { type_actual: typeof actual }\n      );\n\n      assert(\n        actual >= lower && actual <= upper,\n        \"assert_between_inclusive\",\n        description,\n        \"expected a number greater than or equal to ${lower} \" +\n          \"and less than or equal to ${upper} but got ${actual}\",\n        { lower: lower, upper: upper, actual: actual }\n      );\n    }\n    expose_assert(assert_between_inclusive, \"assert_between_inclusive\");\n\n    /**\n     * Assert that ``actual`` matches the RegExp ``expected``.\n     *\n     * @param {String} actual - Test string.\n     * @param {RegExp} expected - RegExp ``actual`` must match.\n     * @param {string} [description] - Description of the condition being tested.\n     */\n    function assert_regexp_match(actual, expected, description) {\n      /*\n       * Test if a string (actual) matches a regexp (expected)\n       */\n      assert(\n        expected.test(actual),\n        \"assert_regexp_match\",\n        description,\n        \"expected ${expected} but got ${actual}\",\n        { expected: expected, actual: actual }\n      );\n    }\n    expose_assert(assert_regexp_match, \"assert_regexp_match\");\n\n    /**\n     * Assert that the class string of ``object`` as returned in\n     * ``Object.prototype.toString`` is equal to ``class_name``.\n     *\n     * @param {Object} object - Object to stringify.\n     * @param {string} class_string - Expected class string for ``object``.\n     * @param {string} [description] - Description of the condition being tested.\n     */\n    function assert_class_string(object, class_string, description) {\n      var actual = {}.toString.call(object);\n      var expected = \"[object \" + class_string + \"]\";\n      assert(\n        same_value(actual, expected),\n        \"assert_class_string\",\n        description,\n        \"expected ${expected} but got ${actual}\",\n        { expected: expected, actual: actual }\n      );\n    }\n    expose_assert(assert_class_string, \"assert_class_string\");\n\n    /**\n     * Assert that ``object`` has an own property with name ``property_name``.\n     *\n     * @param {Object} object - Object that should have the given property.\n     * @param {string} property_name - Expected property name.\n     * @param {string} [description] - Description of the condition being tested.\n     */\n    function assert_own_property(object, property_name, description) {\n      assert(\n        object.hasOwnProperty(property_name),\n        \"assert_own_property\",\n        description,\n        \"expected property ${p} missing\",\n        { p: property_name }\n      );\n    }\n    expose_assert(assert_own_property, \"assert_own_property\");\n\n    /**\n     * Assert that ``object`` does not have an own property with name ``property_name``.\n     *\n     * @param {Object} object - Object that should not have the given property.\n     * @param {string} property_name - Property name to test.\n     * @param {string} [description] - Description of the condition being tested.\n     */\n    function assert_not_own_property(object, property_name, description) {\n      assert(\n        !object.hasOwnProperty(property_name),\n        \"assert_not_own_property\",\n        description,\n        \"unexpected property ${p} is found on object\",\n        { p: property_name }\n      );\n    }\n    expose_assert(assert_not_own_property, \"assert_not_own_property\");\n\n    function _assert_inherits(name) {\n      return function (object, property_name, description) {\n        assert(\n          (typeof object === \"object\" && object !== null) ||\n            typeof object === \"function\" ||\n            // Or has [[IsHTMLDDA]] slot\n            String(object) === \"[object HTMLAllCollection]\",\n          name,\n          description,\n          \"provided value is not an object\"\n        );\n\n        assert(\n          \"hasOwnProperty\" in object,\n          name,\n          description,\n          \"provided value is an object but has no hasOwnProperty method\"\n        );\n\n        assert(\n          !object.hasOwnProperty(property_name),\n          name,\n          description,\n          \"property ${p} found on object expected in prototype chain\",\n          { p: property_name }\n        );\n\n        assert(\n          property_name in object,\n          name,\n          description,\n          \"property ${p} not found in prototype chain\",\n          { p: property_name }\n        );\n      };\n    }\n\n    /**\n     * Assert that ``object`` does not have an own property with name\n     * ``property_name``, but inherits one through the prototype chain.\n     *\n     * @param {Object} object - Object that should have the given property in its prototype chain.\n     * @param {string} property_name - Expected property name.\n     * @param {string} [description] - Description of the condition being tested.\n     */\n    function assert_inherits(object, property_name, description) {\n      return _assert_inherits(\"assert_inherits\")(\n        object,\n        property_name,\n        description\n      );\n    }\n    expose_assert(assert_inherits, \"assert_inherits\");\n\n    /**\n     * Alias for :js:func:`insert_inherits`.\n     *\n     * @param {Object} object - Object that should have the given property in its prototype chain.\n     * @param {string} property_name - Expected property name.\n     * @param {string} [description] - Description of the condition being tested.\n     */\n    function assert_idl_attribute(object, property_name, description) {\n      return _assert_inherits(\"assert_idl_attribute\")(\n        object,\n        property_name,\n        description\n      );\n    }\n    expose_assert(assert_idl_attribute, \"assert_idl_attribute\");\n\n    /**\n     * Assert that ``object`` has a property named ``property_name`` and that the property is readonly.\n     *\n     * Note: The implementation tries to update the named property, so\n     * any side effects of updating will be triggered. Users are\n     * encouraged to instead inspect the property descriptor of ``property_name`` on ``object``.\n     *\n     * @param {Object} object - Object that should have the given property in its prototype chain.\n     * @param {string} property_name - Expected property name.\n     * @param {string} [description] - Description of the condition being tested.\n     */\n    function assert_readonly(object, property_name, description) {\n      var initial_value = object[property_name];\n      try {\n        //Note that this can have side effects in the case where\n        //the property has PutForwards\n        object[property_name] = initial_value + \"a\"; //XXX use some other value here?\n        assert(\n          same_value(object[property_name], initial_value),\n          \"assert_readonly\",\n          description,\n          \"changing property ${p} succeeded\",\n          { p: property_name }\n        );\n      } finally {\n        object[property_name] = initial_value;\n      }\n    }\n    expose_assert(assert_readonly, \"assert_readonly\");\n\n    /**\n     * Assert a JS Error with the expected constructor is thrown.\n     *\n     * @param {object} constructor The expected exception constructor.\n     * @param {Function} func Function which should throw.\n     * @param {string} [description] Error description for the case that the error is not thrown.\n     */\n    function assert_throws_js(constructor, func, description) {\n      assert_throws_js_impl(constructor, func, description, \"assert_throws_js\");\n    }\n    expose_assert(assert_throws_js, \"assert_throws_js\");\n\n    /**\n     * Like assert_throws_js but allows specifying the assertion type\n     * (assert_throws_js or promise_rejects_js, in practice).\n     */\n    function assert_throws_js_impl(\n      constructor,\n      func,\n      description,\n      assertion_type\n    ) {\n      try {\n        func.call(this);\n        assert(false, assertion_type, description, \"${func} did not throw\", {\n          func: func,\n        });\n      } catch (e) {\n        if (e instanceof AssertionError) {\n          throw e;\n        }\n\n        // Basic sanity-checks on the thrown exception.\n        assert(\n          typeof e === \"object\",\n          assertion_type,\n          description,\n          \"${func} threw ${e} with type ${type}, not an object\",\n          { func: func, e: e, type: typeof e }\n        );\n\n        assert(\n          e !== null,\n          assertion_type,\n          description,\n          \"${func} threw null, not an object\",\n          { func: func }\n        );\n\n        // Basic sanity-check on the passed-in constructor\n        assert(\n          typeof constructor == \"function\",\n          assertion_type,\n          description,\n          \"${constructor} is not a constructor\",\n          { constructor: constructor }\n        );\n        var obj = constructor;\n        while (obj) {\n          if (typeof obj === \"function\" && obj.name === \"Error\") {\n            break;\n          }\n          obj = Object.getPrototypeOf(obj);\n        }\n        assert(\n          obj != null,\n          assertion_type,\n          description,\n          \"${constructor} is not an Error subtype\",\n          { constructor: constructor }\n        );\n\n        // And checking that our exception is reasonable\n        assert(\n          e.constructor === constructor && e.name === constructor.name,\n          assertion_type,\n          description,\n          \"${func} threw ${actual} (${actual_name}) expected instance of ${expected} (${expected_name})\",\n          {\n            func: func,\n            actual: e,\n            actual_name: e.name,\n            expected: constructor,\n            expected_name: constructor.name,\n          }\n        );\n      }\n    }\n\n    // TODO: Figure out how to document the overloads better.\n    // sphinx-js doesn't seem to handle @variation correctly,\n    // and only expects a single JSDoc entry per function.\n    /**\n     * Assert a DOMException with the expected type is thrown.\n     *\n     * There are two ways of calling assert_throws_dom:\n     *\n     * 1) If the DOMException is expected to come from the current global, the\n     * second argument should be the function expected to throw and a third,\n     * optional, argument is the assertion description.\n     *\n     * 2) If the DOMException is expected to come from some other global, the\n     * second argument should be the DOMException constructor from that global,\n     * the third argument the function expected to throw, and the fourth, optional,\n     * argument the assertion description.\n     *\n     * @param {number|string} type - The expected exception name or\n     * code.  See the `table of names and codes\n     * <https://webidl.spec.whatwg.org/#dfn-error-names-table>`_. If a\n     * number is passed it should be one of the numeric code values in\n     * that table (e.g. 3, 4, etc).  If a string is passed it can\n     * either be an exception name (e.g. \"HierarchyRequestError\",\n     * \"WrongDocumentError\") or the name of the corresponding error\n     * code (e.g. \"``HIERARCHY_REQUEST_ERR``\", \"``WRONG_DOCUMENT_ERR``\").\n     * @param {Function} descriptionOrFunc - The function expected to\n     * throw (if the exception comes from another global), or the\n     * optional description of the condition being tested (if the\n     * exception comes from the current global).\n     * @param {string} [description] - Description of the condition\n     * being tested (if the exception comes from another global).\n     *\n     */\n    function assert_throws_dom(\n      type,\n      funcOrConstructor,\n      descriptionOrFunc,\n      maybeDescription\n    ) {\n      let constructor, func, description;\n      if (funcOrConstructor.name === \"DOMException\") {\n        constructor = funcOrConstructor;\n        func = descriptionOrFunc;\n        description = maybeDescription;\n      } else {\n        constructor = self.DOMException;\n        func = funcOrConstructor;\n        description = descriptionOrFunc;\n        assert(\n          maybeDescription === undefined,\n          \"Too many args passed to no-constructor version of assert_throws_dom, or accidentally explicitly passed undefined\"\n        );\n      }\n      assert_throws_dom_impl(\n        type,\n        func,\n        description,\n        \"assert_throws_dom\",\n        constructor\n      );\n    }\n    expose_assert(assert_throws_dom, \"assert_throws_dom\");\n\n    /**\n     * Similar to assert_throws_dom but allows specifying the assertion type\n     * (assert_throws_dom or promise_rejects_dom, in practice).  The\n     * \"constructor\" argument must be the DOMException constructor from the\n     * global we expect the exception to come from.\n     */\n    function assert_throws_dom_impl(\n      type,\n      func,\n      description,\n      assertion_type,\n      constructor\n    ) {\n      try {\n        func.call(this);\n        assert(false, assertion_type, description, \"${func} did not throw\", {\n          func: func,\n        });\n      } catch (e) {\n        if (e instanceof AssertionError) {\n          throw e;\n        }\n\n        // Basic sanity-checks on the thrown exception.\n        assert(\n          typeof e === \"object\",\n          assertion_type,\n          description,\n          \"${func} threw ${e} with type ${type}, not an object\",\n          { func: func, e: e, type: typeof e }\n        );\n\n        assert(\n          e !== null,\n          assertion_type,\n          description,\n          \"${func} threw null, not an object\",\n          { func: func }\n        );\n\n        // Sanity-check our type\n        assert(\n          typeof type == \"number\" || typeof type == \"string\",\n          assertion_type,\n          description,\n          \"${type} is not a number or string\",\n          { type: type }\n        );\n\n        var codename_name_map = {\n          INDEX_SIZE_ERR: \"IndexSizeError\",\n          HIERARCHY_REQUEST_ERR: \"HierarchyRequestError\",\n          WRONG_DOCUMENT_ERR: \"WrongDocumentError\",\n          INVALID_CHARACTER_ERR: \"InvalidCharacterError\",\n          NO_MODIFICATION_ALLOWED_ERR: \"NoModificationAllowedError\",\n          NOT_FOUND_ERR: \"NotFoundError\",\n          NOT_SUPPORTED_ERR: \"NotSupportedError\",\n          INUSE_ATTRIBUTE_ERR: \"InUseAttributeError\",\n          INVALID_STATE_ERR: \"InvalidStateError\",\n          SYNTAX_ERR: \"SyntaxError\",\n          INVALID_MODIFICATION_ERR: \"InvalidModificationError\",\n          NAMESPACE_ERR: \"NamespaceError\",\n          INVALID_ACCESS_ERR: \"InvalidAccessError\",\n          TYPE_MISMATCH_ERR: \"TypeMismatchError\",\n          SECURITY_ERR: \"SecurityError\",\n          NETWORK_ERR: \"NetworkError\",\n          ABORT_ERR: \"AbortError\",\n          URL_MISMATCH_ERR: \"URLMismatchError\",\n          QUOTA_EXCEEDED_ERR: \"QuotaExceededError\",\n          TIMEOUT_ERR: \"TimeoutError\",\n          INVALID_NODE_TYPE_ERR: \"InvalidNodeTypeError\",\n          DATA_CLONE_ERR: \"DataCloneError\",\n        };\n\n        var name_code_map = {\n          IndexSizeError: 1,\n          HierarchyRequestError: 3,\n          WrongDocumentError: 4,\n          InvalidCharacterError: 5,\n          NoModificationAllowedError: 7,\n          NotFoundError: 8,\n          NotSupportedError: 9,\n          InUseAttributeError: 10,\n          InvalidStateError: 11,\n          SyntaxError: 12,\n          InvalidModificationError: 13,\n          NamespaceError: 14,\n          InvalidAccessError: 15,\n          TypeMismatchError: 17,\n          SecurityError: 18,\n          NetworkError: 19,\n          AbortError: 20,\n          URLMismatchError: 21,\n          QuotaExceededError: 22,\n          TimeoutError: 23,\n          InvalidNodeTypeError: 24,\n          DataCloneError: 25,\n\n          EncodingError: 0,\n          NotReadableError: 0,\n          UnknownError: 0,\n          ConstraintError: 0,\n          DataError: 0,\n          TransactionInactiveError: 0,\n          ReadOnlyError: 0,\n          VersionError: 0,\n          OperationError: 0,\n          NotAllowedError: 0,\n          OptOutError: 0,\n        };\n\n        var code_name_map = {};\n        for (var key in name_code_map) {\n          if (name_code_map[key] > 0) {\n            code_name_map[name_code_map[key]] = key;\n          }\n        }\n\n        var required_props = {};\n        var name;\n\n        if (typeof type === \"number\") {\n          if (type === 0) {\n            throw new AssertionError(\n              \"Test bug: ambiguous DOMException code 0 passed to assert_throws_dom()\"\n            );\n          } else if (!(type in code_name_map)) {\n            throw new AssertionError(\n              'Test bug: unrecognized DOMException code \"' +\n                type +\n                '\" passed to assert_throws_dom()'\n            );\n          }\n          name = code_name_map[type];\n          required_props.code = type;\n        } else if (typeof type === \"string\") {\n          name = type in codename_name_map ? codename_name_map[type] : type;\n          if (!(name in name_code_map)) {\n            throw new AssertionError(\n              'Test bug: unrecognized DOMException code name or name \"' +\n                type +\n                '\" passed to assert_throws_dom()'\n            );\n          }\n\n          required_props.code = name_code_map[name];\n        }\n\n        if (\n          required_props.code === 0 ||\n          (\"name\" in e &&\n            e.name !== e.name.toUpperCase() &&\n            e.name !== \"DOMException\")\n        ) {\n          // New style exception: also test the name property.\n          required_props.name = name;\n        }\n\n        for (var prop in required_props) {\n          assert(\n            prop in e && e[prop] == required_props[prop],\n            assertion_type,\n            description,\n            \"${func} threw ${e} that is not a DOMException \" +\n              type +\n              \": property ${prop} is equal to ${actual}, expected ${expected}\",\n            {\n              func: func,\n              e: e,\n              prop: prop,\n              actual: e[prop],\n              expected: required_props[prop],\n            }\n          );\n        }\n\n        // Check that the exception is from the right global.  This check is last\n        // so more specific, and more informative, checks on the properties can\n        // happen in case a totally incorrect exception is thrown.\n        assert(\n          e.constructor === constructor,\n          assertion_type,\n          description,\n          \"${func} threw an exception from the wrong global\",\n          { func }\n        );\n      }\n    }\n\n    /**\n     * Assert the provided value is thrown.\n     *\n     * @param {value} exception The expected exception.\n     * @param {Function} func Function which should throw.\n     * @param {string} [description] Error description for the case that the error is not thrown.\n     */\n    function assert_throws_exactly(exception, func, description) {\n      assert_throws_exactly_impl(\n        exception,\n        func,\n        description,\n        \"assert_throws_exactly\"\n      );\n    }\n    expose_assert(assert_throws_exactly, \"assert_throws_exactly\");\n\n    /**\n     * Like assert_throws_exactly but allows specifying the assertion type\n     * (assert_throws_exactly or promise_rejects_exactly, in practice).\n     */\n    function assert_throws_exactly_impl(\n      exception,\n      func,\n      description,\n      assertion_type\n    ) {\n      try {\n        func.call(this);\n        assert(false, assertion_type, description, \"${func} did not throw\", {\n          func: func,\n        });\n      } catch (e) {\n        if (e instanceof AssertionError) {\n          throw e;\n        }\n\n        assert(\n          same_value(e, exception),\n          assertion_type,\n          description,\n          \"${func} threw ${e} but we expected it to throw ${exception}\",\n          { func: func, e: e, exception: exception }\n        );\n      }\n    }\n\n    /**\n     * Asserts if called. Used to ensure that a specific codepath is\n     * not taken e.g. that an error event isn't fired.\n     *\n     * @param {string} [description] - Description of the condition being tested.\n     */\n    function assert_unreached(description) {\n      assert(\n        false,\n        \"assert_unreached\",\n        description,\n        \"Reached unreachable code\"\n      );\n    }\n    expose_assert(assert_unreached, \"assert_unreached\");\n\n    /**\n     * @callback AssertFunc\n     * @param {Any} actual\n     * @param {Any} expected\n     * @param {Any[]} args\n     */\n\n    /**\n     * Asserts that ``actual`` matches at least one value of ``expected``\n     * according to a comparison defined by ``assert_func``.\n     *\n     * Note that tests with multiple allowed pass conditions are bad\n     * practice unless the spec specifically allows multiple\n     * behaviours. Test authors should not use this method simply to\n     * hide UA bugs.\n     *\n     * @param {AssertFunc} assert_func - Function to compare actual\n     * and expected. It must throw when the comparison fails and\n     * return when the comparison passes.\n     * @param {Any} actual - Test value.\n     * @param {Array} expected_array - Array of possible expected values.\n     * @param {Any[]} args - Additional arguments to pass to ``assert_func``.\n     */\n    function assert_any(assert_func, actual, expected_array, ...args) {\n      var errors = [];\n      var passed = false;\n      forEach(expected_array, function (expected) {\n        try {\n          assert_func.apply(this, [actual, expected].concat(args));\n          passed = true;\n        } catch (e) {\n          errors.push(e.message);\n        }\n      });\n      if (!passed) {\n        throw new AssertionError(errors.join(\"\\n\\n\"));\n      }\n    }\n    // FIXME: assert_any cannot use expose_assert, because assert_wrapper does\n    // not support nested assert calls (e.g. to assert_func). We need to\n    // support bypassing assert_wrapper for the inner asserts here.\n    expose(assert_any, \"assert_any\");\n\n    /**\n     * Assert that a feature is implemented, based on a 'truthy' condition.\n     *\n     * This function should be used to early-exit from tests in which there is\n     * no point continuing without support for a non-optional spec or spec\n     * feature. For example:\n     *\n     *     assert_implements(window.Foo, 'Foo is not supported');\n     *\n     * @param {object} condition The truthy value to test\n     * @param {string} [description] Error description for the case that the condition is not truthy.\n     */\n    function assert_implements(condition, description) {\n      assert(!!condition, \"assert_implements\", description);\n    }\n    expose_assert(assert_implements, \"assert_implements\");\n\n    /**\n     * Assert that an optional feature is implemented, based on a 'truthy' condition.\n     *\n     * This function should be used to early-exit from tests in which there is\n     * no point continuing without support for an explicitly optional spec or\n     * spec feature. For example:\n     *\n     *     assert_implements_optional(video.canPlayType(\"video/webm\"),\n     *                                \"webm video playback not supported\");\n     *\n     * @param {object} condition The truthy value to test\n     * @param {string} [description] Error description for the case that the condition is not truthy.\n     */\n    function assert_implements_optional(condition, description) {\n      if (!condition) {\n        throw new OptionalFeatureUnsupportedError(description);\n      }\n    }\n    expose_assert(assert_implements_optional, \"assert_implements_optional\");\n\n    /**\n     * @class\n     *\n     * A single subtest. A Test is not constructed directly but via the\n     * :js:func:`test`, :js:func:`async_test` or :js:func:`promise_test` functions.\n     *\n     * @param {string} name - This must be unique in a given file and must be\n     * invariant between runs.\n     *\n     */\n    function Test(name, properties) {\n      if (tests.file_is_test && tests.tests.length) {\n        throw new Error(\"Tried to create a test with file_is_test\");\n      }\n      /** The test name. */\n      this.name = name;\n\n      this.phase =\n        tests.is_aborted || tests.phase === tests.phases.COMPLETE\n          ? this.phases.COMPLETE\n          : this.phases.INITIAL;\n\n      /** The test status code.*/\n      this.status = this.NOTRUN;\n      this.timeout_id = null;\n      this.index = null;\n\n      this.properties = properties || {};\n      this.timeout_length = settings.test_timeout;\n      if (this.timeout_length !== null) {\n        this.timeout_length *= tests.timeout_multiplier;\n      }\n\n      /** A message indicating the reason for test failure. */\n      this.message = null;\n      /** Stack trace in case of failure. */\n      this.stack = null;\n\n      this.steps = [];\n      this._is_promise_test = false;\n\n      this.cleanup_callbacks = [];\n      this._user_defined_cleanup_count = 0;\n      this._done_callbacks = [];\n\n      if (typeof AbortController === \"function\") {\n        this._abortController = new AbortController();\n      }\n\n      // Tests declared following harness completion are likely an indication\n      // of a programming error, but they cannot be reported\n      // deterministically.\n      if (tests.phase === tests.phases.COMPLETE) {\n        return;\n      }\n\n      tests.push(this);\n    }\n\n    /**\n     * Enum of possible test statuses.\n     *\n     * :values:\n     *   - ``PASS``\n     *   - ``FAIL``\n     *   - ``TIMEOUT``\n     *   - ``NOTRUN``\n     *   - ``PRECONDITION_FAILED``\n     */\n    Test.statuses = {\n      PASS: 0,\n      FAIL: 1,\n      TIMEOUT: 2,\n      NOTRUN: 3,\n      PRECONDITION_FAILED: 4,\n    };\n\n    Test.prototype = merge({}, Test.statuses);\n\n    Test.prototype.phases = {\n      INITIAL: 0,\n      STARTED: 1,\n      HAS_RESULT: 2,\n      CLEANING: 3,\n      COMPLETE: 4,\n    };\n\n    Test.prototype.status_formats = {\n      0: \"Pass\",\n      1: \"Fail\",\n      2: \"Timeout\",\n      3: \"Not Run\",\n      4: \"Optional Feature Unsupported\",\n    };\n\n    Test.prototype.format_status = function () {\n      return this.status_formats[this.status];\n    };\n\n    Test.prototype.structured_clone = function () {\n      if (!this._structured_clone) {\n        var msg = this.message;\n        msg = msg ? String(msg) : msg;\n        this._structured_clone = merge(\n          {\n            name: String(this.name),\n            properties: merge({}, this.properties),\n            phases: merge({}, this.phases),\n          },\n          Test.statuses\n        );\n      }\n      this._structured_clone.status = this.status;\n      this._structured_clone.message = this.message;\n      this._structured_clone.stack = this.stack;\n      this._structured_clone.index = this.index;\n      this._structured_clone.phase = this.phase;\n      return this._structured_clone;\n    };\n\n    /**\n     * Run a single step of an ongoing test.\n     *\n     * @param {string} func - Callback function to run as a step. If\n     * this throws an :js:func:`AssertionError`, or any other\n     * exception, the :js:class:`Test` status is set to ``FAIL``.\n     * @param {Object} [this_obj] - The object to use as the this\n     * value when calling ``func``. Defaults to the  :js:class:`Test` object.\n     */\n    Test.prototype.step = function (func, this_obj) {\n      if (this.phase > this.phases.STARTED) {\n        return;\n      }\n\n      if (settings.debug && this.phase !== this.phases.STARTED) {\n        console.log(\"TEST START\", this.name);\n      }\n      this.phase = this.phases.STARTED;\n      //If we don't get a result before the harness times out that will be a test timeout\n      this.set_status(this.TIMEOUT, \"Test timed out\");\n\n      tests.started = true;\n      tests.current_test = this;\n      tests.notify_test_state(this);\n\n      if (this.timeout_id === null) {\n        this.set_timeout();\n      }\n\n      this.steps.push(func);\n\n      if (arguments.length === 1) {\n        this_obj = this;\n      }\n\n      if (settings.debug) {\n        console.debug(\"TEST STEP\", this.name);\n      }\n\n      try {\n        return func.apply(this_obj, Array.prototype.slice.call(arguments, 2));\n      } catch (e) {\n        if (this.phase >= this.phases.HAS_RESULT) {\n          return;\n        }\n        var status =\n          e instanceof OptionalFeatureUnsupportedError\n            ? this.PRECONDITION_FAILED\n            : this.FAIL;\n        var message = String(\n          typeof e === \"object\" && e !== null ? e.message : e\n        );\n        var stack = e.stack ? e.stack : null;\n\n        this.set_status(status, message, stack);\n        this.phase = this.phases.HAS_RESULT;\n        this.done();\n      } finally {\n        this.current_test = null;\n      }\n    };\n\n    /**\n     * Wrap a function so that it runs as a step of the current test.\n     *\n     * This allows creating a callback function that will run as a\n     * test step.\n     *\n     * @example\n     * let t = async_test(\"Example\");\n     * onload = t.step_func(e => {\n     *   assert_equals(e.name, \"load\");\n     *   // Mark the test as complete.\n     *   t.done();\n     * })\n     *\n     * @param {string} func - Function to run as a step. If this\n     * throws an :js:func:`AssertionError`, or any other exception,\n     * the :js:class:`Test` status is set to ``FAIL``.\n     * @param {Object} [this_obj] - The object to use as the this\n     * value when calling ``func``. Defaults to the :js:class:`Test` object.\n     */\n    Test.prototype.step_func = function (func, this_obj) {\n      var test_this = this;\n\n      if (arguments.length === 1) {\n        this_obj = test_this;\n      }\n\n      return function () {\n        return test_this.step.apply(\n          test_this,\n          [func, this_obj].concat(Array.prototype.slice.call(arguments))\n        );\n      };\n    };\n\n    /**\n     * Wrap a function so that it runs as a step of the current test,\n     * and automatically marks the test as complete if the function\n     * returns without error.\n     *\n     * @param {string} func - Function to run as a step. If this\n     * throws an :js:func:`AssertionError`, or any other exception,\n     * the :js:class:`Test` status is set to ``FAIL``. If it returns\n     * without error the status is set to ``PASS``.\n     * @param {Object} [this_obj] - The object to use as the this\n     * value when calling `func`. Defaults to the :js:class:`Test` object.\n     */\n    Test.prototype.step_func_done = function (func, this_obj) {\n      var test_this = this;\n\n      if (arguments.length === 1) {\n        this_obj = test_this;\n      }\n\n      return function () {\n        if (func) {\n          test_this.step.apply(\n            test_this,\n            [func, this_obj].concat(Array.prototype.slice.call(arguments))\n          );\n        }\n        test_this.done();\n      };\n    };\n\n    /**\n     * Return a function that automatically sets the current test to\n     * ``FAIL`` if it's called.\n     *\n     * @param {string} [description] - Error message to add to assert\n     * in case of failure.\n     *\n     */\n    Test.prototype.unreached_func = function (description) {\n      return this.step_func(function () {\n        assert_unreached(description);\n      });\n    };\n\n    /**\n     * Run a function as a step of the test after a given timeout.\n     *\n     * This multiplies the timeout by the global timeout multiplier to\n     * account for the expected execution speed of the current test\n     * environment. For example ``test.step_timeout(f, 2000)`` with a\n     * timeout multiplier of 2 will wait for 4000ms before calling ``f``.\n     *\n     * In general it's encouraged to use :js:func:`Test.step_wait` or\n     * :js:func:`step_wait_func` in preference to this function where possible,\n     * as they provide better test performance.\n     *\n     * @param {Function} func - Function to run as a test\n     * step.\n     * @param {number} timeout - Time in ms to wait before running the\n     * test step. The actual wait time is ``timeout`` x\n     * ``timeout_multiplier``.\n     *\n     */\n    Test.prototype.step_timeout = function (func, timeout) {\n      var test_this = this;\n      var args = Array.prototype.slice.call(arguments, 2);\n      var local_set_timeout =\n        typeof global_scope.setTimeout === \"undefined\"\n          ? fake_set_timeout\n          : setTimeout;\n      return local_set_timeout(\n        this.step_func(function () {\n          return func.apply(test_this, args);\n        }),\n        timeout * tests.timeout_multiplier\n      );\n    };\n\n    /**\n     * Poll for a function to return true, and call a callback\n     * function once it does, or assert if a timeout is\n     * reached. This is preferred over a simple step_timeout\n     * whenever possible since it allows the timeout to be longer\n     * to reduce intermittents without compromising test execution\n     * speed when the condition is quickly met.\n     *\n     * @param {Function} cond A function taking no arguments and\n     *                        returning a boolean or a Promise. The callback is\n     *                        called when this function returns true, or the\n     *                        returned Promise is resolved with true.\n     * @param {Function} func A function taking no arguments to call once\n     *                        the condition is met.\n     * @param {string} [description] Error message to add to assert in case of\n     *                               failure.\n     * @param {number} timeout Timeout in ms. This is multiplied by the global\n     *                         timeout_multiplier\n     * @param {number} interval Polling interval in ms\n     *\n     */\n    Test.prototype.step_wait_func = function (\n      cond,\n      func,\n      description,\n      timeout = 3000,\n      interval = 100\n    ) {\n      var timeout_full = timeout * tests.timeout_multiplier;\n      var remaining = Math.ceil(timeout_full / interval);\n      var test_this = this;\n      var local_set_timeout =\n        typeof global_scope.setTimeout === \"undefined\"\n          ? fake_set_timeout\n          : setTimeout;\n\n      const step = test_this.step_func((result) => {\n        if (result) {\n          func();\n        } else {\n          if (remaining === 0) {\n            assert(\n              false,\n              \"step_wait_func\",\n              description,\n              \"Timed out waiting on condition\"\n            );\n          }\n          remaining--;\n          local_set_timeout(wait_for_inner, interval);\n        }\n      });\n\n      var wait_for_inner = test_this.step_func(() => {\n        Promise.resolve(cond()).then(\n          step,\n          test_this.unreached_func(\"step_wait_func\")\n        );\n      });\n\n      wait_for_inner();\n    };\n\n    /**\n     * Poll for a function to return true, and invoke a callback\n     * followed by this.done() once it does, or assert if a timeout\n     * is reached. This is preferred over a simple step_timeout\n     * whenever possible since it allows the timeout to be longer\n     * to reduce intermittents without compromising test execution speed\n     * when the condition is quickly met.\n     *\n     * @example\n     * async_test(t => {\n     *  const popup = window.open(\"resources/coop-coep.py?coop=same-origin&coep=&navigate=about:blank\");\n     *  t.add_cleanup(() => popup.close());\n     *  assert_equals(window, popup.opener);\n     *\n     *  popup.onload = t.step_func(() => {\n     *    assert_true(popup.location.href.endsWith(\"&navigate=about:blank\"));\n     *    // Use step_wait_func_done as about:blank cannot message back.\n     *    t.step_wait_func_done(() => popup.location.href === \"about:blank\");\n     *  });\n     * }, \"Navigating a popup to about:blank\");\n     *\n     * @param {Function} cond A function taking no arguments and\n     *                        returning a boolean or a Promise. The callback is\n     *                        called when this function returns true, or the\n     *                        returned Promise is resolved with true.\n     * @param {Function} func A function taking no arguments to call once\n     *                        the condition is met.\n     * @param {string} [description] Error message to add to assert in case of\n     *                               failure.\n     * @param {number} timeout Timeout in ms. This is multiplied by the global\n     *                         timeout_multiplier\n     * @param {number} interval Polling interval in ms\n     *\n     */\n    Test.prototype.step_wait_func_done = function (\n      cond,\n      func,\n      description,\n      timeout = 3000,\n      interval = 100\n    ) {\n      this.step_wait_func(\n        cond,\n        () => {\n          if (func) {\n            func();\n          }\n          this.done();\n        },\n        description,\n        timeout,\n        interval\n      );\n    };\n\n    /**\n     * Poll for a function to return true, and resolve a promise\n     * once it does, or assert if a timeout is reached. This is\n     * preferred over a simple step_timeout whenever possible\n     * since it allows the timeout to be longer to reduce\n     * intermittents without compromising test execution speed\n     * when the condition is quickly met.\n     *\n     * @example\n     * promise_test(async t => {\n     *  // …\n     * await t.step_wait(() => frame.contentDocument === null, \"Frame navigated to a cross-origin document\");\n     * // …\n     * }, \"\");\n     *\n     * @param {Function} cond A function taking no arguments and\n     *                        returning a boolean or a Promise.\n     * @param {string} [description] Error message to add to assert in case of\n     *                              failure.\n     * @param {number} timeout Timeout in ms. This is multiplied by the global\n     *                         timeout_multiplier\n     * @param {number} interval Polling interval in ms\n     * @returns {Promise} Promise resolved once cond is met.\n     *\n     */\n    Test.prototype.step_wait = function (\n      cond,\n      description,\n      timeout = 3000,\n      interval = 100\n    ) {\n      return new Promise((resolve) => {\n        this.step_wait_func(cond, resolve, description, timeout, interval);\n      });\n    };\n\n    /*\n     * Private method for registering cleanup functions. `testharness.js`\n     * internals should use this method instead of the public `add_cleanup`\n     * method in order to hide implementation details from the harness status\n     * message in the case errors.\n     */\n    Test.prototype._add_cleanup = function (callback) {\n      this.cleanup_callbacks.push(callback);\n    };\n\n    /**\n     * Schedule a function to be run after the test result is known, regardless\n     * of passing or failing state.\n     *\n     * The behavior of this function will not\n     * influence the result of the test, but if an exception is thrown, the\n     * test harness will report an error.\n     *\n     * @param {Function} callback - The cleanup function to run. This\n     * is called with no arguments.\n     */\n    Test.prototype.add_cleanup = function (callback) {\n      this._user_defined_cleanup_count += 1;\n      this._add_cleanup(callback);\n    };\n\n    Test.prototype.set_timeout = function () {\n      if (this.timeout_length !== null) {\n        var this_obj = this;\n        this.timeout_id = setTimeout(function () {\n          this_obj.timeout();\n        }, this.timeout_length);\n      }\n    };\n\n    Test.prototype.set_status = function (status, message, stack) {\n      this.status = status;\n      this.message = message;\n      this.stack = stack ? stack : null;\n    };\n\n    /**\n     * Manually set the test status to ``TIMEOUT``.\n     */\n    Test.prototype.timeout = function () {\n      this.timeout_id = null;\n      this.set_status(this.TIMEOUT, \"Test timed out\");\n      this.phase = this.phases.HAS_RESULT;\n      this.done();\n    };\n\n    /**\n     * Manually set the test status to ``TIMEOUT``.\n     *\n     * Alias for `Test.timeout <#Test.timeout>`_.\n     */\n    Test.prototype.force_timeout = function () {\n      return this.timeout();\n    };\n\n    /**\n     * Mark the test as complete.\n     *\n     * This sets the test status to ``PASS`` if no other status was\n     * already recorded. Any subsequent attempts to run additional\n     * test steps will be ignored.\n     *\n     * After setting the test status any test cleanup functions will\n     * be run.\n     */\n    Test.prototype.done = function () {\n      if (this.phase >= this.phases.CLEANING) {\n        return;\n      }\n\n      if (this.phase <= this.phases.STARTED) {\n        this.set_status(this.PASS, null);\n      }\n\n      if (global_scope.clearTimeout) {\n        clearTimeout(this.timeout_id);\n      }\n\n      if (settings.debug) {\n        console.log(\"TEST DONE\", this.status, this.name);\n      }\n\n      this.cleanup();\n    };\n\n    function add_test_done_callback(test, callback) {\n      if (test.phase === test.phases.COMPLETE) {\n        callback();\n        return;\n      }\n\n      test._done_callbacks.push(callback);\n    }\n\n    /*\n     * Invoke all specified cleanup functions. If one or more produce an error,\n     * the context is in an unpredictable state, so all further testing should\n     * be cancelled.\n     */\n    Test.prototype.cleanup = function () {\n      var errors = [];\n      var bad_value_count = 0;\n      function on_error(e) {\n        errors.push(e);\n        // Abort tests immediately so that tests declared within subsequent\n        // cleanup functions are not run.\n        tests.abort();\n      }\n      var this_obj = this;\n      var results = [];\n\n      this.phase = this.phases.CLEANING;\n\n      if (this._abortController) {\n        this._abortController.abort(\"Test cleanup\");\n      }\n\n      forEach(this.cleanup_callbacks, function (cleanup_callback) {\n        var result;\n\n        try {\n          result = cleanup_callback();\n        } catch (e) {\n          on_error(e);\n          return;\n        }\n\n        if (!is_valid_cleanup_result(this_obj, result)) {\n          bad_value_count += 1;\n          // Abort tests immediately so that tests declared\n          // within subsequent cleanup functions are not run.\n          tests.abort();\n        }\n\n        results.push(result);\n      });\n\n      if (!this._is_promise_test) {\n        cleanup_done(this_obj, errors, bad_value_count);\n      } else {\n        all_async(\n          results,\n          function (result, done) {\n            if (result && typeof result.then === \"function\") {\n              result.then(null, on_error).then(done);\n            } else {\n              done();\n            }\n          },\n          function () {\n            cleanup_done(this_obj, errors, bad_value_count);\n          }\n        );\n      }\n    };\n\n    /*\n     * Determine if the return value of a cleanup function is valid for a given\n     * test. Any test may return the value `undefined`. Tests created with\n     * `promise_test` may alternatively return \"thenable\" object values.\n     */\n    function is_valid_cleanup_result(test, result) {\n      if (result === undefined) {\n        return true;\n      }\n\n      if (test._is_promise_test) {\n        return result && typeof result.then === \"function\";\n      }\n\n      return false;\n    }\n\n    function cleanup_done(test, errors, bad_value_count) {\n      if (errors.length || bad_value_count) {\n        var total = test._user_defined_cleanup_count;\n\n        tests.status.status = tests.status.ERROR;\n        tests.status.stack = null;\n        tests.status.message =\n          \"Test named '\" +\n          test.name +\n          \"' specified \" +\n          total +\n          \" 'cleanup' function\" +\n          (total > 1 ? \"s\" : \"\");\n\n        if (errors.length) {\n          tests.status.message += \", and \" + errors.length + \" failed\";\n          tests.status.stack =\n            typeof errors[0] === \"object\" && errors[0].hasOwnProperty(\"stack\")\n              ? errors[0].stack\n              : null;\n        }\n\n        if (bad_value_count) {\n          var type = test._is_promise_test ? \"non-thenable\" : \"non-undefined\";\n          tests.status.message +=\n            \", and \" + bad_value_count + \" returned a \" + type + \" value\";\n        }\n\n        tests.status.message += \".\";\n      }\n\n      test.phase = test.phases.COMPLETE;\n      tests.result(test);\n      forEach(test._done_callbacks, function (callback) {\n        callback();\n      });\n      test._done_callbacks.length = 0;\n    }\n\n    /**\n     * Gives an AbortSignal that will be aborted when the test finishes.\n     */\n    Test.prototype.get_signal = function () {\n      if (!this._abortController) {\n        throw new Error(\"AbortController is not supported in this browser\");\n      }\n      return this._abortController.signal;\n    };\n\n    /**\n     * A RemoteTest object mirrors a Test object on a remote worker. The\n     * associated RemoteWorker updates the RemoteTest object in response to\n     * received events. In turn, the RemoteTest object replicates these events\n     * on the local document. This allows listeners (test result reporting\n     * etc..) to transparently handle local and remote events.\n     */\n    function RemoteTest(clone) {\n      var this_obj = this;\n      Object.keys(clone).forEach(function (key) {\n        this_obj[key] = clone[key];\n      });\n      this.index = null;\n      this.phase = this.phases.INITIAL;\n      this.update_state_from(clone);\n      this._done_callbacks = [];\n      tests.push(this);\n    }\n\n    RemoteTest.prototype.structured_clone = function () {\n      var clone = {};\n      Object.keys(this).forEach(\n        function (key) {\n          var value = this[key];\n          // `RemoteTest` instances are responsible for managing\n          // their own \"done\" callback functions, so those functions\n          // are not relevant in other execution contexts. Because of\n          // this (and because Function values cannot be serialized\n          // for cross-realm transmittance), the property should not\n          // be considered when cloning instances.\n          if (key === \"_done_callbacks\") {\n            return;\n          }\n\n          if (typeof value === \"object\" && value !== null) {\n            clone[key] = merge({}, value);\n          } else {\n            clone[key] = value;\n          }\n        }.bind(this)\n      );\n      clone.phases = merge({}, this.phases);\n      return clone;\n    };\n\n    /**\n     * `RemoteTest` instances are objects which represent tests running in\n     * another realm. They do not define \"cleanup\" functions (if necessary,\n     * such functions are defined on the associated `Test` instance within the\n     * external realm). However, `RemoteTests` may have \"done\" callbacks (e.g.\n     * as attached by the `Tests` instance responsible for tracking the overall\n     * test status in the parent realm). The `cleanup` method delegates to\n     * `done` in order to ensure that such callbacks are invoked following the\n     * completion of the `RemoteTest`.\n     */\n    RemoteTest.prototype.cleanup = function () {\n      this.done();\n    };\n    RemoteTest.prototype.phases = Test.prototype.phases;\n    RemoteTest.prototype.update_state_from = function (clone) {\n      this.status = clone.status;\n      this.message = clone.message;\n      this.stack = clone.stack;\n      if (this.phase === this.phases.INITIAL) {\n        this.phase = this.phases.STARTED;\n      }\n    };\n    RemoteTest.prototype.done = function () {\n      this.phase = this.phases.COMPLETE;\n\n      forEach(this._done_callbacks, function (callback) {\n        callback();\n      });\n    };\n\n    RemoteTest.prototype.format_status = function () {\n      return Test.prototype.status_formats[this.status];\n    };\n\n    /*\n     * A RemoteContext listens for test events from a remote test context, such\n     * as another window or a worker. These events are then used to construct\n     * and maintain RemoteTest objects that mirror the tests running in the\n     * remote context.\n     *\n     * An optional third parameter can be used as a predicate to filter incoming\n     * MessageEvents.\n     */\n    function RemoteContext(remote, message_target, message_filter) {\n      this.running = true;\n      this.started = false;\n      this.tests = new Array();\n      this.early_exception = null;\n\n      var this_obj = this;\n      // If remote context is cross origin assigning to onerror is not\n      // possible, so silently catch those errors.\n      try {\n        remote.onerror = function (error) {\n          this_obj.remote_error(error);\n        };\n      } catch (e) {\n        // Ignore.\n      }\n\n      // Keeping a reference to the remote object and the message handler until\n      // remote_done() is seen prevents the remote object and its message channel\n      // from going away before all the messages are dispatched.\n      this.remote = remote;\n      this.message_target = message_target;\n      this.message_handler = function (message) {\n        var passesFilter = !message_filter || message_filter(message);\n        // The reference to the `running` property in the following\n        // condition is unnecessary because that value is only set to\n        // `false` after the `message_handler` function has been\n        // unsubscribed.\n        // TODO: Simplify the condition by removing the reference.\n        if (\n          this_obj.running &&\n          message.data &&\n          passesFilter &&\n          message.data.type in this_obj.message_handlers\n        ) {\n          this_obj.message_handlers[message.data.type].call(\n            this_obj,\n            message.data\n          );\n        }\n      };\n\n      if (self.Promise) {\n        this.done = new Promise(function (resolve) {\n          this_obj.doneResolve = resolve;\n        });\n      }\n\n      this.message_target.addEventListener(\"message\", this.message_handler);\n    }\n\n    RemoteContext.prototype.remote_error = function (error) {\n      if (error.preventDefault) {\n        error.preventDefault();\n      }\n\n      // Defer interpretation of errors until the testing protocol has\n      // started and the remote test's `allow_uncaught_exception` property\n      // is available.\n      if (!this.started) {\n        this.early_exception = error;\n      } else if (!this.allow_uncaught_exception) {\n        this.report_uncaught(error);\n      }\n    };\n\n    RemoteContext.prototype.report_uncaught = function (error) {\n      var message = error.message || String(error);\n      var filename = error.filename ? \" \" + error.filename : \"\";\n      // FIXME: Display remote error states separately from main document\n      // error state.\n      tests.set_status(\n        tests.status.ERROR,\n        \"Error in remote\" + filename + \": \" + message,\n        error.stack\n      );\n    };\n\n    RemoteContext.prototype.start = function (data) {\n      this.started = true;\n      this.allow_uncaught_exception = data.properties.allow_uncaught_exception;\n\n      if (this.early_exception && !this.allow_uncaught_exception) {\n        this.report_uncaught(this.early_exception);\n      }\n    };\n\n    RemoteContext.prototype.test_state = function (data) {\n      var remote_test = this.tests[data.test.index];\n      if (!remote_test) {\n        remote_test = new RemoteTest(data.test);\n        this.tests[data.test.index] = remote_test;\n      }\n      remote_test.update_state_from(data.test);\n      tests.notify_test_state(remote_test);\n    };\n\n    RemoteContext.prototype.test_done = function (data) {\n      var remote_test = this.tests[data.test.index];\n      remote_test.update_state_from(data.test);\n      remote_test.done();\n      tests.result(remote_test);\n    };\n\n    RemoteContext.prototype.remote_done = function (data) {\n      if (\n        tests.status.status === null &&\n        data.status.status !== data.status.OK\n      ) {\n        tests.set_status(\n          data.status.status,\n          data.status.message,\n          data.status.stack\n        );\n      }\n\n      for (let assert of data.asserts) {\n        var record = new AssertRecord();\n        record.assert_name = assert.assert_name;\n        record.args = assert.args;\n        record.test =\n          assert.test != null ? this.tests[assert.test.index] : null;\n        record.status = assert.status;\n        record.stack = assert.stack;\n        tests.asserts_run.push(record);\n      }\n\n      this.message_target.removeEventListener(\"message\", this.message_handler);\n      this.running = false;\n\n      // If remote context is cross origin assigning to onerror is not\n      // possible, so silently catch those errors.\n      try {\n        this.remote.onerror = null;\n      } catch (e) {\n        // Ignore.\n      }\n\n      this.remote = null;\n      this.message_target = null;\n      if (this.doneResolve) {\n        this.doneResolve();\n      }\n\n      if (tests.all_done()) {\n        tests.complete();\n      }\n    };\n\n    RemoteContext.prototype.message_handlers = {\n      start: RemoteContext.prototype.start,\n      test_state: RemoteContext.prototype.test_state,\n      result: RemoteContext.prototype.test_done,\n      complete: RemoteContext.prototype.remote_done,\n    };\n\n    /**\n     * @class\n     * Status of the overall harness\n     */\n    function TestsStatus() {\n      /** The status code */\n      this.status = null;\n      /** Message in case of failure */\n      this.message = null;\n      /** Stack trace in case of an exception. */\n      this.stack = null;\n    }\n\n    /**\n     * Enum of possible harness statuses.\n     *\n     * :values:\n     *   - ``OK``\n     *   - ``ERROR``\n     *   - ``TIMEOUT``\n     *   - ``PRECONDITION_FAILED``\n     */\n    TestsStatus.statuses = {\n      OK: 0,\n      ERROR: 1,\n      TIMEOUT: 2,\n      PRECONDITION_FAILED: 3,\n    };\n\n    TestsStatus.prototype = merge({}, TestsStatus.statuses);\n\n    TestsStatus.prototype.formats = {\n      0: \"OK\",\n      1: \"Error\",\n      2: \"Timeout\",\n      3: \"Optional Feature Unsupported\",\n    };\n\n    TestsStatus.prototype.structured_clone = function () {\n      if (!this._structured_clone) {\n        var msg = this.message;\n        msg = msg ? String(msg) : msg;\n        this._structured_clone = merge(\n          {\n            status: this.status,\n            message: msg,\n            stack: this.stack,\n          },\n          TestsStatus.statuses\n        );\n      }\n      return this._structured_clone;\n    };\n\n    TestsStatus.prototype.format_status = function () {\n      return this.formats[this.status];\n    };\n\n    /**\n     * @class\n     * Record of an assert that ran.\n     *\n     * @param {Test} test - The test which ran the assert.\n     * @param {string} assert_name - The function name of the assert.\n     * @param {Any} args - The arguments passed to the assert function.\n     */\n    function AssertRecord(test, assert_name, args = []) {\n      /** Name of the assert that ran */\n      this.assert_name = assert_name;\n      /** Test that ran the assert */\n      this.test = test;\n      // Avoid keeping complex objects alive\n      /** Stringification of the arguments that were passed to the assert function */\n      this.args = args.map((x) => format_value(x).replace(/\\n/g, \" \"));\n      /** Status of the assert */\n      this.status = null;\n    }\n\n    AssertRecord.prototype.structured_clone = function () {\n      return {\n        assert_name: this.assert_name,\n        test: this.test ? this.test.structured_clone() : null,\n        args: this.args,\n        status: this.status,\n      };\n    };\n\n    function Tests() {\n      this.tests = [];\n      this.num_pending = 0;\n\n      this.phases = {\n        INITIAL: 0,\n        SETUP: 1,\n        HAVE_TESTS: 2,\n        HAVE_RESULTS: 3,\n        COMPLETE: 4,\n      };\n      this.phase = this.phases.INITIAL;\n\n      this.properties = {};\n\n      this.wait_for_finish = false;\n      this.processing_callbacks = false;\n\n      this.allow_uncaught_exception = false;\n\n      this.file_is_test = false;\n      // This value is lazily initialized in order to avoid introducing a\n      // dependency on ECMAScript 2015 Promises to all tests.\n      this.promise_tests = null;\n      this.promise_setup_called = false;\n\n      this.timeout_multiplier = 1;\n      this.timeout_length = test_environment.test_timeout();\n      this.timeout_id = null;\n\n      this.start_callbacks = [];\n      this.test_state_callbacks = [];\n      this.test_done_callbacks = [];\n      this.all_done_callbacks = [];\n\n      this.hide_test_state = false;\n      this.pending_remotes = [];\n\n      this.current_test = null;\n      this.asserts_run = [];\n\n      // Track whether output is enabled, and thus whether or not we should\n      // track asserts.\n      //\n      // On workers we don't get properties set from testharnessreport.js, so\n      // we don't know whether or not to track asserts. To avoid the\n      // resulting performance hit, we assume we are not meant to. This means\n      // that assert tracking does not function on workers.\n      this.output = settings.output && \"document\" in global_scope;\n\n      this.status = new TestsStatus();\n\n      var this_obj = this;\n\n      test_environment.add_on_loaded_callback(function () {\n        if (this_obj.all_done()) {\n          this_obj.complete();\n        }\n      });\n\n      this.set_timeout();\n    }\n\n    Tests.prototype.setup = function (func, properties) {\n      if (this.phase >= this.phases.HAVE_RESULTS) {\n        return;\n      }\n\n      if (this.phase < this.phases.SETUP) {\n        this.phase = this.phases.SETUP;\n      }\n\n      this.properties = properties;\n\n      for (var p in properties) {\n        if (properties.hasOwnProperty(p)) {\n          var value = properties[p];\n          if (p == \"allow_uncaught_exception\") {\n            this.allow_uncaught_exception = value;\n          } else if (p == \"explicit_done\" && value) {\n            this.wait_for_finish = true;\n          } else if (p == \"explicit_timeout\" && value) {\n            this.timeout_length = null;\n            if (this.timeout_id) {\n              clearTimeout(this.timeout_id);\n            }\n          } else if (p == \"single_test\" && value) {\n            this.set_file_is_test();\n          } else if (p == \"timeout_multiplier\") {\n            this.timeout_multiplier = value;\n            if (this.timeout_length) {\n              this.timeout_length *= this.timeout_multiplier;\n            }\n          } else if (p == \"hide_test_state\") {\n            this.hide_test_state = value;\n          } else if (p == \"output\") {\n            this.output = value;\n          } else if (p === \"debug\") {\n            settings.debug = value;\n          }\n        }\n      }\n\n      if (func) {\n        try {\n          func();\n        } catch (e) {\n          this.status.status =\n            e instanceof OptionalFeatureUnsupportedError\n              ? this.status.PRECONDITION_FAILED\n              : this.status.ERROR;\n          this.status.message = String(e);\n          this.status.stack = e.stack ? e.stack : null;\n          this.complete();\n        }\n      }\n      this.set_timeout();\n    };\n\n    Tests.prototype.set_file_is_test = function () {\n      if (this.tests.length > 0) {\n        throw new Error(\"Tried to set file as test after creating a test\");\n      }\n      this.wait_for_finish = true;\n      this.file_is_test = true;\n      // Create the test, which will add it to the list of tests\n      tests.current_test = async_test();\n    };\n\n    Tests.prototype.set_status = function (status, message, stack) {\n      this.status.status = status;\n      this.status.message = message;\n      this.status.stack = stack ? stack : null;\n    };\n\n    Tests.prototype.set_timeout = function () {\n      if (global_scope.clearTimeout) {\n        var this_obj = this;\n        clearTimeout(this.timeout_id);\n        if (this.timeout_length !== null) {\n          this.timeout_id = setTimeout(function () {\n            this_obj.timeout();\n          }, this.timeout_length);\n        }\n      }\n    };\n\n    Tests.prototype.timeout = function () {\n      var test_in_cleanup = null;\n\n      if (this.status.status === null) {\n        forEach(this.tests, function (test) {\n          // No more than one test is expected to be in the\n          // \"CLEANUP\" phase at any time\n          if (test.phase === test.phases.CLEANING) {\n            test_in_cleanup = test;\n          }\n\n          test.phase = test.phases.COMPLETE;\n        });\n\n        // Timeouts that occur while a test is in the \"cleanup\" phase\n        // indicate that some global state was not properly reverted. This\n        // invalidates the overall test execution, so the timeout should be\n        // reported as an error and cancel the execution of any remaining\n        // tests.\n        if (test_in_cleanup) {\n          this.status.status = this.status.ERROR;\n          this.status.message =\n            \"Timeout while running cleanup for \" +\n            'test named \"' +\n            test_in_cleanup.name +\n            '\".';\n          tests.status.stack = null;\n        } else {\n          this.status.status = this.status.TIMEOUT;\n        }\n      }\n\n      this.complete();\n    };\n\n    Tests.prototype.end_wait = function () {\n      this.wait_for_finish = false;\n      if (this.all_done()) {\n        this.complete();\n      }\n    };\n\n    Tests.prototype.push = function (test) {\n      if (this.phase < this.phases.HAVE_TESTS) {\n        this.start();\n      }\n      this.num_pending++;\n      test.index = this.tests.push(test);\n      this.notify_test_state(test);\n    };\n\n    Tests.prototype.notify_test_state = function (test) {\n      var this_obj = this;\n      forEach(this.test_state_callbacks, function (callback) {\n        callback(test, this_obj);\n      });\n    };\n\n    Tests.prototype.all_done = function () {\n      return (\n        (this.tests.length > 0 || this.pending_remotes.length > 0) &&\n        test_environment.all_loaded &&\n        (this.num_pending === 0 || this.is_aborted) &&\n        !this.wait_for_finish &&\n        !this.processing_callbacks &&\n        !this.pending_remotes.some(function (w) {\n          return w.running;\n        })\n      );\n    };\n\n    Tests.prototype.start = function () {\n      this.phase = this.phases.HAVE_TESTS;\n      this.notify_start();\n    };\n\n    Tests.prototype.notify_start = function () {\n      var this_obj = this;\n      forEach(this.start_callbacks, function (callback) {\n        callback(this_obj.properties);\n      });\n    };\n\n    Tests.prototype.result = function (test) {\n      // If the harness has already transitioned beyond the `HAVE_RESULTS`\n      // phase, subsequent tests should not cause it to revert.\n      if (this.phase <= this.phases.HAVE_RESULTS) {\n        this.phase = this.phases.HAVE_RESULTS;\n      }\n      this.num_pending--;\n      this.notify_result(test);\n    };\n\n    Tests.prototype.notify_result = function (test) {\n      var this_obj = this;\n      this.processing_callbacks = true;\n      forEach(this.test_done_callbacks, function (callback) {\n        callback(test, this_obj);\n      });\n      this.processing_callbacks = false;\n      if (this_obj.all_done()) {\n        this_obj.complete();\n      }\n    };\n\n    Tests.prototype.complete = function () {\n      if (this.phase === this.phases.COMPLETE) {\n        return;\n      }\n      var this_obj = this;\n      var all_complete = function () {\n        this_obj.phase = this_obj.phases.COMPLETE;\n        this_obj.notify_complete();\n      };\n      var incomplete = filter(this.tests, function (test) {\n        return test.phase < test.phases.COMPLETE;\n      });\n\n      /**\n       * To preserve legacy behavior, overall test completion must be\n       * signaled synchronously.\n       */\n      if (incomplete.length === 0) {\n        all_complete();\n        return;\n      }\n\n      all_async(\n        incomplete,\n        function (test, testDone) {\n          if (test.phase === test.phases.INITIAL) {\n            test.phase = test.phases.COMPLETE;\n            testDone();\n          } else {\n            add_test_done_callback(test, testDone);\n            test.cleanup();\n          }\n        },\n        all_complete\n      );\n    };\n\n    Tests.prototype.set_assert = function (assert_name, args) {\n      this.asserts_run.push(\n        new AssertRecord(this.current_test, assert_name, args)\n      );\n    };\n\n    Tests.prototype.set_assert_status = function (index, status, stack) {\n      let assert_record = this.asserts_run[index];\n      assert_record.status = status;\n      assert_record.stack = stack;\n    };\n\n    /**\n     * Update the harness status to reflect an unrecoverable harness error that\n     * should cancel all further testing. Update all previously-defined tests\n     * which have not yet started to indicate that they will not be executed.\n     */\n    Tests.prototype.abort = function () {\n      this.status.status = this.status.ERROR;\n      this.is_aborted = true;\n\n      forEach(this.tests, function (test) {\n        if (test.phase === test.phases.INITIAL) {\n          test.phase = test.phases.COMPLETE;\n        }\n      });\n    };\n\n    /*\n     * Determine if any tests share the same `name` property. Return an array\n     * containing the names of any such duplicates.\n     */\n    Tests.prototype.find_duplicates = function () {\n      var names = Object.create(null);\n      var duplicates = [];\n\n      forEach(this.tests, function (test) {\n        if (test.name in names && duplicates.indexOf(test.name) === -1) {\n          duplicates.push(test.name);\n        }\n        names[test.name] = true;\n      });\n\n      return duplicates;\n    };\n\n    function code_unit_str(char) {\n      return \"U+\" + char.charCodeAt(0).toString(16);\n    }\n\n    function sanitize_unpaired_surrogates(str) {\n      return str.replace(\n        /([\\ud800-\\udbff]+)(?![\\udc00-\\udfff])|(^|[^\\ud800-\\udbff])([\\udc00-\\udfff]+)/g,\n        function (_, low, prefix, high) {\n          var output = prefix || \"\"; // prefix may be undefined\n          var string = low || high; // only one of these alternates can match\n          for (var i = 0; i < string.length; i++) {\n            output += code_unit_str(string[i]);\n          }\n          return output;\n        }\n      );\n    }\n\n    function sanitize_all_unpaired_surrogates(tests) {\n      forEach(tests, function (test) {\n        var sanitized = sanitize_unpaired_surrogates(test.name);\n\n        if (test.name !== sanitized) {\n          test.name = sanitized;\n          delete test._structured_clone;\n        }\n      });\n    }\n\n    Tests.prototype.notify_complete = function () {\n      var this_obj = this;\n      var duplicates;\n\n      if (this.status.status === null) {\n        duplicates = this.find_duplicates();\n\n        // Some transports adhere to UTF-8's restriction on unpaired\n        // surrogates. Sanitize the titles so that the results can be\n        // consistently sent via all transports.\n        sanitize_all_unpaired_surrogates(this.tests);\n\n        // Test names are presumed to be unique within test files--this\n        // allows consumers to use them for identification purposes.\n        // Duplicated names violate this expectation and should therefore\n        // be reported as an error.\n        if (duplicates.length) {\n          this.status.status = this.status.ERROR;\n          this.status.message =\n            duplicates.length +\n            \" duplicate test name\" +\n            (duplicates.length > 1 ? \"s\" : \"\") +\n            ': \"' +\n            duplicates.join('\", \"') +\n            '\"';\n        } else {\n          this.status.status = this.status.OK;\n        }\n      }\n\n      forEach(this.all_done_callbacks, function (callback) {\n        callback(this_obj.tests, this_obj.status, this_obj.asserts_run);\n      });\n    };\n\n    /*\n     * Constructs a RemoteContext that tracks tests from a specific worker.\n     */\n    Tests.prototype.create_remote_worker = function (worker) {\n      var message_port;\n\n      if (is_service_worker(worker)) {\n        message_port = navigator.serviceWorker;\n        worker.postMessage({ type: \"connect\" });\n      } else if (is_shared_worker(worker)) {\n        message_port = worker.port;\n        message_port.start();\n      } else {\n        message_port = worker;\n      }\n\n      return new RemoteContext(worker, message_port);\n    };\n\n    /*\n     * Constructs a RemoteContext that tracks tests from a specific window.\n     */\n    Tests.prototype.create_remote_window = function (remote) {\n      remote.postMessage({ type: \"getmessages\" }, \"*\");\n      return new RemoteContext(remote, window, function (msg) {\n        return msg.source === remote;\n      });\n    };\n\n    Tests.prototype.fetch_tests_from_worker = function (worker) {\n      if (this.phase >= this.phases.COMPLETE) {\n        return;\n      }\n\n      var remoteContext = this.create_remote_worker(worker);\n      this.pending_remotes.push(remoteContext);\n      return remoteContext.done;\n    };\n\n    /**\n     * Get test results from a worker and include them in the current test.\n     *\n     * @param {Worker|SharedWorker|ServiceWorker|MessagePort} port -\n     * Either a worker object or a port connected to a worker which is\n     * running tests..\n     * @returns {Promise} - A promise that's resolved once all the remote tests are complete.\n     */\n    function fetch_tests_from_worker(port) {\n      return tests.fetch_tests_from_worker(port);\n    }\n    expose(fetch_tests_from_worker, \"fetch_tests_from_worker\");\n\n    Tests.prototype.fetch_tests_from_window = function (remote) {\n      if (this.phase >= this.phases.COMPLETE) {\n        return;\n      }\n\n      var remoteContext = this.create_remote_window(remote);\n      this.pending_remotes.push(remoteContext);\n      return remoteContext.done;\n    };\n\n    /**\n     * Aggregate tests from separate windows or iframes\n     * into the current document as if they were all part of the same test file.\n     *\n     * The document of the second window (or iframe) should include\n     * ``testharness.js``, but not ``testharnessreport.js``, and use\n     * :js:func:`test`, :js:func:`async_test`, and :js:func:`promise_test` in\n     * the usual manner.\n     *\n     * @param {Window} window - The window to fetch tests from.\n     */\n    function fetch_tests_from_window(window) {\n      return tests.fetch_tests_from_window(window);\n    }\n    expose(fetch_tests_from_window, \"fetch_tests_from_window\");\n\n    /**\n     * Get test results from a shadow realm and include them in the current test.\n     *\n     * @param {ShadowRealm} realm - A shadow realm also running the test harness\n     * @returns {Promise} - A promise that's resolved once all the remote tests are complete.\n     */\n    function fetch_tests_from_shadow_realm(realm) {\n      var chan = new MessageChannel();\n      function receiveMessage(msg_json) {\n        chan.port1.postMessage(JSON.parse(msg_json));\n      }\n      var done = tests.fetch_tests_from_worker(chan.port2);\n      realm.evaluate(\"begin_shadow_realm_tests\")(receiveMessage);\n      chan.port2.start();\n      return done;\n    }\n    expose(fetch_tests_from_shadow_realm, \"fetch_tests_from_shadow_realm\");\n\n    /**\n     * Begin running tests in this shadow realm test harness.\n     *\n     * To be called after all tests have been loaded; it is an error to call\n     * this more than once or in a non-Shadow Realm environment\n     *\n     * @param {Function} postMessage - A function to send test updates to the\n     * incubating realm-- accepts JSON-encoded messages in the format used by\n     * RemoteContext\n     */\n    function begin_shadow_realm_tests(postMessage) {\n      if (!(test_environment instanceof ShadowRealmTestEnvironment)) {\n        throw new Error(\n          \"begin_shadow_realm_tests called in non-Shadow Realm environment\"\n        );\n      }\n\n      test_environment.begin(function (msg) {\n        postMessage(JSON.stringify(msg));\n      });\n    }\n    expose(begin_shadow_realm_tests, \"begin_shadow_realm_tests\");\n\n    /**\n     * Timeout the tests.\n     *\n     * This only has an effect when ``explicit_timeout`` has been set\n     * in :js:func:`setup`. In other cases any call is a no-op.\n     *\n     */\n    function timeout() {\n      if (tests.timeout_length === null) {\n        tests.timeout();\n      }\n    }\n    expose(timeout, \"timeout\");\n\n    /**\n     * Add a callback that's triggered when the first :js:class:`Test` is created.\n     *\n     * @param {Function} callback - Callback function. This is called\n     * without arguments.\n     */\n    function add_start_callback(callback) {\n      tests.start_callbacks.push(callback);\n    }\n\n    /**\n     * Add a callback that's triggered when a test state changes.\n     *\n     * @param {Function} callback - Callback function, called with the\n     * :js:class:`Test` as the only argument.\n     */\n    function add_test_state_callback(callback) {\n      tests.test_state_callbacks.push(callback);\n    }\n\n    /**\n     * Add a callback that's triggered when a test result is received.\n     *\n     * @param {Function} callback - Callback function, called with the\n     * :js:class:`Test` as the only argument.\n     */\n    function add_result_callback(callback) {\n      tests.test_done_callbacks.push(callback);\n    }\n\n    /**\n     * Add a callback that's triggered when all tests are complete.\n     *\n     * @param {Function} callback - Callback function, called with an\n     * array of :js:class:`Test` objects, a :js:class:`TestsStatus`\n     * object and an array of :js:class:`AssertRecord` objects. If the\n     * debug setting is ``false`` the final argument will be an empty\n     * array.\n     *\n     * For performance reasons asserts are only tracked when the debug\n     * setting is ``true``. In other cases the array of asserts will be\n     * empty.\n     */\n    function add_completion_callback(callback) {\n      tests.all_done_callbacks.push(callback);\n    }\n\n    expose(add_start_callback, \"add_start_callback\");\n    expose(add_test_state_callback, \"add_test_state_callback\");\n    expose(add_result_callback, \"add_result_callback\");\n    expose(add_completion_callback, \"add_completion_callback\");\n\n    function remove(array, item) {\n      var index = array.indexOf(item);\n      if (index > -1) {\n        array.splice(index, 1);\n      }\n    }\n\n    function remove_start_callback(callback) {\n      remove(tests.start_callbacks, callback);\n    }\n\n    function remove_test_state_callback(callback) {\n      remove(tests.test_state_callbacks, callback);\n    }\n\n    function remove_result_callback(callback) {\n      remove(tests.test_done_callbacks, callback);\n    }\n\n    function remove_completion_callback(callback) {\n      remove(tests.all_done_callbacks, callback);\n    }\n\n    /*\n     * Output listener\n     */\n\n    function Output() {\n      this.output_document = document;\n      this.output_node = null;\n      this.enabled = settings.output;\n      this.phase = this.INITIAL;\n    }\n\n    Output.prototype.INITIAL = 0;\n    Output.prototype.STARTED = 1;\n    Output.prototype.HAVE_RESULTS = 2;\n    Output.prototype.COMPLETE = 3;\n\n    Output.prototype.setup = function (properties) {\n      if (this.phase > this.INITIAL) {\n        return;\n      }\n\n      //If output is disabled in testharnessreport.js the test shouldn't be\n      //able to override that\n      this.enabled =\n        this.enabled &&\n        (properties.hasOwnProperty(\"output\")\n          ? properties.output\n          : settings.output);\n    };\n\n    Output.prototype.init = function (properties) {\n      if (this.phase >= this.STARTED) {\n        return;\n      }\n      if (properties.output_document) {\n        this.output_document = properties.output_document;\n      } else {\n        this.output_document = document;\n      }\n      this.phase = this.STARTED;\n    };\n\n    Output.prototype.resolve_log = function () {\n      var output_document;\n      if (this.output_node) {\n        return;\n      }\n      if (typeof this.output_document === \"function\") {\n        output_document = this.output_document.apply(undefined);\n      } else {\n        output_document = this.output_document;\n      }\n      if (!output_document) {\n        return;\n      }\n      var node = output_document.getElementById(\"log\");\n      if (!node) {\n        if (output_document.readyState === \"loading\") {\n          return;\n        }\n        node = output_document.createElementNS(\n          \"http://www.w3.org/1999/xhtml\",\n          \"div\"\n        );\n        node.id = \"log\";\n        if (output_document.body) {\n          output_document.body.appendChild(node);\n        } else {\n          var root = output_document.documentElement;\n          var is_html =\n            root &&\n            root.namespaceURI == \"http://www.w3.org/1999/xhtml\" &&\n            root.localName == \"html\";\n          var is_svg =\n            output_document.defaultView &&\n            \"SVGSVGElement\" in output_document.defaultView &&\n            root instanceof output_document.defaultView.SVGSVGElement;\n          if (is_svg) {\n            var foreignObject = output_document.createElementNS(\n              \"http://www.w3.org/2000/svg\",\n              \"foreignObject\"\n            );\n            foreignObject.setAttribute(\"width\", \"100%\");\n            foreignObject.setAttribute(\"height\", \"100%\");\n            root.appendChild(foreignObject);\n            foreignObject.appendChild(node);\n          } else if (is_html) {\n            root\n              .appendChild(\n                output_document.createElementNS(\n                  \"http://www.w3.org/1999/xhtml\",\n                  \"body\"\n                )\n              )\n              .appendChild(node);\n          } else {\n            root.appendChild(node);\n          }\n        }\n      }\n      this.output_document = output_document;\n      this.output_node = node;\n    };\n\n    Output.prototype.show_status = function () {\n      if (this.phase < this.STARTED) {\n        this.init({});\n      }\n      if (!this.enabled || this.phase === this.COMPLETE) {\n        return;\n      }\n      this.resolve_log();\n      if (this.phase < this.HAVE_RESULTS) {\n        this.phase = this.HAVE_RESULTS;\n      }\n      var done_count = tests.tests.length - tests.num_pending;\n      if (this.output_node && !tests.hide_test_state) {\n        if (\n          done_count < 100 ||\n          (done_count < 1000 && done_count % 100 === 0) ||\n          done_count % 1000 === 0\n        ) {\n          this.output_node.textContent =\n            \"Running, \" +\n            done_count +\n            \" complete, \" +\n            tests.num_pending +\n            \" remain\";\n        }\n      }\n    };\n\n    Output.prototype.show_results = function (\n      tests,\n      harness_status,\n      asserts_run\n    ) {\n      if (this.phase >= this.COMPLETE) {\n        return;\n      }\n      if (!this.enabled) {\n        return;\n      }\n      if (!this.output_node) {\n        this.resolve_log();\n      }\n      this.phase = this.COMPLETE;\n\n      var log = this.output_node;\n      if (!log) {\n        return;\n      }\n      var output_document = this.output_document;\n\n      while (log.lastChild) {\n        log.removeChild(log.lastChild);\n      }\n\n      var stylesheet = output_document.createElementNS(xhtml_ns, \"style\");\n      stylesheet.textContent = stylesheetContent;\n      var heads = output_document.getElementsByTagName(\"head\");\n      if (heads.length) {\n        heads[0].appendChild(stylesheet);\n      }\n\n      var status_number = {};\n      forEach(tests, function (test) {\n        var status = test.format_status();\n        if (status_number.hasOwnProperty(status)) {\n          status_number[status] += 1;\n        } else {\n          status_number[status] = 1;\n        }\n      });\n\n      function status_class(status) {\n        return status.replace(/\\s/g, \"\").toLowerCase();\n      }\n\n      var summary_template = [\n        \"section\",\n        { id: \"summary\" },\n        [\"h2\", {}, \"Summary\"],\n        function () {\n          var status = harness_status.format_status();\n          var rv = [\n            [\n              \"section\",\n              {},\n              [\n                \"p\",\n                {},\n                \"Harness status: \",\n                [\"span\", { class: status_class(status) }, status],\n              ],\n              [\"button\", { id: \"rerun\" }, \"Rerun\"],\n            ],\n          ];\n\n          if (harness_status.status === harness_status.ERROR) {\n            rv[0].push([\"pre\", {}, harness_status.message]);\n            if (harness_status.stack) {\n              rv[0].push([\"pre\", {}, harness_status.stack]);\n            }\n          }\n          return rv;\n        },\n        [\"p\", {}, \"Found ${num_tests} tests\"],\n        function () {\n          var rv = [[\"div\", {}]];\n          var i = 0;\n          while (Test.prototype.status_formats.hasOwnProperty(i)) {\n            if (\n              status_number.hasOwnProperty(Test.prototype.status_formats[i])\n            ) {\n              var status = Test.prototype.status_formats[i];\n              rv[0].push([\n                \"div\",\n                {},\n                [\n                  \"label\",\n                  {},\n                  [\"input\", { type: \"checkbox\", checked: \"checked\" }],\n                  status_number[status] + \" \",\n                  [\"span\", { class: status_class(status) }, status],\n                ],\n              ]);\n            }\n            i++;\n          }\n          return rv;\n        },\n      ];\n\n      log.appendChild(\n        render(summary_template, { num_tests: tests.length }, output_document)\n      );\n\n      output_document\n        .getElementById(\"rerun\")\n        .addEventListener(\"click\", function () {\n          let evt = new Event(\"__test_restart\");\n          let canceled = !window.dispatchEvent(evt);\n          if (!canceled) {\n            location.reload();\n          }\n        });\n\n      forEach(\n        output_document.querySelectorAll(\"section#summary label\"),\n        function (element) {\n          on_event(element, \"click\", function (e) {\n            if (output_document.getElementById(\"results\") === null) {\n              e.preventDefault();\n              return;\n            }\n            var result_class = element\n              .querySelector(\"span[class]\")\n              .getAttribute(\"class\");\n            var style_element = output_document.querySelector(\n              \"style#hide-\" + result_class\n            );\n            var input_element = element.querySelector(\"input\");\n            if (!style_element && !input_element.checked) {\n              style_element = output_document.createElementNS(\n                xhtml_ns,\n                \"style\"\n              );\n              style_element.id = \"hide-\" + result_class;\n              style_element.textContent =\n                \"table#results > tbody > tr.overall-\" +\n                result_class +\n                \"{display:none}\";\n              output_document.body.appendChild(style_element);\n            } else if (style_element && input_element.checked) {\n              style_element.parentNode.removeChild(style_element);\n            }\n          });\n        }\n      );\n\n      function has_assertions() {\n        for (var i = 0; i < tests.length; i++) {\n          if (tests[i].properties.hasOwnProperty(\"assert\")) {\n            return true;\n          }\n        }\n        return false;\n      }\n\n      function get_assertion(test) {\n        if (test.properties.hasOwnProperty(\"assert\")) {\n          if (Array.isArray(test.properties.assert)) {\n            return test.properties.assert.join(\" \");\n          }\n          return test.properties.assert;\n        }\n        return \"\";\n      }\n\n      var asserts_run_by_test = new Map();\n      asserts_run.forEach((assert) => {\n        if (!asserts_run_by_test.has(assert.test)) {\n          asserts_run_by_test.set(assert.test, []);\n        }\n        asserts_run_by_test.get(assert.test).push(assert);\n      });\n\n      function get_asserts_output(test) {\n        const asserts_output = render([\n          \"details\",\n          {},\n          [\"summary\", {}, \"Asserts run\"],\n          [\"table\", {}, \"\"],\n        ]);\n\n        var asserts = asserts_run_by_test.get(test);\n        if (!asserts) {\n          asserts_output\n            .querySelector(\"summary\")\n            .insertAdjacentText(\"afterend\", \"No asserts ran\");\n          return asserts_output;\n        }\n\n        const table = asserts_output.querySelector(\"table\");\n        for (const assert of asserts) {\n          const status_class_name = status_class(\n            Test.prototype.status_formats[assert.status]\n          );\n          var output_fn = \"(\" + assert.args.join(\", \") + \")\";\n          if (assert.stack) {\n            output_fn += \"\\n\";\n            output_fn += assert.stack\n              .split(\"\\n\", 1)[0]\n              .replace(/@?\\w+:\\/\\/[^ \"\\/]+(?::\\d+)?/g, \" \");\n          }\n          table.appendChild(\n            render([\n              \"tr\",\n              { class: \"overall-\" + status_class_name },\n              [\n                \"td\",\n                { class: status_class_name },\n                Test.prototype.status_formats[assert.status],\n              ],\n              [\n                \"td\",\n                {},\n                [\"pre\", {}, [\"strong\", {}, assert.assert_name], output_fn],\n              ],\n            ])\n          );\n        }\n        return asserts_output;\n      }\n\n      var assertions = has_assertions();\n      const section = render([\n        \"section\",\n        {},\n        [\"h2\", {}, \"Details\"],\n        [\n          \"table\",\n          { id: \"results\", class: assertions ? \"assertions\" : \"\" },\n          [\n            \"thead\",\n            {},\n            [\n              \"tr\",\n              {},\n              [\"th\", {}, \"Result\"],\n              [\"th\", {}, \"Test Name\"],\n              assertions ? [\"th\", {}, \"Assertion\"] : \"\",\n              [\"th\", {}, \"Message\"],\n            ],\n          ],\n          [\"tbody\", {}],\n        ],\n      ]);\n\n      const tbody = section.querySelector(\"tbody\");\n      for (const test of tests) {\n        const status = test.format_status();\n        const status_class_name = status_class(status);\n        tbody.appendChild(\n          render([\n            \"tr\",\n            { class: \"overall-\" + status_class_name },\n            [\"td\", { class: status_class_name }, status],\n            [\"td\", {}, test.name],\n            assertions ? [\"td\", {}, get_assertion(test)] : \"\",\n            [\"td\", {}, test.message ?? \"\", [\"pre\", {}, test.stack ?? \"\"]],\n          ])\n        );\n        if (!(test instanceof RemoteTest)) {\n          tbody.lastChild.lastChild.appendChild(get_asserts_output(test));\n        }\n      }\n      log.appendChild(section);\n    };\n\n    /*\n     * Template code\n     *\n     * A template is just a JavaScript structure. An element is represented as:\n     *\n     * [tag_name, {attr_name:attr_value}, child1, child2]\n     *\n     * the children can either be strings (which act like text nodes), other templates or\n     * functions (see below)\n     *\n     * A text node is represented as\n     *\n     * [\"{text}\", value]\n     *\n     * String values have a simple substitution syntax; ${foo} represents a variable foo.\n     *\n     * It is possible to embed logic in templates by using a function in a place where a\n     * node would usually go. The function must either return part of a template or null.\n     *\n     * In cases where a set of nodes are required as output rather than a single node\n     * with children it is possible to just use a list\n     * [node1, node2, node3]\n     *\n     * Usage:\n     *\n     * render(template, substitutions) - take a template and an object mapping\n     * variable names to parameters and return either a DOM node or a list of DOM nodes\n     *\n     * substitute(template, substitutions) - take a template and variable mapping object,\n     * make the variable substitutions and return the substituted template\n     *\n     */\n\n    function is_single_node(template) {\n      return typeof template[0] === \"string\";\n    }\n\n    function substitute(template, substitutions) {\n      if (typeof template === \"function\") {\n        var replacement = template(substitutions);\n        if (!replacement) {\n          return null;\n        }\n\n        return substitute(replacement, substitutions);\n      }\n\n      if (is_single_node(template)) {\n        return substitute_single(template, substitutions);\n      }\n\n      return filter(\n        map(template, function (x) {\n          return substitute(x, substitutions);\n        }),\n        function (x) {\n          return x !== null;\n        }\n      );\n    }\n\n    function substitute_single(template, substitutions) {\n      var substitution_re = /\\$\\{([^ }]*)\\}/g;\n\n      function do_substitution(input) {\n        var components = input.split(substitution_re);\n        var rv = [];\n        for (var i = 0; i < components.length; i += 2) {\n          rv.push(components[i]);\n          if (components[i + 1]) {\n            rv.push(String(substitutions[components[i + 1]]));\n          }\n        }\n        return rv;\n      }\n\n      function substitute_attrs(attrs, rv) {\n        rv[1] = {};\n        for (var name in template[1]) {\n          if (attrs.hasOwnProperty(name)) {\n            var new_name = do_substitution(name).join(\"\");\n            var new_value = do_substitution(attrs[name]).join(\"\");\n            rv[1][new_name] = new_value;\n          }\n        }\n      }\n\n      function substitute_children(children, rv) {\n        for (var i = 0; i < children.length; i++) {\n          if (children[i] instanceof Object) {\n            var replacement = substitute(children[i], substitutions);\n            if (replacement !== null) {\n              if (is_single_node(replacement)) {\n                rv.push(replacement);\n              } else {\n                extend(rv, replacement);\n              }\n            }\n          } else {\n            extend(rv, do_substitution(String(children[i])));\n          }\n        }\n        return rv;\n      }\n\n      var rv = [];\n      rv.push(do_substitution(String(template[0])).join(\"\"));\n\n      if (template[0] === \"{text}\") {\n        substitute_children(template.slice(1), rv);\n      } else {\n        substitute_attrs(template[1], rv);\n        substitute_children(template.slice(2), rv);\n      }\n\n      return rv;\n    }\n\n    function make_dom_single(template, doc) {\n      var output_document = doc || document;\n      var element;\n      if (template[0] === \"{text}\") {\n        element = output_document.createTextNode(\"\");\n        for (var i = 1; i < template.length; i++) {\n          element.data += template[i];\n        }\n      } else {\n        element = output_document.createElementNS(xhtml_ns, template[0]);\n        for (var name in template[1]) {\n          if (template[1].hasOwnProperty(name)) {\n            element.setAttribute(name, template[1][name]);\n          }\n        }\n        for (var i = 2; i < template.length; i++) {\n          if (template[i] instanceof Object) {\n            var sub_element = make_dom(template[i]);\n            element.appendChild(sub_element);\n          } else {\n            var text_node = output_document.createTextNode(template[i]);\n            element.appendChild(text_node);\n          }\n        }\n      }\n\n      return element;\n    }\n\n    function make_dom(template, substitutions, output_document) {\n      if (is_single_node(template)) {\n        return make_dom_single(template, output_document);\n      }\n\n      return map(template, function (x) {\n        return make_dom_single(x, output_document);\n      });\n    }\n\n    function render(template, substitutions, output_document) {\n      return make_dom(substitute(template, substitutions), output_document);\n    }\n\n    /*\n     * Utility functions\n     */\n    function assert(\n      expected_true,\n      function_name,\n      description,\n      error,\n      substitutions\n    ) {\n      if (expected_true !== true) {\n        var msg = make_message(\n          function_name,\n          description,\n          error,\n          substitutions\n        );\n        throw new AssertionError(msg);\n      }\n    }\n\n    /**\n     * @class\n     * Exception type that represents a failing assert.\n     *\n     * @param {string} message - Error message.\n     */\n    function AssertionError(message) {\n      if (typeof message == \"string\") {\n        message = sanitize_unpaired_surrogates(message);\n      }\n      this.message = message;\n      this.stack = get_stack();\n    }\n    expose(AssertionError, \"AssertionError\");\n\n    AssertionError.prototype = Object.create(Error.prototype);\n\n    const get_stack = function () {\n      var stack = new Error().stack;\n\n      // 'Error.stack' is not supported in all browsers/versions\n      if (!stack) {\n        return \"(Stack trace unavailable)\";\n      }\n\n      var lines = stack.split(\"\\n\");\n\n      // Create a pattern to match stack frames originating within testharness.js.  These include the\n      // script URL, followed by the line/col (e.g., '/resources/testharness.js:120:21').\n      // Escape the URL per http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript\n      // in case it contains RegExp characters.\n      var script_url = get_script_url();\n      var re_text = script_url\n        ? script_url.replace(/[-\\/\\\\^$*+?.()|[\\]{}]/g, \"\\\\$&\")\n        : \"\\\\btestharness.js\";\n      var re = new RegExp(re_text + \":\\\\d+:\\\\d+\");\n\n      // Some browsers include a preamble that specifies the type of the error object.  Skip this by\n      // advancing until we find the first stack frame originating from testharness.js.\n      var i = 0;\n      while (!re.test(lines[i]) && i < lines.length) {\n        i++;\n      }\n\n      // Then skip the top frames originating from testharness.js to begin the stack at the test code.\n      while (re.test(lines[i]) && i < lines.length) {\n        i++;\n      }\n\n      // Paranoid check that we didn't skip all frames.  If so, return the original stack unmodified.\n      if (i >= lines.length) {\n        return stack;\n      }\n\n      return lines.slice(i).join(\"\\n\");\n    };\n\n    function OptionalFeatureUnsupportedError(message) {\n      AssertionError.call(this, message);\n    }\n    OptionalFeatureUnsupportedError.prototype = Object.create(\n      AssertionError.prototype\n    );\n    expose(OptionalFeatureUnsupportedError, \"OptionalFeatureUnsupportedError\");\n\n    function make_message(function_name, description, error, substitutions) {\n      for (var p in substitutions) {\n        if (substitutions.hasOwnProperty(p)) {\n          substitutions[p] = format_value(substitutions[p]);\n        }\n      }\n      var node_form = substitute(\n        [\"{text}\", \"${function_name}: ${description}\" + error],\n        merge(\n          {\n            function_name: function_name,\n            description: description ? description + \" \" : \"\",\n          },\n          substitutions\n        )\n      );\n      return node_form.slice(1).join(\"\");\n    }\n\n    function filter(array, callable, thisObj) {\n      var rv = [];\n      for (var i = 0; i < array.length; i++) {\n        if (array.hasOwnProperty(i)) {\n          var pass = callable.call(thisObj, array[i], i, array);\n          if (pass) {\n            rv.push(array[i]);\n          }\n        }\n      }\n      return rv;\n    }\n\n    function map(array, callable, thisObj) {\n      var rv = [];\n      rv.length = array.length;\n      for (var i = 0; i < array.length; i++) {\n        if (array.hasOwnProperty(i)) {\n          rv[i] = callable.call(thisObj, array[i], i, array);\n        }\n      }\n      return rv;\n    }\n\n    function extend(array, items) {\n      Array.prototype.push.apply(array, items);\n    }\n\n    function forEach(array, callback, thisObj) {\n      for (var i = 0; i < array.length; i++) {\n        if (array.hasOwnProperty(i)) {\n          callback.call(thisObj, array[i], i, array);\n        }\n      }\n    }\n\n    /**\n     * Immediately invoke a \"iteratee\" function with a series of values in\n     * parallel and invoke a final \"done\" function when all of the \"iteratee\"\n     * invocations have signaled completion.\n     *\n     * If all callbacks complete synchronously (or if no callbacks are\n     * specified), the ``done_callback`` will be invoked synchronously. It is the\n     * responsibility of the caller to ensure asynchronicity in cases where\n     * that is desired.\n     *\n     * @param {array} value Zero or more values to use in the invocation of\n     *                      ``iter_callback``\n     * @param {function} iter_callback A function that will be invoked\n     *                                 once for each of the values min\n     *                                 ``value``. Two arguments will\n     *                                 be available in each\n     *                                 invocation: the value from\n     *                                 ``value`` and a function that\n     *                                 must be invoked to signal\n     *                                 completion\n     * @param {function} done_callback A function that will be invoked after\n     *                                 all operations initiated by the\n     *                                 ``iter_callback`` function have signaled\n     *                                 completion\n     */\n    function all_async(values, iter_callback, done_callback) {\n      var remaining = values.length;\n\n      if (remaining === 0) {\n        done_callback();\n      }\n\n      forEach(values, function (element) {\n        var invoked = false;\n        var elDone = function () {\n          if (invoked) {\n            return;\n          }\n\n          invoked = true;\n          remaining -= 1;\n\n          if (remaining === 0) {\n            done_callback();\n          }\n        };\n\n        iter_callback(element, elDone);\n      });\n    }\n\n    function merge(a, b) {\n      var rv = {};\n      var p;\n      for (p in a) {\n        rv[p] = a[p];\n      }\n      for (p in b) {\n        rv[p] = b[p];\n      }\n      return rv;\n    }\n\n    function expose(object, name) {\n      var components = name.split(\".\");\n      var target = global_scope;\n      for (var i = 0; i < components.length - 1; i++) {\n        if (!(components[i] in target)) {\n          target[components[i]] = {};\n        }\n        target = target[components[i]];\n      }\n      target[components[components.length - 1]] = object;\n    }\n\n    function is_same_origin(w) {\n      try {\n        \"random_prop\" in w;\n        return true;\n      } catch (e) {\n        return false;\n      }\n    }\n\n    /** Returns the 'src' URL of the first <script> tag in the page to include the file 'testharness.js'. */\n    function get_script_url() {\n      if (!(\"document\" in global_scope)) {\n        return undefined;\n      }\n\n      var scripts = document.getElementsByTagName(\"script\");\n      for (var i = 0; i < scripts.length; i++) {\n        var src;\n        if (scripts[i].src) {\n          src = scripts[i].src;\n        } else if (scripts[i].href) {\n          //SVG case\n          src = scripts[i].href.baseVal;\n        }\n\n        var matches = src && src.match(/^(.*\\/|)testharness\\.js$/);\n        if (matches) {\n          return src;\n        }\n      }\n      return undefined;\n    }\n\n    /** Returns the <title> or filename or \"Untitled\" */\n    function get_title() {\n      if (\"document\" in global_scope) {\n        //Don't use document.title to work around an Opera/Presto bug in XHTML documents\n        var title = document.getElementsByTagName(\"title\")[0];\n        if (title && title.firstChild && title.firstChild.data) {\n          return title.firstChild.data;\n        }\n      }\n      if (\"META_TITLE\" in global_scope && META_TITLE) {\n        return META_TITLE;\n      }\n      if (\"location\" in global_scope && \"pathname\" in location) {\n        return location.pathname.substring(\n          location.pathname.lastIndexOf(\"/\") + 1,\n          location.pathname.indexOf(\".\")\n        );\n      }\n      return \"Untitled\";\n    }\n\n    /** Fetches a JSON resource and parses it */\n    async function fetch_json(resource) {\n      const response = await fetch(resource);\n      return await response.json();\n    }\n    if (!global_scope.GLOBAL || !global_scope.GLOBAL.isShadowRealm()) {\n      expose(fetch_json, \"fetch_json\");\n    }\n\n    /**\n     * Setup globals\n     */\n\n    var tests = new Tests();\n\n    if (global_scope.addEventListener) {\n      var error_handler = function (error, message, stack) {\n        var optional_unsupported =\n          error instanceof OptionalFeatureUnsupportedError;\n        if (tests.file_is_test) {\n          var test = tests.tests[0];\n          if (test.phase >= test.phases.HAS_RESULT) {\n            return;\n          }\n          var status = optional_unsupported\n            ? test.PRECONDITION_FAILED\n            : test.FAIL;\n          test.set_status(status, message, stack);\n          test.phase = test.phases.HAS_RESULT;\n        } else if (!tests.allow_uncaught_exception) {\n          var status = optional_unsupported\n            ? tests.status.PRECONDITION_FAILED\n            : tests.status.ERROR;\n          tests.status.status = status;\n          tests.status.message = message;\n          tests.status.stack = stack;\n        }\n\n        // Do not transition to the \"complete\" phase if the test has been\n        // configured to allow uncaught exceptions. This gives the test an\n        // opportunity to define subtests based on the exception reporting\n        // behavior.\n        if (!tests.allow_uncaught_exception) {\n          done();\n        }\n      };\n\n      addEventListener(\n        \"error\",\n        function (e) {\n          var message = e.message;\n          var stack;\n          if (e.error && e.error.stack) {\n            stack = e.error.stack;\n          } else {\n            stack = e.filename + \":\" + e.lineno + \":\" + e.colno;\n          }\n          error_handler(e.error, message, stack);\n        },\n        false\n      );\n\n      addEventListener(\n        \"unhandledrejection\",\n        function (e) {\n          var message;\n          if (e.reason && e.reason.message) {\n            message = \"Unhandled rejection: \" + e.reason.message;\n          } else {\n            message = \"Unhandled rejection\";\n          }\n          var stack;\n          if (e.reason && e.reason.stack) {\n            stack = e.reason.stack;\n          }\n          error_handler(e.reason, message, stack);\n        },\n        false\n      );\n    }\n\n    test_environment.on_tests_ready();\n\n    /**\n     * Stylesheet\n     */\n    var stylesheetContent =\n      \"\\\nhtml {\\\n    font-family:DejaVu Sans, Bitstream Vera Sans, Arial, Sans;\\\n}\\\n\\\n#log .warning,\\\n#log .warning a {\\\n  color: black;\\\n  background: yellow;\\\n}\\\n\\\n#log .error,\\\n#log .error a {\\\n  color: white;\\\n  background: red;\\\n}\\\n\\\nsection#summary {\\\n    margin-bottom:1em;\\\n}\\\n\\\ntable#results {\\\n    border-collapse:collapse;\\\n    table-layout:fixed;\\\n    width:100%;\\\n}\\\n\\\ntable#results > thead > tr > th:first-child,\\\ntable#results > tbody > tr > td:first-child {\\\n    width:8em;\\\n}\\\n\\\ntable#results > thead > tr > th:last-child,\\\ntable#results > thead > tr > td:last-child {\\\n    width:50%;\\\n}\\\n\\\ntable#results.assertions > thead > tr > th:last-child,\\\ntable#results.assertions > tbody > tr > td:last-child {\\\n    width:35%;\\\n}\\\n\\\ntable#results > thead > > tr > th {\\\n    padding:0;\\\n    padding-bottom:0.5em;\\\n    border-bottom:medium solid black;\\\n}\\\n\\\ntable#results > tbody > tr> td {\\\n    padding:1em;\\\n    padding-bottom:0.5em;\\\n    border-bottom:thin solid black;\\\n}\\\n\\\n.pass {\\\n    color:green;\\\n}\\\n\\\n.fail {\\\n    color:red;\\\n}\\\n\\\ntr.timeout {\\\n    color:red;\\\n}\\\n\\\ntr.notrun {\\\n    color:blue;\\\n}\\\n\\\ntr.optionalunsupported {\\\n    color:blue;\\\n}\\\n\\\n.ok {\\\n    color:green;\\\n}\\\n\\\n.error {\\\n    color:red;\\\n}\\\n\\\n.pass, .fail, .timeout, .notrun, .optionalunsupported .ok, .timeout, .error {\\\n    font-variant:small-caps;\\\n}\\\n\\\ntable#results span {\\\n    display:block;\\\n}\\\n\\\ntable#results span.expected {\\\n    font-family:DejaVu Sans Mono, Bitstream Vera Sans Mono, Monospace;\\\n    white-space:pre;\\\n}\\\n\\\ntable#results span.actual {\\\n    font-family:DejaVu Sans Mono, Bitstream Vera Sans Mono, Monospace;\\\n    white-space:pre;\\\n}\\\n\";\n  })(self);\n  // vim: set expandtab shiftwidth=4 tabstop=4:\n}\n"
  },
  {
    "path": "tests/wpt/streams/resources/recording-streams.js",
    "content": "export default function ({}) {\n  // 'use strict';\n\n  self.recordingReadableStream = (extras = {}, strategy) => {\n    let controllerToCopyOver;\n    const stream = new ReadableStream(\n      {\n        type: extras.type,\n        start(controller) {\n          controllerToCopyOver = controller;\n\n          if (extras.start) {\n            return extras.start(controller);\n          }\n\n          return undefined;\n        },\n        pull(controller) {\n          stream.events.push(\"pull\");\n\n          if (extras.pull) {\n            return extras.pull(controller);\n          }\n\n          return undefined;\n        },\n        cancel(reason) {\n          stream.events.push(\"cancel\", reason);\n          stream.eventsWithoutPulls.push(\"cancel\", reason);\n\n          if (extras.cancel) {\n            return extras.cancel(reason);\n          }\n\n          return undefined;\n        },\n      },\n      strategy\n    );\n\n    stream.controller = controllerToCopyOver;\n    stream.events = [];\n    stream.eventsWithoutPulls = [];\n\n    return stream;\n  };\n\n  self.recordingWritableStream = (extras = {}, strategy) => {\n    let controllerToCopyOver;\n    const stream = new WritableStream(\n      {\n        start(controller) {\n          controllerToCopyOver = controller;\n\n          if (extras.start) {\n            return extras.start(controller);\n          }\n\n          return undefined;\n        },\n        write(chunk, controller) {\n          stream.events.push(\"write\", chunk);\n\n          if (extras.write) {\n            return extras.write(chunk, controller);\n          }\n\n          return undefined;\n        },\n        close() {\n          stream.events.push(\"close\");\n\n          if (extras.close) {\n            return extras.close();\n          }\n\n          return undefined;\n        },\n        abort(e) {\n          stream.events.push(\"abort\", e);\n\n          if (extras.abort) {\n            return extras.abort(e);\n          }\n\n          return undefined;\n        },\n      },\n      strategy\n    );\n\n    stream.controller = controllerToCopyOver;\n    stream.events = [];\n\n    return stream;\n  };\n\n  self.recordingTransformStream = (\n    extras = {},\n    writableStrategy,\n    readableStrategy\n  ) => {\n    let controllerToCopyOver;\n    const stream = new TransformStream(\n      {\n        start(controller) {\n          controllerToCopyOver = controller;\n\n          if (extras.start) {\n            return extras.start(controller);\n          }\n\n          return undefined;\n        },\n\n        transform(chunk, controller) {\n          stream.events.push(\"transform\", chunk);\n\n          if (extras.transform) {\n            return extras.transform(chunk, controller);\n          }\n\n          controller.enqueue(chunk);\n\n          return undefined;\n        },\n\n        flush(controller) {\n          stream.events.push(\"flush\");\n\n          if (extras.flush) {\n            return extras.flush(controller);\n          }\n\n          return undefined;\n        },\n      },\n      writableStrategy,\n      readableStrategy\n    );\n\n    stream.controller = controllerToCopyOver;\n    stream.events = [];\n\n    return stream;\n  };\n}\n"
  },
  {
    "path": "tests/wpt/streams/resources/rs-test-templates.js",
    "content": "export default function ({\n  test,\n  promise_test,\n  assert_equals,\n  assert_not_equals,\n  assert_array_equals,\n  assert_true,\n  assert_false,\n  promise_rejects_exactly,\n  assert_throws_js,\n  promise_rejects_js,\n  assert_object_equals,\n}) {\n  // 'use strict';\n\n  // These tests can be run against any readable stream produced by the web platform that meets the given descriptions.\n  // For readable stream tests, the factory should return the stream. For reader tests, the factory should return a\n  // { stream, reader } object. (You can use this to vary the time at which you acquire a reader.)\n\n  self.templatedRSEmpty = (label, factory) => {\n    test(() => {}, \"Running templatedRSEmpty with \" + label);\n\n    test(() => {\n      const rs = factory();\n\n      assert_equals(typeof rs.locked, \"boolean\", \"has a boolean locked getter\");\n      assert_equals(typeof rs.cancel, \"function\", \"has a cancel method\");\n      assert_equals(typeof rs.getReader, \"function\", \"has a getReader method\");\n      assert_equals(\n        typeof rs.pipeThrough,\n        \"function\",\n        \"has a pipeThrough method\"\n      );\n      assert_equals(typeof rs.pipeTo, \"function\", \"has a pipeTo method\");\n      assert_equals(typeof rs.tee, \"function\", \"has a tee method\");\n    }, label + \": instances have the correct methods and properties\");\n\n    test(() => {\n      const rs = factory();\n\n      assert_throws_js(\n        TypeError,\n        () => rs.getReader({ mode: \"\" }),\n        \"empty string mode should throw\"\n      );\n      assert_throws_js(\n        TypeError,\n        () => rs.getReader({ mode: null }),\n        \"null mode should throw\"\n      );\n      assert_throws_js(\n        TypeError,\n        () => rs.getReader({ mode: \"asdf\" }),\n        \"asdf mode should throw\"\n      );\n      assert_throws_js(TypeError, () => rs.getReader(5), \"5 should throw\");\n\n      // Should not throw\n      rs.getReader(null);\n    }, label + \": calling getReader with invalid arguments should throw appropriate errors\");\n  };\n\n  self.templatedRSClosed = (label, factory) => {\n    test(() => {}, \"Running templatedRSClosed with \" + label);\n\n    promise_test(() => {\n      const rs = factory();\n      const cancelPromise1 = rs.cancel();\n      const cancelPromise2 = rs.cancel();\n\n      assert_not_equals(\n        cancelPromise1,\n        cancelPromise2,\n        \"cancel() calls should return distinct promises\"\n      );\n\n      return Promise.all([\n        cancelPromise1.then((v) =>\n          assert_equals(\n            v,\n            undefined,\n            \"first cancel() call should fulfill with undefined\"\n          )\n        ),\n        cancelPromise2.then((v) =>\n          assert_equals(\n            v,\n            undefined,\n            \"second cancel() call should fulfill with undefined\"\n          )\n        ),\n      ]);\n    }, label + \": cancel() should return a distinct fulfilled promise each time\");\n\n    test(() => {\n      const rs = factory();\n      assert_false(rs.locked, \"locked getter should return false\");\n    }, label + \": locked should be false\");\n\n    test(() => {\n      const rs = factory();\n      rs.getReader(); // getReader() should not throw.\n    }, label + \": getReader() should be OK\");\n\n    test(() => {\n      const rs = factory();\n\n      const reader = rs.getReader();\n      reader.releaseLock();\n\n      const reader2 = rs.getReader(); // Getting a second reader should not throw.\n      reader2.releaseLock();\n\n      rs.getReader(); // Getting a third reader should not throw.\n    }, label + \": should be able to acquire multiple readers if they are released in succession\");\n\n    test(() => {\n      const rs = factory();\n\n      rs.getReader();\n\n      assert_throws_js(\n        TypeError,\n        () => rs.getReader(),\n        \"getting a second reader should throw\"\n      );\n      assert_throws_js(\n        TypeError,\n        () => rs.getReader(),\n        \"getting a third reader should throw\"\n      );\n    }, label + \": should not be able to acquire a second reader if we don't release the first one\");\n  };\n\n  self.templatedRSErrored = (label, factory, error) => {\n    test(() => {}, \"Running templatedRSErrored with \" + label);\n\n    promise_test((t) => {\n      const rs = factory();\n      const reader = rs.getReader();\n\n      return Promise.all([\n        promise_rejects_exactly(t, error, reader.closed),\n        promise_rejects_exactly(t, error, reader.read()),\n      ]);\n    }, label + \": getReader() should return a reader that acts errored\");\n\n    promise_test((t) => {\n      const rs = factory();\n      const reader = rs.getReader();\n\n      return Promise.all([\n        promise_rejects_exactly(t, error, reader.read()),\n        promise_rejects_exactly(t, error, reader.read()),\n        promise_rejects_exactly(t, error, reader.closed),\n      ]);\n    }, label + \": read() twice should give the error each time\");\n\n    test(() => {\n      const rs = factory();\n\n      assert_false(rs.locked, \"locked getter should return false\");\n    }, label + \": locked should be false\");\n  };\n\n  self.templatedRSErroredSyncOnly = (label, factory, error) => {\n    test(() => {}, \"Running templatedRSErroredSyncOnly with \" + label);\n\n    promise_test((t) => {\n      const rs = factory();\n      rs.getReader().releaseLock();\n      const reader = rs.getReader(); // Calling getReader() twice does not throw (the stream is not locked).\n\n      return promise_rejects_exactly(t, error, reader.closed);\n    }, label + \": should be able to obtain a second reader, with the correct closed promise\");\n\n    test(() => {\n      const rs = factory();\n      rs.getReader();\n\n      assert_throws_js(\n        TypeError,\n        () => rs.getReader(),\n        \"getting a second reader should throw a TypeError\"\n      );\n      assert_throws_js(\n        TypeError,\n        () => rs.getReader(),\n        \"getting a third reader should throw a TypeError\"\n      );\n    }, label + \": should not be able to obtain additional readers if we don't release the first lock\");\n\n    promise_test((t) => {\n      const rs = factory();\n      const cancelPromise1 = rs.cancel();\n      const cancelPromise2 = rs.cancel();\n\n      assert_not_equals(\n        cancelPromise1,\n        cancelPromise2,\n        \"cancel() calls should return distinct promises\"\n      );\n\n      return Promise.all([\n        promise_rejects_exactly(t, error, cancelPromise1),\n        promise_rejects_exactly(t, error, cancelPromise2),\n      ]);\n    }, label + \": cancel() should return a distinct rejected promise each time\");\n\n    promise_test((t) => {\n      const rs = factory();\n      const reader = rs.getReader();\n      const cancelPromise1 = reader.cancel();\n      const cancelPromise2 = reader.cancel();\n\n      assert_not_equals(\n        cancelPromise1,\n        cancelPromise2,\n        \"cancel() calls should return distinct promises\"\n      );\n\n      return Promise.all([\n        promise_rejects_exactly(t, error, cancelPromise1),\n        promise_rejects_exactly(t, error, cancelPromise2),\n      ]);\n    }, label + \": reader cancel() should return a distinct rejected promise each time\");\n  };\n\n  self.templatedRSEmptyReader = (label, factory) => {\n    test(() => {}, \"Running templatedRSEmptyReader with \" + label);\n\n    test(() => {\n      const reader = factory().reader;\n\n      assert_true(\"closed\" in reader, \"has a closed property\");\n      assert_equals(\n        typeof reader.closed.then,\n        \"function\",\n        \"closed property is thenable\"\n      );\n\n      assert_equals(typeof reader.cancel, \"function\", \"has a cancel method\");\n      assert_equals(typeof reader.read, \"function\", \"has a read method\");\n      assert_equals(\n        typeof reader.releaseLock,\n        \"function\",\n        \"has a releaseLock method\"\n      );\n    }, label + \": instances have the correct methods and properties\");\n\n    test(() => {\n      const { stream } = factory();\n\n      assert_true(stream.locked, \"locked getter should return true\");\n    }, label + \": locked should be true\");\n\n    promise_test((t) => {\n      const { read } = factory();\n\n      read().then(\n        t.unreached_func(\"read() should not fulfill\"),\n        t.unreached_func(\"read() should not reject\")\n      );\n\n      return delay(500);\n    }, label + \": read() should never settle\");\n\n    promise_test((t) => {\n      const { read } = factory();\n\n      read().then(\n        t.unreached_func(\"read() should not fulfill\"),\n        t.unreached_func(\"read() should not reject\")\n      );\n\n      read().then(\n        t.unreached_func(\"read() should not fulfill\"),\n        t.unreached_func(\"read() should not reject\")\n      );\n\n      return delay(500);\n    }, label + \": two read()s should both never settle\");\n\n    test(() => {\n      const { read } = factory();\n      assert_not_equals(\n        read(),\n        read(),\n        \"the promises returned should be distinct\"\n      );\n    }, label + \": read() should return distinct promises each time\");\n\n    test(() => {\n      const { stream } = factory();\n      assert_throws_js(\n        TypeError,\n        () => stream.getReader(),\n        \"stream.getReader() should throw a TypeError\"\n      );\n    }, label + \": getReader() again on the stream should fail\");\n\n    promise_test(async (t) => {\n      const { stream, reader, read } = factory();\n\n      const read1 = read();\n      const read2 = read();\n      const closed = reader.closed;\n\n      reader.releaseLock();\n\n      assert_false(stream.locked, \"the stream should be unlocked\");\n\n      await Promise.all([\n        promise_rejects_js(t, TypeError, read1, \"first read should reject\"),\n        promise_rejects_js(t, TypeError, read2, \"second read should reject\"),\n        promise_rejects_js(t, TypeError, closed, \"closed should reject\"),\n      ]);\n    }, label + \": releasing the lock should reject all pending read requests\");\n\n    promise_test((t) => {\n      const { reader, read } = factory();\n      reader.releaseLock();\n\n      return Promise.all([\n        promise_rejects_js(t, TypeError, read()),\n        promise_rejects_js(t, TypeError, read()),\n      ]);\n    }, label + \": releasing the lock should cause further read() calls to reject with a TypeError\");\n\n    promise_test((t) => {\n      const { reader } = factory();\n\n      const closedBefore = reader.closed;\n      reader.releaseLock();\n      const closedAfter = reader.closed;\n\n      assert_equals(\n        closedBefore,\n        closedAfter,\n        \"the closed promise should not change identity\"\n      );\n\n      return promise_rejects_js(t, TypeError, closedBefore);\n    }, label + \": releasing the lock should cause closed calls to reject with a TypeError\");\n\n    test(() => {\n      const { stream, reader } = factory();\n\n      reader.releaseLock();\n      assert_false(stream.locked, \"locked getter should return false\");\n    }, label + \": releasing the lock should cause locked to become false\");\n\n    promise_test(() => {\n      const { reader, read } = factory();\n      reader.cancel();\n\n      return read().then((r) => {\n        assert_object_equals(\n          r,\n          { value: undefined, done: true },\n          \"read()ing from the reader should give a done result\"\n        );\n      });\n    }, label + \": canceling via the reader should cause the reader to act closed\");\n\n    promise_test((t) => {\n      const { stream } = factory();\n      return promise_rejects_js(t, TypeError, stream.cancel());\n    }, label + \": canceling via the stream should fail\");\n  };\n\n  self.templatedRSClosedReader = (label, factory) => {\n    test(() => {}, \"Running templatedRSClosedReader with \" + label);\n\n    promise_test(() => {\n      const reader = factory().reader;\n\n      return reader.read().then((v) => {\n        assert_object_equals(\n          v,\n          { value: undefined, done: true },\n          \"read() should fulfill correctly\"\n        );\n      });\n    }, label + \": read() should fulfill with { value: undefined, done: true }\");\n\n    promise_test(() => {\n      const reader = factory().reader;\n\n      return Promise.all([\n        reader.read().then((v) => {\n          assert_object_equals(\n            v,\n            { value: undefined, done: true },\n            \"read() should fulfill correctly\"\n          );\n        }),\n        reader.read().then((v) => {\n          assert_object_equals(\n            v,\n            { value: undefined, done: true },\n            \"read() should fulfill correctly\"\n          );\n        }),\n      ]);\n    }, label + \": read() multiple times should fulfill with { value: undefined, done: true }\");\n\n    promise_test(() => {\n      const reader = factory().reader;\n\n      return reader\n        .read()\n        .then(() => reader.read())\n        .then((v) => {\n          assert_object_equals(\n            v,\n            { value: undefined, done: true },\n            \"read() should fulfill correctly\"\n          );\n        });\n    }, label + \": read() should work when used within another read() fulfill callback\");\n\n    promise_test(() => {\n      const reader = factory().reader;\n\n      return reader.closed.then((v) =>\n        assert_equals(\n          v,\n          undefined,\n          \"reader closed should fulfill with undefined\"\n        )\n      );\n    }, label + \": closed should fulfill with undefined\");\n\n    promise_test((t) => {\n      const reader = factory().reader;\n\n      const closedBefore = reader.closed;\n      reader.releaseLock();\n      const closedAfter = reader.closed;\n\n      assert_not_equals(\n        closedBefore,\n        closedAfter,\n        \"the closed promise should change identity\"\n      );\n\n      return Promise.all([\n        closedBefore.then((v) =>\n          assert_equals(\n            v,\n            undefined,\n            \"reader.closed acquired before release should fulfill\"\n          )\n        ),\n        promise_rejects_js(t, TypeError, closedAfter),\n      ]);\n    }, label + \": releasing the lock should cause closed to reject and change identity\");\n\n    promise_test(() => {\n      const reader = factory().reader;\n      const cancelPromise1 = reader.cancel();\n      const cancelPromise2 = reader.cancel();\n      const closedReaderPromise = reader.closed;\n\n      assert_not_equals(\n        cancelPromise1,\n        cancelPromise2,\n        \"cancel() calls should return distinct promises\"\n      );\n      assert_not_equals(\n        cancelPromise1,\n        closedReaderPromise,\n        \"cancel() promise 1 should be distinct from reader.closed\"\n      );\n      assert_not_equals(\n        cancelPromise2,\n        closedReaderPromise,\n        \"cancel() promise 2 should be distinct from reader.closed\"\n      );\n\n      return Promise.all([\n        cancelPromise1.then((v) =>\n          assert_equals(\n            v,\n            undefined,\n            \"first cancel() should fulfill with undefined\"\n          )\n        ),\n        cancelPromise2.then((v) =>\n          assert_equals(\n            v,\n            undefined,\n            \"second cancel() should fulfill with undefined\"\n          )\n        ),\n      ]);\n    }, label + \": cancel() should return a distinct fulfilled promise each time\");\n  };\n\n  self.templatedRSErroredReader = (label, factory, error) => {\n    test(() => {}, \"Running templatedRSErroredReader with \" + label);\n\n    promise_test((t) => {\n      const reader = factory().reader;\n      return promise_rejects_exactly(t, error, reader.closed);\n    }, label + \": closed should reject with the error\");\n\n    promise_test((t) => {\n      const reader = factory().reader;\n      const closedBefore = reader.closed;\n\n      return promise_rejects_exactly(t, error, closedBefore).then(() => {\n        reader.releaseLock();\n\n        const closedAfter = reader.closed;\n        assert_not_equals(\n          closedBefore,\n          closedAfter,\n          \"the closed promise should change identity\"\n        );\n\n        return promise_rejects_js(t, TypeError, closedAfter);\n      });\n    }, label + \": releasing the lock should cause closed to reject and change identity\");\n\n    promise_test((t) => {\n      const reader = factory().reader;\n      return promise_rejects_exactly(t, error, reader.read());\n    }, label + \": read() should reject with the error\");\n  };\n\n  self.templatedRSTwoChunksOpenReader = (label, factory, chunks) => {\n    test(() => {}, \"Running templatedRSTwoChunksOpenReader with \" + label);\n\n    promise_test(() => {\n      const reader = factory().reader;\n\n      return Promise.all([\n        reader.read().then((r) => {\n          assert_object_equals(\n            r,\n            { value: chunks[0], done: false },\n            \"first result should be correct\"\n          );\n        }),\n        reader.read().then((r) => {\n          assert_object_equals(\n            r,\n            { value: chunks[1], done: false },\n            \"second result should be correct\"\n          );\n        }),\n      ]);\n    }, label + \": calling read() twice without waiting will eventually give both chunks (sequential)\");\n\n    promise_test(() => {\n      const reader = factory().reader;\n\n      return reader.read().then((r) => {\n        assert_object_equals(\n          r,\n          { value: chunks[0], done: false },\n          \"first result should be correct\"\n        );\n\n        return reader.read().then((r2) => {\n          assert_object_equals(\n            r2,\n            { value: chunks[1], done: false },\n            \"second result should be correct\"\n          );\n        });\n      });\n    }, label + \": calling read() twice without waiting will eventually give both chunks (nested)\");\n\n    test(() => {\n      const reader = factory().reader;\n      assert_not_equals(\n        reader.read(),\n        reader.read(),\n        \"the promises returned should be distinct\"\n      );\n    }, label + \": read() should return distinct promises each time\");\n\n    promise_test(() => {\n      const reader = factory().reader;\n\n      const promise1 = reader.closed.then((v) => {\n        assert_equals(\n          v,\n          undefined,\n          \"reader closed should fulfill with undefined\"\n        );\n      });\n\n      const promise2 = reader.read().then((r) => {\n        assert_object_equals(\n          r,\n          { value: chunks[0], done: false },\n          \"promise returned before cancellation should fulfill with a chunk\"\n        );\n      });\n\n      reader.cancel();\n\n      const promise3 = reader.read().then((r) => {\n        assert_object_equals(\n          r,\n          { value: undefined, done: true },\n          \"promise returned after cancellation should fulfill with an end-of-stream signal\"\n        );\n      });\n\n      return Promise.all([promise1, promise2, promise3]);\n    }, label + \": cancel() after a read() should still give that single read result\");\n  };\n\n  self.templatedRSTwoChunksClosedReader = function (label, factory, chunks) {\n    test(() => {}, \"Running templatedRSTwoChunksClosedReader with \" + label);\n\n    promise_test(() => {\n      const reader = factory().reader;\n\n      return Promise.all([\n        reader.read().then((r) => {\n          assert_object_equals(\n            r,\n            { value: chunks[0], done: false },\n            \"first result should be correct\"\n          );\n        }),\n        reader.read().then((r) => {\n          assert_object_equals(\n            r,\n            { value: chunks[1], done: false },\n            \"second result should be correct\"\n          );\n        }),\n        reader.read().then((r) => {\n          assert_object_equals(\n            r,\n            { value: undefined, done: true },\n            \"third result should be correct\"\n          );\n        }),\n      ]);\n    }, label + \": third read(), without waiting, should give { value: undefined, done: true } (sequential)\");\n\n    promise_test(() => {\n      const reader = factory().reader;\n\n      return reader.read().then((r) => {\n        assert_object_equals(\n          r,\n          { value: chunks[0], done: false },\n          \"first result should be correct\"\n        );\n\n        return reader.read().then((r2) => {\n          assert_object_equals(\n            r2,\n            { value: chunks[1], done: false },\n            \"second result should be correct\"\n          );\n\n          return reader.read().then((r3) => {\n            assert_object_equals(\n              r3,\n              { value: undefined, done: true },\n              \"third result should be correct\"\n            );\n          });\n        });\n      });\n    }, label + \": third read(), without waiting, should give { value: undefined, done: true } (nested)\");\n\n    promise_test(() => {\n      const streamAndReader = factory();\n      const stream = streamAndReader.stream;\n      const reader = streamAndReader.reader;\n\n      assert_true(stream.locked, \"stream should start locked\");\n\n      const promise = reader.closed.then((v) => {\n        assert_equals(\n          v,\n          undefined,\n          \"reader closed should fulfill with undefined\"\n        );\n        assert_true(stream.locked, \"stream should remain locked\");\n      });\n\n      reader.read();\n      reader.read();\n\n      return promise;\n    }, label + \": draining the stream via read() should cause the reader closed promise to fulfill, but locked stays true\");\n\n    promise_test(() => {\n      const streamAndReader = factory();\n      const stream = streamAndReader.stream;\n      const reader = streamAndReader.reader;\n\n      const promise = reader.closed.then(() => {\n        assert_true(stream.locked, \"the stream should start locked\");\n        reader.releaseLock(); // Releasing the lock after reader closed should not throw.\n        assert_false(stream.locked, \"the stream should end unlocked\");\n      });\n\n      reader.read();\n      reader.read();\n\n      return promise;\n    }, label + \": releasing the lock after the stream is closed should cause locked to become false\");\n\n    promise_test((t) => {\n      const reader = factory().reader;\n\n      reader.releaseLock();\n\n      return Promise.all([\n        promise_rejects_js(t, TypeError, reader.read()),\n        promise_rejects_js(t, TypeError, reader.read()),\n        promise_rejects_js(t, TypeError, reader.read()),\n      ]);\n    }, label + \": releasing the lock should cause further read() calls to reject with a TypeError\");\n\n    promise_test(() => {\n      const streamAndReader = factory();\n      const stream = streamAndReader.stream;\n      const reader = streamAndReader.reader;\n\n      const readerClosed = reader.closed;\n\n      assert_equals(\n        reader.closed,\n        readerClosed,\n        \"accessing reader.closed twice in succession gives the same value\"\n      );\n\n      const promise = reader.read().then(() => {\n        assert_equals(\n          reader.closed,\n          readerClosed,\n          \"reader.closed is the same after read() fulfills\"\n        );\n\n        reader.releaseLock();\n\n        assert_equals(\n          reader.closed,\n          readerClosed,\n          \"reader.closed is the same after releasing the lock\"\n        );\n\n        const newReader = stream.getReader();\n        return newReader.read();\n      });\n\n      assert_equals(\n        reader.closed,\n        readerClosed,\n        \"reader.closed is the same after calling read()\"\n      );\n\n      return promise;\n    }, label + \": reader's closed property always returns the same promise\");\n  };\n\n  self.templatedRSTeeCancel = (label, factory) => {\n    test(() => {}, `Running templatedRSTeeCancel with ${label}`);\n\n    promise_test(async () => {\n      const reason1 = new Error(\"We're wanted men.\");\n      const reason2 = new Error(\"I have the death sentence on twelve systems.\");\n\n      let resolve;\n      const promise = new Promise((r) => (resolve = r));\n      const rs = factory({\n        cancel(reason) {\n          assert_array_equals(\n            reason,\n            [reason1, reason2],\n            \"the cancel reason should be an array containing those from the branches\"\n          );\n          resolve();\n        },\n      });\n\n      const [branch1, branch2] = rs.tee();\n      await Promise.all([\n        branch1.cancel(reason1),\n        branch2.cancel(reason2),\n        promise,\n      ]);\n    }, `${label}: canceling both branches should aggregate the cancel reasons into an array`);\n\n    promise_test(async () => {\n      const reason1 = new Error(\"This little one's not worth the effort.\");\n      const reason2 = new Error(\"Come, let me get you something.\");\n\n      let resolve;\n      const promise = new Promise((r) => (resolve = r));\n      const rs = factory({\n        cancel(reason) {\n          assert_array_equals(\n            reason,\n            [reason1, reason2],\n            \"the cancel reason should be an array containing those from the branches\"\n          );\n          resolve();\n        },\n      });\n\n      const [branch1, branch2] = rs.tee();\n      await Promise.all([\n        branch2.cancel(reason2),\n        branch1.cancel(reason1),\n        promise,\n      ]);\n    }, `${label}: canceling both branches in reverse order should aggregate the cancel reasons into an array`);\n\n    promise_test(async (t) => {\n      const theError = { name: \"I'll be careful.\" };\n      const rs = factory({\n        cancel() {\n          throw theError;\n        },\n      });\n\n      const [branch1, branch2] = rs.tee();\n      await Promise.all([\n        promise_rejects_exactly(t, theError, branch1.cancel()),\n        promise_rejects_exactly(t, theError, branch2.cancel()),\n      ]);\n    }, `${label}: failing to cancel the original stream should cause cancel() to reject on branches`);\n\n    promise_test(async (t) => {\n      const theError = { name: \"You just watch yourself!\" };\n      let controller;\n      const stream = factory({\n        start(c) {\n          controller = c;\n        },\n      });\n\n      const [branch1, branch2] = stream.tee();\n      controller.error(theError);\n\n      await Promise.all([\n        promise_rejects_exactly(t, theError, branch1.cancel()),\n        promise_rejects_exactly(t, theError, branch2.cancel()),\n      ]);\n    }, `${label}: erroring a teed stream should properly handle canceled branches`);\n  };\n\n  self.templatedRSThrowAfterCloseOrError = (label, factory) => {\n    test(() => {}, \"Running templatedRSThrowAfterCloseOrError with \" + label);\n\n    const theError = new Error(\"a unique string\");\n\n    promise_test(async (t) => {\n      let controller;\n      const stream = factory({\n        start: t.step_func((c) => {\n          controller = c;\n        }),\n      });\n\n      controller.close();\n\n      assert_throws_js(TypeError, () =>\n        controller.enqueue(new Uint8Array([1]))\n      );\n    }, `${label}: enqueue() throws after close()`);\n\n    promise_test(async (t) => {\n      let controller;\n      const stream = factory({\n        start: t.step_func((c) => {\n          controller = c;\n        }),\n      });\n\n      controller.enqueue(new Uint8Array([1]));\n      controller.close();\n\n      assert_throws_js(TypeError, () =>\n        controller.enqueue(new Uint8Array([2]))\n      );\n    }, `${label}: enqueue() throws after enqueue() and close()`);\n\n    promise_test(async (t) => {\n      let controller;\n      const stream = factory({\n        start: t.step_func((c) => {\n          controller = c;\n        }),\n      });\n\n      controller.error(theError);\n\n      assert_throws_js(TypeError, () =>\n        controller.enqueue(new Uint8Array([1]))\n      );\n    }, `${label}: enqueue() throws after error()`);\n\n    promise_test(async (t) => {\n      let controller;\n      const stream = factory({\n        start: t.step_func((c) => {\n          controller = c;\n        }),\n      });\n\n      controller.error(theError);\n\n      assert_throws_js(TypeError, () => controller.close());\n    }, `${label}: close() throws after error()`);\n  };\n}\n"
  },
  {
    "path": "tests/wpt/streams/resources/rs-utils.js",
    "content": "\"use strict\";\nexport default function ({ step_timeout }) {\n  (function () {\n    // Fake setInterval-like functionality in environments that don't have it\n    class IntervalHandle {\n      constructor(callback, delayMs) {\n        this.callback = callback;\n        this.delayMs = delayMs;\n        this.cancelled = false;\n        Promise.resolve().then(() => this.check());\n      }\n\n      async check() {\n        while (true) {\n          await new Promise((resolve) => step_timeout(resolve, this.delayMs));\n          if (this.cancelled) {\n            return;\n          }\n          this.callback();\n        }\n      }\n\n      cancel() {\n        this.cancelled = true;\n      }\n    }\n\n    let localSetInterval, localClearInterval;\n    if (\n      typeof globalThis.setInterval !== \"undefined\" &&\n      typeof globalThis.clearInterval !== \"undefined\"\n    ) {\n      localSetInterval = globalThis.setInterval;\n      localClearInterval = globalThis.clearInterval;\n    } else {\n      localSetInterval = function setInterval(callback, delayMs) {\n        return new IntervalHandle(callback, delayMs);\n      };\n      localClearInterval = function clearInterval(handle) {\n        handle.cancel();\n      };\n    }\n\n    class RandomPushSource {\n      constructor(toPush) {\n        this.pushed = 0;\n        this.toPush = toPush;\n        this.started = false;\n        this.paused = false;\n        this.closed = false;\n\n        this._intervalHandle = null;\n      }\n\n      readStart() {\n        if (this.closed) {\n          return;\n        }\n\n        if (!this.started) {\n          this._intervalHandle = localSetInterval(writeChunk, 2);\n          this.started = true;\n        }\n\n        if (this.paused) {\n          this._intervalHandle = localSetInterval(writeChunk, 2);\n          this.paused = false;\n        }\n\n        const source = this;\n        function writeChunk() {\n          if (source.paused) {\n            return;\n          }\n\n          source.pushed++;\n\n          if (source.toPush > 0 && source.pushed > source.toPush) {\n            if (source._intervalHandle) {\n              localClearInterval(source._intervalHandle);\n              source._intervalHandle = undefined;\n            }\n            source.closed = true;\n            source.onend();\n          } else {\n            source.ondata(randomChunk(128));\n          }\n        }\n      }\n\n      readStop() {\n        if (this.paused) {\n          return;\n        }\n\n        if (this.started) {\n          this.paused = true;\n          localClearInterval(this._intervalHandle);\n          this._intervalHandle = undefined;\n        } else {\n          throw new Error(\"Can't pause reading an unstarted source.\");\n        }\n      }\n    }\n\n    function randomChunk(size) {\n      let chunk = \"\";\n\n      for (let i = 0; i < size; ++i) {\n        // Add a random character from the basic printable ASCII set.\n        chunk += String.fromCharCode(Math.round(Math.random() * 84) + 32);\n      }\n\n      return chunk;\n    }\n\n    function readableStreamToArray(readable, reader) {\n      if (reader === undefined) {\n        reader = readable.getReader();\n      }\n\n      const chunks = [];\n\n      return pump();\n\n      function pump() {\n        return reader.read().then((result) => {\n          if (result.done) {\n            return chunks;\n          }\n\n          chunks.push(result.value);\n          return pump();\n        });\n      }\n    }\n\n    class SequentialPullSource {\n      constructor(limit, options) {\n        const async = options && options.async;\n\n        this.current = 0;\n        this.limit = limit;\n        this.opened = false;\n        this.closed = false;\n\n        this._exec = (f) => f();\n        if (async) {\n          this._exec = (f) => step_timeout(f, 0);\n        }\n      }\n\n      open(cb) {\n        this._exec(() => {\n          this.opened = true;\n          cb();\n        });\n      }\n\n      read(cb) {\n        this._exec(() => {\n          if (++this.current <= this.limit) {\n            cb(null, false, this.current);\n          } else {\n            cb(null, true, null);\n          }\n        });\n      }\n\n      close(cb) {\n        this._exec(() => {\n          this.closed = true;\n          cb();\n        });\n      }\n    }\n\n    function sequentialReadableStream(limit, options) {\n      const sequentialSource = new SequentialPullSource(limit, options);\n\n      const stream = new ReadableStream({\n        start() {\n          return new Promise((resolve, reject) => {\n            sequentialSource.open((err) => {\n              if (err) {\n                reject(err);\n              }\n              resolve();\n            });\n          });\n        },\n\n        pull(c) {\n          return new Promise((resolve, reject) => {\n            sequentialSource.read((err, done, chunk) => {\n              if (err) {\n                reject(err);\n              } else if (done) {\n                sequentialSource.close((err2) => {\n                  if (err2) {\n                    reject(err2);\n                  }\n                  c.close();\n                  resolve();\n                });\n              } else {\n                c.enqueue(chunk);\n                resolve();\n              }\n            });\n          });\n        },\n      });\n\n      stream.source = sequentialSource;\n\n      return stream;\n    }\n\n    function transferArrayBufferView(view) {\n      return structuredClone(view, { transfer: [view.buffer] });\n    }\n\n    self.RandomPushSource = RandomPushSource;\n    self.readableStreamToArray = readableStreamToArray;\n    self.sequentialReadableStream = sequentialReadableStream;\n    self.transferArrayBufferView = transferArrayBufferView;\n  })();\n}\n"
  },
  {
    "path": "tests/wpt/streams/resources/test-utils.js",
    "content": "\"use strict\";\nexport default function ({ step_timeout, assert_equals, assert_array_equals }) {\n  self.delay = (ms) => new Promise((resolve) => step_timeout(resolve, ms));\n\n  // For tests which verify that the implementation doesn't do something it shouldn't, it's better not to use a\n  // timeout. Instead, assume that any reasonable implementation is going to finish work after 2 times around the event\n  // loop, and use flushAsyncEvents().then(() => assert_array_equals(...));\n  // Some tests include promise resolutions which may mean the test code takes a couple of event loop visits itself. So go\n  // around an extra 2 times to avoid complicating those tests.\n  self.flushAsyncEvents = () =>\n    delay(0)\n      .then(() => delay(0))\n      .then(() => delay(0))\n      .then(() => delay(0));\n\n  self.assert_typed_array_equals = (actual, expected, message) => {\n    const prefix = message === undefined ? \"\" : `${message} `;\n    assert_equals(typeof actual, \"object\", `${prefix}type is object`);\n    assert_equals(\n      actual.constructor,\n      expected.constructor,\n      `${prefix}constructor`\n    );\n    assert_equals(\n      actual.byteOffset,\n      expected.byteOffset,\n      `${prefix}byteOffset`\n    );\n    assert_equals(\n      actual.byteLength,\n      expected.byteLength,\n      `${prefix}byteLength`\n    );\n    assert_equals(\n      actual.buffer.byteLength,\n      expected.buffer.byteLength,\n      `${prefix}buffer.byteLength`\n    );\n    assert_array_equals([...actual], [...expected], `${prefix}contents`);\n    assert_array_equals(\n      [...new Uint8Array(actual.buffer)],\n      [...new Uint8Array(expected.buffer)],\n      `${prefix}buffer contents`\n    );\n  };\n\n  self.makePromiseAndResolveFunc = () => {\n    let resolve;\n    const promise = new Promise((r) => {\n      resolve = r;\n    });\n    return [promise, resolve];\n  };\n}\n"
  },
  {
    "path": "tests/wpt/streams.harness.js",
    "content": "import resourcesIdlharness from \"./resources/idlharness.js\";\nimport resourcesTestharness from \"./resources/testharness.js\";\n\nimport commonGc from \"./common/gc.js\";\nimport commonSubsetTests from \"./common/subset-tests.js\";\n\nimport encodings from \"./encoding/resources/encodings.js\";\n\nimport streamsRecordingStreams from \"./streams/resources/recording-streams.js\";\nimport streamsRsTestTemplates from \"./streams/resources/rs-test-templates.js\";\nimport streamsRsUtils from \"./streams/resources/rs-utils.js\";\nimport streamsTestUtils from \"./streams/resources/test-utils.js\";\n\nexport const runTestDynamic = (testSource, done) => {\n  const context = {\n    createBuffer: (type, length) => new self[type](length),\n    encodings_table: encodings,\n    setTimeout: setTimeout,\n    DOMException: DOMException,\n    location: {},\n  };\n\n  resourcesIdlharness(context);\n  resourcesTestharness(context);\n\n  commonGc(context);\n  commonSubsetTests(context);\n\n  streamsRecordingStreams(context);\n  streamsRsTestTemplates(context);\n  streamsRsUtils(context);\n  streamsTestUtils(context);\n\n  context.setup({\n    explicit_done: true,\n    debug: process.env.DEBUG !== undefined,\n  });\n\n  globalThis.gc = globalThis.__gc;\n\n  context.add_completion_callback((tests, status, assertions) => {\n    if (\n      tests.filter(\n        ({ name, status }) => !(name === \"Loading data...\" && status === 0)\n      ).length === 0\n    ) {\n      done(new Error(\"No tests were executed!\"));\n    }\n    const failure = tests.find((test) => test.status !== 0);\n    if (failure) {\n      const message = `[${failure.name}] ${failure.message || String(failure)}`;\n      done(message);\n      return;\n    }\n    done();\n  });\n\n  wrapTestSuite(testSource)(context);\n\n  context.done();\n};\n\nfunction wrapTestSuite(sourceCode) {\n  return new Function(\n    \"context\",\n    `\n      with (context) {\n        ${sourceCode}\n      }\n    `\n  );\n}\n"
  },
  {
    "path": "tests/wpt/streams.piping.test.ts",
    "content": "import { runTestDynamic } from \"./streams.harness.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst SKIP_FILES = [\n  \"general-addition.any.js\", // waiting on resolution of https://github.com/whatwg/streams/issues/1243.\n  \"throwing-options.any.js\", // requires TransformStream\n  \"transform-streams.any.js\", // requires TransformStream\n];\n\nconst __filename = fileURLToPath(import.meta.url);\nconst basename = path.basename(__filename);\nconst subDir = basename\n  .replace(/\\.test\\.[jt]s$/, \"\")\n  .split(\".\")\n  .join(path.sep);\n\nconst CWD = process.cwd();\nconst baseDir = path.join(CWD, \"wpt\");\nconst targetDir = path.join(baseDir, subDir);\n\nconst testFiles = fs\n  .readdirSync(targetDir)\n  .filter((file) => file.endsWith(\".any.js\"));\n\ndescribe(subDir, () => {\n  for (const file of testFiles) {\n    if (!SKIP_FILES.includes(file)) {\n      it(`should pass ${file} tests`, (done) => {\n        const filePath = path.join(targetDir, file);\n        const sourceCode = fs.readFileSync(filePath, \"utf8\");\n        runTestDynamic(sourceCode, done);\n      });\n    }\n  }\n});\n"
  },
  {
    "path": "tests/wpt/streams.readable-byte-streams.test.ts",
    "content": "import { runTestDynamic } from \"./streams.harness.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst SKIP_FILES = [\n  \"non-transferable-buffers.any.js\", // SKIP: WebAssembly support is pending\n];\n\nconst __filename = fileURLToPath(import.meta.url);\nconst basename = path.basename(__filename);\nconst subDir = basename\n  .replace(/\\.test\\.[jt]s$/, \"\")\n  .split(\".\")\n  .join(path.sep);\n\nconst CWD = process.cwd();\nconst baseDir = path.join(CWD, \"wpt\");\nconst targetDir = path.join(baseDir, subDir);\n\nconst testFiles = fs\n  .readdirSync(targetDir)\n  .filter((file) => file.endsWith(\".any.js\"));\n\ndescribe(subDir, () => {\n  for (const file of testFiles) {\n    if (!SKIP_FILES.includes(file)) {\n      it(`should pass ${file} tests`, (done) => {\n        const filePath = path.join(targetDir, file);\n        const sourceCode = fs.readFileSync(filePath, \"utf8\");\n        runTestDynamic(sourceCode, done);\n      });\n    }\n  }\n});\n"
  },
  {
    "path": "tests/wpt/streams.readable-streams.test.ts",
    "content": "import { runTestDynamic } from \"./streams.harness.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst SKIP_FILES = [\n  \"owning-type-video-frame.any.js\", // SKIP: VideoFrame support is pending\n];\n\nconst __filename = fileURLToPath(import.meta.url);\nconst basename = path.basename(__filename);\nconst subDir = basename\n  .replace(/\\.test\\.[jt]s$/, \"\")\n  .split(\".\")\n  .join(path.sep);\n\nconst CWD = process.cwd();\nconst baseDir = path.join(CWD, \"wpt\");\nconst targetDir = path.join(baseDir, subDir);\n\nconst testFiles = fs\n  .readdirSync(targetDir)\n  .filter((file) => file.endsWith(\".any.js\"));\n\ndescribe(subDir, () => {\n  for (const file of testFiles) {\n    if (!SKIP_FILES.includes(file)) {\n      it(`should pass ${file} tests`, (done) => {\n        const filePath = path.join(targetDir, file);\n        const sourceCode = fs.readFileSync(filePath, \"utf8\");\n        runTestDynamic(sourceCode, done);\n      });\n    }\n  }\n});\n"
  },
  {
    "path": "tests/wpt/streams.writable-streams.test.ts",
    "content": "import { runTestDynamic } from \"./streams.harness.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst SKIP_FILES = [];\n\nconst __filename = fileURLToPath(import.meta.url);\nconst basename = path.basename(__filename);\nconst subDir = basename\n  .replace(/\\.test\\.[jt]s$/, \"\")\n  .split(\".\")\n  .join(path.sep);\n\nconst CWD = process.cwd();\nconst baseDir = path.join(CWD, \"wpt\");\nconst targetDir = path.join(baseDir, subDir);\n\nconst testFiles = fs\n  .readdirSync(targetDir)\n  .filter((file) => file.endsWith(\".any.js\"));\n\ndescribe(subDir, () => {\n  for (const file of testFiles) {\n    if (!SKIP_FILES.includes(file)) {\n      it(`should pass ${file} tests`, (done) => {\n        const filePath = path.join(targetDir, file);\n        const sourceCode = fs.readFileSync(filePath, \"utf8\");\n        runTestDynamic(sourceCode, done);\n      });\n    }\n  }\n});\n"
  },
  {
    "path": "tests/wpt/url/resources/IdnaTestV2-removed.json",
    "content": "[\n  \"This is generated with the help from ../tools/IdnaTestV2-compare.py.\",\n  \"These tests are from an older IdnaTestV2 and thus the comment line may no longer be accurate.\",\n  {\n    \"comment\": \"P1; V6; V3 (ignored)\",\n    \"input\": \"-\\udb40\\ude56\\ua867\\uff0e\\udb40\\ude82\\ud8dc\\udd83\\ud83c\\udd09\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"P1; V5; V6\",\n    \"input\": \"\\ud83c\\udd04\\uff0e\\u1cdc\\u2488\\u00df\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"P1; V5; V6\",\n    \"input\": \"\\ud83c\\udd04\\uff0e\\u1cdc\\u2488SS\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"P1; V5; V6\",\n    \"input\": \"\\ud83c\\udd04\\uff0e\\u1cdc\\u2488ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"P1; V5; V6\",\n    \"input\": \"\\ud83c\\udd04\\uff0e\\u1cdc\\u2488Ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; P1; V6\",\n    \"input\": \"\\u0756\\u3002\\u3164\\u200d\\u03c2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; P1; V6\",\n    \"input\": \"\\u0756\\u3002\\u1160\\u200d\\u03c2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; P1; V6\",\n    \"input\": \"\\u0756\\u3002\\u1160\\u200d\\u03a3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; P1; V6\",\n    \"input\": \"\\u0756\\u3002\\u1160\\u200d\\u03c3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; P1; V6\",\n    \"input\": \"\\u0756\\u3002\\u3164\\u200d\\u03a3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; P1; V6\",\n    \"input\": \"\\u0756\\u3002\\u3164\\u200d\\u03c3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"P1; V6\",\n    \"input\": \"\\ud83c\\udd07\\u4f10\\ufe12.\\ud831\\ude5a\\ua8c4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"P1; V5; V6\",\n    \"input\": \"\\ud802\\ude3f.\\ud83c\\udd06\\u2014\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; P1; V5; V6\",\n    \"input\": \"\\u1c32\\ud83c\\udd08\\u2f9b\\u05a6\\uff0e\\u200d\\uda7e\\udd64\\u07fd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; P1; V5; V6\",\n    \"input\": \"\\ud83e\\udc9f\\ud83c\\udd08\\u200d\\ua84e\\uff61\\u0f84\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"P1; V6\",\n    \"input\": \"\\udaa5\\udeaa\\uff61\\ud83c\\udd02\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; P1; V6\",\n    \"input\": \"\\u186f\\u2689\\u59f6\\ud83c\\udd09\\uff0e\\u06f7\\u200d\\ud83c\\udfaa\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; P1; V5; V6\",\n    \"input\": \"\\ua67d\\u200c\\ud87e\\uddf5\\ud83c\\udd06\\uff61\\u200c\\ud804\\udc42\\u1b01\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; P1; V5; V6\",\n    \"input\": \"\\ua67d\\u200c\\u9723\\ud83c\\udd06\\uff61\\u200c\\ud804\\udc42\\u1b01\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; P1; V5; V6; V3 (ignored)\",\n    \"input\": \"-\\u1897\\u200c\\ud83c\\udd04.\\ud805\\udf22\",\n    \"output\": null\n  }\n]\n"
  },
  {
    "path": "tests/wpt/url/resources/IdnaTestV2.json",
    "content": "[\n  \"THIS IS A GENERATED FILE. PLEASE DO NOT MODIFY DIRECTLY. See ../tools/IdnaTestV2-parser.py instead.\",\n  \"--exclude-ipv4-like: True; --exclude-std3: True; --exclude-bidi: True\",\n  {\n    \"input\": \"fass.de\",\n    \"output\": \"fass.de\"\n  },\n  {\n    \"input\": \"fa\\u00df.de\",\n    \"output\": \"xn--fa-hia.de\"\n  },\n  {\n    \"input\": \"Fa\\u00df.de\",\n    \"output\": \"xn--fa-hia.de\"\n  },\n  {\n    \"input\": \"xn--fa-hia.de\",\n    \"output\": \"xn--fa-hia.de\"\n  },\n  {\n    \"input\": \"\\u00e0.\\u05d0\\u0308\",\n    \"output\": \"xn--0ca.xn--ssa73l\"\n  },\n  {\n    \"input\": \"a\\u0300.\\u05d0\\u0308\",\n    \"output\": \"xn--0ca.xn--ssa73l\"\n  },\n  {\n    \"input\": \"A\\u0300.\\u05d0\\u0308\",\n    \"output\": \"xn--0ca.xn--ssa73l\"\n  },\n  {\n    \"input\": \"\\u00c0.\\u05d0\\u0308\",\n    \"output\": \"xn--0ca.xn--ssa73l\"\n  },\n  {\n    \"input\": \"xn--0ca.xn--ssa73l\",\n    \"output\": \"xn--0ca.xn--ssa73l\"\n  },\n  {\n    \"input\": \"\\u00e0\\u0308.\\u05d0\",\n    \"output\": \"xn--0ca81i.xn--4db\"\n  },\n  {\n    \"input\": \"a\\u0300\\u0308.\\u05d0\",\n    \"output\": \"xn--0ca81i.xn--4db\"\n  },\n  {\n    \"input\": \"A\\u0300\\u0308.\\u05d0\",\n    \"output\": \"xn--0ca81i.xn--4db\"\n  },\n  {\n    \"input\": \"\\u00c0\\u0308.\\u05d0\",\n    \"output\": \"xn--0ca81i.xn--4db\"\n  },\n  {\n    \"input\": \"xn--0ca81i.xn--4db\",\n    \"output\": \"xn--0ca81i.xn--4db\"\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"a\\u200cb\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"A\\u200cB\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"A\\u200cb\",\n    \"output\": null\n  },\n  {\n    \"input\": \"ab\",\n    \"output\": \"ab\"\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"xn--ab-j1t\",\n    \"output\": null\n  },\n  {\n    \"input\": \"a\\u094d\\u200cb\",\n    \"output\": \"xn--ab-fsf604u\"\n  },\n  {\n    \"input\": \"A\\u094d\\u200cB\",\n    \"output\": \"xn--ab-fsf604u\"\n  },\n  {\n    \"input\": \"A\\u094d\\u200cb\",\n    \"output\": \"xn--ab-fsf604u\"\n  },\n  {\n    \"input\": \"xn--ab-fsf\",\n    \"output\": \"xn--ab-fsf\"\n  },\n  {\n    \"input\": \"a\\u094db\",\n    \"output\": \"xn--ab-fsf\"\n  },\n  {\n    \"input\": \"A\\u094dB\",\n    \"output\": \"xn--ab-fsf\"\n  },\n  {\n    \"input\": \"A\\u094db\",\n    \"output\": \"xn--ab-fsf\"\n  },\n  {\n    \"input\": \"xn--ab-fsf604u\",\n    \"output\": \"xn--ab-fsf604u\"\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"a\\u200db\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"A\\u200dB\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"A\\u200db\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"xn--ab-m1t\",\n    \"output\": null\n  },\n  {\n    \"input\": \"a\\u094d\\u200db\",\n    \"output\": \"xn--ab-fsf014u\"\n  },\n  {\n    \"input\": \"A\\u094d\\u200dB\",\n    \"output\": \"xn--ab-fsf014u\"\n  },\n  {\n    \"input\": \"A\\u094d\\u200db\",\n    \"output\": \"xn--ab-fsf014u\"\n  },\n  {\n    \"input\": \"xn--ab-fsf014u\",\n    \"output\": \"xn--ab-fsf014u\"\n  },\n  {\n    \"input\": \"\\u00a1\",\n    \"output\": \"xn--7a\"\n  },\n  {\n    \"input\": \"xn--7a\",\n    \"output\": \"xn--7a\"\n  },\n  {\n    \"input\": \"\\u19da\",\n    \"output\": \"xn--pkf\"\n  },\n  {\n    \"input\": \"xn--pkf\",\n    \"output\": \"xn--pkf\"\n  },\n  {\n    \"comment\": \"A4_1 (ignored); A4_2 (ignored)\",\n    \"input\": \"\",\n    \"output\": \"\"\n  },\n  {\n    \"comment\": \"A4_1 (ignored); A4_2 (ignored)\",\n    \"input\": \"\\u3002\",\n    \"output\": \".\"\n  },\n  {\n    \"comment\": \"A4_1 (ignored); A4_2 (ignored)\",\n    \"input\": \".\",\n    \"output\": \".\"\n  },\n  {\n    \"input\": \"\\uab60\",\n    \"output\": \"xn--3y9a\"\n  },\n  {\n    \"input\": \"xn--3y9a\",\n    \"output\": \"xn--3y9a\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"1234567890\\u00e41234567890123456789012345678901234567890123456\",\n    \"output\": \"xn--12345678901234567890123456789012345678901234567890123456-fxe\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"1234567890a\\u03081234567890123456789012345678901234567890123456\",\n    \"output\": \"xn--12345678901234567890123456789012345678901234567890123456-fxe\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"1234567890A\\u03081234567890123456789012345678901234567890123456\",\n    \"output\": \"xn--12345678901234567890123456789012345678901234567890123456-fxe\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"1234567890\\u00c41234567890123456789012345678901234567890123456\",\n    \"output\": \"xn--12345678901234567890123456789012345678901234567890123456-fxe\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--12345678901234567890123456789012345678901234567890123456-fxe\",\n    \"output\": \"xn--12345678901234567890123456789012345678901234567890123456-fxe\"\n  },\n  {\n    \"input\": \"www.eXample.cOm\",\n    \"output\": \"www.example.com\"\n  },\n  {\n    \"input\": \"B\\u00fccher.de\",\n    \"output\": \"xn--bcher-kva.de\"\n  },\n  {\n    \"input\": \"Bu\\u0308cher.de\",\n    \"output\": \"xn--bcher-kva.de\"\n  },\n  {\n    \"input\": \"bu\\u0308cher.de\",\n    \"output\": \"xn--bcher-kva.de\"\n  },\n  {\n    \"input\": \"b\\u00fccher.de\",\n    \"output\": \"xn--bcher-kva.de\"\n  },\n  {\n    \"input\": \"B\\u00dcCHER.DE\",\n    \"output\": \"xn--bcher-kva.de\"\n  },\n  {\n    \"input\": \"BU\\u0308CHER.DE\",\n    \"output\": \"xn--bcher-kva.de\"\n  },\n  {\n    \"input\": \"xn--bcher-kva.de\",\n    \"output\": \"xn--bcher-kva.de\"\n  },\n  {\n    \"input\": \"\\u00d6BB\",\n    \"output\": \"xn--bb-eka\"\n  },\n  {\n    \"input\": \"O\\u0308BB\",\n    \"output\": \"xn--bb-eka\"\n  },\n  {\n    \"input\": \"o\\u0308bb\",\n    \"output\": \"xn--bb-eka\"\n  },\n  {\n    \"input\": \"\\u00f6bb\",\n    \"output\": \"xn--bb-eka\"\n  },\n  {\n    \"input\": \"\\u00d6bb\",\n    \"output\": \"xn--bb-eka\"\n  },\n  {\n    \"input\": \"O\\u0308bb\",\n    \"output\": \"xn--bb-eka\"\n  },\n  {\n    \"input\": \"xn--bb-eka\",\n    \"output\": \"xn--bb-eka\"\n  },\n  {\n    \"input\": \"FA\\u1e9e.de\",\n    \"output\": \"xn--fa-hia.de\"\n  },\n  {\n    \"input\": \"FA\\u1e9e.DE\",\n    \"output\": \"xn--fa-hia.de\"\n  },\n  {\n    \"input\": \"\\u03b2\\u03cc\\u03bb\\u03bf\\u03c2.com\",\n    \"output\": \"xn--nxasmm1c.com\"\n  },\n  {\n    \"input\": \"\\u03b2\\u03bf\\u0301\\u03bb\\u03bf\\u03c2.com\",\n    \"output\": \"xn--nxasmm1c.com\"\n  },\n  {\n    \"input\": \"\\u0392\\u039f\\u0301\\u039b\\u039f\\u03a3.COM\",\n    \"output\": \"xn--nxasmq6b.com\"\n  },\n  {\n    \"input\": \"\\u0392\\u038c\\u039b\\u039f\\u03a3.COM\",\n    \"output\": \"xn--nxasmq6b.com\"\n  },\n  {\n    \"input\": \"\\u03b2\\u03cc\\u03bb\\u03bf\\u03c3.com\",\n    \"output\": \"xn--nxasmq6b.com\"\n  },\n  {\n    \"input\": \"\\u03b2\\u03bf\\u0301\\u03bb\\u03bf\\u03c3.com\",\n    \"output\": \"xn--nxasmq6b.com\"\n  },\n  {\n    \"input\": \"\\u0392\\u03bf\\u0301\\u03bb\\u03bf\\u03c3.com\",\n    \"output\": \"xn--nxasmq6b.com\"\n  },\n  {\n    \"input\": \"\\u0392\\u03cc\\u03bb\\u03bf\\u03c3.com\",\n    \"output\": \"xn--nxasmq6b.com\"\n  },\n  {\n    \"input\": \"xn--nxasmq6b.com\",\n    \"output\": \"xn--nxasmq6b.com\"\n  },\n  {\n    \"input\": \"\\u0392\\u03bf\\u0301\\u03bb\\u03bf\\u03c2.com\",\n    \"output\": \"xn--nxasmm1c.com\"\n  },\n  {\n    \"input\": \"\\u0392\\u03cc\\u03bb\\u03bf\\u03c2.com\",\n    \"output\": \"xn--nxasmm1c.com\"\n  },\n  {\n    \"input\": \"xn--nxasmm1c.com\",\n    \"output\": \"xn--nxasmm1c.com\"\n  },\n  {\n    \"input\": \"xn--nxasmm1c\",\n    \"output\": \"xn--nxasmm1c\"\n  },\n  {\n    \"input\": \"\\u03b2\\u03cc\\u03bb\\u03bf\\u03c2\",\n    \"output\": \"xn--nxasmm1c\"\n  },\n  {\n    \"input\": \"\\u03b2\\u03bf\\u0301\\u03bb\\u03bf\\u03c2\",\n    \"output\": \"xn--nxasmm1c\"\n  },\n  {\n    \"input\": \"\\u0392\\u039f\\u0301\\u039b\\u039f\\u03a3\",\n    \"output\": \"xn--nxasmq6b\"\n  },\n  {\n    \"input\": \"\\u0392\\u038c\\u039b\\u039f\\u03a3\",\n    \"output\": \"xn--nxasmq6b\"\n  },\n  {\n    \"input\": \"\\u03b2\\u03cc\\u03bb\\u03bf\\u03c3\",\n    \"output\": \"xn--nxasmq6b\"\n  },\n  {\n    \"input\": \"\\u03b2\\u03bf\\u0301\\u03bb\\u03bf\\u03c3\",\n    \"output\": \"xn--nxasmq6b\"\n  },\n  {\n    \"input\": \"\\u0392\\u03bf\\u0301\\u03bb\\u03bf\\u03c3\",\n    \"output\": \"xn--nxasmq6b\"\n  },\n  {\n    \"input\": \"\\u0392\\u03cc\\u03bb\\u03bf\\u03c3\",\n    \"output\": \"xn--nxasmq6b\"\n  },\n  {\n    \"input\": \"xn--nxasmq6b\",\n    \"output\": \"xn--nxasmq6b\"\n  },\n  {\n    \"input\": \"\\u0392\\u03cc\\u03bb\\u03bf\\u03c2\",\n    \"output\": \"xn--nxasmm1c\"\n  },\n  {\n    \"input\": \"\\u0392\\u03bf\\u0301\\u03bb\\u03bf\\u03c2\",\n    \"output\": \"xn--nxasmm1c\"\n  },\n  {\n    \"input\": \"www.\\u0dc1\\u0dca\\u200d\\u0dbb\\u0dd3.com\",\n    \"output\": \"www.xn--10cl1a0b660p.com\"\n  },\n  {\n    \"input\": \"WWW.\\u0dc1\\u0dca\\u200d\\u0dbb\\u0dd3.COM\",\n    \"output\": \"www.xn--10cl1a0b660p.com\"\n  },\n  {\n    \"input\": \"Www.\\u0dc1\\u0dca\\u200d\\u0dbb\\u0dd3.com\",\n    \"output\": \"www.xn--10cl1a0b660p.com\"\n  },\n  {\n    \"input\": \"www.xn--10cl1a0b.com\",\n    \"output\": \"www.xn--10cl1a0b.com\"\n  },\n  {\n    \"input\": \"www.\\u0dc1\\u0dca\\u0dbb\\u0dd3.com\",\n    \"output\": \"www.xn--10cl1a0b.com\"\n  },\n  {\n    \"input\": \"WWW.\\u0dc1\\u0dca\\u0dbb\\u0dd3.COM\",\n    \"output\": \"www.xn--10cl1a0b.com\"\n  },\n  {\n    \"input\": \"Www.\\u0dc1\\u0dca\\u0dbb\\u0dd3.com\",\n    \"output\": \"www.xn--10cl1a0b.com\"\n  },\n  {\n    \"input\": \"www.xn--10cl1a0b660p.com\",\n    \"output\": \"www.xn--10cl1a0b660p.com\"\n  },\n  {\n    \"input\": \"\\u0646\\u0627\\u0645\\u0647\\u200c\\u0627\\u06cc\",\n    \"output\": \"xn--mgba3gch31f060k\"\n  },\n  {\n    \"input\": \"xn--mgba3gch31f\",\n    \"output\": \"xn--mgba3gch31f\"\n  },\n  {\n    \"input\": \"\\u0646\\u0627\\u0645\\u0647\\u0627\\u06cc\",\n    \"output\": \"xn--mgba3gch31f\"\n  },\n  {\n    \"input\": \"xn--mgba3gch31f060k\",\n    \"output\": \"xn--mgba3gch31f060k\"\n  },\n  {\n    \"input\": \"xn--mgba3gch31f060k.com\",\n    \"output\": \"xn--mgba3gch31f060k.com\"\n  },\n  {\n    \"input\": \"\\u0646\\u0627\\u0645\\u0647\\u200c\\u0627\\u06cc.com\",\n    \"output\": \"xn--mgba3gch31f060k.com\"\n  },\n  {\n    \"input\": \"\\u0646\\u0627\\u0645\\u0647\\u200c\\u0627\\u06cc.COM\",\n    \"output\": \"xn--mgba3gch31f060k.com\"\n  },\n  {\n    \"input\": \"xn--mgba3gch31f.com\",\n    \"output\": \"xn--mgba3gch31f.com\"\n  },\n  {\n    \"input\": \"\\u0646\\u0627\\u0645\\u0647\\u0627\\u06cc.com\",\n    \"output\": \"xn--mgba3gch31f.com\"\n  },\n  {\n    \"input\": \"\\u0646\\u0627\\u0645\\u0647\\u0627\\u06cc.COM\",\n    \"output\": \"xn--mgba3gch31f.com\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"a.b\\uff0ec\\u3002d\\uff61\",\n    \"output\": \"a.b.c.d.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"a.b.c\\u3002d\\u3002\",\n    \"output\": \"a.b.c.d.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"A.B.C\\u3002D\\u3002\",\n    \"output\": \"a.b.c.d.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"A.b.c\\u3002D\\u3002\",\n    \"output\": \"a.b.c.d.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"a.b.c.d.\",\n    \"output\": \"a.b.c.d.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"A.B\\uff0eC\\u3002D\\uff61\",\n    \"output\": \"a.b.c.d.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"A.b\\uff0ec\\u3002D\\uff61\",\n    \"output\": \"a.b.c.d.\"\n  },\n  {\n    \"input\": \"U\\u0308.xn--tda\",\n    \"output\": \"xn--tda.xn--tda\"\n  },\n  {\n    \"input\": \"\\u00dc.xn--tda\",\n    \"output\": \"xn--tda.xn--tda\"\n  },\n  {\n    \"input\": \"\\u00fc.xn--tda\",\n    \"output\": \"xn--tda.xn--tda\"\n  },\n  {\n    \"input\": \"u\\u0308.xn--tda\",\n    \"output\": \"xn--tda.xn--tda\"\n  },\n  {\n    \"input\": \"U\\u0308.XN--TDA\",\n    \"output\": \"xn--tda.xn--tda\"\n  },\n  {\n    \"input\": \"\\u00dc.XN--TDA\",\n    \"output\": \"xn--tda.xn--tda\"\n  },\n  {\n    \"input\": \"\\u00dc.xn--Tda\",\n    \"output\": \"xn--tda.xn--tda\"\n  },\n  {\n    \"input\": \"U\\u0308.xn--Tda\",\n    \"output\": \"xn--tda.xn--tda\"\n  },\n  {\n    \"input\": \"xn--tda.xn--tda\",\n    \"output\": \"xn--tda.xn--tda\"\n  },\n  {\n    \"input\": \"\\u00fc.\\u00fc\",\n    \"output\": \"xn--tda.xn--tda\"\n  },\n  {\n    \"input\": \"u\\u0308.u\\u0308\",\n    \"output\": \"xn--tda.xn--tda\"\n  },\n  {\n    \"input\": \"U\\u0308.U\\u0308\",\n    \"output\": \"xn--tda.xn--tda\"\n  },\n  {\n    \"input\": \"\\u00dc.\\u00dc\",\n    \"output\": \"xn--tda.xn--tda\"\n  },\n  {\n    \"input\": \"\\u00dc.\\u00fc\",\n    \"output\": \"xn--tda.xn--tda\"\n  },\n  {\n    \"input\": \"U\\u0308.u\\u0308\",\n    \"output\": \"xn--tda.xn--tda\"\n  },\n  {\n    \"comment\": \"V1\",\n    \"input\": \"xn--u-ccb\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"a\\u2488com\",\n    \"output\": null\n  },\n  {\n    \"input\": \"a1.com\",\n    \"output\": \"a1.com\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"A\\u2488COM\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"A\\u2488Com\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--acom-0w1b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--a-ecp.ru\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"P4\",\n    \"input\": \"xn--0.pt\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--a.pt\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"P4\",\n    \"input\": \"xn--a-\\u00c4.pt\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"P4\",\n    \"input\": \"xn--a-A\\u0308.pt\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"P4\",\n    \"input\": \"xn--a-a\\u0308.pt\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"P4\",\n    \"input\": \"xn--a-\\u00e4.pt\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"P4\",\n    \"input\": \"XN--A-\\u00c4.PT\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"P4\",\n    \"input\": \"XN--A-A\\u0308.PT\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"P4\",\n    \"input\": \"Xn--A-A\\u0308.pt\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"P4\",\n    \"input\": \"Xn--A-\\u00c4.pt\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V4; V2 (ignored)\",\n    \"input\": \"xn--xn--a--gua.pt\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\u65e5\\u672c\\u8a9e\\u3002\\uff2a\\uff30\",\n    \"output\": \"xn--wgv71a119e.jp\"\n  },\n  {\n    \"input\": \"\\u65e5\\u672c\\u8a9e\\u3002JP\",\n    \"output\": \"xn--wgv71a119e.jp\"\n  },\n  {\n    \"input\": \"\\u65e5\\u672c\\u8a9e\\u3002jp\",\n    \"output\": \"xn--wgv71a119e.jp\"\n  },\n  {\n    \"input\": \"\\u65e5\\u672c\\u8a9e\\u3002Jp\",\n    \"output\": \"xn--wgv71a119e.jp\"\n  },\n  {\n    \"input\": \"xn--wgv71a119e.jp\",\n    \"output\": \"xn--wgv71a119e.jp\"\n  },\n  {\n    \"input\": \"\\u65e5\\u672c\\u8a9e.jp\",\n    \"output\": \"xn--wgv71a119e.jp\"\n  },\n  {\n    \"input\": \"\\u65e5\\u672c\\u8a9e.JP\",\n    \"output\": \"xn--wgv71a119e.jp\"\n  },\n  {\n    \"input\": \"\\u65e5\\u672c\\u8a9e.Jp\",\n    \"output\": \"xn--wgv71a119e.jp\"\n  },\n  {\n    \"input\": \"\\u65e5\\u672c\\u8a9e\\u3002\\uff4a\\uff50\",\n    \"output\": \"xn--wgv71a119e.jp\"\n  },\n  {\n    \"input\": \"\\u65e5\\u672c\\u8a9e\\u3002\\uff2a\\uff50\",\n    \"output\": \"xn--wgv71a119e.jp\"\n  },\n  {\n    \"input\": \"\\u2615\",\n    \"output\": \"xn--53h\"\n  },\n  {\n    \"input\": \"xn--53h\",\n    \"output\": \"xn--53h\"\n  },\n  {\n    \"comment\": \"C1; C2; A4_2 (ignored)\",\n    \"input\": \"1.a\\u00df\\u200c\\u200db\\u200c\\u200dc\\u00df\\u00df\\u00df\\u00dfd\\u03c2\\u03c3\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00dfe\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00dfx\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00dfy\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u0302\\u00dfz\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; A4_2 (ignored)\",\n    \"input\": \"1.ASS\\u200c\\u200dB\\u200c\\u200dCSSSSSSSSD\\u03a3\\u03a3SSSSSSSSSSSSSSSSESSSSSSSSSSSSSSSSSSSSXSSSSSSSSSSSSSSSSSSSSYSSSSSSSSSSSSSSSS\\u0302SSZ\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; A4_2 (ignored)\",\n    \"input\": \"1.ASS\\u200c\\u200dB\\u200c\\u200dCSSSSSSSSD\\u03a3\\u03a3SSSSSSSSSSSSSSSSESSSSSSSSSSSSSSSSSSSSXSSSSSSSSSSSSSSSSSSSSYSSSSSSSSSSSSSSS\\u015cSSZ\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; A4_2 (ignored)\",\n    \"input\": \"1.ass\\u200c\\u200db\\u200c\\u200dcssssssssd\\u03c3\\u03c3ssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssss\\u015dssz\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; A4_2 (ignored)\",\n    \"input\": \"1.ass\\u200c\\u200db\\u200c\\u200dcssssssssd\\u03c3\\u03c3ssssssssssssssssessssssssssssssssssssxssssssssssssssssssssyssssssssssssssss\\u0302ssz\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; A4_2 (ignored)\",\n    \"input\": \"1.Ass\\u200c\\u200db\\u200c\\u200dcssssssssd\\u03c3\\u03c3ssssssssssssssssessssssssssssssssssssxssssssssssssssssssssyssssssssssssssss\\u0302ssz\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; A4_2 (ignored)\",\n    \"input\": \"1.Ass\\u200c\\u200db\\u200c\\u200dcssssssssd\\u03c3\\u03c3ssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssss\\u015dssz\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"1.xn--assbcssssssssdssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssssz-pxq1419aa\",\n    \"output\": \"1.xn--assbcssssssssdssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssssz-pxq1419aa\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"1.assbcssssssssd\\u03c3\\u03c3ssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssss\\u015dssz\",\n    \"output\": \"1.xn--assbcssssssssdssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssssz-pxq1419aa\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"1.assbcssssssssd\\u03c3\\u03c3ssssssssssssssssessssssssssssssssssssxssssssssssssssssssssyssssssssssssssss\\u0302ssz\",\n    \"output\": \"1.xn--assbcssssssssdssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssssz-pxq1419aa\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"1.ASSBCSSSSSSSSD\\u03a3\\u03a3SSSSSSSSSSSSSSSSESSSSSSSSSSSSSSSSSSSSXSSSSSSSSSSSSSSSSSSSSYSSSSSSSSSSSSSSSS\\u0302SSZ\",\n    \"output\": \"1.xn--assbcssssssssdssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssssz-pxq1419aa\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"1.ASSBCSSSSSSSSD\\u03a3\\u03a3SSSSSSSSSSSSSSSSESSSSSSSSSSSSSSSSSSSSXSSSSSSSSSSSSSSSSSSSSYSSSSSSSSSSSSSSS\\u015cSSZ\",\n    \"output\": \"1.xn--assbcssssssssdssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssssz-pxq1419aa\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"1.Assbcssssssssd\\u03c3\\u03c3ssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssss\\u015dssz\",\n    \"output\": \"1.xn--assbcssssssssdssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssssz-pxq1419aa\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"1.Assbcssssssssd\\u03c3\\u03c3ssssssssssssssssessssssssssssssssssssxssssssssssssssssssssyssssssssssssssss\\u0302ssz\",\n    \"output\": \"1.xn--assbcssssssssdssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssssz-pxq1419aa\"\n  },\n  {\n    \"comment\": \"C1; C2; A4_2 (ignored)\",\n    \"input\": \"1.xn--assbcssssssssdssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssssz-pxq1419aa69989dba9gc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; A4_2 (ignored)\",\n    \"input\": \"1.A\\u00df\\u200c\\u200db\\u200c\\u200dc\\u00df\\u00df\\u00df\\u00dfd\\u03c2\\u03c3\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00dfe\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00dfx\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00dfy\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u00df\\u0302\\u00dfz\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; A4_2 (ignored)\",\n    \"input\": \"1.xn--abcdexyz-qyacaaabaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaa010ze2isb1140zba8cc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200cx\\u200dn\\u200c-\\u200d-b\\u00df\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200cX\\u200dN\\u200c-\\u200d-BSS\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200cx\\u200dn\\u200c-\\u200d-bss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200cX\\u200dn\\u200c-\\u200d-Bss\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--bss\",\n    \"output\": \"xn--bss\"\n  },\n  {\n    \"input\": \"\\u5919\",\n    \"output\": \"xn--bss\"\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"xn--xn--bss-7z6ccid\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200cX\\u200dn\\u200c-\\u200d-B\\u00df\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"xn--xn--b-pqa5796ccahd\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\u02e3\\u034f\\u2115\\u200b\\ufe63\\u00ad\\uff0d\\u180c\\u212c\\ufe00\\u017f\\u2064\\ud835\\udd30\\udb40\\uddef\\ufb04\",\n    \"output\": \"xn--bssffl\"\n  },\n  {\n    \"input\": \"x\\u034fN\\u200b-\\u00ad-\\u180cB\\ufe00s\\u2064s\\udb40\\uddefffl\",\n    \"output\": \"xn--bssffl\"\n  },\n  {\n    \"input\": \"x\\u034fn\\u200b-\\u00ad-\\u180cb\\ufe00s\\u2064s\\udb40\\uddefffl\",\n    \"output\": \"xn--bssffl\"\n  },\n  {\n    \"input\": \"X\\u034fN\\u200b-\\u00ad-\\u180cB\\ufe00S\\u2064S\\udb40\\uddefFFL\",\n    \"output\": \"xn--bssffl\"\n  },\n  {\n    \"input\": \"X\\u034fn\\u200b-\\u00ad-\\u180cB\\ufe00s\\u2064s\\udb40\\uddefffl\",\n    \"output\": \"xn--bssffl\"\n  },\n  {\n    \"input\": \"xn--bssffl\",\n    \"output\": \"xn--bssffl\"\n  },\n  {\n    \"input\": \"\\u5921\\u591e\\u591c\\u5919\",\n    \"output\": \"xn--bssffl\"\n  },\n  {\n    \"input\": \"\\u02e3\\u034f\\u2115\\u200b\\ufe63\\u00ad\\uff0d\\u180c\\u212c\\ufe00S\\u2064\\ud835\\udd30\\udb40\\uddefFFL\",\n    \"output\": \"xn--bssffl\"\n  },\n  {\n    \"input\": \"x\\u034fN\\u200b-\\u00ad-\\u180cB\\ufe00S\\u2064s\\udb40\\uddefFFL\",\n    \"output\": \"xn--bssffl\"\n  },\n  {\n    \"input\": \"\\u02e3\\u034f\\u2115\\u200b\\ufe63\\u00ad\\uff0d\\u180c\\u212c\\ufe00s\\u2064\\ud835\\udd30\\udb40\\uddefffl\",\n    \"output\": \"xn--bssffl\"\n  },\n  {\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b.\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b.\"\n  },\n  {\n    \"comment\": \"A4_1 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901c\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901c\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901234.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901234.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901234.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a.\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901234.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a.\"\n  },\n  {\n    \"comment\": \"A4_1 (ignored); A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901234.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901234.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\"\n  },\n  {\n    \"input\": \"\\u00e41234567890123456789012345678901234567890123456789012345\",\n    \"output\": \"xn--1234567890123456789012345678901234567890123456789012345-9te\"\n  },\n  {\n    \"input\": \"a\\u03081234567890123456789012345678901234567890123456789012345\",\n    \"output\": \"xn--1234567890123456789012345678901234567890123456789012345-9te\"\n  },\n  {\n    \"input\": \"A\\u03081234567890123456789012345678901234567890123456789012345\",\n    \"output\": \"xn--1234567890123456789012345678901234567890123456789012345-9te\"\n  },\n  {\n    \"input\": \"\\u00c41234567890123456789012345678901234567890123456789012345\",\n    \"output\": \"xn--1234567890123456789012345678901234567890123456789012345-9te\"\n  },\n  {\n    \"input\": \"xn--1234567890123456789012345678901234567890123456789012345-9te\",\n    \"output\": \"xn--1234567890123456789012345678901234567890123456789012345-9te\"\n  },\n  {\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890\\u00e4123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\"\n  },\n  {\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890a\\u0308123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\"\n  },\n  {\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890A\\u0308123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890B\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\"\n  },\n  {\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890\\u00c4123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890B\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\"\n  },\n  {\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890\\u00e4123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b.\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890a\\u0308123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b.\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890A\\u0308123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890B.\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890\\u00c4123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890B.\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b.\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b.\"\n  },\n  {\n    \"comment\": \"A4_1 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890\\u00e4123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901c\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901c\"\n  },\n  {\n    \"comment\": \"A4_1 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890a\\u0308123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901c\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901c\"\n  },\n  {\n    \"comment\": \"A4_1 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890A\\u0308123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901C\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901c\"\n  },\n  {\n    \"comment\": \"A4_1 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890\\u00c4123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901C\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901c\"\n  },\n  {\n    \"comment\": \"A4_1 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901c\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901c\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890\\u00e41234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890a\\u03081234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890A\\u03081234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789A\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890\\u00c41234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789A\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890\\u00e41234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a.\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890a\\u03081234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a.\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890A\\u03081234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789A.\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890\\u00c41234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789A.\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a.\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a.\"\n  },\n  {\n    \"comment\": \"A4_1 (ignored); A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890\\u00e41234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\"\n  },\n  {\n    \"comment\": \"A4_1 (ignored); A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890a\\u03081234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\"\n  },\n  {\n    \"comment\": \"A4_1 (ignored); A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890A\\u03081234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890B\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\"\n  },\n  {\n    \"comment\": \"A4_1 (ignored); A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890\\u00c41234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890B\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\"\n  },\n  {\n    \"comment\": \"A4_1 (ignored); A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\"\n  },\n  {\n    \"comment\": \"V2 (ignored); V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"a.b..-q--a-.e\",\n    \"output\": \"a.b..-q--a-.e\"\n  },\n  {\n    \"comment\": \"V2 (ignored); V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"a.b..-q--\\u00e4-.e\",\n    \"output\": \"a.b..xn---q----jra.e\"\n  },\n  {\n    \"comment\": \"V2 (ignored); V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"a.b..-q--a\\u0308-.e\",\n    \"output\": \"a.b..xn---q----jra.e\"\n  },\n  {\n    \"comment\": \"V2 (ignored); V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"A.B..-Q--A\\u0308-.E\",\n    \"output\": \"a.b..xn---q----jra.e\"\n  },\n  {\n    \"comment\": \"V2 (ignored); V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"A.B..-Q--\\u00c4-.E\",\n    \"output\": \"a.b..xn---q----jra.e\"\n  },\n  {\n    \"comment\": \"V2 (ignored); V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"A.b..-Q--\\u00c4-.E\",\n    \"output\": \"a.b..xn---q----jra.e\"\n  },\n  {\n    \"comment\": \"V2 (ignored); V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"A.b..-Q--A\\u0308-.E\",\n    \"output\": \"a.b..xn---q----jra.e\"\n  },\n  {\n    \"comment\": \"V2 (ignored); V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"a.b..xn---q----jra.e\",\n    \"output\": \"a.b..xn---q----jra.e\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"a..c\",\n    \"output\": \"a..c\"\n  },\n  {\n    \"comment\": \"V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"a.-b.\",\n    \"output\": \"a.-b.\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"a.b-.c\",\n    \"output\": \"a.b-.c\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"a.-.c\",\n    \"output\": \"a.-.c\"\n  },\n  {\n    \"comment\": \"V2 (ignored)\",\n    \"input\": \"a.bc--de.f\",\n    \"output\": \"a.bc--de.f\"\n  },\n  {\n    \"comment\": \"V4; V2 (ignored)\",\n    \"input\": \"xn--xn---epa\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u00e4.\\u00ad.c\",\n    \"output\": \"xn--4ca..c\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"a\\u0308.\\u00ad.c\",\n    \"output\": \"xn--4ca..c\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"A\\u0308.\\u00ad.C\",\n    \"output\": \"xn--4ca..c\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u00c4.\\u00ad.C\",\n    \"output\": \"xn--4ca..c\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--4ca..c\",\n    \"output\": \"xn--4ca..c\"\n  },\n  {\n    \"comment\": \"V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"\\u00e4.-b.\",\n    \"output\": \"xn--4ca.-b.\"\n  },\n  {\n    \"comment\": \"V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"a\\u0308.-b.\",\n    \"output\": \"xn--4ca.-b.\"\n  },\n  {\n    \"comment\": \"V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"A\\u0308.-B.\",\n    \"output\": \"xn--4ca.-b.\"\n  },\n  {\n    \"comment\": \"V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"\\u00c4.-B.\",\n    \"output\": \"xn--4ca.-b.\"\n  },\n  {\n    \"comment\": \"V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"xn--4ca.-b.\",\n    \"output\": \"xn--4ca.-b.\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"\\u00e4.b-.c\",\n    \"output\": \"xn--4ca.b-.c\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"a\\u0308.b-.c\",\n    \"output\": \"xn--4ca.b-.c\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"A\\u0308.B-.C\",\n    \"output\": \"xn--4ca.b-.c\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"\\u00c4.B-.C\",\n    \"output\": \"xn--4ca.b-.c\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"\\u00c4.b-.C\",\n    \"output\": \"xn--4ca.b-.c\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"A\\u0308.b-.C\",\n    \"output\": \"xn--4ca.b-.c\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"xn--4ca.b-.c\",\n    \"output\": \"xn--4ca.b-.c\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"\\u00e4.-.c\",\n    \"output\": \"xn--4ca.-.c\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"a\\u0308.-.c\",\n    \"output\": \"xn--4ca.-.c\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"A\\u0308.-.C\",\n    \"output\": \"xn--4ca.-.c\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"\\u00c4.-.C\",\n    \"output\": \"xn--4ca.-.c\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"xn--4ca.-.c\",\n    \"output\": \"xn--4ca.-.c\"\n  },\n  {\n    \"comment\": \"V2 (ignored)\",\n    \"input\": \"\\u00e4.bc--de.f\",\n    \"output\": \"xn--4ca.bc--de.f\"\n  },\n  {\n    \"comment\": \"V2 (ignored)\",\n    \"input\": \"a\\u0308.bc--de.f\",\n    \"output\": \"xn--4ca.bc--de.f\"\n  },\n  {\n    \"comment\": \"V2 (ignored)\",\n    \"input\": \"A\\u0308.BC--DE.F\",\n    \"output\": \"xn--4ca.bc--de.f\"\n  },\n  {\n    \"comment\": \"V2 (ignored)\",\n    \"input\": \"\\u00c4.BC--DE.F\",\n    \"output\": \"xn--4ca.bc--de.f\"\n  },\n  {\n    \"comment\": \"V2 (ignored)\",\n    \"input\": \"\\u00c4.bc--De.f\",\n    \"output\": \"xn--4ca.bc--de.f\"\n  },\n  {\n    \"comment\": \"V2 (ignored)\",\n    \"input\": \"A\\u0308.bc--De.f\",\n    \"output\": \"xn--4ca.bc--de.f\"\n  },\n  {\n    \"comment\": \"V2 (ignored)\",\n    \"input\": \"xn--4ca.bc--de.f\",\n    \"output\": \"xn--4ca.bc--de.f\"\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"a.b.\\u0308c.d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"A.B.\\u0308C.D\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"A.b.\\u0308c.d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"a.b.xn--c-bcb.d\",\n    \"output\": null\n  },\n  {\n    \"input\": \"A0\",\n    \"output\": \"a0\"\n  },\n  {\n    \"input\": \"0A\",\n    \"output\": \"0a\"\n  },\n  {\n    \"input\": \"\\u05d0\\u05c7\",\n    \"output\": \"xn--vdbr\"\n  },\n  {\n    \"input\": \"xn--vdbr\",\n    \"output\": \"xn--vdbr\"\n  },\n  {\n    \"input\": \"\\u05d09\\u05c7\",\n    \"output\": \"xn--9-ihcz\"\n  },\n  {\n    \"input\": \"xn--9-ihcz\",\n    \"output\": \"xn--9-ihcz\"\n  },\n  {\n    \"input\": \"\\u05d0\\u05ea\",\n    \"output\": \"xn--4db6c\"\n  },\n  {\n    \"input\": \"xn--4db6c\",\n    \"output\": \"xn--4db6c\"\n  },\n  {\n    \"input\": \"\\u05d0\\u05f3\\u05ea\",\n    \"output\": \"xn--4db6c0a\"\n  },\n  {\n    \"input\": \"xn--4db6c0a\",\n    \"output\": \"xn--4db6c0a\"\n  },\n  {\n    \"input\": \"\\u05d07\\u05ea\",\n    \"output\": \"xn--7-zhc3f\"\n  },\n  {\n    \"input\": \"xn--7-zhc3f\",\n    \"output\": \"xn--7-zhc3f\"\n  },\n  {\n    \"input\": \"\\u05d0\\u0667\\u05ea\",\n    \"output\": \"xn--4db6c6t\"\n  },\n  {\n    \"input\": \"xn--4db6c6t\",\n    \"output\": \"xn--4db6c6t\"\n  },\n  {\n    \"input\": \"\\u0bb9\\u0bcd\\u200d\",\n    \"output\": \"xn--dmc4b194h\"\n  },\n  {\n    \"input\": \"xn--dmc4b\",\n    \"output\": \"xn--dmc4b\"\n  },\n  {\n    \"input\": \"\\u0bb9\\u0bcd\",\n    \"output\": \"xn--dmc4b\"\n  },\n  {\n    \"input\": \"xn--dmc4b194h\",\n    \"output\": \"xn--dmc4b194h\"\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u0bb9\\u200d\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--dmc\",\n    \"output\": \"xn--dmc\"\n  },\n  {\n    \"input\": \"\\u0bb9\",\n    \"output\": \"xn--dmc\"\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"xn--dmc225h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"xn--1ug\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\u0bb9\\u0bcd\\u200c\",\n    \"output\": \"xn--dmc4by94h\"\n  },\n  {\n    \"input\": \"xn--dmc4by94h\",\n    \"output\": \"xn--dmc4by94h\"\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u0bb9\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"xn--dmc025h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"xn--0ug\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\u0644\\u0670\\u200c\\u06ed\\u06ef\",\n    \"output\": \"xn--ghb2gxqia7523a\"\n  },\n  {\n    \"input\": \"xn--ghb2gxqia\",\n    \"output\": \"xn--ghb2gxqia\"\n  },\n  {\n    \"input\": \"\\u0644\\u0670\\u06ed\\u06ef\",\n    \"output\": \"xn--ghb2gxqia\"\n  },\n  {\n    \"input\": \"xn--ghb2gxqia7523a\",\n    \"output\": \"xn--ghb2gxqia7523a\"\n  },\n  {\n    \"input\": \"\\u0644\\u0670\\u200c\\u06ef\",\n    \"output\": \"xn--ghb2g3qq34f\"\n  },\n  {\n    \"input\": \"xn--ghb2g3q\",\n    \"output\": \"xn--ghb2g3q\"\n  },\n  {\n    \"input\": \"\\u0644\\u0670\\u06ef\",\n    \"output\": \"xn--ghb2g3q\"\n  },\n  {\n    \"input\": \"xn--ghb2g3qq34f\",\n    \"output\": \"xn--ghb2g3qq34f\"\n  },\n  {\n    \"input\": \"\\u0644\\u200c\\u06ed\\u06ef\",\n    \"output\": \"xn--ghb25aga828w\"\n  },\n  {\n    \"input\": \"xn--ghb25aga\",\n    \"output\": \"xn--ghb25aga\"\n  },\n  {\n    \"input\": \"\\u0644\\u06ed\\u06ef\",\n    \"output\": \"xn--ghb25aga\"\n  },\n  {\n    \"input\": \"xn--ghb25aga828w\",\n    \"output\": \"xn--ghb25aga828w\"\n  },\n  {\n    \"input\": \"\\u0644\\u200c\\u06ef\",\n    \"output\": \"xn--ghb65a953d\"\n  },\n  {\n    \"input\": \"xn--ghb65a\",\n    \"output\": \"xn--ghb65a\"\n  },\n  {\n    \"input\": \"\\u0644\\u06ef\",\n    \"output\": \"xn--ghb65a\"\n  },\n  {\n    \"input\": \"xn--ghb65a953d\",\n    \"output\": \"xn--ghb65a953d\"\n  },\n  {\n    \"input\": \"xn--ghb2gxq\",\n    \"output\": \"xn--ghb2gxq\"\n  },\n  {\n    \"input\": \"\\u0644\\u0670\\u06ed\",\n    \"output\": \"xn--ghb2gxq\"\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u06ef\\u200c\\u06ef\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--cmba\",\n    \"output\": \"xn--cmba\"\n  },\n  {\n    \"input\": \"\\u06ef\\u06ef\",\n    \"output\": \"xn--cmba\"\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"xn--cmba004q\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--ghb\",\n    \"output\": \"xn--ghb\"\n  },\n  {\n    \"input\": \"\\u0644\",\n    \"output\": \"xn--ghb\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"a\\u3002\\u3002b\",\n    \"output\": \"a..b\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"A\\u3002\\u3002B\",\n    \"output\": \"a..b\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"a..b\",\n    \"output\": \"a..b\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"..xn--skb\",\n    \"output\": \"..xn--skb\"\n  },\n  {\n    \"comment\": \"U1 (ignored)\",\n    \"input\": \"$\",\n    \"output\": \"$\"\n  },\n  {\n    \"comment\": \"U1 (ignored)\",\n    \"input\": \"\\u2477.four\",\n    \"output\": \"(4).four\"\n  },\n  {\n    \"comment\": \"U1 (ignored)\",\n    \"input\": \"(4).four\",\n    \"output\": \"(4).four\"\n  },\n  {\n    \"comment\": \"U1 (ignored)\",\n    \"input\": \"\\u2477.FOUR\",\n    \"output\": \"(4).four\"\n  },\n  {\n    \"comment\": \"U1 (ignored)\",\n    \"input\": \"\\u2477.Four\",\n    \"output\": \"(4).four\"\n  },\n  {\n    \"comment\": \"V7; A3\",\n    \"input\": \"a\\ud900z\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A3\",\n    \"input\": \"A\\ud900Z\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"P4; A4_1 (ignored); A4_2 (ignored)\",\n    \"input\": \"xn--\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"P4\",\n    \"input\": \"xn---\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"P4\",\n    \"input\": \"xn--ASCII-\",\n    \"output\": null\n  },\n  {\n    \"input\": \"ascii\",\n    \"output\": \"ascii\"\n  },\n  {\n    \"comment\": \"P4\",\n    \"input\": \"xn--unicode-.org\",\n    \"output\": null\n  },\n  {\n    \"input\": \"unicode.org\",\n    \"output\": \"unicode.org\"\n  },\n  {\n    \"input\": \"\\uf951\\ud87e\\udc68\\ud87e\\udc74\\ud87e\\udd1f\\ud87e\\udd5f\\ud87e\\uddbf\",\n    \"output\": \"xn--snl253bgitxhzwu2arn60c\"\n  },\n  {\n    \"input\": \"\\u964b\\u36fc\\u5f53\\ud850\\udfab\\u7aee\\u45d7\",\n    \"output\": \"xn--snl253bgitxhzwu2arn60c\"\n  },\n  {\n    \"input\": \"xn--snl253bgitxhzwu2arn60c\",\n    \"output\": \"xn--snl253bgitxhzwu2arn60c\"\n  },\n  {\n    \"input\": \"\\u96fb\\ud844\\udf6a\\u5f33\\u43ab\\u7aae\\u4d57\",\n    \"output\": \"xn--kbo60w31ob3z6t3av9z5b\"\n  },\n  {\n    \"input\": \"xn--kbo60w31ob3z6t3av9z5b\",\n    \"output\": \"xn--kbo60w31ob3z6t3av9z5b\"\n  },\n  {\n    \"input\": \"xn--A-1ga\",\n    \"output\": \"xn--a-1ga\"\n  },\n  {\n    \"input\": \"a\\u00f6\",\n    \"output\": \"xn--a-1ga\"\n  },\n  {\n    \"input\": \"ao\\u0308\",\n    \"output\": \"xn--a-1ga\"\n  },\n  {\n    \"input\": \"AO\\u0308\",\n    \"output\": \"xn--a-1ga\"\n  },\n  {\n    \"input\": \"A\\u00d6\",\n    \"output\": \"xn--a-1ga\"\n  },\n  {\n    \"input\": \"A\\u00f6\",\n    \"output\": \"xn--a-1ga\"\n  },\n  {\n    \"input\": \"Ao\\u0308\",\n    \"output\": \"xn--a-1ga\"\n  },\n  {\n    \"input\": \"\\uff1d\\u0338\",\n    \"output\": \"xn--1ch\"\n  },\n  {\n    \"input\": \"\\u2260\",\n    \"output\": \"xn--1ch\"\n  },\n  {\n    \"input\": \"=\\u0338\",\n    \"output\": \"xn--1ch\"\n  },\n  {\n    \"input\": \"xn--1ch\",\n    \"output\": \"xn--1ch\"\n  },\n  {\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890A\\u0308123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\"\n  },\n  {\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890\\u00c4123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890A\\u0308123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b.\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890\\u00c4123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b.\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b.\"\n  },\n  {\n    \"comment\": \"A4_1 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890A\\u0308123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901c\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901c\"\n  },\n  {\n    \"comment\": \"A4_1 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890\\u00c4123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901c\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901c\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890A\\u03081234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890\\u00c41234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890A\\u03081234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a.\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890\\u00c41234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a.\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789a.\"\n  },\n  {\n    \"comment\": \"A4_1 (ignored); A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890A\\u03081234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\"\n  },\n  {\n    \"comment\": \"A4_1 (ignored); A4_2 (ignored)\",\n    \"input\": \"123456789012345678901234567890123456789012345678901234567890123.1234567890\\u00c41234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\",\n    \"output\": \"123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890b\"\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\u2495\\u221d\\u065f\\uda0e\\udd26\\uff0e-\\udb40\\udd2f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"14.\\u221d\\u065f\\uda0e\\udd26.-\\udb40\\udd2f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"14.xn--7hb713l3v90n.-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn--7hb713lfwbi1311b.-\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\ua863.\\u07cf\",\n    \"output\": \"xn--8c9a.xn--qsb\"\n  },\n  {\n    \"input\": \"xn--8c9a.xn--qsb\",\n    \"output\": \"xn--8c9a.xn--qsb\"\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u200d\\u2260\\u1899\\u226f.\\uc1a3-\\u1874\\u10a0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u200d=\\u0338\\u1899>\\u0338.\\u1109\\u1169\\u11be-\\u1874\\u10a0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u200d=\\u0338\\u1899>\\u0338.\\u1109\\u1169\\u11be-\\u1874\\u2d00\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u200d\\u2260\\u1899\\u226f.\\uc1a3-\\u1874\\u2d00\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--jbf911clb.xn----p9j493ivi4l\",\n    \"output\": \"xn--jbf911clb.xn----p9j493ivi4l\"\n  },\n  {\n    \"input\": \"\\u2260\\u1899\\u226f.\\uc1a3-\\u1874\\u2d00\",\n    \"output\": \"xn--jbf911clb.xn----p9j493ivi4l\"\n  },\n  {\n    \"input\": \"=\\u0338\\u1899>\\u0338.\\u1109\\u1169\\u11be-\\u1874\\u2d00\",\n    \"output\": \"xn--jbf911clb.xn----p9j493ivi4l\"\n  },\n  {\n    \"input\": \"=\\u0338\\u1899>\\u0338.\\u1109\\u1169\\u11be-\\u1874\\u10a0\",\n    \"output\": \"xn--jbf911clb.xn----p9j493ivi4l\"\n  },\n  {\n    \"input\": \"\\u2260\\u1899\\u226f.\\uc1a3-\\u1874\\u10a0\",\n    \"output\": \"xn--jbf911clb.xn----p9j493ivi4l\"\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"xn--jbf929a90b0b.xn----p9j493ivi4l\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--jbf911clb.xn----6zg521d196p\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--jbf929a90b0b.xn----6zg521d196p\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud97d\\udf9c\\uff0e\\ud803\\udfc7\\u0fa2\\u077d\\u0600\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud97d\\udf9c\\uff0e\\ud803\\udfc7\\u0fa1\\u0fb7\\u077d\\u0600\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud97d\\udf9c.\\ud803\\udfc7\\u0fa1\\u0fb7\\u077d\\u0600\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--gw68a.xn--ifb57ev2psc6027m\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud84f\\udcd4\\u0303.\\ud805\\udcc2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--nsa95820a.xn--wz1d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u200c\\ud9d4\\udfad.\\u10b2\\ud804\\uddc0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u200c\\ud9d4\\udfad.\\u2d12\\ud804\\uddc0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--bn95b.xn--9kj2034e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--0ug15083f.xn--9kj2034e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--bn95b.xn--qnd6272k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--0ug15083f.xn--qnd6272k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u7e71\\ud805\\uddbf\\u200d.\\uff18\\ufe12\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--gl0as212a.i.\",\n    \"output\": \"xn--gl0as212a.i.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u7e71\\ud805\\uddbf.i.\",\n    \"output\": \"xn--gl0as212a.i.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u7e71\\ud805\\uddbf.I.\",\n    \"output\": \"xn--gl0as212a.i.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--1ug6928ac48e.i.\",\n    \"output\": \"xn--1ug6928ac48e.i.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u7e71\\ud805\\uddbf\\u200d.i.\",\n    \"output\": \"xn--1ug6928ac48e.i.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u7e71\\ud805\\uddbf\\u200d.I.\",\n    \"output\": \"xn--1ug6928ac48e.i.\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--gl0as212a.xn--8-o89h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--1ug6928ac48e.xn--8-o89h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"\\udb40\\uddbe\\uff0e\\ud838\\udc08\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"\\udb40\\uddbe.\\ud838\\udc08\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \".xn--ph4h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u00df\\u06eb\\u3002\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"SS\\u06eb\\u3002\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"ss\\u06eb\\u3002\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"Ss\\u06eb\\u3002\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--ss-59d.\",\n    \"output\": \"xn--ss-59d.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"ss\\u06eb.\",\n    \"output\": \"xn--ss-59d.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"SS\\u06eb.\",\n    \"output\": \"xn--ss-59d.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"Ss\\u06eb.\",\n    \"output\": \"xn--ss-59d.\"\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"xn--ss-59d.xn--1ug\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"xn--zca012a.xn--1ug\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\udb41\\udc35\\u200c\\u2488\\uff0e\\udb40\\udf87\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; A4_2 (ignored)\",\n    \"input\": \"\\udb41\\udc35\\u200c1..\\udb40\\udf87\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"xn--1-bs31m..xn--tv36e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; A4_2 (ignored)\",\n    \"input\": \"xn--1-rgn37671n..xn--tv36e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--tshz2001k.xn--tv36e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--0ug88o47900b.xn--tv36e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb3c\\ude23\\u065f\\uaab2\\u00df\\u3002\\udaf1\\udce7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb3c\\ude23\\u065f\\uaab2SS\\u3002\\udaf1\\udce7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb3c\\ude23\\u065f\\uaab2ss\\u3002\\udaf1\\udce7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb3c\\ude23\\u065f\\uaab2Ss\\u3002\\udaf1\\udce7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--ss-3xd2839nncy1m.xn--bb79d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--zca92z0t7n5w96j.xn--bb79d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V7\",\n    \"input\": \"\\u0774\\u200c\\ud83a\\udd3f\\u3002\\ud8b5\\ude10\\u425c\\u200d\\ud9be\\udd3c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V7\",\n    \"input\": \"\\u0774\\u200c\\ud83a\\udd1d\\u3002\\ud8b5\\ude10\\u425c\\u200d\\ud9be\\udd3c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--4pb2977v.xn--z0nt555ukbnv\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V7\",\n    \"input\": \"xn--4pb607jjt73a.xn--1ug236ke314donv1a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"\\u3164\\u094d\\u10a0\\u17d0.\\u180b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"\\u1160\\u094d\\u10a0\\u17d0.\\u180b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"\\u1160\\u094d\\u2d00\\u17d0.\\u180b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"xn--n3b445e53p.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"\\u3164\\u094d\\u2d00\\u17d0.\\u180b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"xn--n3b742bkqf4ty.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"xn--n3b468aoqa89r.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"xn--n3b445e53po6d.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"xn--n3b468azngju2a.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u2763\\u200d\\uff0e\\u09cd\\ud807\\udc3d\\u0612\\ua929\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u2763\\u200d.\\u09cd\\ud807\\udc3d\\u0612\\ua929\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--pei.xn--0fb32q3w7q2g4d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"xn--1ugy10a.xn--0fb32q3w7q2g4d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u0349\\u3002\\ud85e\\udc6b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--nua.xn--bc6k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"\\ud807\\udc3f\\udb40\\udd66\\uff0e\\u1160\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"\\ud807\\udc3f\\udb40\\udd66.\\u1160\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"xn--ok3d.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--ok3d.xn--psd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u850f\\uff61\\ud807\\udc3a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u850f\\u3002\\ud807\\udc3a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--uy1a.xn--jk3d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--8g1d12120a.xn--5l6h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ud804\\udee7\\ua9c02\\uff61\\u39c9\\uda09\\udd84\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ud804\\udee7\\ua9c02\\u3002\\u39c9\\uda09\\udd84\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--2-5z4eu89y.xn--97l02706d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\u2938\\u03c2\\ud8ab\\udc40\\uff61\\uffa0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\u2938\\u03c2\\ud8ab\\udc40\\u3002\\u1160\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\u2938\\u03a3\\ud8ab\\udc40\\u3002\\u1160\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\u2938\\u03c3\\ud8ab\\udc40\\u3002\\u1160\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"xn--4xa192qmp03d.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"xn--3xa392qmp03d.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\u2938\\u03a3\\ud8ab\\udc40\\uff61\\uffa0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\u2938\\u03c3\\ud8ab\\udc40\\uff61\\uffa0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--4xa192qmp03d.xn--psd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--3xa392qmp03d.xn--psd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--4xa192qmp03d.xn--cl7c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--3xa392qmp03d.xn--cl7c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\u200d\\udb7d\\udc56\\udb40\\udc50\\uff0e\\u05bd\\ud826\\udfb0\\ua85d\\ud800\\udee1\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\u200d\\udb7d\\udc56\\udb40\\udc50.\\u05bd\\ud826\\udfb0\\ua85d\\ud800\\udee1\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--b726ey18m.xn--ldb8734fg0qcyzzg\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"xn--1ug66101lt8me.xn--ldb8734fg0qcyzzg\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\u3002\\udbcc\\ude35\\u03c2\\ud8c2\\udc07\\u3002\\ud802\\udf88\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\u3002\\udbcc\\ude35\\u03a3\\ud8c2\\udc07\\u3002\\ud802\\udf88\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\u3002\\udbcc\\ude35\\u03c3\\ud8c2\\udc07\\u3002\\ud802\\udf88\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \".xn--4xa68573c7n64d.xn--f29c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \".xn--3xa88573c7n64d.xn--f29c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2489\\udb40\\ude93\\u2260\\uff61\\u10bf\\u2b23\\u10a8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2489\\udb40\\ude93=\\u0338\\uff61\\u10bf\\u2b23\\u10a8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"2.\\udb40\\ude93\\u2260\\u3002\\u10bf\\u2b23\\u10a8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"2.\\udb40\\ude93=\\u0338\\u3002\\u10bf\\u2b23\\u10a8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"2.\\udb40\\ude93=\\u0338\\u3002\\u2d1f\\u2b23\\u2d08\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"2.\\udb40\\ude93\\u2260\\u3002\\u2d1f\\u2b23\\u2d08\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"2.xn--1chz4101l.xn--45iz7d6b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2489\\udb40\\ude93=\\u0338\\uff61\\u2d1f\\u2b23\\u2d08\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2489\\udb40\\ude93\\u2260\\uff61\\u2d1f\\u2b23\\u2d08\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--1ch07f91401d.xn--45iz7d6b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"2.xn--1chz4101l.xn--gnd9b297j\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--1ch07f91401d.xn--gnd9b297j\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\ud83a\\udd37.\\ud802\\udf90\\ud83a\\udc81\\ud803\\ude60\\u0624\",\n    \"output\": \"xn--ve6h.xn--jgb1694kz0b2176a\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd37.\\ud802\\udf90\\ud83a\\udc81\\ud803\\ude60\\u0648\\u0654\",\n    \"output\": \"xn--ve6h.xn--jgb1694kz0b2176a\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd15.\\ud802\\udf90\\ud83a\\udc81\\ud803\\ude60\\u0648\\u0654\",\n    \"output\": \"xn--ve6h.xn--jgb1694kz0b2176a\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd15.\\ud802\\udf90\\ud83a\\udc81\\ud803\\ude60\\u0624\",\n    \"output\": \"xn--ve6h.xn--jgb1694kz0b2176a\"\n  },\n  {\n    \"input\": \"xn--ve6h.xn--jgb1694kz0b2176a\",\n    \"output\": \"xn--ve6h.xn--jgb1694kz0b2176a\"\n  },\n  {\n    \"comment\": \"V7; V3 (ignored); U1 (ignored)\",\n    \"input\": \"-\\udb40\\ude56\\ua867\\uff0e\\udb40\\ude82\\ud8dc\\udd83\\ud83c\\udd09\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored); U1 (ignored)\",\n    \"input\": \"-\\udb40\\ude56\\ua867.\\udb40\\ude82\\ud8dc\\udd838,\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored); U1 (ignored)\",\n    \"input\": \"xn----hg4ei0361g.xn--8,-k362evu488a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn----hg4ei0361g.xn--207ht163h7m94c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6\",\n    \"input\": \"\\u200c\\uff61\\u0354\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6\",\n    \"input\": \"\\u200c\\u3002\\u0354\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \".xn--yua\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6\",\n    \"input\": \"xn--0ug.xn--yua\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\ud83a\\udd25\\udb40\\udd6e\\uff0e\\u1844\\u10ae\",\n    \"output\": \"xn--de6h.xn--37e857h\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd25\\udb40\\udd6e.\\u1844\\u10ae\",\n    \"output\": \"xn--de6h.xn--37e857h\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd25\\udb40\\udd6e.\\u1844\\u2d0e\",\n    \"output\": \"xn--de6h.xn--37e857h\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd03\\udb40\\udd6e.\\u1844\\u10ae\",\n    \"output\": \"xn--de6h.xn--37e857h\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd03\\udb40\\udd6e.\\u1844\\u2d0e\",\n    \"output\": \"xn--de6h.xn--37e857h\"\n  },\n  {\n    \"input\": \"xn--de6h.xn--37e857h\",\n    \"output\": \"xn--de6h.xn--37e857h\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd25.\\u1844\\u2d0e\",\n    \"output\": \"xn--de6h.xn--37e857h\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd03.\\u1844\\u10ae\",\n    \"output\": \"xn--de6h.xn--37e857h\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd03.\\u1844\\u2d0e\",\n    \"output\": \"xn--de6h.xn--37e857h\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd25\\udb40\\udd6e\\uff0e\\u1844\\u2d0e\",\n    \"output\": \"xn--de6h.xn--37e857h\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd03\\udb40\\udd6e\\uff0e\\u1844\\u10ae\",\n    \"output\": \"xn--de6h.xn--37e857h\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd03\\udb40\\udd6e\\uff0e\\u1844\\u2d0e\",\n    \"output\": \"xn--de6h.xn--37e857h\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--de6h.xn--mnd799a\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\ud83a\\udd25.\\u1844\\u10ae\",\n    \"output\": \"xn--de6h.xn--37e857h\"\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u0fa4\\ud986\\udd2f\\uff0e\\ud835\\udfed\\u10bb\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u0fa4\\ud986\\udd2f.1\\u10bb\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u0fa4\\ud986\\udd2f.1\\u2d1b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--0fd40533g.xn--1-tws\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u0fa4\\ud986\\udd2f\\uff0e\\ud835\\udfed\\u2d1b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--0fd40533g.xn--1-q1g\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u03c2\\ud9d5\\udf0c\\uff18.\\ud83a\\udf64\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u03c2\\ud9d5\\udf0c8.\\ud83a\\udf64\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u03a3\\ud9d5\\udf0c8.\\ud83a\\udf64\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u03c3\\ud9d5\\udf0c8.\\ud83a\\udf64\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--8-zmb14974n.xn--su6h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--8-xmb44974n.xn--su6h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u03a3\\ud9d5\\udf0c\\uff18.\\ud83a\\udf64\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u03c3\\ud9d5\\udf0c\\uff18.\\ud83a\\udf64\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u200c\\uae03.\\u69b6-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u200c\\u1100\\u1173\\u11b2.\\u69b6-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"xn--ej0b.xn----d87b\",\n    \"output\": \"xn--ej0b.xn----d87b\"\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"xn--0ug3307c.xn----d87b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ub253\\u6cd3\\ud833\\udd7d.\\u09cd\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u1102\\u1170\\u11be\\u6cd3\\ud833\\udd7d.\\u09cd\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--lwwp69lqs7m.xn--b7b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--lwwp69lqs7m.xn--b7b605i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u1b44\\uff0e\\u1baa-\\u226e\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u1b44\\uff0e\\u1baa-<\\u0338=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u1b44.\\u1baa-\\u226e\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u1b44.\\u1baa-<\\u0338=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--1uf.xn----nmlz65aub\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u1bf3\\u10b1\\u115f\\uff0e\\ud804\\udd34\\u2132\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u1bf3\\u10b1\\u115f.\\ud804\\udd34\\u2132\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u1bf3\\u2d11\\u115f.\\ud804\\udd34\\u214e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u1bf3\\u10b1\\u115f.\\ud804\\udd34\\u214e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--1zf224e.xn--73g3065g\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u1bf3\\u2d11\\u115f\\uff0e\\ud804\\udd34\\u214e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u1bf3\\u10b1\\u115f\\uff0e\\ud804\\udd34\\u214e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--pnd26a55x.xn--73g3065g\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--osd925cvyn.xn--73g3065g\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--pnd26a55x.xn--f3g7465g\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u10a9\\u7315\\udba5\\udeeb\\u226e\\uff0e\\ufe12\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u10a9\\u7315\\udba5\\udeeb<\\u0338\\uff0e\\ufe12\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\u10a9\\u7315\\udba5\\udeeb\\u226e.\\u3002\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\u10a9\\u7315\\udba5\\udeeb<\\u0338.\\u3002\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\u2d09\\u7315\\udba5\\udeeb<\\u0338.\\u3002\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\u2d09\\u7315\\udba5\\udeeb\\u226e.\\u3002\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"xn--gdh892bbz0d5438s..\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2d09\\u7315\\udba5\\udeeb<\\u0338\\uff0e\\ufe12\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2d09\\u7315\\udba5\\udeeb\\u226e\\uff0e\\ufe12\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--gdh892bbz0d5438s.xn--y86c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"xn--hnd212gz32d54x5r..\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--hnd212gz32d54x5r.xn--y86c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u00c5\\ub444-\\uff0e\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"A\\u030a\\u1103\\u116d\\u11b7-\\uff0e\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u00c5\\ub444-.\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"A\\u030a\\u1103\\u116d\\u11b7-.\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"a\\u030a\\u1103\\u116d\\u11b7-.\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u00e5\\ub444-.\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"xn----1fa1788k.\",\n    \"output\": \"xn----1fa1788k.\"\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"xn----1fa1788k.xn--0ug\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"a\\u030a\\u1103\\u116d\\u11b7-\\uff0e\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u00e5\\ub444-\\uff0e\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V6; V7\",\n    \"input\": \"\\ub8f1\\u200d\\ud880\\udf68\\u200c\\u3002\\ud836\\ude16\\ufe12\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V6; V7\",\n    \"input\": \"\\u1105\\u116e\\u11b0\\u200d\\ud880\\udf68\\u200c\\u3002\\ud836\\ude16\\ufe12\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V6; A4_2 (ignored)\",\n    \"input\": \"\\ub8f1\\u200d\\ud880\\udf68\\u200c\\u3002\\ud836\\ude16\\u3002\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V6; A4_2 (ignored)\",\n    \"input\": \"\\u1105\\u116e\\u11b0\\u200d\\ud880\\udf68\\u200c\\u3002\\ud836\\ude16\\u3002\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"xn--ct2b0738h.xn--772h.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V6; A4_2 (ignored)\",\n    \"input\": \"xn--0ugb3358ili2v.xn--772h.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--ct2b0738h.xn--y86cl899a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V6; V7\",\n    \"input\": \"xn--0ugb3358ili2v.xn--y86cl899a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; U1 (ignored)\",\n    \"input\": \"\\ud83c\\udd04\\uff0e\\u1cdc\\u2488\\u00df\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; U1 (ignored)\",\n    \"input\": \"3,.\\u1cdc1.\\u00df\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; U1 (ignored)\",\n    \"input\": \"3,.\\u1cdc1.SS\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; U1 (ignored)\",\n    \"input\": \"3,.\\u1cdc1.ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; U1 (ignored)\",\n    \"input\": \"3,.\\u1cdc1.Ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; U1 (ignored)\",\n    \"input\": \"3,.xn--1-43l.ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; U1 (ignored)\",\n    \"input\": \"3,.xn--1-43l.xn--zca\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; U1 (ignored)\",\n    \"input\": \"\\ud83c\\udd04\\uff0e\\u1cdc\\u2488SS\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; U1 (ignored)\",\n    \"input\": \"\\ud83c\\udd04\\uff0e\\u1cdc\\u2488ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; U1 (ignored)\",\n    \"input\": \"\\ud83c\\udd04\\uff0e\\u1cdc\\u2488Ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; U1 (ignored)\",\n    \"input\": \"3,.xn--ss-k1r094b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; U1 (ignored)\",\n    \"input\": \"3,.xn--zca344lmif\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--x07h.xn--ss-k1r094b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--x07h.xn--zca344lmif\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u1dfd\\u103a\\u094d\\uff0e\\u2260\\u200d\\u31db\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u103a\\u094d\\u1dfd\\uff0e\\u2260\\u200d\\u31db\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u103a\\u094d\\u1dfd\\uff0e=\\u0338\\u200d\\u31db\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u103a\\u094d\\u1dfd.\\u2260\\u200d\\u31db\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u103a\\u094d\\u1dfd.=\\u0338\\u200d\\u31db\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--n3b956a9zm.xn--1ch912d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"xn--n3b956a9zm.xn--1ug63gz5w\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"\\u1bf3.-\\u900b\\ud98e\\uddad\\udb25\\ude6e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"xn--1zf.xn----483d46987byr50b\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--9ob.xn--4xa\",\n    \"output\": \"xn--9ob.xn--4xa\"\n  },\n  {\n    \"input\": \"\\u0756.\\u03c3\",\n    \"output\": \"xn--9ob.xn--4xa\"\n  },\n  {\n    \"input\": \"\\u0756.\\u03a3\",\n    \"output\": \"xn--9ob.xn--4xa\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--9ob.xn--4xa380e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--9ob.xn--4xa380ebol\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--9ob.xn--3xa580ebol\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--9ob.xn--4xa574u\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--9ob.xn--4xa795lq2l\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--9ob.xn--3xa995lq2l\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u1846\\u10a3\\uff61\\udb3a\\udca7\\u0315\\u200d\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u1846\\u10a3\\u3002\\udb3a\\udca7\\u0315\\u200d\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u1846\\u2d03\\u3002\\udb3a\\udca7\\u0315\\u200d\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--57e237h.xn--5sa98523p\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--57e237h.xn--5sa649la993427a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u1846\\u2d03\\uff61\\udb3a\\udca7\\u0315\\u200d\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--bnd320b.xn--5sa98523p\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--bnd320b.xn--5sa649la993427a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ud838\\udc28\\uff61\\u1b44\\uda45\\udee8\\ud838\\udf87\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ud838\\udc28\\u3002\\u1b44\\uda45\\udee8\\ud838\\udf87\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--mi4h.xn--1uf6843smg20c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u189b\\udb60\\udd5f\\u00df.\\u1327\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u189b\\udb60\\udd5fSS.\\u1327\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u189b\\udb60\\udd5fss.\\u1327\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u189b\\udb60\\udd5fSs.\\u1327\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--ss-7dp66033t.xn--p5d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--zca562jc642x.xn--p5d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u2b92\\u200c.\\ud909\\ude97\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--b9i.xn--5p9y\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--0ugx66b.xn--0ugz2871c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u226f\\ud805\\udf2b\\udb42\\udf47.\\u1734\\ud909\\udfa4\\ud804\\udf6c\\u18a7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \">\\u0338\\ud805\\udf2b\\udb42\\udf47.\\u1734\\ud909\\udfa4\\ud804\\udf6c\\u18a7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--hdhx157g68o0g.xn--c0e65eu616c34o7a\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\u00df\\uff61\\ud800\\udef3\\u10ac\\u0fb8\",\n    \"output\": \"xn--zca.xn--lgd921mvv0m\"\n  },\n  {\n    \"input\": \"\\u00df\\u3002\\ud800\\udef3\\u10ac\\u0fb8\",\n    \"output\": \"xn--zca.xn--lgd921mvv0m\"\n  },\n  {\n    \"input\": \"\\u00df\\u3002\\ud800\\udef3\\u2d0c\\u0fb8\",\n    \"output\": \"xn--zca.xn--lgd921mvv0m\"\n  },\n  {\n    \"input\": \"SS\\u3002\\ud800\\udef3\\u10ac\\u0fb8\",\n    \"output\": \"ss.xn--lgd921mvv0m\"\n  },\n  {\n    \"input\": \"ss\\u3002\\ud800\\udef3\\u2d0c\\u0fb8\",\n    \"output\": \"ss.xn--lgd921mvv0m\"\n  },\n  {\n    \"input\": \"Ss\\u3002\\ud800\\udef3\\u10ac\\u0fb8\",\n    \"output\": \"ss.xn--lgd921mvv0m\"\n  },\n  {\n    \"input\": \"ss.xn--lgd921mvv0m\",\n    \"output\": \"ss.xn--lgd921mvv0m\"\n  },\n  {\n    \"input\": \"ss.\\ud800\\udef3\\u2d0c\\u0fb8\",\n    \"output\": \"ss.xn--lgd921mvv0m\"\n  },\n  {\n    \"input\": \"SS.\\ud800\\udef3\\u10ac\\u0fb8\",\n    \"output\": \"ss.xn--lgd921mvv0m\"\n  },\n  {\n    \"input\": \"Ss.\\ud800\\udef3\\u10ac\\u0fb8\",\n    \"output\": \"ss.xn--lgd921mvv0m\"\n  },\n  {\n    \"input\": \"xn--zca.xn--lgd921mvv0m\",\n    \"output\": \"xn--zca.xn--lgd921mvv0m\"\n  },\n  {\n    \"input\": \"\\u00df.\\ud800\\udef3\\u2d0c\\u0fb8\",\n    \"output\": \"xn--zca.xn--lgd921mvv0m\"\n  },\n  {\n    \"input\": \"\\u00df\\uff61\\ud800\\udef3\\u2d0c\\u0fb8\",\n    \"output\": \"xn--zca.xn--lgd921mvv0m\"\n  },\n  {\n    \"input\": \"SS\\uff61\\ud800\\udef3\\u10ac\\u0fb8\",\n    \"output\": \"ss.xn--lgd921mvv0m\"\n  },\n  {\n    \"input\": \"ss\\uff61\\ud800\\udef3\\u2d0c\\u0fb8\",\n    \"output\": \"ss.xn--lgd921mvv0m\"\n  },\n  {\n    \"input\": \"Ss\\uff61\\ud800\\udef3\\u10ac\\u0fb8\",\n    \"output\": \"ss.xn--lgd921mvv0m\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"ss.xn--lgd10cu829c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--zca.xn--lgd10cu829c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u1a5a\\ud82e\\udd9d\\u0c4d\\u3002\\ud829\\udf6c\\ud835\\udff5\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u1a5a\\ud82e\\udd9d\\u0c4d\\u3002\\ud829\\udf6c9\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--lqc703ebm93a.xn--9-000p\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"\\u1856\\uff61\\u031f\\ud91d\\udee8\\u0b82-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"\\u1856\\u3002\\u031f\\ud91d\\udee8\\u0b82-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"xn--m8e.xn----mdb555dkk71m\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u0596\\u10ab\\uff0e\\ud835\\udff3\\u226f\\ufe12\\ufe0a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u0596\\u10ab\\uff0e\\ud835\\udff3>\\u0338\\ufe12\\ufe0a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"\\u0596\\u10ab.7\\u226f\\u3002\\ufe0a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"\\u0596\\u10ab.7>\\u0338\\u3002\\ufe0a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"\\u0596\\u2d0b.7>\\u0338\\u3002\\ufe0a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"\\u0596\\u2d0b.7\\u226f\\u3002\\ufe0a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"xn--hcb613r.xn--7-pgo.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u0596\\u2d0b\\uff0e\\ud835\\udff3>\\u0338\\ufe12\\ufe0a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u0596\\u2d0b\\uff0e\\ud835\\udff3\\u226f\\ufe12\\ufe0a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--hcb613r.xn--7-pgoy530h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; A4_2 (ignored)\",\n    \"input\": \"xn--hcb887c.xn--7-pgo.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--hcb887c.xn--7-pgoy530h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; U1 (ignored)\",\n    \"input\": \"\\ud83c\\udd07\\u4f10\\ufe12.\\ud831\\ude5a\\ua8c4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; U1 (ignored); A4_2 (ignored)\",\n    \"input\": \"6,\\u4f10\\u3002.\\ud831\\ude5a\\ua8c4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; U1 (ignored); A4_2 (ignored)\",\n    \"input\": \"xn--6,-7i3c..xn--0f9ao925c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; U1 (ignored)\",\n    \"input\": \"xn--6,-7i3cj157d.xn--0f9ao925c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--woqs083bel0g.xn--0f9ao925c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\udb40\\udda0\\uff0e\\ud99d\\udc34\\udaf1\\udfc8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\udb40\\udda0.\\ud99d\\udc34\\udaf1\\udfc8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \".xn--rx21bhv12i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"-.\\u1886\\udb47\\udca3-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"-.xn----pbkx6497q\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\udafd\\udcb0\\uff0e-\\ud835\\udffb\\u00df\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\udafd\\udcb0.-5\\u00df\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\udafd\\udcb0.-5SS\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\udafd\\udcb0.-5ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn--t960e.-5ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn--t960e.xn---5-hia\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\udafd\\udcb0\\uff0e-\\ud835\\udffbSS\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\udafd\\udcb0\\uff0e-\\ud835\\udffbss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\udafd\\udcb0\\uff0e-\\ud835\\udffbSs\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\udafd\\udcb0.-5Ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u200d\\ud802\\ude3f.\\ud83e\\udd12\\u10c5\\uda06\\udfb6\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u200d\\ud802\\ude3f.\\ud83e\\udd12\\u2d25\\uda06\\udfb6\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--0s9c.xn--tljz038l0gz4b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--1ug9533g.xn--tljz038l0gz4b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--0s9c.xn--9nd3211w0gz4b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--1ug9533g.xn--9nd3211w0gz4b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\ud894\\udec5\\u3002\\u00df\\ud873\\udd69\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\ud894\\udec5\\u3002SS\\ud873\\udd69\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\ud894\\udec5\\u3002ss\\ud873\\udd69\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\ud894\\udec5\\u3002Ss\\ud873\\udd69\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--ey1p.xn--ss-eq36b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--ey1p.xn--ss-n1tx0508a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--ey1p.xn--zca870nz438b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\udb40\\udd6f\\ud9df\\udf6d\\u200c\\ud83d\\udf2d\\uff61\\ud805\\uddbf\\u1abb\\u03c2\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\udb40\\udd6f\\ud9df\\udf6d\\u200c\\ud83d\\udf2d\\uff61\\ud805\\uddbf\\u1abb\\u03c2=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\udb40\\udd6f\\ud9df\\udf6d\\u200c\\ud83d\\udf2d\\u3002\\ud805\\uddbf\\u1abb\\u03c2\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\udb40\\udd6f\\ud9df\\udf6d\\u200c\\ud83d\\udf2d\\u3002\\ud805\\uddbf\\u1abb\\u03c2=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\udb40\\udd6f\\ud9df\\udf6d\\u200c\\ud83d\\udf2d\\u3002\\ud805\\uddbf\\u1abb\\u03a3=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\udb40\\udd6f\\ud9df\\udf6d\\u200c\\ud83d\\udf2d\\u3002\\ud805\\uddbf\\u1abb\\u03a3\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\udb40\\udd6f\\ud9df\\udf6d\\u200c\\ud83d\\udf2d\\u3002\\ud805\\uddbf\\u1abb\\u03c3\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\udb40\\udd6f\\ud9df\\udf6d\\u200c\\ud83d\\udf2d\\u3002\\ud805\\uddbf\\u1abb\\u03c3=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--zb9h5968x.xn--4xa378i1mfjw7y\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"xn--0ug3766p5nm1b.xn--4xa378i1mfjw7y\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"xn--0ug3766p5nm1b.xn--3xa578i1mfjw7y\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\udb40\\udd6f\\ud9df\\udf6d\\u200c\\ud83d\\udf2d\\uff61\\ud805\\uddbf\\u1abb\\u03a3=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\udb40\\udd6f\\ud9df\\udf6d\\u200c\\ud83d\\udf2d\\uff61\\ud805\\uddbf\\u1abb\\u03a3\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\udb40\\udd6f\\ud9df\\udf6d\\u200c\\ud83d\\udf2d\\uff61\\ud805\\uddbf\\u1abb\\u03c3\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\udb40\\udd6f\\ud9df\\udf6d\\u200c\\ud83d\\udf2d\\uff61\\ud805\\uddbf\\u1abb\\u03c3=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u248b\\uff61\\u2488\\u200d\\uda8f\\udd22\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; A4_2 (ignored)\",\n    \"input\": \"4.\\u30021.\\u200d\\uda8f\\udd22\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"4..1.xn--sf51d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; A4_2 (ignored)\",\n    \"input\": \"4..1.xn--1ug64613i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--wsh.xn--tsh07994h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--wsh.xn--1ug58o74922a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u10b3\\ud805\\udf2b\\u200d\\uda1e\\udf53\\uff0e\\u06a7\\ud807\\udc36\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u10b3\\ud805\\udf2b\\u200d\\uda1e\\udf53.\\u06a7\\ud807\\udc36\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2d13\\ud805\\udf2b\\u200d\\uda1e\\udf53.\\u06a7\\ud807\\udc36\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--blj6306ey091d.xn--9jb4223l\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--1ugy52cym7p7xu5e.xn--9jb4223l\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2d13\\ud805\\udf2b\\u200d\\uda1e\\udf53\\uff0e\\u06a7\\ud807\\udc36\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--rnd8945ky009c.xn--9jb4223l\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--rnd479ep20q7x12e.xn--9jb4223l\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; U1 (ignored)\",\n    \"input\": \"\\ud802\\ude3f.\\ud83c\\udd06\\u2014\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; U1 (ignored)\",\n    \"input\": \"\\ud802\\ude3f.5,\\u2014\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; U1 (ignored)\",\n    \"input\": \"xn--0s9c.xn--5,-81t\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--0s9c.xn--8ug8324p\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\uda10\\udeb1\\ud8c6\\uddae\\u06f8\\u3002\\udb43\\udfad-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn--lmb18944c0g2z.xn----2k81m\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud83d\\udf85\\udb43\\udce1\\udb30\\udf59.\\ud989\\uddb7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--ie9hi1349bqdlb.xn--oj69a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\u20e7\\ud97e\\udc4e-\\uda6e\\udcdd.4\\u10a4\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\u20e7\\ud97e\\udc4e-\\uda6e\\udcdd.4\\u2d04\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn----9snu5320fi76w.xn--4-ivs\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"xn----9snu5320fi76w.xn--4-sgn589c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn----9snu5320fi76w.xn--4-f0g\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"xn----9snu5320fi76w.xn--4-f0g649i\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\u16ad\\uff61\\ud834\\udf20\\u00df\\ud81a\\udef1\",\n    \"output\": \"xn--hwe.xn--zca4946pblnc\"\n  },\n  {\n    \"input\": \"\\u16ad\\u3002\\ud834\\udf20\\u00df\\ud81a\\udef1\",\n    \"output\": \"xn--hwe.xn--zca4946pblnc\"\n  },\n  {\n    \"input\": \"\\u16ad\\u3002\\ud834\\udf20SS\\ud81a\\udef1\",\n    \"output\": \"xn--hwe.xn--ss-ci1ub261a\"\n  },\n  {\n    \"input\": \"\\u16ad\\u3002\\ud834\\udf20ss\\ud81a\\udef1\",\n    \"output\": \"xn--hwe.xn--ss-ci1ub261a\"\n  },\n  {\n    \"input\": \"\\u16ad\\u3002\\ud834\\udf20Ss\\ud81a\\udef1\",\n    \"output\": \"xn--hwe.xn--ss-ci1ub261a\"\n  },\n  {\n    \"input\": \"xn--hwe.xn--ss-ci1ub261a\",\n    \"output\": \"xn--hwe.xn--ss-ci1ub261a\"\n  },\n  {\n    \"input\": \"\\u16ad.\\ud834\\udf20ss\\ud81a\\udef1\",\n    \"output\": \"xn--hwe.xn--ss-ci1ub261a\"\n  },\n  {\n    \"input\": \"\\u16ad.\\ud834\\udf20SS\\ud81a\\udef1\",\n    \"output\": \"xn--hwe.xn--ss-ci1ub261a\"\n  },\n  {\n    \"input\": \"\\u16ad.\\ud834\\udf20Ss\\ud81a\\udef1\",\n    \"output\": \"xn--hwe.xn--ss-ci1ub261a\"\n  },\n  {\n    \"input\": \"xn--hwe.xn--zca4946pblnc\",\n    \"output\": \"xn--hwe.xn--zca4946pblnc\"\n  },\n  {\n    \"input\": \"\\u16ad.\\ud834\\udf20\\u00df\\ud81a\\udef1\",\n    \"output\": \"xn--hwe.xn--zca4946pblnc\"\n  },\n  {\n    \"input\": \"\\u16ad\\uff61\\ud834\\udf20SS\\ud81a\\udef1\",\n    \"output\": \"xn--hwe.xn--ss-ci1ub261a\"\n  },\n  {\n    \"input\": \"\\u16ad\\uff61\\ud834\\udf20ss\\ud81a\\udef1\",\n    \"output\": \"xn--hwe.xn--ss-ci1ub261a\"\n  },\n  {\n    \"input\": \"\\u16ad\\uff61\\ud834\\udf20Ss\\ud81a\\udef1\",\n    \"output\": \"xn--hwe.xn--ss-ci1ub261a\"\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud805\\udc44\\u226f\\uff61\\ud805\\udf24\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud805\\udc44>\\u0338\\uff61\\ud805\\udf24\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud805\\udc44\\u226f\\u3002\\ud805\\udf24\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud805\\udc44>\\u0338\\u3002\\ud805\\udf24\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--hdh5636g.xn--ci2d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u10ab\\u226e\\ud887\\udc86\\u3002\\u200d\\u07a7\\ud800\\udee3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u10ab<\\u0338\\ud887\\udc86\\u3002\\u200d\\u07a7\\ud800\\udee3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u2d0b<\\u0338\\ud887\\udc86\\u3002\\u200d\\u07a7\\ud800\\udee3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u2d0b\\u226e\\ud887\\udc86\\u3002\\u200d\\u07a7\\ud800\\udee3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--gdhz03bxt42d.xn--lrb6479j\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"xn--gdhz03bxt42d.xn--lrb506jqr4n\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--jnd802gsm17c.xn--lrb6479j\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--jnd802gsm17c.xn--lrb506jqr4n\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u17d2.\\ud9db\\udf52\\u226f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u17d2.\\ud9db\\udf52>\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--u4e.xn--hdhx0084f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ud8fc\\udc47\\u1734\\uff0e\\ud802\\ude3a\\u00c9\\u2b13\\ud804\\udd34\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ud8fc\\udc47\\u1734\\uff0e\\ud802\\ude3aE\\u0301\\u2b13\\ud804\\udd34\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ud8fc\\udc47\\u1734.\\ud802\\ude3a\\u00c9\\u2b13\\ud804\\udd34\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ud8fc\\udc47\\u1734.\\ud802\\ude3aE\\u0301\\u2b13\\ud804\\udd34\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ud8fc\\udc47\\u1734.\\ud802\\ude3ae\\u0301\\u2b13\\ud804\\udd34\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ud8fc\\udc47\\u1734.\\ud802\\ude3a\\u00e9\\u2b13\\ud804\\udd34\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--c0e34564d.xn--9ca207st53lg3f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ud8fc\\udc47\\u1734\\uff0e\\ud802\\ude3ae\\u0301\\u2b13\\ud804\\udd34\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ud8fc\\udc47\\u1734\\uff0e\\ud802\\ude3a\\u00e9\\u2b13\\ud804\\udd34\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--09e4694e..xn--ye6h\",\n    \"output\": \"xn--09e4694e..xn--ye6h\"\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u10c3\\uff0e\\u0653\\u18a4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u10c3.\\u0653\\u18a4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u2d23.\\u0653\\u18a4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--rlj.xn--vhb294g\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u2d23\\uff0e\\u0653\\u18a4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--7nd.xn--vhb294g\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb40\\udd08\\u0813\\uff0e\\uc2c9\\ud9d0\\uddbb\\u10c4\\ud9ca\\udc50\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb40\\udd08\\u0813\\uff0e\\u1109\\u1174\\u11b0\\ud9d0\\uddbb\\u10c4\\ud9ca\\udc50\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb40\\udd08\\u0813.\\uc2c9\\ud9d0\\uddbb\\u10c4\\ud9ca\\udc50\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb40\\udd08\\u0813.\\u1109\\u1174\\u11b0\\ud9d0\\uddbb\\u10c4\\ud9ca\\udc50\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb40\\udd08\\u0813.\\u1109\\u1174\\u11b0\\ud9d0\\uddbb\\u2d24\\ud9ca\\udc50\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb40\\udd08\\u0813.\\uc2c9\\ud9d0\\uddbb\\u2d24\\ud9ca\\udc50\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--oub.xn--sljz109bpe25dviva\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb40\\udd08\\u0813\\uff0e\\u1109\\u1174\\u11b0\\ud9d0\\uddbb\\u2d24\\ud9ca\\udc50\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb40\\udd08\\u0813\\uff0e\\uc2c9\\ud9d0\\uddbb\\u2d24\\ud9ca\\udc50\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--oub.xn--8nd9522gpe69cviva\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\uaa2c\\ud807\\udcab\\u226e\\uff0e\\u2902\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\uaa2c\\ud807\\udcab<\\u0338\\uff0e\\u2902\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\uaa2c\\ud807\\udcab\\u226e.\\u2902\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\uaa2c\\ud807\\udcab<\\u0338.\\u2902\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--gdh1854cn19c.xn--kqi\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"\\ud804\\udc45\\u3002-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"xn--210d.-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"\\ua866\\u1851\\u200d\\u2488\\u3002\\ud800\\udee3-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"\\ua866\\u1851\\u200d1.\\u3002\\ud800\\udee3-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"xn--1-o7j0610f..xn----381i\",\n    \"output\": \"xn--1-o7j0610f..xn----381i\"\n  },\n  {\n    \"comment\": \"C2; V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"xn--1-o7j663bdl7m..xn----381i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn--h8e863drj7h.xn----381i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"xn--h8e470bl0d838o.xn----381i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"\\u2488\\u4c39\\u200d-\\u3002\\uc6c8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"\\u2488\\u4c39\\u200d-\\u3002\\u110b\\u116e\\u11bf\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"1.\\u4c39\\u200d-\\u3002\\uc6c8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"1.\\u4c39\\u200d-\\u3002\\u110b\\u116e\\u11bf\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"1.xn----zw5a.xn--kp5b\",\n    \"output\": \"1.xn----zw5a.xn--kp5b\"\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"1.xn----tgnz80r.xn--kp5b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn----dcp160o.xn--kp5b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"xn----tgnx5rjr6c.xn--kp5b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u3066\\u3002\\u200c\\udb43\\udcfd\\u07f3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--m9j.xn--rtb10784p\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--m9j.xn--rtb154j9l73w\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u03c2\\uff61\\ua9c0\\u06e7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u03c2\\u3002\\ua9c0\\u06e7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u03a3\\u3002\\ua9c0\\u06e7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u03c3\\u3002\\ua9c0\\u06e7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--4xa.xn--3lb1944f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--3xa.xn--3lb1944f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u03a3\\uff61\\ua9c0\\u06e7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u03c3\\uff61\\ua9c0\\u06e7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u0bcd\\udb56\\udec5\\ud9f0\\ude51.\\u10a2\\u10b5\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u0bcd\\udb56\\udec5\\ud9f0\\ude51.\\u2d02\\u2d15\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u0bcd\\udb56\\udec5\\ud9f0\\ude51.\\u10a2\\u2d15\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--xmc83135idcxza.xn--tkjwb\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--xmc83135idcxza.xn--9md086l\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--xmc83135idcxza.xn--9md2b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7; U1 (ignored)\",\n    \"input\": \"\\u1c32\\ud83c\\udd08\\u2f9b\\u05a6\\uff0e\\u200d\\uda7e\\udd64\\u07fd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7; U1 (ignored)\",\n    \"input\": \"\\u1c327,\\u8d70\\u05a6.\\u200d\\uda7e\\udd64\\u07fd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; U1 (ignored)\",\n    \"input\": \"xn--7,-bid991urn3k.xn--1tb13454l\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7; U1 (ignored)\",\n    \"input\": \"xn--7,-bid991urn3k.xn--1tb334j1197q\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--xcb756i493fwi5o.xn--1tb13454l\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"xn--xcb756i493fwi5o.xn--1tb334j1197q\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1897\\uff61\\u04c0\\ud934\\udd3b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1897\\u3002\\u04c0\\ud934\\udd3b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1897\\u3002\\u04cf\\ud934\\udd3b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--hbf.xn--s5a83117e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1897\\uff61\\u04cf\\ud934\\udd3b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--hbf.xn--d5a86117e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"-\\ud800\\udef7\\ud81b\\udf91\\u3002\\udb40\\uddac\",\n    \"output\": \"xn----991iq40y.\"\n  },\n  {\n    \"comment\": \"V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"xn----991iq40y.\",\n    \"output\": \"xn----991iq40y.\"\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud807\\udc98\\udb40\\udd12\\ud80d\\udc61\\uff61\\ud835\\udfea\\u10bc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud807\\udc98\\udb40\\udd12\\ud80d\\udc61\\u30028\\u10bc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud807\\udc98\\udb40\\udd12\\ud80d\\udc61\\u30028\\u2d1c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--7m3d291b.xn--8-vws\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud807\\udc98\\udb40\\udd12\\ud80d\\udc61\\uff61\\ud835\\udfea\\u2d1c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--7m3d291b.xn--8-s1g\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u1bab\\uff61\\ud83c\\udc89\\udb40\\udc70\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u1bab\\u3002\\ud83c\\udc89\\udb40\\udc70\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--zxf.xn--fx7ho0250c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\udb71\\udeb6\\udba0\\uded6\\uda1a\\ude70-\\u3002\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"xn----7i12hu122k9ire.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"xn----7i12hu122k9ire.xn--0ug\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ufe12\\uff0e\\ufe2f\\ud805\\udc42\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ufe12\\uff0e\\ud805\\udc42\\ufe2f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"\\u3002.\\ud805\\udc42\\ufe2f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"..xn--s96cu30b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--y86c.xn--s96cu30b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\ua92c\\u3002\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"xn--zi9a.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"xn--zi9a.xn--1ug\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\udb58\\ude04\\u3002-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn--xm38e.-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u22e0\\ud800\\udeee\\uff0e\\uda98\\ude2e\\u0f18\\u00df\\u226f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u227c\\u0338\\ud800\\udeee\\uff0e\\uda98\\ude2e\\u0f18\\u00df>\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u22e0\\ud800\\udeee.\\uda98\\ude2e\\u0f18\\u00df\\u226f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u227c\\u0338\\ud800\\udeee.\\uda98\\ude2e\\u0f18\\u00df>\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u227c\\u0338\\ud800\\udeee.\\uda98\\ude2e\\u0f18SS>\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u22e0\\ud800\\udeee.\\uda98\\ude2e\\u0f18SS\\u226f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u22e0\\ud800\\udeee.\\uda98\\ude2e\\u0f18ss\\u226f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u227c\\u0338\\ud800\\udeee.\\uda98\\ude2e\\u0f18ss>\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u227c\\u0338\\ud800\\udeee.\\uda98\\ude2e\\u0f18Ss>\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u22e0\\ud800\\udeee.\\uda98\\ude2e\\u0f18Ss\\u226f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--pgh4639f.xn--ss-ifj426nle504a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--pgh4639f.xn--zca593eo6oc013y\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u227c\\u0338\\ud800\\udeee\\uff0e\\uda98\\ude2e\\u0f18SS>\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u22e0\\ud800\\udeee\\uff0e\\uda98\\ude2e\\u0f18SS\\u226f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u22e0\\ud800\\udeee\\uff0e\\uda98\\ude2e\\u0f18ss\\u226f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u227c\\u0338\\ud800\\udeee\\uff0e\\uda98\\ude2e\\u0f18ss>\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u227c\\u0338\\ud800\\udeee\\uff0e\\uda98\\ude2e\\u0f18Ss>\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u22e0\\ud800\\udeee\\uff0e\\uda98\\ude2e\\u0f18Ss\\u226f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u0330\\uff0e\\udb81\\udf31\\u8680\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u0330.\\udb81\\udf31\\u8680\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--xta.xn--e91aw9417e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; U1 (ignored)\",\n    \"input\": \"\\ud83e\\udc9f\\ud83c\\udd08\\u200d\\ua84e\\uff61\\u0f84\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; U1 (ignored)\",\n    \"input\": \"\\ud83e\\udc9f7,\\u200d\\ua84e\\u3002\\u0f84\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; U1 (ignored)\",\n    \"input\": \"xn--7,-gh9hg322i.xn--3ed\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; U1 (ignored)\",\n    \"input\": \"xn--7,-n1t0654eqo3o.xn--3ed\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--nc9aq743ds0e.xn--3ed\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"xn--1ug4874cfd0kbmg.xn--3ed\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ua854\\u3002\\u1039\\u1887\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--tc9a.xn--9jd663b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u20eb\\u226e.\\ud836\\ude16\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u20eb<\\u0338.\\ud836\\ude16\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--e1g71d.xn--772h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u200c.\\u226f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u200c.>\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \".xn--hdh\",\n    \"output\": \".xn--hdh\"\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"xn--0ug.xn--hdh\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"\\ud880\\udd67\\ud94e\\ude60-\\uff0e\\uabed-\\u609c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"\\ud880\\udd67\\ud94e\\ude60-.\\uabed-\\u609c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"xn----7m53aj640l.xn----8f4br83t\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"\\u1849\\ud899\\udce7\\u2b1e\\u189c.-\\u200d\\ud83a\\udcd1\\u202e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn--87e0ol04cdl39e.xn----qinu247r\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"xn--87e0ol04cdl39e.xn----ugn5e3763s\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\ud83a\\udd53\\uff0e\\u0718\",\n    \"output\": \"xn--of6h.xn--inb\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd53.\\u0718\",\n    \"output\": \"xn--of6h.xn--inb\"\n  },\n  {\n    \"input\": \"xn--of6h.xn--inb\",\n    \"output\": \"xn--of6h.xn--inb\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"\\udb40\\udd3d-\\uff0e-\\u0dca\",\n    \"output\": \"-.xn----ptf\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"\\udb40\\udd3d-.-\\u0dca\",\n    \"output\": \"-.xn----ptf\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"-.xn----ptf\",\n    \"output\": \"-.xn----ptf\"\n  },\n  {\n    \"input\": \"\\u10ba\\ud800\\udef8\\udb40\\udd04\\u3002\\ud835\\udfdd\\ud7f6\\u103a\",\n    \"output\": \"xn--ilj2659d.xn--5-dug9054m\"\n  },\n  {\n    \"input\": \"\\u10ba\\ud800\\udef8\\udb40\\udd04\\u30025\\ud7f6\\u103a\",\n    \"output\": \"xn--ilj2659d.xn--5-dug9054m\"\n  },\n  {\n    \"input\": \"\\u2d1a\\ud800\\udef8\\udb40\\udd04\\u30025\\ud7f6\\u103a\",\n    \"output\": \"xn--ilj2659d.xn--5-dug9054m\"\n  },\n  {\n    \"input\": \"xn--ilj2659d.xn--5-dug9054m\",\n    \"output\": \"xn--ilj2659d.xn--5-dug9054m\"\n  },\n  {\n    \"input\": \"\\u2d1a\\ud800\\udef8.5\\ud7f6\\u103a\",\n    \"output\": \"xn--ilj2659d.xn--5-dug9054m\"\n  },\n  {\n    \"input\": \"\\u10ba\\ud800\\udef8.5\\ud7f6\\u103a\",\n    \"output\": \"xn--ilj2659d.xn--5-dug9054m\"\n  },\n  {\n    \"input\": \"\\u2d1a\\ud800\\udef8\\udb40\\udd04\\u3002\\ud835\\udfdd\\ud7f6\\u103a\",\n    \"output\": \"xn--ilj2659d.xn--5-dug9054m\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--ynd2415j.xn--5-dug9054m\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; U1 (ignored)\",\n    \"input\": \"\\u200d-\\u1839\\ufe6a.\\u1de1\\u1922\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; U1 (ignored)\",\n    \"input\": \"\\u200d-\\u1839%.\\u1de1\\u1922\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored); U1 (ignored)\",\n    \"input\": \"xn---%-u4o.xn--gff52t\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; U1 (ignored)\",\n    \"input\": \"xn---%-u4oy48b.xn--gff52t\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"xn----c6jx047j.xn--gff52t\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"xn----c6j614b1z4v.xn--gff52t\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\u2260.\\u183f\",\n    \"output\": \"xn--1ch.xn--y7e\"\n  },\n  {\n    \"input\": \"=\\u0338.\\u183f\",\n    \"output\": \"xn--1ch.xn--y7e\"\n  },\n  {\n    \"input\": \"xn--1ch.xn--y7e\",\n    \"output\": \"xn--1ch.xn--y7e\"\n  },\n  {\n    \"input\": \"\\u0723\\u05a3\\uff61\\u332a\",\n    \"output\": \"xn--ucb18e.xn--eck4c5a\"\n  },\n  {\n    \"input\": \"\\u0723\\u05a3\\u3002\\u30cf\\u30a4\\u30c4\",\n    \"output\": \"xn--ucb18e.xn--eck4c5a\"\n  },\n  {\n    \"input\": \"xn--ucb18e.xn--eck4c5a\",\n    \"output\": \"xn--ucb18e.xn--eck4c5a\"\n  },\n  {\n    \"input\": \"\\u0723\\u05a3.\\u30cf\\u30a4\\u30c4\",\n    \"output\": \"xn--ucb18e.xn--eck4c5a\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud84e\\ude6b\\uff0e\\ud9f1\\udc72\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud84e\\ude6b.\\ud9f1\\udc72\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--td3j.xn--4628b\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--skb\",\n    \"output\": \"xn--skb\"\n  },\n  {\n    \"input\": \"\\u06b9\",\n    \"output\": \"xn--skb\"\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"\\u0c4d\\ud836\\ude3e\\u05a9\\ud835\\udfed\\u3002-\\ud805\\udf28\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"\\u0c4d\\ud836\\ude3e\\u05a91\\u3002-\\ud805\\udf28\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"xn--1-rfc312cdp45c.xn----nq0j\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\uda4f\\udfc8\\u3002\\ub64f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\uda4f\\udfc8\\u3002\\u1104\\u116b\\u11ae\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--ph26c.xn--281b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud916\\ude1a\\udb40\\udd0c\\udb07\\udf40\\u1840.\\u08b6\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--z7e98100evc01b.xn--czb\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u200d\\uff61\\ud8d4\\udc5b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u200d\\u3002\\ud8d4\\udc5b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \".xn--6x4u\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--1ug.xn--6x4u\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\ufff9\\u200c\\uff61\\u66f3\\u2f91\\ud800\\udef0\\u226f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\ufff9\\u200c\\uff61\\u66f3\\u2f91\\ud800\\udef0>\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\ufff9\\u200c\\u3002\\u66f3\\u897e\\ud800\\udef0\\u226f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\ufff9\\u200c\\u3002\\u66f3\\u897e\\ud800\\udef0>\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--vn7c.xn--hdh501y8wvfs5h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--0ug2139f.xn--hdh501y8wvfs5h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u226f\\u2488\\u3002\\u00df\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \">\\u0338\\u2488\\u3002\\u00df\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u226f1.\\u3002\\u00df\",\n    \"output\": \"xn--1-ogo..xn--zca\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \">\\u03381.\\u3002\\u00df\",\n    \"output\": \"xn--1-ogo..xn--zca\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \">\\u03381.\\u3002SS\",\n    \"output\": \"xn--1-ogo..ss\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u226f1.\\u3002SS\",\n    \"output\": \"xn--1-ogo..ss\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u226f1.\\u3002ss\",\n    \"output\": \"xn--1-ogo..ss\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \">\\u03381.\\u3002ss\",\n    \"output\": \"xn--1-ogo..ss\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \">\\u03381.\\u3002Ss\",\n    \"output\": \"xn--1-ogo..ss\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u226f1.\\u3002Ss\",\n    \"output\": \"xn--1-ogo..ss\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--1-ogo..ss\",\n    \"output\": \"xn--1-ogo..ss\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--1-ogo..xn--zca\",\n    \"output\": \"xn--1-ogo..xn--zca\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \">\\u0338\\u2488\\u3002SS\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u226f\\u2488\\u3002SS\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u226f\\u2488\\u3002ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \">\\u0338\\u2488\\u3002ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \">\\u0338\\u2488\\u3002Ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u226f\\u2488\\u3002Ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--hdh84f.ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--hdh84f.xn--zca\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u200c\\uff61\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u200c\\uff61=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u200c\\u3002\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u200c\\u3002=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \".xn--1ch\",\n    \"output\": \".xn--1ch\"\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"xn--0ug.xn--1ch\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6\",\n    \"input\": \"\\ud805\\uddbf\\ud836\\ude14.\\u185f\\ud805\\uddbf\\u1b42\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--461dw464a.xn--v8e29loy65a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6\",\n    \"input\": \"xn--461dw464a.xn--v8e29ldzfo952a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7; V3 (ignored)\",\n    \"input\": \"\\uda12\\udcf3\\u200d\\uda05\\udf71.\\ud81a\\udf34\\u2183\\u2260-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7; V3 (ignored)\",\n    \"input\": \"\\uda12\\udcf3\\u200d\\uda05\\udf71.\\ud81a\\udf34\\u2183=\\u0338-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7; V3 (ignored)\",\n    \"input\": \"\\uda12\\udcf3\\u200d\\uda05\\udf71.\\ud81a\\udf34\\u2184=\\u0338-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7; V3 (ignored)\",\n    \"input\": \"\\uda12\\udcf3\\u200d\\uda05\\udf71.\\ud81a\\udf34\\u2184\\u2260-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"xn--6j00chy9a.xn----81n51bt713h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7; V3 (ignored)\",\n    \"input\": \"xn--1ug15151gkb5a.xn----81n51bt713h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"xn--6j00chy9a.xn----61n81bt713h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7; V3 (ignored)\",\n    \"input\": \"xn--1ug15151gkb5a.xn----61n81bt713h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u200d\\u252e\\udb40\\uddd0\\uff0e\\u0c00\\u0c4d\\u1734\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u200d\\u252e\\udb40\\uddd0.\\u0c00\\u0c4d\\u1734\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--kxh.xn--eoc8m432a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"xn--1ug04r.xn--eoc8m432a40i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; U1 (ignored)\",\n    \"input\": \"\\udaa5\\udeaa\\uff61\\ud83c\\udd02\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; U1 (ignored)\",\n    \"input\": \"\\udaa5\\udeaa\\u30021,\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; U1 (ignored)\",\n    \"input\": \"xn--n433d.1,\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--n433d.xn--v07h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud804\\udf68\\u520d.\\ud83d\\udee6\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--rbry728b.xn--y88h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\udb40\\udf0f3\\uff61\\u1bf1\\ud835\\udfd2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\udb40\\udf0f3\\u3002\\u1bf14\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--3-ib31m.xn--4-pql\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ua87d\\u226f\\uff0e\\udaaf\\udc80\\uda0b\\udcc4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ua87d>\\u0338\\uff0e\\udaaf\\udc80\\uda0b\\udcc4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ua87d\\u226f.\\udaaf\\udc80\\uda0b\\udcc4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ua87d>\\u0338.\\udaaf\\udc80\\uda0b\\udcc4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--hdh8193c.xn--5z40cp629b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\udb43\\udcdb\\uff0e\\u200d\\u492b\\u2260\\u10be\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\udb43\\udcdb\\uff0e\\u200d\\u492b=\\u0338\\u10be\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\udb43\\udcdb.\\u200d\\u492b\\u2260\\u10be\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\udb43\\udcdb.\\u200d\\u492b=\\u0338\\u10be\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\udb43\\udcdb.\\u200d\\u492b=\\u0338\\u2d1e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\udb43\\udcdb.\\u200d\\u492b\\u2260\\u2d1e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--1t56e.xn--1ch153bqvw\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--1t56e.xn--1ug73gzzpwi3a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\udb43\\udcdb\\uff0e\\u200d\\u492b=\\u0338\\u2d1e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\udb43\\udcdb\\uff0e\\u200d\\u492b\\u2260\\u2d1e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--1t56e.xn--2nd141ghl2a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--1t56e.xn--2nd159e9vb743e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"3.1.xn--110d.j\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--tshd3512p.j\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u034a\\uff0e\\ud802\\ude0e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u034a.\\ud802\\ude0e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--oua.xn--mr9c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud6c9\\u226e\\uff61\\u0e34\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u1112\\u116e\\u11ac<\\u0338\\uff61\\u0e34\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud6c9\\u226e\\u3002\\u0e34\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u1112\\u116e\\u11ac<\\u0338\\u3002\\u0e34\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--gdh2512e.xn--i4c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"\\ua846\\u3002\\u2183\\u0fb5\\ub1ae-\",\n    \"output\": \"xn--fc9a.xn----qmg097k469k\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"\\ua846\\u3002\\u2183\\u0fb5\\u1102\\u116a\\u11c1-\",\n    \"output\": \"xn--fc9a.xn----qmg097k469k\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"\\ua846\\u3002\\u2184\\u0fb5\\u1102\\u116a\\u11c1-\",\n    \"output\": \"xn--fc9a.xn----qmg097k469k\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"\\ua846\\u3002\\u2184\\u0fb5\\ub1ae-\",\n    \"output\": \"xn--fc9a.xn----qmg097k469k\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"xn--fc9a.xn----qmg097k469k\",\n    \"output\": \"xn--fc9a.xn----qmg097k469k\"\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn--fc9a.xn----qmg787k869k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u226e\\ud834\\udd76\\uff0e\\ud987\\udc81\\uaaec\\u2e48\\udb82\\udd6d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"<\\u0338\\ud834\\udd76\\uff0e\\ud987\\udc81\\uaaec\\u2e48\\udb82\\udd6d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u226e\\ud834\\udd76.\\ud987\\udc81\\uaaec\\u2e48\\udb82\\udd6d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"<\\u0338\\ud834\\udd76.\\ud987\\udc81\\uaaec\\u2e48\\udb82\\udd6d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--gdh.xn--4tjx101bsg00ds9pyc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--gdh0880o.xn--4tjx101bsg00ds9pyc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\ud805\\udc42\\uff61\\u200d\\udb55\\udf80\\ud83d\\udf95\\uda54\\udc54\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\ud805\\udc42\\u3002\\u200d\\udb55\\udf80\\ud83d\\udf95\\uda54\\udc54\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--8v1d.xn--ye9h41035a2qqs\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"xn--8v1d.xn--1ug1386plvx1cd8vya\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\u00df\\u09c1\\u1ded\\u3002\\u06208\\u2085\",\n    \"output\": \"xn--zca266bwrr.xn--85-psd\"\n  },\n  {\n    \"input\": \"\\u00df\\u09c1\\u1ded\\u3002\\u062085\",\n    \"output\": \"xn--zca266bwrr.xn--85-psd\"\n  },\n  {\n    \"input\": \"SS\\u09c1\\u1ded\\u3002\\u062085\",\n    \"output\": \"xn--ss-e2f077r.xn--85-psd\"\n  },\n  {\n    \"input\": \"ss\\u09c1\\u1ded\\u3002\\u062085\",\n    \"output\": \"xn--ss-e2f077r.xn--85-psd\"\n  },\n  {\n    \"input\": \"Ss\\u09c1\\u1ded\\u3002\\u062085\",\n    \"output\": \"xn--ss-e2f077r.xn--85-psd\"\n  },\n  {\n    \"input\": \"xn--ss-e2f077r.xn--85-psd\",\n    \"output\": \"xn--ss-e2f077r.xn--85-psd\"\n  },\n  {\n    \"input\": \"ss\\u09c1\\u1ded.\\u062085\",\n    \"output\": \"xn--ss-e2f077r.xn--85-psd\"\n  },\n  {\n    \"input\": \"SS\\u09c1\\u1ded.\\u062085\",\n    \"output\": \"xn--ss-e2f077r.xn--85-psd\"\n  },\n  {\n    \"input\": \"Ss\\u09c1\\u1ded.\\u062085\",\n    \"output\": \"xn--ss-e2f077r.xn--85-psd\"\n  },\n  {\n    \"input\": \"xn--zca266bwrr.xn--85-psd\",\n    \"output\": \"xn--zca266bwrr.xn--85-psd\"\n  },\n  {\n    \"input\": \"\\u00df\\u09c1\\u1ded.\\u062085\",\n    \"output\": \"xn--zca266bwrr.xn--85-psd\"\n  },\n  {\n    \"input\": \"SS\\u09c1\\u1ded\\u3002\\u06208\\u2085\",\n    \"output\": \"xn--ss-e2f077r.xn--85-psd\"\n  },\n  {\n    \"input\": \"ss\\u09c1\\u1ded\\u3002\\u06208\\u2085\",\n    \"output\": \"xn--ss-e2f077r.xn--85-psd\"\n  },\n  {\n    \"input\": \"Ss\\u09c1\\u1ded\\u3002\\u06208\\u2085\",\n    \"output\": \"xn--ss-e2f077r.xn--85-psd\"\n  },\n  {\n    \"input\": \"\\ufe0d\\u0a9b\\u3002\\u5d68\",\n    \"output\": \"xn--6dc.xn--tot\"\n  },\n  {\n    \"input\": \"xn--6dc.xn--tot\",\n    \"output\": \"xn--6dc.xn--tot\"\n  },\n  {\n    \"input\": \"\\u0a9b.\\u5d68\",\n    \"output\": \"xn--6dc.xn--tot\"\n  },\n  {\n    \"comment\": \"C1; V6; V7; V3 (ignored)\",\n    \"input\": \"-\\u200c\\u2499\\ud802\\udee5\\uff61\\ud836\\ude35\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V3 (ignored)\",\n    \"input\": \"-\\u200c18.\\ud802\\udee5\\u3002\\ud836\\ude35\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"-18.xn--rx9c.xn--382h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V3 (ignored)\",\n    \"input\": \"xn---18-9m0a.xn--rx9c.xn--382h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"xn----ddps939g.xn--382h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7; V3 (ignored)\",\n    \"input\": \"xn----sgn18r3191a.xn--382h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ufe05\\ufe12\\u3002\\ud858\\udc3e\\u1ce0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\ufe05\\u3002\\u3002\\ud858\\udc3e\\u1ce0\",\n    \"output\": \"..xn--t6f5138v\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"..xn--t6f5138v\",\n    \"output\": \"..xn--t6f5138v\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--y86c.xn--t6f5138v\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--t6f5138v\",\n    \"output\": \"xn--t6f5138v\"\n  },\n  {\n    \"input\": \"\\ud858\\udc3e\\u1ce0\",\n    \"output\": \"xn--t6f5138v\"\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\udb41\\udd4f\\uff0e-\\u00df\\u200c\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\udb41\\udd4f\\uff0e-\\u00df\\u200c=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\udb41\\udd4f.-\\u00df\\u200c\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\udb41\\udd4f.-\\u00df\\u200c=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\udb41\\udd4f.-SS\\u200c=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\udb41\\udd4f.-SS\\u200c\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\udb41\\udd4f.-ss\\u200c\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\udb41\\udd4f.-ss\\u200c=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\udb41\\udd4f.-Ss\\u200c=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\udb41\\udd4f.-Ss\\u200c\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn--u836e.xn---ss-gl2a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"xn--u836e.xn---ss-cn0at5l\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"xn--u836e.xn----qfa750ve7b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\udb41\\udd4f\\uff0e-SS\\u200c=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\udb41\\udd4f\\uff0e-SS\\u200c\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\udb41\\udd4f\\uff0e-ss\\u200c\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\udb41\\udd4f\\uff0e-ss\\u200c=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\udb41\\udd4f\\uff0e-Ss\\u200c=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\udb41\\udd4f\\uff0e-Ss\\u200c\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u1859\\u200c\\uff61\\u226f\\ud800\\udef2\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u1859\\u200c\\uff61>\\u0338\\ud800\\udef2=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u1859\\u200c\\u3002\\u226f\\ud800\\udef2\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u1859\\u200c\\u3002>\\u0338\\ud800\\udef2=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--p8e.xn--1ch3a7084l\",\n    \"output\": \"xn--p8e.xn--1ch3a7084l\"\n  },\n  {\n    \"input\": \"\\u1859.\\u226f\\ud800\\udef2\\u2260\",\n    \"output\": \"xn--p8e.xn--1ch3a7084l\"\n  },\n  {\n    \"input\": \"\\u1859.>\\u0338\\ud800\\udef2=\\u0338\",\n    \"output\": \"xn--p8e.xn--1ch3a7084l\"\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"xn--p8e650b.xn--1ch3a7084l\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\uda7b\\udd5b\\u0613.\\u10b5\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\uda7b\\udd5b\\u0613.\\u2d15\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--1fb94204l.xn--dlj\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--1fb94204l.xn--tnd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u200c\\udb40\\udd37\\uff61\\uda09\\udc41\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u200c\\udb40\\udd37\\u3002\\uda09\\udc41\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \".xn--w720c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--0ug.xn--w720c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u2488\\u0dd6\\u7105.\\udb1e\\udc59\\u200d\\ua85f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"1.\\u0dd6\\u7105.\\udb1e\\udc59\\u200d\\ua85f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"1.xn--t1c6981c.xn--4c9a21133d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"1.xn--t1c6981c.xn--1ugz184c9lw7i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--t1c337io97c.xn--4c9a21133d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--t1c337io97c.xn--1ugz184c9lw7i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud804\\uddc0\\u258d.\\u205e\\u1830\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--9zh3057f.xn--j7e103b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"-3.\\u200d\\u30cc\\u1895\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"-3.xn--fbf115j\",\n    \"output\": \"-3.xn--fbf115j\"\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"-3.xn--fbf739aq5o\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u2132\\u17d2\\u200d\\uff61\\u2260\\u200d\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u2132\\u17d2\\u200d\\uff61=\\u0338\\u200d\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u2132\\u17d2\\u200d\\u3002\\u2260\\u200d\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u2132\\u17d2\\u200d\\u3002=\\u0338\\u200d\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u214e\\u17d2\\u200d\\u3002=\\u0338\\u200d\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u214e\\u17d2\\u200d\\u3002\\u2260\\u200d\\u200c\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--u4e969b.xn--1ch\",\n    \"output\": \"xn--u4e969b.xn--1ch\"\n  },\n  {\n    \"input\": \"\\u214e\\u17d2.\\u2260\",\n    \"output\": \"xn--u4e969b.xn--1ch\"\n  },\n  {\n    \"input\": \"\\u214e\\u17d2.=\\u0338\",\n    \"output\": \"xn--u4e969b.xn--1ch\"\n  },\n  {\n    \"input\": \"\\u2132\\u17d2.=\\u0338\",\n    \"output\": \"xn--u4e969b.xn--1ch\"\n  },\n  {\n    \"input\": \"\\u2132\\u17d2.\\u2260\",\n    \"output\": \"xn--u4e969b.xn--1ch\"\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"xn--u4e823bq1a.xn--0ugb89o\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u214e\\u17d2\\u200d\\uff61=\\u0338\\u200d\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u214e\\u17d2\\u200d\\uff61\\u2260\\u200d\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--u4e319b.xn--1ch\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V7\",\n    \"input\": \"xn--u4e823bcza.xn--0ugb89o\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud9a9\\udd2f\\u0fa8\\uff0e\\u226f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud9a9\\udd2f\\u0fa8\\uff0e>\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud9a9\\udd2f\\u0fa8.\\u226f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud9a9\\udd2f\\u0fa8.>\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--4fd57150h.xn--hdh\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud802\\ude3f\\udb40\\udd8c\\u9e2e\\ud805\\udeb6.\\u03c2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud802\\ude3f\\udb40\\udd8c\\u9e2e\\ud805\\udeb6.\\u03a3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud802\\ude3f\\udb40\\udd8c\\u9e2e\\ud805\\udeb6.\\u03c3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--l76a726rt2h.xn--4xa\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--l76a726rt2h.xn--3xa\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u03c2-\\u3002\\u200c\\ud835\\udfed-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u03c2-\\u3002\\u200c1-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u03a3-\\u3002\\u200c1-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u03c3-\\u3002\\u200c1-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"xn----zmb.1-\",\n    \"output\": \"xn----zmb.1-\"\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"xn----zmb.xn--1--i1t\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"xn----xmb.xn--1--i1t\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u03a3-\\u3002\\u200c\\ud835\\udfed-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u03c3-\\u3002\\u200c\\ud835\\udfed-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u1734-\\u0ce2\\uff0e\\udb40\\udd29\\u10a4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u1734-\\u0ce2.\\udb40\\udd29\\u10a4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u1734-\\u0ce2.\\udb40\\udd29\\u2d04\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn----ggf830f.xn--vkj\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u1734-\\u0ce2\\uff0e\\udb40\\udd29\\u2d04\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn----ggf830f.xn--cnd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\u200d\\u3002\\ud838\\udc18\\u2488\\ua84d\\u64c9\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u200d\\u3002\\ud838\\udc181.\\ua84d\\u64c9\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \".xn--1-1p4r.xn--s7uv61m\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"xn--1ug.xn--1-1p4r.xn--s7uv61m\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; A4_2 (ignored)\",\n    \"input\": \".xn--tsh026uql4bew9p\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"xn--1ug.xn--tsh026uql4bew9p\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2ad0\\uff61\\u10c0-\\udacd\\udc22\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2ad0\\u3002\\u10c0-\\udacd\\udc22\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2ad0\\u3002\\u2d20-\\udacd\\udc22\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--r3i.xn----2wst7439i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2ad0\\uff61\\u2d20-\\udacd\\udc22\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--r3i.xn----z1g58579u\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud805\\udc42\\u25ca\\uff0e\\u299f\\u2220\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud805\\udc42\\u25ca.\\u299f\\u2220\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--01h3338f.xn--79g270a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud5c1\\udb21\\udd99\\u0e3a\\udb28\\udf5a\\u3002\\u06ba\\ud835\\udfdc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1112\\u1164\\u11bc\\udb21\\udd99\\u0e3a\\udb28\\udf5a\\u3002\\u06ba\\ud835\\udfdc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud5c1\\udb21\\udd99\\u0e3a\\udb28\\udf5a\\u3002\\u06ba4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1112\\u1164\\u11bc\\udb21\\udd99\\u0e3a\\udb28\\udf5a\\u3002\\u06ba4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--o4c1723h8g85gt4ya.xn--4-dvc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ua953.\\u033d\\ud804\\udcbd\\u998b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--3j9a.xn--bua0708eqzrd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\udae2\\udedd\\uda69\\udef8\\u200d\\uff61\\u4716\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\udae2\\udedd\\uda69\\udef8\\u200d\\u3002\\u4716\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--g138cxw05a.xn--k0o\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--1ug30527h9mxi.xn--k0o\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; U1 (ignored)\",\n    \"input\": \"\\u186f\\u2689\\u59f6\\ud83c\\udd09\\uff0e\\u06f7\\u200d\\ud83c\\udfaa\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; U1 (ignored)\",\n    \"input\": \"\\u186f\\u2689\\u59f68,.\\u06f7\\u200d\\ud83c\\udfaa\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"U1 (ignored)\",\n    \"input\": \"xn--8,-g9oy26fzu4d.xn--kmb6733w\",\n    \"output\": \"xn--8,-g9oy26fzu4d.xn--kmb6733w\"\n  },\n  {\n    \"comment\": \"C2; U1 (ignored)\",\n    \"input\": \"xn--8,-g9oy26fzu4d.xn--kmb859ja94998b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--c9e433epi4b3j20a.xn--kmb6733w\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--c9e433epi4b3j20a.xn--kmb859ja94998b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7; V3 (ignored)\",\n    \"input\": \"\\u135f\\u1848\\u200c\\uff0e\\ufe12-\\ud81b\\udf90-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"\\u135f\\u1848\\u200c.\\u3002-\\ud81b\\udf90-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"xn--b7d82w..xn-----pe4u\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"xn--b7d82wo4h..xn-----pe4u\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"xn--b7d82w.xn-----c82nz547a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7; V3 (ignored)\",\n    \"input\": \"xn--b7d82wo4h.xn-----c82nz547a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"\\ud836\\ude5c\\u3002-\\u0b4d\\u10ab\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"\\ud836\\ude5c\\u3002-\\u0b4d\\u2d0b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"xn--792h.xn----bse820x\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"xn--792h.xn----bse632b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\ud835\\udff5\\u9681\\u2bee\\uff0e\\u180d\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"9\\u9681\\u2bee.\\u180d\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--9-mfs8024b.\",\n    \"output\": \"xn--9-mfs8024b.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"9\\u9681\\u2bee.\",\n    \"output\": \"xn--9-mfs8024b.\"\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"xn--9-mfs8024b.xn--0ug\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6\",\n    \"input\": \"\\u1bac\\u10ac\\u200c\\u0325\\u3002\\ud835\\udff8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--mta176jjjm.c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6\",\n    \"input\": \"xn--mta176j97cl2q.c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6\",\n    \"input\": \"\\u1bac\\u2d0c\\u200c\\u0325\\u3002\\ud835\\udff8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--mta930emri.c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"xn--mta930emribme.c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\udb40\\udd01\\u035f\\u2fb6\\uff61\\u2087\\ufe12\\ub207\\u226e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\udb40\\udd01\\u035f\\u2fb6\\uff61\\u2087\\ufe12\\u1102\\u116e\\u11aa<\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\udb40\\udd01\\u035f\\u98db\\u30027\\u3002\\ub207\\u226e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\udb40\\udd01\\u035f\\u98db\\u30027\\u3002\\u1102\\u116e\\u11aa<\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--9ua0567e.7.xn--gdh6767c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--9ua0567e.xn--7-ngou006d1ttc\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--2ib43l.xn--te6h\",\n    \"output\": \"xn--2ib43l.xn--te6h\"\n  },\n  {\n    \"input\": \"\\u067d\\u0943.\\ud83a\\udd35\",\n    \"output\": \"xn--2ib43l.xn--te6h\"\n  },\n  {\n    \"input\": \"\\u067d\\u0943.\\ud83a\\udd13\",\n    \"output\": \"xn--2ib43l.xn--te6h\"\n  },\n  {\n    \"comment\": \"C1; V6\",\n    \"input\": \"\\u200c\\u3002\\uffa0\\u0f84\\u0f96\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6\",\n    \"input\": \"\\u200c\\u3002\\u1160\\u0f84\\u0f96\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \".xn--3ed0b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6\",\n    \"input\": \"xn--0ug.xn--3ed0b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \".xn--3ed0b20h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--0ug.xn--3ed0b20h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \".xn--3ed0by082k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--0ug.xn--3ed0by082k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u226f\\ud9f5\\ude05\\uff0e\\u200d\\ud800\\udd7c\\uda88\\udddb\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \">\\u0338\\ud9f5\\ude05\\uff0e\\u200d\\ud800\\udd7c\\uda88\\udddb\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u226f\\ud9f5\\ude05.\\u200d\\ud800\\udd7c\\uda88\\udddb\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \">\\u0338\\ud9f5\\ude05.\\u200d\\ud800\\udd7c\\uda88\\udddb\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--hdh84488f.xn--xy7cw2886b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--hdh84488f.xn--1ug8099fbjp4e\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\ua9d0\\u04c0\\u1baa\\u08f6\\uff0e\\ub235\",\n    \"output\": \"xn--s5a04sn4u297k.xn--2e1b\"\n  },\n  {\n    \"input\": \"\\ua9d0\\u04c0\\u1baa\\u08f6\\uff0e\\u1102\\u116f\\u11bc\",\n    \"output\": \"xn--s5a04sn4u297k.xn--2e1b\"\n  },\n  {\n    \"input\": \"\\ua9d0\\u04c0\\u1baa\\u08f6.\\ub235\",\n    \"output\": \"xn--s5a04sn4u297k.xn--2e1b\"\n  },\n  {\n    \"input\": \"\\ua9d0\\u04c0\\u1baa\\u08f6.\\u1102\\u116f\\u11bc\",\n    \"output\": \"xn--s5a04sn4u297k.xn--2e1b\"\n  },\n  {\n    \"input\": \"\\ua9d0\\u04cf\\u1baa\\u08f6.\\u1102\\u116f\\u11bc\",\n    \"output\": \"xn--s5a04sn4u297k.xn--2e1b\"\n  },\n  {\n    \"input\": \"\\ua9d0\\u04cf\\u1baa\\u08f6.\\ub235\",\n    \"output\": \"xn--s5a04sn4u297k.xn--2e1b\"\n  },\n  {\n    \"input\": \"xn--s5a04sn4u297k.xn--2e1b\",\n    \"output\": \"xn--s5a04sn4u297k.xn--2e1b\"\n  },\n  {\n    \"input\": \"\\ua9d0\\u04cf\\u1baa\\u08f6\\uff0e\\u1102\\u116f\\u11bc\",\n    \"output\": \"xn--s5a04sn4u297k.xn--2e1b\"\n  },\n  {\n    \"input\": \"\\ua9d0\\u04cf\\u1baa\\u08f6\\uff0e\\ub235\",\n    \"output\": \"xn--s5a04sn4u297k.xn--2e1b\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--d5a07sn4u297k.xn--2e1b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ua8ea\\uff61\\ud818\\udd3f\\ud804\\uddbe\\udb40\\uddd7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ua8ea\\u3002\\ud818\\udd3f\\ud804\\uddbe\\udb40\\uddd7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--3g9a.xn--ud1dz07k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udadd\\udcd3\\ud805\\udeb3\\u3002\\ud903\\uddff\\u226f\\u2f87\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udadd\\udcd3\\ud805\\udeb3\\u3002\\ud903\\uddff>\\u0338\\u2f87\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udadd\\udcd3\\ud805\\udeb3\\u3002\\ud903\\uddff\\u226f\\u821b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udadd\\udcd3\\ud805\\udeb3\\u3002\\ud903\\uddff>\\u0338\\u821b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--3e2d79770c.xn--hdh0088abyy1c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--9hb7344k.\",\n    \"output\": \"xn--9hb7344k.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\ud802\\udec7\\u0661.\",\n    \"output\": \"xn--9hb7344k.\"\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\ud944\\udd48\\u782a\\u226f\\u1891\\uff61\\u226f\\ud836\\ude5a\\uda0f\\udd14\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\ud944\\udd48\\u782a>\\u0338\\u1891\\uff61>\\u0338\\ud836\\ude5a\\uda0f\\udd14\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\ud944\\udd48\\u782a\\u226f\\u1891\\u3002\\u226f\\ud836\\ude5a\\uda0f\\udd14\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\ud944\\udd48\\u782a>\\u0338\\u1891\\u3002>\\u0338\\ud836\\ude5a\\uda0f\\udd14\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--bbf561cf95e57y3e.xn--hdh0834o7mj6b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--bbf561cf95e57y3e.xn--0ugz6gc910ejro8c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u10c5.\\ud804\\udd33\\u32b8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u10c5.\\ud804\\udd3343\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u2d25.\\ud804\\udd3343\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--tlj.xn--43-274o\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u2d25.\\ud804\\udd33\\u32b8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--9nd.xn--43-274o\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud91e\\udea8\\udb40\\udd09\\uffa0\\u0fb7.\\ud9a1\\udfb0\\ua953\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud91e\\udea8\\udb40\\udd09\\u1160\\u0fb7.\\ud9a1\\udfb0\\ua953\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--kgd72212e.xn--3j9au7544a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--kgd36f9z57y.xn--3j9au7544a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--kgd7493jee34a.xn--3j9au7544a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6\",\n    \"input\": \"\\u0618.\\u06f3\\u200c\\ua953\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--6fb.xn--gmb0524f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6\",\n    \"input\": \"xn--6fb.xn--gmb469jjf1h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u184c\\uff0e\\ufe12\\u1891\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u184c.\\u3002\\u1891\",\n    \"output\": \"xn--c8e..xn--bbf\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--c8e..xn--bbf\",\n    \"output\": \"xn--c8e..xn--bbf\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--c8e.xn--bbf9168i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud83b\\uddcf\\u3002\\u1822\\uda0d\\ude06\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--hd7h.xn--46e66060j\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud9f0\\uded4\\udb40\\udd8e\\udb40\\udd97\\ud807\\udc95\\u3002\\u226e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud9f0\\uded4\\udb40\\udd8e\\udb40\\udd97\\ud807\\udc95\\u3002<\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--4m3dv4354a.xn--gdh\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"\\udb40\\udda6.\\u08e3\\u6680\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"\\udb40\\udda6.\\u08e3\\u6680=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \".xn--m0b461k3g2c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u40b9\\udbb9\\udd85\\ud800\\udee6\\uff0e\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u40b9\\udbb9\\udd85\\ud800\\udee6.\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"xn--0on3543c5981i.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--0on3543c5981i.xn--1ug\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ufe12\\uff61\\u10a3\\u226f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ufe12\\uff61\\u10a3>\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u3002\\u3002\\u10a3\\u226f\",\n    \"output\": \"..xn--hdh782b\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u3002\\u3002\\u10a3>\\u0338\",\n    \"output\": \"..xn--hdh782b\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u3002\\u3002\\u2d03>\\u0338\",\n    \"output\": \"..xn--hdh782b\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u3002\\u3002\\u2d03\\u226f\",\n    \"output\": \"..xn--hdh782b\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"..xn--hdh782b\",\n    \"output\": \"..xn--hdh782b\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ufe12\\uff61\\u2d03>\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ufe12\\uff61\\u2d03\\u226f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--y86c.xn--hdh782b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"..xn--bnd622g\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--y86c.xn--bnd622g\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u7b83\\u10c1-\\udb40\\udc5d\\uff61\\u2260-\\ud83e\\udd16\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u7b83\\u10c1-\\udb40\\udc5d\\uff61=\\u0338-\\ud83e\\udd16\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u7b83\\u10c1-\\udb40\\udc5d\\u3002\\u2260-\\ud83e\\udd16\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u7b83\\u10c1-\\udb40\\udc5d\\u3002=\\u0338-\\ud83e\\udd16\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u7b83\\u2d21-\\udb40\\udc5d\\u3002=\\u0338-\\ud83e\\udd16\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u7b83\\u2d21-\\udb40\\udc5d\\u3002\\u2260-\\ud83e\\udd16\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn----4wsr321ay823p.xn----tfot873s\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u7b83\\u2d21-\\udb40\\udc5d\\uff61=\\u0338-\\ud83e\\udd16\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u7b83\\u2d21-\\udb40\\udc5d\\uff61\\u2260-\\ud83e\\udd16\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn----11g3013fy8x5m.xn----tfot873s\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\u07e5.\\u06b5\",\n    \"output\": \"xn--dtb.xn--okb\"\n  },\n  {\n    \"input\": \"xn--dtb.xn--okb\",\n    \"output\": \"xn--dtb.xn--okb\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \".xn--3e6h\",\n    \"output\": \".xn--3e6h\"\n  },\n  {\n    \"input\": \"xn--3e6h\",\n    \"output\": \"xn--3e6h\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd3f\",\n    \"output\": \"xn--3e6h\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd1d\",\n    \"output\": \"xn--3e6h\"\n  },\n  {\n    \"comment\": \"C1; V6; V3 (ignored)\",\n    \"input\": \"\\u103a\\u200d\\u200c\\u3002-\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"xn--bkd.-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V3 (ignored)\",\n    \"input\": \"xn--bkd412fca.xn----sgn\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ufe12\\uff61\\u1b44\\u1849\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"\\u3002\\u3002\\u1b44\\u1849\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"..xn--87e93m\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--y86c.xn--87e93m\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"-\\u1bab\\ufe12\\u200d.\\ud90b\\udd88\\ud957\\ude53\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"-\\u1bab\\u3002\\u200d.\\ud90b\\udd88\\ud957\\ude53\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"xn----qml..xn--x50zy803a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"xn----qml.xn--1ug.xn--x50zy803a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn----qml1407i.xn--x50zy803a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"xn----qmlv7tw180a.xn--x50zy803a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb42\\uddae.\\u226f\\ud838\\udc06\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb42\\uddae.>\\u0338\\ud838\\udc06\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--t546e.xn--hdh5166o\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\u06b9\\uff0e\\u1873\\u115f\",\n    \"output\": \"xn--skb.xn--g9e\"\n  },\n  {\n    \"input\": \"\\u06b9.\\u1873\\u115f\",\n    \"output\": \"xn--skb.xn--g9e\"\n  },\n  {\n    \"input\": \"xn--skb.xn--g9e\",\n    \"output\": \"xn--skb.xn--g9e\"\n  },\n  {\n    \"input\": \"\\u06b9.\\u1873\",\n    \"output\": \"xn--skb.xn--g9e\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--skb.xn--osd737a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u3a1b\\ud823\\udc4e.\\ufe12\\ud835\\udfd5\\u0d01\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u3a1b\\ud823\\udc4e.\\u30027\\u0d01\",\n    \"output\": \"xn--mbm8237g..xn--7-7hf\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--mbm8237g..xn--7-7hf\",\n    \"output\": \"xn--mbm8237g..xn--7-7hf\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--mbm8237g.xn--7-7hf1526p\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u00df\\u200c\\uaaf6\\u18a5\\uff0e\\u22b6\\u10c1\\u10b6\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u00df\\u200c\\uaaf6\\u18a5.\\u22b6\\u10c1\\u10b6\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u00df\\u200c\\uaaf6\\u18a5.\\u22b6\\u2d21\\u2d16\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"SS\\u200c\\uaaf6\\u18a5.\\u22b6\\u10c1\\u10b6\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"ss\\u200c\\uaaf6\\u18a5.\\u22b6\\u2d21\\u2d16\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"Ss\\u200c\\uaaf6\\u18a5.\\u22b6\\u10c1\\u2d16\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--ss-4epx629f.xn--ifh802b6a\",\n    \"output\": \"xn--ss-4epx629f.xn--ifh802b6a\"\n  },\n  {\n    \"input\": \"ss\\uaaf6\\u18a5.\\u22b6\\u2d21\\u2d16\",\n    \"output\": \"xn--ss-4epx629f.xn--ifh802b6a\"\n  },\n  {\n    \"input\": \"SS\\uaaf6\\u18a5.\\u22b6\\u10c1\\u10b6\",\n    \"output\": \"xn--ss-4epx629f.xn--ifh802b6a\"\n  },\n  {\n    \"input\": \"Ss\\uaaf6\\u18a5.\\u22b6\\u10c1\\u2d16\",\n    \"output\": \"xn--ss-4epx629f.xn--ifh802b6a\"\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"xn--ss-4ep585bkm5p.xn--ifh802b6a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"xn--zca682johfi89m.xn--ifh802b6a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u00df\\u200c\\uaaf6\\u18a5\\uff0e\\u22b6\\u2d21\\u2d16\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"SS\\u200c\\uaaf6\\u18a5\\uff0e\\u22b6\\u10c1\\u10b6\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"ss\\u200c\\uaaf6\\u18a5\\uff0e\\u22b6\\u2d21\\u2d16\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"Ss\\u200c\\uaaf6\\u18a5\\uff0e\\u22b6\\u10c1\\u2d16\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--ss-4epx629f.xn--5nd703gyrh\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--ss-4ep585bkm5p.xn--5nd703gyrh\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--ss-4epx629f.xn--undv409k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--ss-4ep585bkm5p.xn--undv409k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--zca682johfi89m.xn--undv409k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u200d\\u3002\\u03c2\\udb40\\udc49\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u200d\\u3002\\u03a3\\udb40\\udc49\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u200d\\u3002\\u03c3\\udb40\\udc49\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \".xn--4xa24344p\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--1ug.xn--4xa24344p\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--1ug.xn--3xa44344p\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\u2492\\uda61\\ude19\\uda8f\\udce0\\ud805\\udcc0.-\\udb3a\\udc4a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"11.\\uda61\\ude19\\uda8f\\udce0\\ud805\\udcc0.-\\udb3a\\udc4a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"11.xn--uz1d59632bxujd.xn----x310m\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn--3shy698frsu9dt1me.xn----x310m\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"-\\uff61\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"-\\u3002\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"-.\",\n    \"output\": \"-.\"\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"-.xn--1ug\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u126c\\uda12\\udc3c\\ud8c5\\uddf6\\uff61\\ud802\\ude2c\\ud835\\udfe0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u126c\\uda12\\udc3c\\ud8c5\\uddf6\\u3002\\ud802\\ude2c8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--d0d41273c887z.xn--8-ob5i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"\\u03c2\\u200d-.\\u10c3\\ud859\\udfd9\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"\\u03c2\\u200d-.\\u2d23\\ud859\\udfd9\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"\\u03a3\\u200d-.\\u10c3\\ud859\\udfd9\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"\\u03c3\\u200d-.\\u2d23\\ud859\\udfd9\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"xn----zmb.xn--rlj2573p\",\n    \"output\": \"xn----zmb.xn--rlj2573p\"\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"xn----zmb048s.xn--rlj2573p\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"xn----xmb348s.xn--rlj2573p\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn----zmb.xn--7nd64871a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"xn----zmb048s.xn--7nd64871a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"xn----xmb348s.xn--7nd64871a\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\u2260\\u3002\\ud83d\\udfb3\\ud835\\udff2\",\n    \"output\": \"xn--1ch.xn--6-dl4s\"\n  },\n  {\n    \"input\": \"=\\u0338\\u3002\\ud83d\\udfb3\\ud835\\udff2\",\n    \"output\": \"xn--1ch.xn--6-dl4s\"\n  },\n  {\n    \"input\": \"\\u2260\\u3002\\ud83d\\udfb36\",\n    \"output\": \"xn--1ch.xn--6-dl4s\"\n  },\n  {\n    \"input\": \"=\\u0338\\u3002\\ud83d\\udfb36\",\n    \"output\": \"xn--1ch.xn--6-dl4s\"\n  },\n  {\n    \"input\": \"xn--1ch.xn--6-dl4s\",\n    \"output\": \"xn--1ch.xn--6-dl4s\"\n  },\n  {\n    \"input\": \"\\u2260.\\ud83d\\udfb36\",\n    \"output\": \"xn--1ch.xn--6-dl4s\"\n  },\n  {\n    \"input\": \"=\\u0338.\\ud83d\\udfb36\",\n    \"output\": \"xn--1ch.xn--6-dl4s\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udad6\\udf3d.\\u8814\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--g747d.xn--xl2a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u08e6\\u200d\\uff0e\\ubf3d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u08e6\\u200d\\uff0e\\u1108\\u1168\\u11c0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u08e6\\u200d.\\ubf3d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u08e6\\u200d.\\u1108\\u1168\\u11c0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--p0b.xn--e43b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"xn--p0b869i.xn--e43b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud8f6\\ude3d\\uff0e\\ud8ef\\ude15\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud8f6\\ude3d.\\ud8ef\\ude15\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--pr3x.xn--rv7w\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud802\\udfc0\\ud803\\ude09\\ud83a\\uddcf\\u3002\\ud949\\udea7\\u2084\\u10ab\\ud8cb\\ude6b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud802\\udfc0\\ud803\\ude09\\ud83a\\uddcf\\u3002\\ud949\\udea74\\u10ab\\ud8cb\\ude6b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud802\\udfc0\\ud803\\ude09\\ud83a\\uddcf\\u3002\\ud949\\udea74\\u2d0b\\ud8cb\\ude6b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--039c42bq865a.xn--4-wvs27840bnrzm\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud802\\udfc0\\ud803\\ude09\\ud83a\\uddcf\\u3002\\ud949\\udea7\\u2084\\u2d0b\\ud8cb\\ude6b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--039c42bq865a.xn--4-t0g49302fnrzm\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud835\\udfd3\\u3002\\u06d7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"5\\u3002\\u06d7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"5.xn--nlb\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u200c\\udaab\\ude29.\\u2f95\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u200c\\udaab\\ude29.\\u8c37\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--i183d.xn--6g3a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--0ug26167i.xn--6g3a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V7; V3 (ignored)\",\n    \"input\": \"\\ufe12\\udafb\\udc07\\u200d.-\\u073c\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V7; V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"\\u3002\\udafb\\udc07\\u200d.-\\u073c\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored); A4_2 (ignored)\",\n    \"input\": \".xn--hh50e.xn----t2c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V7; V3 (ignored); A4_2 (ignored)\",\n    \"input\": \".xn--1ug05310k.xn----t2c071q\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn--y86c71305c.xn----t2c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V7; V3 (ignored)\",\n    \"input\": \"xn--1ug1658ftw26f.xn----t2c071q\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u200d\\uff0e\\ud835\\udfd7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u200d.j\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u200d.J\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \".j\",\n    \"output\": \".j\"\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"xn--1ug.j\",\n    \"output\": null\n  },\n  {\n    \"input\": \"j\",\n    \"output\": \"j\"\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u10ad\\ud8be\\udccd\\ua868\\u05ae\\u3002\\u10be\\u200c\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u2d0d\\ud8be\\udccd\\ua868\\u05ae\\u3002\\u2d1e\\u200c\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--5cb172r175fug38a.xn--mlj\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--5cb172r175fug38a.xn--0uga051h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--5cb347co96jug15a.xn--2nd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--5cb347co96jug15a.xn--2nd059ea\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud800\\udef0\\u3002\\udb05\\udcf1\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--k97c.xn--q031e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u08df\\u10ab\\ud89b\\udff8\\uade4\\uff0e\\uda40\\udd7c\\ud835\\udfe2\\ud72a\\u0ae3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u08df\\u10ab\\ud89b\\udff8\\u1100\\u1172\\u11af\\uff0e\\uda40\\udd7c\\ud835\\udfe2\\u1112\\u1171\\u11b9\\u0ae3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u08df\\u10ab\\ud89b\\udff8\\uade4.\\uda40\\udd7c0\\ud72a\\u0ae3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u08df\\u10ab\\ud89b\\udff8\\u1100\\u1172\\u11af.\\uda40\\udd7c0\\u1112\\u1171\\u11b9\\u0ae3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u08df\\u2d0b\\ud89b\\udff8\\u1100\\u1172\\u11af.\\uda40\\udd7c0\\u1112\\u1171\\u11b9\\u0ae3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u08df\\u2d0b\\ud89b\\udff8\\uade4.\\uda40\\udd7c0\\ud72a\\u0ae3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--i0b436pkl2g2h42a.xn--0-8le8997mulr5f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u08df\\u2d0b\\ud89b\\udff8\\u1100\\u1172\\u11af\\uff0e\\uda40\\udd7c\\ud835\\udfe2\\u1112\\u1171\\u11b9\\u0ae3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u08df\\u2d0b\\ud89b\\udff8\\uade4\\uff0e\\uda40\\udd7c\\ud835\\udfe2\\ud72a\\u0ae3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--i0b601b6r7l2hs0a.xn--0-8le8997mulr5f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u0784\\uff0e\\ud83a\\udc5d\\u0601\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u0784.\\ud83a\\udc5d\\u0601\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--lqb.xn--jfb1808v\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u0acd\\u2083.8\\ua8c4\\u200d\\ud83c\\udce4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u0acd3.8\\ua8c4\\u200d\\ud83c\\udce4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--3-yke.xn--8-sl4et308f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--3-yke.xn--8-ugnv982dbkwm\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ua855\\u2260\\u105e\\udb7b\\udff1\\uff61\\ud803\\udd67\\udb40\\udd2b\\uffa0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ua855=\\u0338\\u105e\\udb7b\\udff1\\uff61\\ud803\\udd67\\udb40\\udd2b\\uffa0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ua855\\u2260\\u105e\\udb7b\\udff1\\u3002\\ud803\\udd67\\udb40\\udd2b\\u1160\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ua855=\\u0338\\u105e\\udb7b\\udff1\\u3002\\ud803\\udd67\\udb40\\udd2b\\u1160\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--cld333gn31h0158l.xn--3g0d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u9c4a\\u3002\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--rt6a.\",\n    \"output\": \"xn--rt6a.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u9c4a.\",\n    \"output\": \"xn--rt6a.\"\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"xn--rt6a.xn--0ug\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--4-0bd15808a.\",\n    \"output\": \"xn--4-0bd15808a.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\ud83a\\udd3a\\u07cc4.\",\n    \"output\": \"xn--4-0bd15808a.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\ud83a\\udd18\\u07cc4.\",\n    \"output\": \"xn--4-0bd15808a.\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"-\\uff61\\u43db\",\n    \"output\": \"-.xn--xco\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"-\\u3002\\u43db\",\n    \"output\": \"-.xn--xco\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"-.xn--xco\",\n    \"output\": \"-.xn--xco\"\n  },\n  {\n    \"comment\": \"C1; C2; V7\",\n    \"input\": \"\\u200c\\ud908\\udce0\\uff0e\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V7\",\n    \"input\": \"\\u200c\\ud908\\udce0.\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"xn--dj8y.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V7\",\n    \"input\": \"xn--0ugz7551c.xn--1ug\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ud804\\uddc0.\\udb42\\ude31\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--wd1d.xn--k946e\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\u2f86\\uff0e\\ua848\\uff15\\u226f\\u00df\",\n    \"output\": \"xn--tc1a.xn--5-qfa988w745i\"\n  },\n  {\n    \"input\": \"\\u2f86\\uff0e\\ua848\\uff15>\\u0338\\u00df\",\n    \"output\": \"xn--tc1a.xn--5-qfa988w745i\"\n  },\n  {\n    \"input\": \"\\u820c.\\ua8485\\u226f\\u00df\",\n    \"output\": \"xn--tc1a.xn--5-qfa988w745i\"\n  },\n  {\n    \"input\": \"\\u820c.\\ua8485>\\u0338\\u00df\",\n    \"output\": \"xn--tc1a.xn--5-qfa988w745i\"\n  },\n  {\n    \"input\": \"\\u820c.\\ua8485>\\u0338SS\",\n    \"output\": \"xn--tc1a.xn--5ss-3m2a5009e\"\n  },\n  {\n    \"input\": \"\\u820c.\\ua8485\\u226fSS\",\n    \"output\": \"xn--tc1a.xn--5ss-3m2a5009e\"\n  },\n  {\n    \"input\": \"\\u820c.\\ua8485\\u226fss\",\n    \"output\": \"xn--tc1a.xn--5ss-3m2a5009e\"\n  },\n  {\n    \"input\": \"\\u820c.\\ua8485>\\u0338ss\",\n    \"output\": \"xn--tc1a.xn--5ss-3m2a5009e\"\n  },\n  {\n    \"input\": \"\\u820c.\\ua8485>\\u0338Ss\",\n    \"output\": \"xn--tc1a.xn--5ss-3m2a5009e\"\n  },\n  {\n    \"input\": \"\\u820c.\\ua8485\\u226fSs\",\n    \"output\": \"xn--tc1a.xn--5ss-3m2a5009e\"\n  },\n  {\n    \"input\": \"xn--tc1a.xn--5ss-3m2a5009e\",\n    \"output\": \"xn--tc1a.xn--5ss-3m2a5009e\"\n  },\n  {\n    \"input\": \"xn--tc1a.xn--5-qfa988w745i\",\n    \"output\": \"xn--tc1a.xn--5-qfa988w745i\"\n  },\n  {\n    \"input\": \"\\u2f86\\uff0e\\ua848\\uff15>\\u0338SS\",\n    \"output\": \"xn--tc1a.xn--5ss-3m2a5009e\"\n  },\n  {\n    \"input\": \"\\u2f86\\uff0e\\ua848\\uff15\\u226fSS\",\n    \"output\": \"xn--tc1a.xn--5ss-3m2a5009e\"\n  },\n  {\n    \"input\": \"\\u2f86\\uff0e\\ua848\\uff15\\u226fss\",\n    \"output\": \"xn--tc1a.xn--5ss-3m2a5009e\"\n  },\n  {\n    \"input\": \"\\u2f86\\uff0e\\ua848\\uff15>\\u0338ss\",\n    \"output\": \"xn--tc1a.xn--5ss-3m2a5009e\"\n  },\n  {\n    \"input\": \"\\u2f86\\uff0e\\ua848\\uff15>\\u0338Ss\",\n    \"output\": \"xn--tc1a.xn--5ss-3m2a5009e\"\n  },\n  {\n    \"input\": \"\\u2f86\\uff0e\\ua848\\uff15\\u226fSs\",\n    \"output\": \"xn--tc1a.xn--5ss-3m2a5009e\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd2a.\\u03c2\",\n    \"output\": \"xn--ie6h.xn--3xa\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd08.\\u03a3\",\n    \"output\": \"xn--ie6h.xn--4xa\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd2a.\\u03c3\",\n    \"output\": \"xn--ie6h.xn--4xa\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd08.\\u03c3\",\n    \"output\": \"xn--ie6h.xn--4xa\"\n  },\n  {\n    \"input\": \"xn--ie6h.xn--4xa\",\n    \"output\": \"xn--ie6h.xn--4xa\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd08.\\u03c2\",\n    \"output\": \"xn--ie6h.xn--3xa\"\n  },\n  {\n    \"input\": \"xn--ie6h.xn--3xa\",\n    \"output\": \"xn--ie6h.xn--3xa\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd2a.\\u03a3\",\n    \"output\": \"xn--ie6h.xn--4xa\"\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u200c\\u10ba\\uff61\\u03c2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u200c\\u10ba\\u3002\\u03c2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u200c\\u2d1a\\u3002\\u03c2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u200c\\u10ba\\u3002\\u03a3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u200c\\u2d1a\\u3002\\u03c3\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--ilj.xn--4xa\",\n    \"output\": \"xn--ilj.xn--4xa\"\n  },\n  {\n    \"input\": \"\\u2d1a.\\u03c3\",\n    \"output\": \"xn--ilj.xn--4xa\"\n  },\n  {\n    \"input\": \"\\u10ba.\\u03a3\",\n    \"output\": \"xn--ilj.xn--4xa\"\n  },\n  {\n    \"input\": \"\\u2d1a.\\u03c2\",\n    \"output\": \"xn--ilj.xn--3xa\"\n  },\n  {\n    \"input\": \"\\u10ba.\\u03c2\",\n    \"output\": \"xn--ilj.xn--3xa\"\n  },\n  {\n    \"input\": \"xn--ilj.xn--3xa\",\n    \"output\": \"xn--ilj.xn--3xa\"\n  },\n  {\n    \"input\": \"\\u10ba.\\u03c3\",\n    \"output\": \"xn--ilj.xn--4xa\"\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"xn--0ug262c.xn--4xa\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"xn--0ug262c.xn--3xa\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u200c\\u2d1a\\uff61\\u03c2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u200c\\u10ba\\uff61\\u03a3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u200c\\u2d1a\\uff61\\u03c3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--ynd.xn--4xa\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--ynd.xn--3xa\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--ynd759e.xn--4xa\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--ynd759e.xn--3xa\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200d\\u2f95\\u3002\\u200c\\u0310\\ua953\\ua84e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200d\\u2f95\\u3002\\u200c\\ua953\\u0310\\ua84e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200d\\u8c37\\u3002\\u200c\\ua953\\u0310\\ua84e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--6g3a.xn--0sa8175flwa\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"xn--1ug0273b.xn--0sa359l6n7g13a\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\u6dfd\\u3002\\u183e\",\n    \"output\": \"xn--34w.xn--x7e\"\n  },\n  {\n    \"input\": \"xn--34w.xn--x7e\",\n    \"output\": \"xn--34w.xn--x7e\"\n  },\n  {\n    \"input\": \"\\u6dfd.\\u183e\",\n    \"output\": \"xn--34w.xn--x7e\"\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\uda72\\ude29\\u10b3\\u2753\\uff61\\ud804\\udd28\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\uda72\\ude29\\u10b3\\u2753\\u3002\\ud804\\udd28\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\uda72\\ude29\\u2d13\\u2753\\u3002\\ud804\\udd28\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--8di78qvw32y.xn--k80d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\uda72\\ude29\\u2d13\\u2753\\uff61\\ud804\\udd28\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--rnd896i0j14q.xn--k80d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u17ff\\uff61\\ud83a\\udf33\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u17ff\\u3002\\ud83a\\udf33\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--45e.xn--et6h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u0652\\u200d\\uff61\\u0ccd\\ud805\\udeb3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u0652\\u200d\\u3002\\u0ccd\\ud805\\udeb3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--uhb.xn--8tc4527k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"xn--uhb882k.xn--8tc4527k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u00df\\ud880\\udc3b\\ud8da\\udf17\\uff61\\ud836\\ude68\\ud83d\\udd6e\\u00df\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u00df\\ud880\\udc3b\\ud8da\\udf17\\u3002\\ud836\\ude68\\ud83d\\udd6e\\u00df\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"SS\\ud880\\udc3b\\ud8da\\udf17\\u3002\\ud836\\ude68\\ud83d\\udd6eSS\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"ss\\ud880\\udc3b\\ud8da\\udf17\\u3002\\ud836\\ude68\\ud83d\\udd6ess\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"Ss\\ud880\\udc3b\\ud8da\\udf17\\u3002\\ud836\\ude68\\ud83d\\udd6eSs\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--ss-jl59biy67d.xn--ss-4d11aw87d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--zca20040bgrkh.xn--zca3653v86qa\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"SS\\ud880\\udc3b\\ud8da\\udf17\\uff61\\ud836\\ude68\\ud83d\\udd6eSS\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"ss\\ud880\\udc3b\\ud8da\\udf17\\uff61\\ud836\\ude68\\ud83d\\udd6ess\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"Ss\\ud880\\udc3b\\ud8da\\udf17\\uff61\\ud836\\ude68\\ud83d\\udd6eSs\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200d\\u3002\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"xn--1ug.xn--0ug\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\udb41\\udc58\\uff0e\\udb40\\udd2e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\udb41\\udc58.\\udb40\\udd2e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"xn--s136e.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ua9b7\\udb37\\udd59\\uba79\\u3002\\u249b\\udb42\\ude07\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ua9b7\\udb37\\udd59\\u1106\\u1167\\u11b0\\u3002\\u249b\\udb42\\ude07\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ua9b7\\udb37\\udd59\\uba79\\u300220.\\udb42\\ude07\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ua9b7\\udb37\\udd59\\u1106\\u1167\\u11b0\\u300220.\\udb42\\ude07\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--ym9av13acp85w.20.xn--d846e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--ym9av13acp85w.xn--dth22121k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u200c\\uff61\\ufe12\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; A4_2 (ignored)\",\n    \"input\": \"\\u200c\\u3002\\u3002\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"..\",\n    \"output\": \"..\"\n  },\n  {\n    \"comment\": \"C1; A4_2 (ignored)\",\n    \"input\": \"xn--0ug..\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \".xn--y86c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--0ug.xn--y86c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u1872-\\ud835\\udff9.\\u00df-\\u200c-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u1872-3.\\u00df-\\u200c-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u1872-3.SS-\\u200c-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u1872-3.ss-\\u200c-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u1872-3.Ss-\\u200c-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V2 (ignored); V3 (ignored)\",\n    \"input\": \"xn---3-p9o.ss--\",\n    \"output\": \"xn---3-p9o.ss--\"\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"xn---3-p9o.xn--ss---276a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"xn---3-p9o.xn-----fia9303a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u1872-\\ud835\\udff9.SS-\\u200c-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u1872-\\ud835\\udff9.ss-\\u200c-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u1872-\\ud835\\udff9.Ss-\\u200c-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\udb27\\udd9c\\u1898\\u3002\\u1a7f\\u2ea2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--ibf35138o.xn--fpfz94g\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\uda1c\\udda7\\ud835\\udfef\\u3002\\u2488\\u1a76\\ud835\\udfda\\uda41\\ude0c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\uda1c\\udda73\\u30021.\\u1a762\\uda41\\ude0c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--3-rj42h.1.xn--2-13k96240l\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--3-rj42h.xn--2-13k746cq465x\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u200d\\u2085\\u2488\\u3002\\u226f\\ud835\\udff4\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u200d\\u2085\\u2488\\u3002>\\u0338\\ud835\\udff4\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; A4_2 (ignored)\",\n    \"input\": \"\\u200d51.\\u3002\\u226f8\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; A4_2 (ignored)\",\n    \"input\": \"\\u200d51.\\u3002>\\u03388\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"51..xn--8-ogo\",\n    \"output\": \"51..xn--8-ogo\"\n  },\n  {\n    \"comment\": \"C2; A4_2 (ignored)\",\n    \"input\": \"xn--51-l1t..xn--8-ugn00i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--5-ecp.xn--8-ogo\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--5-tgnz5r.xn--8-ugn00i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud8bb\\uddc2\\u0a42\\u10aa\\ud8c8\\udc9f.\\u226e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud8bb\\uddc2\\u0a42\\u10aa\\ud8c8\\udc9f.<\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud8bb\\uddc2\\u0a42\\u2d0a\\ud8c8\\udc9f.<\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud8bb\\uddc2\\u0a42\\u2d0a\\ud8c8\\udc9f.\\u226e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--nbc229o4y27dgskb.xn--gdh\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--nbc493aro75ggskb.xn--gdh\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\ua860\\uff0e\\u06f2\",\n    \"output\": \"xn--5c9a.xn--fmb\"\n  },\n  {\n    \"input\": \"\\ua860.\\u06f2\",\n    \"output\": \"xn--5c9a.xn--fmb\"\n  },\n  {\n    \"input\": \"xn--5c9a.xn--fmb\",\n    \"output\": \"xn--5c9a.xn--fmb\"\n  },\n  {\n    \"comment\": \"C1; V6; U1 (ignored)\",\n    \"input\": \"\\ua67d\\u200c\\ud87e\\uddf5\\ud83c\\udd06\\uff61\\u200c\\ud804\\udc42\\u1b01\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; U1 (ignored)\",\n    \"input\": \"\\ua67d\\u200c\\u9723\\ud83c\\udd06\\uff61\\u200c\\ud804\\udc42\\u1b01\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; U1 (ignored)\",\n    \"input\": \"\\ua67d\\u200c\\u97235,\\u3002\\u200c\\ud804\\udc42\\u1b01\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; U1 (ignored)\",\n    \"input\": \"xn--5,-op8g373c.xn--4sf0725i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; U1 (ignored)\",\n    \"input\": \"xn--5,-i1tz135dnbqa.xn--4sf36u6u4w\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--2q5a751a653w.xn--4sf0725i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"xn--0ug4208b2vjuk63a.xn--4sf36u6u4w\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u514e\\uff61\\u183c\\udb43\\udd1c\\ud805\\udeb6\\ud807\\udc3f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u514e\\u3002\\u183c\\udb43\\udd1c\\ud805\\udeb6\\ud807\\udc3f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--b5q.xn--v7e6041kqqd4m251b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\ud835\\udfd9\\uff61\\u200d\\ud835\\udff8\\u200d\\u2077\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"1\\u3002\\u200d2\\u200d7\",\n    \"output\": null\n  },\n  {\n    \"input\": \"1.2h\",\n    \"output\": \"1.2h\"\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"1.xn--27-l1tb\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\u1868-\\uff61\\udb43\\udecb\\ud835\\udff7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\u1868-\\u3002\\udb43\\udecb1\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn----z8j.xn--1-5671m\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u10bc\\ud9e3\\udded\\u0f80\\u2f87\\u3002\\u10af\\u2640\\u200c\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u10bc\\ud9e3\\udded\\u0f80\\u821b\\u3002\\u10af\\u2640\\u200c\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u2d1c\\ud9e3\\udded\\u0f80\\u821b\\u3002\\u2d0f\\u2640\\u200c\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--zed372mdj2do3v4h.xn--e5h11w\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--zed372mdj2do3v4h.xn--0uga678bgyh\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u2d1c\\ud9e3\\udded\\u0f80\\u2f87\\u3002\\u2d0f\\u2640\\u200c\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--zed54dz10wo343g.xn--nnd651i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--zed54dz10wo343g.xn--nnd089ea464d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\ud804\\udc46\\ud835\\udff0.\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\ud804\\udc464.\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"xn--4-xu7i.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"xn--4-xu7i.xn--1ug\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\ud97b\\udd18\\u10be\\u7640\\uff61\\ud805\\ude3f\\u200d\\u200c\\ubdbc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\ud97b\\udd18\\u10be\\u7640\\uff61\\ud805\\ude3f\\u200d\\u200c\\u1107\\u1170\\u11ab\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\ud97b\\udd18\\u10be\\u7640\\u3002\\ud805\\ude3f\\u200d\\u200c\\ubdbc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\ud97b\\udd18\\u10be\\u7640\\u3002\\ud805\\ude3f\\u200d\\u200c\\u1107\\u1170\\u11ab\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\ud97b\\udd18\\u2d1e\\u7640\\u3002\\ud805\\ude3f\\u200d\\u200c\\u1107\\u1170\\u11ab\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\ud97b\\udd18\\u2d1e\\u7640\\u3002\\ud805\\ude3f\\u200d\\u200c\\ubdbc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--mlju35u7qx2f.xn--et3bn23n\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"xn--mlju35u7qx2f.xn--0ugb6122js83c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\ud97b\\udd18\\u2d1e\\u7640\\uff61\\ud805\\ude3f\\u200d\\u200c\\u1107\\u1170\\u11ab\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\ud97b\\udd18\\u2d1e\\u7640\\uff61\\ud805\\ude3f\\u200d\\u200c\\ubdbc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--2nd6803c7q37d.xn--et3bn23n\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"xn--2nd6803c7q37d.xn--0ugb6122js83c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1843\\ud835\\udfe7\\u226f\\u1823\\uff0e\\u6c01\\ud960\\udff1\\ua06b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1843\\ud835\\udfe7>\\u0338\\u1823\\uff0e\\u6c01\\ud960\\udff1\\ua06b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u18435\\u226f\\u1823.\\u6c01\\ud960\\udff1\\ua06b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u18435>\\u0338\\u1823.\\u6c01\\ud960\\udff1\\ua06b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--5-24jyf768b.xn--lqw213ime95g\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"-\\ud804\\ude36\\u248f\\uff0e\\u248e\\ud881\\udee2\\udb40\\udfad\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"-\\ud804\\ude368..7.\\ud881\\udee2\\udb40\\udfad\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"xn---8-bv5o..7.xn--c35nf1622b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn----scp6252h.xn--zshy411yzpx2d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200c\\u10a1\\u755d\\u200d\\uff0e\\u226e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200c\\u10a1\\u755d\\u200d\\uff0e<\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200c\\u10a1\\u755d\\u200d.\\u226e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200c\\u10a1\\u755d\\u200d.<\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200c\\u2d01\\u755d\\u200d.<\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200c\\u2d01\\u755d\\u200d.\\u226e\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--skjy82u.xn--gdh\",\n    \"output\": \"xn--skjy82u.xn--gdh\"\n  },\n  {\n    \"input\": \"\\u2d01\\u755d.\\u226e\",\n    \"output\": \"xn--skjy82u.xn--gdh\"\n  },\n  {\n    \"input\": \"\\u2d01\\u755d.<\\u0338\",\n    \"output\": \"xn--skjy82u.xn--gdh\"\n  },\n  {\n    \"input\": \"\\u10a1\\u755d.<\\u0338\",\n    \"output\": \"xn--skjy82u.xn--gdh\"\n  },\n  {\n    \"input\": \"\\u10a1\\u755d.\\u226e\",\n    \"output\": \"xn--skjy82u.xn--gdh\"\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"xn--0ugc160hb36e.xn--gdh\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200c\\u2d01\\u755d\\u200d\\uff0e<\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200c\\u2d01\\u755d\\u200d\\uff0e\\u226e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--8md0962c.xn--gdh\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V7\",\n    \"input\": \"xn--8md700fea3748f.xn--gdh\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\u0ecb\\u200d\\uff0e\\u9381\\udb43\\udc11\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\u0ecb\\u200d.\\u9381\\udb43\\udc11\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--t8c.xn--iz4a43209d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"xn--t8c059f.xn--iz4a43209d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\ud9e5\\udef4.-\\u1862\\u0592\\ud836\\ude20\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn--ep37b.xn----hec165lho83b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\ud8bc\\udc2b\\uff0e\\u1baa\\u03c2\\u10a6\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\ud8bc\\udc2b.\\u1baa\\u03c2\\u10a6\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\ud8bc\\udc2b.\\u1baa\\u03c2\\u2d06\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\ud8bc\\udc2b.\\u1baa\\u03a3\\u10a6\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\ud8bc\\udc2b.\\u1baa\\u03c3\\u2d06\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\ud8bc\\udc2b.\\u1baa\\u03a3\\u2d06\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--nu4s.xn--4xa153j7im\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"xn--nu4s.xn--4xa153jk8cs1q\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"xn--nu4s.xn--3xa353jk8cs1q\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\ud8bc\\udc2b\\uff0e\\u1baa\\u03c2\\u2d06\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\ud8bc\\udc2b\\uff0e\\u1baa\\u03a3\\u10a6\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\ud8bc\\udc2b\\uff0e\\u1baa\\u03c3\\u2d06\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\ud8bc\\udc2b\\uff0e\\u1baa\\u03a3\\u2d06\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--nu4s.xn--4xa217dxri\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"xn--nu4s.xn--4xa217dxriome\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"xn--nu4s.xn--3xa417dxriome\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\u2488\\u200c\\uaaec\\ufe12\\uff0e\\u0acd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; A4_2 (ignored)\",\n    \"input\": \"1.\\u200c\\uaaec\\u3002.\\u0acd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"1.xn--sv9a..xn--mfc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; A4_2 (ignored)\",\n    \"input\": \"1.xn--0ug7185c..xn--mfc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--tsh0720cse8b.xn--mfc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"xn--0ug78o720myr1c.xn--mfc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\u00df\\u200d.\\u1bf2\\ud8d3\\udfbc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"SS\\u200d.\\u1bf2\\ud8d3\\udfbc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"ss\\u200d.\\u1bf2\\ud8d3\\udfbc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"Ss\\u200d.\\u1bf2\\ud8d3\\udfbc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"ss.xn--0zf22107b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"xn--ss-n1t.xn--0zf22107b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"xn--zca870n.xn--0zf22107b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud805\\udcc2\\u200c\\u226e.\\u226e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud805\\udcc2\\u200c<\\u0338.<\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--gdhz656g.xn--gdh\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--0ugy6glz29a.xn--gdh\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\ud83d\\udd7c\\uff0e\\uffa0\",\n    \"output\": \"xn--my8h.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\ud83d\\udd7c.\\u1160\",\n    \"output\": \"xn--my8h.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--my8h.\",\n    \"output\": \"xn--my8h.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\ud83d\\udd7c.\",\n    \"output\": \"xn--my8h.\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--my8h.xn--psd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--my8h.xn--cl7c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u7215\\uda8d\\ude51\\uff0e\\ud835\\udff0\\u6c17\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u7215\\uda8d\\ude51.4\\u6c17\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--1zxq3199c.xn--4-678b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V2 (ignored); V3 (ignored)\",\n    \"input\": \"\\udb39\\udf43\\u3002\\uda04\\udd83\\ud8e6\\udc97--\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V2 (ignored); V3 (ignored)\",\n    \"input\": \"xn--2y75e.xn-----1l15eer88n\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u8530\\u3002\\udb40\\udc79\\u08dd-\\ud804\\ude35\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--sz1a.xn----mrd9984r3dl0i\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\u03c2\\u10c5\\u3002\\u075a\",\n    \"output\": \"xn--3xa403s.xn--epb\"\n  },\n  {\n    \"input\": \"\\u03c2\\u2d25\\u3002\\u075a\",\n    \"output\": \"xn--3xa403s.xn--epb\"\n  },\n  {\n    \"input\": \"\\u03a3\\u10c5\\u3002\\u075a\",\n    \"output\": \"xn--4xa203s.xn--epb\"\n  },\n  {\n    \"input\": \"\\u03c3\\u2d25\\u3002\\u075a\",\n    \"output\": \"xn--4xa203s.xn--epb\"\n  },\n  {\n    \"input\": \"\\u03a3\\u2d25\\u3002\\u075a\",\n    \"output\": \"xn--4xa203s.xn--epb\"\n  },\n  {\n    \"input\": \"xn--4xa203s.xn--epb\",\n    \"output\": \"xn--4xa203s.xn--epb\"\n  },\n  {\n    \"input\": \"\\u03c3\\u2d25.\\u075a\",\n    \"output\": \"xn--4xa203s.xn--epb\"\n  },\n  {\n    \"input\": \"\\u03a3\\u10c5.\\u075a\",\n    \"output\": \"xn--4xa203s.xn--epb\"\n  },\n  {\n    \"input\": \"\\u03a3\\u2d25.\\u075a\",\n    \"output\": \"xn--4xa203s.xn--epb\"\n  },\n  {\n    \"input\": \"xn--3xa403s.xn--epb\",\n    \"output\": \"xn--3xa403s.xn--epb\"\n  },\n  {\n    \"input\": \"\\u03c2\\u2d25.\\u075a\",\n    \"output\": \"xn--3xa403s.xn--epb\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--4xa477d.xn--epb\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--3xa677d.xn--epb\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--vkb.xn--08e172a\",\n    \"output\": \"xn--vkb.xn--08e172a\"\n  },\n  {\n    \"input\": \"\\u06bc.\\u1e8f\\u1864\",\n    \"output\": \"xn--vkb.xn--08e172a\"\n  },\n  {\n    \"input\": \"\\u06bc.y\\u0307\\u1864\",\n    \"output\": \"xn--vkb.xn--08e172a\"\n  },\n  {\n    \"input\": \"\\u06bc.Y\\u0307\\u1864\",\n    \"output\": \"xn--vkb.xn--08e172a\"\n  },\n  {\n    \"input\": \"\\u06bc.\\u1e8e\\u1864\",\n    \"output\": \"xn--vkb.xn--08e172a\"\n  },\n  {\n    \"input\": \"xn--pt9c.xn--0kjya\",\n    \"output\": \"xn--pt9c.xn--0kjya\"\n  },\n  {\n    \"input\": \"\\ud802\\ude57.\\u2d09\\u2d15\",\n    \"output\": \"xn--pt9c.xn--0kjya\"\n  },\n  {\n    \"input\": \"\\ud802\\ude57.\\u10a9\\u10b5\",\n    \"output\": \"xn--pt9c.xn--0kjya\"\n  },\n  {\n    \"input\": \"\\ud802\\ude57.\\u10a9\\u2d15\",\n    \"output\": \"xn--pt9c.xn--0kjya\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--pt9c.xn--hnd666l\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--pt9c.xn--hndy\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\u200c\\u200c\\u3124\\uff0e\\u032e\\udb16\\ude11\\u09c2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\u200c\\u200c\\u3124.\\u032e\\udb16\\ude11\\u09c2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--1fk.xn--vta284a9o563a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"xn--0uga242k.xn--vta284a9o563a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u10b4\\ud836\\ude28\\u2083\\udb40\\udc66\\uff0e\\ud835\\udff3\\ud804\\udcb9\\u0b82\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u10b4\\ud836\\ude283\\udb40\\udc66.7\\ud804\\udcb9\\u0b82\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2d14\\ud836\\ude283\\udb40\\udc66.7\\ud804\\udcb9\\u0b82\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--3-ews6985n35s3g.xn--7-cve6271r\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2d14\\ud836\\ude28\\u2083\\udb40\\udc66\\uff0e\\ud835\\udff3\\ud804\\udcb9\\u0b82\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--3-b1g83426a35t0g.xn--7-cve6271r\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u43c8\\u200c\\u3002\\u200c\\u2488\\ud986\\udc95\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u43c8\\u200c\\u3002\\u200c1.\\ud986\\udc95\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--eco.1.xn--ms39a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--0ug491l.xn--1-rgn.xn--ms39a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--eco.xn--tsh21126d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--0ug491l.xn--0ug88oot66q\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\uff11\\uaaf6\\u00df\\ud807\\udca5\\uff61\\u1dd8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"1\\uaaf6\\u00df\\ud807\\udca5\\u3002\\u1dd8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"1\\uaaf6SS\\ud807\\udca5\\u3002\\u1dd8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"1\\uaaf6ss\\ud807\\udca5\\u3002\\u1dd8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--1ss-ir6ln166b.xn--weg\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--1-qfa2471kdb0d.xn--weg\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\uff11\\uaaf6SS\\ud807\\udca5\\uff61\\u1dd8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\uff11\\uaaf6ss\\ud807\\udca5\\uff61\\u1dd8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"1\\uaaf6Ss\\ud807\\udca5\\u3002\\u1dd8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\uff11\\uaaf6Ss\\ud807\\udca5\\uff61\\u1dd8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--3j78f.xn--mkb20b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud88a\\udd31\\u249b\\u2fb3\\uff0e\\ua866\\u2488\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\ud88a\\udd3120.\\u97f3.\\ua8661.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"xn--20-9802c.xn--0w5a.xn--1-eg4e.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--dth6033bzbvx.xn--tsh9439b\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\u10b5\\u3002\\u06f0\\u226e\\u00df\\u0745\",\n    \"output\": \"xn--dlj.xn--zca912alh227g\"\n  },\n  {\n    \"input\": \"\\u10b5\\u3002\\u06f0<\\u0338\\u00df\\u0745\",\n    \"output\": \"xn--dlj.xn--zca912alh227g\"\n  },\n  {\n    \"input\": \"\\u2d15\\u3002\\u06f0<\\u0338\\u00df\\u0745\",\n    \"output\": \"xn--dlj.xn--zca912alh227g\"\n  },\n  {\n    \"input\": \"\\u2d15\\u3002\\u06f0\\u226e\\u00df\\u0745\",\n    \"output\": \"xn--dlj.xn--zca912alh227g\"\n  },\n  {\n    \"input\": \"\\u10b5\\u3002\\u06f0\\u226eSS\\u0745\",\n    \"output\": \"xn--dlj.xn--ss-jbe65aw27i\"\n  },\n  {\n    \"input\": \"\\u10b5\\u3002\\u06f0<\\u0338SS\\u0745\",\n    \"output\": \"xn--dlj.xn--ss-jbe65aw27i\"\n  },\n  {\n    \"input\": \"\\u2d15\\u3002\\u06f0<\\u0338ss\\u0745\",\n    \"output\": \"xn--dlj.xn--ss-jbe65aw27i\"\n  },\n  {\n    \"input\": \"\\u2d15\\u3002\\u06f0\\u226ess\\u0745\",\n    \"output\": \"xn--dlj.xn--ss-jbe65aw27i\"\n  },\n  {\n    \"input\": \"\\u10b5\\u3002\\u06f0\\u226eSs\\u0745\",\n    \"output\": \"xn--dlj.xn--ss-jbe65aw27i\"\n  },\n  {\n    \"input\": \"\\u10b5\\u3002\\u06f0<\\u0338Ss\\u0745\",\n    \"output\": \"xn--dlj.xn--ss-jbe65aw27i\"\n  },\n  {\n    \"input\": \"xn--dlj.xn--ss-jbe65aw27i\",\n    \"output\": \"xn--dlj.xn--ss-jbe65aw27i\"\n  },\n  {\n    \"input\": \"\\u2d15.\\u06f0\\u226ess\\u0745\",\n    \"output\": \"xn--dlj.xn--ss-jbe65aw27i\"\n  },\n  {\n    \"input\": \"\\u2d15.\\u06f0<\\u0338ss\\u0745\",\n    \"output\": \"xn--dlj.xn--ss-jbe65aw27i\"\n  },\n  {\n    \"input\": \"\\u10b5.\\u06f0<\\u0338SS\\u0745\",\n    \"output\": \"xn--dlj.xn--ss-jbe65aw27i\"\n  },\n  {\n    \"input\": \"\\u10b5.\\u06f0\\u226eSS\\u0745\",\n    \"output\": \"xn--dlj.xn--ss-jbe65aw27i\"\n  },\n  {\n    \"input\": \"\\u10b5.\\u06f0\\u226eSs\\u0745\",\n    \"output\": \"xn--dlj.xn--ss-jbe65aw27i\"\n  },\n  {\n    \"input\": \"\\u10b5.\\u06f0<\\u0338Ss\\u0745\",\n    \"output\": \"xn--dlj.xn--ss-jbe65aw27i\"\n  },\n  {\n    \"input\": \"xn--dlj.xn--zca912alh227g\",\n    \"output\": \"xn--dlj.xn--zca912alh227g\"\n  },\n  {\n    \"input\": \"\\u2d15.\\u06f0\\u226e\\u00df\\u0745\",\n    \"output\": \"xn--dlj.xn--zca912alh227g\"\n  },\n  {\n    \"input\": \"\\u2d15.\\u06f0<\\u0338\\u00df\\u0745\",\n    \"output\": \"xn--dlj.xn--zca912alh227g\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--tnd.xn--ss-jbe65aw27i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--tnd.xn--zca912alh227g\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--ge6h.xn--oc9a\",\n    \"output\": \"xn--ge6h.xn--oc9a\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd28.\\ua84f\",\n    \"output\": \"xn--ge6h.xn--oc9a\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd06.\\ua84f\",\n    \"output\": \"xn--ge6h.xn--oc9a\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2132\\udb40\\udd7a\\ud937\\udd52\\u3002\\u226f\\u2f91\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2132\\udb40\\udd7a\\ud937\\udd52\\u3002>\\u0338\\u2f91\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2132\\udb40\\udd7a\\ud937\\udd52\\u3002\\u226f\\u897e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2132\\udb40\\udd7a\\ud937\\udd52\\u3002>\\u0338\\u897e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u214e\\udb40\\udd7a\\ud937\\udd52\\u3002>\\u0338\\u897e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u214e\\udb40\\udd7a\\ud937\\udd52\\u3002\\u226f\\u897e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--73g39298c.xn--hdhz171b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u214e\\udb40\\udd7a\\ud937\\udd52\\u3002>\\u0338\\u2f91\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u214e\\udb40\\udd7a\\ud937\\udd52\\u3002\\u226f\\u2f91\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--f3g73398c.xn--hdhz171b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u200c.\\u00df\\u10a9-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u200c.\\u00df\\u2d09-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u200c.SS\\u10a9-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u200c.ss\\u2d09-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"\\u200c.Ss\\u2d09-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V3 (ignored); A4_2 (ignored)\",\n    \"input\": \".xn--ss--bi1b\",\n    \"output\": \".xn--ss--bi1b\"\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"xn--0ug.xn--ss--bi1b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V3 (ignored)\",\n    \"input\": \"xn--0ug.xn----pfa2305a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored); A4_2 (ignored)\",\n    \"input\": \".xn--ss--4rn\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"xn--0ug.xn--ss--4rn\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"xn--0ug.xn----pfa042j\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\u9f59--\\ud835\\udff0.\\u00df\",\n    \"output\": \"xn----4-p16k.xn--zca\"\n  },\n  {\n    \"input\": \"\\u9f59--4.\\u00df\",\n    \"output\": \"xn----4-p16k.xn--zca\"\n  },\n  {\n    \"input\": \"\\u9f59--4.SS\",\n    \"output\": \"xn----4-p16k.ss\"\n  },\n  {\n    \"input\": \"\\u9f59--4.ss\",\n    \"output\": \"xn----4-p16k.ss\"\n  },\n  {\n    \"input\": \"\\u9f59--4.Ss\",\n    \"output\": \"xn----4-p16k.ss\"\n  },\n  {\n    \"input\": \"xn----4-p16k.ss\",\n    \"output\": \"xn----4-p16k.ss\"\n  },\n  {\n    \"input\": \"xn----4-p16k.xn--zca\",\n    \"output\": \"xn----4-p16k.xn--zca\"\n  },\n  {\n    \"input\": \"\\u9f59--\\ud835\\udff0.SS\",\n    \"output\": \"xn----4-p16k.ss\"\n  },\n  {\n    \"input\": \"\\u9f59--\\ud835\\udff0.ss\",\n    \"output\": \"xn----4-p16k.ss\"\n  },\n  {\n    \"input\": \"\\u9f59--\\ud835\\udff0.Ss\",\n    \"output\": \"xn----4-p16k.ss\"\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\udb42\\udea2-\\u3002\\uda2c\\udc8f\\u226e\\ud805\\udf2b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\udb42\\udea2-\\u3002\\uda2c\\udc8f<\\u0338\\ud805\\udf2b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn----bh61m.xn--gdhz157g0em1d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V7\",\n    \"input\": \"\\u200c\\udb40\\ude79\\u200d\\u3002\\ud9f3\\udfe7\\u226e\\u10a9\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V7\",\n    \"input\": \"\\u200c\\udb40\\ude79\\u200d\\u3002\\ud9f3\\udfe7<\\u0338\\u10a9\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V7\",\n    \"input\": \"\\u200c\\udb40\\ude79\\u200d\\u3002\\ud9f3\\udfe7<\\u0338\\u2d09\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V7\",\n    \"input\": \"\\u200c\\udb40\\ude79\\u200d\\u3002\\ud9f3\\udfe7\\u226e\\u2d09\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--3n36e.xn--gdh992byu01p\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V7\",\n    \"input\": \"xn--0ugc90904y.xn--gdh992byu01p\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--3n36e.xn--hnd112gpz83n\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V7\",\n    \"input\": \"xn--0ugc90904y.xn--hnd112gpz83n\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud836\\ude9e\\u10b0\\uff61\\ucaa1\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud836\\ude9e\\u10b0\\uff61\\u110d\\u1168\\u11a8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud836\\ude9e\\u10b0\\u3002\\ucaa1\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud836\\ude9e\\u10b0\\u3002\\u110d\\u1168\\u11a8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud836\\ude9e\\u2d10\\u3002\\u110d\\u1168\\u11a8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud836\\ude9e\\u2d10\\u3002\\ucaa1\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--7kj1858k.xn--pi6b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud836\\ude9e\\u2d10\\uff61\\u110d\\u1168\\u11a8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud836\\ude9e\\u2d10\\uff61\\ucaa1\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--ond3755u.xn--pi6b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u1845\\uff10\\u200c\\uff61\\u23a2\\udb52\\ude04\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u18450\\u200c\\u3002\\u23a2\\udb52\\ude04\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--0-z6j.xn--8lh28773l\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--0-z6jy93b.xn--8lh28773l\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\ud88a\\udf9a\\uff19\\ua369\\u17d3\\uff0e\\u200d\\u00df\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\ud88a\\udf9a9\\ua369\\u17d3.\\u200d\\u00df\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\ud88a\\udf9a9\\ua369\\u17d3.\\u200dSS\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\ud88a\\udf9a9\\ua369\\u17d3.\\u200dss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--9-i0j5967eg3qz.ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--9-i0j5967eg3qz.xn--ss-l1t\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--9-i0j5967eg3qz.xn--zca770n\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\ud88a\\udf9a\\uff19\\ua369\\u17d3\\uff0e\\u200dSS\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\ud88a\\udf9a\\uff19\\ua369\\u17d3\\uff0e\\u200dss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\ud88a\\udf9a9\\ua369\\u17d3.\\u200dSs\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\ud88a\\udf9a\\uff19\\ua369\\u17d3\\uff0e\\u200dSs\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\ua5f7\\ud804\\udd80.\\u075d\\ud802\\ude52\",\n    \"output\": \"xn--ju8a625r.xn--hpb0073k\"\n  },\n  {\n    \"input\": \"xn--ju8a625r.xn--hpb0073k\",\n    \"output\": \"xn--ju8a625r.xn--hpb0073k\"\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\u2490\\u226f-\\u3002\\ufe12\\uda65\\udc63-\\ud939\\udee0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\u2490>\\u0338-\\u3002\\ufe12\\uda65\\udc63-\\ud939\\udee0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"9.\\u226f-\\u3002\\u3002\\uda65\\udc63-\\ud939\\udee0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"9.>\\u0338-\\u3002\\u3002\\uda65\\udc63-\\ud939\\udee0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"9.xn----ogo..xn----xj54d1s69k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn----ogot9g.xn----n89hl0522az9u2a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"\\u10af\\udb40\\udd4b-\\uff0e\\u200d\\u10a9\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"\\u10af\\udb40\\udd4b-.\\u200d\\u10a9\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"\\u2d0f\\udb40\\udd4b-.\\u200d\\u2d09\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"xn----3vs.xn--0kj\",\n    \"output\": \"xn----3vs.xn--0kj\"\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"xn----3vs.xn--1ug532c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"\\u2d0f\\udb40\\udd4b-\\uff0e\\u200d\\u2d09\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn----00g.xn--hnd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"xn----00g.xn--hnd399e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"\\u1714\\u3002\\udb40\\udda3-\\ud804\\udeea\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"xn--fze.xn----ly8i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"\\uabe8-\\uff0e\\uda60\\udfdc\\u05bd\\u00df\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"\\uabe8-.\\uda60\\udfdc\\u05bd\\u00df\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"\\uabe8-.\\uda60\\udfdc\\u05bdSS\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"\\uabe8-.\\uda60\\udfdc\\u05bdss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"\\uabe8-.\\uda60\\udfdc\\u05bdSs\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"xn----pw5e.xn--ss-7jd10716y\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"xn----pw5e.xn--zca50wfv060a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"\\uabe8-\\uff0e\\uda60\\udfdc\\u05bdSS\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"\\uabe8-\\uff0e\\uda60\\udfdc\\u05bdss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"\\uabe8-\\uff0e\\uda60\\udfdc\\u05bdSs\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud835\\udfe5\\u266e\\ud805\\udf2b\\u08ed\\uff0e\\u17d2\\ud805\\udf2b8\\udb40\\udd8f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"3\\u266e\\ud805\\udf2b\\u08ed.\\u17d2\\ud805\\udf2b8\\udb40\\udd8f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--3-ksd277tlo7s.xn--8-f0jx021l\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"-\\uff61\\uda14\\udf00\\u200d\\u2761\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"-\\u3002\\uda14\\udf00\\u200d\\u2761\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"-.xn--nei54421f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"-.xn--1ug800aq795s\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ud835\\udfd3\\u2631\\ud835\\udfd0\\uda57\\udc35\\uff61\\ud836\\udeae\\ud902\\udc73\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"5\\u26312\\uda57\\udc35\\u3002\\ud836\\udeae\\ud902\\udc73\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--52-dwx47758j.xn--kd3hk431k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"-.-\\u251c\\uda1a\\udda3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"-.xn----ukp70432h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u03c2\\uff0e\\ufdc1\\ud83d\\udf9b\\u2488\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u03c2.\\u0641\\u0645\\u064a\\ud83d\\udf9b1.\",\n    \"output\": \"xn--3xa.xn--1-gocmu97674d.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u03a3.\\u0641\\u0645\\u064a\\ud83d\\udf9b1.\",\n    \"output\": \"xn--4xa.xn--1-gocmu97674d.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u03c3.\\u0641\\u0645\\u064a\\ud83d\\udf9b1.\",\n    \"output\": \"xn--4xa.xn--1-gocmu97674d.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--4xa.xn--1-gocmu97674d.\",\n    \"output\": \"xn--4xa.xn--1-gocmu97674d.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--3xa.xn--1-gocmu97674d.\",\n    \"output\": \"xn--3xa.xn--1-gocmu97674d.\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u03a3\\uff0e\\ufdc1\\ud83d\\udf9b\\u2488\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u03c3\\uff0e\\ufdc1\\ud83d\\udf9b\\u2488\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--4xa.xn--dhbip2802atb20c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--3xa.xn--dhbip2802atb20c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"9\\udb40\\udde5\\uff0e\\udb6b\\udd34\\u1893\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"9\\udb40\\udde5.\\udb6b\\udd34\\u1893\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"9.xn--dbf91222q\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\ufe12\\u10b6\\u0366\\uff0e\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; A4_2 (ignored)\",\n    \"input\": \"\\u3002\\u10b6\\u0366.\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; A4_2 (ignored)\",\n    \"input\": \"\\u3002\\u2d16\\u0366.\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \".xn--hva754s.\",\n    \"output\": \".xn--hva754s.\"\n  },\n  {\n    \"comment\": \"C1; A4_2 (ignored)\",\n    \"input\": \".xn--hva754s.xn--0ug\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\ufe12\\u2d16\\u0366\\uff0e\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"xn--hva754sy94k.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--hva754sy94k.xn--0ug\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \".xn--hva929d.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; A4_2 (ignored)\",\n    \"input\": \".xn--hva929d.xn--0ug\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"xn--hva929dl29p.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--hva929dl29p.xn--0ug\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--hva754s.\",\n    \"output\": \"xn--hva754s.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u2d16\\u0366.\",\n    \"output\": \"xn--hva754s.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u10b6\\u0366.\",\n    \"output\": \"xn--hva754s.\"\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"xn--hva929d.\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--hzb.xn--ukj4430l\",\n    \"output\": \"xn--hzb.xn--ukj4430l\"\n  },\n  {\n    \"input\": \"\\u08bb.\\u2d03\\ud838\\udc12\",\n    \"output\": \"xn--hzb.xn--ukj4430l\"\n  },\n  {\n    \"input\": \"\\u08bb.\\u10a3\\ud838\\udc12\",\n    \"output\": \"xn--hzb.xn--ukj4430l\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--hzb.xn--bnd2938u\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V7\",\n    \"input\": \"\\u200d\\u200c\\u3002\\uff12\\u4af7\\udb42\\uddf7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V7\",\n    \"input\": \"\\u200d\\u200c\\u30022\\u4af7\\udb42\\uddf7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \".xn--2-me5ay1273i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V7\",\n    \"input\": \"xn--0ugb.xn--2-me5ay1273i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"-\\ud838\\udc24\\udb32\\udc10\\u3002\\ud9e2\\udf16\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn----rq4re4997d.xn--l707b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\udb8d\\udec2\\ufe12\\u200c\\u37c0\\uff0e\\u0624\\u2488\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\udb8d\\udec2\\ufe12\\u200c\\u37c0\\uff0e\\u0648\\u0654\\u2488\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"xn--z272f.xn--etl.xn--1-smc.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--etlt457ccrq7h.xn--jgb476m\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--0ug754gxl4ldlt0k.xn--jgb476m\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u07fc\\ud803\\ude06.\\ud80d\\udd8f\\ufe12\\ud8ea\\ude29\\u10b0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u07fc\\ud803\\ude06.\\ud80d\\udd8f\\u3002\\ud8ea\\ude29\\u10b0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u07fc\\ud803\\ude06.\\ud80d\\udd8f\\u3002\\ud8ea\\ude29\\u2d10\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--0tb8725k.xn--tu8d.xn--7kj73887a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u07fc\\ud803\\ude06.\\ud80d\\udd8f\\ufe12\\ud8ea\\ude29\\u2d10\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--0tb8725k.xn--7kj9008dt18a7py9c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--0tb8725k.xn--tu8d.xn--ond97931d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--0tb8725k.xn--ond3562jt18a7py9c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u10c5\\u26ad\\udb41\\uddab\\u22c3\\uff61\\ud804\\udf3c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u10c5\\u26ad\\udb41\\uddab\\u22c3\\u3002\\ud804\\udf3c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u2d25\\u26ad\\udb41\\uddab\\u22c3\\u3002\\ud804\\udf3c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--vfh16m67gx1162b.xn--ro1d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u2d25\\u26ad\\udb41\\uddab\\u22c3\\uff61\\ud804\\udf3c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--9nd623g4zc5z060c.xn--ro1d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"\\udb40\\udd93\\u26cf-\\u3002\\ua852\",\n    \"output\": \"xn----o9p.xn--rc9a\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"xn----o9p.xn--rc9a\",\n    \"output\": \"xn----o9p.xn--rc9a\"\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\ud8c8\\ude26\\u5e37\\uff61\\u226f\\u843a\\u1dc8-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\ud8c8\\ude26\\u5e37\\uff61>\\u0338\\u843a\\u1dc8-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\ud8c8\\ude26\\u5e37\\u3002\\u226f\\u843a\\u1dc8-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\ud8c8\\ude26\\u5e37\\u3002>\\u0338\\u843a\\u1dc8-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn--qutw175s.xn----mimu6tf67j\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u200d\\u650c\\uabed\\u3002\\u1896-\\u10b8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u200d\\u650c\\uabed\\u3002\\u1896-\\u2d18\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--p9ut19m.xn----mck373i\",\n    \"output\": \"xn--p9ut19m.xn----mck373i\"\n  },\n  {\n    \"input\": \"\\u650c\\uabed.\\u1896-\\u2d18\",\n    \"output\": \"xn--p9ut19m.xn----mck373i\"\n  },\n  {\n    \"input\": \"\\u650c\\uabed.\\u1896-\\u10b8\",\n    \"output\": \"xn--p9ut19m.xn----mck373i\"\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"xn--1ug592ykp6b.xn----mck373i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--p9ut19m.xn----k1g451d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--1ug592ykp6b.xn----k1g451d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u200c\\ua5a8\\uff0e\\u2497\\uff13\\ud212\\u06f3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u200c\\ua5a8\\uff0e\\u2497\\uff13\\u1110\\u116d\\u11a9\\u06f3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u200c\\ua5a8.16.3\\ud212\\u06f3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u200c\\ua5a8.16.3\\u1110\\u116d\\u11a9\\u06f3\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--9r8a.16.xn--3-nyc0117m\",\n    \"output\": \"xn--9r8a.16.xn--3-nyc0117m\"\n  },\n  {\n    \"input\": \"\\ua5a8.16.3\\ud212\\u06f3\",\n    \"output\": \"xn--9r8a.16.xn--3-nyc0117m\"\n  },\n  {\n    \"input\": \"\\ua5a8.16.3\\u1110\\u116d\\u11a9\\u06f3\",\n    \"output\": \"xn--9r8a.16.xn--3-nyc0117m\"\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"xn--0ug2473c.16.xn--3-nyc0117m\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--9r8a.xn--3-nyc678tu07m\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--0ug2473c.xn--3-nyc678tu07m\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\ud835\\udfcf\\ud836\\ude19\\u2e16.\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"1\\ud836\\ude19\\u2e16.\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--1-5bt6845n.\",\n    \"output\": \"xn--1-5bt6845n.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"1\\ud836\\ude19\\u2e16.\",\n    \"output\": \"xn--1-5bt6845n.\"\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"xn--1-5bt6845n.xn--1ug\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"F\\udb40\\udd5f\\uff61\\ud9fd\\uddc5\\u265a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"F\\udb40\\udd5f\\u3002\\ud9fd\\uddc5\\u265a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"f\\udb40\\udd5f\\u3002\\ud9fd\\uddc5\\u265a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"f.xn--45hz6953f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"f\\udb40\\udd5f\\uff61\\ud9fd\\uddc5\\u265a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u0b4d\\ud804\\udd34\\u1de9\\u3002\\ud835\\udfee\\u10b8\\ud838\\udc28\\ud8ce\\udd47\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u0b4d\\ud804\\udd34\\u1de9\\u30022\\u10b8\\ud838\\udc28\\ud8ce\\udd47\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u0b4d\\ud804\\udd34\\u1de9\\u30022\\u2d18\\ud838\\udc28\\ud8ce\\udd47\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--9ic246gs21p.xn--2-nws2918ndrjr\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u0b4d\\ud804\\udd34\\u1de9\\u3002\\ud835\\udfee\\u2d18\\ud838\\udc28\\ud8ce\\udd47\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--9ic246gs21p.xn--2-k1g43076adrwq\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\uda0e\\udc2d\\u200c\\u200c\\u2488\\u3002\\u52c9\\ud804\\udc45\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; A4_2 (ignored)\",\n    \"input\": \"\\uda0e\\udc2d\\u200c\\u200c1.\\u3002\\u52c9\\ud804\\udc45\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"xn--1-yi00h..xn--4grs325b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; A4_2 (ignored)\",\n    \"input\": \"xn--1-rgna61159u..xn--4grs325b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--tsh11906f.xn--4grs325b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--0uga855aez302a.xn--4grs325b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1843.\\u73bf\\ud96c\\ude1c\\udb15\\udf90\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--27e.xn--7cy81125a0yq4a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u200c\\u200c\\uff61\\u2488\\u226f\\ud835\\udff5\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u200c\\u200c\\uff61\\u2488>\\u0338\\ud835\\udff5\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u200c\\u200c\\u30021.\\u226f9\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u200c\\u200c\\u30021.>\\u03389\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \".1.xn--9-ogo\",\n    \"output\": \".1.xn--9-ogo\"\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"xn--0uga.1.xn--9-ogo\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \".xn--9-ogo37g\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--0uga.xn--9-ogo37g\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"\\u20da\\uff0e\\ud805\\ude3f-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"\\u20da.\\ud805\\ude3f-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"xn--w0g.xn----bd0j\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\u1082-\\u200d\\ua8ea\\uff0e\\ua84a\\u200d\\ud9b3\\ude33\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\u1082-\\u200d\\ua8ea.\\ua84a\\u200d\\ud9b3\\ude33\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn----gyg3618i.xn--jc9ao4185a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"xn----gyg250jio7k.xn--1ug8774cri56d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud804\\ude35\\u5eca.\\ud802\\udc0d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--xytw701b.xn--yc9c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u10be\\ud899\\udec0\\ud82d\\uddfb\\uff0e\\u1897\\ub9ab\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u10be\\ud899\\udec0\\ud82d\\uddfb\\uff0e\\u1897\\u1105\\u1174\\u11c2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u10be\\ud899\\udec0\\ud82d\\uddfb.\\u1897\\ub9ab\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u10be\\ud899\\udec0\\ud82d\\uddfb.\\u1897\\u1105\\u1174\\u11c2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2d1e\\ud899\\udec0\\ud82d\\uddfb.\\u1897\\u1105\\u1174\\u11c2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2d1e\\ud899\\udec0\\ud82d\\uddfb.\\u1897\\ub9ab\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--mlj0486jgl2j.xn--hbf6853f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2d1e\\ud899\\udec0\\ud82d\\uddfb\\uff0e\\u1897\\u1105\\u1174\\u11c2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2d1e\\ud899\\udec0\\ud82d\\uddfb\\uff0e\\u1897\\ub9ab\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--2nd8876sgl2j.xn--hbf6853f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u00df\\u200d\\u103a\\uff61\\u2488\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--ss-f4j.b.\",\n    \"output\": \"xn--ss-f4j.b.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"ss\\u103a.b.\",\n    \"output\": \"xn--ss-f4j.b.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"SS\\u103a.B.\",\n    \"output\": \"xn--ss-f4j.b.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"Ss\\u103a.b.\",\n    \"output\": \"xn--ss-f4j.b.\"\n  },\n  {\n    \"comment\": \"C2; A4_2 (ignored)\",\n    \"input\": \"xn--ss-f4j585j.b.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; A4_2 (ignored)\",\n    \"input\": \"xn--zca679eh2l.b.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"SS\\u200d\\u103a\\uff61\\u2488\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"ss\\u200d\\u103a\\uff61\\u2488\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"Ss\\u200d\\u103a\\uff61\\u2488\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--ss-f4j.xn--tsh\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--ss-f4j585j.xn--tsh\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--zca679eh2l.xn--tsh\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"SS\\u103a.b.\",\n    \"output\": \"xn--ss-f4j.b.\"\n  },\n  {\n    \"input\": \"\\u06cc\\ud802\\ude3f\\uff0e\\u00df\\u0f84\\ud804\\udf6c\",\n    \"output\": \"xn--clb2593k.xn--zca216edt0r\"\n  },\n  {\n    \"input\": \"\\u06cc\\ud802\\ude3f.\\u00df\\u0f84\\ud804\\udf6c\",\n    \"output\": \"xn--clb2593k.xn--zca216edt0r\"\n  },\n  {\n    \"input\": \"\\u06cc\\ud802\\ude3f.SS\\u0f84\\ud804\\udf6c\",\n    \"output\": \"xn--clb2593k.xn--ss-toj6092t\"\n  },\n  {\n    \"input\": \"\\u06cc\\ud802\\ude3f.ss\\u0f84\\ud804\\udf6c\",\n    \"output\": \"xn--clb2593k.xn--ss-toj6092t\"\n  },\n  {\n    \"input\": \"xn--clb2593k.xn--ss-toj6092t\",\n    \"output\": \"xn--clb2593k.xn--ss-toj6092t\"\n  },\n  {\n    \"input\": \"xn--clb2593k.xn--zca216edt0r\",\n    \"output\": \"xn--clb2593k.xn--zca216edt0r\"\n  },\n  {\n    \"input\": \"\\u06cc\\ud802\\ude3f\\uff0eSS\\u0f84\\ud804\\udf6c\",\n    \"output\": \"xn--clb2593k.xn--ss-toj6092t\"\n  },\n  {\n    \"input\": \"\\u06cc\\ud802\\ude3f\\uff0ess\\u0f84\\ud804\\udf6c\",\n    \"output\": \"xn--clb2593k.xn--ss-toj6092t\"\n  },\n  {\n    \"input\": \"\\u06cc\\ud802\\ude3f.Ss\\u0f84\\ud804\\udf6c\",\n    \"output\": \"xn--clb2593k.xn--ss-toj6092t\"\n  },\n  {\n    \"input\": \"\\u06cc\\ud802\\ude3f\\uff0eSs\\u0f84\\ud804\\udf6c\",\n    \"output\": \"xn--clb2593k.xn--ss-toj6092t\"\n  },\n  {\n    \"comment\": \"C1; A4_2 (ignored)\",\n    \"input\": \"\\ud835\\udfe0\\u226e\\u200c\\uff61\\udb40\\udd71\\u17b4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; A4_2 (ignored)\",\n    \"input\": \"\\ud835\\udfe0<\\u0338\\u200c\\uff61\\udb40\\udd71\\u17b4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; A4_2 (ignored)\",\n    \"input\": \"8\\u226e\\u200c\\u3002\\udb40\\udd71\\u17b4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; A4_2 (ignored)\",\n    \"input\": \"8<\\u0338\\u200c\\u3002\\udb40\\udd71\\u17b4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--8-ngo.\",\n    \"output\": \"xn--8-ngo.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"8\\u226e.\",\n    \"output\": \"xn--8-ngo.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"8<\\u0338.\",\n    \"output\": \"xn--8-ngo.\"\n  },\n  {\n    \"comment\": \"C1; A4_2 (ignored)\",\n    \"input\": \"xn--8-sgn10i.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--8-ngo.xn--z3e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"xn--8-sgn10i.xn--z3e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1895\\u226f\\ufe12\\ud8d0\\udcaf\\uff0e\\u10a0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1895>\\u0338\\ufe12\\ud8d0\\udcaf\\uff0e\\u10a0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1895\\u226f\\u3002\\ud8d0\\udcaf.\\u10a0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1895>\\u0338\\u3002\\ud8d0\\udcaf.\\u10a0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1895>\\u0338\\u3002\\ud8d0\\udcaf.\\u2d00\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1895\\u226f\\u3002\\ud8d0\\udcaf.\\u2d00\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--fbf851c.xn--ko1u.xn--rkj\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1895>\\u0338\\ufe12\\ud8d0\\udcaf\\uff0e\\u2d00\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1895\\u226f\\ufe12\\ud8d0\\udcaf\\uff0e\\u2d00\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--fbf851cq98poxw1a.xn--rkj\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--fbf851c.xn--ko1u.xn--7md\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--fbf851cq98poxw1a.xn--7md\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"\\u0f9f\\uff0e-\\u082a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"\\u0f9f.-\\u082a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"xn--vfd.xn----fhd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1d6c\\udb40\\udda0\\uff0e\\ud552\\u2492\\u2488\\udbe0\\udd26\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1d6c\\udb40\\udda0\\uff0e\\u1111\\u1175\\u11bd\\u2492\\u2488\\udbe0\\udd26\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1d6c\\udb40\\udda0.\\ud55211.1.\\udbe0\\udd26\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1d6c\\udb40\\udda0.\\u1111\\u1175\\u11bd11.1.\\udbe0\\udd26\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--tbg.xn--11-5o7k.1.xn--k469f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--tbg.xn--tsht7586kyts9l\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2488\\u270c\\uda3e\\udf1f\\uff0e\\ud835\\udfe1\\ud943\\udc63\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"1.\\u270c\\uda3e\\udf1f.9\\ud943\\udc63\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"1.xn--7bi44996f.xn--9-o706d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--tsh24g49550b.xn--9-o706d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u03c2\\uff0e\\ua9c0\\ua8c4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u03c2.\\ua9c0\\ua8c4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u03a3.\\ua9c0\\ua8c4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u03c3.\\ua9c0\\ua8c4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--4xa.xn--0f9ars\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--3xa.xn--0f9ars\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u03a3\\uff0e\\ua9c0\\ua8c4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u03c3\\uff0e\\ua9c0\\ua8c4\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\u7f9a\\uff61\\u226f\",\n    \"output\": \"xn--xt0a.xn--hdh\"\n  },\n  {\n    \"input\": \"\\u7f9a\\uff61>\\u0338\",\n    \"output\": \"xn--xt0a.xn--hdh\"\n  },\n  {\n    \"input\": \"\\u7f9a\\u3002\\u226f\",\n    \"output\": \"xn--xt0a.xn--hdh\"\n  },\n  {\n    \"input\": \"\\u7f9a\\u3002>\\u0338\",\n    \"output\": \"xn--xt0a.xn--hdh\"\n  },\n  {\n    \"input\": \"xn--xt0a.xn--hdh\",\n    \"output\": \"xn--xt0a.xn--hdh\"\n  },\n  {\n    \"input\": \"\\u7f9a.\\u226f\",\n    \"output\": \"xn--xt0a.xn--hdh\"\n  },\n  {\n    \"input\": \"\\u7f9a.>\\u0338\",\n    \"output\": \"xn--xt0a.xn--hdh\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2786\\ud99e\\uddd5\\u1ed7\\u2488\\uff0e\\uda06\\udf12\\ud945\\ude2e\\u085b\\ud835\\udfeb\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2786\\ud99e\\uddd5o\\u0302\\u0303\\u2488\\uff0e\\uda06\\udf12\\ud945\\ude2e\\u085b\\ud835\\udfeb\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\u2786\\ud99e\\uddd5\\u1ed71..\\uda06\\udf12\\ud945\\ude2e\\u085b9\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\u2786\\ud99e\\uddd5o\\u0302\\u03031..\\uda06\\udf12\\ud945\\ude2e\\u085b9\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\u2786\\ud99e\\uddd5O\\u0302\\u03031..\\uda06\\udf12\\ud945\\ude2e\\u085b9\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\u2786\\ud99e\\uddd5\\u1ed61..\\uda06\\udf12\\ud945\\ude2e\\u085b9\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"xn--1-3xm292b6044r..xn--9-6jd87310jtcqs\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2786\\ud99e\\uddd5O\\u0302\\u0303\\u2488\\uff0e\\uda06\\udf12\\ud945\\ude2e\\u085b\\ud835\\udfeb\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2786\\ud99e\\uddd5\\u1ed6\\u2488\\uff0e\\uda06\\udf12\\ud945\\ude2e\\u085b\\ud835\\udfeb\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--6lg26tvvc6v99z.xn--9-6jd87310jtcqs\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \".xn--ye6h\",\n    \"output\": \".xn--ye6h\"\n  },\n  {\n    \"input\": \"xn--ye6h\",\n    \"output\": \"xn--ye6h\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd3a\",\n    \"output\": \"xn--ye6h\"\n  },\n  {\n    \"input\": \"\\ud83a\\udd18\",\n    \"output\": \"xn--ye6h\"\n  },\n  {\n    \"comment\": \"C1; V6; V7; V3 (ignored)\",\n    \"input\": \"\\u073c\\u200c-\\u3002\\ud80d\\udc3e\\u00df\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7; V3 (ignored)\",\n    \"input\": \"\\u073c\\u200c-\\u3002\\ud80d\\udc3eSS\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7; V3 (ignored)\",\n    \"input\": \"\\u073c\\u200c-\\u3002\\ud80d\\udc3ess\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7; V3 (ignored)\",\n    \"input\": \"\\u073c\\u200c-\\u3002\\ud80d\\udc3eSs\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"xn----s2c.xn--ss-066q\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7; V3 (ignored)\",\n    \"input\": \"xn----s2c071q.xn--ss-066q\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7; V3 (ignored)\",\n    \"input\": \"xn----s2c071q.xn--zca7848m\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"-\\uda9d\\udf6c\\u135e\\ud805\\udf27.\\u1deb-\\ufe12\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"-\\uda9d\\udf6c\\u135e\\ud805\\udf27.\\u1deb-\\u3002\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"xn----b5h1837n2ok9f.xn----mkm.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"xn----b5h1837n2ok9f.xn----mkmw278h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ufe12.\\uda2a\\udc21\\u1a59\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\u3002.\\uda2a\\udc21\\u1a59\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"..xn--cof61594i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--y86c.xn--cof61594i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"\\ud807\\udc3a.-\\uda05\\udfcf\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"xn--jk3d.xn----iz68g\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb43\\udee9\\uff0e\\u8d4f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb43\\udee9.\\u8d4f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--2856e.xn--6o3a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u10ad\\uff0e\\ud8f4\\udde6\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u10ad.\\ud8f4\\udde6\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u2d0d.\\ud8f4\\udde6\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--4kj.xn--p01x\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--4kj.xn--0ug56448b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u2d0d\\uff0e\\ud8f4\\udde6\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--lnd.xn--p01x\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--lnd.xn--0ug56448b\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\ud835\\udfdb\\uff0e\\uf9f8\",\n    \"output\": \"3.xn--6vz\"\n  },\n  {\n    \"input\": \"\\ud835\\udfdb\\uff0e\\u7b20\",\n    \"output\": \"3.xn--6vz\"\n  },\n  {\n    \"input\": \"3.\\u7b20\",\n    \"output\": \"3.xn--6vz\"\n  },\n  {\n    \"input\": \"3.xn--6vz\",\n    \"output\": \"3.xn--6vz\"\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"-\\u200d.\\u10be\\ud800\\udef7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"-\\u200d.\\u2d1e\\ud800\\udef7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"-.xn--mlj8559d\",\n    \"output\": \"-.xn--mlj8559d\"\n  },\n  {\n    \"comment\": \"C2; V3 (ignored)\",\n    \"input\": \"xn----ugn.xn--mlj8559d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"-.xn--2nd2315j\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"xn----ugn.xn--2nd2315j\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u200d\\u03c2\\u00df\\u0731\\uff0e\\u0bcd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u200d\\u03c2\\u00df\\u0731.\\u0bcd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u200d\\u03a3SS\\u0731.\\u0bcd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u200d\\u03c3ss\\u0731.\\u0bcd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u200d\\u03a3ss\\u0731.\\u0bcd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--ss-ubc826a.xn--xmc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"xn--ss-ubc826ab34b.xn--xmc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u200d\\u03a3\\u00df\\u0731.\\u0bcd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u200d\\u03c3\\u00df\\u0731.\\u0bcd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"xn--zca39lk1di19a.xn--xmc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"xn--zca19ln1di19a.xn--xmc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u200d\\u03a3SS\\u0731\\uff0e\\u0bcd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u200d\\u03c3ss\\u0731\\uff0e\\u0bcd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u200d\\u03a3ss\\u0731\\uff0e\\u0bcd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u200d\\u03a3\\u00df\\u0731\\uff0e\\u0bcd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u200d\\u03c3\\u00df\\u0731\\uff0e\\u0bcd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u2260\\uff0e\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"=\\u0338\\uff0e\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u2260.\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"=\\u0338.\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--1ch.\",\n    \"output\": \"xn--1ch.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u2260.\",\n    \"output\": \"xn--1ch.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"=\\u0338.\",\n    \"output\": \"xn--1ch.\"\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"xn--1ch.xn--1ug\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb5c\\udef5\\u09cd\\u03c2\\uff0e\\u03c2\\ud802\\ude3f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb5c\\udef5\\u09cd\\u03c2.\\u03c2\\ud802\\ude3f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb5c\\udef5\\u09cd\\u03a3.\\u03a3\\ud802\\ude3f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb5c\\udef5\\u09cd\\u03c3.\\u03c2\\ud802\\ude3f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb5c\\udef5\\u09cd\\u03c3.\\u03c3\\ud802\\ude3f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb5c\\udef5\\u09cd\\u03a3.\\u03c3\\ud802\\ude3f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--4xa502av8297a.xn--4xa6055k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb5c\\udef5\\u09cd\\u03a3.\\u03c2\\ud802\\ude3f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--4xa502av8297a.xn--3xa8055k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--3xa702av8297a.xn--3xa8055k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb5c\\udef5\\u09cd\\u03a3\\uff0e\\u03a3\\ud802\\ude3f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb5c\\udef5\\u09cd\\u03c3\\uff0e\\u03c2\\ud802\\ude3f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb5c\\udef5\\u09cd\\u03c3\\uff0e\\u03c3\\ud802\\ude3f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb5c\\udef5\\u09cd\\u03a3\\uff0e\\u03c3\\ud802\\ude3f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb5c\\udef5\\u09cd\\u03a3\\uff0e\\u03c2\\ud802\\ude3f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud94e\\udd12\\uff61\\ub967\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud94e\\udd12\\uff61\\u1105\\u1172\\u11b6\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud94e\\udd12\\u3002\\ub967\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud94e\\udd12\\u3002\\u1105\\u1172\\u11b6\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--s264a.xn--pw2b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1846\\ud805\\udcdd\\uff0e\\ud83b\\udd46\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u1846\\ud805\\udcdd.\\ud83b\\udd46\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--57e0440k.xn--k86h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udbef\\udfe6\\uff61\\u183d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udbef\\udfe6\\u3002\\u183d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--j890g.xn--w7e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u5b03\\ud834\\udf4c\\uff0e\\u200d\\u0b44\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u5b03\\ud834\\udf4c.\\u200d\\u0b44\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--b6s0078f.xn--0ic\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"xn--b6s0078f.xn--0ic557h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u200c.\\ud93d\\udee4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \".xn--q823a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--0ug.xn--q823a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udaa9\\uded5\\u10a3\\u4805\\uff0e\\ud803\\ude11\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udaa9\\uded5\\u10a3\\u4805.\\ud803\\ude11\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udaa9\\uded5\\u2d03\\u4805.\\ud803\\ude11\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--ukju77frl47r.xn--yl0d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udaa9\\uded5\\u2d03\\u4805\\uff0e\\ud803\\ude11\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--bnd074zr557n.xn--yl0d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"-\\uff61\\ufe12\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"-\\u3002\\u3002\",\n    \"output\": \"-..\"\n  },\n  {\n    \"comment\": \"V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"-..\",\n    \"output\": \"-..\"\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"-.xn--y86c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u200d.F\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u200d.f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \".f\",\n    \"output\": \".f\"\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"xn--1ug.f\",\n    \"output\": null\n  },\n  {\n    \"input\": \"f\",\n    \"output\": \"f\"\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u200d\\u3a32\\uff61\\u00df\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u200d\\u3a32\\u3002\\u00df\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u200d\\u3a32\\u3002SS\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u200d\\u3a32\\u3002ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u200d\\u3a32\\u3002Ss\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--9bm.ss\",\n    \"output\": \"xn--9bm.ss\"\n  },\n  {\n    \"input\": \"\\u3a32.ss\",\n    \"output\": \"xn--9bm.ss\"\n  },\n  {\n    \"input\": \"\\u3a32.SS\",\n    \"output\": \"xn--9bm.ss\"\n  },\n  {\n    \"input\": \"\\u3a32.Ss\",\n    \"output\": \"xn--9bm.ss\"\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"xn--1ug914h.ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"xn--1ug914h.xn--zca\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u200d\\u3a32\\uff61SS\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u200d\\u3a32\\uff61ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\u200d\\u3a32\\uff61Ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u200d\\uff0e\\udbc3\\ude28\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u200d.\\udbc3\\ude28\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \".xn--h327f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--1ug.xn--h327f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud94e\\udf7b\\ud8f2\\udd41\\uff61\\u2260\\ud835\\udff2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud94e\\udf7b\\ud8f2\\udd41\\uff61=\\u0338\\ud835\\udff2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud94e\\udf7b\\ud8f2\\udd41\\u3002\\u22606\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud94e\\udf7b\\ud8f2\\udd41\\u3002=\\u03386\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--h79w4z99a.xn--6-tfo\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--98e.xn--om9c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\uaaf6\\u188f\\u0e3a\\uff12.\\ud800\\udee2\\u0745\\u0f9f\\ufe12\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"\\uaaf6\\u188f\\u0e3a2.\\ud800\\udee2\\u0745\\u0f9f\\u3002\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"xn--2-2zf840fk16m.xn--sob093b2m7s.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--2-2zf840fk16m.xn--sob093bj62sz9d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udad7\\udd27\\uff61\\u2260-\\udb41\\ude44\\u2f9b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udad7\\udd27\\uff61=\\u0338-\\udb41\\ude44\\u2f9b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udad7\\udd27\\u3002\\u2260-\\udb41\\ude44\\u8d70\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udad7\\udd27\\u3002=\\u0338-\\udb41\\ude44\\u8d70\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--gm57d.xn----tfo4949b3664m\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\ud835\\udfce\\u3002\\u752f\",\n    \"output\": \"0.xn--qny\"\n  },\n  {\n    \"input\": \"0\\u3002\\u752f\",\n    \"output\": \"0.xn--qny\"\n  },\n  {\n    \"input\": \"0.xn--qny\",\n    \"output\": \"0.xn--qny\"\n  },\n  {\n    \"input\": \"0.\\u752f\",\n    \"output\": \"0.xn--qny\"\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"-\\u2f86\\uff0e\\uaaf6\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"-\\u820c.\\uaaf6\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"xn----ef8c.xn--2v9a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"-\\uff61\\u1898\",\n    \"output\": \"-.xn--ibf\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"-\\u3002\\u1898\",\n    \"output\": \"-.xn--ibf\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"-.xn--ibf\",\n    \"output\": \"-.xn--ibf\"\n  },\n  {\n    \"input\": \"\\ud83c\\udcb4\\u10ab.\\u226e\",\n    \"output\": \"xn--2kj7565l.xn--gdh\"\n  },\n  {\n    \"input\": \"\\ud83c\\udcb4\\u10ab.<\\u0338\",\n    \"output\": \"xn--2kj7565l.xn--gdh\"\n  },\n  {\n    \"input\": \"\\ud83c\\udcb4\\u2d0b.<\\u0338\",\n    \"output\": \"xn--2kj7565l.xn--gdh\"\n  },\n  {\n    \"input\": \"\\ud83c\\udcb4\\u2d0b.\\u226e\",\n    \"output\": \"xn--2kj7565l.xn--gdh\"\n  },\n  {\n    \"input\": \"xn--2kj7565l.xn--gdh\",\n    \"output\": \"xn--2kj7565l.xn--gdh\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--jnd1986v.xn--gdh\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u74bc\\ud836\\ude2d\\uff61\\u200c\\udb40\\udddf\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u74bc\\ud836\\ude2d\\u3002\\u200c\\udb40\\udddf\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--gky8837e.\",\n    \"output\": \"xn--gky8837e.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u74bc\\ud836\\ude2d.\",\n    \"output\": \"xn--gky8837e.\"\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"xn--gky8837e.xn--0ug\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u200c.\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"xn--0ug.xn--0ug\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--157b.xn--gnb\",\n    \"output\": \"xn--157b.xn--gnb\"\n  },\n  {\n    \"input\": \"\\ud29b.\\u0716\",\n    \"output\": \"xn--157b.xn--gnb\"\n  },\n  {\n    \"input\": \"\\u1110\\u1171\\u11c2.\\u0716\",\n    \"output\": \"xn--157b.xn--gnb\"\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u10b7\\uff0e\\u05c2\\ud804\\udd34\\ua9b7\\ud920\\udce8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u10b7\\uff0e\\ud804\\udd34\\u05c2\\ua9b7\\ud920\\udce8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u10b7.\\ud804\\udd34\\u05c2\\ua9b7\\ud920\\udce8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u2d17.\\ud804\\udd34\\u05c2\\ua9b7\\ud920\\udce8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--flj.xn--qdb0605f14ycrms3c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u2d17\\uff0e\\ud804\\udd34\\u05c2\\ua9b7\\ud920\\udce8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u2d17\\uff0e\\u05c2\\ud804\\udd34\\ua9b7\\ud920\\udce8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--vnd.xn--qdb0605f14ycrms3c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u2488\\u916b\\ufe12\\u3002\\u08d6\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"1.\\u916b\\u3002\\u3002\\u08d6\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; A4_2 (ignored)\",\n    \"input\": \"1.xn--8j4a..xn--8zb\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--tsh4490bfe8c.xn--8zb\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6\",\n    \"input\": \"\\u2de3\\u200c\\u226e\\u1a6b.\\u200c\\u0e3a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6\",\n    \"input\": \"\\u2de3\\u200c<\\u0338\\u1a6b.\\u200c\\u0e3a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--uof548an0j.xn--o4c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6\",\n    \"input\": \"xn--uof63xk4bf3s.xn--o4c732g\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--co6h.xn--1-kwssa\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--co6h.xn--1-h1g429s\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--co6h.xn--1-h1gs\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\ua806\\u3002\\ud8ad\\ude8f\\u0fb0\\u2495\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; A4_2 (ignored)\",\n    \"input\": \"\\ua806\\u3002\\ud8ad\\ude8f\\u0fb014.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; A4_2 (ignored)\",\n    \"input\": \"xn--l98a.xn--14-jsj57880f.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--l98a.xn--dgd218hhp28d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\ud835\\udfe04\\udb40\\uddd7\\ud834\\ude3b\\uff0e\\u200d\\ud800\\udef5\\u26e7\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"84\\udb40\\uddd7\\ud834\\ude3b.\\u200d\\ud800\\udef5\\u26e7\\u200d\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--84-s850a.xn--59h6326e\",\n    \"output\": \"xn--84-s850a.xn--59h6326e\"\n  },\n  {\n    \"input\": \"84\\ud834\\ude3b.\\ud800\\udef5\\u26e7\",\n    \"output\": \"xn--84-s850a.xn--59h6326e\"\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"xn--84-s850a.xn--1uga573cfq1w\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\u226e\\ud835\\udfd5\\uff0e\\u8b16\\u00df\\u226f\",\n    \"output\": \"xn--7-mgo.xn--zca892oly5e\"\n  },\n  {\n    \"input\": \"<\\u0338\\ud835\\udfd5\\uff0e\\u8b16\\u00df>\\u0338\",\n    \"output\": \"xn--7-mgo.xn--zca892oly5e\"\n  },\n  {\n    \"input\": \"\\u226e7.\\u8b16\\u00df\\u226f\",\n    \"output\": \"xn--7-mgo.xn--zca892oly5e\"\n  },\n  {\n    \"input\": \"<\\u03387.\\u8b16\\u00df>\\u0338\",\n    \"output\": \"xn--7-mgo.xn--zca892oly5e\"\n  },\n  {\n    \"input\": \"<\\u03387.\\u8b16SS>\\u0338\",\n    \"output\": \"xn--7-mgo.xn--ss-xjvv174c\"\n  },\n  {\n    \"input\": \"\\u226e7.\\u8b16SS\\u226f\",\n    \"output\": \"xn--7-mgo.xn--ss-xjvv174c\"\n  },\n  {\n    \"input\": \"\\u226e7.\\u8b16ss\\u226f\",\n    \"output\": \"xn--7-mgo.xn--ss-xjvv174c\"\n  },\n  {\n    \"input\": \"<\\u03387.\\u8b16ss>\\u0338\",\n    \"output\": \"xn--7-mgo.xn--ss-xjvv174c\"\n  },\n  {\n    \"input\": \"<\\u03387.\\u8b16Ss>\\u0338\",\n    \"output\": \"xn--7-mgo.xn--ss-xjvv174c\"\n  },\n  {\n    \"input\": \"\\u226e7.\\u8b16Ss\\u226f\",\n    \"output\": \"xn--7-mgo.xn--ss-xjvv174c\"\n  },\n  {\n    \"input\": \"xn--7-mgo.xn--ss-xjvv174c\",\n    \"output\": \"xn--7-mgo.xn--ss-xjvv174c\"\n  },\n  {\n    \"input\": \"xn--7-mgo.xn--zca892oly5e\",\n    \"output\": \"xn--7-mgo.xn--zca892oly5e\"\n  },\n  {\n    \"input\": \"<\\u0338\\ud835\\udfd5\\uff0e\\u8b16SS>\\u0338\",\n    \"output\": \"xn--7-mgo.xn--ss-xjvv174c\"\n  },\n  {\n    \"input\": \"\\u226e\\ud835\\udfd5\\uff0e\\u8b16SS\\u226f\",\n    \"output\": \"xn--7-mgo.xn--ss-xjvv174c\"\n  },\n  {\n    \"input\": \"\\u226e\\ud835\\udfd5\\uff0e\\u8b16ss\\u226f\",\n    \"output\": \"xn--7-mgo.xn--ss-xjvv174c\"\n  },\n  {\n    \"input\": \"<\\u0338\\ud835\\udfd5\\uff0e\\u8b16ss>\\u0338\",\n    \"output\": \"xn--7-mgo.xn--ss-xjvv174c\"\n  },\n  {\n    \"input\": \"<\\u0338\\ud835\\udfd5\\uff0e\\u8b16Ss>\\u0338\",\n    \"output\": \"xn--7-mgo.xn--ss-xjvv174c\"\n  },\n  {\n    \"input\": \"\\u226e\\ud835\\udfd5\\uff0e\\u8b16Ss\\u226f\",\n    \"output\": \"xn--7-mgo.xn--ss-xjvv174c\"\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\ud975\\udf0e\\u2488\\uff61\\u200c\\ud835\\udfe4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; A4_2 (ignored)\",\n    \"input\": \"\\ud975\\udf0e1.\\u3002\\u200c2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"xn--1-ex54e..c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; A4_2 (ignored)\",\n    \"input\": \"xn--1-ex54e..xn--2-rgn\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--tsh94183d.c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--tsh94183d.xn--2-rgn\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200d\\u200c\\udb40\\uddaa\\uff61\\u00df\\ud805\\udcc3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200d\\u200c\\udb40\\uddaa\\u3002\\u00df\\ud805\\udcc3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200d\\u200c\\udb40\\uddaa\\u3002SS\\ud805\\udcc3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200d\\u200c\\udb40\\uddaa\\u3002ss\\ud805\\udcc3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200d\\u200c\\udb40\\uddaa\\u3002Ss\\ud805\\udcc3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \".xn--ss-bh7o\",\n    \"output\": \".xn--ss-bh7o\"\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"xn--0ugb.xn--ss-bh7o\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"xn--0ugb.xn--zca0732l\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200d\\u200c\\udb40\\uddaa\\uff61SS\\ud805\\udcc3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200d\\u200c\\udb40\\uddaa\\uff61ss\\ud805\\udcc3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2\",\n    \"input\": \"\\u200d\\u200c\\udb40\\uddaa\\uff61Ss\\ud805\\udcc3\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--ss-bh7o\",\n    \"output\": \"xn--ss-bh7o\"\n  },\n  {\n    \"input\": \"ss\\ud805\\udcc3\",\n    \"output\": \"xn--ss-bh7o\"\n  },\n  {\n    \"input\": \"SS\\ud805\\udcc3\",\n    \"output\": \"xn--ss-bh7o\"\n  },\n  {\n    \"input\": \"Ss\\ud805\\udcc3\",\n    \"output\": \"xn--ss-bh7o\"\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\ufe12\\u200c\\u30f6\\u44a9.\\ua86a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; A4_2 (ignored)\",\n    \"input\": \"\\u3002\\u200c\\u30f6\\u44a9.\\ua86a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \".xn--qekw60d.xn--gd9a\",\n    \"output\": \".xn--qekw60d.xn--gd9a\"\n  },\n  {\n    \"comment\": \"C1; A4_2 (ignored)\",\n    \"input\": \".xn--0ug287dj0o.xn--gd9a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--qekw60dns9k.xn--gd9a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--0ug287dj0or48o.xn--gd9a\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--qekw60d.xn--gd9a\",\n    \"output\": \"xn--qekw60d.xn--gd9a\"\n  },\n  {\n    \"input\": \"\\u30f6\\u44a9.\\ua86a\",\n    \"output\": \"xn--qekw60d.xn--gd9a\"\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u200c\\u2488\\ud852\\udf8d.\\udb49\\udccb\\u1a60\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u200c1.\\ud852\\udf8d.\\udb49\\udccb\\u1a60\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"1.xn--4x6j.xn--jof45148n\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--1-rgn.xn--4x6j.xn--jof45148n\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--tshw462r.xn--jof45148n\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--0ug88o7471d.xn--jof45148n\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\ud834\\udd75\\uff61\\ud835\\udfeb\\ud838\\udc08\\u4b3a\\u2488\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\ud834\\udd75\\u30029\\ud838\\udc08\\u4b3a1.\",\n    \"output\": \".xn--91-030c1650n.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \".xn--91-030c1650n.\",\n    \"output\": \".xn--91-030c1650n.\"\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \".xn--9-ecp936non25a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"xn--3f1h.xn--91-030c1650n.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--3f1h.xn--9-ecp936non25a\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--8c1a.xn--2ib8jn539l\",\n    \"output\": \"xn--8c1a.xn--2ib8jn539l\"\n  },\n  {\n    \"input\": \"\\u821b.\\u067d\\ud83a\\udd34\\u06bb\",\n    \"output\": \"xn--8c1a.xn--2ib8jn539l\"\n  },\n  {\n    \"input\": \"\\u821b.\\u067d\\ud83a\\udd12\\u06bb\",\n    \"output\": \"xn--8c1a.xn--2ib8jn539l\"\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"-\\udb40\\udd710\\uff61\\u17cf\\u1dfd\\ud187\\uc2ed\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"-\\udb40\\udd710\\uff61\\u17cf\\u1dfd\\u1110\\u1168\\u11aa\\u1109\\u1175\\u11b8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"-\\udb40\\udd710\\u3002\\u17cf\\u1dfd\\ud187\\uc2ed\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"-\\udb40\\udd710\\u3002\\u17cf\\u1dfd\\u1110\\u1168\\u11aa\\u1109\\u1175\\u11b8\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"-0.xn--r4e872ah77nghm\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u115f\\u10bf\\u10b5\\u10e0\\uff61\\u0b4d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u115f\\u10bf\\u10b5\\u10e0\\u3002\\u0b4d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u115f\\u2d1f\\u2d15\\u10e0\\u3002\\u0b4d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u115f\\u10bf\\u10b5\\u1ca0\\u3002\\u0b4d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--1od555l3a.xn--9ic\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u115f\\u2d1f\\u2d15\\u10e0\\uff61\\u0b4d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u115f\\u10bf\\u10b5\\u1ca0\\uff61\\u0b4d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--tndt4hvw.xn--9ic\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--1od7wz74eeb.xn--9ic\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u115f\\u10bf\\u2d15\\u10e0\\u3002\\u0b4d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--3nd0etsm92g.xn--9ic\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u115f\\u10bf\\u2d15\\u10e0\\uff61\\u0b4d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--l96h.xn--o8e4044k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--l96h.xn--03e93aq365d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"\\ud835\\udfdb\\ud834\\uddaa\\ua8c4\\uff61\\ua8ea-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"\\ud835\\udfdb\\ua8c4\\ud834\\uddaa\\uff61\\ua8ea-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"3\\ua8c4\\ud834\\uddaa\\u3002\\ua8ea-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"xn--3-sl4eu679e.xn----xn4e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u1139\\uff61\\u0eca\\uda42\\udfe4\\udb40\\udd1e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u1139\\u3002\\u0eca\\uda42\\udfe4\\udb40\\udd1e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--lrd.xn--s8c05302k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u10a6\\udaae\\udca9\\uff0e\\udb40\\udda1\\ufe09\\ud83a\\udd0d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u10a6\\udaae\\udca9.\\udb40\\udda1\\ufe09\\ud83a\\udd0d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2d06\\udaae\\udca9.\\udb40\\udda1\\ufe09\\ud83a\\udd2f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--xkjw3965g.xn--ne6h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2d06\\udaae\\udca9\\uff0e\\udb40\\udda1\\ufe09\\ud83a\\udd2f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--end82983m.xn--ne6h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2d06\\udaae\\udca9.\\udb40\\udda1\\ufe09\\ud83a\\udd0d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\u2d06\\udaae\\udca9\\uff0e\\udb40\\udda1\\ufe09\\ud83a\\udd0d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud91d\\udee8.\\ud9d5\\udfe2\\ud835\\udfe8\\ua8c4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud91d\\udee8.\\ud9d5\\udfe26\\ua8c4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--mi60a.xn--6-sl4es8023c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud800\\udef8\\udb79\\ude0b\\u10c2.\\u10a1\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud800\\udef8\\udb79\\ude0b\\u2d22.\\u2d01\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud800\\udef8\\udb79\\ude0b\\u10c2.\\u2d01\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--qlj1559dr224h.xn--skj\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--6nd5215jr2u0h.xn--skj\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--6nd5215jr2u0h.xn--8md\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud91d\\udc7f\\ua806\\u2084\\uda65\\udf86\\uff61\\ud88a\\ude67\\udb41\\udcb9\\u03c2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud91d\\udc7f\\ua8064\\uda65\\udf86\\u3002\\ud88a\\ude67\\udb41\\udcb9\\u03c2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud91d\\udc7f\\ua8064\\uda65\\udf86\\u3002\\ud88a\\ude67\\udb41\\udcb9\\u03a3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud91d\\udc7f\\ua8064\\uda65\\udf86\\u3002\\ud88a\\ude67\\udb41\\udcb9\\u03c3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--4-w93ej7463a9io5a.xn--4xa31142bk3f0d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--4-w93ej7463a9io5a.xn--3xa51142bk3f0d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud91d\\udc7f\\ua806\\u2084\\uda65\\udf86\\uff61\\ud88a\\ude67\\udb41\\udcb9\\u03a3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud91d\\udc7f\\ua806\\u2084\\uda65\\udf86\\uff61\\ud88a\\ude67\\udb41\\udcb9\\u03c3\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud8ba\\udcac\\u3002\\u0729\\u3002\\ucbd95\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud8ba\\udcac\\u3002\\u0729\\u3002\\u110d\\u1173\\u11ac5\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--t92s.xn--znb.xn--5-y88f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u17ca.\\u200d\\ud835\\udfee\\ud804\\udc3f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"\\u17ca.\\u200d2\\ud804\\udc3f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--m4e.xn--2-ku7i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6\",\n    \"input\": \"xn--m4e.xn--2-tgnv469h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\uaaf6\\u3002\\u5b36\\u00df\\u847d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\uaaf6\\u3002\\u5b36SS\\u847d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\uaaf6\\u3002\\u5b36ss\\u847d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\uaaf6\\u3002\\u5b36Ss\\u847d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--2v9a.xn--ss-q40dp97m\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--2v9a.xn--zca7637b14za\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u03c2\\ud805\\udc3d\\ud896\\udc88\\ud805\\udf2b\\uff61\\ud83a\\udf29\\u200c\\ud802\\udec4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u03c2\\ud805\\udc3d\\ud896\\udc88\\ud805\\udf2b\\u3002\\ud83a\\udf29\\u200c\\ud802\\udec4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u03a3\\ud805\\udc3d\\ud896\\udc88\\ud805\\udf2b\\u3002\\ud83a\\udf29\\u200c\\ud802\\udec4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u03c3\\ud805\\udc3d\\ud896\\udc88\\ud805\\udf2b\\u3002\\ud83a\\udf29\\u200c\\ud802\\udec4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--4xa2260lk3b8z15g.xn--tw9ct349a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--4xa2260lk3b8z15g.xn--0ug4653g2xzf\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--3xa4260lk3b8z15g.xn--0ug4653g2xzf\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u03a3\\ud805\\udc3d\\ud896\\udc88\\ud805\\udf2b\\uff61\\ud83a\\udf29\\u200c\\ud802\\udec4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u03c3\\ud805\\udc3d\\ud896\\udc88\\ud805\\udf2b\\uff61\\ud83a\\udf29\\u200c\\ud802\\udec4\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u2ea2\\ud9df\\ude85\\ud835\\udfe4\\uff61\\u200d\\ud83d\\udeb7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u2ea2\\ud9df\\ude852\\u3002\\u200d\\ud83d\\udeb7\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--2-4jtr4282f.xn--m78h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--2-4jtr4282f.xn--1ugz946p\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud836\\ude25\\u3002\\u2adf\\ud804\\ude3e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--n82h.xn--63iw010f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V3 (ignored); U1 (ignored)\",\n    \"input\": \"-\\u1897\\u200c\\ud83c\\udd04.\\ud805\\udf22\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V3 (ignored); U1 (ignored)\",\n    \"input\": \"-\\u1897\\u200c3,.\\ud805\\udf22\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored); U1 (ignored)\",\n    \"input\": \"xn---3,-3eu.xn--9h2d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V3 (ignored); U1 (ignored)\",\n    \"input\": \"xn---3,-3eu051c.xn--9h2d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"xn----pck1820x.xn--9h2d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7; V3 (ignored)\",\n    \"input\": \"xn----pck312bx563c.xn--9h2d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"\\u17b4.\\ucb87-\",\n    \"output\": \".xn----938f\"\n  },\n  {\n    \"comment\": \"V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"\\u17b4.\\u110d\\u1170\\u11ae-\",\n    \"output\": \".xn----938f\"\n  },\n  {\n    \"comment\": \"V3 (ignored); A4_2 (ignored)\",\n    \"input\": \".xn----938f\",\n    \"output\": \".xn----938f\"\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"xn--z3e.xn----938f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"\\u200c\\ud805\\udcc2\\u3002\\u2488-\\udbc2\\ude9b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\u200c\\ud805\\udcc2\\u30021.-\\udbc2\\ude9b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"xn--wz1d.1.xn----rg03o\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"xn--0ugy057g.1.xn----rg03o\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--wz1d.xn----dcp29674o\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7\",\n    \"input\": \"xn--0ugy057g.xn----dcp29674o\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \".xn--hcb32bni\",\n    \"output\": \".xn--hcb32bni\"\n  },\n  {\n    \"input\": \"xn--hcb32bni\",\n    \"output\": \"xn--hcb32bni\"\n  },\n  {\n    \"input\": \"\\u06bd\\u0663\\u0596\",\n    \"output\": \"xn--hcb32bni\"\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"\\u0f94\\ua84b-\\uff0e-\\ud81a\\udf34\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"\\u0f94\\ua84b-.-\\ud81a\\udf34\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V3 (ignored)\",\n    \"input\": \"xn----ukg9938i.xn----4u5m\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\ud9bd\\udcb3-\\u22e2\\u200c\\uff0e\\u6807-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\ud9bd\\udcb3-\\u2291\\u0338\\u200c\\uff0e\\u6807-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\ud9bd\\udcb3-\\u22e2\\u200c.\\u6807-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"\\ud9bd\\udcb3-\\u2291\\u0338\\u200c.\\u6807-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn----9mo67451g.xn----qj7b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V7; V3 (ignored)\",\n    \"input\": \"xn----sgn90kn5663a.xn----qj7b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"-\\ud914\\ude74.\\u06e0\\u189a-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"xn----qi38c.xn----jxc827k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \"\\u3002\\u0635\\u0649\\u0e37\\u0644\\u0627\\u3002\\u5c93\\u1bf2\\udb43\\udf83\\u1842\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; A4_2 (ignored)\",\n    \"input\": \".xn--mgb1a7bt462h.xn--17e10qe61f9r71s\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"\\u188c\\uff0e-\\u085a\",\n    \"output\": \"xn--59e.xn----5jd\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"\\u188c.-\\u085a\",\n    \"output\": \"xn--59e.xn----5jd\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"xn--59e.xn----5jd\",\n    \"output\": \"xn--59e.xn----5jd\"\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u1039-\\ud82a\\udfad\\ud83d\\udfa2\\uff0e\\u00df\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u1039-\\ud82a\\udfad\\ud83d\\udfa2.\\u00df\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u1039-\\ud82a\\udfad\\ud83d\\udfa2.SS\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u1039-\\ud82a\\udfad\\ud83d\\udfa2.ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u1039-\\ud82a\\udfad\\ud83d\\udfa2.Ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn----9tg11172akr8b.ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn----9tg11172akr8b.xn--zca\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u1039-\\ud82a\\udfad\\ud83d\\udfa2\\uff0eSS\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u1039-\\ud82a\\udfad\\ud83d\\udfa2\\uff0ess\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u1039-\\ud82a\\udfad\\ud83d\\udfa2\\uff0eSs\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V6; V7\",\n    \"input\": \"\\u0d4d-\\u200d\\u200c\\uff61\\ud955\\udfa7\\u2085\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V6; V7\",\n    \"input\": \"\\u0d4d-\\u200d\\u200c\\uff61\\ud955\\udfa7\\u2085=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V6; V7\",\n    \"input\": \"\\u0d4d-\\u200d\\u200c\\u3002\\ud955\\udfa75\\u2260\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V6; V7\",\n    \"input\": \"\\u0d4d-\\u200d\\u200c\\u3002\\ud955\\udfa75=\\u0338\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; V3 (ignored)\",\n    \"input\": \"xn----jmf.xn--5-ufo50192e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; C2; V6; V7\",\n    \"input\": \"xn----jmf215lda.xn--5-ufo50192e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\u9523\\u3002\\u0a4d\\udb41\\ude3b\\udb41\\ude86\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--gc5a.xn--ybc83044ppga\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--8gb2338k.xn--lhb0154f\",\n    \"output\": \"xn--8gb2338k.xn--lhb0154f\"\n  },\n  {\n    \"input\": \"\\u063d\\ud804\\ude3e.\\u0649\\ua92b\",\n    \"output\": \"xn--8gb2338k.xn--lhb0154f\"\n  },\n  {\n    \"input\": \"\\u10c1\\u10b16\\u0318\\u3002\\u00df\\u1b03\",\n    \"output\": \"xn--6-8cb7433a2ba.xn--zca894k\"\n  },\n  {\n    \"input\": \"\\u2d21\\u2d116\\u0318\\u3002\\u00df\\u1b03\",\n    \"output\": \"xn--6-8cb7433a2ba.xn--zca894k\"\n  },\n  {\n    \"input\": \"\\u10c1\\u10b16\\u0318\\u3002SS\\u1b03\",\n    \"output\": \"xn--6-8cb7433a2ba.xn--ss-2vq\"\n  },\n  {\n    \"input\": \"\\u2d21\\u2d116\\u0318\\u3002ss\\u1b03\",\n    \"output\": \"xn--6-8cb7433a2ba.xn--ss-2vq\"\n  },\n  {\n    \"input\": \"\\u10c1\\u2d116\\u0318\\u3002Ss\\u1b03\",\n    \"output\": \"xn--6-8cb7433a2ba.xn--ss-2vq\"\n  },\n  {\n    \"input\": \"xn--6-8cb7433a2ba.xn--ss-2vq\",\n    \"output\": \"xn--6-8cb7433a2ba.xn--ss-2vq\"\n  },\n  {\n    \"input\": \"\\u2d21\\u2d116\\u0318.ss\\u1b03\",\n    \"output\": \"xn--6-8cb7433a2ba.xn--ss-2vq\"\n  },\n  {\n    \"input\": \"\\u10c1\\u10b16\\u0318.SS\\u1b03\",\n    \"output\": \"xn--6-8cb7433a2ba.xn--ss-2vq\"\n  },\n  {\n    \"input\": \"\\u10c1\\u2d116\\u0318.Ss\\u1b03\",\n    \"output\": \"xn--6-8cb7433a2ba.xn--ss-2vq\"\n  },\n  {\n    \"input\": \"xn--6-8cb7433a2ba.xn--zca894k\",\n    \"output\": \"xn--6-8cb7433a2ba.xn--zca894k\"\n  },\n  {\n    \"input\": \"\\u2d21\\u2d116\\u0318.\\u00df\\u1b03\",\n    \"output\": \"xn--6-8cb7433a2ba.xn--zca894k\"\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--6-8cb306hms1a.xn--ss-2vq\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--6-8cb555h2b.xn--ss-2vq\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--6-8cb555h2b.xn--zca894k\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud9ee\\udc50\\uff61\\u226f\\ud804\\udeea\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud9ee\\udc50\\uff61>\\u0338\\ud804\\udeea\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud9ee\\udc50\\u3002\\u226f\\ud804\\udeea\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\ud9ee\\udc50\\u3002>\\u0338\\ud804\\udeea\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--eo08b.xn--hdh3385g\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; A4_2 (ignored)\",\n    \"input\": \"\\udb40\\udd0f\\ud81a\\udf34\\udb43\\udcbd\\uff61\\uffa0\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; A4_2 (ignored)\",\n    \"input\": \"\\udb40\\udd0f\\ud81a\\udf34\\udb43\\udcbd\\u3002\\u1160\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7; A4_2 (ignored)\",\n    \"input\": \"xn--619ep9154c.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--619ep9154c.xn--psd\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--619ep9154c.xn--cl7c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb42\\udf54.\\ud800\\udef1\\u2082\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"\\udb42\\udf54.\\ud800\\udef12\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--vi56e.xn--2-w91i\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u2dbf.\\u00df\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u2dbf.SS\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u2dbf.ss\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u2dbf.Ss\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--7pj.ss\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--7pj.xn--ss-n1t\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--7pj.xn--zca870n\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"\\u6889\\u3002\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--7zv.\",\n    \"output\": \"xn--7zv.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\u6889.\",\n    \"output\": \"xn--7zv.\"\n  },\n  {\n    \"comment\": \"C1\",\n    \"input\": \"xn--7zv.xn--0ug\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--iwb.ss\",\n    \"output\": \"xn--iwb.ss\"\n  },\n  {\n    \"input\": \"\\u0853.ss\",\n    \"output\": \"xn--iwb.ss\"\n  },\n  {\n    \"input\": \"\\u0853.SS\",\n    \"output\": \"xn--iwb.ss\"\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"\\u40da\\u87e5-\\u3002-\\ud9b5\\udc98\\u2488\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"\\u40da\\u87e5-\\u3002-\\ud9b5\\udc981.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored); A4_2 (ignored)\",\n    \"input\": \"xn----n50a258u.xn---1-up07j.\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn----n50a258u.xn----ecp33805f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u1894\\u2260\\udbec\\ude42.\\u200d\\ud800\\udee2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u1894=\\u0338\\udbec\\ude42.\\u200d\\ud800\\udee2\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--ebf031cf7196a.xn--587c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--ebf031cf7196a.xn--1ug9540g\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"-\\uff61\\u2e90\",\n    \"output\": \"-.xn--6vj\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"-\\u3002\\u2e90\",\n    \"output\": \"-.xn--6vj\"\n  },\n  {\n    \"comment\": \"V3 (ignored)\",\n    \"input\": \"-.xn--6vj\",\n    \"output\": \"-.xn--6vj\"\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\udb43\\udc29\\ud807\\udcac\\uff0e\\u065c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"\\udb43\\udc29\\ud807\\udcac.\\u065c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--sn3d59267c.xn--4hb\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\ud800\\udf7a.\\ud928\\uddc3\\u200c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--ie8c.xn--2g51a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"xn--ie8c.xn--0ug03366c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"\\u200d\\u226e\\uff0e\\udb41\\udfea\\ud8a6\\udecf-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"\\u200d<\\u0338\\uff0e\\udb41\\udfea\\ud8a6\\udecf-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"\\u200d\\u226e.\\udb41\\udfea\\ud8a6\\udecf-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"\\u200d<\\u0338.\\udb41\\udfea\\ud8a6\\udecf-\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7; V3 (ignored)\",\n    \"input\": \"xn--gdh.xn----cr99a1w710b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7; V3 (ignored)\",\n    \"input\": \"xn--1ug95g.xn----cr99a1w710b\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u200d\\u200d\\u8954\\u3002\\u10bc5\\ua86e\\ud995\\udf4f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"\\u200d\\u200d\\u8954\\u3002\\u2d1c5\\ua86e\\ud995\\udf4f\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--2u2a.xn--5-uws5848bpf44e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--1uga7691f.xn--5-uws5848bpf44e\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V7\",\n    \"input\": \"xn--2u2a.xn--5-r1g7167ipfw8d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V7\",\n    \"input\": \"xn--1uga7691f.xn--5-r1g7167ipfw8d\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--ix9c26l.xn--q0s\",\n    \"output\": \"xn--ix9c26l.xn--q0s\"\n  },\n  {\n    \"input\": \"\\ud802\\udedc\\ud804\\udf3c.\\u5a40\",\n    \"output\": \"xn--ix9c26l.xn--q0s\"\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\ua9b9\\u200d\\ud077\\ud8af\\udda1\\uff61\\u2082\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"\\ua9b9\\u200d\\u110f\\u1173\\u11b2\\ud8af\\udda1\\uff61\\u2082\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--0m9as84e2e21c.c\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2; V6; V7\",\n    \"input\": \"xn--1ug1435cfkyaoi04d.c\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\ud802\\udec0\\uff0e\\u0689\\ud804\\udf00\",\n    \"output\": \"xn--pw9c.xn--fjb8658k\"\n  },\n  {\n    \"input\": \"\\ud802\\udec0.\\u0689\\ud804\\udf00\",\n    \"output\": \"xn--pw9c.xn--fjb8658k\"\n  },\n  {\n    \"input\": \"xn--pw9c.xn--fjb8658k\",\n    \"output\": \"xn--pw9c.xn--fjb8658k\"\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\u2260\\u81a3\\u3002\\u0f83\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"=\\u0338\\u81a3\\u3002\\u0f83\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--1chy468a.xn--2ed\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"\\ud800\\udef7\\u3002\\u200d\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"xn--r97c.\",\n    \"output\": \"xn--r97c.\"\n  },\n  {\n    \"comment\": \"A4_2 (ignored)\",\n    \"input\": \"\\ud800\\udef7.\",\n    \"output\": \"xn--r97c.\"\n  },\n  {\n    \"comment\": \"C2\",\n    \"input\": \"xn--r97c.xn--1ug\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"\\ud807\\udc33\\ud804\\ude2f\\u3002\\u296a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6\",\n    \"input\": \"xn--2g1d14o.xn--jti\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\ud804\\udd80\\u4074\\ud952\\udde3\\uff0e\\u10b5\\ud835\\udfdc\\u200c\\u0348\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\ud804\\udd80\\u4074\\ud952\\udde3.\\u10b54\\u200c\\u0348\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\ud804\\udd80\\u4074\\ud952\\udde3.\\u2d154\\u200c\\u0348\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--1mnx647cg3x1b.xn--4-zfb5123a\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"xn--1mnx647cg3x1b.xn--4-zfb502tlsl\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"\\ud804\\udd80\\u4074\\ud952\\udde3\\uff0e\\u2d15\\ud835\\udfdc\\u200c\\u0348\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"V6; V7\",\n    \"input\": \"xn--1mnx647cg3x1b.xn--4-zfb324h\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"C1; V6; V7\",\n    \"input\": \"xn--1mnx647cg3x1b.xn--4-zfb324h32o\",\n    \"output\": null\n  }\n]\n"
  },
  {
    "path": "tests/wpt/url/resources/percent-encoding.json",
    "content": "[\n  \"Tests for percent-encoding.\",\n  {\n    \"input\": \"\\u2020\",\n    \"output\": {\n      \"big5\": \"%26%238224%3B\",\n      \"euc-kr\": \"%A2%D3\",\n      \"utf-8\": \"%E2%80%A0\",\n      \"windows-1252\": \"%86\"\n    }\n  },\n  \"This uses a trailing A to prevent the URL parser from trimming the C0 control.\",\n  {\n    \"input\": \"\\u000EA\",\n    \"output\": {\n      \"big5\": \"%0EA\",\n      \"iso-2022-jp\": \"%26%2365533%3BA\",\n      \"utf-8\": \"%0EA\"\n    }\n  },\n  {\n    \"input\": \"\\u203E\\u005C\",\n    \"output\": {\n      \"iso-2022-jp\": \"%1B(J~%1B(B\\\\\",\n      \"utf-8\": \"%E2%80%BE\\\\\"\n    }\n  },\n  {\n    \"input\": \"\\uE5E5\",\n    \"output\": {\n      \"gb18030\": \"%26%2358853%3B\",\n      \"utf-8\": \"%EE%97%A5\"\n    }\n  },\n  {\n    \"input\": \"\\u2212\",\n    \"output\": {\n      \"shift_jis\": \"%81|\",\n      \"utf-8\": \"%E2%88%92\"\n    }\n  },\n  {\n    \"input\": \"á|\",\n    \"output\": {\n      \"utf-8\": \"%C3%A1|\"\n    }\n  }\n]\n"
  },
  {
    "path": "tests/wpt/url/resources/setters_tests.json",
    "content": "{\n  \"comment\": [\n    \"## Tests for setters of https://url.spec.whatwg.org/#urlutils-members\",\n    \"\",\n    \"This file contains a JSON object.\",\n    \"Other than 'comment', each key is an attribute of the `URL` interface\",\n    \"defined in WHATWG’s URL Standard.\",\n    \"The values are arrays of test case objects for that attribute.\",\n    \"\",\n    \"To run a test case for the attribute `attr`:\",\n    \"\",\n    \"* Create a new `URL` object with the value for the 'href' key\",\n    \"  the constructor single parameter. (Without a base URL.)\",\n    \"  This must not throw.\",\n    \"* Set the attribute `attr` to (invoke its setter with)\",\n    \"  with the value of for 'new_value' key.\",\n    \"* The value for the 'expected' key is another object.\",\n    \"  For each `key` / `value` pair of that object,\",\n    \"  get the attribute `key` (invoke its getter).\",\n    \"  The returned string must be equal to `value`.\",\n    \"\",\n    \"Note: the 'href' setter is already covered by urltestdata.json.\"\n  ],\n  \"protocol\": [\n    {\n      \"comment\": \"The empty string is not a valid scheme. Setter leaves the URL unchanged.\",\n      \"href\": \"a://example.net\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"a://example.net\",\n        \"protocol\": \"a:\"\n      }\n    },\n    {\n      \"href\": \"a://example.net\",\n      \"new_value\": \"b\",\n      \"expected\": {\n        \"href\": \"b://example.net\",\n        \"protocol\": \"b:\"\n      }\n    },\n    {\n      \"href\": \"javascript:alert(1)\",\n      \"new_value\": \"defuse\",\n      \"expected\": {\n        \"href\": \"defuse:alert(1)\",\n        \"protocol\": \"defuse:\"\n      }\n    },\n    {\n      \"comment\": \"Upper-case ASCII is lower-cased\",\n      \"href\": \"a://example.net\",\n      \"new_value\": \"B\",\n      \"expected\": {\n        \"href\": \"b://example.net\",\n        \"protocol\": \"b:\"\n      }\n    },\n    {\n      \"comment\": \"Non-ASCII is rejected\",\n      \"href\": \"a://example.net\",\n      \"new_value\": \"é\",\n      \"expected\": {\n        \"href\": \"a://example.net\",\n        \"protocol\": \"a:\"\n      }\n    },\n    {\n      \"comment\": \"No leading digit\",\n      \"href\": \"a://example.net\",\n      \"new_value\": \"0b\",\n      \"expected\": {\n        \"href\": \"a://example.net\",\n        \"protocol\": \"a:\"\n      }\n    },\n    {\n      \"comment\": \"No leading punctuation\",\n      \"href\": \"a://example.net\",\n      \"new_value\": \"+b\",\n      \"expected\": {\n        \"href\": \"a://example.net\",\n        \"protocol\": \"a:\"\n      }\n    },\n    {\n      \"href\": \"a://example.net\",\n      \"new_value\": \"bC0+-.\",\n      \"expected\": {\n        \"href\": \"bc0+-.://example.net\",\n        \"protocol\": \"bc0+-.:\"\n      }\n    },\n    {\n      \"comment\": \"Only some punctuation is acceptable\",\n      \"href\": \"a://example.net\",\n      \"new_value\": \"b,c\",\n      \"expected\": {\n        \"href\": \"a://example.net\",\n        \"protocol\": \"a:\"\n      }\n    },\n    {\n      \"comment\": \"Non-ASCII is rejected\",\n      \"href\": \"a://example.net\",\n      \"new_value\": \"bé\",\n      \"expected\": {\n        \"href\": \"a://example.net\",\n        \"protocol\": \"a:\"\n      }\n    },\n    {\n      \"comment\": \"Can’t switch from URL containing username/password/port to file\",\n      \"href\": \"http://test@example.net\",\n      \"new_value\": \"file\",\n      \"expected\": {\n        \"href\": \"http://test@example.net/\",\n        \"protocol\": \"http:\"\n      }\n    },\n    {\n      \"href\": \"https://example.net:1234\",\n      \"new_value\": \"file\",\n      \"expected\": {\n        \"href\": \"https://example.net:1234/\",\n        \"protocol\": \"https:\"\n      }\n    },\n    {\n      \"href\": \"wss://x:x@example.net:1234\",\n      \"new_value\": \"file\",\n      \"expected\": {\n        \"href\": \"wss://x:x@example.net:1234/\",\n        \"protocol\": \"wss:\"\n      }\n    },\n    {\n      \"comment\": \"Can’t switch from file URL with no host\",\n      \"href\": \"file://localhost/\",\n      \"new_value\": \"http\",\n      \"expected\": {\n        \"href\": \"file:///\",\n        \"protocol\": \"file:\"\n      }\n    },\n    {\n      \"href\": \"file:///test\",\n      \"new_value\": \"https\",\n      \"expected\": {\n        \"href\": \"file:///test\",\n        \"protocol\": \"file:\"\n      }\n    },\n    {\n      \"href\": \"file:\",\n      \"new_value\": \"wss\",\n      \"expected\": {\n        \"href\": \"file:///\",\n        \"protocol\": \"file:\"\n      }\n    },\n    {\n      \"comment\": \"Can’t switch from special scheme to non-special\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"b\",\n      \"expected\": {\n        \"href\": \"http://example.net/\",\n        \"protocol\": \"http:\"\n      }\n    },\n    {\n      \"href\": \"file://hi/path\",\n      \"new_value\": \"s\",\n      \"expected\": {\n        \"href\": \"file://hi/path\",\n        \"protocol\": \"file:\"\n      }\n    },\n    {\n      \"href\": \"https://example.net\",\n      \"new_value\": \"s\",\n      \"expected\": {\n        \"href\": \"https://example.net/\",\n        \"protocol\": \"https:\"\n      }\n    },\n    {\n      \"href\": \"ftp://example.net\",\n      \"new_value\": \"test\",\n      \"expected\": {\n        \"href\": \"ftp://example.net/\",\n        \"protocol\": \"ftp:\"\n      }\n    },\n    {\n      \"comment\": \"Cannot-be-a-base URL doesn’t have a host, but URL in a special scheme must.\",\n      \"href\": \"mailto:me@example.net\",\n      \"new_value\": \"http\",\n      \"expected\": {\n        \"href\": \"mailto:me@example.net\",\n        \"protocol\": \"mailto:\"\n      }\n    },\n    {\n      \"comment\": \"Can’t switch from non-special scheme to special\",\n      \"href\": \"ssh://me@example.net\",\n      \"new_value\": \"http\",\n      \"expected\": {\n        \"href\": \"ssh://me@example.net\",\n        \"protocol\": \"ssh:\"\n      }\n    },\n    {\n      \"href\": \"ssh://me@example.net\",\n      \"new_value\": \"https\",\n      \"expected\": {\n        \"href\": \"ssh://me@example.net\",\n        \"protocol\": \"ssh:\"\n      }\n    },\n    {\n      \"href\": \"ssh://me@example.net\",\n      \"new_value\": \"file\",\n      \"expected\": {\n        \"href\": \"ssh://me@example.net\",\n        \"protocol\": \"ssh:\"\n      }\n    },\n    {\n      \"href\": \"ssh://example.net\",\n      \"new_value\": \"file\",\n      \"expected\": {\n        \"href\": \"ssh://example.net\",\n        \"protocol\": \"ssh:\"\n      }\n    },\n    {\n      \"href\": \"nonsense:///test\",\n      \"new_value\": \"https\",\n      \"expected\": {\n        \"href\": \"nonsense:///test\",\n        \"protocol\": \"nonsense:\"\n      }\n    },\n    {\n      \"comment\": \"Stuff after the first ':' is ignored\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"https:foo : bar\",\n      \"expected\": {\n        \"href\": \"https://example.net/\",\n        \"protocol\": \"https:\"\n      }\n    },\n    {\n      \"comment\": \"Stuff after the first ':' is ignored\",\n      \"href\": \"data:text/html,<p>Test\",\n      \"new_value\": \"view-source+data:foo : bar\",\n      \"expected\": {\n        \"href\": \"view-source+data:text/html,<p>Test\",\n        \"protocol\": \"view-source+data:\"\n      }\n    },\n    {\n      \"comment\": \"Port is set to null if it is the default for new scheme.\",\n      \"href\": \"http://foo.com:443/\",\n      \"new_value\": \"https\",\n      \"expected\": {\n        \"href\": \"https://foo.com/\",\n        \"protocol\": \"https:\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Tab and newline are stripped\",\n      \"href\": \"http://test/\",\n      \"new_value\": \"h\\u000D\\u000Att\\u0009ps\",\n      \"expected\": {\n        \"href\": \"https://test/\",\n        \"protocol\": \"https:\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"href\": \"http://test/\",\n      \"new_value\": \"https\\u000D\",\n      \"expected\": {\n        \"href\": \"https://test/\",\n        \"protocol\": \"https:\"\n      }\n    },\n    {\n      \"comment\": \"Non-tab/newline C0 controls result in no-op\",\n      \"href\": \"http://test/\",\n      \"new_value\": \"https\\u0000\",\n      \"expected\": {\n        \"href\": \"http://test/\",\n        \"protocol\": \"http:\"\n      }\n    },\n    {\n      \"href\": \"http://test/\",\n      \"new_value\": \"https\\u000C\",\n      \"expected\": {\n        \"href\": \"http://test/\",\n        \"protocol\": \"http:\"\n      }\n    },\n    {\n      \"href\": \"http://test/\",\n      \"new_value\": \"https\\u000E\",\n      \"expected\": {\n        \"href\": \"http://test/\",\n        \"protocol\": \"http:\"\n      }\n    },\n    {\n      \"href\": \"http://test/\",\n      \"new_value\": \"https\\u0020\",\n      \"expected\": {\n        \"href\": \"http://test/\",\n        \"protocol\": \"http:\"\n      }\n    }\n  ],\n  \"username\": [\n    {\n      \"comment\": \"No host means no username\",\n      \"href\": \"file:///home/you/index.html\",\n      \"new_value\": \"me\",\n      \"expected\": {\n        \"href\": \"file:///home/you/index.html\",\n        \"username\": \"\"\n      }\n    },\n    {\n      \"comment\": \"No host means no username\",\n      \"href\": \"unix:/run/foo.socket\",\n      \"new_value\": \"me\",\n      \"expected\": {\n        \"href\": \"unix:/run/foo.socket\",\n        \"username\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Cannot-be-a-base means no username\",\n      \"href\": \"mailto:you@example.net\",\n      \"new_value\": \"me\",\n      \"expected\": {\n        \"href\": \"mailto:you@example.net\",\n        \"username\": \"\"\n      }\n    },\n    {\n      \"href\": \"javascript:alert(1)\",\n      \"new_value\": \"wario\",\n      \"expected\": {\n        \"href\": \"javascript:alert(1)\",\n        \"username\": \"\"\n      }\n    },\n    {\n      \"href\": \"http://example.net\",\n      \"new_value\": \"me\",\n      \"expected\": {\n        \"href\": \"http://me@example.net/\",\n        \"username\": \"me\"\n      }\n    },\n    {\n      \"href\": \"http://:secret@example.net\",\n      \"new_value\": \"me\",\n      \"expected\": {\n        \"href\": \"http://me:secret@example.net/\",\n        \"username\": \"me\"\n      }\n    },\n    {\n      \"href\": \"http://me@example.net\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"http://example.net/\",\n        \"username\": \"\"\n      }\n    },\n    {\n      \"href\": \"http://me:secret@example.net\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"http://:secret@example.net/\",\n        \"username\": \"\"\n      }\n    },\n    {\n      \"comment\": \"UTF-8 percent encoding with the userinfo encode set.\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"\\u0000\\u0001\\t\\n\\r\\u001f !\\\"#$%&'()*+,-./09:;<=>?@AZ[\\\\]^_`az{|}~\\u007f\\u0080\\u0081Éé\",\n      \"expected\": {\n        \"href\": \"http://%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/\",\n        \"username\": \"%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9\"\n      }\n    },\n    {\n      \"comment\": \"Bytes already percent-encoded are left as-is.\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"%c3%89té\",\n      \"expected\": {\n        \"href\": \"http://%c3%89t%C3%A9@example.net/\",\n        \"username\": \"%c3%89t%C3%A9\"\n      }\n    },\n    {\n      \"href\": \"sc:///\",\n      \"new_value\": \"x\",\n      \"expected\": {\n        \"href\": \"sc:///\",\n        \"username\": \"\"\n      }\n    },\n    {\n      \"href\": \"javascript://x/\",\n      \"new_value\": \"wario\",\n      \"expected\": {\n        \"href\": \"javascript://wario@x/\",\n        \"username\": \"wario\"\n      }\n    },\n    {\n      \"href\": \"file://test/\",\n      \"new_value\": \"test\",\n      \"expected\": {\n        \"href\": \"file://test/\",\n        \"username\": \"\"\n      }\n    }\n  ],\n  \"password\": [\n    {\n      \"comment\": \"No host means no password\",\n      \"href\": \"file:///home/me/index.html\",\n      \"new_value\": \"secret\",\n      \"expected\": {\n        \"href\": \"file:///home/me/index.html\",\n        \"password\": \"\"\n      }\n    },\n    {\n      \"comment\": \"No host means no password\",\n      \"href\": \"unix:/run/foo.socket\",\n      \"new_value\": \"secret\",\n      \"expected\": {\n        \"href\": \"unix:/run/foo.socket\",\n        \"password\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Cannot-be-a-base means no password\",\n      \"href\": \"mailto:me@example.net\",\n      \"new_value\": \"secret\",\n      \"expected\": {\n        \"href\": \"mailto:me@example.net\",\n        \"password\": \"\"\n      }\n    },\n    {\n      \"href\": \"http://example.net\",\n      \"new_value\": \"secret\",\n      \"expected\": {\n        \"href\": \"http://:secret@example.net/\",\n        \"password\": \"secret\"\n      }\n    },\n    {\n      \"href\": \"http://me@example.net\",\n      \"new_value\": \"secret\",\n      \"expected\": {\n        \"href\": \"http://me:secret@example.net/\",\n        \"password\": \"secret\"\n      }\n    },\n    {\n      \"href\": \"http://:secret@example.net\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"http://example.net/\",\n        \"password\": \"\"\n      }\n    },\n    {\n      \"href\": \"http://me:secret@example.net\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"http://me@example.net/\",\n        \"password\": \"\"\n      }\n    },\n    {\n      \"comment\": \"UTF-8 percent encoding with the userinfo encode set.\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"\\u0000\\u0001\\t\\n\\r\\u001f !\\\"#$%&'()*+,-./09:;<=>?@AZ[\\\\]^_`az{|}~\\u007f\\u0080\\u0081Éé\",\n      \"expected\": {\n        \"href\": \"http://:%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/\",\n        \"password\": \"%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9\"\n      }\n    },\n    {\n      \"comment\": \"Bytes already percent-encoded are left as-is.\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"%c3%89té\",\n      \"expected\": {\n        \"href\": \"http://:%c3%89t%C3%A9@example.net/\",\n        \"password\": \"%c3%89t%C3%A9\"\n      }\n    },\n    {\n      \"href\": \"sc:///\",\n      \"new_value\": \"x\",\n      \"expected\": {\n        \"href\": \"sc:///\",\n        \"password\": \"\"\n      }\n    },\n    {\n      \"href\": \"javascript://x/\",\n      \"new_value\": \"bowser\",\n      \"expected\": {\n        \"href\": \"javascript://:bowser@x/\",\n        \"password\": \"bowser\"\n      }\n    },\n    {\n      \"href\": \"file://test/\",\n      \"new_value\": \"test\",\n      \"expected\": {\n        \"href\": \"file://test/\",\n        \"password\": \"\"\n      }\n    }\n  ],\n  \"host\": [\n    {\n      \"comment\": \"Non-special scheme\",\n      \"href\": \"sc://x/\",\n      \"new_value\": \"\\u0000\",\n      \"expected\": {\n        \"href\": \"sc://x/\",\n        \"host\": \"x\",\n        \"hostname\": \"x\"\n      }\n    },\n    {\n      \"href\": \"sc://x/\",\n      \"new_value\": \"\\u0009\",\n      \"expected\": {\n        \"href\": \"sc:///\",\n        \"host\": \"\",\n        \"hostname\": \"\"\n      }\n    },\n    {\n      \"href\": \"sc://x/\",\n      \"new_value\": \"\\u000A\",\n      \"expected\": {\n        \"href\": \"sc:///\",\n        \"host\": \"\",\n        \"hostname\": \"\"\n      }\n    },\n    {\n      \"href\": \"sc://x/\",\n      \"new_value\": \"\\u000D\",\n      \"expected\": {\n        \"href\": \"sc:///\",\n        \"host\": \"\",\n        \"hostname\": \"\"\n      }\n    },\n    {\n      \"href\": \"sc://x/\",\n      \"new_value\": \" \",\n      \"expected\": {\n        \"href\": \"sc://x/\",\n        \"host\": \"x\",\n        \"hostname\": \"x\"\n      }\n    },\n    {\n      \"href\": \"sc://x/\",\n      \"new_value\": \"#\",\n      \"expected\": {\n        \"href\": \"sc:///\",\n        \"host\": \"\",\n        \"hostname\": \"\"\n      }\n    },\n    {\n      \"href\": \"sc://x/\",\n      \"new_value\": \"/\",\n      \"expected\": {\n        \"href\": \"sc:///\",\n        \"host\": \"\",\n        \"hostname\": \"\"\n      }\n    },\n    {\n      \"href\": \"sc://x/\",\n      \"new_value\": \"?\",\n      \"expected\": {\n        \"href\": \"sc:///\",\n        \"host\": \"\",\n        \"hostname\": \"\"\n      }\n    },\n    {\n      \"href\": \"sc://x/\",\n      \"new_value\": \"@\",\n      \"expected\": {\n        \"href\": \"sc://x/\",\n        \"host\": \"x\",\n        \"hostname\": \"x\"\n      }\n    },\n    {\n      \"href\": \"sc://x/\",\n      \"new_value\": \"ß\",\n      \"expected\": {\n        \"href\": \"sc://%C3%9F/\",\n        \"host\": \"%C3%9F\",\n        \"hostname\": \"%C3%9F\"\n      }\n    },\n    {\n      \"comment\": \"IDNA Nontransitional_Processing\",\n      \"href\": \"https://x/\",\n      \"new_value\": \"ß\",\n      \"expected\": {\n        \"href\": \"https://xn--zca/\",\n        \"host\": \"xn--zca\",\n        \"hostname\": \"xn--zca\"\n      }\n    },\n    {\n      \"comment\": \"Cannot-be-a-base means no host\",\n      \"href\": \"mailto:me@example.net\",\n      \"new_value\": \"example.com\",\n      \"expected\": {\n        \"href\": \"mailto:me@example.net\",\n        \"host\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Cannot-be-a-base means no host\",\n      \"href\": \"data:text/plain,Stuff\",\n      \"new_value\": \"example.net\",\n      \"expected\": {\n        \"href\": \"data:text/plain,Stuff\",\n        \"host\": \"\"\n      }\n    },\n    {\n      \"href\": \"http://example.net\",\n      \"new_value\": \"example.com:8080\",\n      \"expected\": {\n        \"href\": \"http://example.com:8080/\",\n        \"host\": \"example.com:8080\",\n        \"hostname\": \"example.com\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Port number is unchanged if not specified in the new value\",\n      \"href\": \"http://example.net:8080\",\n      \"new_value\": \"example.com\",\n      \"expected\": {\n        \"href\": \"http://example.com:8080/\",\n        \"host\": \"example.com:8080\",\n        \"hostname\": \"example.com\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Port number is unchanged if not specified\",\n      \"href\": \"http://example.net:8080\",\n      \"new_value\": \"example.com:\",\n      \"expected\": {\n        \"href\": \"http://example.com:8080/\",\n        \"host\": \"example.com:8080\",\n        \"hostname\": \"example.com\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"The empty host is not valid for special schemes\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"http://example.net/\",\n        \"host\": \"example.net\"\n      }\n    },\n    {\n      \"comment\": \"The empty host is OK for non-special schemes\",\n      \"href\": \"view-source+http://example.net/foo\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"view-source+http:///foo\",\n        \"host\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Path-only URLs can gain a host\",\n      \"href\": \"a:/foo\",\n      \"new_value\": \"example.net\",\n      \"expected\": {\n        \"href\": \"a://example.net/foo\",\n        \"host\": \"example.net\"\n      }\n    },\n    {\n      \"comment\": \"IPv4 address syntax is normalized\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"0x7F000001:8080\",\n      \"expected\": {\n        \"href\": \"http://127.0.0.1:8080/\",\n        \"host\": \"127.0.0.1:8080\",\n        \"hostname\": \"127.0.0.1\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"IPv6 address syntax is normalized\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"[::0:01]:2\",\n      \"expected\": {\n        \"href\": \"http://[::1]:2/\",\n        \"host\": \"[::1]:2\",\n        \"hostname\": \"[::1]\",\n        \"port\": \"2\"\n      }\n    },\n    {\n      \"comment\": \"IPv6 literal address with port, crbug.com/1012416\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"[2001:db8::2]:4002\",\n      \"expected\": {\n        \"href\": \"http://[2001:db8::2]:4002/\",\n        \"host\": \"[2001:db8::2]:4002\",\n        \"hostname\": \"[2001:db8::2]\",\n        \"port\": \"4002\"\n      }\n    },\n    {\n      \"comment\": \"Default port number is removed\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"example.com:80\",\n      \"expected\": {\n        \"href\": \"http://example.com/\",\n        \"host\": \"example.com\",\n        \"hostname\": \"example.com\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Default port number is removed\",\n      \"href\": \"https://example.net\",\n      \"new_value\": \"example.com:443\",\n      \"expected\": {\n        \"href\": \"https://example.com/\",\n        \"host\": \"example.com\",\n        \"hostname\": \"example.com\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Default port number is only removed for the relevant scheme\",\n      \"href\": \"https://example.net\",\n      \"new_value\": \"example.com:80\",\n      \"expected\": {\n        \"href\": \"https://example.com:80/\",\n        \"host\": \"example.com:80\",\n        \"hostname\": \"example.com\",\n        \"port\": \"80\"\n      }\n    },\n    {\n      \"comment\": \"Port number is removed if new port is scheme default and existing URL has a non-default port\",\n      \"href\": \"http://example.net:8080\",\n      \"new_value\": \"example.com:80\",\n      \"expected\": {\n        \"href\": \"http://example.com/\",\n        \"host\": \"example.com\",\n        \"hostname\": \"example.com\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Stuff after a / delimiter is ignored\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"example.com/stuff\",\n      \"expected\": {\n        \"href\": \"http://example.com/path\",\n        \"host\": \"example.com\",\n        \"hostname\": \"example.com\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Stuff after a / delimiter is ignored\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"example.com:8080/stuff\",\n      \"expected\": {\n        \"href\": \"http://example.com:8080/path\",\n        \"host\": \"example.com:8080\",\n        \"hostname\": \"example.com\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Stuff after a ? delimiter is ignored\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"example.com?stuff\",\n      \"expected\": {\n        \"href\": \"http://example.com/path\",\n        \"host\": \"example.com\",\n        \"hostname\": \"example.com\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Stuff after a ? delimiter is ignored, trailing 'port'\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"example.com?stuff:8080\",\n      \"expected\": {\n        \"href\": \"http://example.com/path\",\n        \"host\": \"example.com\",\n        \"hostname\": \"example.com\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Stuff after a ? delimiter is ignored\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"example.com:8080?stuff\",\n      \"expected\": {\n        \"href\": \"http://example.com:8080/path\",\n        \"host\": \"example.com:8080\",\n        \"hostname\": \"example.com\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Stuff after a # delimiter is ignored\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"example.com#stuff\",\n      \"expected\": {\n        \"href\": \"http://example.com/path\",\n        \"host\": \"example.com\",\n        \"hostname\": \"example.com\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Stuff after a # delimiter is ignored\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"example.com:8080#stuff\",\n      \"expected\": {\n        \"href\": \"http://example.com:8080/path\",\n        \"host\": \"example.com:8080\",\n        \"hostname\": \"example.com\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Stuff after a \\\\ delimiter is ignored for special schemes\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"example.com\\\\stuff\",\n      \"expected\": {\n        \"href\": \"http://example.com/path\",\n        \"host\": \"example.com\",\n        \"hostname\": \"example.com\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Stuff after a \\\\ delimiter is ignored for special schemes\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"example.com:8080\\\\stuff\",\n      \"expected\": {\n        \"href\": \"http://example.com:8080/path\",\n        \"host\": \"example.com:8080\",\n        \"hostname\": \"example.com\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"\\\\ is not a delimiter for non-special schemes, but still forbidden in hosts\",\n      \"href\": \"view-source+http://example.net/path\",\n      \"new_value\": \"example.com\\\\stuff\",\n      \"expected\": {\n        \"href\": \"view-source+http://example.net/path\",\n        \"host\": \"example.net\",\n        \"hostname\": \"example.net\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Anything other than ASCII digit stops the port parser in a setter but is not an error\",\n      \"href\": \"view-source+http://example.net/path\",\n      \"new_value\": \"example.com:8080stuff2\",\n      \"expected\": {\n        \"href\": \"view-source+http://example.com:8080/path\",\n        \"host\": \"example.com:8080\",\n        \"hostname\": \"example.com\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Anything other than ASCII digit stops the port parser in a setter but is not an error\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"example.com:8080stuff2\",\n      \"expected\": {\n        \"href\": \"http://example.com:8080/path\",\n        \"host\": \"example.com:8080\",\n        \"hostname\": \"example.com\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Anything other than ASCII digit stops the port parser in a setter but is not an error\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"example.com:8080+2\",\n      \"expected\": {\n        \"href\": \"http://example.com:8080/path\",\n        \"host\": \"example.com:8080\",\n        \"hostname\": \"example.com\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Anything other than ASCII digit stops the port parser in a setter but is not an error\",\n      \"href\": \"http://example.net:8080\",\n      \"new_value\": \"example.com:invalid\",\n      \"expected\": {\n        \"href\": \"http://example.com:8080/\",\n        \"host\": \"example.com:8080\",\n        \"hostname\": \"example.com\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Anything other than ASCII digit stops the port parser in a setter but is not an error\",\n      \"href\": \"http://example.net:8080/test\",\n      \"new_value\": \"[::1]:invalid\",\n      \"expected\": {\n        \"href\": \"http://[::1]:8080/test\",\n        \"host\": \"[::1]:8080\",\n        \"hostname\": \"[::1]\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"IPv6 without port\",\n      \"href\": \"http://example.net:8080/test\",\n      \"new_value\": \"[::1]\",\n      \"expected\": {\n        \"href\": \"http://[::1]:8080/test\",\n        \"host\": \"[::1]:8080\",\n        \"hostname\": \"[::1]\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Port numbers are 16 bit integers\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"example.com:65535\",\n      \"expected\": {\n        \"href\": \"http://example.com:65535/path\",\n        \"host\": \"example.com:65535\",\n        \"hostname\": \"example.com\",\n        \"port\": \"65535\"\n      }\n    },\n    {\n      \"comment\": \"Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"example.com:65536\",\n      \"expected\": {\n        \"href\": \"http://example.com/path\",\n        \"host\": \"example.com\",\n        \"hostname\": \"example.com\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Broken IPv6\",\n      \"href\": \"http://example.net/\",\n      \"new_value\": \"[google.com]\",\n      \"expected\": {\n        \"href\": \"http://example.net/\",\n        \"host\": \"example.net\",\n        \"hostname\": \"example.net\"\n      }\n    },\n    {\n      \"href\": \"http://example.net/\",\n      \"new_value\": \"[::1.2.3.4x]\",\n      \"expected\": {\n        \"href\": \"http://example.net/\",\n        \"host\": \"example.net\",\n        \"hostname\": \"example.net\"\n      }\n    },\n    {\n      \"href\": \"http://example.net/\",\n      \"new_value\": \"[::1.2.3.]\",\n      \"expected\": {\n        \"href\": \"http://example.net/\",\n        \"host\": \"example.net\",\n        \"hostname\": \"example.net\"\n      }\n    },\n    {\n      \"href\": \"http://example.net/\",\n      \"new_value\": \"[::1.2.]\",\n      \"expected\": {\n        \"href\": \"http://example.net/\",\n        \"host\": \"example.net\",\n        \"hostname\": \"example.net\"\n      }\n    },\n    {\n      \"href\": \"http://example.net/\",\n      \"new_value\": \"[::1.]\",\n      \"expected\": {\n        \"href\": \"http://example.net/\",\n        \"host\": \"example.net\",\n        \"hostname\": \"example.net\"\n      }\n    },\n    {\n      \"href\": \"file://y/\",\n      \"new_value\": \"x:123\",\n      \"expected\": {\n        \"href\": \"file://y/\",\n        \"host\": \"y\",\n        \"hostname\": \"y\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"href\": \"file://y/\",\n      \"new_value\": \"loc%41lhost\",\n      \"expected\": {\n        \"href\": \"file:///\",\n        \"host\": \"\",\n        \"hostname\": \"\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"href\": \"file://hi/x\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"file:///x\",\n        \"host\": \"\",\n        \"hostname\": \"\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"href\": \"sc://test@test/\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"sc://test@test/\",\n        \"host\": \"test\",\n        \"hostname\": \"test\",\n        \"username\": \"test\"\n      }\n    },\n    {\n      \"href\": \"sc://test:12/\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"sc://test:12/\",\n        \"host\": \"test:12\",\n        \"hostname\": \"test\",\n        \"port\": \"12\"\n      }\n    },\n    {\n      \"comment\": \"Leading / is not stripped\",\n      \"href\": \"http://example.com/\",\n      \"new_value\": \"///bad.com\",\n      \"expected\": {\n        \"href\": \"http://example.com/\",\n        \"host\": \"example.com\",\n        \"hostname\": \"example.com\"\n      }\n    },\n    {\n      \"comment\": \"Leading / is not stripped\",\n      \"href\": \"sc://example.com/\",\n      \"new_value\": \"///bad.com\",\n      \"expected\": {\n        \"href\": \"sc:///\",\n        \"host\": \"\",\n        \"hostname\": \"\"\n      }\n    },\n    {\n      \"href\": \"https://example.com/\",\n      \"new_value\": \"a%C2%ADb\",\n      \"expected\": {\n        \"href\": \"https://ab/\",\n        \"host\": \"ab\",\n        \"hostname\": \"ab\"\n      }\n    },\n    {\n      \"href\": \"https://example.com/\",\n      \"new_value\": \"\\u00AD\",\n      \"expected\": {\n        \"href\": \"https://example.com/\",\n        \"host\": \"example.com\",\n        \"hostname\": \"example.com\"\n      }\n    },\n    {\n      \"href\": \"https://example.com/\",\n      \"new_value\": \"%C2%AD\",\n      \"expected\": {\n        \"href\": \"https://example.com/\",\n        \"host\": \"example.com\",\n        \"hostname\": \"example.com\"\n      }\n    },\n    {\n      \"href\": \"https://example.com/\",\n      \"new_value\": \"xn--\",\n      \"expected\": {\n        \"href\": \"https://example.com/\",\n        \"host\": \"example.com\",\n        \"hostname\": \"example.com\"\n      }\n    },\n    {\n      \"href\": \"https://test.invalid/\",\n      \"new_value\": \"*\",\n      \"expected\": {\n        \"href\": \"https://*/\",\n        \"host\": \"*\",\n        \"hostname\": \"*\"\n      }\n    },\n    {\n      \"href\": \"https://test.invalid/\",\n      \"new_value\": \"x@x\",\n      \"expected\": {\n        \"href\": \"https://test.invalid/\",\n        \"host\": \"test.invalid\",\n        \"hostname\": \"test.invalid\"\n      }\n    },\n    {\n      \"href\": \"https://test.invalid/\",\n      \"new_value\": \"foo\\t\\r\\nbar\",\n      \"expected\": {\n        \"href\": \"https://foobar/\",\n        \"host\": \"foobar\",\n        \"hostname\": \"foobar\"\n      }\n    },\n    {\n      \"href\": \"https://test.invalid/\",\n      \"new_value\": \"><\",\n      \"expected\": {\n        \"href\": \"https://test.invalid/\",\n        \"host\": \"test.invalid\",\n        \"hostname\": \"test.invalid\"\n      }\n    },\n    {\n      \"href\": \"https://test.invalid/\",\n      \"new_value\": \"test/@aaa\",\n      \"expected\": {\n        \"href\": \"https://test/\",\n        \"host\": \"test\",\n        \"hostname\": \"test\"\n      }\n    },\n    {\n      \"href\": \"https://test.invalid/\",\n      \"new_value\": \"test/:aaa\",\n      \"expected\": {\n        \"href\": \"https://test/\",\n        \"host\": \"test\",\n        \"hostname\": \"test\"\n      }\n    }\n  ],\n  \"hostname\": [\n    {\n      \"comment\": \"Non-special scheme\",\n      \"href\": \"sc://x/\",\n      \"new_value\": \"\\u0000\",\n      \"expected\": {\n        \"href\": \"sc://x/\",\n        \"host\": \"x\",\n        \"hostname\": \"x\"\n      }\n    },\n    {\n      \"href\": \"sc://x/\",\n      \"new_value\": \"\\u0009\",\n      \"expected\": {\n        \"href\": \"sc:///\",\n        \"host\": \"\",\n        \"hostname\": \"\"\n      }\n    },\n    {\n      \"href\": \"sc://x/\",\n      \"new_value\": \"\\u000A\",\n      \"expected\": {\n        \"href\": \"sc:///\",\n        \"host\": \"\",\n        \"hostname\": \"\"\n      }\n    },\n    {\n      \"href\": \"sc://x/\",\n      \"new_value\": \"\\u000D\",\n      \"expected\": {\n        \"href\": \"sc:///\",\n        \"host\": \"\",\n        \"hostname\": \"\"\n      }\n    },\n    {\n      \"href\": \"sc://x/\",\n      \"new_value\": \" \",\n      \"expected\": {\n        \"href\": \"sc://x/\",\n        \"host\": \"x\",\n        \"hostname\": \"x\"\n      }\n    },\n    {\n      \"href\": \"sc://x/\",\n      \"new_value\": \"#\",\n      \"expected\": {\n        \"href\": \"sc:///\",\n        \"host\": \"\",\n        \"hostname\": \"\"\n      }\n    },\n    {\n      \"href\": \"sc://x/\",\n      \"new_value\": \"/\",\n      \"expected\": {\n        \"href\": \"sc:///\",\n        \"host\": \"\",\n        \"hostname\": \"\"\n      }\n    },\n    {\n      \"href\": \"sc://x/\",\n      \"new_value\": \"?\",\n      \"expected\": {\n        \"href\": \"sc:///\",\n        \"host\": \"\",\n        \"hostname\": \"\"\n      }\n    },\n    {\n      \"href\": \"sc://x/\",\n      \"new_value\": \"@\",\n      \"expected\": {\n        \"href\": \"sc://x/\",\n        \"host\": \"x\",\n        \"hostname\": \"x\"\n      }\n    },\n    {\n      \"comment\": \"Cannot-be-a-base means no host\",\n      \"href\": \"mailto:me@example.net\",\n      \"new_value\": \"example.com\",\n      \"expected\": {\n        \"href\": \"mailto:me@example.net\",\n        \"host\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Cannot-be-a-base means no host\",\n      \"href\": \"data:text/plain,Stuff\",\n      \"new_value\": \"example.net\",\n      \"expected\": {\n        \"href\": \"data:text/plain,Stuff\",\n        \"host\": \"\"\n      }\n    },\n    {\n      \"href\": \"http://example.net:8080\",\n      \"new_value\": \"example.com\",\n      \"expected\": {\n        \"href\": \"http://example.com:8080/\",\n        \"host\": \"example.com:8080\",\n        \"hostname\": \"example.com\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"The empty host is not valid for special schemes\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"http://example.net/\",\n        \"host\": \"example.net\"\n      }\n    },\n    {\n      \"comment\": \"The empty host is OK for non-special schemes\",\n      \"href\": \"view-source+http://example.net/foo\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"view-source+http:///foo\",\n        \"host\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Path-only URLs can gain a host\",\n      \"href\": \"a:/foo\",\n      \"new_value\": \"example.net\",\n      \"expected\": {\n        \"href\": \"a://example.net/foo\",\n        \"host\": \"example.net\"\n      }\n    },\n    {\n      \"comment\": \"IPv4 address syntax is normalized\",\n      \"href\": \"http://example.net:8080\",\n      \"new_value\": \"0x7F000001\",\n      \"expected\": {\n        \"href\": \"http://127.0.0.1:8080/\",\n        \"host\": \"127.0.0.1:8080\",\n        \"hostname\": \"127.0.0.1\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"IPv6 address syntax is normalized\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"[::0:01]\",\n      \"expected\": {\n        \"href\": \"http://[::1]/\",\n        \"host\": \"[::1]\",\n        \"hostname\": \"[::1]\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"comment\": \": delimiter invalidates entire value\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"example.com:8080\",\n      \"expected\": {\n        \"href\": \"http://example.net/path\",\n        \"host\": \"example.net\",\n        \"hostname\": \"example.net\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"comment\": \": delimiter invalidates entire value\",\n      \"href\": \"http://example.net:8080/path\",\n      \"new_value\": \"example.com:\",\n      \"expected\": {\n        \"href\": \"http://example.net:8080/path\",\n        \"host\": \"example.net:8080\",\n        \"hostname\": \"example.net\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Stuff after a / delimiter is ignored\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"example.com/stuff\",\n      \"expected\": {\n        \"href\": \"http://example.com/path\",\n        \"host\": \"example.com\",\n        \"hostname\": \"example.com\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Stuff after a ? delimiter is ignored\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"example.com?stuff\",\n      \"expected\": {\n        \"href\": \"http://example.com/path\",\n        \"host\": \"example.com\",\n        \"hostname\": \"example.com\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Stuff after a # delimiter is ignored\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"example.com#stuff\",\n      \"expected\": {\n        \"href\": \"http://example.com/path\",\n        \"host\": \"example.com\",\n        \"hostname\": \"example.com\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Stuff after a \\\\ delimiter is ignored for special schemes\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"example.com\\\\stuff\",\n      \"expected\": {\n        \"href\": \"http://example.com/path\",\n        \"host\": \"example.com\",\n        \"hostname\": \"example.com\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"comment\": \"\\\\ is not a delimiter for non-special schemes, but still forbidden in hosts\",\n      \"href\": \"view-source+http://example.net/path\",\n      \"new_value\": \"example.com\\\\stuff\",\n      \"expected\": {\n        \"href\": \"view-source+http://example.net/path\",\n        \"host\": \"example.net\",\n        \"hostname\": \"example.net\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Broken IPv6\",\n      \"href\": \"http://example.net/\",\n      \"new_value\": \"[google.com]\",\n      \"expected\": {\n        \"href\": \"http://example.net/\",\n        \"host\": \"example.net\",\n        \"hostname\": \"example.net\"\n      }\n    },\n    {\n      \"href\": \"http://example.net/\",\n      \"new_value\": \"[::1.2.3.4x]\",\n      \"expected\": {\n        \"href\": \"http://example.net/\",\n        \"host\": \"example.net\",\n        \"hostname\": \"example.net\"\n      }\n    },\n    {\n      \"href\": \"http://example.net/\",\n      \"new_value\": \"[::1.2.3.]\",\n      \"expected\": {\n        \"href\": \"http://example.net/\",\n        \"host\": \"example.net\",\n        \"hostname\": \"example.net\"\n      }\n    },\n    {\n      \"href\": \"http://example.net/\",\n      \"new_value\": \"[::1.2.]\",\n      \"expected\": {\n        \"href\": \"http://example.net/\",\n        \"host\": \"example.net\",\n        \"hostname\": \"example.net\"\n      }\n    },\n    {\n      \"href\": \"http://example.net/\",\n      \"new_value\": \"[::1.]\",\n      \"expected\": {\n        \"href\": \"http://example.net/\",\n        \"host\": \"example.net\",\n        \"hostname\": \"example.net\"\n      }\n    },\n    {\n      \"href\": \"file://y/\",\n      \"new_value\": \"x:123\",\n      \"expected\": {\n        \"href\": \"file://y/\",\n        \"host\": \"y\",\n        \"hostname\": \"y\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"href\": \"file://y/\",\n      \"new_value\": \"loc%41lhost\",\n      \"expected\": {\n        \"href\": \"file:///\",\n        \"host\": \"\",\n        \"hostname\": \"\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"href\": \"file://hi/x\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"file:///x\",\n        \"host\": \"\",\n        \"hostname\": \"\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"href\": \"sc://test@test/\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"sc://test@test/\",\n        \"host\": \"test\",\n        \"hostname\": \"test\",\n        \"username\": \"test\"\n      }\n    },\n    {\n      \"href\": \"sc://test:12/\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"sc://test:12/\",\n        \"host\": \"test:12\",\n        \"hostname\": \"test\",\n        \"port\": \"12\"\n      }\n    },\n    {\n      \"comment\": \"Drop /. from path\",\n      \"href\": \"non-spec:/.//p\",\n      \"new_value\": \"h\",\n      \"expected\": {\n        \"href\": \"non-spec://h//p\",\n        \"host\": \"h\",\n        \"hostname\": \"h\",\n        \"pathname\": \"//p\"\n      }\n    },\n    {\n      \"href\": \"non-spec:/.//p\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"non-spec:////p\",\n        \"host\": \"\",\n        \"hostname\": \"\",\n        \"pathname\": \"//p\"\n      }\n    },\n    {\n      \"comment\": \"Leading / is not stripped\",\n      \"href\": \"http://example.com/\",\n      \"new_value\": \"///bad.com\",\n      \"expected\": {\n        \"href\": \"http://example.com/\",\n        \"host\": \"example.com\",\n        \"hostname\": \"example.com\"\n      }\n    },\n    {\n      \"comment\": \"Leading / is not stripped\",\n      \"href\": \"sc://example.com/\",\n      \"new_value\": \"///bad.com\",\n      \"expected\": {\n        \"href\": \"sc:///\",\n        \"host\": \"\",\n        \"hostname\": \"\"\n      }\n    },\n    {\n      \"href\": \"https://example.com/\",\n      \"new_value\": \"a%C2%ADb\",\n      \"expected\": {\n        \"href\": \"https://ab/\",\n        \"host\": \"ab\",\n        \"hostname\": \"ab\"\n      }\n    },\n    {\n      \"href\": \"https://example.com/\",\n      \"new_value\": \"\\u00AD\",\n      \"expected\": {\n        \"href\": \"https://example.com/\",\n        \"host\": \"example.com\",\n        \"hostname\": \"example.com\"\n      }\n    },\n    {\n      \"href\": \"https://example.com/\",\n      \"new_value\": \"%C2%AD\",\n      \"expected\": {\n        \"href\": \"https://example.com/\",\n        \"host\": \"example.com\",\n        \"hostname\": \"example.com\"\n      }\n    },\n    {\n      \"href\": \"https://example.com/\",\n      \"new_value\": \"xn--\",\n      \"expected\": {\n        \"href\": \"https://example.com/\",\n        \"host\": \"example.com\",\n        \"hostname\": \"example.com\"\n      }\n    },\n    {\n      \"href\": \"https://test.invalid/\",\n      \"new_value\": \"*\",\n      \"expected\": {\n        \"href\": \"https://*/\",\n        \"host\": \"*\",\n        \"hostname\": \"*\"\n      }\n    },\n    {\n      \"href\": \"https://test.invalid/\",\n      \"new_value\": \"x@x\",\n      \"expected\": {\n        \"href\": \"https://test.invalid/\",\n        \"host\": \"test.invalid\",\n        \"hostname\": \"test.invalid\"\n      }\n    },\n    {\n      \"href\": \"https://test.invalid/\",\n      \"new_value\": \"foo\\t\\r\\nbar\",\n      \"expected\": {\n        \"href\": \"https://foobar/\",\n        \"host\": \"foobar\",\n        \"hostname\": \"foobar\"\n      }\n    },\n    {\n      \"href\": \"https://test.invalid/\",\n      \"new_value\": \"><\",\n      \"expected\": {\n        \"href\": \"https://test.invalid/\",\n        \"host\": \"test.invalid\",\n        \"hostname\": \"test.invalid\"\n      }\n    },\n    {\n      \"href\": \"https://test.invalid/\",\n      \"new_value\": \"test/@aaa\",\n      \"expected\": {\n        \"href\": \"https://test/\",\n        \"host\": \"test\",\n        \"hostname\": \"test\"\n      }\n    },\n    {\n      \"href\": \"https://test.invalid/\",\n      \"new_value\": \"test/:aaa\",\n      \"expected\": {\n        \"href\": \"https://test/\",\n        \"host\": \"test\",\n        \"hostname\": \"test\"\n      }\n    }\n  ],\n  \"port\": [\n    {\n      \"href\": \"http://example.net\",\n      \"new_value\": \"8080\",\n      \"expected\": {\n        \"href\": \"http://example.net:8080/\",\n        \"host\": \"example.net:8080\",\n        \"hostname\": \"example.net\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Port number is removed if empty is the new value\",\n      \"href\": \"http://example.net:8080\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"http://example.net/\",\n        \"host\": \"example.net\",\n        \"hostname\": \"example.net\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Default port number is removed\",\n      \"href\": \"http://example.net:8080\",\n      \"new_value\": \"80\",\n      \"expected\": {\n        \"href\": \"http://example.net/\",\n        \"host\": \"example.net\",\n        \"hostname\": \"example.net\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Default port number is removed\",\n      \"href\": \"https://example.net:4433\",\n      \"new_value\": \"443\",\n      \"expected\": {\n        \"href\": \"https://example.net/\",\n        \"host\": \"example.net\",\n        \"hostname\": \"example.net\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Default port number is only removed for the relevant scheme\",\n      \"href\": \"https://example.net\",\n      \"new_value\": \"80\",\n      \"expected\": {\n        \"href\": \"https://example.net:80/\",\n        \"host\": \"example.net:80\",\n        \"hostname\": \"example.net\",\n        \"port\": \"80\"\n      }\n    },\n    {\n      \"comment\": \"Stuff after a / delimiter is ignored\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"8080/stuff\",\n      \"expected\": {\n        \"href\": \"http://example.net:8080/path\",\n        \"host\": \"example.net:8080\",\n        \"hostname\": \"example.net\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Stuff after a ? delimiter is ignored\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"8080?stuff\",\n      \"expected\": {\n        \"href\": \"http://example.net:8080/path\",\n        \"host\": \"example.net:8080\",\n        \"hostname\": \"example.net\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Stuff after a # delimiter is ignored\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"8080#stuff\",\n      \"expected\": {\n        \"href\": \"http://example.net:8080/path\",\n        \"host\": \"example.net:8080\",\n        \"hostname\": \"example.net\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Stuff after a \\\\ delimiter is ignored for special schemes\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"8080\\\\stuff\",\n      \"expected\": {\n        \"href\": \"http://example.net:8080/path\",\n        \"host\": \"example.net:8080\",\n        \"hostname\": \"example.net\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Anything other than ASCII digit stops the port parser in a setter but is not an error\",\n      \"href\": \"view-source+http://example.net/path\",\n      \"new_value\": \"8080stuff2\",\n      \"expected\": {\n        \"href\": \"view-source+http://example.net:8080/path\",\n        \"host\": \"example.net:8080\",\n        \"hostname\": \"example.net\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Anything other than ASCII digit stops the port parser in a setter but is not an error\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"8080stuff2\",\n      \"expected\": {\n        \"href\": \"http://example.net:8080/path\",\n        \"host\": \"example.net:8080\",\n        \"hostname\": \"example.net\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Anything other than ASCII digit stops the port parser in a setter but is not an error\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"8080+2\",\n      \"expected\": {\n        \"href\": \"http://example.net:8080/path\",\n        \"host\": \"example.net:8080\",\n        \"hostname\": \"example.net\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Port numbers are 16 bit integers\",\n      \"href\": \"http://example.net/path\",\n      \"new_value\": \"65535\",\n      \"expected\": {\n        \"href\": \"http://example.net:65535/path\",\n        \"host\": \"example.net:65535\",\n        \"hostname\": \"example.net\",\n        \"port\": \"65535\"\n      }\n    },\n    {\n      \"comment\": \"Port numbers are 16 bit integers, overflowing is an error\",\n      \"href\": \"http://example.net:8080/path\",\n      \"new_value\": \"65536\",\n      \"expected\": {\n        \"href\": \"http://example.net:8080/path\",\n        \"host\": \"example.net:8080\",\n        \"hostname\": \"example.net\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Setting port to a string that doesn't parse as a number\",\n      \"href\": \"http://example.net:8080/path\",\n      \"new_value\": \"randomstring\",\n      \"expected\": {\n        \"href\": \"http://example.net:8080/path\",\n        \"host\": \"example.net:8080\",\n        \"hostname\": \"example.net\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Port numbers are 16 bit integers, overflowing is an error\",\n      \"href\": \"non-special://example.net:8080/path\",\n      \"new_value\": \"65536\",\n      \"expected\": {\n        \"href\": \"non-special://example.net:8080/path\",\n        \"host\": \"example.net:8080\",\n        \"hostname\": \"example.net\",\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"href\": \"file://test/\",\n      \"new_value\": \"12\",\n      \"expected\": {\n        \"href\": \"file://test/\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"href\": \"file://localhost/\",\n      \"new_value\": \"12\",\n      \"expected\": {\n        \"href\": \"file:///\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"href\": \"non-base:value\",\n      \"new_value\": \"12\",\n      \"expected\": {\n        \"href\": \"non-base:value\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"href\": \"sc:///\",\n      \"new_value\": \"12\",\n      \"expected\": {\n        \"href\": \"sc:///\",\n        \"port\": \"\"\n      }\n    },\n    {\n      \"href\": \"sc://x/\",\n      \"new_value\": \"12\",\n      \"expected\": {\n        \"href\": \"sc://x:12/\",\n        \"port\": \"12\"\n      }\n    },\n    {\n      \"href\": \"javascript://x/\",\n      \"new_value\": \"12\",\n      \"expected\": {\n        \"href\": \"javascript://x:12/\",\n        \"port\": \"12\"\n      }\n    },\n    {\n      \"comment\": \"Leading u0009 on special scheme\",\n      \"href\": \"https://domain.com:443\",\n      \"new_value\": \"\\u00098080\",\n      \"expected\": {\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Leading u0009 on non-special scheme\",\n      \"href\": \"wpt++://domain.com:443\",\n      \"new_value\": \"\\u00098080\",\n      \"expected\": {\n        \"port\": \"8080\"\n      }\n    },\n    {\n      \"comment\": \"Should use all ascii prefixed characters as port\",\n      \"href\": \"https://www.google.com:4343\",\n      \"new_value\": \"4wpt\",\n      \"expected\": {\n        \"port\": \"4\"\n      }\n    }\n  ],\n  \"pathname\": [\n    {\n      \"comment\": \"Opaque paths cannot be set\",\n      \"href\": \"mailto:me@example.net\",\n      \"new_value\": \"/foo\",\n      \"expected\": {\n        \"href\": \"mailto:me@example.net\",\n        \"pathname\": \"me@example.net\"\n      }\n    },\n    {\n      \"href\": \"data:original\",\n      \"new_value\": \"new value\",\n      \"expected\": {\n        \"href\": \"data:original\",\n        \"pathname\": \"original\"\n      }\n    },\n    {\n      \"href\": \"sc:original\",\n      \"new_value\": \"new value\",\n      \"expected\": {\n        \"href\": \"sc:original\",\n        \"pathname\": \"original\"\n      }\n    },\n    {\n      \"comment\": \"Special URLs cannot have their paths erased\",\n      \"href\": \"file:///some/path\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"file:///\",\n        \"pathname\": \"/\"\n      }\n    },\n    {\n      \"comment\": \"Non-special URLs can have their paths erased\",\n      \"href\": \"foo://somehost/some/path\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"foo://somehost\",\n        \"pathname\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Non-special URLs with an empty host can have their paths erased\",\n      \"href\": \"foo:///some/path\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"foo://\",\n        \"pathname\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Path-only URLs cannot have their paths erased\",\n      \"href\": \"foo:/some/path\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"foo:/\",\n        \"pathname\": \"/\"\n      }\n    },\n    {\n      \"comment\": \"Path-only URLs always have an initial slash\",\n      \"href\": \"foo:/some/path\",\n      \"new_value\": \"test\",\n      \"expected\": {\n        \"href\": \"foo:/test\",\n        \"pathname\": \"/test\"\n      }\n    },\n    {\n      \"href\": \"unix:/run/foo.socket?timeout=10\",\n      \"new_value\": \"/var/log/../run/bar.socket\",\n      \"expected\": {\n        \"href\": \"unix:/var/run/bar.socket?timeout=10\",\n        \"pathname\": \"/var/run/bar.socket\"\n      }\n    },\n    {\n      \"href\": \"https://example.net#nav\",\n      \"new_value\": \"home\",\n      \"expected\": {\n        \"href\": \"https://example.net/home#nav\",\n        \"pathname\": \"/home\"\n      }\n    },\n    {\n      \"href\": \"https://example.net#nav\",\n      \"new_value\": \"../home\",\n      \"expected\": {\n        \"href\": \"https://example.net/home#nav\",\n        \"pathname\": \"/home\"\n      }\n    },\n    {\n      \"comment\": \"\\\\ is a segment delimiter for 'special' URLs\",\n      \"href\": \"http://example.net/home?lang=fr#nav\",\n      \"new_value\": \"\\\\a\\\\%2E\\\\b\\\\%2e.\\\\c\",\n      \"expected\": {\n        \"href\": \"http://example.net/a/c?lang=fr#nav\",\n        \"pathname\": \"/a/c\"\n      }\n    },\n    {\n      \"comment\": \"\\\\ is *not* a segment delimiter for non-'special' URLs\",\n      \"href\": \"view-source+http://example.net/home?lang=fr#nav\",\n      \"new_value\": \"\\\\a\\\\%2E\\\\b\\\\%2e.\\\\c\",\n      \"expected\": {\n        \"href\": \"view-source+http://example.net/\\\\a\\\\%2E\\\\b\\\\%2e.\\\\c?lang=fr#nav\",\n        \"pathname\": \"/\\\\a\\\\%2E\\\\b\\\\%2e.\\\\c\"\n      }\n    },\n    {\n      \"comment\": \"UTF-8 percent encoding with the default encode set. Tabs and newlines are removed.\",\n      \"href\": \"a:/\",\n      \"new_value\": \"\\u0000\\u0001\\t\\n\\r\\u001f !\\\"#$%&'()*+,-./09:;<=>?@AZ[\\\\]^_`az{|}~\\u007f\\u0080\\u0081Éé\",\n      \"expected\": {\n        \"href\": \"a:/%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\\\]%5E_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9\",\n        \"pathname\": \"/%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\\\]%5E_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9\"\n      }\n    },\n    {\n      \"comment\": \"Bytes already percent-encoded are left as-is, including %2E outside dotted segments.\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"%2e%2E%c3%89té\",\n      \"expected\": {\n        \"href\": \"http://example.net/%2e%2E%c3%89t%C3%A9\",\n        \"pathname\": \"/%2e%2E%c3%89t%C3%A9\"\n      }\n    },\n    {\n      \"comment\": \"? needs to be encoded\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"?\",\n      \"expected\": {\n        \"href\": \"http://example.net/%3F\",\n        \"pathname\": \"/%3F\"\n      }\n    },\n    {\n      \"comment\": \"# needs to be encoded\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"#\",\n      \"expected\": {\n        \"href\": \"http://example.net/%23\",\n        \"pathname\": \"/%23\"\n      }\n    },\n    {\n      \"comment\": \"? needs to be encoded, non-special scheme\",\n      \"href\": \"sc://example.net\",\n      \"new_value\": \"?\",\n      \"expected\": {\n        \"href\": \"sc://example.net/%3F\",\n        \"pathname\": \"/%3F\"\n      }\n    },\n    {\n      \"comment\": \"# needs to be encoded, non-special scheme\",\n      \"href\": \"sc://example.net\",\n      \"new_value\": \"#\",\n      \"expected\": {\n        \"href\": \"sc://example.net/%23\",\n        \"pathname\": \"/%23\"\n      }\n    },\n    {\n      \"comment\": \"? doesn't mess up encoding\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"/?é\",\n      \"expected\": {\n        \"href\": \"http://example.net/%3F%C3%A9\",\n        \"pathname\": \"/%3F%C3%A9\"\n      }\n    },\n    {\n      \"comment\": \"# doesn't mess up encoding\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"/#é\",\n      \"expected\": {\n        \"href\": \"http://example.net/%23%C3%A9\",\n        \"pathname\": \"/%23%C3%A9\"\n      }\n    },\n    {\n      \"comment\": \"File URLs and (back)slashes\",\n      \"href\": \"file://monkey/\",\n      \"new_value\": \"\\\\\\\\\",\n      \"expected\": {\n        \"href\": \"file://monkey//\",\n        \"pathname\": \"//\"\n      }\n    },\n    {\n      \"comment\": \"File URLs and (back)slashes\",\n      \"href\": \"file:///unicorn\",\n      \"new_value\": \"//\\\\/\",\n      \"expected\": {\n        \"href\": \"file://////\",\n        \"pathname\": \"////\"\n      }\n    },\n    {\n      \"comment\": \"File URLs and (back)slashes\",\n      \"href\": \"file:///unicorn\",\n      \"new_value\": \"//monkey/..//\",\n      \"expected\": {\n        \"href\": \"file://///\",\n        \"pathname\": \"///\"\n      }\n    },\n    {\n      \"comment\": \"Serialize /. in path\",\n      \"href\": \"non-spec:/\",\n      \"new_value\": \"/.//p\",\n      \"expected\": {\n        \"href\": \"non-spec:/.//p\",\n        \"pathname\": \"//p\"\n      }\n    },\n    {\n      \"href\": \"non-spec:/\",\n      \"new_value\": \"/..//p\",\n      \"expected\": {\n        \"href\": \"non-spec:/.//p\",\n        \"pathname\": \"//p\"\n      }\n    },\n    {\n      \"href\": \"non-spec:/\",\n      \"new_value\": \"//p\",\n      \"expected\": {\n        \"href\": \"non-spec:/.//p\",\n        \"pathname\": \"//p\"\n      }\n    },\n    {\n      \"comment\": \"Drop /. from path\",\n      \"href\": \"non-spec:/.//\",\n      \"new_value\": \"p\",\n      \"expected\": {\n        \"href\": \"non-spec:/p\",\n        \"pathname\": \"/p\"\n      }\n    },\n    {\n      \"comment\": \"Non-special URLs with non-opaque paths percent-encode U+0020\",\n      \"href\": \"data:/nospace\",\n      \"new_value\": \"space \",\n      \"expected\": {\n        \"href\": \"data:/space%20\",\n        \"pathname\": \"/space%20\"\n      }\n    },\n    {\n      \"href\": \"sc:/nospace\",\n      \"new_value\": \"space \",\n      \"expected\": {\n        \"href\": \"sc:/space%20\",\n        \"pathname\": \"/space%20\"\n      }\n    },\n    {\n      \"comment\": \"Trailing space should be encoded\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \" \",\n      \"expected\": {\n        \"href\": \"http://example.net/%20\",\n        \"pathname\": \"/%20\"\n      }\n    },\n    {\n      \"comment\": \"Trailing C0 control should be encoded\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"\\u0000\",\n      \"expected\": {\n        \"href\": \"http://example.net/%00\",\n        \"pathname\": \"/%00\"\n      }\n    }\n  ],\n  \"search\": [\n    {\n      \"href\": \"https://example.net#nav\",\n      \"new_value\": \"lang=fr\",\n      \"expected\": {\n        \"href\": \"https://example.net/?lang=fr#nav\",\n        \"search\": \"?lang=fr\"\n      }\n    },\n    {\n      \"href\": \"https://example.net?lang=en-US#nav\",\n      \"new_value\": \"lang=fr\",\n      \"expected\": {\n        \"href\": \"https://example.net/?lang=fr#nav\",\n        \"search\": \"?lang=fr\"\n      }\n    },\n    {\n      \"href\": \"https://example.net?lang=en-US#nav\",\n      \"new_value\": \"?lang=fr\",\n      \"expected\": {\n        \"href\": \"https://example.net/?lang=fr#nav\",\n        \"search\": \"?lang=fr\"\n      }\n    },\n    {\n      \"href\": \"https://example.net?lang=en-US#nav\",\n      \"new_value\": \"??lang=fr\",\n      \"expected\": {\n        \"href\": \"https://example.net/??lang=fr#nav\",\n        \"search\": \"??lang=fr\"\n      }\n    },\n    {\n      \"href\": \"https://example.net?lang=en-US#nav\",\n      \"new_value\": \"?\",\n      \"expected\": {\n        \"href\": \"https://example.net/?#nav\",\n        \"search\": \"\"\n      }\n    },\n    {\n      \"href\": \"https://example.net?lang=en-US#nav\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"https://example.net/#nav\",\n        \"search\": \"\"\n      }\n    },\n    {\n      \"href\": \"https://example.net?lang=en-US\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"https://example.net/\",\n        \"search\": \"\"\n      }\n    },\n    {\n      \"href\": \"https://example.net\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"https://example.net/\",\n        \"search\": \"\"\n      }\n    },\n    {\n      \"comment\": \"UTF-8 percent encoding with the query encode set. Tabs and newlines are removed.\",\n      \"href\": \"a:/\",\n      \"new_value\": \"\\u0000\\u0001\\t\\n\\r\\u001f !\\\"#$%&'()*+,-./09:;<=>?@AZ[\\\\]^_`az{|}~\\u007f\\u0080\\u0081Éé\",\n      \"expected\": {\n        \"href\": \"a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9\",\n        \"search\": \"?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9\"\n      }\n    },\n    {\n      \"comment\": \"Bytes already percent-encoded are left as-is\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"%c3%89té\",\n      \"expected\": {\n        \"href\": \"http://example.net/?%c3%89t%C3%A9\",\n        \"search\": \"?%c3%89t%C3%A9\"\n      }\n    },\n    {\n      \"comment\": \"Trailing spaces and opaque paths\",\n      \"href\": \"data:space ?query\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"data:space%20\",\n        \"pathname\": \"space%20\",\n        \"search\": \"\"\n      }\n    },\n    {\n      \"href\": \"sc:space ?query\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"sc:space%20\",\n        \"pathname\": \"space%20\",\n        \"search\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Trailing spaces and opaque paths\",\n      \"href\": \"data:space  ?query#fragment\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"data:space %20#fragment\",\n        \"search\": \"\"\n      }\n    },\n    {\n      \"href\": \"sc:space  ?query#fragment\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"sc:space %20#fragment\",\n        \"search\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Trailing space should be encoded\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \" \",\n      \"expected\": {\n        \"href\": \"http://example.net/?%20\",\n        \"search\": \"?%20\"\n      }\n    },\n    {\n      \"comment\": \"Trailing C0 control should be encoded\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"\\u0000\",\n      \"expected\": {\n        \"href\": \"http://example.net/?%00\",\n        \"search\": \"?%00\"\n      }\n    }\n  ],\n  \"hash\": [\n    {\n      \"href\": \"https://example.net\",\n      \"new_value\": \"main\",\n      \"expected\": {\n        \"href\": \"https://example.net/#main\",\n        \"hash\": \"#main\"\n      }\n    },\n    {\n      \"href\": \"https://example.net#nav\",\n      \"new_value\": \"main\",\n      \"expected\": {\n        \"href\": \"https://example.net/#main\",\n        \"hash\": \"#main\"\n      }\n    },\n    {\n      \"href\": \"https://example.net?lang=en-US\",\n      \"new_value\": \"##nav\",\n      \"expected\": {\n        \"href\": \"https://example.net/?lang=en-US##nav\",\n        \"hash\": \"##nav\"\n      }\n    },\n    {\n      \"href\": \"https://example.net?lang=en-US#nav\",\n      \"new_value\": \"#main\",\n      \"expected\": {\n        \"href\": \"https://example.net/?lang=en-US#main\",\n        \"hash\": \"#main\"\n      }\n    },\n    {\n      \"href\": \"https://example.net?lang=en-US#nav\",\n      \"new_value\": \"#\",\n      \"expected\": {\n        \"href\": \"https://example.net/?lang=en-US#\",\n        \"hash\": \"\"\n      }\n    },\n    {\n      \"href\": \"https://example.net?lang=en-US#nav\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"https://example.net/?lang=en-US\",\n        \"hash\": \"\"\n      }\n    },\n    {\n      \"href\": \"http://example.net\",\n      \"new_value\": \"#foo bar\",\n      \"expected\": {\n        \"href\": \"http://example.net/#foo%20bar\",\n        \"hash\": \"#foo%20bar\"\n      }\n    },\n    {\n      \"href\": \"http://example.net\",\n      \"new_value\": \"#foo\\\"bar\",\n      \"expected\": {\n        \"href\": \"http://example.net/#foo%22bar\",\n        \"hash\": \"#foo%22bar\"\n      }\n    },\n    {\n      \"href\": \"http://example.net\",\n      \"new_value\": \"#foo<bar\",\n      \"expected\": {\n        \"href\": \"http://example.net/#foo%3Cbar\",\n        \"hash\": \"#foo%3Cbar\"\n      }\n    },\n    {\n      \"href\": \"http://example.net\",\n      \"new_value\": \"#foo>bar\",\n      \"expected\": {\n        \"href\": \"http://example.net/#foo%3Ebar\",\n        \"hash\": \"#foo%3Ebar\"\n      }\n    },\n    {\n      \"href\": \"http://example.net\",\n      \"new_value\": \"#foo`bar\",\n      \"expected\": {\n        \"href\": \"http://example.net/#foo%60bar\",\n        \"hash\": \"#foo%60bar\"\n      }\n    },\n    {\n      \"comment\": \"Simple percent-encoding; tabs and newlines are removed\",\n      \"href\": \"a:/\",\n      \"new_value\": \"\\u0000\\u0001\\t\\n\\r\\u001f !\\\"#$%&'()*+,-./09:;<=>?@AZ[\\\\]^_`az{|}~\\u007f\\u0080\\u0081Éé\",\n      \"expected\": {\n        \"href\": \"a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9\",\n        \"hash\": \"#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9\"\n      }\n    },\n    {\n      \"comment\": \"Percent-encode NULLs in fragment\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"a\\u0000b\",\n      \"expected\": {\n        \"href\": \"http://example.net/#a%00b\",\n        \"hash\": \"#a%00b\"\n      }\n    },\n    {\n      \"comment\": \"Percent-encode NULLs in fragment\",\n      \"href\": \"non-spec:/\",\n      \"new_value\": \"a\\u0000b\",\n      \"expected\": {\n        \"href\": \"non-spec:/#a%00b\",\n        \"hash\": \"#a%00b\"\n      }\n    },\n    {\n      \"comment\": \"Bytes already percent-encoded are left as-is\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"%c3%89té\",\n      \"expected\": {\n        \"href\": \"http://example.net/#%c3%89t%C3%A9\",\n        \"hash\": \"#%c3%89t%C3%A9\"\n      }\n    },\n    {\n      \"href\": \"javascript:alert(1)\",\n      \"new_value\": \"castle\",\n      \"expected\": {\n        \"href\": \"javascript:alert(1)#castle\",\n        \"hash\": \"#castle\"\n      }\n    },\n    {\n      \"comment\": \"Trailing spaces and opaque paths\",\n      \"href\": \"data:space                                                                                                                                  #fragment\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"data:space                                                                                                                                 %20\",\n        \"pathname\": \"space                                                                                                                                 %20\",\n        \"hash\": \"\"\n      }\n    },\n    {\n      \"href\": \"sc:space    #fragment\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"sc:space   %20\",\n        \"pathname\": \"space   %20\",\n        \"hash\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Trailing spaces and opaque paths\",\n      \"href\": \"data:space  ?query#fragment\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"data:space %20?query\",\n        \"hash\": \"\"\n      }\n    },\n    {\n      \"href\": \"sc:space  ?query#fragment\",\n      \"new_value\": \"\",\n      \"expected\": {\n        \"href\": \"sc:space %20?query\",\n        \"hash\": \"\"\n      }\n    },\n    {\n      \"comment\": \"Trailing space should be encoded\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \" \",\n      \"expected\": {\n        \"href\": \"http://example.net/#%20\",\n        \"hash\": \"#%20\"\n      }\n    },\n    {\n      \"comment\": \"Trailing C0 control should be encoded\",\n      \"href\": \"http://example.net\",\n      \"new_value\": \"\\u0000\",\n      \"expected\": {\n        \"href\": \"http://example.net/#%00\",\n        \"hash\": \"#%00\"\n      }\n    }\n  ],\n  \"href\": [\n    {\n      \"href\": \"file:///var/log/system.log\",\n      \"new_value\": \"http://0300.168.0xF0\",\n      \"expected\": {\n        \"href\": \"http://192.168.0.240/\",\n        \"protocol\": \"http:\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "tests/wpt/url/resources/toascii.json",
    "content": "[\n  \"This contains assorted IDNA tests that IdnaTestV2 might not cover.\",\n  \"Feel free to deduplicate with a clear commit message.\",\n  \"\",\n  \"If the test only applies to the URL Standard's 'domain to ASCII', \",\n  \"and not to TR46's ToASCII, then tag it with `urlStandardOnly`\",\n  {\n    \"comment\": \"Label with hyphens in 3rd and 4th position\",\n    \"input\": \"aa--\",\n    \"output\": \"aa--\"\n  },\n  {\n    \"input\": \"a†--\",\n    \"output\": \"xn--a---kp0a\"\n  },\n  {\n    \"input\": \"ab--c\",\n    \"output\": \"ab--c\"\n  },\n  {\n    \"comment\": \"Label with leading hyphen\",\n    \"input\": \"-x\",\n    \"output\": \"-x\"\n  },\n  {\n    \"input\": \"-†\",\n    \"output\": \"xn----xhn\"\n  },\n  {\n    \"input\": \"-x.xn--zca\",\n    \"output\": \"-x.xn--zca\"\n  },\n  {\n    \"input\": \"-x.ß\",\n    \"output\": \"-x.xn--zca\"\n  },\n  {\n    \"comment\": \"Label with trailing hyphen\",\n    \"input\": \"x-.xn--zca\",\n    \"output\": \"x-.xn--zca\"\n  },\n  {\n    \"input\": \"x-.ß\",\n    \"output\": \"x-.xn--zca\"\n  },\n  {\n    \"comment\": \"Empty labels\",\n    \"input\": \"x..xn--zca\",\n    \"output\": \"x..xn--zca\"\n  },\n  {\n    \"input\": \"x..ß\",\n    \"output\": \"x..xn--zca\"\n  },\n  {\n    \"comment\": \"Invalid Punycode\",\n    \"input\": \"xn--a\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--a.xn--zca\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--a.ß\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--ls8h=\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"Invalid Punycode (contains non-ASCII character)\",\n    \"input\": \"xn--tešla\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"Valid Punycode\",\n    \"input\": \"xn--zca.xn--zca\",\n    \"output\": \"xn--zca.xn--zca\"\n  },\n  {\n    \"comment\": \"Mixed\",\n    \"input\": \"xn--zca.ß\",\n    \"output\": \"xn--zca.xn--zca\"\n  },\n  {\n    \"input\": \"ab--c.xn--zca\",\n    \"output\": \"ab--c.xn--zca\"\n  },\n  {\n    \"input\": \"ab--c.ß\",\n    \"output\": \"ab--c.xn--zca\"\n  },\n  {\n    \"comment\": \"CheckJoiners is true\",\n    \"input\": \"\\u200D.example\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--1ug.example\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"CheckBidi is true\",\n    \"input\": \"يa\",\n    \"output\": null\n  },\n  {\n    \"input\": \"xn--a-yoc\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"processing_option is Nontransitional_Processing\",\n    \"input\": \"ශ්‍රී\",\n    \"output\": \"xn--10cl1a0b660p\"\n  },\n  {\n    \"input\": \"نامه‌ای\",\n    \"output\": \"xn--mgba3gch31f060k\"\n  },\n  {\n    \"comment\": \"U+FFFD\",\n    \"input\": \"\\uFFFD.com\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"U+FFFD character encoded in Punycode\",\n    \"input\": \"xn--zn7c.com\",\n    \"output\": null\n  },\n  {\n    \"comment\": \"Label longer than 63 code points\",\n    \"input\": \"x01234567890123456789012345678901234567890123456789012345678901x\",\n    \"output\": \"x01234567890123456789012345678901234567890123456789012345678901x\"\n  },\n  {\n    \"input\": \"x01234567890123456789012345678901234567890123456789012345678901†\",\n    \"output\": \"xn--x01234567890123456789012345678901234567890123456789012345678901-6963b\"\n  },\n  {\n    \"input\": \"x01234567890123456789012345678901234567890123456789012345678901x.xn--zca\",\n    \"output\": \"x01234567890123456789012345678901234567890123456789012345678901x.xn--zca\"\n  },\n  {\n    \"input\": \"x01234567890123456789012345678901234567890123456789012345678901x.ß\",\n    \"output\": \"x01234567890123456789012345678901234567890123456789012345678901x.xn--zca\"\n  },\n  {\n    \"comment\": \"Domain excluding TLD longer than 253 code points\",\n    \"input\": \"01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.x\",\n    \"output\": \"01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.x\"\n  },\n  {\n    \"input\": \"01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.xn--zca\",\n    \"output\": \"01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.xn--zca\"\n  },\n  {\n    \"input\": \"01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.ß\",\n    \"output\": \"01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.xn--zca\"\n  },\n  {\n    \"comment\": \"IDNA ignored code points\",\n    \"input\": \"a\\u00ADb\",\n    \"output\": \"ab\"\n  },\n  {\n    \"comment\": \"Interesting UseSTD3ASCIIRules=false cases\",\n    \"input\": \"≠\",\n    \"output\": \"xn--1ch\"\n  },\n  {\n    \"input\": \"≮\",\n    \"output\": \"xn--gdh\"\n  },\n  {\n    \"input\": \"≯\",\n    \"output\": \"xn--hdh\"\n  },\n  {\n    \"comment\": \"NFC normalization (forbidden < and > characters are normalized to valid ones)\",\n    \"input\": \"=\\u0338\",\n    \"output\": \"xn--1ch\"\n  },\n  {\n    \"input\": \"<\\u0338\",\n    \"output\": \"xn--gdh\"\n  },\n  {\n    \"input\": \">\\u0338\",\n    \"output\": \"xn--hdh\"\n  },\n  {\n    \"comment\": \"Same with inserted IDNA ignored code point\",\n    \"input\": \"=\\u00AD\\u0338\",\n    \"output\": \"xn--1ch\"\n  },\n  {\n    \"input\": \"<\\u00AD\\u0338\",\n    \"output\": \"xn--gdh\"\n  },\n  {\n    \"input\": \">\\u00AD\\u0338\",\n    \"output\": \"xn--hdh\"\n  },\n  \"Tests below are from WebKit (fast/url/idna2003.html & fast/url/idna2008.html; contributed by Chris Weber back in 2011).\",\n  {\n    \"input\": \"fa\\u00DF.de\",\n    \"output\": \"xn--fa-hia.de\"\n  },\n  {\n    \"input\": \"\\u03B2\\u03CC\\u03BB\\u03BF\\u03C2.com\",\n    \"output\": \"xn--nxasmm1c.com\"\n  },\n  {\n    \"input\": \"\\u0DC1\\u0DCA\\u200D\\u0DBB\\u0DD3.com\",\n    \"output\": \"xn--10cl1a0b660p.com\"\n  },\n  {\n    \"input\": \"\\u0646\\u0627\\u0645\\u0647\\u200C\\u0627\\u06CC.com\",\n    \"output\": \"xn--mgba3gch31f060k.com\"\n  },\n  {\n    \"input\": \"www.loo\\u0138out.net\",\n    \"output\": \"www.xn--looout-5bb.net\"\n  },\n  {\n    \"input\": \"\\u15EF\\u15EF\\u15EF.lookout.net\",\n    \"output\": \"xn--1qeaa.lookout.net\"\n  },\n  {\n    \"input\": \"www.lookout.\\u0441\\u043E\\u043C\",\n    \"output\": \"www.lookout.xn--l1adi\"\n  },\n  {\n    \"input\": \"www\\u2025lookout.net\",\n    \"output\": null\n  },\n  {\n    \"input\": \"www.lookout\\u2027net\",\n    \"output\": \"www.xn--lookoutnet-406e\"\n  },\n  {\n    \"input\": \"www.lookout.net\\u2A7480\",\n    \"output\": null,\n    \"urlStandardOnly\": true\n  },\n  {\n    \"input\": \"www\\u00A0.lookout.net\",\n    \"output\": null,\n    \"urlStandardOnly\": true\n  },\n  {\n    \"input\": \"\\u1680lookout.net\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\u001flookout.net\",\n    \"output\": null,\n    \"urlStandardOnly\": true\n  },\n  {\n    \"input\": \"look\\u06DDout.net\",\n    \"output\": null\n  },\n  {\n    \"input\": \"look\\u180Eout.net\",\n    \"output\": \"lookout.net\"\n  },\n  {\n    \"input\": \"look\\u2060out.net\",\n    \"output\": \"lookout.net\"\n  },\n  {\n    \"input\": \"look\\uFEFFout.net\",\n    \"output\": \"lookout.net\"\n  },\n  {\n    \"input\": \"look\\uD83F\\uDFFEout.net\",\n    \"output\": null\n  },\n  {\n    \"input\": \"look\\uFFFAout.net\",\n    \"output\": null\n  },\n  {\n    \"input\": \"look\\u2FF0out.net\",\n    \"output\": null\n  },\n  {\n    \"input\": \"look\\u0341out.net\",\n    \"output\": \"xn--looout-kp7b.net\"\n  },\n  {\n    \"input\": \"look\\u202Eout.net\",\n    \"output\": null\n  },\n  {\n    \"input\": \"look\\u206Bout.net\",\n    \"output\": \"lookout.net\"\n  },\n  {\n    \"input\": \"look\\uDB40\\uDC01out.net\",\n    \"output\": null\n  },\n  {\n    \"input\": \"look\\uDB40\\uDC20out.net\",\n    \"output\": null\n  },\n  {\n    \"input\": \"look\\u05BEout.net\",\n    \"output\": null\n  },\n  {\n    \"input\": \"B\\u00FCcher.de\",\n    \"output\": \"xn--bcher-kva.de\"\n  },\n  {\n    \"input\": \"\\u2665.net\",\n    \"output\": \"xn--g6h.net\"\n  },\n  {\n    \"input\": \"\\u0378.net\",\n    \"output\": null\n  },\n  {\n    \"input\": \"\\u04C0.com\",\n    \"output\": \"xn--s5a.com\"\n  },\n  {\n    \"input\": \"\\uD87E\\uDC68.com\",\n    \"output\": \"xn--snl.com\"\n  },\n  {\n    \"input\": \"\\u2183.com\",\n    \"output\": \"xn--r5g.com\"\n  },\n  {\n    \"input\": \"look\\u034Fout.net\",\n    \"output\": \"lookout.net\"\n  },\n  {\n    \"input\": \"gOoGle.com\",\n    \"output\": \"google.com\"\n  },\n  {\n    \"input\": \"\\u09dc.com\",\n    \"output\": \"xn--15b8c.com\"\n  },\n  {\n    \"input\": \"\\u1E9E.com\",\n    \"output\": \"xn--zca.com\"\n  },\n  {\n    \"input\": \"\\u1E9E.foo.com\",\n    \"output\": \"xn--zca.foo.com\"\n  },\n  {\n    \"input\": \"-foo.bar.com\",\n    \"output\": \"-foo.bar.com\"\n  },\n  {\n    \"input\": \"foo-.bar.com\",\n    \"output\": \"foo-.bar.com\"\n  },\n  {\n    \"input\": \"ab--cd.com\",\n    \"output\": \"ab--cd.com\"\n  },\n  {\n    \"input\": \"xn--0.com\",\n    \"output\": null\n  },\n  {\n    \"input\": \"foo\\u0300.bar.com\",\n    \"output\": \"xn--fo-3ja.bar.com\"\n  }\n]\n"
  },
  {
    "path": "tests/wpt/url/resources/urltestdata-javascript-only.json",
    "content": "[\n  \"See ../README.md for a description of the format.\",\n  {\n    \"input\": \"http://example.com/\\uD800\\uD801\\uDFFE\\uDFFF\\uFDD0\\uFDCF\\uFDEF\\uFDF0\\uFFFE\\uFFFF?\\uD800\\uD801\\uDFFE\\uDFFF\\uFDD0\\uFDCF\\uFDEF\\uFDF0\\uFFFE\\uFFFF\",\n    \"base\": null,\n    \"href\": \"http://example.com/%EF%BF%BD%F0%90%9F%BE%EF%BF%BD%EF%B7%90%EF%B7%8F%EF%B7%AF%EF%B7%B0%EF%BF%BE%EF%BF%BF?%EF%BF%BD%F0%90%9F%BE%EF%BF%BD%EF%B7%90%EF%B7%8F%EF%B7%AF%EF%B7%B0%EF%BF%BE%EF%BF%BF\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/%EF%BF%BD%F0%90%9F%BE%EF%BF%BD%EF%B7%90%EF%B7%8F%EF%B7%AF%EF%B7%B0%EF%BF%BE%EF%BF%BF\",\n    \"search\": \"?%EF%BF%BD%F0%90%9F%BE%EF%BF%BD%EF%B7%90%EF%B7%8F%EF%B7%AF%EF%B7%B0%EF%BF%BE%EF%BF%BF\",\n    \"hash\": \"\"\n  }\n]\n"
  },
  {
    "path": "tests/wpt/url/resources/urltestdata.json",
    "content": "[\n  \"See ../README.md for a description of the format.\",\n  {\n    \"input\": \"http://example\\t.\\norg\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://user:pass@foo:21/bar;par?b#c\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://user:pass@foo:21/bar;par?b#c\",\n    \"origin\": \"http://foo:21\",\n    \"protocol\": \"http:\",\n    \"username\": \"user\",\n    \"password\": \"pass\",\n    \"host\": \"foo:21\",\n    \"hostname\": \"foo\",\n    \"port\": \"21\",\n    \"pathname\": \"/bar;par\",\n    \"search\": \"?b\",\n    \"hash\": \"#c\"\n  },\n  {\n    \"input\": \"https://test:@test\",\n    \"base\": null,\n    \"href\": \"https://test@test/\",\n    \"origin\": \"https://test\",\n    \"protocol\": \"https:\",\n    \"username\": \"test\",\n    \"password\": \"\",\n    \"host\": \"test\",\n    \"hostname\": \"test\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"https://:@test\",\n    \"base\": null,\n    \"href\": \"https://test/\",\n    \"origin\": \"https://test\",\n    \"protocol\": \"https:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"test\",\n    \"hostname\": \"test\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"non-special://test:@test/x\",\n    \"base\": null,\n    \"href\": \"non-special://test@test/x\",\n    \"origin\": \"null\",\n    \"protocol\": \"non-special:\",\n    \"username\": \"test\",\n    \"password\": \"\",\n    \"host\": \"test\",\n    \"hostname\": \"test\",\n    \"port\": \"\",\n    \"pathname\": \"/x\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"non-special://:@test/x\",\n    \"base\": null,\n    \"href\": \"non-special://test/x\",\n    \"origin\": \"null\",\n    \"protocol\": \"non-special:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"test\",\n    \"hostname\": \"test\",\n    \"port\": \"\",\n    \"pathname\": \"/x\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http:foo.com\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/foo.com\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/foo.com\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"\\t   :foo.com   \\n\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/:foo.com\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/:foo.com\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \" foo.com  \",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/foo.com\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/foo.com\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"a:\\t foo.com\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"a: foo.com\",\n    \"origin\": \"null\",\n    \"protocol\": \"a:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \" foo.com\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://f:21/ b ? d # e \",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://f:21/%20b%20?%20d%20#%20e\",\n    \"origin\": \"http://f:21\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"f:21\",\n    \"hostname\": \"f\",\n    \"port\": \"21\",\n    \"pathname\": \"/%20b%20\",\n    \"search\": \"?%20d%20\",\n    \"hash\": \"#%20e\"\n  },\n  {\n    \"input\": \"lolscheme:x x#x x\",\n    \"base\": null,\n    \"href\": \"lolscheme:x x#x%20x\",\n    \"protocol\": \"lolscheme:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"x x\",\n    \"search\": \"\",\n    \"hash\": \"#x%20x\"\n  },\n  {\n    \"input\": \"http://f:/c\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://f/c\",\n    \"origin\": \"http://f\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"f\",\n    \"hostname\": \"f\",\n    \"port\": \"\",\n    \"pathname\": \"/c\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://f:0/c\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://f:0/c\",\n    \"origin\": \"http://f:0\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"f:0\",\n    \"hostname\": \"f\",\n    \"port\": \"0\",\n    \"pathname\": \"/c\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://f:00000000000000/c\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://f:0/c\",\n    \"origin\": \"http://f:0\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"f:0\",\n    \"hostname\": \"f\",\n    \"port\": \"0\",\n    \"pathname\": \"/c\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://f:00000000000000000000080/c\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://f/c\",\n    \"origin\": \"http://f\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"f\",\n    \"hostname\": \"f\",\n    \"port\": \"\",\n    \"pathname\": \"/c\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://f:b/c\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://f: /c\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://f:\\n/c\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://f/c\",\n    \"origin\": \"http://f\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"f\",\n    \"hostname\": \"f\",\n    \"port\": \"\",\n    \"pathname\": \"/c\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://f:fifty-two/c\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://f:999999/c\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"non-special://f:999999/c\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://f: 21 / b ? d # e \",\n    \"base\": \"http://example.org/foo/bar\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/bar\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/bar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"  \\t\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/bar\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/bar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \":foo.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/:foo.com/\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/:foo.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \":foo.com\\\\\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/:foo.com/\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/:foo.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \":\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/:\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/:\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \":a\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/:a\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/:a\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \":/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/:/\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \":\\\\\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/:/\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \":#\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/:#\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/:\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"#\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/bar#\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/bar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"#/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/bar#/\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/bar\",\n    \"search\": \"\",\n    \"hash\": \"#/\"\n  },\n  {\n    \"input\": \"#\\\\\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/bar#\\\\\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/bar\",\n    \"search\": \"\",\n    \"hash\": \"#\\\\\"\n  },\n  {\n    \"input\": \"#;?\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/bar#;?\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/bar\",\n    \"search\": \"\",\n    \"hash\": \"#;?\"\n  },\n  {\n    \"input\": \"?\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/bar?\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/bar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \":23\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/:23\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/:23\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/:23\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/:23\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/:23\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"\\\\x\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/x\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/x\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"\\\\\\\\x\\\\hello\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://x/hello\",\n    \"origin\": \"http://x\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"x\",\n    \"hostname\": \"x\",\n    \"port\": \"\",\n    \"pathname\": \"/hello\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"::\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/::\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/::\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"::23\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/::23\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/::23\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"foo://\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"foo://\",\n    \"origin\": \"null\",\n    \"protocol\": \"foo:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://a:b@c:29/d\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://a:b@c:29/d\",\n    \"origin\": \"http://c:29\",\n    \"protocol\": \"http:\",\n    \"username\": \"a\",\n    \"password\": \"b\",\n    \"host\": \"c:29\",\n    \"hostname\": \"c\",\n    \"port\": \"29\",\n    \"pathname\": \"/d\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http::@c:29\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/:@c:29\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/:@c:29\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://&a:foo(b]c@d:2/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://&a:foo(b%5Dc@d:2/\",\n    \"origin\": \"http://d:2\",\n    \"protocol\": \"http:\",\n    \"username\": \"&a\",\n    \"password\": \"foo(b%5Dc\",\n    \"host\": \"d:2\",\n    \"hostname\": \"d\",\n    \"port\": \"2\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://::@c@d:2\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://:%3A%40c@d:2/\",\n    \"origin\": \"http://d:2\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"%3A%40c\",\n    \"host\": \"d:2\",\n    \"hostname\": \"d\",\n    \"port\": \"2\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://foo.com:b@d/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://foo.com:b@d/\",\n    \"origin\": \"http://d\",\n    \"protocol\": \"http:\",\n    \"username\": \"foo.com\",\n    \"password\": \"b\",\n    \"host\": \"d\",\n    \"hostname\": \"d\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://foo.com/\\\\@\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://foo.com//@\",\n    \"origin\": \"http://foo.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo.com\",\n    \"hostname\": \"foo.com\",\n    \"port\": \"\",\n    \"pathname\": \"//@\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http:\\\\\\\\foo.com\\\\\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://foo.com/\",\n    \"origin\": \"http://foo.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo.com\",\n    \"hostname\": \"foo.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http:\\\\\\\\a\\\\b:c\\\\d@foo.com\\\\\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://a/b:c/d@foo.com/\",\n    \"origin\": \"http://a\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"a\",\n    \"hostname\": \"a\",\n    \"port\": \"\",\n    \"pathname\": \"/b:c/d@foo.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://a:b@c\\\\\",\n    \"base\": null,\n    \"href\": \"http://a:b@c/\",\n    \"origin\": \"http://c\",\n    \"protocol\": \"http:\",\n    \"username\": \"a\",\n    \"password\": \"b\",\n    \"host\": \"c\",\n    \"hostname\": \"c\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"ws://a@b\\\\c\",\n    \"base\": null,\n    \"href\": \"ws://a@b/c\",\n    \"origin\": \"ws://b\",\n    \"protocol\": \"ws:\",\n    \"username\": \"a\",\n    \"password\": \"\",\n    \"host\": \"b\",\n    \"hostname\": \"b\",\n    \"port\": \"\",\n    \"pathname\": \"/c\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"foo:/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"foo:/\",\n    \"origin\": \"null\",\n    \"protocol\": \"foo:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"foo:/bar.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"foo:/bar.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"foo:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/bar.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"foo://///////\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"foo://///////\",\n    \"origin\": \"null\",\n    \"protocol\": \"foo:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"///////\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"foo://///////bar.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"foo://///////bar.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"foo:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"///////bar.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"foo:////://///\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"foo:////://///\",\n    \"origin\": \"null\",\n    \"protocol\": \"foo:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//://///\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"c:/foo\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"c:/foo\",\n    \"origin\": \"null\",\n    \"protocol\": \"c:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/foo\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"//foo/bar\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://foo/bar\",\n    \"origin\": \"http://foo\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo\",\n    \"hostname\": \"foo\",\n    \"port\": \"\",\n    \"pathname\": \"/bar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://foo/path;a??e#f#g\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://foo/path;a??e#f#g\",\n    \"origin\": \"http://foo\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo\",\n    \"hostname\": \"foo\",\n    \"port\": \"\",\n    \"pathname\": \"/path;a\",\n    \"search\": \"??e\",\n    \"hash\": \"#f#g\"\n  },\n  {\n    \"input\": \"http://foo/abcd?efgh?ijkl\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://foo/abcd?efgh?ijkl\",\n    \"origin\": \"http://foo\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo\",\n    \"hostname\": \"foo\",\n    \"port\": \"\",\n    \"pathname\": \"/abcd\",\n    \"search\": \"?efgh?ijkl\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://foo/abcd#foo?bar\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://foo/abcd#foo?bar\",\n    \"origin\": \"http://foo\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo\",\n    \"hostname\": \"foo\",\n    \"port\": \"\",\n    \"pathname\": \"/abcd\",\n    \"search\": \"\",\n    \"hash\": \"#foo?bar\"\n  },\n  {\n    \"input\": \"[61:24:74]:98\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/[61:24:74]:98\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/[61:24:74]:98\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http:[61:27]/:foo\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/[61:27]/:foo\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/[61:27]/:foo\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://[1::2]:3:4\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://2001::1\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://2001::1]\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://2001::1]:80\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://[2001::1]\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://[2001::1]/\",\n    \"origin\": \"http://[2001::1]\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"[2001::1]\",\n    \"hostname\": \"[2001::1]\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://[::127.0.0.1]\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://[::7f00:1]/\",\n    \"origin\": \"http://[::7f00:1]\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"[::7f00:1]\",\n    \"hostname\": \"[::7f00:1]\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://[::127.0.0.1.]\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://[0:0:0:0:0:0:13.1.68.3]\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://[::d01:4403]/\",\n    \"origin\": \"http://[::d01:4403]\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"[::d01:4403]\",\n    \"hostname\": \"[::d01:4403]\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://[2001::1]:80\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://[2001::1]/\",\n    \"origin\": \"http://[2001::1]\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"[2001::1]\",\n    \"hostname\": \"[2001::1]\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http:/example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/example.com/\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"ftp:/example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"ftp://example.com/\",\n    \"origin\": \"ftp://example.com\",\n    \"protocol\": \"ftp:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"https:/example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"https://example.com/\",\n    \"origin\": \"https://example.com\",\n    \"protocol\": \"https:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"madeupscheme:/example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"madeupscheme:/example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"madeupscheme:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:/example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"file:///example.com/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file://example:1/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"file://example:test/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"file://example%/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"file://[example]/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"ftps:/example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"ftps:/example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"ftps:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"gopher:/example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"gopher:/example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"gopher:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"ws:/example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"ws://example.com/\",\n    \"origin\": \"ws://example.com\",\n    \"protocol\": \"ws:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"wss:/example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"wss://example.com/\",\n    \"origin\": \"wss://example.com\",\n    \"protocol\": \"wss:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"data:/example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"data:/example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"data:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"javascript:/example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"javascript:/example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"javascript:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"mailto:/example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"mailto:/example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"mailto:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http:example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/example.com/\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"ftp:example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"ftp://example.com/\",\n    \"origin\": \"ftp://example.com\",\n    \"protocol\": \"ftp:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"https:example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"https://example.com/\",\n    \"origin\": \"https://example.com\",\n    \"protocol\": \"https:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"madeupscheme:example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"madeupscheme:example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"madeupscheme:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"ftps:example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"ftps:example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"ftps:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"gopher:example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"gopher:example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"gopher:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"ws:example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"ws://example.com/\",\n    \"origin\": \"ws://example.com\",\n    \"protocol\": \"ws:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"wss:example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"wss://example.com/\",\n    \"origin\": \"wss://example.com\",\n    \"protocol\": \"wss:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"data:example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"data:example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"data:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"javascript:example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"javascript:example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"javascript:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"mailto:example.com/\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"mailto:example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"mailto:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/a/b/c\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/a/b/c\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/a/b/c\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/a/ /c\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/a/%20/c\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/a/%20/c\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/a%2fc\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/a%2fc\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/a%2fc\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/a/%2f/c\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/a/%2f/c\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/a/%2f/c\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"#β\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/bar#%CE%B2\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/bar\",\n    \"search\": \"\",\n    \"hash\": \"#%CE%B2\"\n  },\n  {\n    \"input\": \"data:text/html,test#test\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"data:text/html,test#test\",\n    \"origin\": \"null\",\n    \"protocol\": \"data:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"text/html,test\",\n    \"search\": \"\",\n    \"hash\": \"#test\"\n  },\n  {\n    \"input\": \"tel:1234567890\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"tel:1234567890\",\n    \"origin\": \"null\",\n    \"protocol\": \"tel:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"1234567890\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# Based on https://felixfbecker.github.io/whatwg-url-custom-host-repro/\",\n  {\n    \"input\": \"ssh://example.com/foo/bar.git\",\n    \"base\": \"http://example.org/\",\n    \"href\": \"ssh://example.com/foo/bar.git\",\n    \"origin\": \"null\",\n    \"protocol\": \"ssh:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/bar.git\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/file.html\",\n  {\n    \"input\": \"file:c:\\\\foo\\\\bar.html\",\n    \"base\": \"file:///tmp/mock/path\",\n    \"href\": \"file:///c:/foo/bar.html\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/c:/foo/bar.html\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"  File:c|////foo\\\\bar.html\",\n    \"base\": \"file:///tmp/mock/path\",\n    \"href\": \"file:///c:////foo/bar.html\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/c:////foo/bar.html\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"C|/foo/bar\",\n    \"base\": \"file:///tmp/mock/path\",\n    \"href\": \"file:///C:/foo/bar\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/foo/bar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/C|\\\\foo\\\\bar\",\n    \"base\": \"file:///tmp/mock/path\",\n    \"href\": \"file:///C:/foo/bar\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/foo/bar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"//C|/foo/bar\",\n    \"base\": \"file:///tmp/mock/path\",\n    \"href\": \"file:///C:/foo/bar\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/foo/bar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"//server/file\",\n    \"base\": \"file:///tmp/mock/path\",\n    \"href\": \"file://server/file\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"server\",\n    \"hostname\": \"server\",\n    \"port\": \"\",\n    \"pathname\": \"/file\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"\\\\\\\\server\\\\file\",\n    \"base\": \"file:///tmp/mock/path\",\n    \"href\": \"file://server/file\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"server\",\n    \"hostname\": \"server\",\n    \"port\": \"\",\n    \"pathname\": \"/file\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/\\\\server/file\",\n    \"base\": \"file:///tmp/mock/path\",\n    \"href\": \"file://server/file\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"server\",\n    \"hostname\": \"server\",\n    \"port\": \"\",\n    \"pathname\": \"/file\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:///foo/bar.txt\",\n    \"base\": \"file:///tmp/mock/path\",\n    \"href\": \"file:///foo/bar.txt\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/bar.txt\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:///home/me\",\n    \"base\": \"file:///tmp/mock/path\",\n    \"href\": \"file:///home/me\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/home/me\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"//\",\n    \"base\": \"file:///tmp/mock/path\",\n    \"href\": \"file:///\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"///\",\n    \"base\": \"file:///tmp/mock/path\",\n    \"href\": \"file:///\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"///test\",\n    \"base\": \"file:///tmp/mock/path\",\n    \"href\": \"file:///test\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file://test\",\n    \"base\": \"file:///tmp/mock/path\",\n    \"href\": \"file://test/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"test\",\n    \"hostname\": \"test\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file://localhost\",\n    \"base\": \"file:///tmp/mock/path\",\n    \"href\": \"file:///\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file://localhost/\",\n    \"base\": \"file:///tmp/mock/path\",\n    \"href\": \"file:///\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file://localhost/test\",\n    \"base\": \"file:///tmp/mock/path\",\n    \"href\": \"file:///test\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"test\",\n    \"base\": \"file:///tmp/mock/path\",\n    \"href\": \"file:///tmp/mock/test\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/tmp/mock/test\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:test\",\n    \"base\": \"file:///tmp/mock/path\",\n    \"href\": \"file:///tmp/mock/test\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/tmp/mock/test\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:///w|m\",\n    \"base\": null,\n    \"href\": \"file:///w|m\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/w|m\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:///w||m\",\n    \"base\": null,\n    \"href\": \"file:///w||m\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/w||m\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:///w|/m\",\n    \"base\": null,\n    \"href\": \"file:///w:/m\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/w:/m\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:C|/m/\",\n    \"base\": null,\n    \"href\": \"file:///C:/m/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/m/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:C||/m/\",\n    \"base\": null,\n    \"href\": \"file:///C||/m/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/C||/m/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/path.js\",\n  {\n    \"input\": \"http://example.com/././foo\",\n    \"base\": null,\n    \"href\": \"http://example.com/foo\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/./.foo\",\n    \"base\": null,\n    \"href\": \"http://example.com/.foo\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/.foo\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo/.\",\n    \"base\": null,\n    \"href\": \"http://example.com/foo/\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo/./\",\n    \"base\": null,\n    \"href\": \"http://example.com/foo/\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo/bar/..\",\n    \"base\": null,\n    \"href\": \"http://example.com/foo/\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo/bar/../\",\n    \"base\": null,\n    \"href\": \"http://example.com/foo/\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo/..bar\",\n    \"base\": null,\n    \"href\": \"http://example.com/foo/..bar\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/..bar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo/bar/../ton\",\n    \"base\": null,\n    \"href\": \"http://example.com/foo/ton\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/ton\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo/bar/../ton/../../a\",\n    \"base\": null,\n    \"href\": \"http://example.com/a\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/a\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo/../../..\",\n    \"base\": null,\n    \"href\": \"http://example.com/\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo/../../../ton\",\n    \"base\": null,\n    \"href\": \"http://example.com/ton\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/ton\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo/%2e\",\n    \"base\": null,\n    \"href\": \"http://example.com/foo/\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo/%2e%2\",\n    \"base\": null,\n    \"href\": \"http://example.com/foo/%2e%2\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/%2e%2\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo/%2e./%2e%2e/.%2e/%2e.bar\",\n    \"base\": null,\n    \"href\": \"http://example.com/%2e.bar\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/%2e.bar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com////../..\",\n    \"base\": null,\n    \"href\": \"http://example.com//\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"//\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo/bar//../..\",\n    \"base\": null,\n    \"href\": \"http://example.com/foo/\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo/bar//..\",\n    \"base\": null,\n    \"href\": \"http://example.com/foo/bar/\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/bar/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo\",\n    \"base\": null,\n    \"href\": \"http://example.com/foo\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/%20foo\",\n    \"base\": null,\n    \"href\": \"http://example.com/%20foo\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/%20foo\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo%\",\n    \"base\": null,\n    \"href\": \"http://example.com/foo%\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo%\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo%2\",\n    \"base\": null,\n    \"href\": \"http://example.com/foo%2\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo%2\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo%2zbar\",\n    \"base\": null,\n    \"href\": \"http://example.com/foo%2zbar\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo%2zbar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo%2Â©zbar\",\n    \"base\": null,\n    \"href\": \"http://example.com/foo%2%C3%82%C2%A9zbar\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo%2%C3%82%C2%A9zbar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo%41%7a\",\n    \"base\": null,\n    \"href\": \"http://example.com/foo%41%7a\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo%41%7a\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo\\t\\u0091%91\",\n    \"base\": null,\n    \"href\": \"http://example.com/foo%C2%91%91\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo%C2%91%91\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo%00%51\",\n    \"base\": null,\n    \"href\": \"http://example.com/foo%00%51\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo%00%51\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/(%28:%3A%29)\",\n    \"base\": null,\n    \"href\": \"http://example.com/(%28:%3A%29)\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/(%28:%3A%29)\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/%3A%3a%3C%3c\",\n    \"base\": null,\n    \"href\": \"http://example.com/%3A%3a%3C%3c\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/%3A%3a%3C%3c\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/foo\\tbar\",\n    \"base\": null,\n    \"href\": \"http://example.com/foobar\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foobar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com\\\\\\\\foo\\\\\\\\bar\",\n    \"base\": null,\n    \"href\": \"http://example.com//foo//bar\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"//foo//bar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd\",\n    \"base\": null,\n    \"href\": \"http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/%7Ffp3%3Eju%3Dduvgw%3Dd\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/@asdf%40\",\n    \"base\": null,\n    \"href\": \"http://example.com/@asdf%40\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/@asdf%40\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/你好你好\",\n    \"base\": null,\n    \"href\": \"http://example.com/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/‥/foo\",\n    \"base\": null,\n    \"href\": \"http://example.com/%E2%80%A5/foo\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/%E2%80%A5/foo\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/﻿/foo\",\n    \"base\": null,\n    \"href\": \"http://example.com/%EF%BB%BF/foo\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/%EF%BB%BF/foo\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.com/‮/foo/‭/bar\",\n    \"base\": null,\n    \"href\": \"http://example.com/%E2%80%AE/foo/%E2%80%AD/bar\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/%E2%80%AE/foo/%E2%80%AD/bar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/relative.js\",\n  {\n    \"input\": \"http://www.google.com/foo?bar=baz#\",\n    \"base\": null,\n    \"href\": \"http://www.google.com/foo?bar=baz#\",\n    \"origin\": \"http://www.google.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www.google.com\",\n    \"hostname\": \"www.google.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo\",\n    \"search\": \"?bar=baz\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://www.google.com/foo?bar=baz# »\",\n    \"base\": null,\n    \"href\": \"http://www.google.com/foo?bar=baz#%20%C2%BB\",\n    \"origin\": \"http://www.google.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www.google.com\",\n    \"hostname\": \"www.google.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo\",\n    \"search\": \"?bar=baz\",\n    \"hash\": \"#%20%C2%BB\"\n  },\n  {\n    \"input\": \"data:test# »\",\n    \"base\": null,\n    \"href\": \"data:test#%20%C2%BB\",\n    \"origin\": \"null\",\n    \"protocol\": \"data:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"test\",\n    \"search\": \"\",\n    \"hash\": \"#%20%C2%BB\"\n  },\n  {\n    \"input\": \"http://www.google.com\",\n    \"base\": null,\n    \"href\": \"http://www.google.com/\",\n    \"origin\": \"http://www.google.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www.google.com\",\n    \"hostname\": \"www.google.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://192.0x00A80001\",\n    \"base\": null,\n    \"href\": \"http://192.168.0.1/\",\n    \"origin\": \"http://192.168.0.1\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"192.168.0.1\",\n    \"hostname\": \"192.168.0.1\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://www/foo%2Ehtml\",\n    \"base\": null,\n    \"href\": \"http://www/foo%2Ehtml\",\n    \"origin\": \"http://www\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www\",\n    \"hostname\": \"www\",\n    \"port\": \"\",\n    \"pathname\": \"/foo%2Ehtml\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://www/foo/%2E/html\",\n    \"base\": null,\n    \"href\": \"http://www/foo/html\",\n    \"origin\": \"http://www\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www\",\n    \"hostname\": \"www\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/html\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://user:pass@/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://%25DOMAIN:foobar@foodomain.com/\",\n    \"base\": null,\n    \"href\": \"http://%25DOMAIN:foobar@foodomain.com/\",\n    \"origin\": \"http://foodomain.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"%25DOMAIN\",\n    \"password\": \"foobar\",\n    \"host\": \"foodomain.com\",\n    \"hostname\": \"foodomain.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http:\\\\\\\\www.google.com\\\\foo\",\n    \"base\": null,\n    \"href\": \"http://www.google.com/foo\",\n    \"origin\": \"http://www.google.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www.google.com\",\n    \"hostname\": \"www.google.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://foo:80/\",\n    \"base\": null,\n    \"href\": \"http://foo/\",\n    \"origin\": \"http://foo\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo\",\n    \"hostname\": \"foo\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://foo:81/\",\n    \"base\": null,\n    \"href\": \"http://foo:81/\",\n    \"origin\": \"http://foo:81\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo:81\",\n    \"hostname\": \"foo\",\n    \"port\": \"81\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"httpa://foo:80/\",\n    \"base\": null,\n    \"href\": \"httpa://foo:80/\",\n    \"origin\": \"null\",\n    \"protocol\": \"httpa:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo:80\",\n    \"hostname\": \"foo\",\n    \"port\": \"80\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://foo:-80/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"https://foo:443/\",\n    \"base\": null,\n    \"href\": \"https://foo/\",\n    \"origin\": \"https://foo\",\n    \"protocol\": \"https:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo\",\n    \"hostname\": \"foo\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"https://foo:80/\",\n    \"base\": null,\n    \"href\": \"https://foo:80/\",\n    \"origin\": \"https://foo:80\",\n    \"protocol\": \"https:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo:80\",\n    \"hostname\": \"foo\",\n    \"port\": \"80\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"ftp://foo:21/\",\n    \"base\": null,\n    \"href\": \"ftp://foo/\",\n    \"origin\": \"ftp://foo\",\n    \"protocol\": \"ftp:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo\",\n    \"hostname\": \"foo\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"ftp://foo:80/\",\n    \"base\": null,\n    \"href\": \"ftp://foo:80/\",\n    \"origin\": \"ftp://foo:80\",\n    \"protocol\": \"ftp:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo:80\",\n    \"hostname\": \"foo\",\n    \"port\": \"80\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"gopher://foo:70/\",\n    \"base\": null,\n    \"href\": \"gopher://foo:70/\",\n    \"origin\": \"null\",\n    \"protocol\": \"gopher:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo:70\",\n    \"hostname\": \"foo\",\n    \"port\": \"70\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"gopher://foo:443/\",\n    \"base\": null,\n    \"href\": \"gopher://foo:443/\",\n    \"origin\": \"null\",\n    \"protocol\": \"gopher:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo:443\",\n    \"hostname\": \"foo\",\n    \"port\": \"443\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"ws://foo:80/\",\n    \"base\": null,\n    \"href\": \"ws://foo/\",\n    \"origin\": \"ws://foo\",\n    \"protocol\": \"ws:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo\",\n    \"hostname\": \"foo\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"ws://foo:81/\",\n    \"base\": null,\n    \"href\": \"ws://foo:81/\",\n    \"origin\": \"ws://foo:81\",\n    \"protocol\": \"ws:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo:81\",\n    \"hostname\": \"foo\",\n    \"port\": \"81\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"ws://foo:443/\",\n    \"base\": null,\n    \"href\": \"ws://foo:443/\",\n    \"origin\": \"ws://foo:443\",\n    \"protocol\": \"ws:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo:443\",\n    \"hostname\": \"foo\",\n    \"port\": \"443\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"ws://foo:815/\",\n    \"base\": null,\n    \"href\": \"ws://foo:815/\",\n    \"origin\": \"ws://foo:815\",\n    \"protocol\": \"ws:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo:815\",\n    \"hostname\": \"foo\",\n    \"port\": \"815\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"wss://foo:80/\",\n    \"base\": null,\n    \"href\": \"wss://foo:80/\",\n    \"origin\": \"wss://foo:80\",\n    \"protocol\": \"wss:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo:80\",\n    \"hostname\": \"foo\",\n    \"port\": \"80\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"wss://foo:81/\",\n    \"base\": null,\n    \"href\": \"wss://foo:81/\",\n    \"origin\": \"wss://foo:81\",\n    \"protocol\": \"wss:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo:81\",\n    \"hostname\": \"foo\",\n    \"port\": \"81\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"wss://foo:443/\",\n    \"base\": null,\n    \"href\": \"wss://foo/\",\n    \"origin\": \"wss://foo\",\n    \"protocol\": \"wss:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo\",\n    \"hostname\": \"foo\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"wss://foo:815/\",\n    \"base\": null,\n    \"href\": \"wss://foo:815/\",\n    \"origin\": \"wss://foo:815\",\n    \"protocol\": \"wss:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo:815\",\n    \"hostname\": \"foo\",\n    \"port\": \"815\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http:/example.com/\",\n    \"base\": null,\n    \"href\": \"http://example.com/\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"ftp:/example.com/\",\n    \"base\": null,\n    \"href\": \"ftp://example.com/\",\n    \"origin\": \"ftp://example.com\",\n    \"protocol\": \"ftp:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"https:/example.com/\",\n    \"base\": null,\n    \"href\": \"https://example.com/\",\n    \"origin\": \"https://example.com\",\n    \"protocol\": \"https:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"madeupscheme:/example.com/\",\n    \"base\": null,\n    \"href\": \"madeupscheme:/example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"madeupscheme:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:/example.com/\",\n    \"base\": null,\n    \"href\": \"file:///example.com/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"ftps:/example.com/\",\n    \"base\": null,\n    \"href\": \"ftps:/example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"ftps:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"gopher:/example.com/\",\n    \"base\": null,\n    \"href\": \"gopher:/example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"gopher:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"ws:/example.com/\",\n    \"base\": null,\n    \"href\": \"ws://example.com/\",\n    \"origin\": \"ws://example.com\",\n    \"protocol\": \"ws:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"wss:/example.com/\",\n    \"base\": null,\n    \"href\": \"wss://example.com/\",\n    \"origin\": \"wss://example.com\",\n    \"protocol\": \"wss:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"data:/example.com/\",\n    \"base\": null,\n    \"href\": \"data:/example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"data:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"javascript:/example.com/\",\n    \"base\": null,\n    \"href\": \"javascript:/example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"javascript:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"mailto:/example.com/\",\n    \"base\": null,\n    \"href\": \"mailto:/example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"mailto:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http:example.com/\",\n    \"base\": null,\n    \"href\": \"http://example.com/\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"ftp:example.com/\",\n    \"base\": null,\n    \"href\": \"ftp://example.com/\",\n    \"origin\": \"ftp://example.com\",\n    \"protocol\": \"ftp:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"https:example.com/\",\n    \"base\": null,\n    \"href\": \"https://example.com/\",\n    \"origin\": \"https://example.com\",\n    \"protocol\": \"https:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"madeupscheme:example.com/\",\n    \"base\": null,\n    \"href\": \"madeupscheme:example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"madeupscheme:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"ftps:example.com/\",\n    \"base\": null,\n    \"href\": \"ftps:example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"ftps:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"gopher:example.com/\",\n    \"base\": null,\n    \"href\": \"gopher:example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"gopher:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"ws:example.com/\",\n    \"base\": null,\n    \"href\": \"ws://example.com/\",\n    \"origin\": \"ws://example.com\",\n    \"protocol\": \"ws:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"wss:example.com/\",\n    \"base\": null,\n    \"href\": \"wss://example.com/\",\n    \"origin\": \"wss://example.com\",\n    \"protocol\": \"wss:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"data:example.com/\",\n    \"base\": null,\n    \"href\": \"data:example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"data:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"javascript:example.com/\",\n    \"base\": null,\n    \"href\": \"javascript:example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"javascript:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"mailto:example.com/\",\n    \"base\": null,\n    \"href\": \"mailto:example.com/\",\n    \"origin\": \"null\",\n    \"protocol\": \"mailto:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"example.com/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"https://example.com/aaa/bbb/%2e%2e?query\",\n    \"base\": null,\n    \"href\": \"https://example.com/aaa/?query\",\n    \"origin\": \"https://example.com\",\n    \"protocol\": \"https:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/aaa/\",\n    \"search\": \"?query\",\n    \"hash\": \"\"\n  },\n  \"# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/segments-userinfo-vs-host.html\",\n  {\n    \"input\": \"http:@www.example.com\",\n    \"base\": null,\n    \"href\": \"http://www.example.com/\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http:/@www.example.com\",\n    \"base\": null,\n    \"href\": \"http://www.example.com/\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://@www.example.com\",\n    \"base\": null,\n    \"href\": \"http://www.example.com/\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http:a:b@www.example.com\",\n    \"base\": null,\n    \"href\": \"http://a:b@www.example.com/\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"a\",\n    \"password\": \"b\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http:/a:b@www.example.com\",\n    \"base\": null,\n    \"href\": \"http://a:b@www.example.com/\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"a\",\n    \"password\": \"b\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://a:b@www.example.com\",\n    \"base\": null,\n    \"href\": \"http://a:b@www.example.com/\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"a\",\n    \"password\": \"b\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://@pple.com\",\n    \"base\": null,\n    \"href\": \"http://pple.com/\",\n    \"origin\": \"http://pple.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"pple.com\",\n    \"hostname\": \"pple.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http::b@www.example.com\",\n    \"base\": null,\n    \"href\": \"http://:b@www.example.com/\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"b\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http:/:b@www.example.com\",\n    \"base\": null,\n    \"href\": \"http://:b@www.example.com/\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"b\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://:b@www.example.com\",\n    \"base\": null,\n    \"href\": \"http://:b@www.example.com/\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"b\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http:/:@/www.example.com\",\n    \"base\": null,\n    \"failure\": true,\n    \"relativeTo\": \"non-opaque-path-base\"\n  },\n  {\n    \"input\": \"http://user@/www.example.com\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http:@/www.example.com\",\n    \"base\": null,\n    \"failure\": true,\n    \"relativeTo\": \"non-opaque-path-base\"\n  },\n  {\n    \"input\": \"http:/@/www.example.com\",\n    \"base\": null,\n    \"failure\": true,\n    \"relativeTo\": \"non-opaque-path-base\"\n  },\n  {\n    \"input\": \"http://@/www.example.com\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"https:@/www.example.com\",\n    \"base\": null,\n    \"failure\": true,\n    \"relativeTo\": \"non-opaque-path-base\"\n  },\n  {\n    \"input\": \"http:a:b@/www.example.com\",\n    \"base\": null,\n    \"failure\": true,\n    \"relativeTo\": \"non-opaque-path-base\"\n  },\n  {\n    \"input\": \"http:/a:b@/www.example.com\",\n    \"base\": null,\n    \"failure\": true,\n    \"relativeTo\": \"non-opaque-path-base\"\n  },\n  {\n    \"input\": \"http://a:b@/www.example.com\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http::@/www.example.com\",\n    \"base\": null,\n    \"failure\": true,\n    \"relativeTo\": \"non-opaque-path-base\"\n  },\n  {\n    \"input\": \"http:a:@www.example.com\",\n    \"base\": null,\n    \"href\": \"http://a@www.example.com/\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"a\",\n    \"password\": \"\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http:/a:@www.example.com\",\n    \"base\": null,\n    \"href\": \"http://a@www.example.com/\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"a\",\n    \"password\": \"\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://a:@www.example.com\",\n    \"base\": null,\n    \"href\": \"http://a@www.example.com/\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"a\",\n    \"password\": \"\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://www.@pple.com\",\n    \"base\": null,\n    \"href\": \"http://www.@pple.com/\",\n    \"origin\": \"http://pple.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"www.\",\n    \"password\": \"\",\n    \"host\": \"pple.com\",\n    \"hostname\": \"pple.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http:@:www.example.com\",\n    \"base\": null,\n    \"failure\": true,\n    \"relativeTo\": \"non-opaque-path-base\"\n  },\n  {\n    \"input\": \"http:/@:www.example.com\",\n    \"base\": null,\n    \"failure\": true,\n    \"relativeTo\": \"non-opaque-path-base\"\n  },\n  {\n    \"input\": \"http://@:www.example.com\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://:@www.example.com\",\n    \"base\": null,\n    \"href\": \"http://www.example.com/\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# Others\",\n  {\n    \"input\": \"/\",\n    \"base\": \"http://www.example.com/test\",\n    \"href\": \"http://www.example.com/\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/test.txt\",\n    \"base\": \"http://www.example.com/test\",\n    \"href\": \"http://www.example.com/test.txt\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/test.txt\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \".\",\n    \"base\": \"http://www.example.com/test\",\n    \"href\": \"http://www.example.com/\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"..\",\n    \"base\": \"http://www.example.com/test\",\n    \"href\": \"http://www.example.com/\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"test.txt\",\n    \"base\": \"http://www.example.com/test\",\n    \"href\": \"http://www.example.com/test.txt\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/test.txt\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"./test.txt\",\n    \"base\": \"http://www.example.com/test\",\n    \"href\": \"http://www.example.com/test.txt\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/test.txt\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"../test.txt\",\n    \"base\": \"http://www.example.com/test\",\n    \"href\": \"http://www.example.com/test.txt\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/test.txt\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"../aaa/test.txt\",\n    \"base\": \"http://www.example.com/test\",\n    \"href\": \"http://www.example.com/aaa/test.txt\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/aaa/test.txt\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"../../test.txt\",\n    \"base\": \"http://www.example.com/test\",\n    \"href\": \"http://www.example.com/test.txt\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/test.txt\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"中/test.txt\",\n    \"base\": \"http://www.example.com/test\",\n    \"href\": \"http://www.example.com/%E4%B8%AD/test.txt\",\n    \"origin\": \"http://www.example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/%E4%B8%AD/test.txt\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://www.example2.com\",\n    \"base\": \"http://www.example.com/test\",\n    \"href\": \"http://www.example2.com/\",\n    \"origin\": \"http://www.example2.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www.example2.com\",\n    \"hostname\": \"www.example2.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"//www.example2.com\",\n    \"base\": \"http://www.example.com/test\",\n    \"href\": \"http://www.example2.com/\",\n    \"origin\": \"http://www.example2.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www.example2.com\",\n    \"hostname\": \"www.example2.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:...\",\n    \"base\": \"http://www.example.com/test\",\n    \"href\": \"file:///...\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/...\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:..\",\n    \"base\": \"http://www.example.com/test\",\n    \"href\": \"file:///\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:a\",\n    \"base\": \"http://www.example.com/test\",\n    \"href\": \"file:///a\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/a\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:.\",\n    \"base\": null,\n    \"href\": \"file:///\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:.\",\n    \"base\": \"http://www.example.com/test\",\n    \"href\": \"file:///\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/host.html\",\n  \"Basic canonicalization, uppercase should be converted to lowercase\",\n  {\n    \"input\": \"http://ExAmPlE.CoM\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://example.com/\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example example.com\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://Goo%20 goo%7C|.com\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://[]\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://[:]\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  \"U+3000 is mapped to U+0020 (space) which is disallowed\",\n  {\n    \"input\": \"http://GOO\\u00a0\\u3000goo.com\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  \"Other types of space (no-break, zero-width, zero-width-no-break) are name-prepped away to nothing. U+200B, U+2060, and U+FEFF, are ignored\",\n  {\n    \"input\": \"http://GOO\\u200b\\u2060\\ufeffgoo.com\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://googoo.com/\",\n    \"origin\": \"http://googoo.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"googoo.com\",\n    \"hostname\": \"googoo.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"Leading and trailing C0 control or space\",\n  {\n    \"input\": \"\\u0000\\u001b\\u0004\\u0012 http://example.com/\\u001f \\u000d \",\n    \"base\": null,\n    \"href\": \"http://example.com/\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"non-special:opaque  \",\n    \"base\": null,\n    \"href\": \"non-special:opaque\",\n    \"origin\": \"null\",\n    \"protocol\": \"non-special:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"opaque\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"non-special:opaque  ?hi\",\n    \"base\": null,\n    \"href\": \"non-special:opaque %20?hi\",\n    \"origin\": \"null\",\n    \"protocol\": \"non-special:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"opaque %20\",\n    \"search\": \"?hi\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"non-special:opaque  #hi\",\n    \"base\": null,\n    \"href\": \"non-special:opaque %20#hi\",\n    \"origin\": \"null\",\n    \"protocol\": \"non-special:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"opaque %20\",\n    \"search\": \"\",\n    \"hash\": \"#hi\"\n  },\n  {\n    \"input\": \"non-special:opaque  x?hi\",\n    \"base\": null,\n    \"href\": \"non-special:opaque  x?hi\",\n    \"origin\": \"null\",\n    \"protocol\": \"non-special:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"opaque  x\",\n    \"search\": \"?hi\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"non-special:opaque  x#hi\",\n    \"base\": null,\n    \"href\": \"non-special:opaque  x#hi\",\n    \"origin\": \"null\",\n    \"protocol\": \"non-special:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"opaque  x\",\n    \"search\": \"\",\n    \"hash\": \"#hi\"\n  },\n  {\n    \"input\": \"non-special:opaque \\t\\t  \\t#hi\",\n    \"base\": null,\n    \"href\": \"non-special:opaque  %20#hi\",\n    \"origin\": \"null\",\n    \"protocol\": \"non-special:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"opaque  %20\",\n    \"search\": \"\",\n    \"hash\": \"#hi\"\n  },\n  {\n    \"input\": \"non-special:opaque \\t\\t  #hi\",\n    \"base\": null,\n    \"href\": \"non-special:opaque  %20#hi\",\n    \"origin\": \"null\",\n    \"protocol\": \"non-special:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"opaque  %20\",\n    \"search\": \"\",\n    \"hash\": \"#hi\"\n  },\n  {\n    \"input\": \"non-special:opaque\\t\\t  \\r #hi\",\n    \"base\": null,\n    \"href\": \"non-special:opaque  %20#hi\",\n    \"origin\": \"null\",\n    \"protocol\": \"non-special:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"opaque  %20\",\n    \"search\": \"\",\n    \"hash\": \"#hi\"\n  },\n  \"Ideographic full stop (full-width period for Chinese, etc.) should be treated as a dot. U+3002 is mapped to U+002E (dot)\",\n  {\n    \"input\": \"http://www.foo。bar.com\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://www.foo.bar.com/\",\n    \"origin\": \"http://www.foo.bar.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"www.foo.bar.com\",\n    \"hostname\": \"www.foo.bar.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"Invalid unicode characters should fail... U+FDD0 is disallowed; %ef%b7%90 is U+FDD0\",\n  {\n    \"input\": \"http://\\ufdd0zyx.com\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  \"This is the same as previous but escaped\",\n  {\n    \"input\": \"http://%ef%b7%90zyx.com\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  \"U+FFFD\",\n  {\n    \"input\": \"https://\\ufffd\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"https://%EF%BF%BD\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"https://x/\\ufffd?\\ufffd#\\ufffd\",\n    \"base\": null,\n    \"href\": \"https://x/%EF%BF%BD?%EF%BF%BD#%EF%BF%BD\",\n    \"origin\": \"https://x\",\n    \"protocol\": \"https:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"x\",\n    \"hostname\": \"x\",\n    \"port\": \"\",\n    \"pathname\": \"/%EF%BF%BD\",\n    \"search\": \"?%EF%BF%BD\",\n    \"hash\": \"#%EF%BF%BD\"\n  },\n  \"Domain is ASCII, but a label is invalid IDNA\",\n  {\n    \"input\": \"http://a.b.c.xn--pokxncvks\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://10.0.0.xn--pokxncvks\",\n    \"base\": null,\n    \"failure\": true\n  },\n  \"IDNA labels should be matched case-insensitively\",\n  {\n    \"input\": \"http://a.b.c.XN--pokxncvks\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a.b.c.Xn--pokxncvks\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://10.0.0.XN--pokxncvks\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://10.0.0.xN--pokxncvks\",\n    \"base\": null,\n    \"failure\": true\n  },\n  \"Test name prepping, fullwidth input should be converted to ASCII and NOT IDN-ized. This is 'Go' in fullwidth UTF-8/UTF-16.\",\n  {\n    \"input\": \"http://Ｇｏ.com\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://go.com/\",\n    \"origin\": \"http://go.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"go.com\",\n    \"hostname\": \"go.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"URL spec forbids the following. https://www.w3.org/Bugs/Public/show_bug.cgi?id=24257\",\n  {\n    \"input\": \"http://％４１.com\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://%ef%bc%85%ef%bc%94%ef%bc%91.com\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  \"...%00 in fullwidth should fail (also as escaped UTF-8 input)\",\n  {\n    \"input\": \"http://％００.com\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://%ef%bc%85%ef%bc%90%ef%bc%90.com\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  \"Basic IDN support, UTF-8 and UTF-16 input should be converted to IDN\",\n  {\n    \"input\": \"http://你好你好\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://xn--6qqa088eba/\",\n    \"origin\": \"http://xn--6qqa088eba\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"xn--6qqa088eba\",\n    \"hostname\": \"xn--6qqa088eba\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"https://faß.ExAmPlE/\",\n    \"base\": null,\n    \"href\": \"https://xn--fa-hia.example/\",\n    \"origin\": \"https://xn--fa-hia.example\",\n    \"protocol\": \"https:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"xn--fa-hia.example\",\n    \"hostname\": \"xn--fa-hia.example\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"sc://faß.ExAmPlE/\",\n    \"base\": null,\n    \"href\": \"sc://fa%C3%9F.ExAmPlE/\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"fa%C3%9F.ExAmPlE\",\n    \"hostname\": \"fa%C3%9F.ExAmPlE\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"Invalid escaped characters should fail and the percents should be escaped. https://www.w3.org/Bugs/Public/show_bug.cgi?id=24191\",\n  {\n    \"input\": \"http://%zz%66%a.com\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  \"If we get an invalid character that has been escaped.\",\n  {\n    \"input\": \"http://%25\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://hello%00\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  \"Escaped numbers should be treated like IP addresses if they are.\",\n  {\n    \"input\": \"http://%30%78%63%30%2e%30%32%35%30.01\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://192.168.0.1/\",\n    \"origin\": \"http://192.168.0.1\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"192.168.0.1\",\n    \"hostname\": \"192.168.0.1\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://%30%78%63%30%2e%30%32%35%30.01%2e\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://192.168.0.1/\",\n    \"origin\": \"http://192.168.0.1\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"192.168.0.1\",\n    \"hostname\": \"192.168.0.1\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://192.168.0.257\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  \"Invalid escaping in hosts causes failure\",\n  {\n    \"input\": \"http://%3g%78%63%30%2e%30%32%35%30%2E.01\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  \"A space in a host causes failure\",\n  {\n    \"input\": \"http://192.168.0.1 hello\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"https://x x:12\",\n    \"base\": null,\n    \"failure\": true\n  },\n  \"Fullwidth and escaped UTF-8 fullwidth should still be treated as IP\",\n  {\n    \"input\": \"http://０Ｘｃ０．０２５０．０１\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://192.168.0.1/\",\n    \"origin\": \"http://192.168.0.1\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"192.168.0.1\",\n    \"hostname\": \"192.168.0.1\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"Domains with empty labels\",\n  {\n    \"input\": \"http://./\",\n    \"base\": null,\n    \"href\": \"http://./\",\n    \"origin\": \"http://.\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \".\",\n    \"hostname\": \".\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://../\",\n    \"base\": null,\n    \"href\": \"http://../\",\n    \"origin\": \"http://..\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"..\",\n    \"hostname\": \"..\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"Non-special domains with empty labels\",\n  {\n    \"input\": \"h://.\",\n    \"base\": null,\n    \"href\": \"h://.\",\n    \"origin\": \"null\",\n    \"protocol\": \"h:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \".\",\n    \"hostname\": \".\",\n    \"port\": \"\",\n    \"pathname\": \"\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"Broken IPv6\",\n  {\n    \"input\": \"http://[www.google.com]/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://[google.com]\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://[::1.2.3.4x]\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://[::1.2.3.]\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://[::1.2.]\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://[::.1.2]\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://[::1.]\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://[::.1]\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://[::%31]\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://%5B::1]\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  \"Misc Unicode\",\n  {\n    \"input\": \"http://foo:💩@example.com/bar\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://foo:%F0%9F%92%A9@example.com/bar\",\n    \"origin\": \"http://example.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"foo\",\n    \"password\": \"%F0%9F%92%A9\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"port\": \"\",\n    \"pathname\": \"/bar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# resolving a fragment against any scheme succeeds\",\n  {\n    \"input\": \"#\",\n    \"base\": \"test:test\",\n    \"href\": \"test:test#\",\n    \"origin\": \"null\",\n    \"protocol\": \"test:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"test\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"#x\",\n    \"base\": \"mailto:x@x.com\",\n    \"href\": \"mailto:x@x.com#x\",\n    \"origin\": \"null\",\n    \"protocol\": \"mailto:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"x@x.com\",\n    \"search\": \"\",\n    \"hash\": \"#x\"\n  },\n  {\n    \"input\": \"#x\",\n    \"base\": \"data:,\",\n    \"href\": \"data:,#x\",\n    \"origin\": \"null\",\n    \"protocol\": \"data:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \",\",\n    \"search\": \"\",\n    \"hash\": \"#x\"\n  },\n  {\n    \"input\": \"#x\",\n    \"base\": \"about:blank\",\n    \"href\": \"about:blank#x\",\n    \"origin\": \"null\",\n    \"protocol\": \"about:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"blank\",\n    \"search\": \"\",\n    \"hash\": \"#x\"\n  },\n  {\n    \"input\": \"#x:y\",\n    \"base\": \"about:blank\",\n    \"href\": \"about:blank#x:y\",\n    \"origin\": \"null\",\n    \"protocol\": \"about:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"blank\",\n    \"search\": \"\",\n    \"hash\": \"#x:y\"\n  },\n  {\n    \"input\": \"#\",\n    \"base\": \"test:test?test\",\n    \"href\": \"test:test?test#\",\n    \"origin\": \"null\",\n    \"protocol\": \"test:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"test\",\n    \"search\": \"?test\",\n    \"hash\": \"\"\n  },\n  \"# multiple @ in authority state\",\n  {\n    \"input\": \"https://@test@test@example:800/\",\n    \"base\": \"http://doesnotmatter/\",\n    \"href\": \"https://%40test%40test@example:800/\",\n    \"origin\": \"https://example:800\",\n    \"protocol\": \"https:\",\n    \"username\": \"%40test%40test\",\n    \"password\": \"\",\n    \"host\": \"example:800\",\n    \"hostname\": \"example\",\n    \"port\": \"800\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"https://@@@example\",\n    \"base\": \"http://doesnotmatter/\",\n    \"href\": \"https://%40%40@example/\",\n    \"origin\": \"https://example\",\n    \"protocol\": \"https:\",\n    \"username\": \"%40%40\",\n    \"password\": \"\",\n    \"host\": \"example\",\n    \"hostname\": \"example\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"non-az-09 characters\",\n  {\n    \"input\": \"http://`{}:`{}@h/`{}?`{}\",\n    \"base\": \"http://doesnotmatter/\",\n    \"href\": \"http://%60%7B%7D:%60%7B%7D@h/%60%7B%7D?`{}\",\n    \"origin\": \"http://h\",\n    \"protocol\": \"http:\",\n    \"username\": \"%60%7B%7D\",\n    \"password\": \"%60%7B%7D\",\n    \"host\": \"h\",\n    \"hostname\": \"h\",\n    \"port\": \"\",\n    \"pathname\": \"/%60%7B%7D\",\n    \"search\": \"?`{}\",\n    \"hash\": \"\"\n  },\n  \"byte is ' and url is special\",\n  {\n    \"input\": \"http://host/?'\",\n    \"base\": null,\n    \"href\": \"http://host/?%27\",\n    \"origin\": \"http://host\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"?%27\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"notspecial://host/?'\",\n    \"base\": null,\n    \"href\": \"notspecial://host/?'\",\n    \"origin\": \"null\",\n    \"protocol\": \"notspecial:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"?'\",\n    \"hash\": \"\"\n  },\n  \"# Credentials in base\",\n  {\n    \"input\": \"/some/path\",\n    \"base\": \"http://user@example.org/smth\",\n    \"href\": \"http://user@example.org/some/path\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"user\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/some/path\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"\",\n    \"base\": \"http://user:pass@example.org:21/smth\",\n    \"href\": \"http://user:pass@example.org:21/smth\",\n    \"origin\": \"http://example.org:21\",\n    \"protocol\": \"http:\",\n    \"username\": \"user\",\n    \"password\": \"pass\",\n    \"host\": \"example.org:21\",\n    \"hostname\": \"example.org\",\n    \"port\": \"21\",\n    \"pathname\": \"/smth\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/some/path\",\n    \"base\": \"http://user:pass@example.org:21/smth\",\n    \"href\": \"http://user:pass@example.org:21/some/path\",\n    \"origin\": \"http://example.org:21\",\n    \"protocol\": \"http:\",\n    \"username\": \"user\",\n    \"password\": \"pass\",\n    \"host\": \"example.org:21\",\n    \"hostname\": \"example.org\",\n    \"port\": \"21\",\n    \"pathname\": \"/some/path\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# a set of tests designed by zcorpan for relative URLs with unknown schemes\",\n  {\n    \"input\": \"i\",\n    \"base\": \"sc:sd\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"i\",\n    \"base\": \"sc:sd/sd\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"i\",\n    \"base\": \"sc:/pa/pa\",\n    \"href\": \"sc:/pa/i\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/pa/i\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"i\",\n    \"base\": \"sc://ho/pa\",\n    \"href\": \"sc://ho/i\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"ho\",\n    \"hostname\": \"ho\",\n    \"port\": \"\",\n    \"pathname\": \"/i\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"i\",\n    \"base\": \"sc:///pa/pa\",\n    \"href\": \"sc:///pa/i\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/pa/i\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"../i\",\n    \"base\": \"sc:sd\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"../i\",\n    \"base\": \"sc:sd/sd\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"../i\",\n    \"base\": \"sc:/pa/pa\",\n    \"href\": \"sc:/i\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/i\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"../i\",\n    \"base\": \"sc://ho/pa\",\n    \"href\": \"sc://ho/i\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"ho\",\n    \"hostname\": \"ho\",\n    \"port\": \"\",\n    \"pathname\": \"/i\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"../i\",\n    \"base\": \"sc:///pa/pa\",\n    \"href\": \"sc:///i\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/i\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/i\",\n    \"base\": \"sc:sd\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"/i\",\n    \"base\": \"sc:sd/sd\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"/i\",\n    \"base\": \"sc:/pa/pa\",\n    \"href\": \"sc:/i\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/i\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/i\",\n    \"base\": \"sc://ho/pa\",\n    \"href\": \"sc://ho/i\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"ho\",\n    \"hostname\": \"ho\",\n    \"port\": \"\",\n    \"pathname\": \"/i\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/i\",\n    \"base\": \"sc:///pa/pa\",\n    \"href\": \"sc:///i\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/i\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"?i\",\n    \"base\": \"sc:sd\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"?i\",\n    \"base\": \"sc:sd/sd\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"?i\",\n    \"base\": \"sc:/pa/pa\",\n    \"href\": \"sc:/pa/pa?i\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/pa/pa\",\n    \"search\": \"?i\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"?i\",\n    \"base\": \"sc://ho/pa\",\n    \"href\": \"sc://ho/pa?i\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"ho\",\n    \"hostname\": \"ho\",\n    \"port\": \"\",\n    \"pathname\": \"/pa\",\n    \"search\": \"?i\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"?i\",\n    \"base\": \"sc:///pa/pa\",\n    \"href\": \"sc:///pa/pa?i\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/pa/pa\",\n    \"search\": \"?i\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"#i\",\n    \"base\": \"sc:sd\",\n    \"href\": \"sc:sd#i\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"sd\",\n    \"search\": \"\",\n    \"hash\": \"#i\"\n  },\n  {\n    \"input\": \"#i\",\n    \"base\": \"sc:sd/sd\",\n    \"href\": \"sc:sd/sd#i\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"sd/sd\",\n    \"search\": \"\",\n    \"hash\": \"#i\"\n  },\n  {\n    \"input\": \"#i\",\n    \"base\": \"sc:/pa/pa\",\n    \"href\": \"sc:/pa/pa#i\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/pa/pa\",\n    \"search\": \"\",\n    \"hash\": \"#i\"\n  },\n  {\n    \"input\": \"#i\",\n    \"base\": \"sc://ho/pa\",\n    \"href\": \"sc://ho/pa#i\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"ho\",\n    \"hostname\": \"ho\",\n    \"port\": \"\",\n    \"pathname\": \"/pa\",\n    \"search\": \"\",\n    \"hash\": \"#i\"\n  },\n  {\n    \"input\": \"#i\",\n    \"base\": \"sc:///pa/pa\",\n    \"href\": \"sc:///pa/pa#i\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/pa/pa\",\n    \"search\": \"\",\n    \"hash\": \"#i\"\n  },\n  \"# make sure that relative URL logic works on known typically non-relative schemes too\",\n  {\n    \"input\": \"about:/../\",\n    \"base\": null,\n    \"href\": \"about:/\",\n    \"origin\": \"null\",\n    \"protocol\": \"about:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"data:/../\",\n    \"base\": null,\n    \"href\": \"data:/\",\n    \"origin\": \"null\",\n    \"protocol\": \"data:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"javascript:/../\",\n    \"base\": null,\n    \"href\": \"javascript:/\",\n    \"origin\": \"null\",\n    \"protocol\": \"javascript:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"mailto:/../\",\n    \"base\": null,\n    \"href\": \"mailto:/\",\n    \"origin\": \"null\",\n    \"protocol\": \"mailto:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# unknown schemes and their hosts\",\n  {\n    \"input\": \"sc://ñ.test/\",\n    \"base\": null,\n    \"href\": \"sc://%C3%B1.test/\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"%C3%B1.test\",\n    \"hostname\": \"%C3%B1.test\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"sc://%/\",\n    \"base\": null,\n    \"href\": \"sc://%/\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"%\",\n    \"hostname\": \"%\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"sc://@/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"sc://te@s:t@/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"sc://:/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"sc://:12/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"x\",\n    \"base\": \"sc://ñ\",\n    \"href\": \"sc://%C3%B1/x\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"%C3%B1\",\n    \"hostname\": \"%C3%B1\",\n    \"port\": \"\",\n    \"pathname\": \"/x\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# unknown schemes and backslashes\",\n  {\n    \"input\": \"sc:\\\\../\",\n    \"base\": null,\n    \"href\": \"sc:\\\\../\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"\\\\../\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# unknown scheme with path looking like a password\",\n  {\n    \"input\": \"sc::a@example.net\",\n    \"base\": null,\n    \"href\": \"sc::a@example.net\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \":a@example.net\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# unknown scheme with bogus percent-encoding\",\n  {\n    \"input\": \"wow:%NBD\",\n    \"base\": null,\n    \"href\": \"wow:%NBD\",\n    \"origin\": \"null\",\n    \"protocol\": \"wow:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"%NBD\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"wow:%1G\",\n    \"base\": null,\n    \"href\": \"wow:%1G\",\n    \"origin\": \"null\",\n    \"protocol\": \"wow:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"%1G\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# unknown scheme with non-URL characters\",\n  {\n    \"input\": \"wow:\\uFFFF\",\n    \"base\": null,\n    \"href\": \"wow:%EF%BF%BF\",\n    \"origin\": \"null\",\n    \"protocol\": \"wow:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"%EF%BF%BF\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"Forbidden host code points\",\n  {\n    \"input\": \"sc://a\\u0000b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"sc://a b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"sc://a<b\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"sc://a>b\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"sc://a[b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"sc://a\\\\b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"sc://a]b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"sc://a^b\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"sc://a|b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  \"Forbidden host codepoints: tabs and newlines are removed during preprocessing\",\n  {\n    \"input\": \"foo://ho\\u0009st/\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"href\": \"foo://host/\",\n    \"password\": \"\",\n    \"pathname\": \"/\",\n    \"port\": \"\",\n    \"protocol\": \"foo:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"foo://ho\\u000Ast/\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"href\": \"foo://host/\",\n    \"password\": \"\",\n    \"pathname\": \"/\",\n    \"port\": \"\",\n    \"protocol\": \"foo:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"foo://ho\\u000Dst/\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"href\": \"foo://host/\",\n    \"password\": \"\",\n    \"pathname\": \"/\",\n    \"port\": \"\",\n    \"protocol\": \"foo:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  \"Forbidden domain code-points\",\n  {\n    \"input\": \"http://a\\u0000b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u0001b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u0002b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u0003b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u0004b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u0005b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u0006b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u0007b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u0008b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u000Bb/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u000Cb/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u000Eb/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u000Fb/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u0010b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u0011b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u0012b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u0013b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u0014b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u0015b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u0016b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u0017b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u0018b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u0019b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u001Ab/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u001Bb/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u001Cb/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u001Db/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u001Eb/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u001Fb/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a%b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a<b\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a>b\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a[b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a]b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a^b\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a|b/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://a\\u007Fb/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  \"Forbidden domain codepoints: tabs and newlines are removed during preprocessing\",\n  {\n    \"input\": \"http://ho\\u0009st/\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"href\": \"http://host/\",\n    \"password\": \"\",\n    \"pathname\": \"/\",\n    \"port\": \"\",\n    \"protocol\": \"http:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"http://ho\\u000Ast/\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"href\": \"http://host/\",\n    \"password\": \"\",\n    \"pathname\": \"/\",\n    \"port\": \"\",\n    \"protocol\": \"http:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"http://ho\\u000Dst/\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"href\": \"http://host/\",\n    \"password\": \"\",\n    \"pathname\": \"/\",\n    \"port\": \"\",\n    \"protocol\": \"http:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  \"Encoded forbidden domain codepoints in special URLs\",\n  {\n    \"input\": \"http://ho%00st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%01st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%02st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%03st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%04st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%05st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%06st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%07st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%08st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%09st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%0Ast/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%0Bst/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%0Cst/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%0Dst/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%0Est/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%0Fst/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%10st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%11st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%12st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%13st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%14st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%15st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%16st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%17st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%18st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%19st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%1Ast/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%1Bst/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%1Cst/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%1Dst/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%1Est/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%1Fst/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%20st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%23st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%25st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%2Fst/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%3Ast/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%3Cst/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%3Est/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%3Fst/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%40st/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%5Bst/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%5Cst/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%5Dst/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%7Cst/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://ho%7Fst/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  \"Allowed host/domain code points\",\n  {\n    \"input\": \"http://!\\\"$&'()*+,-.;=_`{}~/\",\n    \"base\": null,\n    \"href\": \"http://!\\\"$&'()*+,-.;=_`{}~/\",\n    \"origin\": \"http://!\\\"$&'()*+,-.;=_`{}~\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"!\\\"$&'()*+,-.;=_`{}~\",\n    \"hostname\": \"!\\\"$&'()*+,-.;=_`{}~\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"sc://\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\u0008\\u000B\\u000C\\u000E\\u000F\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F\\u007F!\\\"$%&'()*+,-.;=_`{}~/\",\n    \"base\": null,\n    \"href\": \"sc://%01%02%03%04%05%06%07%08%0B%0C%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%7F!\\\"$%&'()*+,-.;=_`{}~/\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"%01%02%03%04%05%06%07%08%0B%0C%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%7F!\\\"$%&'()*+,-.;=_`{}~\",\n    \"hostname\": \"%01%02%03%04%05%06%07%08%0B%0C%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%7F!\\\"$%&'()*+,-.;=_`{}~\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# Hosts and percent-encoding\",\n  {\n    \"input\": \"ftp://example.com%80/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"ftp://example.com%A0/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"https://example.com%80/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"https://example.com%A0/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"ftp://%e2%98%83\",\n    \"base\": null,\n    \"href\": \"ftp://xn--n3h/\",\n    \"origin\": \"ftp://xn--n3h\",\n    \"protocol\": \"ftp:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"xn--n3h\",\n    \"hostname\": \"xn--n3h\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"https://%e2%98%83\",\n    \"base\": null,\n    \"href\": \"https://xn--n3h/\",\n    \"origin\": \"https://xn--n3h\",\n    \"protocol\": \"https:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"xn--n3h\",\n    \"hostname\": \"xn--n3h\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# tests from jsdom/whatwg-url designed for code coverage\",\n  {\n    \"input\": \"http://127.0.0.1:10100/relative_import.html\",\n    \"base\": null,\n    \"href\": \"http://127.0.0.1:10100/relative_import.html\",\n    \"origin\": \"http://127.0.0.1:10100\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"127.0.0.1:10100\",\n    \"hostname\": \"127.0.0.1\",\n    \"port\": \"10100\",\n    \"pathname\": \"/relative_import.html\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://facebook.com/?foo=%7B%22abc%22\",\n    \"base\": null,\n    \"href\": \"http://facebook.com/?foo=%7B%22abc%22\",\n    \"origin\": \"http://facebook.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"facebook.com\",\n    \"hostname\": \"facebook.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"?foo=%7B%22abc%22\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"https://localhost:3000/jqueryui@1.2.3\",\n    \"base\": null,\n    \"href\": \"https://localhost:3000/jqueryui@1.2.3\",\n    \"origin\": \"https://localhost:3000\",\n    \"protocol\": \"https:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"localhost:3000\",\n    \"hostname\": \"localhost\",\n    \"port\": \"3000\",\n    \"pathname\": \"/jqueryui@1.2.3\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# tab/LF/CR\",\n  {\n    \"input\": \"h\\tt\\nt\\rp://h\\to\\ns\\rt:9\\t0\\n0\\r0/p\\ta\\nt\\rh?q\\tu\\ne\\rry#f\\tr\\na\\rg\",\n    \"base\": null,\n    \"href\": \"http://host:9000/path?query#frag\",\n    \"origin\": \"http://host:9000\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"host:9000\",\n    \"hostname\": \"host\",\n    \"port\": \"9000\",\n    \"pathname\": \"/path\",\n    \"search\": \"?query\",\n    \"hash\": \"#frag\"\n  },\n  \"# Stringification of URL.searchParams\",\n  {\n    \"input\": \"?a=b&c=d\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/bar?a=b&c=d\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/bar\",\n    \"search\": \"?a=b&c=d\",\n    \"searchParams\": \"a=b&c=d\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"??a=b&c=d\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/bar??a=b&c=d\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/bar\",\n    \"search\": \"??a=b&c=d\",\n    \"searchParams\": \"%3Fa=b&c=d\",\n    \"hash\": \"\"\n  },\n  \"# Scheme only\",\n  {\n    \"input\": \"http:\",\n    \"base\": \"http://example.org/foo/bar\",\n    \"href\": \"http://example.org/foo/bar\",\n    \"origin\": \"http://example.org\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/bar\",\n    \"search\": \"\",\n    \"searchParams\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http:\",\n    \"base\": \"https://example.org/foo/bar\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"sc:\",\n    \"base\": \"https://example.org/foo/bar\",\n    \"href\": \"sc:\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"\",\n    \"search\": \"\",\n    \"searchParams\": \"\",\n    \"hash\": \"\"\n  },\n  \"# Percent encoding of fragments\",\n  {\n    \"input\": \"http://foo.bar/baz?qux#foo\\bbar\",\n    \"base\": null,\n    \"href\": \"http://foo.bar/baz?qux#foo%08bar\",\n    \"origin\": \"http://foo.bar\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo.bar\",\n    \"hostname\": \"foo.bar\",\n    \"port\": \"\",\n    \"pathname\": \"/baz\",\n    \"search\": \"?qux\",\n    \"searchParams\": \"qux=\",\n    \"hash\": \"#foo%08bar\"\n  },\n  {\n    \"input\": \"http://foo.bar/baz?qux#foo\\\"bar\",\n    \"base\": null,\n    \"href\": \"http://foo.bar/baz?qux#foo%22bar\",\n    \"origin\": \"http://foo.bar\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo.bar\",\n    \"hostname\": \"foo.bar\",\n    \"port\": \"\",\n    \"pathname\": \"/baz\",\n    \"search\": \"?qux\",\n    \"searchParams\": \"qux=\",\n    \"hash\": \"#foo%22bar\"\n  },\n  {\n    \"input\": \"http://foo.bar/baz?qux#foo<bar\",\n    \"base\": null,\n    \"href\": \"http://foo.bar/baz?qux#foo%3Cbar\",\n    \"origin\": \"http://foo.bar\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo.bar\",\n    \"hostname\": \"foo.bar\",\n    \"port\": \"\",\n    \"pathname\": \"/baz\",\n    \"search\": \"?qux\",\n    \"searchParams\": \"qux=\",\n    \"hash\": \"#foo%3Cbar\"\n  },\n  {\n    \"input\": \"http://foo.bar/baz?qux#foo>bar\",\n    \"base\": null,\n    \"href\": \"http://foo.bar/baz?qux#foo%3Ebar\",\n    \"origin\": \"http://foo.bar\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo.bar\",\n    \"hostname\": \"foo.bar\",\n    \"port\": \"\",\n    \"pathname\": \"/baz\",\n    \"search\": \"?qux\",\n    \"searchParams\": \"qux=\",\n    \"hash\": \"#foo%3Ebar\"\n  },\n  {\n    \"input\": \"http://foo.bar/baz?qux#foo`bar\",\n    \"base\": null,\n    \"href\": \"http://foo.bar/baz?qux#foo%60bar\",\n    \"origin\": \"http://foo.bar\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foo.bar\",\n    \"hostname\": \"foo.bar\",\n    \"port\": \"\",\n    \"pathname\": \"/baz\",\n    \"search\": \"?qux\",\n    \"searchParams\": \"qux=\",\n    \"hash\": \"#foo%60bar\"\n  },\n  \"# IPv4 parsing (via https://github.com/nodejs/node/pull/10317)\",\n  {\n    \"input\": \"http://1.2.3.4/\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://1.2.3.4/\",\n    \"origin\": \"http://1.2.3.4\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"1.2.3.4\",\n    \"hostname\": \"1.2.3.4\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://1.2.3.4./\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://1.2.3.4/\",\n    \"origin\": \"http://1.2.3.4\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"1.2.3.4\",\n    \"hostname\": \"1.2.3.4\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://192.168.257\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://192.168.1.1/\",\n    \"origin\": \"http://192.168.1.1\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"192.168.1.1\",\n    \"hostname\": \"192.168.1.1\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://192.168.257.\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://192.168.1.1/\",\n    \"origin\": \"http://192.168.1.1\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"192.168.1.1\",\n    \"hostname\": \"192.168.1.1\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://192.168.257.com\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://192.168.257.com/\",\n    \"origin\": \"http://192.168.257.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"192.168.257.com\",\n    \"hostname\": \"192.168.257.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://256\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://0.0.1.0/\",\n    \"origin\": \"http://0.0.1.0\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"0.0.1.0\",\n    \"hostname\": \"0.0.1.0\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://256.com\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://256.com/\",\n    \"origin\": \"http://256.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"256.com\",\n    \"hostname\": \"256.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://999999999\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://59.154.201.255/\",\n    \"origin\": \"http://59.154.201.255\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"59.154.201.255\",\n    \"hostname\": \"59.154.201.255\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://999999999.\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://59.154.201.255/\",\n    \"origin\": \"http://59.154.201.255\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"59.154.201.255\",\n    \"hostname\": \"59.154.201.255\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://999999999.com\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://999999999.com/\",\n    \"origin\": \"http://999999999.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"999999999.com\",\n    \"hostname\": \"999999999.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://10000000000\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://10000000000.com\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://10000000000.com/\",\n    \"origin\": \"http://10000000000.com\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"10000000000.com\",\n    \"hostname\": \"10000000000.com\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://4294967295\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://255.255.255.255/\",\n    \"origin\": \"http://255.255.255.255\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"255.255.255.255\",\n    \"hostname\": \"255.255.255.255\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://4294967296\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://0xffffffff\",\n    \"base\": \"http://other.com/\",\n    \"href\": \"http://255.255.255.255/\",\n    \"origin\": \"http://255.255.255.255\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"255.255.255.255\",\n    \"hostname\": \"255.255.255.255\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://0xffffffff1\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://256.256.256.256\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"https://0x.0x.0\",\n    \"base\": null,\n    \"href\": \"https://0.0.0.0/\",\n    \"origin\": \"https://0.0.0.0\",\n    \"protocol\": \"https:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"0.0.0.0\",\n    \"hostname\": \"0.0.0.0\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"More IPv4 parsing (via https://github.com/jsdom/whatwg-url/issues/92)\",\n  {\n    \"input\": \"https://0x100000000/test\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"https://256.0.0.1/test\",\n    \"base\": null,\n    \"failure\": true\n  },\n  \"# file URLs containing percent-encoded Windows drive letters (shouldn't work)\",\n  {\n    \"input\": \"file:///C%3A/\",\n    \"base\": null,\n    \"href\": \"file:///C%3A/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/C%3A/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:///C%7C/\",\n    \"base\": null,\n    \"href\": \"file:///C%7C/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/C%7C/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file://%43%3A\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"file://%43%7C\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"file://%43|\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"file://C%7C\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"file://%43%7C/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"https://%43%7C/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"asdf://%43|/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"asdf://%43%7C/\",\n    \"base\": null,\n    \"href\": \"asdf://%43%7C/\",\n    \"origin\": \"null\",\n    \"protocol\": \"asdf:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"%43%7C\",\n    \"hostname\": \"%43%7C\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# file URLs relative to other file URLs (via https://github.com/jsdom/whatwg-url/pull/60)\",\n  {\n    \"input\": \"pix/submit.gif\",\n    \"base\": \"file:///C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/anchor.html\",\n    \"href\": \"file:///C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"..\",\n    \"base\": \"file:///C:/\",\n    \"href\": \"file:///C:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"..\",\n    \"base\": \"file:///\",\n    \"href\": \"file:///\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# More file URL tests by zcorpan and annevk\",\n  {\n    \"input\": \"/\",\n    \"base\": \"file:///C:/a/b\",\n    \"href\": \"file:///C:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/\",\n    \"base\": \"file://h/C:/a/b\",\n    \"href\": \"file://h/C:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"h\",\n    \"hostname\": \"h\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/\",\n    \"base\": \"file://h/a/b\",\n    \"href\": \"file://h/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"h\",\n    \"hostname\": \"h\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"//d:\",\n    \"base\": \"file:///C:/a/b\",\n    \"href\": \"file:///d:\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/d:\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"//d:/..\",\n    \"base\": \"file:///C:/a/b\",\n    \"href\": \"file:///d:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/d:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"..\",\n    \"base\": \"file:///ab:/\",\n    \"href\": \"file:///\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"..\",\n    \"base\": \"file:///1:/\",\n    \"href\": \"file:///\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"\",\n    \"base\": \"file:///test?test#test\",\n    \"href\": \"file:///test?test\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"?test\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:\",\n    \"base\": \"file:///test?test#test\",\n    \"href\": \"file:///test?test\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"?test\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"?x\",\n    \"base\": \"file:///test?test#test\",\n    \"href\": \"file:///test?x\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"?x\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:?x\",\n    \"base\": \"file:///test?test#test\",\n    \"href\": \"file:///test?x\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"?x\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"#x\",\n    \"base\": \"file:///test?test#test\",\n    \"href\": \"file:///test?test#x\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"?test\",\n    \"hash\": \"#x\"\n  },\n  {\n    \"input\": \"file:#x\",\n    \"base\": \"file:///test?test#test\",\n    \"href\": \"file:///test?test#x\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"?test\",\n    \"hash\": \"#x\"\n  },\n  \"# File URLs and many (back)slashes\",\n  {\n    \"input\": \"file:\\\\\\\\//\",\n    \"base\": null,\n    \"href\": \"file:////\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:\\\\\\\\\\\\\\\\\",\n    \"base\": null,\n    \"href\": \"file:////\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:\\\\\\\\\\\\\\\\?fox\",\n    \"base\": null,\n    \"href\": \"file:////?fox\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//\",\n    \"search\": \"?fox\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:\\\\\\\\\\\\\\\\#guppy\",\n    \"base\": null,\n    \"href\": \"file:////#guppy\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//\",\n    \"search\": \"\",\n    \"hash\": \"#guppy\"\n  },\n  {\n    \"input\": \"file://spider///\",\n    \"base\": null,\n    \"href\": \"file://spider///\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"spider\",\n    \"hostname\": \"spider\",\n    \"port\": \"\",\n    \"pathname\": \"///\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:\\\\\\\\localhost//\",\n    \"base\": null,\n    \"href\": \"file:////\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:///localhost//cat\",\n    \"base\": null,\n    \"href\": \"file:///localhost//cat\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/localhost//cat\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file://\\\\/localhost//cat\",\n    \"base\": null,\n    \"href\": \"file:////localhost//cat\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//localhost//cat\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file://localhost//a//../..//\",\n    \"base\": null,\n    \"href\": \"file://///\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"///\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/////mouse\",\n    \"base\": \"file:///elephant\",\n    \"href\": \"file://///mouse\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"///mouse\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"\\\\//pig\",\n    \"base\": \"file://lion/\",\n    \"href\": \"file:///pig\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/pig\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"\\\\/localhost//pig\",\n    \"base\": \"file://lion/\",\n    \"href\": \"file:////pig\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//pig\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"//localhost//pig\",\n    \"base\": \"file://lion/\",\n    \"href\": \"file:////pig\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//pig\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/..//localhost//pig\",\n    \"base\": \"file://lion/\",\n    \"href\": \"file://lion//localhost//pig\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"lion\",\n    \"hostname\": \"lion\",\n    \"port\": \"\",\n    \"pathname\": \"//localhost//pig\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file://\",\n    \"base\": \"file://ape/\",\n    \"href\": \"file:///\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# File URLs with non-empty hosts\",\n  {\n    \"input\": \"/rooibos\",\n    \"base\": \"file://tea/\",\n    \"href\": \"file://tea/rooibos\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"tea\",\n    \"hostname\": \"tea\",\n    \"port\": \"\",\n    \"pathname\": \"/rooibos\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/?chai\",\n    \"base\": \"file://tea/\",\n    \"href\": \"file://tea/?chai\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"tea\",\n    \"hostname\": \"tea\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"?chai\",\n    \"hash\": \"\"\n  },\n  \"# Windows drive letter handling with the 'file:' base URL\",\n  {\n    \"input\": \"C|\",\n    \"base\": \"file://host/dir/file\",\n    \"href\": \"file://host/C:\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"port\": \"\",\n    \"pathname\": \"/C:\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"C|\",\n    \"base\": \"file://host/D:/dir1/dir2/file\",\n    \"href\": \"file://host/C:\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"port\": \"\",\n    \"pathname\": \"/C:\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"C|#\",\n    \"base\": \"file://host/dir/file\",\n    \"href\": \"file://host/C:#\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"port\": \"\",\n    \"pathname\": \"/C:\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"C|?\",\n    \"base\": \"file://host/dir/file\",\n    \"href\": \"file://host/C:?\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"port\": \"\",\n    \"pathname\": \"/C:\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"C|/\",\n    \"base\": \"file://host/dir/file\",\n    \"href\": \"file://host/C:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"C|\\n/\",\n    \"base\": \"file://host/dir/file\",\n    \"href\": \"file://host/C:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"C|\\\\\",\n    \"base\": \"file://host/dir/file\",\n    \"href\": \"file://host/C:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"C\",\n    \"base\": \"file://host/dir/file\",\n    \"href\": \"file://host/dir/C\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"port\": \"\",\n    \"pathname\": \"/dir/C\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"C|a\",\n    \"base\": \"file://host/dir/file\",\n    \"href\": \"file://host/dir/C|a\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"port\": \"\",\n    \"pathname\": \"/dir/C|a\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# Windows drive letter quirk in the file slash state\",\n  {\n    \"input\": \"/c:/foo/bar\",\n    \"base\": \"file:///c:/baz/qux\",\n    \"href\": \"file:///c:/foo/bar\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/c:/foo/bar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/c|/foo/bar\",\n    \"base\": \"file:///c:/baz/qux\",\n    \"href\": \"file:///c:/foo/bar\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/c:/foo/bar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:\\\\c:\\\\foo\\\\bar\",\n    \"base\": \"file:///c:/baz/qux\",\n    \"href\": \"file:///c:/foo/bar\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/c:/foo/bar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/c:/foo/bar\",\n    \"base\": \"file://host/path\",\n    \"href\": \"file://host/c:/foo/bar\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"port\": \"\",\n    \"pathname\": \"/c:/foo/bar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# Do not drop the host in the presence of a drive letter\",\n  {\n    \"input\": \"file://example.net/C:/\",\n    \"base\": null,\n    \"href\": \"file://example.net/C:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.net\",\n    \"hostname\": \"example.net\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file://1.2.3.4/C:/\",\n    \"base\": null,\n    \"href\": \"file://1.2.3.4/C:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"1.2.3.4\",\n    \"hostname\": \"1.2.3.4\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file://[1::8]/C:/\",\n    \"base\": null,\n    \"href\": \"file://[1::8]/C:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"[1::8]\",\n    \"hostname\": \"[1::8]\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# Copy the host from the base URL in the following cases\",\n  {\n    \"input\": \"C|/\",\n    \"base\": \"file://host/\",\n    \"href\": \"file://host/C:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/C:/\",\n    \"base\": \"file://host/\",\n    \"href\": \"file://host/C:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:C:/\",\n    \"base\": \"file://host/\",\n    \"href\": \"file://host/C:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:/C:/\",\n    \"base\": \"file://host/\",\n    \"href\": \"file://host/C:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# Copy the empty host from the input in the following cases\",\n  {\n    \"input\": \"//C:/\",\n    \"base\": \"file://host/\",\n    \"href\": \"file:///C:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file://C:/\",\n    \"base\": \"file://host/\",\n    \"href\": \"file:///C:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"///C:/\",\n    \"base\": \"file://host/\",\n    \"href\": \"file:///C:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:///C:/\",\n    \"base\": \"file://host/\",\n    \"href\": \"file:///C:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# Windows drive letter quirk (no host)\",\n  {\n    \"input\": \"file:/C|/\",\n    \"base\": null,\n    \"href\": \"file:///C:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file://C|/\",\n    \"base\": null,\n    \"href\": \"file:///C:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/C:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# file URLs without base URL by Rimas Misevičius\",\n  {\n    \"input\": \"file:\",\n    \"base\": null,\n    \"href\": \"file:///\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:?q=v\",\n    \"base\": null,\n    \"href\": \"file:///?q=v\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"?q=v\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:#frag\",\n    \"base\": null,\n    \"href\": \"file:///#frag\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"#frag\"\n  },\n  \"# file: drive letter cases from https://crbug.com/1078698\",\n  {\n    \"input\": \"file:///Y:\",\n    \"base\": null,\n    \"href\": \"file:///Y:\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/Y:\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:///Y:/\",\n    \"base\": null,\n    \"href\": \"file:///Y:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/Y:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:///./Y\",\n    \"base\": null,\n    \"href\": \"file:///Y\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/Y\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:///./Y:\",\n    \"base\": null,\n    \"href\": \"file:///Y:\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/Y:\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"\\\\\\\\\\\\.\\\\Y:\",\n    \"base\": null,\n    \"failure\": true,\n    \"relativeTo\": \"non-opaque-path-base\"\n  },\n  \"# file: drive letter cases from https://crbug.com/1078698 but lowercased\",\n  {\n    \"input\": \"file:///y:\",\n    \"base\": null,\n    \"href\": \"file:///y:\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/y:\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:///y:/\",\n    \"base\": null,\n    \"href\": \"file:///y:/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/y:/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:///./y\",\n    \"base\": null,\n    \"href\": \"file:///y\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/y\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:///./y:\",\n    \"base\": null,\n    \"href\": \"file:///y:\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/y:\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"\\\\\\\\\\\\.\\\\y:\",\n    \"base\": null,\n    \"failure\": true,\n    \"relativeTo\": \"non-opaque-path-base\"\n  },\n  \"# Additional file URL tests for (https://github.com/whatwg/url/issues/405)\",\n  {\n    \"input\": \"file://localhost//a//../..//foo\",\n    \"base\": null,\n    \"href\": \"file://///foo\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"///foo\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file://localhost////foo\",\n    \"base\": null,\n    \"href\": \"file://////foo\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"////foo\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:////foo\",\n    \"base\": null,\n    \"href\": \"file:////foo\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//foo\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:///one/two\",\n    \"base\": \"file:///\",\n    \"href\": \"file:///one/two\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/one/two\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:////one/two\",\n    \"base\": \"file:///\",\n    \"href\": \"file:////one/two\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//one/two\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"//one/two\",\n    \"base\": \"file:///\",\n    \"href\": \"file://one/two\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"one\",\n    \"hostname\": \"one\",\n    \"port\": \"\",\n    \"pathname\": \"/two\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"///one/two\",\n    \"base\": \"file:///\",\n    \"href\": \"file:///one/two\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/one/two\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"////one/two\",\n    \"base\": \"file:///\",\n    \"href\": \"file:////one/two\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//one/two\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:///.//\",\n    \"base\": \"file:////\",\n    \"href\": \"file:////\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"File URL tests for https://github.com/whatwg/url/issues/549\",\n  {\n    \"input\": \"file:.//p\",\n    \"base\": null,\n    \"href\": \"file:////p\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//p\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file:/.//p\",\n    \"base\": null,\n    \"href\": \"file:////p\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//p\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# IPv6 tests\",\n  {\n    \"input\": \"http://[1:0::]\",\n    \"base\": \"http://example.net/\",\n    \"href\": \"http://[1::]/\",\n    \"origin\": \"http://[1::]\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"[1::]\",\n    \"hostname\": \"[1::]\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://[0:1:2:3:4:5:6:7:8]\",\n    \"base\": \"http://example.net/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"https://[0::0::0]\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"https://[0:.0]\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"https://[0:0:]\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"https://[0:1:2:3:4:5:6:7.0.0.0.1]\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"https://[0:1.00.0.0.0]\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"https://[0:1.290.0.0.0]\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"https://[0:1.23.23]\",\n    \"base\": null,\n    \"failure\": true\n  },\n  \"# Empty host\",\n  {\n    \"input\": \"http://?\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://#\",\n    \"base\": null,\n    \"failure\": true\n  },\n  \"Port overflow (2^32 + 81)\",\n  {\n    \"input\": \"http://f:4294967377/c\",\n    \"base\": \"http://example.org/\",\n    \"failure\": true\n  },\n  \"Port overflow (2^64 + 81)\",\n  {\n    \"input\": \"http://f:18446744073709551697/c\",\n    \"base\": \"http://example.org/\",\n    \"failure\": true\n  },\n  \"Port overflow (2^128 + 81)\",\n  {\n    \"input\": \"http://f:340282366920938463463374607431768211537/c\",\n    \"base\": \"http://example.org/\",\n    \"failure\": true\n  },\n  \"# Non-special-URL path tests\",\n  {\n    \"input\": \"sc://ñ\",\n    \"base\": null,\n    \"href\": \"sc://%C3%B1\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"%C3%B1\",\n    \"hostname\": \"%C3%B1\",\n    \"port\": \"\",\n    \"pathname\": \"\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"sc://ñ?x\",\n    \"base\": null,\n    \"href\": \"sc://%C3%B1?x\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"%C3%B1\",\n    \"hostname\": \"%C3%B1\",\n    \"port\": \"\",\n    \"pathname\": \"\",\n    \"search\": \"?x\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"sc://ñ#x\",\n    \"base\": null,\n    \"href\": \"sc://%C3%B1#x\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"%C3%B1\",\n    \"hostname\": \"%C3%B1\",\n    \"port\": \"\",\n    \"pathname\": \"\",\n    \"search\": \"\",\n    \"hash\": \"#x\"\n  },\n  {\n    \"input\": \"#x\",\n    \"base\": \"sc://ñ\",\n    \"href\": \"sc://%C3%B1#x\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"%C3%B1\",\n    \"hostname\": \"%C3%B1\",\n    \"port\": \"\",\n    \"pathname\": \"\",\n    \"search\": \"\",\n    \"hash\": \"#x\"\n  },\n  {\n    \"input\": \"?x\",\n    \"base\": \"sc://ñ\",\n    \"href\": \"sc://%C3%B1?x\",\n    \"origin\": \"null\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"%C3%B1\",\n    \"hostname\": \"%C3%B1\",\n    \"port\": \"\",\n    \"pathname\": \"\",\n    \"search\": \"?x\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"sc://?\",\n    \"base\": null,\n    \"href\": \"sc://?\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"sc://#\",\n    \"base\": null,\n    \"href\": \"sc://#\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"///\",\n    \"base\": \"sc://x/\",\n    \"href\": \"sc:///\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"////\",\n    \"base\": \"sc://x/\",\n    \"href\": \"sc:////\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"////x/\",\n    \"base\": \"sc://x/\",\n    \"href\": \"sc:////x/\",\n    \"protocol\": \"sc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//x/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"tftp://foobar.com/someconfig;mode=netascii\",\n    \"base\": null,\n    \"href\": \"tftp://foobar.com/someconfig;mode=netascii\",\n    \"origin\": \"null\",\n    \"protocol\": \"tftp:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"foobar.com\",\n    \"hostname\": \"foobar.com\",\n    \"port\": \"\",\n    \"pathname\": \"/someconfig;mode=netascii\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"telnet://user:pass@foobar.com:23/\",\n    \"base\": null,\n    \"href\": \"telnet://user:pass@foobar.com:23/\",\n    \"origin\": \"null\",\n    \"protocol\": \"telnet:\",\n    \"username\": \"user\",\n    \"password\": \"pass\",\n    \"host\": \"foobar.com:23\",\n    \"hostname\": \"foobar.com\",\n    \"port\": \"23\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"ut2004://10.10.10.10:7777/Index.ut2\",\n    \"base\": null,\n    \"href\": \"ut2004://10.10.10.10:7777/Index.ut2\",\n    \"origin\": \"null\",\n    \"protocol\": \"ut2004:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"10.10.10.10:7777\",\n    \"hostname\": \"10.10.10.10\",\n    \"port\": \"7777\",\n    \"pathname\": \"/Index.ut2\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"redis://foo:bar@somehost:6379/0?baz=bam&qux=baz\",\n    \"base\": null,\n    \"href\": \"redis://foo:bar@somehost:6379/0?baz=bam&qux=baz\",\n    \"origin\": \"null\",\n    \"protocol\": \"redis:\",\n    \"username\": \"foo\",\n    \"password\": \"bar\",\n    \"host\": \"somehost:6379\",\n    \"hostname\": \"somehost\",\n    \"port\": \"6379\",\n    \"pathname\": \"/0\",\n    \"search\": \"?baz=bam&qux=baz\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"rsync://foo@host:911/sup\",\n    \"base\": null,\n    \"href\": \"rsync://foo@host:911/sup\",\n    \"origin\": \"null\",\n    \"protocol\": \"rsync:\",\n    \"username\": \"foo\",\n    \"password\": \"\",\n    \"host\": \"host:911\",\n    \"hostname\": \"host\",\n    \"port\": \"911\",\n    \"pathname\": \"/sup\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"git://github.com/foo/bar.git\",\n    \"base\": null,\n    \"href\": \"git://github.com/foo/bar.git\",\n    \"origin\": \"null\",\n    \"protocol\": \"git:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"github.com\",\n    \"hostname\": \"github.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/bar.git\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"irc://myserver.com:6999/channel?passwd\",\n    \"base\": null,\n    \"href\": \"irc://myserver.com:6999/channel?passwd\",\n    \"origin\": \"null\",\n    \"protocol\": \"irc:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"myserver.com:6999\",\n    \"hostname\": \"myserver.com\",\n    \"port\": \"6999\",\n    \"pathname\": \"/channel\",\n    \"search\": \"?passwd\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"dns://fw.example.org:9999/foo.bar.org?type=TXT\",\n    \"base\": null,\n    \"href\": \"dns://fw.example.org:9999/foo.bar.org?type=TXT\",\n    \"origin\": \"null\",\n    \"protocol\": \"dns:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"fw.example.org:9999\",\n    \"hostname\": \"fw.example.org\",\n    \"port\": \"9999\",\n    \"pathname\": \"/foo.bar.org\",\n    \"search\": \"?type=TXT\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"ldap://localhost:389/ou=People,o=JNDITutorial\",\n    \"base\": null,\n    \"href\": \"ldap://localhost:389/ou=People,o=JNDITutorial\",\n    \"origin\": \"null\",\n    \"protocol\": \"ldap:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"localhost:389\",\n    \"hostname\": \"localhost\",\n    \"port\": \"389\",\n    \"pathname\": \"/ou=People,o=JNDITutorial\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"git+https://github.com/foo/bar\",\n    \"base\": null,\n    \"href\": \"git+https://github.com/foo/bar\",\n    \"origin\": \"null\",\n    \"protocol\": \"git+https:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"github.com\",\n    \"hostname\": \"github.com\",\n    \"port\": \"\",\n    \"pathname\": \"/foo/bar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"urn:ietf:rfc:2648\",\n    \"base\": null,\n    \"href\": \"urn:ietf:rfc:2648\",\n    \"origin\": \"null\",\n    \"protocol\": \"urn:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"ietf:rfc:2648\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"tag:joe@example.org,2001:foo/bar\",\n    \"base\": null,\n    \"href\": \"tag:joe@example.org,2001:foo/bar\",\n    \"origin\": \"null\",\n    \"protocol\": \"tag:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"joe@example.org,2001:foo/bar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"Serialize /. in path\",\n  {\n    \"input\": \"non-spec:/.//\",\n    \"base\": null,\n    \"href\": \"non-spec:/.//\",\n    \"protocol\": \"non-spec:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"non-spec:/..//\",\n    \"base\": null,\n    \"href\": \"non-spec:/.//\",\n    \"protocol\": \"non-spec:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"non-spec:/a/..//\",\n    \"base\": null,\n    \"href\": \"non-spec:/.//\",\n    \"protocol\": \"non-spec:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"non-spec:/.//path\",\n    \"base\": null,\n    \"href\": \"non-spec:/.//path\",\n    \"protocol\": \"non-spec:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//path\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"non-spec:/..//path\",\n    \"base\": null,\n    \"href\": \"non-spec:/.//path\",\n    \"protocol\": \"non-spec:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//path\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"non-spec:/a/..//path\",\n    \"base\": null,\n    \"href\": \"non-spec:/.//path\",\n    \"protocol\": \"non-spec:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//path\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/.//path\",\n    \"base\": \"non-spec:/p\",\n    \"href\": \"non-spec:/.//path\",\n    \"protocol\": \"non-spec:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//path\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/..//path\",\n    \"base\": \"non-spec:/p\",\n    \"href\": \"non-spec:/.//path\",\n    \"protocol\": \"non-spec:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//path\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"..//path\",\n    \"base\": \"non-spec:/p\",\n    \"href\": \"non-spec:/.//path\",\n    \"protocol\": \"non-spec:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//path\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"a/..//path\",\n    \"base\": \"non-spec:/p\",\n    \"href\": \"non-spec:/.//path\",\n    \"protocol\": \"non-spec:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//path\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"\",\n    \"base\": \"non-spec:/..//p\",\n    \"href\": \"non-spec:/.//p\",\n    \"protocol\": \"non-spec:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//p\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"path\",\n    \"base\": \"non-spec:/..//p\",\n    \"href\": \"non-spec:/.//path\",\n    \"protocol\": \"non-spec:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"//path\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"Do not serialize /. in path\",\n  {\n    \"input\": \"../path\",\n    \"base\": \"non-spec:/.//p\",\n    \"href\": \"non-spec:/path\",\n    \"protocol\": \"non-spec:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/path\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# percent encoded hosts in non-special-URLs\",\n  {\n    \"input\": \"non-special://%E2%80%A0/\",\n    \"base\": null,\n    \"href\": \"non-special://%E2%80%A0/\",\n    \"protocol\": \"non-special:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"%E2%80%A0\",\n    \"hostname\": \"%E2%80%A0\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"non-special://H%4fSt/path\",\n    \"base\": null,\n    \"href\": \"non-special://H%4fSt/path\",\n    \"protocol\": \"non-special:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"H%4fSt\",\n    \"hostname\": \"H%4fSt\",\n    \"port\": \"\",\n    \"pathname\": \"/path\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# IPv6 in non-special-URLs\",\n  {\n    \"input\": \"non-special://[1:2:0:0:5:0:0:0]/\",\n    \"base\": null,\n    \"href\": \"non-special://[1:2:0:0:5::]/\",\n    \"protocol\": \"non-special:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"[1:2:0:0:5::]\",\n    \"hostname\": \"[1:2:0:0:5::]\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"non-special://[1:2:0:0:0:0:0:3]/\",\n    \"base\": null,\n    \"href\": \"non-special://[1:2::3]/\",\n    \"protocol\": \"non-special:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"[1:2::3]\",\n    \"hostname\": \"[1:2::3]\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"non-special://[1:2::3]:80/\",\n    \"base\": null,\n    \"href\": \"non-special://[1:2::3]:80/\",\n    \"protocol\": \"non-special:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"[1:2::3]:80\",\n    \"hostname\": \"[1:2::3]\",\n    \"port\": \"80\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"non-special://[:80/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"blob:https://example.com:443/\",\n    \"base\": null,\n    \"href\": \"blob:https://example.com:443/\",\n    \"origin\": \"https://example.com\",\n    \"protocol\": \"blob:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"https://example.com:443/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"blob:http://example.org:88/\",\n    \"base\": null,\n    \"href\": \"blob:http://example.org:88/\",\n    \"origin\": \"http://example.org:88\",\n    \"protocol\": \"blob:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"http://example.org:88/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"blob:d3958f5c-0777-0845-9dcf-2cb28783acaf\",\n    \"base\": null,\n    \"href\": \"blob:d3958f5c-0777-0845-9dcf-2cb28783acaf\",\n    \"origin\": \"null\",\n    \"protocol\": \"blob:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"d3958f5c-0777-0845-9dcf-2cb28783acaf\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"blob:\",\n    \"base\": null,\n    \"href\": \"blob:\",\n    \"origin\": \"null\",\n    \"protocol\": \"blob:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"blob: in blob:\",\n  {\n    \"input\": \"blob:blob:\",\n    \"base\": null,\n    \"href\": \"blob:blob:\",\n    \"origin\": \"null\",\n    \"protocol\": \"blob:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"blob:\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"blob:blob:https://example.org/\",\n    \"base\": null,\n    \"href\": \"blob:blob:https://example.org/\",\n    \"origin\": \"null\",\n    \"protocol\": \"blob:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"blob:https://example.org/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"Non-http(s): in blob:\",\n  {\n    \"input\": \"blob:about:blank\",\n    \"base\": null,\n    \"href\": \"blob:about:blank\",\n    \"origin\": \"null\",\n    \"protocol\": \"blob:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"about:blank\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"blob:file://host/path\",\n    \"base\": null,\n    \"href\": \"blob:file://host/path\",\n    \"protocol\": \"blob:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"file://host/path\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"blob:ftp://host/path\",\n    \"base\": null,\n    \"href\": \"blob:ftp://host/path\",\n    \"origin\": \"null\",\n    \"protocol\": \"blob:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"ftp://host/path\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"blob:ws://example.org/\",\n    \"base\": null,\n    \"href\": \"blob:ws://example.org/\",\n    \"origin\": \"null\",\n    \"protocol\": \"blob:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"ws://example.org/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"blob:wss://example.org/\",\n    \"base\": null,\n    \"href\": \"blob:wss://example.org/\",\n    \"origin\": \"null\",\n    \"protocol\": \"blob:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"wss://example.org/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"Percent-encoded http: in blob:\",\n  {\n    \"input\": \"blob:http%3a//example.org/\",\n    \"base\": null,\n    \"href\": \"blob:http%3a//example.org/\",\n    \"origin\": \"null\",\n    \"protocol\": \"blob:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"http%3a//example.org/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"Invalid IPv4 radix digits\",\n  {\n    \"input\": \"http://0x7f.0.0.0x7g\",\n    \"base\": null,\n    \"href\": \"http://0x7f.0.0.0x7g/\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"0x7f.0.0.0x7g\",\n    \"hostname\": \"0x7f.0.0.0x7g\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://0X7F.0.0.0X7G\",\n    \"base\": null,\n    \"href\": \"http://0x7f.0.0.0x7g/\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"0x7f.0.0.0x7g\",\n    \"hostname\": \"0x7f.0.0.0x7g\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"Invalid IPv4 portion of IPv6 address\",\n  {\n    \"input\": \"http://[::127.0.0.0.1]\",\n    \"base\": null,\n    \"failure\": true\n  },\n  \"Uncompressed IPv6 addresses with 0\",\n  {\n    \"input\": \"http://[0:1:0:1:0:1:0:1]\",\n    \"base\": null,\n    \"href\": \"http://[0:1:0:1:0:1:0:1]/\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"[0:1:0:1:0:1:0:1]\",\n    \"hostname\": \"[0:1:0:1:0:1:0:1]\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://[1:0:1:0:1:0:1:0]\",\n    \"base\": null,\n    \"href\": \"http://[1:0:1:0:1:0:1:0]/\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"[1:0:1:0:1:0:1:0]\",\n    \"hostname\": \"[1:0:1:0:1:0:1:0]\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"Percent-encoded query and fragment\",\n  {\n    \"input\": \"http://example.org/test?\\u0022\",\n    \"base\": null,\n    \"href\": \"http://example.org/test?%22\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"?%22\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.org/test?\\u0023\",\n    \"base\": null,\n    \"href\": \"http://example.org/test?#\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.org/test?\\u003C\",\n    \"base\": null,\n    \"href\": \"http://example.org/test?%3C\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"?%3C\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.org/test?\\u003E\",\n    \"base\": null,\n    \"href\": \"http://example.org/test?%3E\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"?%3E\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.org/test?\\u2323\",\n    \"base\": null,\n    \"href\": \"http://example.org/test?%E2%8C%A3\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"?%E2%8C%A3\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.org/test?%23%23\",\n    \"base\": null,\n    \"href\": \"http://example.org/test?%23%23\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"?%23%23\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.org/test?%GH\",\n    \"base\": null,\n    \"href\": \"http://example.org/test?%GH\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"?%GH\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"http://example.org/test?a#%EF\",\n    \"base\": null,\n    \"href\": \"http://example.org/test?a#%EF\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"?a\",\n    \"hash\": \"#%EF\"\n  },\n  {\n    \"input\": \"http://example.org/test?a#%GH\",\n    \"base\": null,\n    \"href\": \"http://example.org/test?a#%GH\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"?a\",\n    \"hash\": \"#%GH\"\n  },\n  \"URLs that require a non-about:blank base. (Also serve as invalid base tests.)\",\n  {\n    \"input\": \"a\",\n    \"base\": null,\n    \"failure\": true,\n    \"relativeTo\": \"non-opaque-path-base\"\n  },\n  {\n    \"input\": \"a/\",\n    \"base\": null,\n    \"failure\": true,\n    \"relativeTo\": \"non-opaque-path-base\"\n  },\n  {\n    \"input\": \"a//\",\n    \"base\": null,\n    \"failure\": true,\n    \"relativeTo\": \"non-opaque-path-base\"\n  },\n  \"Bases that don't fail to parse but fail to be bases\",\n  {\n    \"input\": \"test-a-colon.html\",\n    \"base\": \"a:\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"test-a-colon-b.html\",\n    \"base\": \"a:b\",\n    \"failure\": true\n  },\n  \"Other base URL tests, that must succeed\",\n  {\n    \"input\": \"test-a-colon-slash.html\",\n    \"base\": \"a:/\",\n    \"href\": \"a:/test-a-colon-slash.html\",\n    \"protocol\": \"a:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/test-a-colon-slash.html\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"test-a-colon-slash-slash.html\",\n    \"base\": \"a://\",\n    \"href\": \"a:///test-a-colon-slash-slash.html\",\n    \"protocol\": \"a:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/test-a-colon-slash-slash.html\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"test-a-colon-slash-b.html\",\n    \"base\": \"a:/b\",\n    \"href\": \"a:/test-a-colon-slash-b.html\",\n    \"protocol\": \"a:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/test-a-colon-slash-b.html\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"test-a-colon-slash-slash-b.html\",\n    \"base\": \"a://b\",\n    \"href\": \"a://b/test-a-colon-slash-slash-b.html\",\n    \"protocol\": \"a:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"b\",\n    \"hostname\": \"b\",\n    \"port\": \"\",\n    \"pathname\": \"/test-a-colon-slash-slash-b.html\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"Null code point in fragment\",\n  {\n    \"input\": \"http://example.org/test?a#b\\u0000c\",\n    \"base\": null,\n    \"href\": \"http://example.org/test?a#b%00c\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"?a\",\n    \"hash\": \"#b%00c\"\n  },\n  {\n    \"input\": \"non-spec://example.org/test?a#b\\u0000c\",\n    \"base\": null,\n    \"href\": \"non-spec://example.org/test?a#b%00c\",\n    \"protocol\": \"non-spec:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"?a\",\n    \"hash\": \"#b%00c\"\n  },\n  {\n    \"input\": \"non-spec:/test?a#b\\u0000c\",\n    \"base\": null,\n    \"href\": \"non-spec:/test?a#b%00c\",\n    \"protocol\": \"non-spec:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"?a\",\n    \"hash\": \"#b%00c\"\n  },\n  \"First scheme char - not allowed: https://github.com/whatwg/url/issues/464\",\n  {\n    \"input\": \"10.0.0.7:8080/foo.html\",\n    \"base\": \"file:///some/dir/bar.html\",\n    \"href\": \"file:///some/dir/10.0.0.7:8080/foo.html\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/some/dir/10.0.0.7:8080/foo.html\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"Subsequent scheme chars - not allowed\",\n  {\n    \"input\": \"a!@$*=/foo.html\",\n    \"base\": \"file:///some/dir/bar.html\",\n    \"href\": \"file:///some/dir/a!@$*=/foo.html\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/some/dir/a!@$*=/foo.html\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"First and subsequent scheme chars - allowed\",\n  {\n    \"input\": \"a1234567890-+.:foo/bar\",\n    \"base\": \"http://example.com/dir/file\",\n    \"href\": \"a1234567890-+.:foo/bar\",\n    \"protocol\": \"a1234567890-+.:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"foo/bar\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"IDNA ignored code points in file URLs hosts\",\n  {\n    \"input\": \"file://a\\u00ADb/p\",\n    \"base\": null,\n    \"href\": \"file://ab/p\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"ab\",\n    \"hostname\": \"ab\",\n    \"port\": \"\",\n    \"pathname\": \"/p\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"file://a%C2%ADb/p\",\n    \"base\": null,\n    \"href\": \"file://ab/p\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"ab\",\n    \"hostname\": \"ab\",\n    \"port\": \"\",\n    \"pathname\": \"/p\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"IDNA hostnames which get mapped to 'localhost'\",\n  {\n    \"input\": \"file://loC𝐀𝐋𝐇𝐨𝐬𝐭/usr/bin\",\n    \"base\": null,\n    \"href\": \"file:///usr/bin\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/usr/bin\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"Empty host after the domain to ASCII\",\n  {\n    \"input\": \"file://\\u00ad/p\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"file://%C2%AD/p\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"file://xn--/p\",\n    \"base\": null,\n    \"failure\": true\n  },\n  \"https://bugzilla.mozilla.org/show_bug.cgi?id=1647058\",\n  {\n    \"input\": \"#link\",\n    \"base\": \"https://example.org/##link\",\n    \"href\": \"https://example.org/#link\",\n    \"protocol\": \"https:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"#link\"\n  },\n  \"UTF-8 percent-encode of C0 control percent-encode set and supersets\",\n  {\n    \"input\": \"non-special:cannot-be-a-base-url-\\u0000\\u0001\\u001F\\u001E\\u007E\\u007F\\u0080\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"href\": \"non-special:cannot-be-a-base-url-%00%01%1F%1E~%7F%C2%80\",\n    \"origin\": \"null\",\n    \"password\": \"\",\n    \"pathname\": \"cannot-be-a-base-url-%00%01%1F%1E~%7F%C2%80\",\n    \"port\": \"\",\n    \"protocol\": \"non-special:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"non-special:cannot-be-a-base-url-!\\\"$%&'()*+,-.;<=>@[\\\\]^_`{|}~@/\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"href\": \"non-special:cannot-be-a-base-url-!\\\"$%&'()*+,-.;<=>@[\\\\]^_`{|}~@/\",\n    \"origin\": \"null\",\n    \"password\": \"\",\n    \"pathname\": \"cannot-be-a-base-url-!\\\"$%&'()*+,-.;<=>@[\\\\]^_`{|}~@/\",\n    \"port\": \"\",\n    \"protocol\": \"non-special:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"https://www.example.com/path{\\u007Fpath.html?query'\\u007F=query#fragment<\\u007Ffragment\",\n    \"base\": null,\n    \"hash\": \"#fragment%3C%7Ffragment\",\n    \"host\": \"www.example.com\",\n    \"hostname\": \"www.example.com\",\n    \"href\": \"https://www.example.com/path%7B%7Fpath.html?query%27%7F=query#fragment%3C%7Ffragment\",\n    \"origin\": \"https://www.example.com\",\n    \"password\": \"\",\n    \"pathname\": \"/path%7B%7Fpath.html\",\n    \"port\": \"\",\n    \"protocol\": \"https:\",\n    \"search\": \"?query%27%7F=query\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"https://user:pass[\\u007F@foo/bar\",\n    \"base\": \"http://example.org\",\n    \"hash\": \"\",\n    \"host\": \"foo\",\n    \"hostname\": \"foo\",\n    \"href\": \"https://user:pass%5B%7F@foo/bar\",\n    \"origin\": \"https://foo\",\n    \"password\": \"pass%5B%7F\",\n    \"pathname\": \"/bar\",\n    \"port\": \"\",\n    \"protocol\": \"https:\",\n    \"search\": \"\",\n    \"username\": \"user\"\n  },\n  \"Tests for the distinct percent-encode sets\",\n  {\n    \"input\": \"foo:// !\\\"$%&'()*+,-.;<=>@[\\\\]^_`{|}~@host/\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"href\": \"foo://%20!%22$%&'()*+,-.%3B%3C%3D%3E%40%5B%5C%5D%5E_%60%7B%7C%7D~@host/\",\n    \"origin\": \"null\",\n    \"password\": \"\",\n    \"pathname\": \"/\",\n    \"port\": \"\",\n    \"protocol\": \"foo:\",\n    \"search\": \"\",\n    \"username\": \"%20!%22$%&'()*+,-.%3B%3C%3D%3E%40%5B%5C%5D%5E_%60%7B%7C%7D~\"\n  },\n  {\n    \"input\": \"wss:// !\\\"$%&'()*+,-.;<=>@[]^_`{|}~@host/\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"href\": \"wss://%20!%22$%&'()*+,-.%3B%3C%3D%3E%40%5B%5D%5E_%60%7B%7C%7D~@host/\",\n    \"origin\": \"wss://host\",\n    \"password\": \"\",\n    \"pathname\": \"/\",\n    \"port\": \"\",\n    \"protocol\": \"wss:\",\n    \"search\": \"\",\n    \"username\": \"%20!%22$%&'()*+,-.%3B%3C%3D%3E%40%5B%5D%5E_%60%7B%7C%7D~\"\n  },\n  {\n    \"input\": \"foo://joe: !\\\"$%&'()*+,-.:;<=>@[\\\\]^_`{|}~@host/\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"href\": \"foo://joe:%20!%22$%&'()*+,-.%3A%3B%3C%3D%3E%40%5B%5C%5D%5E_%60%7B%7C%7D~@host/\",\n    \"origin\": \"null\",\n    \"password\": \"%20!%22$%&'()*+,-.%3A%3B%3C%3D%3E%40%5B%5C%5D%5E_%60%7B%7C%7D~\",\n    \"pathname\": \"/\",\n    \"port\": \"\",\n    \"protocol\": \"foo:\",\n    \"search\": \"\",\n    \"username\": \"joe\"\n  },\n  {\n    \"input\": \"wss://joe: !\\\"$%&'()*+,-.:;<=>@[]^_`{|}~@host/\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"href\": \"wss://joe:%20!%22$%&'()*+,-.%3A%3B%3C%3D%3E%40%5B%5D%5E_%60%7B%7C%7D~@host/\",\n    \"origin\": \"wss://host\",\n    \"password\": \"%20!%22$%&'()*+,-.%3A%3B%3C%3D%3E%40%5B%5D%5E_%60%7B%7C%7D~\",\n    \"pathname\": \"/\",\n    \"port\": \"\",\n    \"protocol\": \"wss:\",\n    \"search\": \"\",\n    \"username\": \"joe\"\n  },\n  {\n    \"input\": \"foo://!\\\"$%&'()*+,-.;=_`{}~/\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"!\\\"$%&'()*+,-.;=_`{}~\",\n    \"hostname\": \"!\\\"$%&'()*+,-.;=_`{}~\",\n    \"href\": \"foo://!\\\"$%&'()*+,-.;=_`{}~/\",\n    \"origin\": \"null\",\n    \"password\": \"\",\n    \"pathname\": \"/\",\n    \"port\": \"\",\n    \"protocol\": \"foo:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"wss://!\\\"$&'()*+,-.;=_`{}~/\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"!\\\"$&'()*+,-.;=_`{}~\",\n    \"hostname\": \"!\\\"$&'()*+,-.;=_`{}~\",\n    \"href\": \"wss://!\\\"$&'()*+,-.;=_`{}~/\",\n    \"origin\": \"wss://!\\\"$&'()*+,-.;=_`{}~\",\n    \"password\": \"\",\n    \"pathname\": \"/\",\n    \"port\": \"\",\n    \"protocol\": \"wss:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"foo://host/ !\\\"$%&'()*+,-./:;<=>@[\\\\]^_`{|}~\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"href\": \"foo://host/%20!%22$%&'()*+,-./:;%3C=%3E@[\\\\]%5E_%60%7B|%7D~\",\n    \"origin\": \"null\",\n    \"password\": \"\",\n    \"pathname\": \"/%20!%22$%&'()*+,-./:;%3C=%3E@[\\\\]%5E_%60%7B|%7D~\",\n    \"port\": \"\",\n    \"protocol\": \"foo:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"wss://host/ !\\\"$%&'()*+,-./:;<=>@[\\\\]^_`{|}~\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"href\": \"wss://host/%20!%22$%&'()*+,-./:;%3C=%3E@[/]%5E_%60%7B|%7D~\",\n    \"origin\": \"wss://host\",\n    \"password\": \"\",\n    \"pathname\": \"/%20!%22$%&'()*+,-./:;%3C=%3E@[/]%5E_%60%7B|%7D~\",\n    \"port\": \"\",\n    \"protocol\": \"wss:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"foo://host/dir/? !\\\"$%&'()*+,-./:;<=>?@[\\\\]^_`{|}~\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"href\": \"foo://host/dir/?%20!%22$%&'()*+,-./:;%3C=%3E?@[\\\\]^_`{|}~\",\n    \"origin\": \"null\",\n    \"password\": \"\",\n    \"pathname\": \"/dir/\",\n    \"port\": \"\",\n    \"protocol\": \"foo:\",\n    \"search\": \"?%20!%22$%&'()*+,-./:;%3C=%3E?@[\\\\]^_`{|}~\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"wss://host/dir/? !\\\"$%&'()*+,-./:;<=>?@[\\\\]^_`{|}~\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"href\": \"wss://host/dir/?%20!%22$%&%27()*+,-./:;%3C=%3E?@[\\\\]^_`{|}~\",\n    \"origin\": \"wss://host\",\n    \"password\": \"\",\n    \"pathname\": \"/dir/\",\n    \"port\": \"\",\n    \"protocol\": \"wss:\",\n    \"search\": \"?%20!%22$%&%27()*+,-./:;%3C=%3E?@[\\\\]^_`{|}~\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"foo://host/dir/# !\\\"#$%&'()*+,-./:;<=>?@[\\\\]^_`{|}~\",\n    \"base\": null,\n    \"hash\": \"#%20!%22#$%&'()*+,-./:;%3C=%3E?@[\\\\]^_%60{|}~\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"href\": \"foo://host/dir/#%20!%22#$%&'()*+,-./:;%3C=%3E?@[\\\\]^_%60{|}~\",\n    \"origin\": \"null\",\n    \"password\": \"\",\n    \"pathname\": \"/dir/\",\n    \"port\": \"\",\n    \"protocol\": \"foo:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"wss://host/dir/# !\\\"#$%&'()*+,-./:;<=>?@[\\\\]^_`{|}~\",\n    \"base\": null,\n    \"hash\": \"#%20!%22#$%&'()*+,-./:;%3C=%3E?@[\\\\]^_%60{|}~\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"href\": \"wss://host/dir/#%20!%22#$%&'()*+,-./:;%3C=%3E?@[\\\\]^_%60{|}~\",\n    \"origin\": \"wss://host\",\n    \"password\": \"\",\n    \"pathname\": \"/dir/\",\n    \"port\": \"\",\n    \"protocol\": \"wss:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  \"Ensure that input schemes are not ignored when resolving non-special URLs\",\n  {\n    \"input\": \"abc:rootless\",\n    \"base\": \"abc://host/path\",\n    \"hash\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"href\": \"abc:rootless\",\n    \"password\": \"\",\n    \"pathname\": \"rootless\",\n    \"port\": \"\",\n    \"protocol\": \"abc:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"abc:rootless\",\n    \"base\": \"abc:/path\",\n    \"hash\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"href\": \"abc:rootless\",\n    \"password\": \"\",\n    \"pathname\": \"rootless\",\n    \"port\": \"\",\n    \"protocol\": \"abc:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"abc:rootless\",\n    \"base\": \"abc:path\",\n    \"hash\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"href\": \"abc:rootless\",\n    \"password\": \"\",\n    \"pathname\": \"rootless\",\n    \"port\": \"\",\n    \"protocol\": \"abc:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"abc:/rooted\",\n    \"base\": \"abc://host/path\",\n    \"hash\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"href\": \"abc:/rooted\",\n    \"password\": \"\",\n    \"pathname\": \"/rooted\",\n    \"port\": \"\",\n    \"protocol\": \"abc:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  \"Empty query and fragment with blank should throw an error\",\n  {\n    \"input\": \"#\",\n    \"base\": null,\n    \"failure\": true,\n    \"relativeTo\": \"any-base\"\n  },\n  {\n    \"input\": \"?\",\n    \"base\": null,\n    \"failure\": true,\n    \"relativeTo\": \"non-opaque-path-base\"\n  },\n  \"Last component looks like a number, but not valid IPv4\",\n  {\n    \"input\": \"http://1.2.3.4.5\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://1.2.3.4.5.\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://0..0x300/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://0..0x300./\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://256.256.256.256.256\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://256.256.256.256.256.\",\n    \"base\": \"http://other.com/\",\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://1.2.3.08\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://1.2.3.08.\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://1.2.3.09\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://09.2.3.4\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://09.2.3.4.\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://01.2.3.4.5\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://01.2.3.4.5.\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://0x100.2.3.4\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://0x100.2.3.4.\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://0x1.2.3.4.5\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://0x1.2.3.4.5.\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://foo.1.2.3.4\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://foo.1.2.3.4.\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://foo.2.3.4\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://foo.2.3.4.\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://foo.09\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://foo.09.\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://foo.0x4\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://foo.0x4.\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://foo.09..\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"foo.09..\",\n    \"hostname\": \"foo.09..\",\n    \"href\": \"http://foo.09../\",\n    \"password\": \"\",\n    \"pathname\": \"/\",\n    \"port\": \"\",\n    \"protocol\": \"http:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"http://0999999999999999999/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://foo.0x\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://foo.0XFfFfFfFfFfFfFfFfFfAcE123\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"http://💩.123/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  \"U+0000 and U+FFFF in various places\",\n  {\n    \"input\": \"https://\\u0000y\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"https://x/\\u0000y\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"x\",\n    \"hostname\": \"x\",\n    \"href\": \"https://x/%00y\",\n    \"password\": \"\",\n    \"pathname\": \"/%00y\",\n    \"port\": \"\",\n    \"protocol\": \"https:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"https://x/?\\u0000y\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"x\",\n    \"hostname\": \"x\",\n    \"href\": \"https://x/?%00y\",\n    \"password\": \"\",\n    \"pathname\": \"/\",\n    \"port\": \"\",\n    \"protocol\": \"https:\",\n    \"search\": \"?%00y\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"https://x/?#\\u0000y\",\n    \"base\": null,\n    \"hash\": \"#%00y\",\n    \"host\": \"x\",\n    \"hostname\": \"x\",\n    \"href\": \"https://x/?#%00y\",\n    \"password\": \"\",\n    \"pathname\": \"/\",\n    \"port\": \"\",\n    \"protocol\": \"https:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"https://\\uFFFFy\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"https://x/\\uFFFFy\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"x\",\n    \"hostname\": \"x\",\n    \"href\": \"https://x/%EF%BF%BFy\",\n    \"password\": \"\",\n    \"pathname\": \"/%EF%BF%BFy\",\n    \"port\": \"\",\n    \"protocol\": \"https:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"https://x/?\\uFFFFy\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"x\",\n    \"hostname\": \"x\",\n    \"href\": \"https://x/?%EF%BF%BFy\",\n    \"password\": \"\",\n    \"pathname\": \"/\",\n    \"port\": \"\",\n    \"protocol\": \"https:\",\n    \"search\": \"?%EF%BF%BFy\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"https://x/?#\\uFFFFy\",\n    \"base\": null,\n    \"hash\": \"#%EF%BF%BFy\",\n    \"host\": \"x\",\n    \"hostname\": \"x\",\n    \"href\": \"https://x/?#%EF%BF%BFy\",\n    \"password\": \"\",\n    \"pathname\": \"/\",\n    \"port\": \"\",\n    \"protocol\": \"https:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"non-special:\\u0000y\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"href\": \"non-special:%00y\",\n    \"password\": \"\",\n    \"pathname\": \"%00y\",\n    \"port\": \"\",\n    \"protocol\": \"non-special:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"non-special:x/\\u0000y\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"href\": \"non-special:x/%00y\",\n    \"password\": \"\",\n    \"pathname\": \"x/%00y\",\n    \"port\": \"\",\n    \"protocol\": \"non-special:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"non-special:x/?\\u0000y\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"href\": \"non-special:x/?%00y\",\n    \"password\": \"\",\n    \"pathname\": \"x/\",\n    \"port\": \"\",\n    \"protocol\": \"non-special:\",\n    \"search\": \"?%00y\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"non-special:x/?#\\u0000y\",\n    \"base\": null,\n    \"hash\": \"#%00y\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"href\": \"non-special:x/?#%00y\",\n    \"password\": \"\",\n    \"pathname\": \"x/\",\n    \"port\": \"\",\n    \"protocol\": \"non-special:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"non-special:\\uFFFFy\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"href\": \"non-special:%EF%BF%BFy\",\n    \"password\": \"\",\n    \"pathname\": \"%EF%BF%BFy\",\n    \"port\": \"\",\n    \"protocol\": \"non-special:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"non-special:x/\\uFFFFy\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"href\": \"non-special:x/%EF%BF%BFy\",\n    \"password\": \"\",\n    \"pathname\": \"x/%EF%BF%BFy\",\n    \"port\": \"\",\n    \"protocol\": \"non-special:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"non-special:x/?\\uFFFFy\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"href\": \"non-special:x/?%EF%BF%BFy\",\n    \"password\": \"\",\n    \"pathname\": \"x/\",\n    \"port\": \"\",\n    \"protocol\": \"non-special:\",\n    \"search\": \"?%EF%BF%BFy\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"non-special:x/?#\\uFFFFy\",\n    \"base\": null,\n    \"hash\": \"#%EF%BF%BFy\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"href\": \"non-special:x/?#%EF%BF%BFy\",\n    \"password\": \"\",\n    \"pathname\": \"x/\",\n    \"port\": \"\",\n    \"protocol\": \"non-special:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"\",\n    \"base\": null,\n    \"failure\": true,\n    \"relativeTo\": \"non-opaque-path-base\"\n  },\n  {\n    \"input\": \"https://example.com/\\\"quoted\\\"\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"example.com\",\n    \"hostname\": \"example.com\",\n    \"href\": \"https://example.com/%22quoted%22\",\n    \"origin\": \"https://example.com\",\n    \"password\": \"\",\n    \"pathname\": \"/%22quoted%22\",\n    \"port\": \"\",\n    \"protocol\": \"https:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"input\": \"https://a%C2%ADb/\",\n    \"base\": null,\n    \"hash\": \"\",\n    \"host\": \"ab\",\n    \"hostname\": \"ab\",\n    \"href\": \"https://ab/\",\n    \"origin\": \"https://ab\",\n    \"password\": \"\",\n    \"pathname\": \"/\",\n    \"port\": \"\",\n    \"protocol\": \"https:\",\n    \"search\": \"\",\n    \"username\": \"\"\n  },\n  {\n    \"comment\": \"Empty host after domain to ASCII\",\n    \"input\": \"https://\\u00AD/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"https://%C2%AD/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"https://xn--/\",\n    \"base\": null,\n    \"failure\": true\n  },\n  \"Non-special schemes that some implementations might incorrectly treat as special\",\n  {\n    \"input\": \"data://example.com:8080/pathname?search#hash\",\n    \"base\": null,\n    \"href\": \"data://example.com:8080/pathname?search#hash\",\n    \"origin\": \"null\",\n    \"protocol\": \"data:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com:8080\",\n    \"hostname\": \"example.com\",\n    \"port\": \"8080\",\n    \"pathname\": \"/pathname\",\n    \"search\": \"?search\",\n    \"hash\": \"#hash\"\n  },\n  {\n    \"input\": \"data:///test\",\n    \"base\": null,\n    \"href\": \"data:///test\",\n    \"origin\": \"null\",\n    \"protocol\": \"data:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"data://test/a/../b\",\n    \"base\": null,\n    \"href\": \"data://test/b\",\n    \"origin\": \"null\",\n    \"protocol\": \"data:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"test\",\n    \"hostname\": \"test\",\n    \"port\": \"\",\n    \"pathname\": \"/b\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"data://:443\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"data://test:test\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"data://[:1]\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"javascript://example.com:8080/pathname?search#hash\",\n    \"base\": null,\n    \"href\": \"javascript://example.com:8080/pathname?search#hash\",\n    \"origin\": \"null\",\n    \"protocol\": \"javascript:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com:8080\",\n    \"hostname\": \"example.com\",\n    \"port\": \"8080\",\n    \"pathname\": \"/pathname\",\n    \"search\": \"?search\",\n    \"hash\": \"#hash\"\n  },\n  {\n    \"input\": \"javascript:///test\",\n    \"base\": null,\n    \"href\": \"javascript:///test\",\n    \"origin\": \"null\",\n    \"protocol\": \"javascript:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"javascript://test/a/../b\",\n    \"base\": null,\n    \"href\": \"javascript://test/b\",\n    \"origin\": \"null\",\n    \"protocol\": \"javascript:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"test\",\n    \"hostname\": \"test\",\n    \"port\": \"\",\n    \"pathname\": \"/b\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"javascript://:443\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"javascript://test:test\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"javascript://[:1]\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"mailto://example.com:8080/pathname?search#hash\",\n    \"base\": null,\n    \"href\": \"mailto://example.com:8080/pathname?search#hash\",\n    \"origin\": \"null\",\n    \"protocol\": \"mailto:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com:8080\",\n    \"hostname\": \"example.com\",\n    \"port\": \"8080\",\n    \"pathname\": \"/pathname\",\n    \"search\": \"?search\",\n    \"hash\": \"#hash\"\n  },\n  {\n    \"input\": \"mailto:///test\",\n    \"base\": null,\n    \"href\": \"mailto:///test\",\n    \"origin\": \"null\",\n    \"protocol\": \"mailto:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"mailto://test/a/../b\",\n    \"base\": null,\n    \"href\": \"mailto://test/b\",\n    \"origin\": \"null\",\n    \"protocol\": \"mailto:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"test\",\n    \"hostname\": \"test\",\n    \"port\": \"\",\n    \"pathname\": \"/b\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"mailto://:443\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"mailto://test:test\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"mailto://[:1]\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"intent://example.com:8080/pathname?search#hash\",\n    \"base\": null,\n    \"href\": \"intent://example.com:8080/pathname?search#hash\",\n    \"origin\": \"null\",\n    \"protocol\": \"intent:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com:8080\",\n    \"hostname\": \"example.com\",\n    \"port\": \"8080\",\n    \"pathname\": \"/pathname\",\n    \"search\": \"?search\",\n    \"hash\": \"#hash\"\n  },\n  {\n    \"input\": \"intent:///test\",\n    \"base\": null,\n    \"href\": \"intent:///test\",\n    \"origin\": \"null\",\n    \"protocol\": \"intent:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"intent://test/a/../b\",\n    \"base\": null,\n    \"href\": \"intent://test/b\",\n    \"origin\": \"null\",\n    \"protocol\": \"intent:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"test\",\n    \"hostname\": \"test\",\n    \"port\": \"\",\n    \"pathname\": \"/b\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"intent://:443\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"intent://test:test\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"intent://[:1]\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"urn://example.com:8080/pathname?search#hash\",\n    \"base\": null,\n    \"href\": \"urn://example.com:8080/pathname?search#hash\",\n    \"origin\": \"null\",\n    \"protocol\": \"urn:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com:8080\",\n    \"hostname\": \"example.com\",\n    \"port\": \"8080\",\n    \"pathname\": \"/pathname\",\n    \"search\": \"?search\",\n    \"hash\": \"#hash\"\n  },\n  {\n    \"input\": \"urn:///test\",\n    \"base\": null,\n    \"href\": \"urn:///test\",\n    \"origin\": \"null\",\n    \"protocol\": \"urn:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"urn://test/a/../b\",\n    \"base\": null,\n    \"href\": \"urn://test/b\",\n    \"origin\": \"null\",\n    \"protocol\": \"urn:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"test\",\n    \"hostname\": \"test\",\n    \"port\": \"\",\n    \"pathname\": \"/b\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"urn://:443\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"urn://test:test\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"urn://[:1]\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"turn://example.com:8080/pathname?search#hash\",\n    \"base\": null,\n    \"href\": \"turn://example.com:8080/pathname?search#hash\",\n    \"origin\": \"null\",\n    \"protocol\": \"turn:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com:8080\",\n    \"hostname\": \"example.com\",\n    \"port\": \"8080\",\n    \"pathname\": \"/pathname\",\n    \"search\": \"?search\",\n    \"hash\": \"#hash\"\n  },\n  {\n    \"input\": \"turn:///test\",\n    \"base\": null,\n    \"href\": \"turn:///test\",\n    \"origin\": \"null\",\n    \"protocol\": \"turn:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"turn://test/a/../b\",\n    \"base\": null,\n    \"href\": \"turn://test/b\",\n    \"origin\": \"null\",\n    \"protocol\": \"turn:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"test\",\n    \"hostname\": \"test\",\n    \"port\": \"\",\n    \"pathname\": \"/b\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"turn://:443\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"turn://test:test\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"turn://[:1]\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"stun://example.com:8080/pathname?search#hash\",\n    \"base\": null,\n    \"href\": \"stun://example.com:8080/pathname?search#hash\",\n    \"origin\": \"null\",\n    \"protocol\": \"stun:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.com:8080\",\n    \"hostname\": \"example.com\",\n    \"port\": \"8080\",\n    \"pathname\": \"/pathname\",\n    \"search\": \"?search\",\n    \"hash\": \"#hash\"\n  },\n  {\n    \"input\": \"stun:///test\",\n    \"base\": null,\n    \"href\": \"stun:///test\",\n    \"origin\": \"null\",\n    \"protocol\": \"stun:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/test\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"stun://test/a/../b\",\n    \"base\": null,\n    \"href\": \"stun://test/b\",\n    \"origin\": \"null\",\n    \"protocol\": \"stun:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"test\",\n    \"hostname\": \"test\",\n    \"port\": \"\",\n    \"pathname\": \"/b\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"stun://:443\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"stun://test:test\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"stun://[:1]\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"w://x:0\",\n    \"base\": null,\n    \"href\": \"w://x:0\",\n    \"origin\": \"null\",\n    \"protocol\": \"w:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"x:0\",\n    \"hostname\": \"x\",\n    \"port\": \"0\",\n    \"pathname\": \"\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"west://x:0\",\n    \"base\": null,\n    \"href\": \"west://x:0\",\n    \"origin\": \"null\",\n    \"protocol\": \"west:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"x:0\",\n    \"hostname\": \"x\",\n    \"port\": \"0\",\n    \"pathname\": \"\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"android://x:0/a\",\n    \"base\": null,\n    \"href\": \"android://x:0/a\",\n    \"origin\": \"null\",\n    \"protocol\": \"android:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"x:0\",\n    \"hostname\": \"x\",\n    \"port\": \"0\",\n    \"pathname\": \"/a\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"drivefs://x:0/a\",\n    \"base\": null,\n    \"href\": \"drivefs://x:0/a\",\n    \"origin\": \"null\",\n    \"protocol\": \"drivefs:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"x:0\",\n    \"hostname\": \"x\",\n    \"port\": \"0\",\n    \"pathname\": \"/a\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"chromeos-steam://x:0/a\",\n    \"base\": null,\n    \"href\": \"chromeos-steam://x:0/a\",\n    \"origin\": \"null\",\n    \"protocol\": \"chromeos-steam:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"x:0\",\n    \"hostname\": \"x\",\n    \"port\": \"0\",\n    \"pathname\": \"/a\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"steam://x:0/a\",\n    \"base\": null,\n    \"href\": \"steam://x:0/a\",\n    \"origin\": \"null\",\n    \"protocol\": \"steam:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"x:0\",\n    \"hostname\": \"x\",\n    \"port\": \"0\",\n    \"pathname\": \"/a\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"materialized-view://x:0/a\",\n    \"base\": null,\n    \"href\": \"materialized-view://x:0/a\",\n    \"origin\": \"null\",\n    \"protocol\": \"materialized-view:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"x:0\",\n    \"hostname\": \"x\",\n    \"port\": \"0\",\n    \"pathname\": \"/a\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"android-app://x:0\",\n    \"base\": null,\n    \"href\": \"android-app://x:0\",\n    \"origin\": \"null\",\n    \"protocol\": \"android-app:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"x:0\",\n    \"hostname\": \"x\",\n    \"port\": \"0\",\n    \"pathname\": \"\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"chrome-distiller://x:0\",\n    \"base\": null,\n    \"href\": \"chrome-distiller://x:0\",\n    \"origin\": \"null\",\n    \"protocol\": \"chrome-distiller:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"x:0\",\n    \"hostname\": \"x\",\n    \"port\": \"0\",\n    \"pathname\": \"\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"chrome-extension://x:0\",\n    \"base\": null,\n    \"href\": \"chrome-extension://x:0\",\n    \"origin\": \"null\",\n    \"protocol\": \"chrome-extension:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"x:0\",\n    \"hostname\": \"x\",\n    \"port\": \"0\",\n    \"pathname\": \"\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"chrome-native://x:0\",\n    \"base\": null,\n    \"href\": \"chrome-native://x:0\",\n    \"origin\": \"null\",\n    \"protocol\": \"chrome-native:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"x:0\",\n    \"hostname\": \"x\",\n    \"port\": \"0\",\n    \"pathname\": \"\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"chrome-resource://x:0\",\n    \"base\": null,\n    \"href\": \"chrome-resource://x:0\",\n    \"origin\": \"null\",\n    \"protocol\": \"chrome-resource:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"x:0\",\n    \"hostname\": \"x\",\n    \"port\": \"0\",\n    \"pathname\": \"\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"chrome-search://x:0\",\n    \"base\": null,\n    \"href\": \"chrome-search://x:0\",\n    \"origin\": \"null\",\n    \"protocol\": \"chrome-search:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"x:0\",\n    \"hostname\": \"x\",\n    \"port\": \"0\",\n    \"pathname\": \"\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"fuchsia-dir://x:0\",\n    \"base\": null,\n    \"href\": \"fuchsia-dir://x:0\",\n    \"origin\": \"null\",\n    \"protocol\": \"fuchsia-dir:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"x:0\",\n    \"hostname\": \"x\",\n    \"port\": \"0\",\n    \"pathname\": \"\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"isolated-app://x:0\",\n    \"base\": null,\n    \"href\": \"isolated-app://x:0\",\n    \"origin\": \"null\",\n    \"protocol\": \"isolated-app:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"x:0\",\n    \"hostname\": \"x\",\n    \"port\": \"0\",\n    \"pathname\": \"\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"Scheme relative path starting with multiple slashes\",\n  {\n    \"input\": \"///test\",\n    \"base\": \"http://example.org/\",\n    \"href\": \"http://test/\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"test\",\n    \"hostname\": \"test\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"///\\\\//\\\\//test\",\n    \"base\": \"http://example.org/\",\n    \"href\": \"http://test/\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"test\",\n    \"hostname\": \"test\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"///example.org/path\",\n    \"base\": \"http://example.org/\",\n    \"href\": \"http://example.org/path\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/path\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"///example.org/../path\",\n    \"base\": \"http://example.org/\",\n    \"href\": \"http://example.org/path\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/path\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"///example.org/../../\",\n    \"base\": \"http://example.org/\",\n    \"href\": \"http://example.org/\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"///example.org/../path/../../\",\n    \"base\": \"http://example.org/\",\n    \"href\": \"http://example.org/\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"///example.org/../path/../../path\",\n    \"base\": \"http://example.org/\",\n    \"href\": \"http://example.org/path\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/path\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/\\\\/\\\\//example.org/../path\",\n    \"base\": \"http://example.org/\",\n    \"href\": \"http://example.org/path\",\n    \"protocol\": \"http:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"example.org\",\n    \"hostname\": \"example.org\",\n    \"port\": \"\",\n    \"pathname\": \"/path\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"///abcdef/../\",\n    \"base\": \"file:///\",\n    \"href\": \"file:///\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"/\\\\//\\\\/a/../\",\n    \"base\": \"file:///\",\n    \"href\": \"file://////\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"////\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"//a/../\",\n    \"base\": \"file:///\",\n    \"href\": \"file://a/\",\n    \"protocol\": \"file:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"a\",\n    \"hostname\": \"a\",\n    \"port\": \"\",\n    \"pathname\": \"/\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  \"# Non-special URL and backslashes\",\n  {\n    \"input\": \"non-special:\\\\\\\\opaque\",\n    \"base\": null,\n    \"href\": \"non-special:\\\\\\\\opaque\",\n    \"origin\": \"null\",\n    \"protocol\": \"non-special:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"\\\\\\\\opaque\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"non-special:\\\\\\\\opaque/path\",\n    \"base\": null,\n    \"href\": \"non-special:\\\\\\\\opaque/path\",\n    \"origin\": \"null\",\n    \"protocol\": \"non-special:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"\\\\\\\\opaque/path\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"non-special:\\\\\\\\opaque\\\\path\",\n    \"base\": null,\n    \"href\": \"non-special:\\\\\\\\opaque\\\\path\",\n    \"origin\": \"null\",\n    \"protocol\": \"non-special:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"\\\\\\\\opaque\\\\path\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"non-special:\\\\/opaque\",\n    \"base\": null,\n    \"href\": \"non-special:\\\\/opaque\",\n    \"origin\": \"null\",\n    \"protocol\": \"non-special:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"\\\\/opaque\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"non-special:/\\\\path\",\n    \"base\": null,\n    \"href\": \"non-special:/\\\\path\",\n    \"origin\": \"null\",\n    \"protocol\": \"non-special:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"\",\n    \"hostname\": \"\",\n    \"port\": \"\",\n    \"pathname\": \"/\\\\path\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  },\n  {\n    \"input\": \"non-special://host\\\\a\",\n    \"base\": null,\n    \"failure\": true\n  },\n  {\n    \"input\": \"non-special://host/a\\\\b\",\n    \"base\": null,\n    \"href\": \"non-special://host/a\\\\b\",\n    \"origin\": \"null\",\n    \"protocol\": \"non-special:\",\n    \"username\": \"\",\n    \"password\": \"\",\n    \"host\": \"host\",\n    \"hostname\": \"host\",\n    \"port\": \"\",\n    \"pathname\": \"/a\\\\b\",\n    \"search\": \"\",\n    \"hash\": \"\"\n  }\n]\n"
  },
  {
    "path": "tests/wpt/url.harness.js",
    "content": "import encodings from \"./encoding/resources/encodings.js\";\n\nimport commonGc from \"./common/gc.js\";\nimport commonSubsetTests from \"./common/subset-tests.js\";\n\nimport resourcesIdlharness from \"./resources/idlharness.js\";\nimport resourcesTestharness from \"./resources/testharness.js\";\n\nimport encodingDecodingHelpers from \"./encoding/resources/decoding-helpers.js\";\n\nexport const runTestDynamic = (testSource, done) => {\n  const context = {\n    createBuffer: (type, length) => new self[type](length),\n    encodings_table: encodings,\n    fetch: (url) => {\n      let data;\n      switch (url) {\n        case \"resources/urltestdata-javascript-only.json\":\n          data = require(\"./url/resources/urltestdata-javascript-only.json\");\n          break;\n        case \"resources/urltestdata.json\":\n          data = require(\"./url/resources/urltestdata.json\");\n          break;\n        case \"resources/setters_tests.json\":\n          data = require(\"./url/resources/setters_tests.json\");\n          break;\n        default:\n          throw new Error(`Cannot fetch URL: ${url}`);\n      }\n      return Promise.resolve({\n        json: () => Promise.resolve(data),\n      });\n    },\n    setTimeout: setTimeout,\n    DOMException: DOMException,\n    location: {},\n  };\n\n  commonGc(context);\n  commonSubsetTests(context);\n\n  resourcesIdlharness(context);\n  resourcesTestharness(context);\n\n  encodingDecodingHelpers(context);\n\n  context.setup({\n    explicit_done: true,\n    debug: process.env.DEBUG !== undefined,\n  });\n\n  globalThis.gc = globalThis.__gc;\n\n  context.add_completion_callback((tests, status, assertions) => {\n    if (\n      tests.filter(\n        ({ name, status }) => !(name === \"Loading data...\" && status === 0)\n      ).length === 0\n    ) {\n      done(new Error(\"No tests were executed!\"));\n    }\n    const failure = tests.find((test) => test.status !== 0);\n    if (failure) {\n      const message = `[${failure.name}] ${failure.message || String(failure)}`;\n      done(message);\n      return;\n    }\n    done();\n  });\n\n  wrapTestSuite(testSource)(context);\n\n  context.done();\n};\n\nfunction wrapTestSuite(sourceCode) {\n  return new Function(\n    \"context\",\n    `\n      with (context) {\n        ${sourceCode}\n      }\n    `\n  );\n}\n"
  },
  {
    "path": "tests/wpt/url.test.ts",
    "content": "import { runTestDynamic } from \"./url.harness.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst SKIP_FILES = [\n  \"historical.any.js\", // TypeError: cannot read property 'isWindow' of undefined\n  \"idlharness.any.js\", // ReferenceError: idl_test is not defined\n];\n\nconst __filename = fileURLToPath(import.meta.url);\nconst basename = path.basename(__filename);\nconst subDir = basename\n  .replace(/\\.test\\.[jt]s$/, \"\")\n  .split(\".\")\n  .join(path.sep);\n\nconst CWD = process.cwd();\nconst baseDir = path.join(CWD, \"wpt\");\nconst targetDir = path.join(baseDir, subDir);\n\nconst testFiles = fs\n  .readdirSync(targetDir)\n  .filter((file) => file.endsWith(\".any.js\"));\n\ndescribe(subDir, () => {\n  for (const file of testFiles) {\n    if (!SKIP_FILES.includes(file)) {\n      it(`should pass ${file} tests`, (done) => {\n        const filePath = path.join(targetDir, file);\n        const sourceCode = fs.readFileSync(filePath, \"utf8\");\n        runTestDynamic(sourceCode, done);\n      });\n    }\n  }\n});\n"
  },
  {
    "path": "tests/wpt/webidl-harness.js",
    "content": "import encodings from \"./encoding/resources/encodings.js\";\n\nimport commonGc from \"./common/gc.js\";\nimport commonSubsetTests from \"./common/subset-tests.js\";\n\nimport resourcesIdlharness from \"./resources/idlharness.js\";\nimport resourcesTestharness from \"./resources/testharness.js\";\n\nimport encodingDecodingHelpers from \"./encoding/resources/decoding-helpers.js\";\n\nexport const runTestDynamic = (testSource, done) => {\n  const context = {\n    createBuffer: (type, length) => new self[type](length),\n    encodings_table: encodings,\n    setTimeout: setTimeout,\n    DOMException: DOMException,\n    location: {},\n  };\n\n  commonGc(context);\n  commonSubsetTests(context);\n\n  resourcesIdlharness(context);\n  resourcesTestharness(context);\n\n  encodingDecodingHelpers(context);\n\n  context.setup({\n    explicit_done: true,\n    debug: process.env.DEBUG !== undefined,\n  });\n\n  globalThis.gc = globalThis.__gc;\n\n  context.add_completion_callback((tests, status, assertions) => {\n    if (\n      tests.filter(\n        ({ name, status }) => !(name === \"Loading data...\" && status === 0)\n      ).length === 0\n    ) {\n      done(new Error(\"No tests were executed!\"));\n    }\n    const failure = tests.find((test) => test.status !== 0);\n    if (failure) {\n      const message = `[${failure.name}] ${failure.message || String(failure)}`;\n      done(message);\n      return;\n    }\n    done();\n  });\n\n  wrapTestSuite(testSource)(context);\n\n  context.done();\n};\n\nfunction wrapTestSuite(sourceCode) {\n  return new Function(\n    \"context\",\n    `\n      with (context) {\n        ${sourceCode}\n      }\n    `\n  );\n}\n"
  },
  {
    "path": "tests/wpt/webidl.ecmascript-binding.es-exceptions.test.ts",
    "content": "import { runTestDynamic } from \"./webidl-harness.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst SKIP_FILES = [];\n\nconst __filename = fileURLToPath(import.meta.url);\nconst basename = path.basename(__filename);\nconst subDir = basename\n  .replace(/\\.test\\.[jt]s$/, \"\")\n  .split(\".\")\n  .join(path.sep);\n\nconst CWD = process.cwd();\nconst baseDir = path.join(CWD, \"wpt\");\nconst targetDir = path.join(baseDir, subDir);\n\nconst testFiles = fs\n  .readdirSync(targetDir)\n  .filter((file) => file.endsWith(\".any.js\"));\n\ndescribe(subDir, () => {\n  for (const file of testFiles) {\n    if (!SKIP_FILES.includes(file)) {\n      it(`should pass ${file} tests`, (done) => {\n        const filePath = path.join(targetDir, file);\n        const sourceCode = fs.readFileSync(filePath, \"utf8\");\n        runTestDynamic(sourceCode, done);\n      });\n    }\n  }\n});\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es2023\",\n    \"lib\": [\"es2023\"],\n    \"module\": \"es2022\",\n    \"esModuleInterop\": true,\n    \"moduleResolution\": \"node\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"strict\": true,\n    \"skipLibCheck\": true\n  },\n  \"exclude\": [\"example/**/*\"]\n}\n"
  },
  {
    "path": "types/.eslintrc.cjs",
    "content": "module.exports = {\n  root: true,\n  extends: [\"plugin:@definitelytyped/all\"],\n};\n"
  },
  {
    "path": "types/abort.d.ts",
    "content": "export {};\n\ndeclare global {\n  class AbortController {\n    /**\n     * Creates a new `AbortController` object instance.\n     */\n    constructor();\n\n    /**\n     * Returns the AbortSignal object associated with this object.\n     */\n    readonly signal: AbortSignal;\n\n    /**\n     * Invoking this method will set this object's AbortSignal's aborted flag and signal to any observers that the associated activity is to be aborted.\n     */\n    abort(reason?: any): void;\n  }\n\n  /** A signal object that allows you to communicate with a DOM request (such as a Fetch) and abort it if required via an AbortController object. */\n  class AbortSignal extends EventTarget {\n    /**\n     * Creates a new `AbortSignal` object instance.\n     */\n    constructor();\n\n    /**\n     * Returns true if this AbortSignal's AbortController has signaled to abort, and false otherwise.\n     */\n    readonly aborted: boolean;\n\n    /**\n     * A JavaScript value providing the abort reason, once the signal has aborted.\n     */\n    readonly reason: any;\n\n    /**\n     * Registers an event listener callback to execute when an `abort` event is observed.\n     */\n    onabort: null | ((this: AbortSignal, event: Event) => any);\n\n    /**\n     * Throws the signal's abort reason if the signal has been aborted; otherwise it does nothing.\n     */\n    throwIfAborted(): void;\n\n    /**\n     * Returns an `AbortSignal` instance that is already set as aborted.\n     *\n     * @param reason The reason for the abort.\n     */\n    static abort(reason?: any): AbortSignal;\n\n    /**\n     * Returns an `AbortSignal` instance that will automatically abort after a specified time.\n     *\n     * @param milliseconds The number of milliseconds to wait before aborting.\n     */\n    static timeout(milliseconds: number): AbortSignal;\n\n    /**\n     * Returns an `AbortSignal` that aborts when any of the given abort signals abort.\n     *\n     * @param signals An array of `AbortSignal` objects to observe.\n     */\n    static any(signals: AbortSignal[]): AbortSignal;\n  }\n}\n"
  },
  {
    "path": "types/assert.d.ts",
    "content": "/**\n * The `assert` module provides a set of assertion functions for verifying invariants.\n */\ndeclare module \"assert\" {\n  /**\n   * An alias of {@link ok}.\n   * @param value The input that is checked for being truthy.\n   */\n  function assert(value: unknown, message?: string | Error): asserts value;\n  /**\n   * Tests if `value` is truthy.\n   *\n   * If `value` is not truthy, an `AssertionError` is thrown with a `message` property set equal to the value of the `message` parameter. If the `message` parameter is `undefined`, a default\n   * error message is assigned. If the `message` parameter is an instance of an `Error` then it will be thrown instead of the `AssertionError`.\n   * If no arguments are passed in at all `message` will be set to the string:`` 'No value argument passed to `assert.ok()`' ``.\n   *\n   * ```js\n   * import * as assert from 'assert';\n   *\n   * assert.ok(true);\n   * // OK\n   * assert.ok(1);\n   * // OK\n   *\n   * assert.ok();\n   * // TypeError: Error calling function with 0 argument(s) while 1 where expected\n   *\n   * assert.ok(false, 'it\\'s false');\n   * // AssertionError: it's false\n   *\n   * assert.ok(false);\n   * // AssertionError: The expression was evaluated to a falsy value\n   *\n   * assert.ok(0);\n   * // AssertionError: The expression was evaluated to a falsy value\n   * ```\n   */\n  function ok(value: unknown, message?: string | Error): asserts value;\n}\n"
  },
  {
    "path": "types/async_hooks.d.ts",
    "content": "/**\n * We strongly discourage the use of the `async_hooks` API.\n * Other APIs that can cover most of its use cases include:\n *\n * * [`AsyncLocalStorage`](https://nodejs.org/docs/latest-v22.x/api/async_context.html#class-asynclocalstorage) tracks async context\n * * [`process.getActiveResourcesInfo()`](https://nodejs.org/docs/latest-v22.x/api/process.html#processgetactiveresourcesinfo) tracks active resources\n *\n * The `async_hooks` module provides an API to track asynchronous resources.\n * It can be accessed using:\n *\n * ```js\n * import async_hooks from 'async_hooks';\n * ```\n * @experimental\n * @see [source](https://github.com/nodejs/node/blob/v22.x/lib/async_hooks.js)\n */\ndeclare module \"async_hooks\" {\n  /**\n   * ```js\n   * import { executionAsyncId } from 'async_hooks';\n   * import fs from 'fs';\n   *\n   * console.log(executionAsyncId());  // 1 - bootstrap\n   * const path = '.';\n   * fs.open(path, 'r', (err, fd) => {\n   *   console.log(executionAsyncId());  // 6 - open()\n   * });\n   * ```\n   *\n   * The ID returned from `executionAsyncId()` is related to execution timing, not\n   * causality (which is covered by `triggerAsyncId()`):\n   *\n   * ```js\n   * const server = net.createServer((conn) => {\n   *   // Returns the ID of the server, not of the new connection, because the\n   *   // callback runs in the execution scope of the server's MakeCallback().\n   *   async_hooks.executionAsyncId();\n   *\n   * }).listen(port, () => {\n   *   // Returns the ID of a TickObject (process.nextTick()) because all\n   *   // callbacks passed to .listen() are wrapped in a nextTick().\n   *   async_hooks.executionAsyncId();\n   * });\n   * ```\n   *\n   * Promise contexts may not get precise `executionAsyncIds` by default.\n   * See the section on [promise execution tracking](https://nodejs.org/docs/latest-v22.x/api/async_hooks.html#promise-execution-tracking).\n   * @return The `asyncId` of the current execution context. Useful to track when something calls.\n   */\n  function executionAsyncId(): number;\n  /**\n   * Resource objects returned by `executionAsyncResource()` are most often internal\n   * LLRT handle objects with undocumented APIs. Using any functions or properties\n   * on the object is likely to crash your application and should be avoided.\n   *\n   * Using `executionAsyncResource()` in the top-level execution context will\n   * return an empty object as there is no handle or request object to use,\n   * but having an object representing the top-level can be helpful.\n   *\n   * ```js\n   * import { open } from 'fs';\n   * import { executionAsyncId, executionAsyncResource } from 'async_hooks';\n   *\n   * console.log(executionAsyncId(), executionAsyncResource());  // 1 {}\n   * open(new URL(import.meta.url), 'r', (err, fd) => {\n   *   console.log(executionAsyncId(), executionAsyncResource());  // 7 FSReqWrap\n   * });\n   * ```\n   *\n   * This can be used to implement continuation local storage without the\n   * use of a tracking `Map` to store the metadata:\n   *\n   * ```js\n   * import { createServer } from 'http';\n   * import {\n   *   executionAsyncId,\n   *   executionAsyncResource,\n   *   createHook,\n   * } from 'async_hooks';\n   * const sym = Symbol('state'); // Private symbol to avoid pollution\n   *\n   * createHook({\n   *   init(asyncId, type, triggerAsyncId, resource) {\n   *     const cr = executionAsyncResource();\n   *     if (cr) {\n   *       resource[sym] = cr[sym];\n   *     }\n   *   },\n   * }).enable();\n   *\n   * const server = createServer((req, res) => {\n   *   executionAsyncResource()[sym] = { state: req.url };\n   *   setTimeout(function() {\n   *     res.end(JSON.stringify(executionAsyncResource()[sym]));\n   *   }, 100);\n   * }).listen(3000);\n   * ```\n   * @return The resource representing the current execution. Useful to store data within the resource.\n   */\n  function executionAsyncResource(): object;\n  /**\n   * ```js\n   * const server = net.createServer((conn) => {\n   *   // The resource that caused (or triggered) this callback to be called\n   *   // was that of the new connection. Thus the return value of triggerAsyncId()\n   *   // is the asyncId of \"conn\".\n   *   async_hooks.triggerAsyncId();\n   *\n   * }).listen(port, () => {\n   *   // Even though all callbacks passed to .listen() are wrapped in a nextTick()\n   *   // the callback itself exists because the call to the server's .listen()\n   *   // was made. So the return value would be the ID of the server.\n   *   async_hooks.triggerAsyncId();\n   * });\n   * ```\n   *\n   * Promise contexts may not get valid `triggerAsyncId`s by default. See\n   * the section on [promise execution tracking](https://nodejs.org/docs/latest-v22.x/api/async_hooks.html#promise-execution-tracking).\n   * @return The ID of the resource responsible for calling the callback that is currently being executed.\n   */\n  function triggerAsyncId(): number;\n  interface HookCallbacks {\n    /**\n     * Called when a class is constructed that has the possibility to emit an asynchronous event.\n     * @param asyncId A unique ID for the async resource\n     * @param type The type of the async resource\n     * @param triggerAsyncId The unique ID of the async resource in whose execution context this async resource was created\n     */\n    init?(asyncId: number, type: string, triggerAsyncId: number): void;\n    /**\n     * When an asynchronous operation is initiated or completes a callback is called to notify the user.\n     * The before callback is called just before said callback is executed.\n     * @param asyncId the unique identifier assigned to the resource about to execute the callback.\n     */\n    before?(asyncId: number): void;\n    /**\n     * Called immediately after the callback specified in `before` is completed.\n     *\n     * If an uncaught exception occurs during execution of the callback, then `after` will run after the `'uncaughtException'` event is emitted or a `domain`'s handler runs.\n     * @param asyncId the unique identifier assigned to the resource which has executed the callback.\n     */\n    after?(asyncId: number): void;\n    /**\n     * Called when a promise has resolve() called. This may not be in the same execution id\n     * as the promise itself.\n     * @param asyncId the unique id for the promise that was resolve()d.\n     */\n    promiseResolve?(asyncId: number): void;\n    /**\n     * Called after the resource corresponding to asyncId is destroyed\n     * @param asyncId a unique ID for the async resource\n     */\n    destroy?(asyncId: number): void;\n  }\n  interface AsyncHook {\n    /**\n     * Enable the callbacks for a given AsyncHook instance. If no callbacks are provided enabling is a noop.\n     */\n    enable(): this;\n    /**\n     * Disable the callbacks for a given AsyncHook instance from the global pool of AsyncHook callbacks to be executed. Once a hook has been disabled it will not be called again until enabled.\n     */\n    disable(): this;\n  }\n  /**\n   * Registers functions to be called for different lifetime events of each async\n   * operation.\n   *\n   * The callbacks `init()`/`before()`/`after()`/`destroy()` are called for the\n   * respective asynchronous event during a resource's lifetime.\n   *\n   * All callbacks are optional. For example, if only resource cleanup needs to\n   * be tracked, then only the `destroy` callback needs to be passed. The\n   * specifics of all functions that can be passed to `callbacks` is in the `Hook Callbacks` section.\n   *\n   * ```js\n   * import { createHook } from 'async_hooks';\n   *\n   * const asyncHook = createHook({\n   *   init(asyncId, type, triggerAsyncId, resource) { },\n   *   destroy(asyncId) { },\n   * });\n   * ```\n   *\n   * The callbacks will be inherited via the prototype chain:\n   *\n   * ```js\n   * class MyAsyncCallbacks {\n   *   init(asyncId, type, triggerAsyncId, resource) { }\n   *   destroy(asyncId) {}\n   * }\n   *\n   * class MyAddedCallbacks extends MyAsyncCallbacks {\n   *   before(asyncId) { }\n   *   after(asyncId) { }\n   * }\n   *\n   * const asyncHook = async_hooks.createHook(new MyAddedCallbacks());\n   * ```\n   *\n   * Because promises are asynchronous resources whose lifecycle is tracked\n   * via the async hooks mechanism, the `init()`, `before()`, `after()`, and`destroy()` callbacks _must not_ be async functions that return promises.\n   * @param callbacks The `Hook Callbacks` to register\n   * @return Instance used for disabling and enabling hooks\n   */\n  function createHook(callbacks: HookCallbacks): AsyncHook;\n}\ndeclare module \"async_hooks\" {\n  export * from \"async_hooks\";\n}\n"
  },
  {
    "path": "types/buffer.d.ts",
    "content": "/**\n * `Buffer` objects are used to represent a fixed-length sequence of bytes. Many\n * LLRT APIs support `Buffer`s.\n *\n * The `Buffer` class is a subclass of JavaScript's [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) class and\n * extends it with methods that cover additional use cases. LLRT APIs accept\n * plain [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) s wherever `Buffer`s are supported as well.\n *\n * While the `Buffer` class is available within the global scope, it is still\n * recommended to explicitly reference it via an import or require statement.\n *\n * ```js\n * import { Buffer } from 'buffer';\n *\n * // Creates a zero-filled Buffer of length 10.\n * const buf1 = Buffer.alloc(10);\n *\n * // Creates a Buffer of length 10,\n * // filled with bytes which all have the value `1`.\n * const buf2 = Buffer.alloc(10, 1);\n *\n * // Creates a Buffer containing the bytes [1, 2, 3].\n * const buf4 = Buffer.from([1, 2, 3]);\n *\n * // Creates a Buffer containing the bytes [1, 1, 1, 1] – the entries\n * // are all truncated using `(value &#x26; 255)` to fit into the range 0–255.\n * const buf5 = Buffer.from([257, 257.5, -255, '1']);\n *\n * // Creates a Buffer containing the UTF-8-encoded bytes for the string 'tést':\n * // [0x74, 0xc3, 0xa9, 0x73, 0x74] (in hexadecimal notation)\n * // [116, 195, 169, 115, 116] (in decimal notation)\n * const buf6 = Buffer.from('tést');\n *\n * // Creates a Buffer containing the Latin-1 bytes [0x74, 0xe9, 0x73, 0x74].\n * const buf7 = Buffer.from('tést', 'latin1');\n * ```\n */\ndeclare module \"buffer\" {\n  export const constants: {\n    MAX_LENGTH: number;\n    MAX_STRING_LENGTH: number;\n  };\n  export type BufferEncoding =\n    | \"hex\"\n    | \"base64\"\n    | \"utf-8\"\n    | \"utf8\"\n    | \"unicode-1-1-utf8\"\n    | \"ucs2\"\n    | \"ucs-2\"\n    | \"utf-16le\"\n    | \"utf16le\"\n    | \"utf-16\"\n    | \"utf16\"\n    | \"utf-16be\"\n    | \"utf16be\"\n    | \"windows-1252\"\n    | \"ansi_x3.4-1968\"\n    | \"ascii\"\n    | \"cp1252\"\n    | \"cp819\"\n    | \"csisolatin1\"\n    | \"ibm819\"\n    | \"iso-8859-1\"\n    | \"iso-ir-100\"\n    | \"iso8859-1\"\n    | \"iso88591\"\n    | \"iso_8859-1\"\n    | \"iso_8859-1:1987\"\n    | \"l1\"\n    | \"latin1\"\n    | \"us-ascii\"\n    | \"x-cp1252\";\n  type WithImplicitCoercion<T> =\n    | T\n    | {\n        valueOf(): T;\n      };\n  interface BufferConstructor {\n    /**\n     * Returns the byte length of a string when encoded using `encoding`.\n     * This is not the same as [`String.prototype.length`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length), which does not account\n     * for the encoding that is used to convert the string into bytes.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const str = '\\u00bd + \\u00bc = \\u00be';\n     *\n     * console.log(`${str}: ${str.length} characters, ` +\n     *             `${Buffer.byteLength(str, 'utf8')} bytes`);\n     * // Prints: ½ + ¼ = ¾: 9 characters, 12 bytes\n     * ```\n     *\n     * When `string` is a\n     * `Buffer`/[`DataView`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView)/[`TypedArray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/-\n     * Reference/Global_Objects/TypedArray)/[`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer)/[`SharedArrayBuffer`](https://develop-\n     * er.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer), the byte length as reported by `.byteLength`is returned.\n     * @param string A value to calculate the length of.\n     * @param [encoding='utf8'] If `string` is a string, this is its encoding.\n     * @return The number of bytes contained within `string`.\n     */\n    byteLength(\n      string:\n        | string\n        | Buffer\n        | QuickJS.ArrayBufferView\n        | ArrayBuffer\n        | SharedArrayBuffer,\n      encoding?: BufferEncoding\n    ): number;\n    /**\n     * Returns a new `Buffer` which is the result of concatenating all the `Buffer` instances in the `list` together.\n     *\n     * If the list has no items, or if the `totalLength` is 0, then a new zero-length `Buffer` is returned.\n     *\n     * If `totalLength` is not provided, it is calculated from the `Buffer` instances\n     * in `list` by adding their lengths.\n     *\n     * If `totalLength` is provided, it is coerced to an unsigned integer. If the\n     * combined length of the `Buffer`s in `list` exceeds `totalLength`, the result is\n     * truncated to `totalLength`.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * // Create a single `Buffer` from a list of three `Buffer` instances.\n     *\n     * const buf1 = Buffer.alloc(10);\n     * const buf2 = Buffer.alloc(14);\n     * const buf3 = Buffer.alloc(18);\n     * const totalLength = buf1.length + buf2.length + buf3.length;\n     *\n     * console.log(totalLength);\n     * // Prints: 42\n     *\n     * const bufA = Buffer.concat([buf1, buf2, buf3], totalLength);\n     *\n     * console.log(bufA);\n     * // Prints: <Buffer 00 00 00 00 ...>\n     * console.log(bufA.length);\n     * // Prints: 42\n     * ```\n     *\n     * @param list List of `Buffer` or {@link Uint8Array} instances to concatenate.\n     * @param totalLength Total length of the `Buffer` instances in `list` when concatenated.\n     */\n    concat(list: readonly Uint8Array[], totalLength?: number): Buffer;\n    /**\n     * Allocates a new `Buffer` using an `array` of bytes in the range `0` – `255`.\n     */\n    from(\n      arrayBuffer: WithImplicitCoercion<ArrayBuffer | SharedArrayBuffer>,\n      byteOffset?: number,\n      length?: number\n    ): Buffer;\n    /**\n     * Creates a new Buffer using the passed {data}\n     * @param data data to create a new Buffer\n     */\n    from(data: Uint8Array | readonly number[]): Buffer;\n    from(\n      data: WithImplicitCoercion<Uint8Array | readonly number[] | string>\n    ): Buffer;\n    /**\n     * Creates a new Buffer containing the given JavaScript string {str}.\n     * If provided, the {encoding} parameter identifies the character encoding.\n     * If not provided, {encoding} defaults to 'utf8'.\n     */\n    from(\n      str:\n        | WithImplicitCoercion<string>\n        | {\n            [Symbol.toPrimitive](hint: \"string\"): string;\n          },\n      encoding?: BufferEncoding\n    ): Buffer;\n    /**\n     * Returns `true` if `obj` is a `Buffer`, `false` otherwise.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * Buffer.isBuffer(Buffer.alloc(10)); // true\n     * Buffer.isBuffer(Buffer.from('foo')); // true\n     * Buffer.isBuffer('a string'); // false\n     * Buffer.isBuffer([]); // false\n     * Buffer.isBuffer(new Uint8Array(1024)); // false\n     * ```\n     */\n    isBuffer(obj: any): obj is Buffer;\n    /**\n     * Returns `true` if `encoding` is the name of a supported character encoding,\n     * or `false` otherwise.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * console.log(Buffer.isEncoding('utf8'));\n     * // Prints: true\n     *\n     * console.log(Buffer.isEncoding('hex'));\n     * // Prints: true\n     *\n     * console.log(Buffer.isEncoding('utf/8'));\n     * // Prints: false\n     *\n     * console.log(Buffer.isEncoding(''));\n     * // Prints: false\n     * ```\n     * @param encoding A character encoding name to check.\n     */\n    isEncoding(encoding: string): encoding is BufferEncoding;\n    /**\n     * Allocates a new `Buffer` of `size` bytes. If `fill` is `undefined`, the `Buffer` will be zero-filled.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.alloc(5);\n     *\n     * console.log(buf);\n     * // Prints: <Buffer 00 00 00 00 00>\n     * ```\n     *\n     * If `fill` is specified, the allocated `Buffer` will be initialized by calling `Buffer.alloc(size, fill)`.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.alloc(5, 'a');\n     *\n     * console.log(buf);\n     * // Prints: <Buffer 61 61 61 61 61>\n     * ```\n     *\n     * If both `fill` and `encoding` are specified, the allocated `Buffer` will be\n     * initialized by calling `Buffer.aloc(size, fill, encoding)`.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.alloc(11, 'aGVsbG8gd29ybGQ=', 'base64');\n     *\n     * console.log(buf);\n     * // Prints: <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>\n     * ```\n     *\n     * @param size The desired length of the new `Buffer`.\n     * @param [fill=0] A value to pre-fill the new `Buffer` with.\n     * @param [encoding='utf8'] If `fill` is a string, this is its encoding.\n     */\n    alloc(\n      size: number,\n      fill?: string | Uint8Array | number,\n      encoding?: BufferEncoding\n    ): Buffer;\n    /**\n     * Allocates a new `Buffer` of `size` bytes.\n     *\n     * The underlying memory for `Buffer` instances created in this way is _not_\n     * _initialized_. The contents of the newly created `Buffer` are unknown and _may contain sensitive data_. Use `Buffer.alloc()` instead to initialize`Buffer` instances with zeroes.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.allocUnsafe(10);\n     *\n     * console.log(buf);\n     * // Prints (contents may vary): <Buffer a0 8b 28 3f 01 00 00 00 50 32>\n     *\n     * buf.fill(0);\n     *\n     * console.log(buf);\n     * // Prints: <Buffer 00 00 00 00 00 00 00 00 00 00>\n     * ```\n     *\n     * A `TypeError` will be thrown if `size` is not a number.\n     *\n     * @param size The desired length of the new `Buffer`.\n     */\n    allocUnsafe(size: number): Buffer;\n    /**\n     * Allocates a new `Buffer` of `size` bytes.\n     *\n     * The underlying memory for `Buffer` instances created in this way is _not_\n     * _initialized_. The contents of the newly created `Buffer` are unknown and _may contain sensitive data_. Use `buf.fill(0)` to initialize\n     * such `Buffer` instances with zeroes.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * // Need to keep around a few small chunks of memory.\n     * const store = [];\n     *\n     * socket.on('readable', () => {\n     *   let data;\n     *   while (null !== (data = readable.read())) {\n     *     // Allocate for retained data.\n     *     const sb = Buffer.allocUnsafeSlow(10);\n     *\n     *     // Copy the data into the new allocation.\n     *     data.copy(sb, 0, 0, 10);\n     *\n     *     store.push(sb);\n     *   }\n     * });\n     * ```\n     *\n     * A `TypeError` will be thrown if `size` is not a number.\n     *\n     * @param size The desired length of the new `Buffer`.\n     */\n    allocUnsafeSlow(size: number): Buffer;\n  }\n  interface Buffer extends Uint8Array {\n    /**\n     * Writes `string` to `buf` at `offset` according to the character encoding in`encoding`. The `length` parameter is the number of bytes to write. If `buf` did\n     * not contain enough space to fit the entire string, only part of `string` will be\n     * written. However, partially encoded characters will not be written.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.alloc(256);\n     *\n     * const len = buf.write('\\u00bd + \\u00bc = \\u00be', 0);\n     *\n     * console.log(`${len} bytes: ${buf.toString('utf8', 0, len)}`);\n     * // Prints: 12 bytes: ½ + ¼ = ¾\n     *\n     * const buffer = Buffer.alloc(10);\n     *\n     * const length = buffer.write('abcd', 8);\n     *\n     * console.log(`${length} bytes: ${buffer.toString('utf8', 8, 10)}`);\n     * // Prints: 2 bytes : ab\n     * ```\n     * @param string String to write to `buf`.\n     * @param [offset=0] Number of bytes to skip before starting to write `string`.\n     * @param [length=buf.length - offset] Maximum number of bytes to write (written bytes will not exceed `buf.length - offset`).\n     * @param [encoding='utf8'] The character encoding of `string`.\n     * @return Number of bytes written.\n     */\n    write(string: string, encoding?: BufferEncoding): number;\n    write(string: string, offset: number, encoding?: BufferEncoding): number;\n    write(\n      string: string,\n      offset: number,\n      length: number,\n      encoding?: BufferEncoding\n    ): number;\n    /**\n     * Decodes `buf` to a string according to the specified character encoding in`encoding`. `start` and `end` may be passed to decode only a subset of `buf`.\n     *\n     * If `encoding` is `'utf8'` and a byte sequence in the input is not valid UTF-8,\n     * then each invalid byte is replaced with the replacement character `U+FFFD`.\n     *\n     * ```js\n     * import { Buffer } from 'node:buffer';\n     *\n     * const buf1 = Buffer.allocUnsafe(26);\n     *\n     * for (let i = 0; i < 26; i++) {\n     *   // 97 is the decimal ASCII value for 'a'.\n     *   buf1[i] = i + 97;\n     * }\n     *\n     * console.log(buf1.toString('utf8'));\n     * // Prints: abcdefghijklmnopqrstuvwxyz\n     * console.log(buf1.toString('utf8', 0, 5));\n     * // Prints: abcde\n     *\n     * const buf2 = Buffer.from('tést');\n     *\n     * console.log(buf2.toString('hex'));\n     * // Prints: 74c3a97374\n     * console.log(buf2.toString('utf8', 0, 3));\n     * // Prints: té\n     * console.log(buf2.toString(undefined, 0, 3));\n     * // Prints: té\n     * ```\n     * @param [encoding='utf8'] The character encoding to use.\n     * @param [start=0] The byte offset to start decoding at.\n     * @param [end=buf.length] The byte offset to stop decoding at (not inclusive).\n     */\n    toString(encoding?: BufferEncoding, start?: number, end?: number): string;\n    /**\n     * Copies data from a region of `buf` to a region in `target`, even if the `target`memory region overlaps with `buf`.\n     *\n     * [`TypedArray.prototype.set()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/set) performs the same operation, and is available\n     * for all TypedArrays, including `Buffer`s, although it takes\n     * different function arguments.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * // Create two `Buffer` instances.\n     * const buf1 = Buffer.allocUnsafe(26);\n     * const buf2 = Buffer.allocUnsafe(26).fill('!');\n     *\n     * for (let i = 0; i < 26; i++) {\n     *   // 97 is the decimal ASCII value for 'a'.\n     *   buf1[i] = i + 97;\n     * }\n     *\n     * // Copy `buf1` bytes 16 through 19 into `buf2` starting at byte 8 of `buf2`.\n     * buf1.copy(buf2, 8, 16, 20);\n     * // This is equivalent to:\n     * // buf2.set(buf1.subarray(16, 20), 8);\n     *\n     * console.log(buf2.toString('ascii', 0, 25));\n     * // Prints: !!!!!!!!qrst!!!!!!!!!!!!!\n     * ```\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * // Create a `Buffer` and copy data from one region to an overlapping region\n     * // within the same `Buffer`.\n     *\n     * const buf = Buffer.allocUnsafe(26);\n     *\n     * for (let i = 0; i < 26; i++) {\n     *   // 97 is the decimal ASCII value for 'a'.\n     *   buf[i] = i + 97;\n     * }\n     *\n     * buf.copy(buf, 0, 4, 10);\n     *\n     * console.log(buf.toString());\n     * // Prints: efghijghijklmnopqrstuvwxyz\n     * ```\n     * @param target A `Buffer` or {@link Uint8Array} to copy into.\n     * @param [targetStart=0] The offset within `target` at which to begin writing.\n     * @param [sourceStart=0] The offset within `buf` from which to begin copying.\n     * @param [sourceEnd=buf.length] The offset within `buf` at which to stop copying (not inclusive).\n     * @return The number of bytes copied.\n     */\n    copy(\n      target: Uint8Array,\n      targetStart?: number,\n      sourceStart?: number,\n      sourceEnd?: number\n    ): number;\n    /**\n     * Returns a new `Buffer` that references the same memory as the original, but\n     * offset and cropped by the `start` and `end` indices.\n     *\n     * Specifying `end` greater than `buf.length` will return the same result as\n     * that of `end` equal to `buf.length`.\n     *\n     * This method is inherited from [`TypedArray.prototype.subarray()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/subarray).\n     *\n     * Modifying the new `Buffer` slice will modify the memory in the original `Buffer`because the allocated memory of the two objects overlap.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * // Create a `Buffer` with the ASCII alphabet, take a slice, and modify one byte\n     * // from the original `Buffer`.\n     *\n     * const buf1 = Buffer.alloc(26);\n     *\n     * for (let i = 0; i < 26; i++) {\n     *   // 97 is the decimal ASCII value for 'a'.\n     *   buf1[i] = i + 97;\n     * }\n     *\n     * const buf2 = buf1.subarray(0, 3);\n     *\n     * console.log(buf2.toString('ascii', 0, buf2.length));\n     * // Prints: abc\n     *\n     * buf1[0] = 33;\n     *\n     * console.log(buf2.toString('ascii', 0, buf2.length));\n     * // Prints: !bc\n     * ```\n     *\n     * Specifying negative indexes causes the slice to be generated relative to the\n     * end of `buf` rather than the beginning.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.from('buffer');\n     *\n     * console.log(buf.subarray(-6, -1).toString());\n     * // Prints: buffe\n     * // (Equivalent to buf.subarray(0, 5).)\n     *\n     * console.log(buf.subarray(-6, -2).toString());\n     * // Prints: buff\n     * // (Equivalent to buf.subarray(0, 4).)\n     *\n     * console.log(buf.subarray(-5, -2).toString());\n     * // Prints: uff\n     * // (Equivalent to buf.subarray(1, 4).)\n     * ```\n     * @param [start=0] Where the new `Buffer` will start.\n     * @param [end=buf.length] Where the new `Buffer` will end (not inclusive).\n     */\n    subarray(start?: number, end?: number): Buffer;\n    /**\n     * Writes `value` to `buf` at the specified `offset` as big-endian.\n     *\n     * `value` is interpreted and written as a two's complement signed integer.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.allocUnsafe(8);\n     *\n     * buf.writeBigInt64BE(0x0102030405060708n, 0);\n     *\n     * console.log(buf);\n     * // Prints: <Buffer 01 02 03 04 05 06 07 08>\n     * ```\n     * @param value Number to be written to `buf`.\n     * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy: `0 <= offset <= buf.length - 8`.\n     * @return `offset` plus the number of bytes written.\n     */\n    writeBigInt64BE(value: bigint, offset?: number): number;\n    /**\n     * @alias Buffer.writeBigUInt64BE\n     */\n    writeBigUint64BE(value: bigint, offset?: number): number;\n    /**\n     * Writes `value` to `buf` at the specified `offset` as little-endian.\n     *\n     * `value` is interpreted and written as a two's complement signed integer.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.allocUnsafe(8);\n     *\n     * buf.writeBigInt64LE(0x0102030405060708n, 0);\n     *\n     * console.log(buf);\n     * // Prints: <Buffer 08 07 06 05 04 03 02 01>\n     * ```\n     * @param value Number to be written to `buf`.\n     * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy: `0 <= offset <= buf.length - 8`.\n     * @return `offset` plus the number of bytes written.\n     */\n    writeBigInt64LE(value: bigint, offset?: number): number;\n    /**\n     * @alias Buffer.writeBigUInt64LE\n     */\n    writeBigUint64LE(value: bigint, offset?: number): number;\n    /**\n     * Reads an unsigned, big-endian 64-bit integer from `buf` at the specified`offset`.\n     *\n     * This function is also available under the `readBigUint64BE` alias.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.from([0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff]);\n     *\n     * console.log(buf.readBigUInt64BE(0));\n     * // Prints: 4294967295n\n     * ```\n     * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy: `0 <= offset <= buf.length - 8`.\n     */\n    readBigUInt64BE(offset?: number): bigint;\n    /**\n     * @alias Buffer.readBigUInt64BE\n     */\n    readBigUint64BE(offset?: number): bigint;\n    /**\n     * Reads an unsigned, little-endian 64-bit integer from `buf` at the specified`offset`.\n     *\n     * This function is also available under the `readBigUint64LE` alias.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.from([0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff]);\n     *\n     * console.log(buf.readBigUInt64LE(0));\n     * // Prints: 18446744069414584320n\n     * ```\n     * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy: `0 <= offset <= buf.length - 8`.\n     */\n    readBigUInt64LE(offset?: number): bigint;\n    /**\n     * @alias Buffer.readBigUInt64LE\n     */\n    readBigUint64LE(offset?: number): bigint;\n    /**\n     * Reads a signed, big-endian 64-bit integer from `buf` at the specified `offset`.\n     *\n     * Integers read from a `Buffer` are interpreted as two's complement signed\n     * values.\n     * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy: `0 <= offset <= buf.length - 8`.\n     */\n    readBigInt64BE(offset?: number): bigint;\n    /**\n     * Reads a signed, little-endian 64-bit integer from `buf` at the specified`offset`.\n     *\n     * Integers read from a `Buffer` are interpreted as two's complement signed\n     * values.\n     * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy: `0 <= offset <= buf.length - 8`.\n     */\n    readBigInt64LE(offset?: number): bigint;\n    /**\n     * Reads an unsigned 8-bit integer from `buf` at the specified `offset`.\n     *\n     * This function is also available under the `readUint8` alias.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.from([1, -2]);\n     *\n     * console.log(buf.readUInt8(0));\n     * // Prints: 1\n     * console.log(buf.readUInt8(1));\n     * // Prints: 254\n     * console.log(buf.readUInt8(2));\n     * // Throws ERR_OUT_OF_RANGE.\n     * ```\n     * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 1`.\n     */\n    readUInt8(offset?: number): number;\n    /**\n     * @alias Buffer.readUInt8\n     */\n    readUint8(offset?: number): number;\n    /**\n     * Reads an unsigned, little-endian 16-bit integer from `buf` at the specified `offset`.\n     *\n     * This function is also available under the `readUint16LE` alias.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.from([0x12, 0x34, 0x56]);\n     *\n     * console.log(buf.readUInt16LE(0).toString(16));\n     * // Prints: 3412\n     * console.log(buf.readUInt16LE(1).toString(16));\n     * // Prints: 5634\n     * console.log(buf.readUInt16LE(2).toString(16));\n     * // Throws ERR_OUT_OF_RANGE.\n     * ```\n     * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 2`.\n     */\n    readUInt16LE(offset?: number): number;\n    /**\n     * @alias Buffer.readUInt16LE\n     */\n    readUint16LE(offset?: number): number;\n    /**\n     * Reads an unsigned, big-endian 16-bit integer from `buf` at the specified`offset`.\n     *\n     * This function is also available under the `readUint16BE` alias.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.from([0x12, 0x34, 0x56]);\n     *\n     * console.log(buf.readUInt16BE(0).toString(16));\n     * // Prints: 1234\n     * console.log(buf.readUInt16BE(1).toString(16));\n     * // Prints: 3456\n     * ```\n     * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 2`.\n     */\n    readUInt16BE(offset?: number): number;\n    /**\n     * @alias Buffer.readUInt16BE\n     */\n    readUint16BE(offset?: number): number;\n    /**\n     * Reads an unsigned, little-endian 32-bit integer from `buf` at the specified`offset`.\n     *\n     * This function is also available under the `readUint32LE` alias.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.from([0x12, 0x34, 0x56, 0x78]);\n     *\n     * console.log(buf.readUInt32LE(0).toString(16));\n     * // Prints: 78563412\n     * console.log(buf.readUInt32LE(1).toString(16));\n     * // Throws ERR_OUT_OF_RANGE.\n     * ```\n     * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 4`.\n     */\n    readUInt32LE(offset?: number): number;\n    /**\n     * @alias Buffer.readUInt32LE\n     */\n    readUint32LE(offset?: number): number;\n    /**\n     * Reads a signed 8-bit integer from `buf` at the specified `offset`.\n     *\n     * Integers read from a `Buffer` are interpreted as two's complement signed values.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.from([-1, 5]);\n     *\n     * console.log(buf.readInt8(0));\n     * // Prints: -1\n     * console.log(buf.readInt8(1));\n     * // Prints: 5\n     * console.log(buf.readInt8(2));\n     * // Throws ERR_OUT_OF_RANGE.\n     * ```\n     * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 1`.\n     */\n    readInt8(offset?: number): number;\n    /**\n     * Reads a signed, little-endian 16-bit integer from `buf` at the specified`offset`.\n     *\n     * Integers read from a `Buffer` are interpreted as two's complement signed values.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.from([0, 5]);\n     *\n     * console.log(buf.readInt16LE(0));\n     * // Prints: 1280\n     * console.log(buf.readInt16LE(1));\n     * // Throws ERR_OUT_OF_RANGE.\n     * ```\n     * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 2`.\n     */\n    readInt16LE(offset?: number): number;\n    /**\n     * Reads a signed, big-endian 16-bit integer from `buf` at the specified `offset`.\n     *\n     * Integers read from a `Buffer` are interpreted as two's complement signed values.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.from([0, 5]);\n     *\n     * console.log(buf.readInt16BE(0));\n     * // Prints: 5\n     * ```\n     * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 2`.\n     */\n    readInt16BE(offset?: number): number;\n    /**\n     * Reads a signed, little-endian 32-bit integer from `buf` at the specified`offset`.\n     *\n     * Integers read from a `Buffer` are interpreted as two's complement signed values.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.from([0, 0, 0, 5]);\n     *\n     * console.log(buf.readInt32LE(0));\n     * // Prints: 83886080\n     * console.log(buf.readInt32LE(1));\n     * // Throws ERR_OUT_OF_RANGE.\n     * ```\n     * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 4`.\n     */\n    readInt32LE(offset?: number): number;\n    /**\n     * Reads a signed, big-endian 32-bit integer from `buf` at the specified `offset`.\n     *\n     * Integers read from a `Buffer` are interpreted as two's complement signed values.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.from([0, 0, 0, 5]);\n     *\n     * console.log(buf.readInt32BE(0));\n     * // Prints: 5\n     * ```\n     * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 4`.\n     */\n    readInt32BE(offset?: number): number;\n    /**\n     * Reads a 32-bit, little-endian float from `buf` at the specified `offset`.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.from([1, 2, 3, 4]);\n     *\n     * console.log(buf.readFloatLE(0));\n     * // Prints: 1.539989614439558e-36\n     * console.log(buf.readFloatLE(1));\n     * // Throws ERR_OUT_OF_RANGE.\n     * ```\n     * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 4`.\n     */\n    readFloatLE(offset?: number): number;\n    /**\n     * Reads a 32-bit, big-endian float from `buf` at the specified `offset`.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.from([1, 2, 3, 4]);\n     *\n     * console.log(buf.readFloatBE(0));\n     * // Prints: 2.387939260590663e-38\n     * ```\n     * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 4`.\n     */\n    readFloatBE(offset?: number): number;\n    /**\n     * Reads a 64-bit, little-endian double from `buf` at the specified `offset`.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]);\n     *\n     * console.log(buf.readDoubleLE(0));\n     * // Prints: 5.447603722011605e-270\n     * console.log(buf.readDoubleLE(1));\n     * // Throws ERR_OUT_OF_RANGE.\n     * ```\n     * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 8`.\n     */\n    readDoubleLE(offset?: number): number;\n    /**\n     * Reads a 64-bit, big-endian double from `buf` at the specified `offset`.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]);\n     *\n     * console.log(buf.readDoubleBE(0));\n     * // Prints: 8.20788039913184e-304\n     * ```\n     * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 8`.\n     */\n    readDoubleBE(offset?: number): number;\n    /**\n     * Writes `value` to `buf` at the specified `offset`. `value` must be a\n     * valid unsigned 8-bit integer. Behavior is undefined when `value` is anything\n     * other than an unsigned 8-bit integer.\n     *\n     * This function is also available under the `writeUint8` alias.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.allocUnsafe(4);\n     *\n     * buf.writeUInt8(0x3, 0);\n     * buf.writeUInt8(0x4, 1);\n     * buf.writeUInt8(0x23, 2);\n     * buf.writeUInt8(0x42, 3);\n     *\n     * console.log(buf);\n     * // Prints: <Buffer 03 04 23 42>\n     * ```\n     * @param value Number to be written to `buf`.\n     * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 1`.\n     * @return `offset` plus the number of bytes written.\n     */\n    writeUInt8(value: number, offset?: number): number;\n    /**\n     * @alias Buffer.writeUInt8\n     */\n    writeUint8(value: number, offset?: number): number;\n    /**\n     * Writes `value` to `buf` at the specified `offset` as little-endian. The `value` must be a valid unsigned 16-bit integer. Behavior is undefined when `value` is\n     * anything other than an unsigned 16-bit integer.\n     *\n     * This function is also available under the `writeUint16LE` alias.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.allocUnsafe(4);\n     *\n     * buf.writeUInt16LE(0xdead, 0);\n     * buf.writeUInt16LE(0xbeef, 2);\n     *\n     * console.log(buf);\n     * // Prints: <Buffer ad de ef be>\n     * ```\n     * @param value Number to be written to `buf`.\n     * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 2`.\n     * @return `offset` plus the number of bytes written.\n     */\n    writeUInt16LE(value: number, offset?: number): number;\n    /**\n     * @alias Buffer.writeUInt16LE\n     */\n    writeUint16LE(value: number, offset?: number): number;\n    /**\n     * Writes `value` to `buf` at the specified `offset` as big-endian. The `value` must be a valid unsigned 16-bit integer. Behavior is undefined when `value`is anything other than an\n     * unsigned 16-bit integer.\n     *\n     * This function is also available under the `writeUint16BE` alias.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.allocUnsafe(4);\n     *\n     * buf.writeUInt16BE(0xdead, 0);\n     * buf.writeUInt16BE(0xbeef, 2);\n     *\n     * console.log(buf);\n     * // Prints: <Buffer de ad be ef>\n     * ```\n     * @param value Number to be written to `buf`.\n     * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 2`.\n     * @return `offset` plus the number of bytes written.\n     */\n    writeUInt16BE(value: number, offset?: number): number;\n    /**\n     * @alias Buffer.writeUInt16BE\n     */\n    writeUint16BE(value: number, offset?: number): number;\n    /**\n     * Writes `value` to `buf` at the specified `offset` as little-endian. The `value` must be a valid unsigned 32-bit integer. Behavior is undefined when `value` is\n     * anything other than an unsigned 32-bit integer.\n     *\n     * This function is also available under the `writeUint32LE` alias.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.allocUnsafe(4);\n     *\n     * buf.writeUInt32LE(0xfeedface, 0);\n     *\n     * console.log(buf);\n     * // Prints: <Buffer ce fa ed fe>\n     * ```\n     * @param value Number to be written to `buf`.\n     * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 4`.\n     * @return `offset` plus the number of bytes written.\n     */\n    writeUInt32LE(value: number, offset?: number): number;\n    /**\n     * @alias Buffer.writeUInt32LE\n     */\n    writeUint32LE(value: number, offset?: number): number;\n    /**\n     * Writes `value` to `buf` at the specified `offset` as big-endian. The `value` must be a valid unsigned 32-bit integer. Behavior is undefined when `value`is anything other than an\n     * unsigned 32-bit integer.\n     *\n     * This function is also available under the `writeUint32BE` alias.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.allocUnsafe(4);\n     *\n     * buf.writeUInt32BE(0xfeedface, 0);\n     *\n     * console.log(buf);\n     * // Prints: <Buffer fe ed fa ce>\n     * ```\n     * @param value Number to be written to `buf`.\n     * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 4`.\n     * @return `offset` plus the number of bytes written.\n     */\n    writeUInt32BE(value: number, offset?: number): number;\n    /**\n     * @alias Buffer.writeUInt32BE\n     */\n    writeUint32BE(value: number, offset?: number): number;\n    /**\n     * Writes `value` to `buf` at the specified `offset`. `value` must be a valid\n     * signed 8-bit integer. Behavior is undefined when `value` is anything other than\n     * a signed 8-bit integer.\n     *\n     * `value` is interpreted and written as a two's complement signed integer.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.allocUnsafe(2);\n     *\n     * buf.writeInt8(2, 0);\n     * buf.writeInt8(-2, 1);\n     *\n     * console.log(buf);\n     * // Prints: <Buffer 02 fe>\n     * ```\n     * @param value Number to be written to `buf`.\n     * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 1`.\n     * @return `offset` plus the number of bytes written.\n     */\n    writeInt8(value: number, offset?: number): number;\n    /**\n     * Writes `value` to `buf` at the specified `offset` as little-endian.  The `value` must be a valid signed 16-bit integer. Behavior is undefined when `value` is\n     * anything other than a signed 16-bit integer.\n     *\n     * The `value` is interpreted and written as a two's complement signed integer.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.allocUnsafe(2);\n     *\n     * buf.writeInt16LE(0x0304, 0);\n     *\n     * console.log(buf);\n     * // Prints: <Buffer 04 03>\n     * ```\n     * @param value Number to be written to `buf`.\n     * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 2`.\n     * @return `offset` plus the number of bytes written.\n     */\n    writeInt16LE(value: number, offset?: number): number;\n    /**\n     * Writes `value` to `buf` at the specified `offset` as big-endian.  The `value` must be a valid signed 16-bit integer. Behavior is undefined when `value` is\n     * anything other than a signed 16-bit integer.\n     *\n     * The `value` is interpreted and written as a two's complement signed integer.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.allocUnsafe(2);\n     *\n     * buf.writeInt16BE(0x0102, 0);\n     *\n     * console.log(buf);\n     * // Prints: <Buffer 01 02>\n     * ```\n     * @param value Number to be written to `buf`.\n     * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 2`.\n     * @return `offset` plus the number of bytes written.\n     */\n    writeInt16BE(value: number, offset?: number): number;\n    /**\n     * Writes `value` to `buf` at the specified `offset` as little-endian. The `value` must be a valid signed 32-bit integer. Behavior is undefined when `value` is\n     * anything other than a signed 32-bit integer.\n     *\n     * The `value` is interpreted and written as a two's complement signed integer.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.allocUnsafe(4);\n     *\n     * buf.writeInt32LE(0x05060708, 0);\n     *\n     * console.log(buf);\n     * // Prints: <Buffer 08 07 06 05>\n     * ```\n     * @param value Number to be written to `buf`.\n     * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 4`.\n     * @return `offset` plus the number of bytes written.\n     */\n    writeInt32LE(value: number, offset?: number): number;\n    /**\n     * Writes `value` to `buf` at the specified `offset` as big-endian. The `value` must be a valid signed 32-bit integer. Behavior is undefined when `value` is\n     * anything other than a signed 32-bit integer.\n     *\n     * The `value` is interpreted and written as a two's complement signed integer.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.allocUnsafe(4);\n     *\n     * buf.writeInt32BE(0x01020304, 0);\n     *\n     * console.log(buf);\n     * // Prints: <Buffer 01 02 03 04>\n     * ```\n     * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 4`.\n     * @return `offset` plus the number of bytes written.\n     */\n    writeInt32BE(value: number, offset?: number): number;\n    /**\n     * Writes `value` to `buf` at the specified `offset` as little-endian. Behavior is\n     * undefined when `value` is anything other than a JavaScript number.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.allocUnsafe(4);\n     *\n     * buf.writeFloatLE(0xcafebabe, 0);\n     *\n     * console.log(buf);\n     * // Prints: <Buffer bb fe 4a 4f>\n     * ```\n     * @param value Number to be written to `buf`.\n     * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 4`.\n     * @return `offset` plus the number of bytes written.\n     */\n    writeFloatLE(value: number, offset?: number): number;\n    /**\n     * Writes `value` to `buf` at the specified `offset` as big-endian. Behavior is\n     * undefined when `value` is anything other than a JavaScript number.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.allocUnsafe(4);\n     *\n     * buf.writeFloatBE(0xcafebabe, 0);\n     *\n     * console.log(buf);\n     * // Prints: <Buffer 4f 4a fe bb>\n     * ```\n     * @param value Number to be written to `buf`.\n     * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 4`.\n     * @return `offset` plus the number of bytes written.\n     */\n    writeFloatBE(value: number, offset?: number): number;\n    /**\n     * Writes `value` to `buf` at the specified `offset` as little-endian. The `value` must be a JavaScript number. Behavior is undefined when `value` is anything\n     * other than a JavaScript number.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.allocUnsafe(8);\n     *\n     * buf.writeDoubleLE(123.456, 0);\n     *\n     * console.log(buf);\n     * // Prints: <Buffer 77 be 9f 1a 2f dd 5e 40>\n     * ```\n     * @param value Number to be written to `buf`.\n     * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 8`.\n     * @return `offset` plus the number of bytes written.\n     */\n    writeDoubleLE(value: number, offset?: number): number;\n    /**\n     * Writes `value` to `buf` at the specified `offset` as big-endian. The `value` must be a JavaScript number. Behavior is undefined when `value` is anything\n     * other than a JavaScript number.\n     *\n     * ```js\n     * import { Buffer } from 'buffer';\n     *\n     * const buf = Buffer.allocUnsafe(8);\n     *\n     * buf.writeDoubleBE(123.456, 0);\n     *\n     * console.log(buf);\n     * // Prints: <Buffer 40 5e dd 2f 1a 9f be 77>\n     * ```\n     * @param value Number to be written to `buf`.\n     * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 8`.\n     * @return `offset` plus the number of bytes written.\n     */\n    writeDoubleBE(value: number, offset?: number): number;\n  }\n  var Buffer: BufferConstructor;\n  /**\n   * Decodes a string of Base64-encoded data into bytes, and encodes those bytes\n   * into a string using UTF-8.\n   *\n   * The `data` may be any JavaScript-value that can be coerced into a string.\n   *\n   * @legacy Use `Buffer.from(data, 'base64')` instead.\n   * @param data The Base64-encoded input string.\n   */\n  function atob(data: string): string;\n  /**\n   * Decodes a string into bytes using UTF-8, and encodes those bytes\n   * into a string using Base64.\n   *\n   * The `data` may be any JavaScript-value that can be coerced into a string.\n   *\n   * @legacy Use `buf.toString('base64')` instead.\n   * @param data An ASCII (Latin1) string.\n   */\n  function btoa(data: string): string;\n\n  export { Buffer, atob, btoa };\n}\n"
  },
  {
    "path": "types/child_process.d.ts",
    "content": "declare module \"child_process\" {\n  import { EventEmitter } from \"events\";\n  import {\n    DefaultReadableStream as Readable,\n    DefaultWritableStream as Writable,\n  } from \"stream\";\n\n  /**\n   * Instances of the `ChildProcess` represent spawned child processes.\n   *\n   * Instances of `ChildProcess` are not intended to be created directly. Rather,\n   * use the {@link spawn} method to create instances of `ChildProcess`.\n   */\n  class ChildProcess extends EventEmitter {\n    /**\n     * A `Writable Stream` that represents the child process's `stdin`.\n     *\n     * If a child process waits to read all of its input, the child will not continue\n     * until this stream has been closed via `end()`.\n     *\n     * If the child was spawned with `stdio[0]` set to anything other than `'pipe'`,\n     * then this will be `null`.\n     *\n     * `subprocess.stdin` is an alias for `subprocess.stdio[0]`. Both properties will\n     * refer to the same value.\n     *\n     * The `subprocess.stdin` property can be `null` or `undefined` if the child process could not be successfully spawned.\n     */\n    stdin: Writable | null;\n\n    /**\n     * A `Readable Stream` that represents the child process's `stdout`.\n     *\n     * If the child was spawned with `stdio[1]` set to anything other than `'pipe'`,\n     * then this will be `null`.\n     *\n     * `subprocess.stdout` is an alias for `subprocess.stdio[1]`. Both properties will\n     * refer to the same value.\n     *\n     * ```js\n     * const { spawn } = require('child_process');\n     *\n     * const subprocess = spawn('ls');\n     *\n     * subprocess.stdout.on('data', (data) => {\n     *   console.log(`Received chunk ${data}`);\n     * });\n     * ```\n     *\n     * The `subprocess.stdout` property can be `null` or `undefined` if the child process could not be successfully spawned.\n     */\n    stdout: Readable | null;\n\n    /**\n     * A `Readable Stream` that represents the child process's `stderr`.\n     *\n     * If the child was spawned with `stdio[2]` set to anything other than `'pipe'`,\n     * then this will be `null`.\n     *\n     * `subprocess.stderr` is an alias for `subprocess.stdio[2]`. Both properties will\n     * refer to the same value.\n     *\n     * The `subprocess.stderr` property can be `null` or `undefined` if the child process could not be successfully spawned.\n     */\n    stderr: Readable | null;\n\n    /**\n     * Returns the process identifier (PID) of the child process. If the child process\n     * fails to spawn due to errors, then the value is `undefined` and `error` is\n     * emitted.\n     *\n     * ```js\n     * const { spawn } = require('child_process');\n     * const grep = spawn('grep', ['ssh']);\n     *\n     * console.log(`Spawned child pid: ${grep.pid}`);\n     * grep.stdin.end();\n     * ```\n     */\n    readonly pid?: number | undefined;\n\n    /**\n     * The `subprocess.kill()` method sends a signal to the child process. If no\n     * argument is given, the process will be sent the `'SIGTERM'` signal. See [`signal(7)`](http://man7.org/linux/man-pages/man7/signal.7.html) for a list of available signals. This function\n     * returns `true` if [`kill(2)`](http://man7.org/linux/man-pages/man2/kill.2.html) succeeds, and `false` otherwise.\n     *\n     * ```js\n     * const { spawn } = require('child_process');\n     * const grep = spawn('grep', ['ssh']);\n     *\n     * grep.on('close', (code, signal) => {\n     *   console.log(\n     *     `child process terminated due to receipt of signal ${signal}`);\n     * });\n     *\n     * // Send SIGHUP to process.\n     * grep.kill('SIGHUP');\n     * ```\n     *\n     * The `ChildProcess` object may emit an `'error'` event if the signal\n     * cannot be delivered. Sending a signal to a child process that has already exited\n     * is not an error but may have unforeseen consequences. Specifically, if the\n     * process identifier (PID) has been reassigned to another process, the signal will\n     * be delivered to that process instead which can have unexpected results.\n     *\n     * While the function is called `kill`, the signal delivered to the child process\n     * may not actually terminate the process.\n     *\n     * See [`kill(2)`](http://man7.org/linux/man-pages/man2/kill.2.html) for reference.\n     *\n     * On Windows, where POSIX signals do not exist, the `signal` argument will be\n     * ignored, and the process will be killed forcefully and abruptly (similar to `'SIGKILL'`).\n     * See `Signal Events` for more details.\n     *\n     * On Linux, child processes of child processes will not be terminated\n     * when attempting to kill their parent. This is likely to happen when running a\n     * new process in a shell or with the use of the `shell` option of `ChildProcess`:\n     *\n     * ```js\n     * 'use strict';\n     * const { spawn } = require('child_process');\n     *\n     * const subprocess = spawn(\n     *   'sh',\n     *   [\n     *     '-c',\n     *     `node -e \"setInterval(() => {\n     *       console.log(process.pid, 'is alive')\n     *     }, 500);\"`,\n     *   ], {\n     *     stdio: ['inherit', 'inherit', 'inherit'],\n     *   },\n     * );\n     *\n     * setTimeout(() => {\n     *   subprocess.kill(); // Does not terminate the Node.js process in the shell.\n     * }, 2000);\n     * ```\n     */\n    kill(signal?: QuickJS.Signals | number): boolean;\n\n    /**\n     * Calls {@link ChildProcess.kill} with `'SIGTERM'`.\n     */\n    [Symbol.dispose](): void;\n\n    /**\n     * events.EventEmitter\n     * 1. close\n     * 2. error\n     * 3. exit\n     */\n    addListener(event: string, listener: (...args: any[]) => void): this;\n    addListener(\n      event: \"close\",\n      listener: (code: number | null, signal: QuickJS.Signals | null) => void\n    ): this;\n    addListener(event: \"error\", listener: (err: Error) => void): this;\n    addListener(\n      event: \"exit\",\n      listener: (code: number | null, signal: QuickJS.Signals | null) => void\n    ): this;\n    emit(event: string | symbol, ...args: any[]): boolean;\n    emit(\n      event: \"close\",\n      code: number | null,\n      signal: QuickJS.Signals | null\n    ): boolean;\n    emit(event: \"error\", err: Error): boolean;\n    emit(\n      event: \"exit\",\n      code: number | null,\n      signal: QuickJS.Signals | null\n    ): boolean;\n    on(event: string, listener: (...args: any[]) => void): this;\n    on(\n      event: \"close\",\n      listener: (code: number | null, signal: QuickJS.Signals | null) => void\n    ): this;\n    on(event: \"error\", listener: (err: Error) => void): this;\n    on(\n      event: \"exit\",\n      listener: (code: number | null, signal: QuickJS.Signals | null) => void\n    ): this;\n    once(event: string, listener: (...args: any[]) => void): this;\n    once(\n      event: \"close\",\n      listener: (code: number | null, signal: QuickJS.Signals | null) => void\n    ): this;\n    once(event: \"error\", listener: (err: Error) => void): this;\n    once(\n      event: \"exit\",\n      listener: (code: number | null, signal: QuickJS.Signals | null) => void\n    ): this;\n    prependListener(event: string, listener: (...args: any[]) => void): this;\n    prependListener(\n      event: \"close\",\n      listener: (code: number | null, signal: QuickJS.Signals | null) => void\n    ): this;\n    prependListener(event: \"error\", listener: (err: Error) => void): this;\n    prependListener(\n      event: \"exit\",\n      listener: (code: number | null, signal: QuickJS.Signals | null) => void\n    ): this;\n    prependOnceListener(\n      event: string,\n      listener: (...args: any[]) => void\n    ): this;\n    prependOnceListener(\n      event: \"close\",\n      listener: (code: number | null, signal: QuickJS.Signals | null) => void\n    ): this;\n    prependOnceListener(event: \"error\", listener: (err: Error) => void): this;\n    prependOnceListener(\n      event: \"exit\",\n      listener: (code: number | null, signal: QuickJS.Signals | null) => void\n    ): this;\n  }\n  // return this object when stdio option is undefined or not specified\n  interface ChildProcessWithoutNullStreams extends ChildProcess {\n    stdin: Writable;\n    stdout: Readable;\n    stderr: Readable;\n  }\n  // return this object when stdio option is a tuple of 3\n  interface ChildProcessByStdio<\n    I extends null | Writable,\n    O extends null | Readable,\n    E extends null | Readable,\n  > extends ChildProcess {\n    stdin: I;\n    stdout: O;\n    stderr: E;\n  }\n\n  type IOType = \"pipe\" | \"ignore\" | \"inherit\";\n  type StdioOptions = IOType | Array<IOType | number | null | undefined>;\n\n  interface ProcessEnvOptions {\n    uid?: number | undefined;\n    gid?: number | undefined;\n    cwd?: string | undefined;\n  }\n  interface SpawnOptions extends ProcessEnvOptions {\n    /**\n     * Can be set to 'pipe', 'inherit', or 'ignore', or an array of these strings.\n     * If passed as an array, the first element is used for `stdin`, the second for\n     * `stdout`, and the third for `stderr`.\n     *\n     * @default 'pipe'\n     */\n    stdio?: StdioOptions | undefined;\n    shell?: boolean | string | undefined;\n    windowsVerbatimArguments?: boolean | undefined;\n  }\n  interface SpawnOptionsWithoutStdio extends SpawnOptions {\n    stdio?: StdioPipeNamed | StdioPipe[] | undefined;\n  }\n  type StdioNull = \"inherit\" | \"ignore\";\n  type StdioPipeNamed = \"pipe\";\n  type StdioPipe = undefined | null | StdioPipeNamed;\n  interface SpawnOptionsWithStdioTuple<\n    Stdin extends StdioNull | StdioPipe,\n    Stdout extends StdioNull | StdioPipe,\n    Stderr extends StdioNull | StdioPipe,\n  > extends SpawnOptions {\n    stdio: [Stdin, Stdout, Stderr];\n  }\n\n  /**\n   * The `child_process.spawn()` method spawns a new process using the given `command`, with command-line arguments in `args`.\n   * If omitted, `args` defaults to an empty array.\n   *\n   * **If the `shell` option is enabled, do not pass unsanitized user input to this**\n   * **function. Any input containing shell metacharacters may be used to trigger**\n   * **arbitrary command execution.**\n   *\n   * A third argument may be used to specify additional options.\n   *\n   * Use `cwd` to specify the working directory from which the process is spawned.\n   * If not given, the default is to inherit the current working directory. If given,\n   * but the path does not exist, the child process emits an `ENOENT` error\n   * and exits immediately. `ENOENT` is also emitted when the command\n   * does not exist.\n   *\n   * Example of running `ls -lh /usr`, capturing `stdout`, `stderr`, and the\n   * exit code:\n   *\n   * ```js\n   * const { spawn } = require('child_process');\n   * const ls = spawn('ls', ['-lh', '/usr']);\n   *\n   * ls.stdout.on('data', (data) => {\n   *   console.log(`stdout: ${data}`);\n   * });\n   *\n   * ls.stderr.on('data', (data) => {\n   *   console.error(`stderr: ${data}`);\n   * });\n   *\n   * ls.on('close', (code) => {\n   *   console.log(`child process exited with code ${code}`);\n   * });\n   * ```\n   *\n   * Example: A very elaborate way to run `ps ax | grep ssh`\n   *\n   * ```js\n   * const { spawn } = require('child_process');\n   * const ps = spawn('ps', ['ax']);\n   * const grep = spawn('grep', ['ssh']);\n   *\n   * ps.stdout.on('data', (data) => {\n   *   grep.stdin.write(data);\n   * });\n   *\n   * ps.stderr.on('data', (data) => {\n   *   console.error(`ps stderr: ${data}`);\n   * });\n   *\n   * ps.on('close', (code) => {\n   *   if (code !== 0) {\n   *     console.log(`ps process exited with code ${code}`);\n   *   }\n   *   grep.stdin.end();\n   * });\n   *\n   * grep.stdout.on('data', (data) => {\n   *   console.log(data.toString());\n   * });\n   *\n   * grep.stderr.on('data', (data) => {\n   *   console.error(`grep stderr: ${data}`);\n   * });\n   *\n   * grep.on('close', (code) => {\n   *   if (code !== 0) {\n   *     console.log(`grep process exited with code ${code}`);\n   *   }\n   * });\n   * ```\n   *\n   * Example of checking for failed `spawn`:\n   *\n   * ```js\n   * const { spawn } = require('child_process');\n   * const subprocess = spawn('bad_command');\n   *\n   * subprocess.on('error', (err) => {\n   *   console.error('Failed to start subprocess.');\n   * });\n   * ```\n   *\n   * Certain platforms (macOS, Linux) will use the value of `argv[0]` for the process\n   * title while others (Windows, SunOS) will use `command`.\n   * @param command The command to run.\n   * @param args List of string arguments.\n   */\n  function spawn(\n    command: string,\n    options?: SpawnOptionsWithoutStdio\n  ): ChildProcessWithoutNullStreams;\n  function spawn(\n    command: string,\n    options: SpawnOptionsWithStdioTuple<StdioPipe, StdioPipe, StdioPipe>\n  ): ChildProcessByStdio<Writable, Readable, Readable>;\n  function spawn(\n    command: string,\n    options: SpawnOptionsWithStdioTuple<StdioPipe, StdioPipe, StdioNull>\n  ): ChildProcessByStdio<Writable, Readable, null>;\n  function spawn(\n    command: string,\n    options: SpawnOptionsWithStdioTuple<StdioPipe, StdioNull, StdioPipe>\n  ): ChildProcessByStdio<Writable, null, Readable>;\n  function spawn(\n    command: string,\n    options: SpawnOptionsWithStdioTuple<StdioNull, StdioPipe, StdioPipe>\n  ): ChildProcessByStdio<null, Readable, Readable>;\n  function spawn(\n    command: string,\n    options: SpawnOptionsWithStdioTuple<StdioPipe, StdioNull, StdioNull>\n  ): ChildProcessByStdio<Writable, null, null>;\n  function spawn(\n    command: string,\n    options: SpawnOptionsWithStdioTuple<StdioNull, StdioPipe, StdioNull>\n  ): ChildProcessByStdio<null, Readable, null>;\n  function spawn(\n    command: string,\n    options: SpawnOptionsWithStdioTuple<StdioNull, StdioNull, StdioPipe>\n  ): ChildProcessByStdio<null, null, Readable>;\n  function spawn(\n    command: string,\n    options: SpawnOptionsWithStdioTuple<StdioNull, StdioNull, StdioNull>\n  ): ChildProcessByStdio<null, null, null>;\n  function spawn(command: string, options: SpawnOptions): ChildProcess;\n  // overloads of spawn with 'args'\n  function spawn(\n    command: string,\n    args?: readonly string[],\n    options?: SpawnOptionsWithoutStdio\n  ): ChildProcessWithoutNullStreams;\n  function spawn(\n    command: string,\n    args: readonly string[],\n    options: SpawnOptionsWithStdioTuple<StdioPipe, StdioPipe, StdioPipe>\n  ): ChildProcessByStdio<Writable, Readable, Readable>;\n  function spawn(\n    command: string,\n    args: readonly string[],\n    options: SpawnOptionsWithStdioTuple<StdioPipe, StdioPipe, StdioNull>\n  ): ChildProcessByStdio<Writable, Readable, null>;\n  function spawn(\n    command: string,\n    args: readonly string[],\n    options: SpawnOptionsWithStdioTuple<StdioPipe, StdioNull, StdioPipe>\n  ): ChildProcessByStdio<Writable, null, Readable>;\n  function spawn(\n    command: string,\n    args: readonly string[],\n    options: SpawnOptionsWithStdioTuple<StdioNull, StdioPipe, StdioPipe>\n  ): ChildProcessByStdio<null, Readable, Readable>;\n  function spawn(\n    command: string,\n    args: readonly string[],\n    options: SpawnOptionsWithStdioTuple<StdioPipe, StdioNull, StdioNull>\n  ): ChildProcessByStdio<Writable, null, null>;\n  function spawn(\n    command: string,\n    args: readonly string[],\n    options: SpawnOptionsWithStdioTuple<StdioNull, StdioPipe, StdioNull>\n  ): ChildProcessByStdio<null, Readable, null>;\n  function spawn(\n    command: string,\n    args: readonly string[],\n    options: SpawnOptionsWithStdioTuple<StdioNull, StdioNull, StdioPipe>\n  ): ChildProcessByStdio<null, null, Readable>;\n  function spawn(\n    command: string,\n    args: readonly string[],\n    options: SpawnOptionsWithStdioTuple<StdioNull, StdioNull, StdioNull>\n  ): ChildProcessByStdio<null, null, null>;\n  function spawn(\n    command: string,\n    args: readonly string[],\n    options: SpawnOptions\n  ): ChildProcess;\n}\n"
  },
  {
    "path": "types/console.d.ts",
    "content": "/**\n * The `console` module provides a simple debugging console that is similar to\n * the JavaScript console mechanism provided by web browsers.\n *\n * Example using the global `console`:\n *\n * ```js\n * console.log('hello world');\n * // Prints: hello world, to stdout\n * console.log('hello %s', 'world');\n * // Prints: hello world, to stdout\n * console.error(new Error('Whoops, something bad happened'));\n * // Prints error message and stack trace to stderr:\n * //   Error: Whoops, something bad happened\n * //     at [eval]:5:15\n * //     at Script.runInThisContext (vm:132:18)\n * //     at Object.runInThisContext (vm:309:38)\n * //     at internal/process/execution:77:19\n * //     at [eval]-wrapper:6:22\n * //     at evalScript (internal/process/execution:76:60)\n * //     at internal/main/eval_string:23:3\n *\n * const name = 'Will Robinson';\n * console.warn(`Danger ${name}! Danger!`);\n * // Prints: Danger Will Robinson! Danger!, to stderr\n * ```\n *\n * Example using the `Console` class:\n *\n * ```js\n * const out = getStreamSomehow();\n * const err = getStreamSomehow();\n * const myConsole = new console.Console(out, err);\n *\n * myConsole.log('hello world');\n * // Prints: hello world, to out\n * myConsole.log('hello %s', 'world');\n * // Prints: hello world, to out\n * myConsole.error(new Error('Whoops, something bad happened'));\n * // Prints: [Error: Whoops, something bad happened], to err\n *\n * const name = 'Will Robinson';\n * myConsole.warn(`Danger ${name}! Danger!`);\n * // Prints: Danger Will Robinson! Danger!, to err\n * ```\n * @see [source](https://github.com/nodejs/node/blob/v22.x/lib/console.js)\n */\ndeclare module \"console\" {\n    global {\n        // This needs to be global to avoid TS2403 in case lib.dom.d.ts is present in the same build\n        interface Console {\n            /**\n             * `console.assert()` writes a message if `value` is [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) or omitted. It only\n             * writes a message and does not otherwise affect execution. The output always\n             * starts with `\"Assertion failed\"`. If provided, `message` is formatted using\n             * [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args).\n             *\n             * If `value` is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), nothing happens.\n             *\n             * ```js\n             * console.assert(true, 'does nothing');\n             *\n             * console.assert(false, 'Whoops %s work', 'didn\\'t');\n             * // Assertion failed: Whoops didn't work\n             *\n             * console.assert();\n             * // Assertion failed\n             * ```\n             * @param value The value tested for being truthy.\n             * @param message All arguments besides `value` are used as error message.\n             */\n            assert(value: any, message?: string, ...optionalParams: any[]): void;\n            /**\n             * When `stdout` is a TTY, calling `console.clear()` will attempt to clear the\n             * TTY. When `stdout` is not a TTY, this method does nothing.\n             *\n             * The specific operation of `console.clear()` can vary across operating systems\n             * and terminal types. For most Linux operating systems, `console.clear()` operates similarly to the `clear` shell command. On Windows, `console.clear()` will clear only the output in the\n             * current terminal viewport for the LLRT\n             * binary.\n             */\n            clear(): void;\n            /**\n             * The `console.debug()` function is an alias for {@link log}.\n             */\n            debug(message?: any, ...optionalParams: any[]): void;\n            /**\n             * Prints to `stderr` with newline. Multiple arguments can be passed, with the\n             * first used as the primary message and all additional used as substitution\n             * values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)\n             * (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)).\n             *\n             * ```js\n             * const code = 5;\n             * console.error('error #%d', code);\n             * // Prints: error #5, to stderr\n             * console.error('error', code);\n             * // Prints: error 5, to stderr\n             * ```\n             *\n             * If formatting elements (e.g. `%d`) are not found in the first string then\n             * [`util.inspect()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilinspectobject-options) is called on each argument and the\n             * resulting string values are concatenated. See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)\n             * for more information.\n             */\n            error(message?: any, ...optionalParams: any[]): void;\n            /**\n             * The `console.info()` function is an alias for {@link log}.\n             */\n            info(message?: any, ...optionalParams: any[]): void;\n            /**\n             * Prints to `stdout` with newline. Multiple arguments can be passed, with the\n             * first used as the primary message and all additional used as substitution\n             * values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)\n             * (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)).\n             *\n             * ```js\n             * const count = 5;\n             * console.log('count: %d', count);\n             * // Prints: count: 5, to stdout\n             * console.log('count:', count);\n             * // Prints: count: 5, to stdout\n             * ```\n             *\n             * See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.\n             */\n            log(message?: any, ...optionalParams: any[]): void;\n            /**\n             * Prints to `stderr` the string `'Trace: '`, followed by the [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)\n             * formatted message and stack trace to the current position in the code.\n             *\n             * ```js\n             * console.trace('Show me');\n             * // Prints: (stack trace will vary based on where trace is called)\n             * //  Trace: Show me\n             * //    at repl:2:9\n             * //    at REPLServer.defaultEval (repl.js:248:27)\n             * //    at bound (domain.js:287:14)\n             * //    at REPLServer.runBound [as eval] (domain.js:300:12)\n             * //    at REPLServer.<anonymous> (repl.js:412:12)\n             * //    at emitOne (events.js:82:20)\n             * //    at REPLServer.emit (events.js:169:7)\n             * //    at REPLServer.Interface._onLine (readline.js:210:10)\n             * //    at REPLServer.Interface._line (readline.js:549:8)\n             * //    at REPLServer.Interface._ttyWrite (readline.js:826:14)\n             * ```\n             */\n            trace(message?: any, ...optionalParams: any[]): void;\n            /**\n             * The `console.warn()` function is an alias for {@link error}.\n             */\n            warn(message?: any, ...optionalParams: any[]): void;\n        }\n        /**\n         * The `console` module provides a simple debugging console that is similar to the\n         * JavaScript console mechanism provided by web browsers.\n         *\n         *\n         * _**Warning**_: The global console object's methods are neither consistently\n         * synchronous like the browser APIs they resemble, nor are they consistently\n         * asynchronous like all other LLRT streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for\n         * more information.\n         *\n         * Example using the global `console`:\n         *\n         * ```js\n         * console.log('hello world');\n         * // Prints: hello world, to stdout\n         * console.log('hello %s', 'world');\n         * // Prints: hello world, to stdout\n         * console.error(new Error('Whoops, something bad happened'));\n         * // Prints error message and stack trace to stderr:\n         * //   Error: Whoops, something bad happened\n         * //     at [eval]:5:15\n         * //     at Script.runInThisContext (vm:132:18)\n         * //     at Object.runInThisContext (vm:309:38)\n         * //     at internal/process/execution:77:19\n         * //     at [eval]-wrapper:6:22\n         * //     at evalScript (internal/process/execution:76:60)\n         * //     at internal/main/eval_string:23:3\n         *\n         * const name = 'Will Robinson';\n         * console.warn(`Danger ${name}! Danger!`);\n         * // Prints: Danger Will Robinson! Danger!, to stderr\n         * ```\n         *\n         * Example using the `Console` class:\n         *\n         * ```js\n         * const out = getStreamSomehow();\n         * const err = getStreamSomehow();\n         * const myConsole = new console.Console(out, err);\n         *\n         * myConsole.log('hello world');\n         * // Prints: hello world, to out\n         * myConsole.log('hello %s', 'world');\n         * // Prints: hello world, to out\n         * myConsole.error(new Error('Whoops, something bad happened'));\n         * // Prints: [Error: Whoops, something bad happened], to err\n         *\n         * const name = 'Will Robinson';\n         * myConsole.warn(`Danger ${name}! Danger!`);\n         * // Prints: Danger Will Robinson! Danger!, to err\n         * ```\n         * @see [source](https://github.com/nodejs/node/blob/v22.x/lib/console.js)\n         */\n        var console: Console;\n    }\n    export = globalThis.console;\n}\n"
  },
  {
    "path": "types/crypto.d.ts",
    "content": "/**\n * The `crypto` module provides cryptographic functionality that includes a\n * set of wrappers for OpenSSL's hash, HMAC.\n *\n * ```js\n * import { createHmac } from 'crypto';\n *\n * const secret = 'abcdefg';\n * const hash = createHmac('sha256', secret)\n *                .update('I love cupcakes')\n *                .digest('hex');\n * console.log(hash);\n * // Prints:\n * //   c0fa1bc00531bd78ef38c628449c5102aeabd49b5dc3a2a516ea6ea959d6658e\n * ```\n */\ndeclare module \"crypto\" {\n  import { Buffer } from \"buffer\";\n  type BinaryLike = string | QuickJS.ArrayBufferView;\n  type BinaryToTextEncoding = \"base64\" | \"hex\";\n  type CharacterEncoding = \"utf8\" | \"utf-8\" | \"utf16le\" | \"utf-16le\" | \"latin1\";\n  type LegacyCharacterEncoding = \"ascii\";\n  type Encoding =\n    | BinaryToTextEncoding\n    | CharacterEncoding\n    | LegacyCharacterEncoding;\n  /**\n   * Creates and returns a `Hash` object that can be used to generate hash digests\n   * using the given `algorithm`.\n   *\n   * The `algorithm` is supported by `'sha1'`, `'sha256'`,`'sha384'` and `'sha512'`.\n   */\n  function createHash(algorithm: string): Hash;\n  /**\n   * Creates and returns an `Hmac` object that uses the given `algorithm` and `key`.\n   *\n   * The `algorithm` is supported by `'sha1'`, `'sha256'`,`'sha384'` and `'sha512'`.\n   *\n   * The `key` is the HMAC key used to generate the cryptographic HMAC hash.\n   * If it is a string, please consider `caveats when using strings as inputs to cryptographic APIs`.\n   * If it was obtained from a cryptographically secure source of entropy, such as {@link randomBytes}\n   * or {@link generateKey}, its length should not exceed the block size of `algorithm`\n   * (e.g., 512 bits for SHA-256).\n   */\n  function createHmac(algorithm: string, key: BinaryLike): Hmac;\n  /**\n   * The `Hash` class is a utility for creating hash digests of data.\n   *\n   * Using the `hash.update()` and `hash.digest()` methods to produce the\n   * computed hash.\n   *\n   * The {@link createHash} method is used to create `Hash` instances.\n   * `Hash`objects are not to be created directly using the `new` keyword.\n   *\n   * Example: Using the `hash.update()` and `hash.digest()` methods:\n   *\n   * ```js\n   * import { createHash } from 'crypto';\n   *\n   * const hash = createHash('sha256');\n   *\n   * hash.update('some data to hash');\n   * console.log(hash.digest('hex'));\n   * // Prints:\n   * //   6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50\n   * ```\n   */\n  class Hash {\n    private constructor();\n    /**\n     * Updates the hash content with the given `data`, the encoding of which\n     * is given in `inputEncoding`.\n     * If `encoding` is not provided, and the `data` is a string, an\n     * encoding of `'utf8'` is enforced. If `data` is a `Buffer`, `TypedArray`, or`DataView`,\n     * then `inputEncoding` is ignored.\n     *\n     * This can be called many times with new data as it is streamed.\n     * @param inputEncoding The `encoding` of the `data` string.\n     */\n    update(data: BinaryLike): Hash;\n    update(data: string, inputEncoding: Encoding): Hash;\n    /**\n     * Calculates the digest of all of the data passed to be hashed (using the `hash.update()` method).\n     * If `encoding` is provided a string will be returned; otherwise\n     * a `Buffer` is returned.\n     *\n     * The `Hash` object can not be used again after `hash.digest()` method has been\n     * called. Multiple calls will cause an error to be thrown.\n     * @param encoding The `encoding` of the return value.\n     */\n    digest(): Buffer;\n    digest(encoding: BinaryToTextEncoding): string;\n  }\n  /**\n   * The `Hmac` class is a utility for creating cryptographic HMAC digests.\n   *\n   * Using the `hmac.update()` and `hmac.digest()` methods to produce the\n   * computed HMAC digest.\n   *\n   * The {@link createHmac} method is used to create `Hmac` instances.\n   * `Hmac`objects are not to be created directly using the `new` keyword.\n   *\n   * Example: Using the `hmac.update()` and `hmac.digest()` methods:\n   *\n   * ```js\n   * import { createHmac } from 'crypto';\n   *\n   * const hmac = createHmac('sha256', 'a secret');\n   *\n   * hmac.update('some data to hash');\n   * console.log(hmac.digest('hex'));\n   * // Prints:\n   * //   7fd04df92f636fd450bc841c9418e5825c17f33ad9c87c518115a45971f7f77e\n   * ```\n   */\n  class Hmac {\n    private constructor();\n    /**\n     * Updates the `Hmac` content with the given `data`, the encoding of which\n     * is given in `inputEncoding`.\n     * If `encoding` is not provided, and the `data` is a string, an\n     * encoding of `'utf8'` is enforced. If `data` is a `Buffer`, `TypedArray`, or`DataView`,\n     * then `inputEncoding` is ignored.\n     *\n     * This can be called many times with new data as it is streamed.\n     * @param inputEncoding The `encoding` of the `data` string.\n     */\n    update(data: BinaryLike): Hmac;\n    update(data: string, inputEncoding: Encoding): Hmac;\n    /**\n     * Calculates the HMAC digest of all of the data passed using `hmac.update()`.\n     * If `encoding` is\n     * provided a string is returned; otherwise a `Buffer` is returned;\n     *\n     * The `Hmac` object can not be used again after `hmac.digest()` has been\n     * called. Multiple calls to `hmac.digest()` will result in an error being thrown.\n     * @param encoding The `encoding` of the return value.\n     */\n    digest(): Buffer;\n    digest(encoding: BinaryToTextEncoding): string;\n  }\n  /**\n   * Generates cryptographically strong pseudorandom data. The `size` argument\n   * is a number indicating the number of bytes to generate.\n   *\n   * the random bytes are generated synchronously and returned as a `Buffer`.\n   * An error will be thrown if there is a problem generating the bytes.\n   *\n   * ```js\n   * // Synchronous\n   * import { randomBytes } from 'crypto';\n   *\n   * const buf = randomBytes(256);\n   * console.log(\n   *   `${buf.length} bytes of random data: ${buf.toString('hex')}`);\n   * ```\n   *\n   * The `crypto.randomBytes()` method will not complete until there is\n   * sufficient entropy available.\n   * This should normally never take longer than a few milliseconds. The only time\n   * when generating the random bytes may conceivably block for a longer period of\n   * time is right after boot, when the whole system is still low on entropy.\n   *\n   * @param size The number of bytes to generate. The `size` must not be larger than `2**31 - 1`.\n   */\n  function randomBytes(size: number): Buffer;\n  /**\n   * Return a random integer `n` such that `min <= n < max`.  This\n   * implementation avoids [modulo bias](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#Modulo_bias).\n   *\n   * The range (`max - min`) must be less than 2**48. `min` and `max` must\n   * be [safe integers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isSafeInteger).\n   *\n   * ```js\n   * // Synchronous\n   * import { randomInt } from 'crypto';\n   *\n   * const n = randomInt(3);\n   * console.log(`Random number chosen from (0, 1, 2): ${n}`);\n   * ```\n   *\n   * ```js\n   * // With `min` argument\n   * import { randomInt } from 'crypto';\n   *\n   * const n = randomInt(1, 7);\n   * console.log(`The dice rolled: ${n}`);\n   * ```\n   * @param [min=0] Start of random range (inclusive).\n   * @param max End of random range (exclusive).\n   */\n  function randomInt(max: number): number;\n  function randomInt(min: number, max: number): number;\n  /**\n   * Synchronous version of {@link randomFill}.\n   *\n   * ```js\n   * import { Buffer } from 'buffer';\n   * import { randomFillSync } from 'crypto';\n   *\n   * const buf = Buffer.alloc(10);\n   * console.log(randomFillSync(buf).toString('hex'));\n   *\n   * randomFillSync(buf, 5);\n   * console.log(buf.toString('hex'));\n   *\n   * // The above is equivalent to the following:\n   * randomFillSync(buf, 5, 5);\n   * console.log(buf.toString('hex'));\n   * ```\n   *\n   * Any `ArrayBuffer`, `TypedArray` or `DataView` instance may be passed as`buffer`.\n   *\n   * ```js\n   * import { Buffer } from 'buffer';\n   * import { randomFillSync } from 'crypto';\n   *\n   * const a = new Uint32Array(10);\n   * console.log(Buffer.from(randomFillSync(a).buffer,\n   *                         a.byteOffset, a.byteLength).toString('hex'));\n   *\n   * const b = new DataView(new ArrayBuffer(10));\n   * console.log(Buffer.from(randomFillSync(b).buffer,\n   *                         b.byteOffset, b.byteLength).toString('hex'));\n   *\n   * const c = new ArrayBuffer(10);\n   * console.log(Buffer.from(randomFillSync(c)).toString('hex'));\n   * ```\n   * @param buffer Must be supplied. The size of the provided `buffer` must not be larger than `2**31 - 1`.\n   * @param [offset=0]\n   * @param [size=buffer.length - offset]\n   * @return The object passed as `buffer` argument.\n   */\n  function randomFillSync<T extends QuickJS.ArrayBufferView>(\n    buffer: T,\n    offset?: number,\n    size?: number\n  ): T;\n  /**\n   * This function is similar to {@link randomBytes} but requires the first\n   * argument to be a `Buffer` that will be filled. It also\n   * requires that a callback is passed in.\n   *\n   * If the `callback` function is not provided, an error will be thrown.\n   *\n   * ```js\n   * import { Buffer } from 'buffer';\n   * import { randomFill } from 'crypto';\n   *\n   * const buf = Buffer.alloc(10);\n   * randomFill(buf, (err, buf) => {\n   *   if (err) throw err;\n   *   console.log(buf.toString('hex'));\n   * });\n   *\n   * randomFill(buf, 5, (err, buf) => {\n   *   if (err) throw err;\n   *   console.log(buf.toString('hex'));\n   * });\n   *\n   * // The above is equivalent to the following:\n   * randomFill(buf, 5, 5, (err, buf) => {\n   *   if (err) throw err;\n   *   console.log(buf.toString('hex'));\n   * });\n   * ```\n   *\n   * Any `ArrayBuffer`, `TypedArray`, or `DataView` instance may be passed as `buffer`.\n   *\n   * While this includes instances of `Float32Array` and `Float64Array`, this\n   * function should not be used to generate random floating-point numbers. The\n   * result may contain `+Infinity`, `-Infinity`, and `NaN`, and even if the array\n   * contains finite numbers only, they are not drawn from a uniform random\n   * distribution and have no meaningful lower or upper bounds.\n   *\n   * ```js\n   * import { Buffer } from 'buffer';\n   * import { randomFill } from 'crypto';\n   *\n   * const a = new Uint32Array(10);\n   * randomFill(a, (err, buf) => {\n   *   if (err) throw err;\n   *   console.log(Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength)\n   *     .toString('hex'));\n   * });\n   *\n   * const b = new DataView(new ArrayBuffer(10));\n   * randomFill(b, (err, buf) => {\n   *   if (err) throw err;\n   *   console.log(Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength)\n   *     .toString('hex'));\n   * });\n   *\n   * const c = new ArrayBuffer(10);\n   * randomFill(c, (err, buf) => {\n   *   if (err) throw err;\n   *   console.log(Buffer.from(buf).toString('hex'));\n   * });\n   * ```\n   * @param buffer Must be supplied. The size of the provided `buffer` must not be larger than `2**31 - 1`.\n   * @param [offset=0]\n   * @param [size=buffer.length - offset]\n   * @param callback `function(err, buf) {}`.\n   */\n  function randomFill<T extends QuickJS.ArrayBufferView>(\n    buffer: T,\n    callback: (err: Error | null, buf: T) => void\n  ): void;\n  function randomFill<T extends QuickJS.ArrayBufferView>(\n    buffer: T,\n    offset: number,\n    callback: (err: Error | null, buf: T) => void\n  ): void;\n  function randomFill<T extends QuickJS.ArrayBufferView>(\n    buffer: T,\n    offset: number,\n    size: number,\n    callback: (err: Error | null, buf: T) => void\n  ): void;\n  type UUID = `${string}-${string}-${string}-${string}-${string}`;\n  /**\n   * A convenient alias for {@link webcrypto.getRandomValues}. This\n   * implementation is not compliant with the Web Crypto spec, to write\n   * web-compatible code use {@link webcrypto.getRandomValues} instead.\n   * @return Returns `typedArray`.\n   */\n  function getRandomValues<T extends QuickJS.ArrayBufferView>(typedArray: T): T;\n  /**\n   * Generates a random {@link https://www.rfc-editor.org/rfc/rfc4122.txt RFC 4122} version 4 UUID.\n   * The UUID is generated using a cryptographic pseudorandom number generator.\n   */\n  function randomUUID(): UUID;\n\n  /**\n   * A convenient alias for `crypto.webcrypto.subtle`.\n   * @since v17.4.0\n   */\n  const subtle: webcrypto.SubtleCrypto;\n  /**\n   * An implementation of the Web Crypto API standard.\n   *\n   * See the {@link https://nodejs.org/docs/latest/api/webcrypto.html Web Crypto API documentation} for details.\n   */\n  namespace webcrypto {\n    type BufferSource = ArrayBufferView | ArrayBuffer;\n    type KeyFormat = \"jwk\" | \"pkcs8\" | \"raw\" | \"spki\";\n    type KeyType = \"private\" | \"public\" | \"secret\";\n    type KeyUsage =\n      | \"decrypt\"\n      | \"deriveBits\"\n      | \"deriveKey\"\n      | \"encrypt\"\n      | \"sign\"\n      | \"unwrapKey\"\n      | \"verify\"\n      | \"wrapKey\";\n    type AlgorithmIdentifier = Algorithm | string;\n    type HashAlgorithmIdentifier = AlgorithmIdentifier;\n    type NamedCurve = string;\n    type BigInteger = Uint8Array;\n    interface AesCbcParams extends Algorithm {\n      iv: BufferSource;\n    }\n    interface AesCtrParams extends Algorithm {\n      counter: BufferSource;\n      length: number;\n    }\n    interface AesDerivedKeyParams extends Algorithm {\n      length: number;\n    }\n    interface AesGcmParams extends Algorithm {\n      additionalData?: BufferSource;\n      iv: BufferSource;\n      tagLength?: number;\n    }\n    interface AesKeyAlgorithm extends KeyAlgorithm {\n      length: number;\n    }\n    interface AesKeyGenParams extends Algorithm {\n      length: number;\n    }\n    interface Algorithm {\n      name: string;\n    }\n    interface EcKeyAlgorithm extends KeyAlgorithm {\n      namedCurve: NamedCurve;\n    }\n    interface EcKeyGenParams extends Algorithm {\n      namedCurve: NamedCurve;\n    }\n    interface EcKeyImportParams extends Algorithm {\n      namedCurve: NamedCurve;\n    }\n    interface EcdhKeyDeriveParams extends Algorithm {\n      public: CryptoKey;\n    }\n    interface EcdsaParams extends Algorithm {\n      hash: HashAlgorithmIdentifier;\n    }\n    interface Ed448Params extends Algorithm {\n      context?: BufferSource;\n    }\n    interface HkdfParams extends Algorithm {\n      hash: HashAlgorithmIdentifier;\n      info: BufferSource;\n      salt: BufferSource;\n    }\n    interface HmacImportParams extends Algorithm {\n      hash: HashAlgorithmIdentifier;\n      length?: number;\n    }\n    interface HmacKeyAlgorithm extends KeyAlgorithm {\n      hash: KeyAlgorithm;\n      length: number;\n    }\n    interface HmacKeyGenParams extends Algorithm {\n      hash: HashAlgorithmIdentifier;\n      length?: number;\n    }\n    interface JsonWebKey {\n      alg?: string;\n      crv?: string;\n      d?: string;\n      dp?: string;\n      dq?: string;\n      e?: string;\n      ext?: boolean;\n      k?: string;\n      key_ops?: string[];\n      kty?: string;\n      n?: string;\n      oth?: RsaOtherPrimesInfo[];\n      p?: string;\n      q?: string;\n      qi?: string;\n      use?: string;\n      x?: string;\n      y?: string;\n    }\n    interface KeyAlgorithm {\n      name: string;\n    }\n    interface Pbkdf2Params extends Algorithm {\n      hash: HashAlgorithmIdentifier;\n      iterations: number;\n      salt: BufferSource;\n    }\n    interface RsaHashedImportParams extends Algorithm {\n      hash: HashAlgorithmIdentifier;\n    }\n    interface RsaHashedKeyAlgorithm extends RsaKeyAlgorithm {\n      hash: KeyAlgorithm;\n    }\n    interface RsaHashedKeyGenParams extends RsaKeyGenParams {\n      hash: HashAlgorithmIdentifier;\n    }\n    interface RsaKeyAlgorithm extends KeyAlgorithm {\n      modulusLength: number;\n      publicExponent: BigInteger;\n    }\n    interface RsaKeyGenParams extends Algorithm {\n      modulusLength: number;\n      publicExponent: BigInteger;\n    }\n    interface RsaOaepParams extends Algorithm {\n      label?: BufferSource;\n    }\n    interface RsaOtherPrimesInfo {\n      d?: string;\n      r?: string;\n      t?: string;\n    }\n    interface RsaPssParams extends Algorithm {\n      saltLength: number;\n    }\n\n    interface CryptoKey {\n      /**\n       * An object detailing the algorithm for which the key can be used along with additional algorithm-specific parameters.\n       */\n      readonly algorithm: KeyAlgorithm;\n      /**\n       * When `true`, the {@link CryptoKey} can be extracted using either `subtleCrypto.exportKey()` or `subtleCrypto.wrapKey()`.\n       */\n      readonly extractable: boolean;\n      /**\n       * A string identifying whether the key is a symmetric (`'secret'`) or asymmetric (`'private'` or `'public'`) key.\n       */\n      readonly type: KeyType;\n      /**\n       * An array of strings identifying the operations for which the key may be used.\n       *\n       * The possible usages are:\n       * - `'encrypt'` - The key may be used to encrypt data.\n       * - `'decrypt'` - The key may be used to decrypt data.\n       * - `'sign'` - The key may be used to generate digital signatures.\n       * - `'verify'` - The key may be used to verify digital signatures.\n       * - `'deriveKey'` - The key may be used to derive a new key.\n       * - `'deriveBits'` - The key may be used to derive bits.\n       * - `'wrapKey'` - The key may be used to wrap another key.\n       * - `'unwrapKey'` - The key may be used to unwrap another key.\n       *\n       * Valid key usages depend on the key algorithm (identified by `cryptokey.algorithm.name`).\n       * @since v15.0.0\n       */\n      readonly usages: KeyUsage[];\n    }\n    /**\n     * The `CryptoKeyPair` is a simple dictionary object with `publicKey` and `privateKey` properties, representing an asymmetric key pair.\n     */\n    interface CryptoKeyPair {\n      /**\n       * A {@link CryptoKey} whose type will be `'private'`.\n       */\n      privateKey: CryptoKey;\n      /**\n       * A {@link CryptoKey} whose type will be `'public'`.\n       */\n      publicKey: CryptoKey;\n    }\n\n    interface SubtleCrypto {\n      /**\n       * Using the method and parameters specified in `algorithm` and the keying material provided by `key`,\n       * `subtle.decrypt()` attempts to decipher the provided `data`. If successful,\n       * the returned promise will be resolved with an `<ArrayBuffer>` containing the plaintext result.\n       *\n       * The algorithms currently supported include:\n       *\n       * - `'RSA-OAEP'`\n       * - `'AES-CTR'`\n       * - `'AES-CBC'`\n       * - `'AES-GCM'`\n       */\n      decrypt(\n        algorithm:\n          | AlgorithmIdentifier\n          | RsaOaepParams\n          | AesCtrParams\n          | AesCbcParams\n          | AesGcmParams,\n        key: CryptoKey,\n        data: BufferSource\n      ): Promise<ArrayBuffer>;\n      /**\n       * Using the method and parameters specified in `algorithm` and the keying material provided by `baseKey`,\n       * `subtle.deriveBits()` attempts to generate `length` bits.\n       * The LLRT implementation requires that when `length` is a number it must be multiple of `8`.\n       * When `length` is `null` the maximum number of bits for a given algorithm is generated. This is allowed\n       * for the `'ECDH'`, `'X25519'`, and `'X448'` algorithms.\n       * If successful, the returned promise will be resolved with an `<ArrayBuffer>` containing the generated data.\n       *\n       * The algorithms currently supported include:\n       *\n       * - `'ECDH'`\n       * - `'X25519'`\n       * - `'X448'`\n       * - `'HKDF'`\n       * - `'PBKDF2'`\n       */\n      deriveBits(\n        algorithm: EcdhKeyDeriveParams,\n        baseKey: CryptoKey,\n        length: number | null\n      ): Promise<ArrayBuffer>;\n      deriveBits(\n        algorithm: AlgorithmIdentifier | HkdfParams | Pbkdf2Params,\n        baseKey: CryptoKey,\n        length: number\n      ): Promise<ArrayBuffer>;\n      /**\n       * Using the method and parameters specified in `algorithm`, and the keying material provided by `baseKey`,\n       * `subtle.deriveKey()` attempts to generate a new <CryptoKey>` based on the method and parameters in `derivedKeyAlgorithm`.\n       *\n       * Calling `subtle.deriveKey()` is equivalent to calling `subtle.deriveBits()` to generate raw keying material,\n       * then passing the result into the `subtle.importKey()` method using the `deriveKeyAlgorithm`, `extractable`, and `keyUsages` parameters as input.\n       *\n       * The algorithms currently supported include:\n       *\n       * - `'ECDH'`\n       * - `'X25519'`\n       * - `'X448'`\n       * - `'HKDF'`\n       * - `'PBKDF2'`\n       * @param keyUsages See {@link https://nodejs.org/docs/latest/api/webcrypto.html#cryptokeyusages Key usages}.\n       */\n      deriveKey(\n        algorithm:\n          | AlgorithmIdentifier\n          | EcdhKeyDeriveParams\n          | HkdfParams\n          | Pbkdf2Params,\n        baseKey: CryptoKey,\n        derivedKeyAlgorithm:\n          | AlgorithmIdentifier\n          | AesDerivedKeyParams\n          | HmacImportParams\n          | HkdfParams\n          | Pbkdf2Params,\n        extractable: boolean,\n        keyUsages: readonly KeyUsage[]\n      ): Promise<CryptoKey>;\n      /**\n       * Using the method identified by `algorithm`, `subtle.digest()` attempts to generate a digest of `data`.\n       * If successful, the returned promise is resolved with an `<ArrayBuffer>` containing the computed digest.\n       *\n       * If `algorithm` is provided as a `<string>`, it must be one of:\n       *\n       * - `'SHA-1'`\n       * - `'SHA-256'`\n       * - `'SHA-384'`\n       * - `'SHA-512'`\n       *\n       * If `algorithm` is provided as an `<Object>`, it must have a `name` property whose value is one of the above.\n       */\n      digest(\n        algorithm: AlgorithmIdentifier,\n        data: BufferSource\n      ): Promise<ArrayBuffer>;\n      /**\n       * Using the method and parameters specified by `algorithm` and the keying material provided by `key`,\n       * `subtle.encrypt()` attempts to encipher `data`. If successful,\n       * the returned promise is resolved with an `<ArrayBuffer>` containing the encrypted result.\n       *\n       * The algorithms currently supported include:\n       *\n       * - `'RSA-OAEP'`\n       * - `'AES-CTR'`\n       * - `'AES-CBC'`\n       * - `'AES-GCM'`\n       */\n      encrypt(\n        algorithm:\n          | AlgorithmIdentifier\n          | RsaOaepParams\n          | AesCtrParams\n          | AesCbcParams\n          | AesGcmParams,\n        key: CryptoKey,\n        data: BufferSource\n      ): Promise<ArrayBuffer>;\n      /**\n       * Exports the given key into the specified format, if supported.\n       *\n       * If the `<CryptoKey>` is not extractable, the returned promise will reject.\n       *\n       * When `format` is either `'pkcs8'` or `'spki'` and the export is successful,\n       * the returned promise will be resolved with an `<ArrayBuffer>` containing the exported key data.\n       *\n       * When `format` is `'jwk'` and the export is successful, the returned promise will be resolved with a\n       * JavaScript object conforming to the {@link https://tools.ietf.org/html/rfc7517 JSON Web Key} specification.\n       * @param format Must be one of `'raw'`, `'pkcs8'`, `'spki'`, or `'jwk'`.\n       * @returns `<Promise>` containing `<ArrayBuffer>`.\n       */\n      exportKey(format: \"jwk\", key: CryptoKey): Promise<JsonWebKey>;\n      exportKey(\n        format: Exclude<KeyFormat, \"jwk\">,\n        key: CryptoKey\n      ): Promise<ArrayBuffer>;\n      /**\n       * Using the method and parameters provided in `algorithm`,\n       * `subtle.generateKey()` attempts to generate new keying material.\n       * Depending the method used, the method may generate either a single `<CryptoKey>` or a `<CryptoKeyPair>`.\n       *\n       * The `<CryptoKeyPair>` (public and private key) generating algorithms supported include:\n       *\n       * - `'RSASSA-PKCS1-v1_5'`\n       * - `'RSA-PSS'`\n       * - `'RSA-OAEP'`\n       * - `'ECDSA'`\n       * - `'ECDH'`\n       * - `'Ed25519'`\n       * The `<CryptoKey>` (secret key) generating algorithms supported include:\n       *\n       * - `'HMAC'`\n       * - `'AES-CTR'`\n       * - `'AES-CBC'`\n       * - `'AES-GCM'`\n       * - `'AES-KW'`\n       * @param keyUsages See {@link https://nodejs.org/docs/latest/api/webcrypto.html#cryptokeyusages Key usages}.\n       */\n      generateKey(\n        algorithm: RsaHashedKeyGenParams | EcKeyGenParams,\n        extractable: boolean,\n        keyUsages: readonly KeyUsage[]\n      ): Promise<CryptoKeyPair>;\n      generateKey(\n        algorithm: AesKeyGenParams | HmacKeyGenParams | Pbkdf2Params,\n        extractable: boolean,\n        keyUsages: readonly KeyUsage[]\n      ): Promise<CryptoKey>;\n      generateKey(\n        algorithm: AlgorithmIdentifier,\n        extractable: boolean,\n        keyUsages: KeyUsage[]\n      ): Promise<CryptoKeyPair | CryptoKey>;\n      /**\n       * The `subtle.importKey()` method attempts to interpret the provided `keyData` as the given `format`\n       * to create a `<CryptoKey>` instance using the provided `algorithm`, `extractable`, and `keyUsages` arguments.\n       * If the import is successful, the returned promise will be resolved with the created `<CryptoKey>`.\n       *\n       * If importing a `'PBKDF2'` key, `extractable` must be `false`.\n       * @param format Must be one of `'raw'`, `'pkcs8'`, `'spki'`, or `'jwk'`.\n       * @param keyUsages See {@link https://nodejs.org/docs/latest/api/webcrypto.html#cryptokeyusages Key usages}.\n       */\n      importKey(\n        format: \"jwk\",\n        keyData: JsonWebKey,\n        algorithm:\n          | AlgorithmIdentifier\n          | RsaHashedImportParams\n          | EcKeyImportParams\n          | HmacImportParams\n          | AesKeyAlgorithm,\n        extractable: boolean,\n        keyUsages: readonly KeyUsage[]\n      ): Promise<CryptoKey>;\n      importKey(\n        format: Exclude<KeyFormat, \"jwk\">,\n        keyData: BufferSource,\n        algorithm:\n          | AlgorithmIdentifier\n          | RsaHashedImportParams\n          | EcKeyImportParams\n          | HmacImportParams\n          | AesKeyAlgorithm,\n        extractable: boolean,\n        keyUsages: KeyUsage[]\n      ): Promise<CryptoKey>;\n      /**\n       * Using the method and parameters given by `algorithm` and the keying material provided by `key`,\n       * `subtle.sign()` attempts to generate a cryptographic signature of `data`. If successful,\n       * the returned promise is resolved with an `<ArrayBuffer>` containing the generated signature.\n       *\n       * The algorithms currently supported include:\n       *\n       * - `'RSASSA-PKCS1-v1_5'`\n       * - `'RSA-PSS'`\n       * - `'ECDSA'`\n       * - `'Ed25519'`\n       * - `'HMAC'`\n       */\n      sign(\n        algorithm:\n          | AlgorithmIdentifier\n          | RsaPssParams\n          | EcdsaParams\n          | Ed448Params,\n        key: CryptoKey,\n        data: BufferSource\n      ): Promise<ArrayBuffer>;\n      /**\n       * In cryptography, \"wrapping a key\" refers to exporting and then encrypting the keying material.\n       * The `subtle.unwrapKey()` method attempts to decrypt a wrapped key and create a `<CryptoKey>` instance.\n       * It is equivalent to calling `subtle.decrypt()` first on the encrypted key data (using the `wrappedKey`, `unwrapAlgo`, and `unwrappingKey` arguments as input)\n       * then passing the results in to the `subtle.importKey()` method using the `unwrappedKeyAlgo`, `extractable`, and `keyUsages` arguments as inputs.\n       * If successful, the returned promise is resolved with a `<CryptoKey>` object.\n       *\n       * The wrapping algorithms currently supported include:\n       *\n       * - `'RSA-OAEP'`\n       * - `'AES-CTR'`\n       * - `'AES-CBC'`\n       * - `'AES-GCM'`\n       * - `'AES-KW'`\n       *\n       * The unwrapped key algorithms supported include:\n       *\n       * - `'RSASSA-PKCS1-v1_5'`\n       * - `'RSA-PSS'`\n       * - `'RSA-OAEP'`\n       * - `'ECDSA'`\n       * - `'ECDH'`\n       * - `'HMAC'`\n       * - `'AES-CTR'`\n       * - `'AES-CBC'`\n       * - `'AES-GCM'`\n       * - `'AES-KW'`\n       * @param format Must be one of `'raw'`, `'pkcs8'`, `'spki'`, or `'jwk'`.\n       * @param keyUsages See {@link https://nodejs.org/docs/latest/api/webcrypto.html#cryptokeyusages Key usages}.\n       */\n      unwrapKey(\n        format: KeyFormat,\n        wrappedKey: BufferSource,\n        unwrappingKey: CryptoKey,\n        unwrapAlgorithm:\n          | AlgorithmIdentifier\n          | RsaOaepParams\n          | AesCtrParams\n          | AesCbcParams\n          | AesGcmParams,\n        unwrappedKeyAlgorithm:\n          | AlgorithmIdentifier\n          | RsaHashedImportParams\n          | EcKeyImportParams\n          | HmacImportParams\n          | AesKeyAlgorithm,\n        extractable: boolean,\n        keyUsages: KeyUsage[]\n      ): Promise<CryptoKey>;\n      /**\n       * Using the method and parameters given in `algorithm` and the keying material provided by `key`,\n       * `subtle.verify()` attempts to verify that `signature` is a valid cryptographic signature of `data`.\n       * The returned promise is resolved with either `true` or `false`.\n       *\n       * The algorithms currently supported include:\n       *\n       * - `'RSASSA-PKCS1-v1_5'`\n       * - `'RSA-PSS'`\n       * - `'ECDSA'`\n       * - `'Ed25519'`\n       * - `'HMAC'`\n       */\n      verify(\n        algorithm:\n          | AlgorithmIdentifier\n          | RsaPssParams\n          | EcdsaParams\n          | Ed448Params,\n        key: CryptoKey,\n        signature: BufferSource,\n        data: BufferSource\n      ): Promise<boolean>;\n      /**\n       * In cryptography, \"wrapping a key\" refers to exporting and then encrypting the keying material.\n       * The `subtle.wrapKey()` method exports the keying material into the format identified by `format`,\n       * then encrypts it using the method and parameters specified by `wrapAlgo` and the keying material provided by `wrappingKey`.\n       * It is the equivalent to calling `subtle.exportKey()` using `format` and `key` as the arguments,\n       * then passing the result to the `subtle.encrypt()` method using `wrappingKey` and `wrapAlgo` as inputs.\n       * If successful, the returned promise will be resolved with an `<ArrayBuffer>` containing the encrypted key data.\n       *\n       * The wrapping algorithms currently supported include:\n       *\n       * - `'RSA-OAEP'`\n       * - `'AES-CTR'`\n       * - `'AES-CBC'`\n       * - `'AES-GCM'`\n       * - `'AES-KW'`\n       * @param format Must be one of `'raw'`, `'pkcs8'`, `'spki'`, or `'jwk'`.\n       */\n      wrapKey(\n        format: KeyFormat,\n        key: CryptoKey,\n        wrappingKey: CryptoKey,\n        wrapAlgorithm:\n          | AlgorithmIdentifier\n          | RsaOaepParams\n          | AesCtrParams\n          | AesCbcParams\n          | AesGcmParams\n      ): Promise<ArrayBuffer>;\n    }\n  }\n}\n"
  },
  {
    "path": "types/dgram.d.ts",
    "content": "/**\n * The `dgram` module provides an implementation of UDP datagram sockets.\n *\n * ```js\n * import dgram from 'dgram';\n *\n * const server = dgram.createSocket('udp4');\n *\n * server.on('message', (msg, rinfo) => {\n *   console.log(`server got: ${msg} from ${rinfo.address}:${rinfo.port}`);\n * });\n *\n * server.bind(41234);\n * ```\n */\ndeclare module \"dgram\" {\n  import { EventEmitter } from \"events\";\n  import { Buffer } from \"buffer\";\n\n  interface RemoteInfo {\n    /**\n     * The IP address of the sender.\n     */\n    address: string;\n    /**\n     * The address family ('IPv4' or 'IPv6').\n     */\n    family: \"IPv4\" | \"IPv6\";\n    /**\n     * The port number of the sender.\n     */\n    port: number;\n  }\n\n  interface BindOptions {\n    /**\n     * The port to bind to.\n     */\n    port?: number | undefined;\n    /**\n     * The address to bind to.\n     */\n    address?: string | undefined;\n  }\n\n  interface SocketOptions {\n    /**\n     * The type of socket. Must be either 'udp4' or 'udp6'.\n     */\n    type: SocketType;\n  }\n\n  type SocketType = \"udp4\" | \"udp6\";\n\n  /**\n   * Encapsulates the datagram functionality.\n   *\n   * New instances of `dgram.Socket` are created using {@link createSocket}.\n   * The `new` keyword is not to be used to create `dgram.Socket` instances.\n   */\n  class Socket extends EventEmitter {\n    /**\n     * Tells the kernel to join a multicast group at the given `multicastAddress` and `multicastInterface` using the `IP_ADD_MEMBERSHIP` socket option.\n     * If the `multicastInterface` argument is not specified, the operating system will choose one interface and will add membership to it.\n     * To add membership to every available interface, call `addMembership` multiple times, once per interface.\n     */\n    addMembership(\n      multicastAddress: string,\n      multicastInterface?: string\n    ): void;\n    /**\n     * Returns an object containing the address information for a socket.\n     * For UDP sockets, this object will contain `address`, `family`, and `port` properties.\n     *\n     * This method throws `EBADF` if called on an unbound socket.\n     */\n    address(): AddressInfo;\n    /**\n     * For UDP sockets, causes the `dgram.Socket` to listen for datagram messages on a named `port` and optional `address`.\n     * If `port` is not specified or is `0`, the operating system will attempt to bind to a random port.\n     * If `address` is not specified, the operating system will attempt to listen on all addresses.\n     * Once binding is complete, a `'listening'` event is emitted and the optional `callback` function is called.\n     *\n     * Specifying both a `'listening'` event listener and passing a `callback` to the `socket.bind()` method is not harmful but not very useful.\n     *\n     * @param port The port to listen on.\n     * @param address The address to listen on.\n     * @param callback Called when binding is complete.\n     */\n    bind(port?: number, address?: string, callback?: () => void): this;\n    bind(port?: number, callback?: () => void): this;\n    bind(callback?: () => void): this;\n    bind(options: BindOptions, callback?: () => void): this;\n    /**\n     * Close the underlying socket and stop listening for data on it. If a callback is provided, it is added as a listener for the `'close'` event.\n     *\n     * @param callback Called when the socket has been closed.\n     */\n    close(callback?: () => void): this;\n    /**\n     * Instructs the kernel to leave a multicast group at `multicastAddress` using the `IP_DROP_MEMBERSHIP` socket option.\n     * This method is automatically called by the kernel when the socket is closed or the process terminates, so most apps will never have reason to call this.\n     *\n     * If `multicastInterface` is not specified, the operating system will attempt to drop membership on all valid interfaces.\n     */\n    dropMembership(\n      multicastAddress: string,\n      multicastInterface?: string\n    ): void;\n    /**\n     * By default, binding a socket will cause it to block the LLRT process from exiting as long as the socket is open.\n     * The `socket.unref()` method can be used to exclude the socket from the reference counting that keeps the LLRT process active.\n     * The `socket.ref()` method adds the socket back to the reference counting and restores the default behavior.\n     *\n     * Calling `socket.ref()` multiples times will have no additional effect.\n     *\n     * The `socket.ref()` method returns a reference to the socket so calls can be chained.\n     */\n    ref(): this;\n    /**\n     * Broadcasts a datagram on the socket.\n     * For connectionless sockets, the destination `port` and `address` must be specified.\n     * Connected sockets, on the other hand, will use their associated remote endpoint, so the `port` and `address` arguments must not be set.\n     *\n     * The `msg` argument contains the message to be sent.\n     * Depending on its type, different behavior can apply.\n     * If `msg` is a `Buffer`, any `TypedArray` or a `DataView`, the `offset` and `length` specify the offset within the `Buffer` where the message begins and the number of bytes in the message, respectively.\n     * If `msg` is a `String`, then it is automatically converted to a `Buffer` with `'utf8'` encoding.\n     * With messages that contain multi-byte characters, `offset` and `length` will be calculated with respect to byte length and not the character position.\n     * If `msg` is an array, `offset` and `length` must not be specified.\n     *\n     * The `address` argument is a string. If the value of `address` is a host name, DNS will be used to resolve the address of the host.\n     * If `address` is not provided or otherwise nullish, `'127.0.0.1'` (for `udp4` sockets) or `'::1'` (for `udp6` sockets) will be used by default.\n     *\n     * If the socket has not been previously bound with a call to `bind`, the socket is assigned a random port number and is bound to the \"all interfaces\" address (`'0.0.0.0'` for `udp4` sockets, `'::0'` for `udp6` sockets.)\n     *\n     * An optional `callback` function may be specified to as a way of reporting DNS errors or for determining when it is safe to reuse the `buf` object.\n     * DNS lookups delay the time to send for at least one tick of the LLRT event loop.\n     *\n     * The only way to know for sure that the datagram has been sent is by using a `callback`. If an error occurs and a `callback` is given, the error will be passed as the first argument to the `callback`.\n     * If a `callback` is not given, the error is emitted as an `'error'` event on the `socket` object.\n     *\n     * Offset and length are optional but both _must_ be set if either are used.\n     * They are supported only when the first argument is a `Buffer`, a `TypedArray`, or a `DataView`.\n     *\n     * @param msg Message to be sent.\n     * @param port Destination port.\n     * @param address Destination host name or IP address.\n     * @param callback Called when the message has been sent.\n     */\n    send(\n      msg: string | Uint8Array | readonly any[],\n      port?: number,\n      address?: string,\n      callback?: (error: Error | null, bytes: number) => void\n    ): void;\n    send(\n      msg: string | Uint8Array | readonly any[],\n      port?: number,\n      callback?: (error: Error | null, bytes: number) => void\n    ): void;\n    send(\n      msg: string | Uint8Array,\n      offset: number,\n      length: number,\n      port?: number,\n      address?: string,\n      callback?: (error: Error | null, bytes: number) => void\n    ): void;\n    send(\n      msg: string | Uint8Array,\n      offset: number,\n      length: number,\n      port?: number,\n      callback?: (error: Error | null, bytes: number) => void\n    ): void;\n    /**\n     * Sets or clears the `SO_BROADCAST` socket option. When set to `true`, UDP packets may be sent to a local interface's broadcast address.\n     *\n     * This method throws `EBADF` if called on an unbound socket.\n     */\n    setBroadcast(flag: boolean): void;\n    /**\n     * _All references to scope in this section are referring to [IPv6 Zone Indices](https://en.wikipedia.org/wiki/IPv6_address#Scoped_literal_IPv6_addresses), which are defined by [RFC 4007](https://tools.ietf.org/html/rfc4007). In string form, an IP_\n     * _with a scope index is written as `'IP%scope'` where scope is an interface name or interface number._\n     *\n     * Sets the default outgoing multicast interface of the socket to a chosen interface or back to system interface selection.\n     * The `multicastInterface` must be a valid string representation of an IP from the socket's family.\n     *\n     * For IPv4 sockets, this should be the IP configured for the desired physical interface.\n     * All packets sent to multicast on the socket will be sent on the interface determined by the most recent successful use of this call.\n     *\n     * For IPv6 sockets, `multicastInterface` should include a scope to indicate the interface as in the examples that follow.\n     * In IPv6, individual `send` calls can also use explicit scope in addresses, so only packets sent to a multicast address without specifying an explicit scope are affected by the most recent successful use of this call.\n     *\n     * This method throws `EBADF` if called on an unbound socket.\n     *\n     * #### Example: IPv6 outgoing multicast interface\n     *\n     * On most systems, where scope format uses the interface name:\n     *\n     * ```js\n     * const socket = dgram.createSocket('udp6');\n     *\n     * socket.bind(1234, () => {\n     *   socket.setMulticastInterface('::%eth1');\n     * });\n     * ```\n     *\n     * On Windows, where scope format uses an interface number:\n     *\n     * ```js\n     * const socket = dgram.createSocket('udp6');\n     *\n     * socket.bind(1234, () => {\n     *   socket.setMulticastInterface('::%2');\n     * });\n     * ```\n     *\n     * #### Example: IPv4 outgoing multicast interface\n     *\n     * All systems use an IP of the host on the desired physical interface:\n     *\n     * ```js\n     * const socket = dgram.createSocket('udp4');\n     *\n     * socket.bind(1234, () => {\n     *   socket.setMulticastInterface('10.0.0.2');\n     * });\n     * ```\n     */\n    setMulticastInterface(multicastInterface: string): void;\n    /**\n     * Sets or clears the `IP_MULTICAST_LOOP` socket option. When set to `true`, multicast packets will also be received on the local interface.\n     *\n     * This method throws `EBADF` if called on an unbound socket.\n     */\n    setMulticastLoopback(flag: boolean): void;\n    /**\n     * Sets the `IP_MULTICAST_TTL` socket option. While TTL generally stands for \"Time to Live\", in this context it specifies the number of IP hops that a packet is allowed to travel through, specifically for multicast traffic.\n     * Each router or gateway that forwards a packet decrements the TTL. If the TTL is decremented to 0 by a router, it will not be forwarded.\n     *\n     * The `ttl` argument may be between 0 and 255. The default on most systems is `1`.\n     *\n     * This method throws `EBADF` if called on an unbound socket.\n     */\n    setMulticastTTL(ttl: number): void;\n    /**\n     * Sets the `IP_RECVTOS` socket option. When enabled, the socket will return the Type of Service (TOS) header field on received packets.\n     *\n     * This method throws `EBADF` if called on an unbound socket.\n     */\n    setRecvBufferSize(size: number): void;\n    /**\n     * Sets the `SO_SNDBUF` socket option. Sets the maximum socket send buffer in bytes.\n     *\n     * This method throws `EBADF` if called on an unbound socket.\n     */\n    setSendBufferSize(size: number): void;\n    /**\n     * Sets the `IP_TTL` socket option. While TTL generally stands for \"Time to Live\", in this context it specifies the number of IP hops that a packet is allowed to travel through.\n     * Each router or gateway that forwards a packet decrements the TTL. If the TTL is decremented to 0 by a router, it will not be forwarded.\n     * Changing TTL values is typically done for network probes or when multicasting.\n     *\n     * The `ttl` argument may be between 1 and 255. The default on most systems is 64.\n     *\n     * This method throws `EBADF` if called on an unbound socket.\n     */\n    setTTL(ttl: number): void;\n    /**\n     * By default, binding a socket will cause it to block the LLRT process from exiting as long as the socket is open.\n     * The `socket.unref()` method can be used to exclude the socket from the reference counting that keeps the LLRT process active, allowing the process to exit even if the socket is still listening.\n     *\n     * Calling `socket.unref()` multiple times will have no addition effect.\n     *\n     * The `socket.unref()` method returns a reference to the socket so calls can be chained.\n     */\n    unref(): this;\n    /**\n     * Emitted when the socket is closed with {@link close}.\n     * No new `'message'` events will be emitted on this socket.\n     */\n    addListener(event: \"close\", listener: () => void): this;\n    /**\n     * Emitted when the socket is ready to receive data.\n     */\n    addListener(event: \"listening\", listener: () => void): this;\n    /**\n     * Emitted when a new datagram is available on a socket.\n     * The event handler function is passed two arguments: `msg` and `rinfo`.\n     */\n    addListener(\n      event: \"message\",\n      listener: (msg: Buffer, rinfo: RemoteInfo) => void\n    ): this;\n    /**\n     * Emitted when an error occurs. The event handler function is passed a single `Error` object.\n     */\n    addListener(event: \"error\", listener: (err: Error) => void): this;\n    addListener(event: string, listener: (...args: any[]) => void): this;\n    emit(event: \"close\"): boolean;\n    emit(event: \"listening\"): boolean;\n    emit(event: \"message\", msg: Buffer, rinfo: RemoteInfo): boolean;\n    emit(event: \"error\", err: Error): boolean;\n    emit(event: string | symbol, ...args: any[]): boolean;\n    on(event: \"close\", listener: () => void): this;\n    on(event: \"listening\", listener: () => void): this;\n    on(\n      event: \"message\",\n      listener: (msg: Buffer, rinfo: RemoteInfo) => void\n    ): this;\n    on(event: \"error\", listener: (err: Error) => void): this;\n    on(event: string, listener: (...args: any[]) => void): this;\n    once(event: \"close\", listener: () => void): this;\n    once(event: \"listening\", listener: () => void): this;\n    once(\n      event: \"message\",\n      listener: (msg: Buffer, rinfo: RemoteInfo) => void\n    ): this;\n    once(event: \"error\", listener: (err: Error) => void): this;\n    once(event: string, listener: (...args: any[]) => void): this;\n    prependListener(event: \"close\", listener: () => void): this;\n    prependListener(event: \"listening\", listener: () => void): this;\n    prependListener(\n      event: \"message\",\n      listener: (msg: Buffer, rinfo: RemoteInfo) => void\n    ): this;\n    prependListener(event: \"error\", listener: (err: Error) => void): this;\n    prependListener(event: string, listener: (...args: any[]) => void): this;\n    prependOnceListener(event: \"close\", listener: () => void): this;\n    prependOnceListener(event: \"listening\", listener: () => void): this;\n    prependOnceListener(\n      event: \"message\",\n      listener: (msg: Buffer, rinfo: RemoteInfo) => void\n    ): this;\n    prependOnceListener(event: \"error\", listener: (err: Error) => void): this;\n    prependOnceListener(\n      event: string,\n      listener: (...args: any[]) => void\n    ): this;\n  }\n\n  interface AddressInfo {\n    address: string;\n    family: \"IPv4\" | \"IPv6\";\n    port: number;\n  }\n\n  /**\n   * Creates a `dgram.Socket` object. Once the socket is created, calling `socket.bind()` will instruct the socket to begin listening for datagram messages.\n   * When `address` and `port` are not passed to `socket.bind()` the method will bind the socket to the \"all interfaces\" address on a random port (it does the right thing for both `udp4` and `udp6` sockets).\n   * The bound address and port can be retrieved using `socket.address().address` and `socket.address().port`.\n   *\n   * If the `signal` option is enabled, calling `.abort()` on the corresponding `AbortController` is similar to calling `.close()` on the socket:\n   *\n   * ```js\n   * const controller = new AbortController();\n   * const { signal } = controller;\n   * const server = dgram.createSocket({ type: 'udp4', signal });\n   * server.on('message', (msg, rinfo) => {\n   *   console.log(`server got: ${msg} from ${rinfo.address}:${rinfo.port}`);\n   * });\n   * // Later, when you want to close the server.\n   * controller.abort();\n   * ```\n   *\n   * @param type The family of socket. Must be either 'udp4' or 'udp6'.\n   * @param callback Attached as a listener to `'message'` events.\n   */\n  function createSocket(\n    type: SocketType,\n    callback?: (msg: Buffer, rinfo: RemoteInfo) => void\n  ): Socket;\n  function createSocket(\n    options: SocketOptions,\n    callback?: (msg: Buffer, rinfo: RemoteInfo) => void\n  ): Socket;\n}\ndeclare module \"node:dgram\" {\n  export * from \"dgram\";\n}\n"
  },
  {
    "path": "types/dns.d.ts",
    "content": "/**\n * The `dns` module enables name resolution. For example, use it to look up IP\n * addresses of host names.\n *\n * Although named for the [Domain Name System (DNS)](https://en.wikipedia.org/wiki/Domain_Name_System), it does not always use the\n * DNS protocol for lookups. {@link lookup} uses the operating system\n * facilities to perform name resolution. It may not need to perform any network\n * communication. To perform name resolution the way other applications on the same\n * system do, use {@link lookup}.\n *\n * ```js\n * import dns from 'dns';\n *\n * dns.lookup('example.org', (err, address, family) => {\n *   console.log('address: %j family: IPv%s', address, family);\n * });\n * // address: \"93.184.216.34\" family: IPv4\n * ```\n *\n */\ndeclare module \"dns\" {\n  export interface LookupOptions {\n    /**\n     * The record family. Must be `4`, `6`, or `0`.\n     * The value 0 indicates that either an IPv4 or IPv6 address is returned.\n     * @default 0\n     */\n    family?: number | \"IPv4\" | \"IPv6\" | undefined;\n    /**\n     * When `true`, the callback returns all resolved addresses in an array. Otherwise, returns a single address.\n     * @default false\n     */\n    all?: boolean | undefined;\n    /**\n     * When `verbatim`, the resolved addresses are return unsorted. When `ipv4first`, the resolved addresses are sorted\n     * by placing IPv4 addresses before IPv6 addresses. When `ipv6first`, the resolved addresses are sorted by placing IPv6\n     * addresses before IPv4 addresses. Default value is configurable using\n     * {@link setDefaultResultOrder} or [`--dns-result-order`](https://nodejs.org/docs/latest-v20.x/api/cli.html#--dns-result-orderorder).\n     * @default `verbatim` (addresses are not reordered)\n     */\n    order?: \"verbatim\" | \"ipv4first\" | \"ipv6first\" | undefined;\n  }\n  export interface LookupOneOptions extends LookupOptions {\n    all?: false | undefined;\n  }\n  export interface LookupAllOptions extends LookupOptions {\n    all: true;\n  }\n  export interface LookupAddress {\n    /**\n     * A string representation of an IPv4 or IPv6 address.\n     */\n    address: string;\n    /**\n     * `4` or `6`, denoting the family of `address`, or `0` if the address is not an IPv4 or IPv6 address. `0` is a likely indicator of a\n     * bug in the name resolution service used by the operating system.\n     */\n    family: number;\n  }\n  /**\n   * Resolves a host name (e.g. `'nodejs.org'`) into the first found A (IPv4) or\n   * AAAA (IPv6) record. All `option` properties are optional. If `options` is an\n   * integer, then it must be `4` or `6` – if `options` is `0` or not provided, then\n   * IPv4 and IPv6 addresses are both returned if found.\n   *\n   * On error, `err` is an `Error` object, where `err.code` is the error code.\n   * Keep in mind that `err.code` will be set to `'ENOTFOUND'` not only when\n   * the host name does not exist but also when the lookup fails in other ways\n   * such as no available file descriptors.\n   *\n   * `dns.lookup()` does not necessarily have anything to do with the DNS protocol.\n   * The implementation uses an operating system facility that can associate names\n   * with addresses and vice versa.\n   *\n   * Example usage:\n   *\n   * ```js\n   * import dns from 'dns';\n   * const options = {\n   *   family: 6,\n   * };\n   * dns.lookup('example.com', options, (err, address, family) =>\n   *   console.log('address: %j family: IPv%s', address, family));\n   * // address: \"2606:2800:220:1:248:1893:25c8:1946\" family: IPv6\n   *\n   * ```\n   *\n   */\n  export function lookup(\n    hostname: string,\n    family: number,\n    callback: (\n      err: DOMException | null,\n      address: string,\n      family: number\n    ) => void\n  ): void;\n  export function lookup(\n    hostname: string,\n    options: LookupOneOptions,\n    callback: (err: Error | null, address: string, family: number) => void\n  ): void;\n  export function lookup(\n    hostname: string,\n    options: LookupAllOptions,\n    callback: (err: Error | null, addresses: LookupAddress[]) => void\n  ): void;\n  export function lookup(\n    hostname: string,\n    options: LookupOptions,\n    callback: (\n      err: Error | null,\n      address: string | LookupAddress[],\n      family: number\n    ) => void\n  ): void;\n  export function lookup(\n    hostname: string,\n    callback: (err: Error | null, address: string, family: number) => void\n  ): void;\n}\ndeclare module \"dns\" {\n  export * from \"dns\";\n}\n"
  },
  {
    "path": "types/dom-events.d.ts",
    "content": "export {};\n\ninterface EventListener {\n  (evt: Event): void;\n}\n\ninterface AddEventListenerOptions {\n  /** When `true`, the listener is automatically removed when it is first invoked. Default: `false`. */\n  once?: boolean;\n}\n\ndeclare global {\n  type EventKey = string | symbol;\n\n  /** An event which takes place in the system. */\n  interface Event {\n    /** Returns the type of event, e.g. \"click\", \"hashchange\", or \"submit\". */\n    readonly type: EventKey;\n  }\n\n  class CustomEvent<D = any> implements Event {\n    constructor(type: string, opts?: { details?: D });\n    readonly type: string;\n    readonly details: D | null;\n  }\n\n  /**\n   * EventTarget is an interface implemented by objects that can\n   * receive events and may have listeners for them.\n   */\n  class EventTarget {\n    constructor();\n\n    /**\n     * Adds a new handler for the `type` event. Any given `listener` is added only once per `type`.\n     *\n     * If the `once` option is true, the `listener` is removed after the next time a `type` event is dispatched.\n     */\n    addEventListener(\n      type: EventKey,\n      listener: EventListener,\n      options?: AddEventListenerOptions\n    ): void;\n\n    /** Dispatches a synthetic event event to target */\n    dispatchEvent(event: Event): void;\n\n    /** Removes the event listener in target's event listener list with the same type and callback */\n    removeEventListener(type: EventKey, listener: EventListener): void;\n  }\n}\n"
  },
  {
    "path": "types/events.d.ts",
    "content": "declare module \"events\" {\n  type EventMap<T> = Record<keyof T, any[]> | DefaultEventMap;\n  type DefaultEventMap = [never];\n  type AnyRest = [...args: any[]];\n  type Args<K, T> = T extends DefaultEventMap\n    ? AnyRest\n    : K extends keyof T\n      ? T[K]\n      : never;\n  type Key<K, T> = T extends DefaultEventMap ? EventKey : K | keyof T;\n  type Key2<K, T> = T extends DefaultEventMap ? EventKey : K & keyof T;\n  type Listener<K, T, F> = T extends DefaultEventMap\n    ? F\n    : K extends keyof T\n      ? T[K] extends unknown[]\n        ? (...args: T[K]) => void\n        : never\n      : never;\n  type Listener1<K, T> = Listener<K, T, (...args: any[]) => void>;\n\n  export class EventEmitter<T extends EventMap<T> = DefaultEventMap> {\n    constructor();\n\n    /**\n     * Alias for `emitter.on(eventName, listener)`.\n     */\n    addListener<K>(eventName: Key<K, T>, listener: Listener1<K, T>): this;\n\n    /**\n     * Adds the `listener` function to the end of the listeners array for the event\n     * named `eventName`. No checks are made to see if the `listener` has already\n     * been added. Multiple calls passing the same combination of `eventName` and\n     * `listener` will result in the `listener` being added, and called, multiple times.\n     *\n     * ```js\n     * server.on('connection', (stream) => {\n     *   console.log('someone connected!');\n     * });\n     * ```\n     *\n     * Returns a reference to the `EventEmitter`, so that calls can be chained.\n     *\n     * By default, event listeners are invoked in the order they are added. The `emitter.prependListener()` method can be used as an alternative to add the\n     * event listener to the beginning of the listeners array.\n     *\n     * ```js\n     * import { EventEmitter } from 'events';\n     * const myEE = new EventEmitter();\n     * myEE.on('foo', () => console.log('a'));\n     * myEE.prependListener('foo', () => console.log('b'));\n     * myEE.emit('foo');\n     * // Prints:\n     * //   b\n     * //   a\n     * ```\n     * @param eventName The name of the event.\n     * @param listener The callback function\n     */\n    on<K>(eventName: Key<K, T>, listener: Listener1<K, T>): this;\n\n    /**\n     * Adds a **one-time** `listener` function for the event named `eventName`. The\n     * next time `eventName` is triggered, this listener is removed and then invoked.\n     *\n     * Returns a reference to the `EventEmitter`, so that calls can be chained.\n     *\n     * By default, event listeners are invoked in the order they are added. The `emitter.prependOnceListener()` method can be used as an alternative to add the\n     * event listener to the beginning of the listeners array.\n     *\n     * ```js\n     * import { EventEmitter } from 'events';\n     * const myEE = new EventEmitter();\n     * myEE.once('foo', () => console.log('a'));\n     * myEE.prependOnceListener('foo', () => console.log('b'));\n     * myEE.emit('foo');\n     * // Prints:\n     * //   b\n     * //   a\n     * ```\n     * @since v0.3.0\n     * @param eventName The name of the event.\n     * @param listener The callback function\n     */\n    once<K>(eventName: Key<K, T>, listener: Listener1<K, T>): this;\n\n    /**\n     * Removes the specified `listener` from the listener array for the event named `eventName`.\n     *\n     * `removeListener()` will remove, at most, one instance of a listener from the\n     * listener array. If any single listener has been added multiple times to the\n     * listener array for the specified `eventName`, then `removeListener()` must be\n     * called multiple times to remove each instance.\n     *\n     * Once an event is emitted, all listeners attached to it at the time of emitting are called in order.\n     * This implies that any `removeListener()` calls _after_ emitting and _before_ the last listener finishes execution\n     * will not remove them from `emit()` in progress. Subsequent events behave as expected.\n     *\n     * ```js\n     * import { EventEmitter } from 'events';\n     * class MyEmitter extends EventEmitter {}\n     * const myEmitter = new MyEmitter();\n     *\n     * const callbackA = () => {\n     *   console.log('A');\n     *   myEmitter.removeListener('event', callbackB);\n     * };\n     *\n     * const callbackB = () => {\n     *   console.log('B');\n     * };\n     *\n     * myEmitter.on('event', callbackA);\n     *\n     * myEmitter.on('event', callbackB);\n     *\n     * // callbackA removes listener callbackB but it will still be called.\n     * // Internal listener array at time of emit [callbackA, callbackB]\n     * myEmitter.emit('event');\n     * // Prints:\n     * //   A\n     * //   B\n     *\n     * // callbackB is now removed.\n     * // Internal listener array [callbackA]\n     * myEmitter.emit('event');\n     * // Prints:\n     * //   A\n     * ```\n     *\n     * Because listeners are managed using an internal array, calling this will\n     * change the position indices of any listener registered _after_ the listener\n     * being removed. This will not impact the order in which listeners are called,\n     * but it means that any copies of the listener array as returned by\n     * the `emitter.listeners()` method will need to be recreated.\n     *\n     * When a single function has been added as a handler multiple times for a single\n     * event (as in the example below), `removeListener()` will remove the most\n     * recently added instance. In the example the `once('ping')` listener is removed:\n     *\n     * ```js\n     * import { EventEmitter } from 'events';\n     * const ee = new EventEmitter();\n     *\n     * function pong() {\n     *   console.log('pong');\n     * }\n     *\n     * ee.on('ping', pong);\n     * ee.once('ping', pong);\n     * ee.removeListener('ping', pong);\n     *\n     * ee.emit('ping');\n     * ee.emit('ping');\n     * ```\n     *\n     * Returns a reference to the `EventEmitter`, so that calls can be chained.\n     */\n    removeListener<K>(eventName: Key<K, T>, listener: Listener1<K, T>): this;\n\n    /**\n     * Alias for `emitter.removeListener()`.\n     */\n    off<K>(eventName: Key<K, T>, listener: Listener1<K, T>): this;\n\n    /**\n     * Synchronously calls each of the listeners registered for the event named `eventName`, in the order they were registered, passing the supplied arguments\n     * to each.\n     *\n     * ```js\n     * import { EventEmitter } from 'events';\n     * const myEmitter = new EventEmitter();\n     *\n     * // First listener\n     * myEmitter.on('event', function firstListener() {\n     *   console.log('Helloooo! first listener');\n     * });\n     * // Second listener\n     * myEmitter.on('event', function secondListener(arg1, arg2) {\n     *   console.log(`event with parameters ${arg1}, ${arg2} in second listener`);\n     * });\n     * // Third listener\n     * myEmitter.on('event', function thirdListener(...args) {\n     *   const parameters = args.join(', ');\n     *   console.log(`event with parameters ${parameters} in third listener`);\n     * });\n     *\n     * myEmitter.emit('event', 1, 2, 3, 4, 5);\n     *\n     * // Prints:\n     * // Helloooo! first listener\n     * // event with parameters 1, 2 in second listener\n     * // event with parameters 1, 2, 3, 4, 5 in third listener\n     * ```\n     */\n    emit<K>(eventName: Key<K, T>, ...args: Args<K, T>): void;\n\n    /**\n     * Adds the `listener` function to the _beginning_ of the listeners array for the\n     * event named `eventName`. No checks are made to see if the `listener` has\n     * already been added. Multiple calls passing the same combination of `eventName`\n     * and `listener` will result in the `listener` being added, and called, multiple times.\n     *\n     *\n     * Returns a reference to the `EventEmitter`, so that calls can be chained.\n     * @param eventName The name of the event.\n     * @param listener The callback function\n     */\n    prependListener<K>(eventName: Key<K, T>, listener: Listener1<K, T>): this;\n\n    /**\n     * Adds a **one-time**`listener` function for the event named `eventName` to the _beginning_ of the listeners array.\n     * The next time `eventName` is triggered, this listener is removed, and then invoked.\n     *\n     * Returns a reference to the `EventEmitter`, so that calls can be chained.\n     * @param eventName The name of the event.\n     * @param listener The callback function\n     */\n    prependOnceListener<K>(\n      eventName: Key<K, T>,\n      listener: Listener1<K, T>\n    ): this;\n\n    /**\n     * Returns an array listing the events for which the emitter has registered\n     * listeners. The values in the array are strings or `Symbol`s.\n     *\n     * ```js\n     * import { EventEmitter } from 'events';\n     *\n     * const myEE = new EventEmitter();\n     * myEE.on('foo', () => {});\n     * myEE.on('bar', () => {});\n     *\n     * const sym = Symbol('symbol');\n     * myEE.on(sym, () => {});\n     *\n     * console.log(myEE.eventNames());\n     * // Prints: [ 'foo', 'bar', Symbol(symbol) ]\n     * ```\n     */\n    eventNames(): Array<EventKey & Key2<unknown, T>>;\n  }\n\n  export default EventEmitter;\n}\n"
  },
  {
    "path": "types/exceptions.d.ts",
    "content": "export {};\n\ndeclare global {\n  interface Error {\n    name: string;\n    message: string;\n    stack?: string;\n  }\n\n  interface ErrorConstructor {\n    new (message?: string): Error;\n    (message?: string): Error;\n    readonly prototype: Error;\n  }\n\n  interface DOMException extends Error {\n    readonly message: string;\n    readonly name: string;\n    readonly stack: string;\n  }\n  var Error: ErrorConstructor;\n  var DOMException: {\n    prototype: DOMException;\n    new (message?: string, name?: string): DOMException;\n  };\n}\n"
  },
  {
    "path": "types/fetch.d.ts",
    "content": "import { Agent } from \"https\";\n\nexport {};\n\ndeclare global {\n  interface BlobOpts {\n    /**\n     * One of either `'transparent'` or `'native'`. When set to `'native'`, line endings in string source parts\n     * will be converted to the platform native line-ending as specified by `import { EOL } from 'os'`.\n     */\n    endings?: \"transparent\" | \"native\";\n    /**\n     * The Blob content-type. The intent is for `type` to convey the MIME media type of the data,\n     * however no validation of the type format is performed.\n     */\n    type?: string | undefined;\n  }\n\n  /**\n   * The `Body` of a {@link Response} or {@link Request}.\n   * Currently NOT a `ReadableStream`.\n   */\n  type Body = QuickJS.ArrayBufferView | Blob | null;\n\n  /**\n   * A [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) encapsulates immutable, raw data.\n   */\n  class Blob {\n    /**\n     * Creates a new `Blob` object containing a concatenation of the given sources.\n     *\n     * {ArrayBuffer}, and {Blob} sources are copied into the 'Blob' and can therefore be\n     * safely modified after the 'Blob' is created.\n     *\n     * String sources are also copied into the `Blob`.\n     */\n    constructor(parts: Array<ArrayBuffer | string | Blob>, opts?: BlobOpts);\n    /**\n     * The total size of the `Blob` in bytes.\n     */\n    readonly size: number;\n    /**\n     * The content-type of the `Blob`.\n     */\n    readonly type: string;\n    /**\n     * Returns a promise that fulfills with an [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) containing a copy of\n     * the `Blob` data.\n     */\n    arrayBuffer(): Promise<ArrayBuffer>;\n    /**\n     * Creates and returns a new `Blob` containing a subset of this `Blob` objects\n     * data. The original `Blob` is not altered.\n     * @param start The starting index.\n     * @param end The ending index.\n     * @param type The content-type for the new `Blob`\n     */\n    slice(start?: number, end?: number, type?: string): Blob;\n    /**\n     * Returns a promise that fulfills with the contents of the `Blob` decoded as a UTF-8 string.\n     */\n    text(): Promise<string>;\n    /**\n     * Returns a promise that resolves with an Uint8Array containing the contents of the Blob.\n     */\n    bytes(): Promise<Uint8Array>;\n  }\n\n  interface FileOpts extends BlobOpts {\n    /**\n     * The last modified date of the file as the number of milliseconds since the Unix epoch (January 1, 1970 at midnight).\n     * Files without a known last modified date return the current date.\n     */\n    lastModified?: number;\n  }\n\n  class File extends Blob {\n    /**\n     * Returns a newly constructed File.\n     */\n    constructor(\n      data: Array<ArrayBuffer | string | Blob>,\n      fileName: string,\n      opts?: FileOpts\n    );\n    /**\n     * Name of the file referenced by the File object.\n     */\n    readonly name: string;\n    /**\n     * The last modified date of the file as the number of milliseconds since the Unix epoch (January 1, 1970 at midnight).\n     * Files without a known last modified date return the current date.\n     */\n    readonly lastModified: number;\n  }\n\n  type HeadersLike = Record<string, string> | Headers;\n\n  type HeadersOpts = string[][] | HeadersLike;\n\n  class Headers implements Iterable<[string, string]> {\n    /**\n     * Creates a new Headers object.\n     */\n    constructor(opts?: HeadersOpts);\n    /**\n     * Appends a new value onto an existing header inside a Headers object, or adds the header if it does not already exist.\n     */\n    readonly append: (name: string, value: string) => void;\n    /**\n     * Deletes a header from a Headers object.\n     */\n    readonly delete: (name: string) => void;\n    /**\n     * A String sequence representing the values of the retrieved header or null if this header is not set.\n     */\n    readonly get: (name: string) => string | null;\n    /**\n     * Returns a boolean stating whether a Headers object contains a certain header.\n     */\n    readonly has: (name: string) => boolean;\n    /**\n     * Sets a new value for an existing header inside a Headers object, or adds the header if it does not already exist.\n     */\n    readonly set: (name: string, value: string) => void;\n    /**\n     * Returns an array containing the values of all Set-Cookie headers associated with a response.\n     */\n    readonly getSetCookie: () => string[];\n    /**\n     * Executes a provided function once for each key/value pair in this Headers object.\n     */\n    readonly forEach: (\n      callbackfn: (value: string, key: string) => void\n    ) => void;\n    /**\n     * Returns an iterator allowing you to go through all keys of the key/value pairs contained in this object.\n     */\n    readonly keys: () => IterableIterator<string>;\n    /**\n     * Returns an iterator allowing you to go through all values of the key/value pairs contained in this object.\n     */\n    readonly values: () => IterableIterator<string>;\n    /**\n     * Returns an iterator allowing to go through all key/value pairs contained in this object.\n     */\n    readonly entries: () => IterableIterator<[string, string]>;\n    readonly [Symbol.iterator]: () => Iterator<[string, string]>;\n  }\n\n  interface RequestOpts {\n    url?: string;\n    method?: string;\n    signal?: AbortSignal;\n    body?: Blob;\n    headers?: HeadersLike;\n    agent?: Agent;\n  }\n\n  type RequestCache = \"no-cache\";\n\n  type RequestMode = \"navigate\";\n\n  /**\n   * The Request interface of the Fetch API represents a resource request.\n   */\n  class Request {\n    /**\n     * Creates a new Request object.\n     */\n    constructor(input: string | URL | Request, init?: RequestOpts);\n    /**\n     * Contains the cache mode of the request\n     */\n    readonly cache: RequestCache;\n    /**\n     * Contains the associated Headers object of the request.\n     */\n    readonly headers: Headers;\n    /**\n     * Contains the request's method (GET, POST, etc.)\n     */\n    readonly method: string;\n    /**\n     * Contains the mode of the request\n     */\n    readonly mode: RequestMode;\n    /**\n     * Contains the URL of the request.\n     */\n    readonly url: string;\n    /**\n     * Contains the request's keepalive setting (true or false), which indicates whether llrt will\n     * keep the associated connection alive.\n     */\n    readonly keepalive: boolean;\n    /**\n     * Returns the {@link AbortSignal} associated with the request\n     */\n    readonly signal: AbortSignal;\n    /**\n     * The body content.\n     */\n    readonly body: Body;\n    /**\n     * Stores true or false to indicate whether or not the body has been used in a request yet.\n     */\n    readonly bodyUsed: boolean;\n    /**\n     * The {@link Agent} associated with the request.\n     */\n    readonly agent: Agent;\n    /**\n     * Returns a promise that resolves with an ArrayBuffer representation of the request body.\n     */\n    readonly arrayBuffer: () => Promise<ArrayBuffer>;\n    /**\n     * Returns a promise that resolves with a {@link Blob} representation of the request body.\n     */\n    readonly blob: () => Promise<Blob>;\n    /**\n     * Returns a promise that resolves with a {@link Uint8Array} representation of the request body.\n     */\n    readonly bytes: () => Promise<Uint8Array>;\n    /**\n     * Returns a promise that resolves with the result of parsing the request body as JSON.\n     */\n    readonly json: () => Promise<unknown>;\n    /**\n     * Returns a promise that resolves with a text representation of the request body.\n     */\n    readonly text: () => Promise<string>;\n    /**\n     * Creates a copy of the current {@link Request} object.\n     */\n    readonly clone: () => Request;\n  }\n\n  type ResponseType = \"basic\" | \"error\";\n\n  interface ResponseInit {\n    readonly status?: number;\n    readonly statusText?: string;\n    readonly headers?: HeadersLike;\n  }\n\n  interface ResponseOpts extends ResponseInit {\n    readonly url?: string;\n    readonly signal?: AbortSignal;\n  }\n\n  /**\n   * The Response interface of the Fetch API represents the response to a request.\n   */\n  class Response {\n    /**\n     * Creates a new Response object.\n     */\n    constructor(body?: Body, opts?: ResponseOpts);\n\n    /**\n     * The {@link Headers} object associated with the response.\n     */\n    readonly headers: Headers;\n    /**\n     * A boolean indicating whether the response was successful (status in the range 200 – 299) or not.\n     */\n    readonly ok: boolean;\n    /**\n     * The status code of the response. (This will be 200 for a success).\n     */\n    readonly status: number;\n    /**\n     * The status message corresponding to the status code. (e.g., OK for 200).\n     */\n    readonly statusText: string;\n    /**\n     * The type of the response.\n     */\n    readonly type: ResponseType;\n    readonly url: string;\n    /**\n     * Indicates whether or not the response is the result of a redirect (that is, its URL list has more than one entry).\n     */\n    readonly redirected: boolean;\n    /**\n     * The body content (NOT IMPLEMENTED YET).\n     */\n    readonly body: undefined;\n    /**\n     * Stores a boolean value that declares whether the body has been used in a response yet.\n     */\n    readonly bodyUsed: boolean;\n    /**\n     * Returns a promise that resolves with an {@link ArrayBuffer} representation of the response body.\n     */\n    readonly arrayBuffer: () => Promise<ArrayBuffer>;\n    /**\n     * Returns a promise that resolves with a {@link Blob} representation of the response body.\n     */\n    readonly blob: () => Promise<Blob>;\n    /**\n     * Returns a promise that resolves with the result of parsing the response body text as JSON.\n     */\n    readonly json: () => Promise<unknown>;\n    /**\n     * Returns a promise that resolves with a text representation of the response body.\n     */\n    readonly text: () => Promise<string>;\n    /**\n     * Creates a clone of a {@link Response} object.\n     */\n    readonly clone: () => Response;\n    /**\n     * Returns a new {@link Response} object associated with a network error.\n     */\n    static error(): Response;\n    /**\n     * Returns a new {@link Response} object for returning the provided JSON encoded data.\n     */\n    static json(data: any, init?: ResponseInit): Response;\n    /**\n     * Returns a new {@link Response} with a different URL.\n     */\n    static redirect(url: string | URL, status?: number): Response;\n  }\n\n  function fetch(\n    input: string | URL | Request,\n    init?: RequestOpts\n  ): Promise<Response>;\n}\n"
  },
  {
    "path": "types/fs/promises.d.ts",
    "content": "/**\n * The `fs/promises` API provides asynchronous file system methods that return\n * promises.\n */\ndeclare module \"fs/promises\" {\n  import { Buffer, BufferEncoding } from \"buffer\";\n  import {\n    constants as fsConstants,\n    Dirent,\n    MakeDirectoryOptions,\n    Mode,\n    PathLike,\n    RmDirOptions,\n    RmOptions,\n    Stats,\n  } from \"fs\";\n\n  export type FileSystemFlags =\n    | \"a\"\n    | \"ax\"\n    | \"a+\"\n    | \"r\"\n    | \"r+\"\n    | \"w\"\n    | \"wx\"\n    | \"w+\"\n    | \"wx+\";\n\n  interface FileReadResult<T extends QuickJS.ArrayBufferView> {\n    bytesRead: number;\n    buffer: T;\n  }\n\n  interface FileReadOptions<T extends QuickJS.ArrayBufferView = Buffer> {\n    /**\n     * @default `Buffer.alloc(16384)`\n     */\n    buffer?: T;\n    /**\n     * @default 0\n     */\n    offset?: number | null;\n    /**\n     * @default `buffer.byteLength - offset`\n     */\n    length?: number | null;\n    position?: number | null;\n  }\n\n  class FileHandle {\n    /**\n     * The numeric file descriptor managed by the {FileHandle} object.\n     */\n    readonly fd: number;\n\n    /**\n     * Changes the ownership of the file. A wrapper for [`chown(2)`](http://man7.org/linux/man-pages/man2/chown.2.html).\n     * @param uid The file's new owner's user id.\n     * @param gid The file's new group's group id.\n     * @return Fulfills with `undefined` upon success.\n     */\n    chown(uid: number, gid: number): Promise<void>;\n\n    /**\n     * Modifies the permissions on the file. See [`chmod(2)`](http://man7.org/linux/man-pages/man2/chmod.2.html).\n     * @param mode the file mode bit mask.\n     * @return Fulfills with `undefined` upon success.\n     */\n    chmod(mode: Mode): Promise<void>;\n\n    /**\n     * Forces all currently queued I/O operations associated with the file to the\n     * operating system's synchronized I/O completion state. Refer to the POSIX [`fdatasync(2)`](http://man7.org/linux/man-pages/man2/fdatasync.2.html) documentation for details.\n     *\n     * Unlike `filehandle.sync` this method does not flush modified metadata.\n     * @return Fulfills with `undefined` upon success.\n     */\n    datasync(): Promise<void>;\n\n    /**\n     * Request that all data for the open file descriptor is flushed to the storage\n     * device. The specific implementation is operating system and device specific.\n     * Refer to the POSIX [`fsync(2)`](http://man7.org/linux/man-pages/man2/fsync.2.html) documentation for more detail.\n     * @return Fulfills with `undefined` upon success.\n     */\n    sync(): Promise<void>;\n\n    /**\n     * Reads data from the file and stores that in the given buffer.\n     *\n     * If the file is not modified concurrently, the end-of-file is reached when the\n     * number of bytes read is zero.\n     * @param buffer A buffer that will be filled with the file data read.\n     * @param offset The location in the buffer at which to start filling.\n     * @param length The number of bytes to read.\n     * @param position The location where to begin reading data from the file. If `null`, data will be read from the current file position, and the position will be updated. If `position` is an\n     * integer, the current file position will remain unchanged.\n     * @return Fulfills upon success with an object with two properties: bytesRead and buffer\n     */\n    read<T extends QuickJS.ArrayBufferView>(\n      buffer: T,\n      offset?: number | null,\n      length?: number | null,\n      position?: number | null\n    ): Promise<FileReadResult<T>>;\n    read<T extends QuickJS.ArrayBufferView = Buffer>(\n      buffer: T,\n      options?: FileReadOptions<T>\n    ): Promise<FileReadResult<T>>;\n    read<T extends QuickJS.ArrayBufferView = Buffer>(\n      options?: FileReadOptions<T>\n    ): Promise<FileReadResult<T>>;\n\n    /**\n     * Asynchronously reads the entire contents of a file.\n     *\n     * If `options` is a string, then it specifies the `encoding`.\n     *\n     * The `FileHandle` has to support reading.\n     *\n     * If one or more `filehandle.read()` calls are made on a file handle and then a `filehandle.readFile()` call is made, the data will be read from the current\n     * position till the end of the file. It doesn't always read from the beginning\n     * of the file.\n     * @return Fulfills upon a successful read with the contents of the file. If no encoding is specified (using `options.encoding`), the data is returned as a {Buffer} object. Otherwise, the\n     * data will be a string.\n     */\n    readFile(\n      options?: {\n        encoding?: null | undefined;\n      } | null\n    ): Promise<Buffer>;\n    readFile(\n      options:\n        | {\n            encoding: BufferEncoding;\n          }\n        | BufferEncoding\n    ): Promise<string>;\n\n    /**\n     * Get {FileHandle} status.\n     * @return Fulfills with the {fs.Stats} object.\n     */\n    stat(): Promise<Stats>;\n\n    /**\n     * Truncates the file.\n     *\n     * If the file was larger than `len` bytes, only the first `len` bytes will be\n     * retained in the file.\n     *\n     * The following example retains only the first four bytes of the file:\n     *\n     * ```js\n     * import { open } from 'fs/promises';\n     *\n     * let filehandle = null;\n     * try {\n     *   filehandle = await open('temp.txt', 'r+');\n     *   await filehandle.truncate(4);\n     * } finally {\n     *   await filehandle?.close();\n     * }\n     * ```\n     *\n     * If the file previously was shorter than `len` bytes, it is extended, and the\n     * extended part is filled with null bytes (`'\\0'`):\n     *\n     * @param [len=0]\n     * @return Fulfills with `undefined` upon success.\n     */\n    truncate(len?: number): Promise<void>;\n\n    /**\n     * Asynchronously writes data to a file, replacing the file if it already exists.\n     *\n     * If `options` is a string, then it specifies the `encoding`.\n     *\n     * The `FileHandle` has to support writing.\n     *\n     * It is unsafe to use `filehandle.writeFile()` multiple times on the same file\n     * without waiting for the promise to be fulfilled (or rejected).\n     *\n     * If one or more `filehandle.write()` calls are made on a file handle and then a`filehandle.writeFile()` call is made, the data will be written from the\n     * current position till the end of the file. It doesn't always write from the beginning of the file.\n     */\n    writeFile(\n      data: string | QuickJS.ArrayBufferView,\n      options?:\n        | {\n            encoding?: BufferEncoding | null;\n          }\n        | BufferEncoding\n        | null\n    ): Promise<void>;\n\n    /**\n     * Write `buffer` to the file.\n     *\n     * The promise is fulfilled with an object containing two properties:\n     *\n     * It is unsafe to use `filehandle.write()` multiple times on the same file\n     * without waiting for the promise to be fulfilled (or rejected). For this\n     * scenario, use `filehandle.createWriteStream()`.\n     *\n     * On Linux, positional writes do not work when the file is opened in append mode.\n     * The kernel ignores the position argument and always appends the data to\n     * the end of the file.\n     * @param offset The start position from within `buffer` where the data to write begins.\n     * @param [length=buffer.byteLength - offset] The number of bytes from `buffer` to write.\n     * @param [position='null'] The offset from the beginning of the file where the data from `buffer` should be written. If `position` is not a `number`, the data will be written at the current\n     * position. See the POSIX pwrite(2) documentation for more detail.\n     */\n    write<TBuffer extends QuickJS.ArrayBufferView>(\n      buffer: TBuffer,\n      offset?: number | null,\n      length?: number | null,\n      position?: number | null\n    ): Promise<{\n      bytesWritten: number;\n      buffer: TBuffer;\n    }>;\n    write<TBuffer extends QuickJS.ArrayBufferView>(\n      buffer: TBuffer,\n      options?: {\n        offset?: number | null;\n        length?: number | null;\n        position?: number | null;\n      } | null\n    ): Promise<{\n      bytesWritten: number;\n      buffer: TBuffer;\n    }>;\n    write(\n      data: string,\n      position?: number | null,\n      encoding?: BufferEncoding | null\n    ): Promise<{\n      bytesWritten: number;\n      buffer: string;\n    }>;\n\n    /**\n     * Closes the file handle after waiting for any pending operation on the handle to\n     * complete.\n     *\n     * ```js\n     * import { open } from 'fs/promises';\n     *\n     * let filehandle;\n     * try {\n     *   filehandle = await open('thefile.txt', 'r');\n     * } finally {\n     *   await filehandle?.close();\n     * }\n     * ```\n     * @return Fulfills with `undefined` upon success.\n     */\n    close(): Promise<void>;\n  }\n\n  const constants: typeof fsConstants;\n\n  /**\n   * Tests a user's permissions for the file or directory specified by `path`.\n   * The `mode` argument is an optional integer that specifies the accessibility\n   * checks to be performed. `mode` should be either the value `fs.constants.F_OK` or a mask consisting of the bitwise OR of any of `fs.constants.R_OK`, `fs.constants.W_OK`, and `fs.constants.X_OK`\n   * (e.g.`fs.constants.W_OK | fs.constants.R_OK`). Check `File access constants` for\n   * possible values of `mode`.\n   *\n   * If the accessibility check is successful, the promise is fulfilled with no\n   * value. If any of the accessibility checks fail, the promise is rejected\n   * with an [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) object. The following example checks if the file`/etc/passwd` can be read and\n   * written by the current process.\n   *\n   * ```js\n   * import { access, constants } from 'fs/promises';\n   *\n   * try {\n   *   await access('/etc/passwd', constants.R_OK | constants.W_OK);\n   *   console.log('can access');\n   * } catch {\n   *   console.error('cannot access');\n   * }\n   * ```\n   *\n   * Using `fsPromises.access()` to check for the accessibility of a file before\n   * calling `fsPromises.open()` is not recommended. Doing so introduces a race\n   * condition, since other processes may change the file's state between the two\n   * calls. Instead, user code should open/read/write the file directly and handle\n   * the error raised if the file is not accessible.\n   * @param [mode=fs.constants.F_OK]\n   * @return Fulfills with `undefined` upon success.\n   */\n  function access(path: PathLike, mode?: Mode): Promise<void>;\n\n  /**\n   * Opens a `FileHandle`.\n   *\n   * Refer to the POSIX [`open(2)`](http://man7.org/linux/man-pages/man2/open.2.html) documentation for more detail.\n   *\n   * Some characters (`< > : \" / \\ | ? *`) are reserved under Windows as documented\n   * by [Naming Files, Paths, and Namespaces](https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file).\n   * @param [flags='r'] See {FileSystemFlags}.\n   * @param [mode=0o666] Sets the file mode if the file is created (UNIX).\n   * @return Fulfills with a {FileHandle} object.\n   */\n  function open(\n    path: PathLike,\n    flags?: FileSystemFlags,\n    mode?: Mode\n  ): Promise<FileHandle>;\n\n  /**\n   * Removes the directory identified by `path`.\n   *\n   * Using `fsPromises.rmdir()` on a file (not a directory) results in the\n   * promise being rejected with an `ENOENT` error on Windows and an `ENOTDIR` error on POSIX.\n   *\n   * To get a behavior similar to the `rm -rf` Unix command, use `fsPromises.rm()` with options `{ recursive: true, force: true }`.\n   * @return Fulfills with `undefined` upon success.\n   */\n  function rmdir(path: PathLike, options?: RmDirOptions): Promise<void>;\n\n  /**\n   * Removes files and directories (modeled on the standard POSIX `rm` utility).\n   * @return Fulfills with `undefined` upon success.\n   */\n  function rm(path: PathLike, options?: RmOptions): Promise<void>;\n\n  /**\n   * Asynchronously creates a directory.\n   *\n   * The optional `options` argument can be an object with a `mode` property and a `recursive` property indicating whether parent directories should be created.\n   * Calling `fsPromises.mkdir()` when `path` is a directory that exists results in a rejection only when `recursive` is false.\n   *\n   * ```js\n   * import { mkdir } from 'fs/promises';\n   *\n   * try {\n   *   const projectFolder = './test/project/123';\n   *   const createDir = await mkdir(projectFolder, { recursive: true });\n   *\n   *   console.log(`created ${createDir}`);\n   * } catch (err) {\n   *   console.error(err.message);\n   * }\n   * ```\n   * @return Upon success, fulfills with `undefined` if `recursive` is `false`, or the first directory path created if `recursive` is `true`.\n   */\n  function mkdir(\n    path: PathLike,\n    options?: MakeDirectoryOptions\n  ): Promise<string>;\n\n  /**\n   * Reads the contents of a directory.\n   *\n   * If `options.withFileTypes` is set to `true`, the returned array will contain `fs.Dirent` objects.\n   *\n   * ```js\n   * import { readdir } from 'fs/promises';\n   *\n   * try {\n   *   const files = await readdir(path);\n   *   for (const file of files)\n   *     console.log(file);\n   * } catch (err) {\n   *   console.error(err);\n   * }\n   * ```\n   * @return Fulfills with an array of the names of the files in the directory excluding `'.'` and `'..'`.\n   */\n  function readdir(\n    path: PathLike,\n    options?: {\n      withFileTypes?: false | undefined;\n      recursive?: boolean | undefined;\n    }\n  ): Promise<string[]>;\n\n  /**\n   * Asynchronous readdir(2) - read a directory.\n   * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.\n   * @param options If called with `withFileTypes: true` the result data will be an array of Dirent.\n   */\n  function readdir(\n    path: PathLike,\n    options: {\n      withFileTypes: true;\n      recursive?: boolean | undefined;\n    }\n  ): Promise<Dirent[]>;\n\n  /**\n   * Asynchronous stat - Get file status.\n   * @param path A path to a file.\n   * @return Fulfills with the {fs.Stats} object for the given `path`.\n   */\n  function stat(path: PathLike): Promise<Stats>;\n\n  /**\n   * Creates a symbolic link.\n   *\n   * The `type` argument is only used on Windows platforms and can be one of `'dir'`, `'file'`, or `'junction'`. If the `type` argument is not a string, LLRT will\n   * autodetect `target` type and use `'file'` or `'dir'`. If the `target` does not\n   * exist, `'file'` will be used. Windows junction points require the destination\n   * path to be absolute. When using `'junction'`, the `target` argument will\n   * automatically be normalized to absolute path. Junction points on NTFS volumes\n   * can only point to directories.\n   * @param [type='null']\n   * @return Fulfills with `undefined` upon success.\n   */\n  function symlink(\n    target: PathLike,\n    path: PathLike,\n    type?: \"dir\" | \"file\" | \"junction\" | null\n  ): Promise<void>;\n\n  /**\n   * Creates a unique temporary directory. A unique directory name is generated by\n   * appending six random characters to the end of the provided `prefix`. Due to\n   * platform inconsistencies, avoid trailing `X` characters in `prefix`. Some\n   * platforms, notably the BSDs, can return more than six random characters, and\n   * replace trailing `X` characters in `prefix` with random characters.\n   *\n   * ```js\n   * import { mkdtemp } from 'fs/promises';\n   * import { join } from 'path';\n   * import { tmpdir } from 'os';\n   *\n   * try {\n   *   await mkdtemp(join(tmpdir(), 'foo-'));\n   * } catch (err) {\n   *   console.error(err);\n   * }\n   * ```\n   *\n   * The `fsPromises.mkdtemp()` method will append the six randomly selected\n   * characters directly to the `prefix` string. For instance, given a directory `/tmp`, if the intention is to create a temporary directory _within_ `/tmp`, the `prefix` must end with a trailing\n   * platform-specific path separator\n   * (`require('path').sep`).\n   * @return Fulfills with a string containing the file system path of the newly created temporary directory.\n   */\n  function mkdtemp(prefix: string): Promise<string>;\n\n  /**\n   * Asynchronously writes data to a file, replacing the file if it already exists.\n   *\n   * The `encoding` option is ignored if `data` is a buffer.\n   *\n   * It is unsafe to use `fsPromises.writeFile()` multiple times on the same file\n   * without waiting for the promise to be settled.\n   *\n   * Similarly to `fsPromises.readFile` \\- `fsPromises.writeFile` is a convenience\n   * method that performs multiple `write` calls internally to write the buffer\n   * passed to it.\n   *\n   * @param file filename or `FileHandle`\n   * @return Fulfills with `undefined` upon success.\n   */\n  function writeFile(\n    file: PathLike,\n    data:\n      | string\n      | Buffer\n      | QuickJS.ArrayBufferView\n      | ArrayBuffer\n      | SharedArrayBuffer,\n    options?:\n      | {\n          mode?: Mode | undefined;\n        }\n      | undefined\n  ): Promise<void>;\n\n  /**\n   * Asynchronously reads the entire contents of a file.\n   *\n   * If no encoding is specified (using `options.encoding`), the data is returned\n   * as a `Buffer` object. Otherwise, the data will be a string.\n   *\n   * If `options` is a string, then it specifies the encoding.\n   *\n   * When the `path` is a directory, the behavior of `fsPromises.readFile()` is\n   * platform-specific. On macOS, Linux, and Windows, the promise will be rejected\n   * with an error. On FreeBSD, a representation of the directory's contents will be\n   * returned.\n   *\n   * An example of reading a `package.json` file.\n   *\n   * ```js\n   * import { readFile } from 'fs/promises';\n   * try {\n   *   const filePath = './package.json';\n   *   const contents = await readFile(filePath, { encoding: 'utf8' });\n   *   console.log(contents);\n   * } catch (err) {\n   *   console.error(err.message);\n   * }\n   * ```\n   *\n   * @param path filename or `FileHandle`\n   * @return Fulfills with the contents of the file.\n   */\n  function readFile(\n    path: PathLike,\n    options?: {\n      encoding?: null | undefined;\n    } | null\n  ): Promise<Buffer>;\n\n  /**\n   * Asynchronously reads the entire contents of a file.\n   * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.\n   * If a `FileHandle` is provided, the underlying file will _not_ be closed automatically.\n   * @param options An object that may contain an optional flag.\n   * If a flag is not provided, it defaults to `'r'`.\n   */\n  function readFile(\n    path: PathLike,\n    options:\n      | {\n          encoding: BufferEncoding;\n        }\n      | BufferEncoding\n  ): Promise<string>;\n\n  /**\n   * Changes the permissions of a file.\n   * @return Fulfills with `undefined` upon success.\n   */\n  function chmod(path: PathLike, mode: Mode): Promise<void>;\n\n  /**\n   * Asynchronously renames a file or directory from `oldPath` to `newPath`.\n   *\n   * ```js\n   * import { rename } from 'fs/promises';\n   *\n   * try {\n   *   await rename('oldfile.txt', 'newfile.txt');\n   *   console.log('Rename complete!');\n   * } catch (err) {\n   *   console.error(err);\n   * }\n   * ```\n   *\n   * @param oldPath A path to a file or directory.\n   * @param newPath The new path for the file or directory.\n   * @return Fulfills with `undefined` upon success.\n   */\n  function rename(oldPath: PathLike, newPath: PathLike): Promise<void>;\n}\n"
  },
  {
    "path": "types/fs.d.ts",
    "content": "/**\n * The `fs` module enables interacting with the file system in a\n * way modeled on standard POSIX functions.\n *\n * To use the promise-based APIs:\n *\n * ```js\n * import * as fs from 'fs/promises';\n * ```\n *\n * To use the sync APIs:\n *\n * ```js\n * import * as fs from 'fs';\n * ```\n *\n * All file system operations have synchronous and promise-based forms.\n */\ndeclare module \"fs\" {\n  import * as promises from \"fs/promises\";\n  import { Buffer, BufferEncoding } from \"buffer\";\n  export { promises };\n\n  /**\n   * Valid types for path values in \"fs\".\n   */\n  export type PathLike = string;\n  export type Mode = number;\n\n  export interface StatsBase<T> {\n    isFile(): boolean;\n    isDirectory(): boolean;\n    isBlockDevice(): boolean;\n    isCharacterDevice(): boolean;\n    isSymbolicLink(): boolean;\n    isFIFO(): boolean;\n    isSocket(): boolean;\n    dev: T;\n    ino: T;\n    mode: T;\n    nlink: T;\n    uid: T;\n    gid: T;\n    rdev: T;\n    size: T;\n    blksize: T;\n    blocks: T;\n    atimeMs: T;\n    mtimeMs: T;\n    ctimeMs: T;\n    birthtimeMs: T;\n    atime: Date;\n    mtime: Date;\n    ctime: Date;\n    birthtime: Date;\n  }\n  export interface Stats extends StatsBase<number> {}\n  /**\n   * A `fs.Stats` object provides information about a file.\n   *\n   * `Stat` objects are not to be created directly using the `new` keyword.\n   *\n   * ```console\n   * Stats {\n   *   dev: 2114,\n   *   ino: 48064969,\n   *   mode: 33188,\n   *   nlink: 1,\n   *   uid: 85,\n   *   gid: 100,\n   *   rdev: 0,\n   *   size: 527,\n   *   blksize: 4096,\n   *   blocks: 8,\n   *   atimeMs: 1318289051000.1,\n   *   mtimeMs: 1318289051000.1,\n   *   ctimeMs: 1318289051000.1,\n   *   birthtimeMs: 1318289051000.1,\n   *   atime: Mon, 10 Oct 2011 23:24:11 GMT,\n   *   mtime: Mon, 10 Oct 2011 23:24:11 GMT,\n   *   ctime: Mon, 10 Oct 2011 23:24:11 GMT,\n   *   birthtime: Mon, 10 Oct 2011 23:24:11 GMT }\n   * ```\n   */\n  export class Stats {}\n\n  /**\n   * A representation of a directory entry, which can be a file or a subdirectory\n   * within the directory. A directory entry is a combination of the file name and file type pairs.\n   *\n   * Additionally, when {@link promises.readdir} or {@link readdirSync} is called with\n   * the `withFileTypes` option set to `true`, the resulting array is filled with `fs.Dirent` objects, rather than strings.\n   */\n  export class Dirent {\n    /**\n     * Returns `true` if the `fs.Dirent` object describes a regular file.\n     */\n    isFile(): boolean;\n    /**\n     * Returns `true` if the `fs.Dirent` object describes a file system\n     * directory.\n     */\n    isDirectory(): boolean;\n    /**\n     * Returns `true` if the `fs.Dirent` object describes a block device.\n     */\n    isBlockDevice(): boolean;\n    /**\n     * Returns `true` if the `fs.Dirent` object describes a character device.\n     */\n    isCharacterDevice(): boolean;\n    /**\n     * Returns `true` if the `fs.Dirent` object describes a symbolic link.\n     */\n    isSymbolicLink(): boolean;\n    /**\n     * Returns `true` if the `fs.Dirent` object describes a first-in-first-out\n     * (FIFO) pipe.\n     */\n    isFIFO(): boolean;\n    /**\n     * Returns `true` if the `fs.Dirent` object describes a socket.\n     */\n    isSocket(): boolean;\n    /**\n     * The file name that this `fs.Dirent` object refers to.\n     */\n    name: string;\n    /**\n     * The base path that this `fs.Dirent` object refers to.\n     */\n    parentPath: string;\n  }\n\n  export interface StatSyncFn extends Function {\n    (path: PathLike): Stats;\n  }\n  /**\n   * Synchronous stat - Get file status.\n   * @param path A path to a file.\n   */\n  export const statSync: StatSyncFn;\n\n  export interface RmDirOptions {\n    /**\n     * @deprecated Use `fs.rm(path, { recursive: true, force: true })` instead.\n     *\n     * If `true`, perform a recursive directory removal. In\n     * recursive mode, operations are retried on failure.\n     * @default false\n     */\n    recursive?: boolean | undefined;\n  }\n  /**\n   * Synchronous symlink(2) - Create a new symbolic link to an existing file.\n   * @param target A path to an existing file. If a URL is provided, it must use the `file:` protocol.\n   * @param path A path to the new symlink. If a URL is provided, it must use the `file:` protocol.\n   * @param [type='null']\n   */\n  export function symlinkSync(\n    target: PathLike,\n    path: PathLike,\n    type?: \"dir\" | \"file\" | \"junction\" | null\n  ): void;\n\n  /**\n   * Synchronous [`rmdir(2)`](http://man7.org/linux/man-pages/man2/rmdir.2.html). Returns `undefined`.\n   *\n   * Using `fs.rmdirSync()` on a file (not a directory) results in an `ENOENT` error\n   * on Windows and an `ENOTDIR` error on POSIX.\n   *\n   * To get a behavior similar to the `rm -rf` Unix command, use {@link rmSync} with options `{ recursive: true, force: true }`.\n   */\n  export function rmdirSync(path: PathLike, options?: RmDirOptions): void;\n\n  export interface RmOptions {\n    /**\n     * When `true`, exceptions will be ignored if `path` does not exist.\n     * @default false\n     */\n    force?: boolean | undefined;\n    /**\n     * If `true`, perform a recursive directory removal. In\n     * recursive mode, operations are retried on failure.\n     * @default false\n     */\n    recursive?: boolean | undefined;\n  }\n\n  /**\n   * Synchronously removes files and directories (modeled on the standard POSIX `rm` utility). Returns `undefined`.\n   */\n  export function rmSync(path: PathLike, options?: RmOptions): void;\n\n  export interface MakeDirectoryOptions {\n    /**\n     * Indicates whether parent folders should be created.\n     * If a folder was created, the path to the first created folder will be returned.\n     * @default false\n     */\n    recursive?: boolean | undefined;\n    /**\n     * A file mode. If not specified\n     * @default 0o777\n     */\n    mode?: Mode | undefined;\n  }\n\n  /**\n   * Synchronously creates a directory. Returns the `path`.\n   *\n   * See the POSIX [`mkdir(2)`](http://man7.org/linux/man-pages/man2/mkdir.2.html) documentation for more details.\n   */\n  export function mkdirSync(\n    path: PathLike,\n    options?: MakeDirectoryOptions\n  ): string;\n\n  /**\n   * Returns the created directory path.\n   *\n   * For detailed information, see the documentation of the asynchronous version of\n   * this API: {@link promises.mkdtemp}.\n   */\n  export function mkdtempSync(prefix: string): string;\n\n  /**\n   * Reads the contents of the directory.\n   *\n   * See the POSIX [`readdir(3)`](http://man7.org/linux/man-pages/man3/readdir.3.html) documentation for more details.\n   *\n   * If `options.withFileTypes` is set to `true`, the result will contain `fs.Dirent` objects.\n   */\n  export function readdirSync(\n    path: PathLike,\n    options?: {\n      withFileTypes?: false | undefined;\n      recursive?: boolean | undefined;\n    }\n  ): string[];\n\n  /**\n   * Synchronous readdir (2) - read a directory.\n   * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.\n   * @param options If called with `withFileTypes: true` the result data will be an array of Dirent.\n   */\n  export function readdirSync(\n    path: PathLike,\n    options: {\n      withFileTypes: true;\n      recursive?: boolean | undefined;\n    }\n  ): Dirent[];\n\n  /**\n   * Returns the contents of the `path`.\n   *\n   * For detailed information, see the documentation of the asynchronous version of\n   * this API: {@link promises.readFile}.\n   *\n   * If the `encoding` option is specified then this function returns a\n   * string. Otherwise it returns a buffer.\n   *\n   * @param path A path to a file.\n   */\n  export function readFileSync(\n    path: PathLike,\n    options?: {\n      encoding?: null | undefined;\n    } | null\n  ): Buffer;\n\n  /**\n   * Synchronously reads the entire contents of a file.\n   * @param path A path to a file.\n   * @param options Either the encoding for the result, or an object that contains the encoding.\n   */\n  export function readFileSync(\n    path: PathLike,\n    options:\n      | {\n          encoding: BufferEncoding;\n        }\n      | BufferEncoding\n  ): string;\n\n  /**\n   * Returns `undefined`.\n   *\n   * For detailed information, see the documentation of the asynchronous version of\n   * this API: {@link promises.writeFile}.\n   * @param file A path to a file.\n   */\n  export function writeFileSync(\n    file: PathLike,\n    data:\n      | string\n      | Buffer\n      | QuickJS.ArrayBufferView\n      | ArrayBuffer\n      | SharedArrayBuffer,\n    options?:\n      | {\n          mode?: Mode | undefined;\n        }\n      | undefined\n  ): void;\n\n  export namespace constants {\n    // File Access Constants\n    /** Constant for fs.access(). File is visible to the calling process. */\n    const F_OK: number;\n    /** Constant for fs.access(). File can be read by the calling process. */\n    const R_OK: number;\n    /** Constant for fs.access(). File can be written by the calling process. */\n    const W_OK: number;\n    /** Constant for fs.access(). File can be executed by the calling process. */\n    const X_OK: number;\n  }\n\n  /**\n   * Synchronously tests a user's permissions for the file or directory specified\n   * by `path`. The `mode` argument is an optional integer that specifies the\n   * accessibility checks to be performed. `mode` should be either the value `fs.constants.F_OK` or a mask consisting of the bitwise OR of any of `fs.constants.R_OK`, `fs.constants.W_OK`, and\n   * `fs.constants.X_OK` (e.g.`fs.constants.W_OK | fs.constants.R_OK`). Check `File access constants` for\n   * possible values of `mode`.\n   *\n   * If any of the accessibility checks fail, an `Error` will be thrown. Otherwise,\n   * the method will return `undefined`.\n   *\n   * ```js\n   * import { accessSync, constants } from 'fs';\n   *\n   * try {\n   *   accessSync('etc/passwd', constants.R_OK | constants.W_OK);\n   *   console.log('can read/write');\n   * } catch (err) {\n   *   console.error('no access!');\n   * }\n   * ```\n   * @param [mode=fs.constants.F_OK]\n   */\n  export function accessSync(path: PathLike, mode?: Mode): void;\n\n  /**\n   * For detailed information, see the documentation of the asynchronous version of\n   * this API: {@link chmod}.\n   *\n   * See the POSIX [`chmod(2)`](http://man7.org/linux/man-pages/man2/chmod.2.html) documentation for more detail.\n   */\n  export function chmodSync(path: PathLike, mode: Mode): void;\n\n  /**\n   * Synchronously renames a file or directory from `oldPath` to `newPath`.\n   *\n   * For detailed information, see the documentation of the asynchronous version of\n   * this API: {@link promises.rename}.\n   */\n  export function renameSync(oldPath: PathLike, newPath: PathLike): void;\n}\n"
  },
  {
    "path": "types/globals.d.ts",
    "content": "import { Performance } from \"perf_hooks\";\n\nexport {};\n\ndeclare global {\n  namespace QuickJS {\n    type TypedArray =\n      | Uint8Array\n      | Uint8ClampedArray\n      | Uint16Array\n      | Uint32Array\n      | Int8Array\n      | Int16Array\n      | Int32Array\n      | BigUint64Array\n      | BigInt64Array\n      | Float32Array\n      | Float64Array;\n    type ArrayBufferView = TypedArray | DataView;\n  }\n\n  var performance: Performance;\n}\n"
  },
  {
    "path": "types/https.d.ts",
    "content": "/**\n * HTTPS is the HTTP protocol over TLS/SSL.\n */\ndeclare module \"https\" {\n  import { Buffer } from \"buffer\";\n\n  interface AgentOptions {\n    /**\n     * Optionally override the trusted CA certificates. Default is to trust\n     * the well-known CAs curated by Mozilla. Mozilla's CAs are completely\n     * replaced when CAs are explicitly specified using this option.\n     */\n    ca?: string | Buffer | Array<string | Buffer> | undefined;\n    /**\n     * Whether to reject unauthorized certificates. Default is `true`.\n     */\n    rejectUnauthorized?: boolean | undefined;\n  }\n  /**\n   * An `Agent` is responsible for managing connection persistence\n   * and reuse for HTTP clients. Currently only a small subset of the options\n   * are supported.\n   */\n  class Agent {\n    constructor(opts?: AgentOptions);\n  }\n}\n"
  },
  {
    "path": "types/index.d.ts",
    "content": "/// <reference types=\"./abort.d.ts\" />\n/// <reference types=\"./assert.d.ts\" />\n/// <reference types=\"./async_hooks.d.ts\" />\n/// <reference types=\"./buffer.d.ts\" />\n/// <reference types=\"./child_process.d.ts\" />\n/// <reference types=\"./console.d.ts\" />\n/// <reference types=\"./crypto.d.ts\" />\n/// <reference types=\"./dgram.d.ts\" />\n/// <reference types=\"./dns.d.ts\" />\n/// <reference types=\"./dom-events.d.ts\" />\n/// <reference types=\"./events.d.ts\" />\n/// <reference types=\"./exceptions.d.ts\" />\n/// <reference types=\"./fetch.d.ts\" />\n/// <reference types=\"./fs.d.ts\" />\n/// <reference types=\"./fs/promises.d.ts\" />\n/// <reference types=\"./globals.d.ts\" />\n/// <reference types=\"./https.d.ts\" />\n/// <reference types=\"./module.d.ts\" />\n/// <reference types=\"./navigator.d.ts\" />\n/// <reference types=\"./net.d.ts\" />\n/// <reference types=\"./os.d.ts\" />\n/// <reference types=\"./path.d.ts\" />\n/// <reference types=\"./perf_hooks.d.ts\" />\n/// <reference types=\"./process.d.ts\" />\n/// <reference types=\"./stream.d.ts\" />\n/// <reference types=\"./stream/web.d.ts\" />\n/// <reference types=\"./timers.d.ts\" />\n/// <reference types=\"./timezone.d.ts\" />\n/// <reference types=\"./tty.d.ts\" />\n/// <reference types=\"./url.d.ts\" />\n/// <reference types=\"./util.d.ts\" />\n/// <reference types=\"./zlib.d.ts\" />\n"
  },
  {
    "path": "types/module.d.ts",
    "content": "/**\n * @since v0.3.7\n */\ndeclare module \"module\" {\n  import { URL } from \"node:url\";\n  class Module {\n    constructor(id: string, parent?: Module);\n  }\n  interface Module extends NodeJS.Module {}\n  namespace Module {\n    export { Module };\n  }\n  namespace Module {\n    /**\n     * A list of the names of all modules provided by Node.js. Can be used to verify\n     * if a module is maintained by a third party or not.\n     *\n     * Note: the list doesn't contain prefix-only modules like `node:test`.\n     */\n    const builtinModules: readonly string[];\n    /**\n     * @param path Filename to be used to construct the require\n     * function. Must be a file URL object, file URL string, or absolute path\n     * string.\n     */\n    function createRequire(path: string | URL): NodeJS.Require;\n    /**\n     */\n    function isBuiltin(moduleName: string): boolean;\n    interface RegisterOptions<Data> {\n      /**\n       * If you want to resolve `specifier` relative to a\n       * base URL, such as `import.meta.url`, you can pass that URL here. This\n       * property is ignored if the `parentURL` is supplied as the second argument.\n       * @default 'data:'\n       */\n      parentURL?: string | URL | undefined;\n      /**\n       * Any arbitrary, cloneable JavaScript value to pass into the\n       * {@link initialize} hook.\n       */\n      data?: Data | undefined;\n      /**\n       * [Transferable objects](https://nodejs.org/docs/latest-v24.x/api/worker_threads.html#portpostmessagevalue-transferlist)\n       * to be passed into the `initialize` hook.\n       */\n      transferList?: any[] | undefined;\n    }\n    interface RegisterHooksOptions {\n      /**\n       * See [load hook](https://nodejs.org/docs/latest-v24.x/api/module.html#loadurl-context-nextload).\n       * @default undefined\n       */\n      load?: LoadHookSync | undefined;\n      /**\n       * See [resolve hook](https://nodejs.org/docs/latest-v24.x/api/module.html#resolvespecifier-context-nextresolve).\n       * @default undefined\n       */\n      resolve?: ResolveHookSync | undefined;\n    }\n    interface ModuleHooks {\n      /**\n       * Deregister the hook instance.\n       */\n      deregister(): void;\n    }\n    /**\n     * Register [hooks](https://nodejs.org/docs/latest-v24.x/api/module.html#customization-hooks)\n     * that customize Node.js module resolution and loading behavior.\n     * @experimental\n     */\n    function registerHooks(options: RegisterHooksOptions): ModuleHooks;\n    interface ImportAttributes extends NodeJS.Dict<string> {\n      type?: string | undefined;\n    }\n    type ImportPhase = \"source\" | \"evaluation\";\n    type ModuleFormat =\n      | \"addon\"\n      | \"builtin\"\n      | \"commonjs\"\n      | \"commonjs-typescript\"\n      | \"json\"\n      | \"module\"\n      | \"module-typescript\"\n      | \"wasm\";\n    type ModuleSource = string | ArrayBuffer | NodeJS.TypedArray;\n    interface ResolveHookContext {\n      /**\n       * Export conditions of the relevant `package.json`\n       */\n      conditions: string[];\n      /**\n       *  An object whose key-value pairs represent the assertions for the module to import\n       */\n      importAttributes: ImportAttributes;\n      /**\n       * The module importing this one, or undefined if this is the Node.js entry point\n       */\n      parentURL: string | undefined;\n    }\n    interface ResolveFnOutput {\n      /**\n       * A hint to the load hook (it might be ignored); can be an intermediary value.\n       */\n      format?: string | null | undefined;\n      /**\n       * The import attributes to use when caching the module (optional; if excluded the input will be used)\n       */\n      importAttributes?: ImportAttributes | undefined;\n      /**\n       * A signal that this hook intends to terminate the chain of `resolve` hooks.\n       * @default false\n       */\n      shortCircuit?: boolean | undefined;\n      /**\n       * The absolute URL to which this input resolves\n       */\n      url: string;\n    }\n    /**\n     * The `resolve` hook chain is responsible for telling Node.js where to find and\n     * how to cache a given `import` statement or expression, or `require` call. It can\n     * optionally return a format (such as `'module'`) as a hint to the `load` hook. If\n     * a format is specified, the `load` hook is ultimately responsible for providing\n     * the final `format` value (and it is free to ignore the hint provided by\n     * `resolve`); if `resolve` provides a `format`, a custom `load` hook is required\n     * even if only to pass the value to the Node.js default `load` hook.\n     */\n    type ResolveHook = (\n      specifier: string,\n      context: ResolveHookContext,\n      nextResolve: (\n        specifier: string,\n        context?: Partial<ResolveHookContext>\n      ) => ResolveFnOutput | Promise<ResolveFnOutput>\n    ) => ResolveFnOutput | Promise<ResolveFnOutput>;\n    type ResolveHookSync = (\n      specifier: string,\n      context: ResolveHookContext,\n      nextResolve: (\n        specifier: string,\n        context?: Partial<ResolveHookContext>\n      ) => ResolveFnOutput\n    ) => ResolveFnOutput;\n    interface LoadHookContext {\n      /**\n       * Export conditions of the relevant `package.json`\n       */\n      conditions: string[];\n      /**\n       * The format optionally supplied by the `resolve` hook chain (can be an intermediary value).\n       */\n      format: string | null | undefined;\n      /**\n       *  An object whose key-value pairs represent the assertions for the module to import\n       */\n      importAttributes: ImportAttributes;\n    }\n    interface LoadFnOutput {\n      format: string | null | undefined;\n      /**\n       * A signal that this hook intends to terminate the chain of `resolve` hooks.\n       * @default false\n       */\n      shortCircuit?: boolean | undefined;\n      /**\n       * The source for Node.js to evaluate\n       */\n      source?: ModuleSource | undefined;\n    }\n    /**\n     * The `load` hook provides a way to define a custom method of determining how a\n     * URL should be interpreted, retrieved, and parsed. It is also in charge of\n     * validating the import attributes.\n     */\n    type LoadHook = (\n      url: string,\n      context: LoadHookContext,\n      nextLoad: (\n        url: string,\n        context?: Partial<LoadHookContext>\n      ) => LoadFnOutput | Promise<LoadFnOutput>\n    ) => LoadFnOutput | Promise<LoadFnOutput>;\n    type LoadHookSync = (\n      url: string,\n      context: LoadHookContext,\n      nextLoad: (\n        url: string,\n        context?: Partial<LoadHookContext>\n      ) => LoadFnOutput\n    ) => LoadFnOutput;\n  }\n  global {\n    interface ImportMeta {\n      /**\n       * The absolute `file:` URL of the module.\n       *\n       * This is defined exactly the same as it is in browsers providing the URL of the\n       * current module file.\n       *\n       * This enables useful patterns such as relative file loading:\n       *\n       * ```js\n       * import { readFileSync } from 'node:fs';\n       * const buffer = readFileSync(new URL('./data.proto', import.meta.url));\n       * ```\n       */\n      url: string;\n    }\n    namespace NodeJS {\n      interface Module {\n        /**\n         * The `module.exports` object is created by the `Module` system. Sometimes this is\n         * not acceptable; many want their module to be an instance of some class. To do\n         * this, assign the desired export object to `module.exports`.\n         */\n        exports: any;\n        /**\n         * The directory name of the module. This is usually the same as the\n         * `path.dirname()` of the `module.id`.\n         */\n        path: string;\n        /**\n         * The `module.require()` method provides a way to load a module as if\n         * `require()` was called from the original module.\n         */\n        require(id: string): any;\n      }\n      interface Require {\n        /**\n         */\n        resolve: RequireResolve;\n      }\n      interface RequireResolveOptions {\n        /**\n         * Paths to resolve module location from. If present, these\n         * paths are used instead of the default resolution paths, with the exception\n         * of\n         * [GLOBAL\\_FOLDERS](https://nodejs.org/docs/latest-v24.x/api/modules.html#loading-from-the-global-folders)\n         * like `$HOME/.node_modules`, which are\n         * always included. Each of these paths is used as a starting point for\n         * the module resolution algorithm, meaning that the `node_modules` hierarchy\n         * is checked from this location.\n         */\n        paths?: string[] | undefined;\n      }\n      interface RequireResolve {\n        /**\n         * Use the internal `require()` machinery to look up the location of a module,\n         * but rather than loading the module, just return the resolved filename.\n         *\n         * If the module can not be found, a `MODULE_NOT_FOUND` error is thrown.\n         * @param request The module path to resolve.\n         */\n        (request: string, options?: RequireResolveOptions): string;\n        /**\n         * Returns an array containing the paths searched during resolution of `request` or\n         * `null` if the `request` string references a core module, for example `http` or\n         * `fs`.\n         * @param request The module path whose lookup paths are being retrieved.\n         */\n        paths(request: string): string[] | null;\n      }\n    }\n    /**\n     * The `exports` variable is available within a module's file-level scope, and is\n     * assigned the value of `module.exports` before the module is evaluated.\n     */\n    var exports: NodeJS.Module[\"exports\"];\n    /**\n     * A reference to the current module.\n     * @since v0.1.16\n     */\n    var module: NodeJS.Module;\n    /**\n     * @since v0.1.13\n     */\n    var require: NodeJS.Require;\n  }\n  export = Module;\n}\ndeclare module \"node:module\" {\n  import module = require(\"module\");\n  export = module;\n}\n"
  },
  {
    "path": "types/navigator.d.ts",
    "content": "export {};\n\ndeclare global {\n  interface Navigator {\n    readonly userAgent: string;\n  }\n\n  var navigator: Navigator;\n}\n"
  },
  {
    "path": "types/net.d.ts",
    "content": "/**\n * The `net` module provides an asynchronous network API for creating stream-based\n * TCP or `IPC` servers ({@link createServer}) and clients ({@link createConnection}).\n *\n * It can be accessed using:\n *\n * ```js\n * import * as net from 'net';\n * ```\n */\ndeclare module \"net\" {\n  import { Buffer } from \"buffer\";\n  import { EventEmitter } from \"events\";\n  import { DefaultDuplexStream as Duplex } from \"stream\";\n\n  interface AddressInfo {\n    address: string;\n    family: string;\n    port: number;\n  }\n\n  interface SocketConstructorOpts {\n    allowHalfOpen?: boolean | undefined;\n  }\n  interface TcpSocketConnectOpts {\n    port: number;\n    host?: string | undefined;\n  }\n  interface IpcSocketConnectOpts {\n    path: string;\n  }\n  type SocketConnectOpts = TcpSocketConnectOpts | IpcSocketConnectOpts;\n  type SocketReadyState =\n    | \"opening\"\n    | \"open\"\n    | \"readOnly\"\n    | \"writeOnly\"\n    | \"closed\";\n\n  /**\n   * This class is an abstraction of a TCP socket or a streaming `IPC` endpoint (only available on Unix with domain sockets).\n   * It is also an `EventEmitter`.\n   *\n   * A `net.Socket` can be created by the user and used directly to interact with a server. For example, it is returned by {@link createConnection},\n   * so the user can use it to talk to the server.\n   *\n   * It can also be created by LLRT and passed to the user when a connection is received.\n   * For example, it is passed to the listeners of a `'connection'` event emitted on a {@link Server}, so the user can use it to interact with the client.\n   */\n  class Socket extends Duplex {\n    constructor(options?: SocketConstructorOpts);\n\n    /**\n     * Initiate a connection on a given socket.\n     *\n     * Possible signatures:\n     *\n     * * `socket.connect(options[, connectListener])`\n     * * `socket.connect(path[, connectListener])` for `IPC` connections.\n     * * `socket.connect(port[, host][, connectListener])` for TCP connections.\n     * * Returns: `net.Socket` The socket itself.\n     *\n     * This function is asynchronous. When the connection is established, the `'connect'` event will be emitted. If there is a problem connecting,\n     * instead of a `'connect'` event, an `'error'` event will be emitted with\n     * the error passed to the `'error'` listener.\n     * The last parameter `connectListener`, if supplied, will be added as a listener\n     * for the `'connect'` event **once**.\n     *\n     * This function should only be used for reconnecting a socket after`'close'` has been emitted or otherwise it may lead to undefined\n     * behavior.\n     */\n    connect(options: SocketConnectOpts, connectionListener?: () => void): this;\n    connect(port: number, host: string, connectionListener?: () => void): this;\n    connect(port: number, connectionListener?: () => void): this;\n    connect(path: string, connectionListener?: () => void): this;\n\n    /**\n     * Returns the bound `address`, the address `family` name and `port` of the\n     * socket as reported by the operating system:`{ port: 12346, family: 'IPv4', address: '127.0.0.1' }`\n     * @since v0.1.90\n     */\n    address(): AddressInfo | {};\n\n    /**\n     * If `true`, `socket.connect(options[, connectListener])` was\n     * called and has not yet finished. It will stay `true` until the socket becomes\n     * connected, then it is set to `false` and the `'connect'` event is emitted. Note\n     * that the `socket.connect(options[, connectListener])` callback is a listener for the `'connect'` event.\n     */\n    readonly connecting: boolean;\n\n    /**\n     * This is `true` if the socket is not connected yet, either because `.connect()`has not yet been called or because it is still in the process of connecting\n     * (see `socket.connecting`).\n     */\n    readonly pending: boolean;\n\n    /**\n     * The string representation of the local IP address the remote client is\n     * connecting on. For example, in a server listening on `'0.0.0.0'`, if a client\n     * connects on `'192.168.1.1'`, the value of `socket.localAddress` would be`'192.168.1.1'`.\n     */\n    readonly localAddress?: string;\n\n    /**\n     * The numeric representation of the local port. For example, `80` or `21`.\n     */\n    readonly localPort?: number;\n\n    /**\n     * The string representation of the local IP family. `'IPv4'` or `'IPv6'`.\n     */\n    readonly localFamily?: string;\n\n    /**\n     * This property represents the state of the connection as a string.\n     *\n     * * If the stream is connecting `socket.readyState` is `opening`.\n     * * If the stream is readable and writable, it is `open`.\n     * * If the stream is readable and not writable, it is `readOnly`.\n     * * If the stream is not readable and writable, it is `writeOnly`.\n     */\n    readonly readyState: SocketReadyState;\n\n    /**\n     * The string representation of the remote IP address. For example,`'74.125.127.100'` or `'2001:4860:a005::68'`. Value may be `undefined` if\n     * the socket is destroyed (for example, if the client disconnected).\n     */\n    readonly remoteAddress?: string;\n\n    /**\n     * The string representation of the remote IP family. `'IPv4'` or `'IPv6'`. Value may be `undefined` if\n     * the socket is destroyed (for example, if the client disconnected).\n     */\n    readonly remoteFamily?: string;\n\n    /**\n     * The numeric representation of the remote port. For example, `80` or `21`. Value may be `undefined` if\n     * the socket is destroyed (for example, if the client disconnected).\n     */\n    readonly remotePort?: number | undefined;\n\n    /**\n     * Half-closes the socket. i.e., it sends a FIN packet. It is possible the server will still send some data.\n     *\n     * @param callback Optional callback for when the socket is finished.\n     * @return The socket itself.\n     */\n    end(callback?: () => void): this;\n\n    /**\n     * events.EventEmitter\n     *   1. close\n     *   2. connect\n     *   3. data\n     *   4. end\n     *   5. error\n     */\n    addListener(event: string, listener: (...args: any[]) => void): this;\n    addListener(event: \"close\", listener: (hadError: boolean) => void): this;\n    addListener(event: \"connect\", listener: () => void): this;\n    addListener(event: \"data\", listener: (data: Buffer) => void): this;\n    addListener(event: \"drain\", listener: () => void): this;\n    addListener(event: \"end\", listener: () => void): this;\n    addListener(event: \"error\", listener: (err: Error) => void): this;\n    emit(event: string | symbol, ...args: any[]): boolean;\n    emit(event: \"close\", hadError: boolean): boolean;\n    emit(event: \"connect\"): boolean;\n    emit(event: \"data\", data: Buffer): boolean;\n    emit(event: \"end\"): boolean;\n    emit(event: \"error\", err: Error): boolean;\n    on(event: string, listener: (...args: any[]) => void): this;\n    on(event: \"close\", listener: (hadError: boolean) => void): this;\n    on(event: \"connect\", listener: () => void): this;\n    on(event: \"data\", listener: (data: Buffer) => void): this;\n    on(event: \"end\", listener: () => void): this;\n    on(event: \"error\", listener: (err: Error) => void): this;\n    once(event: string, listener: (...args: any[]) => void): this;\n    once(event: \"close\", listener: (hadError: boolean) => void): this;\n    once(event: \"connect\", listener: () => void): this;\n    once(event: \"data\", listener: (data: Buffer) => void): this;\n    once(event: \"end\", listener: () => void): this;\n    once(event: \"error\", listener: (err: Error) => void): this;\n    prependListener(event: string, listener: (...args: any[]) => void): this;\n    prependListener(\n      event: \"close\",\n      listener: (hadError: boolean) => void\n    ): this;\n    prependListener(event: \"connect\", listener: () => void): this;\n    prependListener(event: \"data\", listener: (data: Buffer) => void): this;\n    prependListener(event: \"end\", listener: () => void): this;\n    prependListener(event: \"error\", listener: (err: Error) => void): this;\n    prependOnceListener(\n      event: string,\n      listener: (...args: any[]) => void\n    ): this;\n    prependOnceListener(\n      event: \"close\",\n      listener: (hadError: boolean) => void\n    ): this;\n    prependOnceListener(event: \"connect\", listener: () => void): this;\n    prependOnceListener(event: \"data\", listener: (data: Buffer) => void): this;\n    prependOnceListener(event: \"end\", listener: () => void): this;\n    prependOnceListener(event: \"error\", listener: (err: Error) => void): this;\n  }\n\n  interface ListenOptions {\n    port?: number | undefined;\n    host?: string | undefined;\n    backlog?: number | undefined;\n    path?: string | undefined;\n  }\n\n  interface ServerOpts {\n    /**\n     * Indicates whether half-opened TCP connections are allowed.\n     * @default false\n     */\n    allowHalfOpen?: boolean | undefined;\n  }\n\n  /**\n   * This class is used to create a TCP or `IPC` server.\n   */\n  class Server extends EventEmitter {\n    constructor(connectionListener?: (socket: Socket) => void);\n    constructor(\n      options?: ServerOpts,\n      connectionListener?: (socket: Socket) => void\n    );\n\n    /**\n     * Start a server listening for connections. A `net.Server` can be a TCP or\n     * an `IPC` server depending on what it listens to.\n     *\n     * Possible signatures:\n     *\n     * * `server.listen(options[, callback])`\n     * * `server.listen(path[, backlog][, callback])` for `IPC` servers\n     * * `server.listen([port[, host[, backlog]]][, callback])` for TCP servers\n     *\n     * This function is asynchronous. When the server starts listening, the `'listening'` event will be emitted. The last parameter `callback`will be added as a listener for the `'listening'`\n     * event.\n     *\n     * All `listen()` methods can take a `backlog` parameter to specify the maximum length of the queue of pending connections.\n     * Currently this parameter is IGNORED, support will be added in the future.\n     *\n     * All {@link Socket} are set to `SO_REUSEADDR` (see [`socket(7)`](https://man7.org/linux/man-pages/man7/socket.7.html) for details).\n     *\n     * The `server.listen()` method can be called again if and only if there was an error during the first `server.listen()`\n     * call or `server.close()` has been called. Otherwise, an error will be thrown.\n     */\n    listen(listeningListener?: () => void): void;\n    listen(\n      port?: number,\n      hostname?: string,\n      backlog?: number,\n      listeningListener?: () => void\n    ): void;\n    listen(\n      port?: number,\n      hostname?: string,\n      listeningListener?: () => void\n    ): void;\n    listen(\n      port?: number,\n      backlog?: number,\n      listeningListener?: () => void\n    ): void;\n    listen(port?: number, listeningListener?: () => void): void;\n    listen(\n      path: string,\n      backlog?: number,\n      listeningListener?: () => void\n    ): void;\n    listen(path: string, listeningListener?: () => void): void;\n    listen(options: ListenOptions, listeningListener?: () => void): void;\n\n    /**\n     * Stops the server from accepting new connections and keeps existing\n     * connections. This function is asynchronous, the server is finally closed\n     * when all connections are ended and the server emits a `'close'` event.\n     * The optional `callback` will be called once the `'close'` event occurs. Unlike\n     * that event, it will be called with an `Error` as its only argument if the server\n     * was not open when it was closed.\n     * @param callback Called when the server is closed.\n     */\n    close(callback?: (err?: Error) => void): this;\n\n    /**\n     * Returns the bound `address`, the address `family` name, and `port` of the server\n     * as reported by the operating system if listening on an IP socket\n     * (useful to find which port was assigned when getting an OS-assigned address):`{ port: 12346, family: 'IPv4', address: '127.0.0.1' }`.\n     *\n     * For a server listening on a pipe or Unix domain socket, the name is returned\n     * as a string.\n     *\n     * ```js\n     * const server = net.createServer((socket) => {\n     *   socket.end('goodbye\\n');\n     * }).on('error', (err) => {\n     *   // Handle errors here.\n     *   throw err;\n     * });\n     *\n     * // Grab an arbitrary unused port.\n     * server.listen(() => {\n     *   console.log('opened server on', server.address());\n     * });\n     * ```\n     *\n     * `server.address()` returns `null` before the `'listening'` event has been\n     * emitted or after calling `server.close()`.\n     */\n    address(): AddressInfo | string | null;\n\n    /**\n     * events.EventEmitter\n     *   1. close\n     *   2. connection\n     *   3. error\n     *   4. listening\n     */\n    addListener(event: string, listener: (...args: any[]) => void): this;\n    addListener(event: \"close\", listener: () => void): this;\n    addListener(event: \"connection\", listener: (socket: Socket) => void): this;\n    addListener(event: \"error\", listener: (err: Error) => void): this;\n    addListener(event: \"listening\", listener: () => void): this;\n    emit(event: string | symbol, ...args: any[]): boolean;\n    emit(event: \"close\"): boolean;\n    emit(event: \"connection\", socket: Socket): boolean;\n    emit(event: \"error\", err: Error): boolean;\n    emit(event: \"listening\"): boolean;\n    on(event: string, listener: (...args: any[]) => void): this;\n    on(event: \"close\", listener: () => void): this;\n    on(event: \"connection\", listener: (socket: Socket) => void): this;\n    on(event: \"error\", listener: (err: Error) => void): this;\n    on(event: \"listening\", listener: () => void): this;\n    once(event: string, listener: (...args: any[]) => void): this;\n    once(event: \"close\", listener: () => void): this;\n    once(event: \"connection\", listener: (socket: Socket) => void): this;\n    once(event: \"error\", listener: (err: Error) => void): this;\n    once(event: \"listening\", listener: () => void): this;\n    prependListener(event: string, listener: (...args: any[]) => void): this;\n    prependListener(event: \"close\", listener: () => void): this;\n    prependListener(\n      event: \"connection\",\n      listener: (socket: Socket) => void\n    ): this;\n    prependListener(event: \"error\", listener: (err: Error) => void): this;\n    prependListener(event: \"listening\", listener: () => void): this;\n    prependOnceListener(\n      event: string,\n      listener: (...args: any[]) => void\n    ): this;\n    prependOnceListener(event: \"close\", listener: () => void): this;\n    prependOnceListener(\n      event: \"connection\",\n      listener: (socket: Socket) => void\n    ): this;\n    prependOnceListener(event: \"error\", listener: (err: Error) => void): this;\n    prependOnceListener(event: \"listening\", listener: () => void): this;\n  }\n\n  type NetConnectOpts = TcpSocketConnectOpts | IpcSocketConnectOpts;\n\n  /**\n   * Creates a new TCP or `IPC` server.\n   *\n   * If `allowHalfOpen` is set to `true`, when the other end of the socket\n   * signals the end of transmission, the server will only send back the end of\n   * transmission when `socket.end()` is explicitly called. For example, in the\n   * context of TCP, when a FIN packed is received, a FIN packed is sent\n   * back only when `socket.end()` is explicitly called. Until then the\n   * connection is half-closed (non-readable but still writable). See `'end'` event and [RFC 1122](https://tools.ietf.org/html/rfc1122) (section 4.2.2.13) for more information.\n   *\n   * If `pauseOnConnect` is set to `true`, then the socket associated with each\n   * incoming connection will be paused, and no data will be read from its handle.\n   * This allows connections to be passed between processes without any data being\n   * read by the original process. To begin reading data from a paused socket, call `socket.resume()`.\n   *\n   * The server can be a TCP server or an `IPC` server, depending on what it `listen()` to.\n   *\n   * Here is an example of a TCP echo server which listens for connections\n   * on port 8124:\n   *\n   * ```js\n   * import * as net from 'net';\n   * const server = net.createServer((c) => {\n   *   // 'connection' listener.\n   *   console.log('client connected');\n   *   c.on('end', () => {\n   *     console.log('client disconnected');\n   *   });\n   *   c.write('hello\\r\\n');\n   *\n   * });\n   * server.on('error', (err) => {\n   *   throw err;\n   * });\n   * server.listen(8124, () => {\n   *   console.log('server bound');\n   * });\n   * ```\n   *\n   * Test this by using `telnet`:\n   *\n   * ```bash\n   * telnet localhost 8124\n   * ```\n   *\n   * To listen on the socket `/tmp/echo.sock`:\n   *\n   * ```js\n   * server.listen('/tmp/echo.sock', () => {\n   *   console.log('server bound');\n   * });\n   * ```\n   *\n   * Use `nc` to connect to a Unix domain socket server:\n   *\n   * ```bash\n   * nc -U /tmp/echo.sock\n   * ```\n   * @param connectionListener Automatically set as a listener for the {@link 'connection'} event.\n   */\n  function createServer(connectionListener?: (socket: Socket) => void): Server;\n  function createServer(\n    options?: ServerOpts,\n    connectionListener?: (socket: Socket) => void\n  ): Server;\n\n  /**\n   * Aliases to {@link createConnection}.\n   *\n   * Possible signatures:\n   *\n   * * {@link connect}\n   * * {@link connect} for `IPC` connections.\n   * * {@link connect} for TCP connections.\n   */\n  function connect(\n    options: NetConnectOpts,\n    connectionListener?: () => void\n  ): Socket;\n  function connect(\n    port: number,\n    host: string,\n    connectionListener?: () => void\n  ): Socket;\n  function connect(port: number, connectionListener?: () => void): Socket;\n  function connect(path: string, connectionListener?: () => void): Socket;\n\n  /**\n   * A factory function, which creates a new {@link Socket},\n   * immediately initiates connection with `socket.connect()`,\n   * then returns the `net.Socket` that starts the connection.\n   *\n   * When the connection is established, a `'connect'` event will be emitted\n   * on the returned socket. The last parameter `connectListener`, if supplied,\n   * will be added as a listener for the `'connect'` event **once**.\n   *\n   * Possible signatures:\n   *\n   * * {@link createConnection}\n   * * {@link createConnection} for `IPC` connections.\n   * * {@link createConnection} for TCP connections.\n   *\n   * The {@link connect} function is an alias to this function.\n   */\n  function createConnection(\n    options: NetConnectOpts,\n    connectionListener?: () => void\n  ): Socket;\n  function createConnection(\n    port: number,\n    host: string,\n    connectionListener?: () => void\n  ): Socket;\n  function createConnection(\n    port: number,\n    connectionListener?: () => void\n  ): Socket;\n  function createConnection(\n    path: string,\n    connectionListener?: () => void\n  ): Socket;\n}\n"
  },
  {
    "path": "types/os.d.ts",
    "content": "declare module \"os\" {\n  interface CpuInfo {\n    model: string;\n    speed: number;\n    /** The number of milliseconds spent by the CPU in each mode cannot be obtained at this time. */\n    times: {\n      /** The number of milliseconds the CPU has spent in user mode. */\n      user: number;\n      /** The number of milliseconds the CPU has spent in nice mode. */\n      nice: number;\n      /** The number of milliseconds the CPU has spent in sys mode. */\n      sys: number;\n      /** The number of milliseconds the CPU has spent in idle mode. */\n      idle: number;\n      /** The number of milliseconds the CPU has spent in irq mode. */\n      irq: number;\n    };\n  }\n  interface NetworkInterfaceBase {\n    address: string;\n    netmask: string;\n    mac: string;\n    internal: boolean;\n    cidr: string | null;\n  }\n  interface NetworkInterfaceInfoIPv4 extends NetworkInterfaceBase {\n    family: \"IPv4\";\n    scopeid?: undefined;\n  }\n  interface NetworkInterfaceInfoIPv6 extends NetworkInterfaceBase {\n    family: \"IPv6\";\n    scopeid: number;\n  }\n  interface UserInfo<T> {\n    username: T;\n    uid: number;\n    gid: number;\n    shell: T | null;\n    homedir: T;\n  }\n  type NetworkInterfaceInfo =\n    | NetworkInterfaceInfoIPv4\n    | NetworkInterfaceInfoIPv6;\n  /**\n   * Returns an estimate of the default amount of parallelism a program should use.\n   * Always returns a value greater than zero.\n   */\n  function availableParallelism(): number;\n  /**\n   * Returns the operating system CPU architecture for which the LLRT binary was compiled.\n   * Possible values are 'arm64', 'x64'. The return value is equivalent to `process.arch`.\n   */\n  function arch(): string;\n  /**\n   * Returns an array of objects containing information about each logical CPU core.\n   * The array will be empty if no CPU information is available, such as if the `/proc` file system is unavailable.\n   *\n   * The properties included on each object include:\n   *\n   * ```js\n   * [\n   *   {\n   *     model: 'Intel(R) Core(TM) i7 CPU         860  @ 2.80GHz',\n   *     speed: 2926,\n   *     times: {\n   *       user: 252020,\n   *       nice: 0,\n   *       sys: 30340,\n   *       idle: 1070356870,\n   *       irq: 0,\n   *     },\n   *   },\n   *   {\n   *     model: 'Intel(R) Core(TM) i7 CPU         860  @ 2.80GHz',\n   *     speed: 2926,\n   *     times: {\n   *       user: 306960,\n   *       nice: 0,\n   *       sys: 26980,\n   *       idle: 1071569080,\n   *       irq: 0,\n   *     },\n   *   },\n   *   {\n   *     model: 'Intel(R) Core(TM) i7 CPU         860  @ 2.80GHz',\n   *     speed: 2926,\n   *     times: {\n   *       user: 248450,\n   *       nice: 0,\n   *       sys: 21750,\n   *       idle: 1070919370,\n   *       irq: 0,\n   *     },\n   *   },\n   *   {\n   *     model: 'Intel(R) Core(TM) i7 CPU         860  @ 2.80GHz',\n   *     speed: 2926,\n   *     times: {\n   *       user: 256880,\n   *       nice: 0,\n   *       sys: 19430,\n   *       idle: 1070905480,\n   *       irq: 20,\n   *     },\n   *   },\n   * ]\n   * ```\n   *\n   * `nice` values are POSIX-only. On Windows, the `nice` values of all processors\n   * are always 0.\n   *\n   * `os.cpus().length` should not be used to calculate the amount of parallelism\n   * available to an application. Use {@link availableParallelism} for this purpose.\n   */\n  function cpus(): CpuInfo[];\n  const devNull: string;\n  /**\n   * Returns a string identifying the endianness of the CPU for which the Node.js\n   * binary was compiled.\n   *\n   * Possible values are `'BE'` for big endian and `'LE'` for little endian.\n   */\n  function endianness(): \"BE\" | \"LE\";\n  /**\n   * The operating system-specific end-of-line marker.\n   * * `\\n` on POSIX\n   * * `\\r\\n` on Windows\n   */\n  const EOL: string;\n  /**\n   * Returns the amount of free system memory in bytes as an integer.\n   */\n  function freemem(): number;\n  /**\n   * Returns the scheduling priority for the process specified by `pid`. If `pid` is\n   * not provided or is `0`, the priority of the current process is returned.\n   * @param [pid=0] The process ID to retrieve scheduling priority for.\n   */\n  function getPriority(pid?: number): number;\n  /**\n   * Returns the string path of the current user's home directory.\n   *\n   * On POSIX, it uses the `$HOME` environment variable if defined. Otherwise it\n   * uses the [effective UID](https://en.wikipedia.org/wiki/User_identifier#Effective_user_ID) to look up the user's home directory.\n   *\n   * On Windows, it uses the `USERPROFILE` environment variable if defined.\n   * Otherwise it uses the path to the profile directory of the current user.\n   */\n  function homedir(): string;\n  /**\n   * Returns the host name of the operating system as a string.\n   */\n  function hostname(): string;\n  /**\n   * Returns an array containing the 1, 5, and 15 minute load averages.\n   *\n   * The load average is a measure of system activity calculated by the operating\n   * system and expressed as a fractional number.\n   *\n   * The load average is a Unix-specific concept. On Windows, the return value is\n   * always `[0, 0, 0]`.\n   */\n  function loadavg(): number[];\n  /**\n   * Returns the machine type as a string, such as `arm64`, `aarch64`, `x86_64`.\n   *\n   * On POSIX systems, the machine type is determined by calling [`uname(3)`](https://linux.die.net/man/3/uname). On Windows, `RtlGetVersion()` is used, and if it is not\n   * available, `GetVersionExW()` will be used. See [https://en.wikipedia.org/wiki/Uname#Examples](https://en.wikipedia.org/wiki/Uname#Examples) for more information.\n   */\n  function machine(): string;\n  /**\n   * Returns an object containing network interfaces that have been assigned a\n   * network address.\n   *\n   * Each key on the returned object identifies a network interface. The associated\n   * value is an array of objects that each describe an assigned network address.\n   *\n   * The properties available on the assigned network address object include:\n   *\n   * ```js\n   * {\n   *   lo: [\n   *     {\n   *       address: '127.0.0.1',\n   *       netmask: '255.0.0.0',\n   *       family: 'IPv4',\n   *       mac: '00:00:00:00:00:00',\n   *       internal: true,\n   *       cidr: '127.0.0.1/8'\n   *     },\n   *     {\n   *       address: '::1',\n   *       netmask: 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',\n   *       family: 'IPv6',\n   *       mac: '00:00:00:00:00:00',\n   *       scopeid: 0,\n   *       internal: true,\n   *       cidr: '::1/128'\n   *     }\n   *   ],\n   *   eth0: [\n   *     {\n   *       address: '192.168.1.108',\n   *       netmask: '255.255.255.0',\n   *       family: 'IPv4',\n   *       mac: '01:02:03:0a:0b:0c',\n   *       internal: false,\n   *       cidr: '192.168.1.108/24'\n   *     },\n   *     {\n   *       address: 'fe80::a00:27ff:fe4e:66a1',\n   *       netmask: 'ffff:ffff:ffff:ffff::',\n   *       family: 'IPv6',\n   *       mac: '01:02:03:0a:0b:0c',\n   *       scopeid: 1,\n   *       internal: false,\n   *       cidr: 'fe80::a00:27ff:fe4e:66a1/64'\n   *     }\n   *   ]\n   * }\n   * ```\n   */\n  function networkInterfaces(): NodeJS.Dict<NetworkInterfaceInfo[]>;\n  /**\n   * Returns a string identifying the operating system platform for which\n   * the Node.js binary was compiled. The value is set at compile time.\n   */\n  function platform(): Platform;\n  function release(): string;\n  /**\n   * Returns the operating system's default directory for temporary files as a\n   * string.\n   */\n  /**\n   * Attempts to set the scheduling priority for the process specified by `pid`. If `pid` is not provided or is `0`, the process ID of the current process is used.\n   *\n   * The `priority` input must be an integer between `-20` (high priority) and `19` (low priority). Due to differences between Unix priority levels and Windows\n   * priority classes, `priority` is mapped to one of six priority constants in `os.constants.priority`. When retrieving a process priority level, this range\n   * mapping may cause the return value to be slightly different on Windows. To avoid\n   * confusion, set `priority` to one of the priority constants.\n   *\n   * On Windows, not currently supported on Windows.\n   *\n   * @param [pid=0] The process ID to set scheduling priority for.\n   * @param priority The scheduling priority to assign to the process.\n   */\n  function setPriority(priority: number): void;\n  function setPriority(pid: number, priority: number): void;\n  /**\n   * Returns the operating system release as a string.\n   *\n   * On POSIX systems, the operating system release is determined by calling [`uname(3)`](https://linux.die.net/man/3/uname). On Windows, `RtlGetVersion()` is used. See\n   * [https://en.wikipedia.org/wiki/Uname#Examples](https://en.wikipedia.org/wiki/Uname#Examples) for more information.\n   */\n  function tmpdir(): string;\n  /**\n   * Returns the total amount of system memory in bytes as an integer.\n   */\n  function totalmem(): number;\n  /**\n   * Returns the operating system name as returned by [`uname(3)`](https://linux.die.net/man/3/uname). For example, it\n   * returns `'Linux'` on Linux, `'Darwin'` on macOS, and `'Windows_NT'` on Windows.\n   *\n   * See [https://en.wikipedia.org/wiki/Uname#Examples](https://en.wikipedia.org/wiki/Uname#Examples) for additional information\n   * about the output of running [`uname(3)`](https://linux.die.net/man/3/uname) on various operating systems.\n   */\n  function type(): string;\n  /**\n   * Returns the system uptime in number of seconds.\n   */\n  function uptime(): number;\n  /**\n   * Returns a string identifying the kernel version.\n   *\n   * On POSIX systems, the operating system release is determined by calling [`uname(3)`](https://linux.die.net/man/3/uname). On Windows, `RtlGetVersion()` is used.\n   * See [https://en.wikipedia.org/wiki/Uname#Examples](https://en.wikipedia.org/wiki/Uname#Examples) for more information.\n   */\n  /**\n   * Returns information about the currently effective user. On POSIX platforms,\n   * this is typically a subset of the password file. The returned object includes\n   * the `username`, `uid`, `gid`, `shell`, and `homedir`. On Windows, the `uid` and `gid` fields are `-1`, and `shell` is `null`.\n   *\n   * The value of `homedir` returned by `os.userInfo()` is provided by the operating\n   * system. This differs from the result of `os.homedir()`, which queries\n   * environment variables for the home directory before falling back to the\n   * operating system response.\n   *\n   * Throws a [`SystemError`](https://nodejs.org/docs/latest-v22.x/api/errors.html#class-systemerror) if a user has no `username` or `homedir`.\n   */\n  //function userInfo(options: { encoding: \"buffer\" }): UserInfo<Buffer>;\n  function userInfo(options?: { encoding: BufferEncoding }): UserInfo<string>;\n  function version(): string;\n}\n"
  },
  {
    "path": "types/package.json",
    "content": "{\n  \"name\": \"llrt-types\",\n  \"license\": \"Apache-2.0\",\n  \"version\": \"0.0.1\",\n  \"main\": \"\",\n  \"types\": \"index.d.ts\",\n  \"description\": \"Type definitions for LLRT, Low Latency Runtime\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/awslabs/llrt\",\n    \"directory\": \"types\"\n  },\n  \"files\": [\n    \"*.d.ts\"\n  ],\n  \"devDependencies\": {\n    \"@definitelytyped/dtslint\": \"^0.2.22\",\n    \"@definitelytyped/eslint-plugin\": \"^0.1.17\",\n    \"typescript\": \"^5.5.3\"\n  },\n  \"scripts\": {\n    \"test\": \"tsc\"\n  },\n  \"keywords\": [\n    \"llrt\",\n    \"types\"\n  ]\n}"
  },
  {
    "path": "types/path.d.ts",
    "content": "/**\n * The `path` module provides utilities for working with file and directory\n * paths. It can be accessed using:\n *\n * ```js\n * import path from 'path';\n * ```\n */\ndeclare module \"path\" {\n  namespace path {\n    /**\n     * A parsed path object generated by path.parse() or consumed by path.format().\n     */\n    interface ParsedPath {\n      /**\n       * The root of the path such as '/' or 'c:\\'\n       */\n      root: string;\n      /**\n       * The full directory path such as '/home/user/dir' or 'c:\\path\\dir'\n       */\n      dir: string;\n      /**\n       * The file name including extension (if any) such as 'index.html'\n       */\n      base: string;\n      /**\n       * The file extension (if any) such as '.html'\n       */\n      ext: string;\n      /**\n       * The file name without extension (if any) such as 'index'\n       */\n      name: string;\n    }\n    interface FormatInputPathObject {\n      /**\n       * The root of the path such as '/' or 'c:\\'\n       */\n      root?: string | undefined;\n      /**\n       * The full directory path such as '/home/user/dir' or 'c:\\path\\dir'\n       */\n      dir?: string | undefined;\n      /**\n       * The file name including extension (if any) such as 'index.html'\n       */\n      base?: string | undefined;\n      /**\n       * The file extension (if any) such as '.html'\n       */\n      ext?: string | undefined;\n      /**\n       * The file name without extension (if any) such as 'index'\n       */\n      name?: string | undefined;\n    }\n    interface PlatformPath {\n      /**\n       * Normalize a string path, reducing '..' and '.' parts.\n       * When multiple slashes are found, they're replaced by a single one; when the path contains a trailing slash, it is preserved. On Windows backslashes are used.\n       *\n       * @param path string path to normalize.\n       * @throws {TypeError} if `path` is not a string.\n       */\n      normalize(path: string): string;\n      /**\n       * Join all arguments together and normalize the resulting path.\n       *\n       * @param paths paths to join.\n       * @throws {TypeError} if any of the path segments is not a string.\n       */\n      join(...paths: string[]): string;\n      /**\n       * The right-most parameter is considered {to}. Other parameters are considered an array of {from}.\n       *\n       * Starting from leftmost {from} parameter, resolves {to} to an absolute path.\n       *\n       * If {to} isn't already absolute, {from} arguments are prepended in right to left order,\n       * until an absolute path is found. If after using all {from} paths still no absolute path is found,\n       * the current working directory is used as well. The resulting path is normalized,\n       * and trailing slashes are removed unless the path gets resolved to the root directory.\n       *\n       * @param paths A sequence of paths or path segments.\n       * @throws {TypeError} if any of the arguments is not a string.\n       */\n      resolve(...paths: string[]): string;\n      /**\n       * Determines whether {path} is an absolute path. An absolute path will always resolve to the same location, regardless of the working directory.\n       *\n       * If the given {path} is a zero-length string, `false` will be returned.\n       *\n       * @param path path to test.\n       */\n      isAbsolute(path: string): boolean;\n      /**\n       * Return the directory name of a path. Similar to the Unix dirname command.\n       *\n       * @param path the path to evaluate.\n       */\n      dirname(path: string): string;\n      /**\n       * Return the last portion of a path. Similar to the Unix basename command.\n       * Often used to extract the file name from a fully qualified path.\n       *\n       * @param path the path to evaluate.\n       * @param suffix optionally, an extension to remove from the result.\n       */\n      basename(path: string, suffix?: string): string;\n      /**\n       * Return the extension of the path, from the last '.' to end of string in the last portion of the path.\n       * If there is no '.' in the last portion of the path or the first character of it is '.', then it returns an empty string.\n       *\n       * @param path the path to evaluate.\n       */\n      extname(path: string): string;\n      /**\n       * The platform-specific file separator. '\\\\' or '/'.\n       */\n      readonly sep: \"\\\\\" | \"/\";\n      /**\n       * The platform-specific file delimiter. ';' or ':'.\n       */\n      readonly delimiter: \";\" | \":\";\n      /**\n       * Returns an object from a path string - the opposite of format().\n       *\n       * @param path path to evaluate.\n       * @throws {TypeError} if `path` is not a string.\n       */\n      parse(path: string): ParsedPath;\n      /**\n       * Returns a path string from an object - the opposite of parse().\n       *\n       * @param pathObject path to evaluate.\n       */\n      format(pathObject: FormatInputPathObject): string;\n    }\n  }\n  const path: path.PlatformPath;\n  export = path;\n}\n"
  },
  {
    "path": "types/perf_hooks.d.ts",
    "content": "/**\n * This module provides an implementation of a subset of the W3C [Web Performance APIs](https://w3c.github.io/perf-timing-primer/) as well as additional APIs for\n * Node.js-specific performance measurements.\n *\n*/\ndeclare module \"perf_hooks\" {\n  interface Performance {\n    /**\n     * Returns the current high resolution millisecond timestamp, where 0 represents the start of the current `node` process.\n     * @since v8.5.0\n     */\n    now(): number;\n    /**\n     * The [`timeOrigin`](https://w3c.github.io/hr-time/#dom-performance-timeorigin) specifies the high resolution millisecond timestamp\n     * at which the current `node` process began, measured in Unix time.\n     * @since v8.5.0\n     */\n    readonly timeOrigin: number;\n    /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Performance/toJSON) */\n    toJSON(): { timeOrigin: number }; // TODO: llrt currently has only one field\n  }\n  var performance: Performance\n}\n"
  },
  {
    "path": "types/process.d.ts",
    "content": "declare module \"process\" {\n  import { EventEmitter } from \"events\";\n\n  global {\n    var process: Process;\n\n    namespace QuickJS {\n      type Signals =\n        | \"SIGABRT\"\n        | \"SIGALRM\"\n        | \"SIGFPE\"\n        | \"SIGHUP\"\n        | \"SIGILL\"\n        | \"SIGINT\"\n        | \"SIGKILL\"\n        | \"SIGPIPE\"\n        | \"SIGQUIT\"\n        | \"SIGSEGV\"\n        | \"SIGTERM\";\n    }\n    type Platform = \"darwin\" | \"linux\" | \"win32\";\n    type Architecture = \"arm64\" | \"x64\";\n  }\n  interface Dict<T> {\n    [key: string]: T | undefined;\n  }\n  // Alias for compatibility\n  interface ProcessEnv extends Dict<string> {}\n  interface HRTime {\n    (): [number, number];\n\n    /**\n     * The `bigint` version of the `{@link process.hrtime()}` method returning the current high-resolution real time in nanoseconds as a `bigint`.\n     */\n    bigint(): bigint;\n  }\n  interface ProcessRelease {\n    name: string;\n  }\n  interface ProcessVersions extends Dict<string> {\n    llrt: string;\n  }\n  interface Process extends EventEmitter {\n    hrtime: HRTime;\n    /**\n     * The `process.cwd()` method returns the current working directory of the llrt\n     * process.\n     *\n     * ```js\n     * import { cwd } from 'process';\n     *\n     * console.log(`Current directory: ${cwd()}`);\n     * ```\n     */\n    cwd(): string;\n    /**\n     * The `process.argv0` property stores a read-only copy of the original value of`argv[0]` passed when llrt starts.\n     *\n     * ```console\n     * $ ./llrt -e 'console.log(process.argv[0])'\n     * ./llrt\n     * $ ./llrt -e 'console.log(process.argv0)'\n     * ./llrt\n     * ```\n     */\n    argv0: string;\n    /**\n     * Returns the OS-assigned process identifier associated with this process.\n     */\n    id: number;\n    /**\n     * The `process.argv` property returns an array containing the command-line\n     * arguments passed when the llrt process was launched. The first element will\n     * be {@link execPath}. See `process.argv0` if access to the original value\n     * of `argv[0]` is needed. The second element will be the path to the JavaScript\n     * file being executed. The remaining elements will be any additional command-line\n     * arguments.\n     *\n     * For example, assuming the following script for `process-args.js`:\n     *\n     * ```js\n     * import { argv } from 'process';\n     *\n     * // print process.argv\n     * argv.forEach((val, index) => {\n     *   console.log(`${index}: ${val}`);\n     * });\n     * ```\n     * ```\n     */\n    argv: string[];\n    /**\n     * The operating system CPU architecture for which the llrt binary was compiled.\n     * Possible values are: `'arm64'` and `'x64'`.\n     *\n     * ```js\n     * import { arch } from 'process';\n     *\n     * console.log(`This processor architecture is ${arch}`);\n     * ```\n     */\n    readonly arch: Architecture;\n    /**\n     * The `process.platform` property returns a string identifying the operating\n     * system platform for which the llrt binary was compiled.\n     *\n     * Currently possible values are:\n     *\n     * * `'darwin'`\n     * * `'linux'`\n     * * `'win32'`\n     *\n     * ```js\n     * import { platform } from 'process';\n     *\n     * console.log(`This platform is ${platform}`);\n     * ```\n     */\n    readonly platform: Platform;\n\n    /**\n     * The `process.release` property returns an `Object` containing metadata related\n     * to the current release, including URLs for the source tarball and headers-only\n     * tarball.\n     *\n     * `process.release` contains the following properties:\n     *\n     * ```js\n     * {\n     *   name: 'llrt',\n     * }\n     * ```\n     *\n     * In custom builds from non-release versions of the source tree, only the `name` property may be present. The additional properties should not be\n     * relied upon to exist.\n     */\n    readonly release: ProcessRelease;\n    /**\n     * The `process.version` property contains the llrt version string.\n     *\n     * ```js\n     * import { version } from 'process';\n     *\n     * console.log(`Version: ${version}`);\n     * // Version: 0.1.15\n     * ```\n     */\n    readonly version: string;\n    /**\n     * The `process.versions` property returns an object listing the version strings of\n     * llrt and its dependencies. `process.versions.modules` indicates the current\n     * ABI version, which is increased whenever a C++ API changes. llrt will refuse\n     * to load modules that were compiled against a different module ABI version.\n     *\n     * ```js\n     * import { versions } from 'process';\n     *\n     * console.log(versions);\n     * ```\n     *\n     * Will generate an object similar to:\n     *\n     * ```console\n     * {\n     *   llrt:'0.1.15'\n     * }\n     * ```\n     */\n    readonly versions: ProcessVersions;\n    /**\n     * The `process.exit()` method instructs llrt to terminate the process\n     * synchronously with an exit status of `code`. If `code` is omitted, exit uses\n     * either the 'success' code `0` or the value of `process.exitCode` if it has been\n     * set. llrt will not terminate until all the `'exit'` event listeners are\n     * called.\n     *\n     * To exit with a 'failure' code:\n     *\n     * ```js\n     * import { exit } from 'process';\n     *\n     * exit(1);\n     * ```\n     */\n    exit(code?: number | string | null | undefined): never;\n\n    /**\n     * The `process.kill()` method sends the `signal` to the process identified by `pid`.\n     *\n     * Signal names are strings such as 'SIGINT' or 'SIGHUP'. See Signal Events and kill(2)\n     * for more information.\n     *\n     * This method will throw an error if the target pid does not exist. As a special case,\n     * a signal of 0 can be used to test for the existence of a process. Windows platforms\n     * will throw an error if the pid is used to kill a process group.\n     *\n     * Even though the name of this function is process.kill(), it is really just a signal\n     * sender, like the kill system call. The signal sent may do something other than kill\n     * the target process.\n     *\n     * ```js\n     * import { kill } from 'process';\n     *\n     * process.on('SIGHUP', () => {\n     *   console.log('Got SIGHUP signal.');\n     * });\n     *\n     * setTimeout(() => {\n     *   console.log('Exiting.');\n     *   process.exit(0);\n     * }, 100);\n     *\n     * kill(process.pid, 'SIGHUP');\n     * ```\n     *\n     * When `SIGUSR1` is received by a Node.js process, Node.js will start the debugger.\n     * See the debugger documentation for more information.\n     *\n     * @since v0.1.31\n     * @param pid A process ID\n     * @param signal The signal to send, either as a string or number. Default: 'SIGTERM'.\n     */\n    kill(pid: number, signal?: QuickJS.Signals | number): void;\n\n    /**\n     * The `process.exitCode` property indicates the exit code that will be used\n     * when the llrt process eventually exits. If it is not specified, the default\n     * exit code is `undefined` and will be 0 on exit.\n     *\n     * ```js\n     * import { exitCode, exit } from 'process';\n     *\n     * exitCode = 42;\n     * exit();\n     * ```\n     *\n     * This will cause the llrt process to exit with the exit code `42`.\n     */\n    exitCode: number | null;\n\n    /**\n     * The `process.getgid()` method returns the numerical group identity of the\n     * process. (See [`getgid(2)`](http://man7.org/linux/man-pages/man2/getgid.2.html).)\n     *\n     * ```js\n     * import process from 'process';\n     *\n     * if (process.getgid) {\n     *   console.log(`Current gid: ${process.getgid()}`);\n     * }\n     * ```\n     *\n     * This function is only available on POSIX platforms (i.e. not Windows or\n     * Android).\n     * @since v0.1.31\n     */\n    getgid?: () => number;\n    /**\n     * The `process.setgid()` method sets the group identity of the process. (See [`setgid(2)`](http://man7.org/linux/man-pages/man2/setgid.2.html).) The `id` can be passed as either a\n     * numeric ID or a group name\n     * string. If a group name is specified, this method blocks while resolving the\n     * associated numeric ID.\n     *\n     * ```js\n     * import process from 'process';\n     *\n     * if (process.getgid &#x26;&#x26; process.setgid) {\n     *   console.log(`Current gid: ${process.getgid()}`);\n     *   try {\n     *     process.setgid(501);\n     *     console.log(`New gid: ${process.getgid()}`);\n     *   } catch (err) {\n     *     console.log(`Failed to set gid: ${err}`);\n     *   }\n     * }\n     * ```\n     *\n     * This function is only available on POSIX platforms (i.e. not Windows or\n     * Android).\n     * This feature is not available in `Worker` threads.\n     * @since v0.1.31\n     * @param id The group name or ID\n     */\n    setgid?: (id: number) => void;\n    /**\n     * The `process.getuid()` method returns the numeric user identity of the process.\n     * (See [`getuid(2)`](http://man7.org/linux/man-pages/man2/getuid.2.html).)\n     *\n     * ```js\n     * import process from 'process';\n     *\n     * if (process.getuid) {\n     *   console.log(`Current uid: ${process.getuid()}`);\n     * }\n     * ```\n     *\n     * This function is only available on POSIX platforms (i.e. not Windows or\n     * Android).\n     * @since v0.1.28\n     */\n    getuid?: () => number;\n    /**\n     * The `process.setuid(id)` method sets the user identity of the process. (See [`setuid(2)`](http://man7.org/linux/man-pages/man2/setuid.2.html).) The `id` can be passed as either a\n     * numeric ID or a username string.\n     * If a username is specified, the method blocks while resolving the associated\n     * numeric ID.\n     *\n     * ```js\n     * import process from 'process';\n     *\n     * if (process.getuid &#x26;&#x26; process.setuid) {\n     *   console.log(`Current uid: ${process.getuid()}`);\n     *   try {\n     *     process.setuid(501);\n     *     console.log(`New uid: ${process.getuid()}`);\n     *   } catch (err) {\n     *     console.log(`Failed to set uid: ${err}`);\n     *   }\n     * }\n     * ```\n     *\n     * This function is only available on POSIX platforms (i.e. not Windows or\n     * Android).\n     * This feature is not available in `Worker` threads.\n     * @since v0.1.28\n     */\n    setuid?: (id: number) => void;\n    /**\n     * The `process.geteuid()` method returns the numerical effective user identity of\n     * the process. (See [`geteuid(2)`](http://man7.org/linux/man-pages/man2/geteuid.2.html).)\n     *\n     * ```js\n     * import process from 'process';\n     *\n     * if (process.geteuid) {\n     *   console.log(`Current uid: ${process.geteuid()}`);\n     * }\n     * ```\n     *\n     * This function is only available on POSIX platforms (i.e. not Windows or\n     * Android).\n     * @since v2.0.0\n     */\n    geteuid?: () => number;\n    /**\n     * The `process.seteuid()` method sets the effective user identity of the process.\n     * (See [`seteuid(2)`](http://man7.org/linux/man-pages/man2/seteuid.2.html).) The `id` can be passed as either a numeric ID or a username\n     * string. If a username is specified, the method blocks while resolving the\n     * associated numeric ID.\n     *\n     * ```js\n     * import process from 'process';\n     *\n     * if (process.geteuid &#x26;&#x26; process.seteuid) {\n     *   console.log(`Current uid: ${process.geteuid()}`);\n     *   try {\n     *     process.seteuid(501);\n     *     console.log(`New uid: ${process.geteuid()}`);\n     *   } catch (err) {\n     *     console.log(`Failed to set uid: ${err}`);\n     *   }\n     * }\n     * ```\n     *\n     * This function is only available on POSIX platforms (i.e. not Windows or\n     * Android).\n     * This feature is not available in `Worker` threads.\n     * @since v2.0.0\n     * @param id A user name or ID\n     */\n    seteuid?: (id: number) => void;\n    /**\n     * The `process.getegid()` method returns the numerical effective group identity\n     * of the Node.js process. (See [`getegid(2)`](http://man7.org/linux/man-pages/man2/getegid.2.html).)\n     *\n     * ```js\n     * import process from 'process';\n     *\n     * if (process.getegid) {\n     *   console.log(`Current gid: ${process.getegid()}`);\n     * }\n     * ```\n     *\n     * This function is only available on POSIX platforms (i.e. not Windows or\n     * Android).\n     * @since v2.0.0\n     */\n    getegid?: () => number;\n    /**\n     * The `process.setegid()` method sets the effective group identity of the process.\n     * (See [`setegid(2)`](http://man7.org/linux/man-pages/man2/setegid.2.html).) The `id` can be passed as either a numeric ID or a group\n     * name string. If a group name is specified, this method blocks while resolving\n     * the associated a numeric ID.\n     *\n     * ```js\n     * import process from 'process';\n     *\n     * if (process.getegid &#x26;&#x26; process.setegid) {\n     *   console.log(`Current gid: ${process.getegid()}`);\n     *   try {\n     *     process.setegid(501);\n     *     console.log(`New gid: ${process.getegid()}`);\n     *   } catch (err) {\n     *     console.log(`Failed to set gid: ${err}`);\n     *   }\n     * }\n     * ```\n     *\n     * This function is only available on POSIX platforms (i.e. not Windows or\n     * Android).\n     * This feature is not available in `Worker` threads.\n     * @since v2.0.0\n     * @param id A group name or ID\n     */\n    setegid?: (id: number) => void;\n    /**\n     * The `process.env` property returns an object containing the user environment.\n     * See [`environ(7)`](http://man7.org/linux/man-pages/man7/environ.7.html).\n     *\n     * An example of this object looks like:\n     *\n     * ```js\n     * {\n     *   TERM: 'xterm-256color',\n     *   SHELL: '/usr/local/bin/bash',\n     *   USER: 'maciej',\n     *   PATH: '~/.bin/:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin',\n     *   PWD: '/Users/maciej',\n     *   EDITOR: 'vim',\n     *   SHLVL: '1',\n     *   HOME: '/Users/maciej',\n     *   LOGNAME: 'maciej',\n     *   _: '/usr/local/bin/node'\n     * }\n     * ```\n     *\n     * It is possible to modify this object, but such modifications will not be\n     * reflected outside the Node.js process, or (unless explicitly requested)\n     * to other `Worker` threads.\n     * In other words, the following example would not work:\n     *\n     * ```bash\n     * node -e 'process.env.foo = \"bar\"' &#x26;&#x26; echo $foo\n     * ```\n     *\n     * While the following will:\n     *\n     * ```js\n     * import { env } from 'node:process';\n     *\n     * env.foo = 'bar';\n     * console.log(env.foo);\n     * ```\n     *\n     * Assigning a property on `process.env` will implicitly convert the value\n     * to a string. **This behavior is deprecated.** Future versions of Node.js may\n     * throw an error when the value is not a string, number, or boolean.\n     *\n     * ```js\n     * import { env } from 'node:process';\n     *\n     * env.test = null;\n     * console.log(env.test);\n     * // => 'null'\n     * env.test = undefined;\n     * console.log(env.test);\n     * // => 'undefined'\n     * ```\n     *\n     * Use `delete` to delete a property from `process.env`.\n     *\n     * ```js\n     * import { env } from 'node:process';\n     *\n     * env.TEST = 1;\n     * delete env.TEST;\n     * console.log(env.TEST);\n     * // => undefined\n     * ```\n     *\n     * On Windows operating systems, environment variables are case-insensitive.\n     *\n     * ```js\n     * import { env } from 'node:process';\n     *\n     * env.TEST = 1;\n     * console.log(env.test);\n     * // => 1\n     * ```\n     *\n     * Unless explicitly specified when creating a `Worker` instance,\n     * each `Worker` thread has its own copy of `process.env`, based on its\n     * parent thread's `process.env`, or whatever was specified as the `env` option\n     * to the `Worker` constructor. Changes to `process.env` will not be visible\n     * across `Worker` threads, and only the main thread can make changes that\n     * are visible to the operating system or to native add-ons. On Windows, a copy of `process.env` on a `Worker` instance operates in a case-sensitive manner\n     * unlike the main thread.\n     * @since v0.1.27\n     */\n    env: ProcessEnv;\n  }\n}\n"
  },
  {
    "path": "types/stream/web.d.ts",
    "content": "type _ByteLengthQueuingStrategy = typeof globalThis extends { onmessage: any }\n  ? {}\n  : import(\"stream/web\").ByteLengthQueuingStrategy;\ntype _CountQueuingStrategy = typeof globalThis extends { onmessage: any }\n  ? {}\n  : import(\"stream/web\").CountQueuingStrategy;\ntype _ReadableByteStreamController = typeof globalThis extends {\n  onmessage: any;\n}\n  ? {}\n  : import(\"stream/web\").ReadableByteStreamController;\ntype _ReadableStream<R = any> = typeof globalThis extends { onmessage: any }\n  ? {}\n  : import(\"stream/web\").ReadableStream<R>;\ntype _ReadableStreamBYOBReader = typeof globalThis extends { onmessage: any }\n  ? {}\n  : import(\"stream/web\").ReadableStreamBYOBReader;\ntype _ReadableStreamBYOBRequest = typeof globalThis extends { onmessage: any }\n  ? {}\n  : import(\"stream/web\").ReadableStreamBYOBRequest;\ntype _ReadableStreamDefaultController<R = any> = typeof globalThis extends {\n  onmessage: any;\n}\n  ? {}\n  : import(\"stream/web\").ReadableStreamDefaultController<R>;\ntype _ReadableStreamDefaultReader<R = any> = typeof globalThis extends {\n  onmessage: any;\n}\n  ? {}\n  : import(\"stream/web\").ReadableStreamDefaultReader<R>;\ntype _WritableStream<W = any> = typeof globalThis extends { onmessage: any }\n  ? {}\n  : import(\"stream/web\").WritableStream<W>;\ntype _WritableStreamDefaultController = typeof globalThis extends {\n  onmessage: any;\n}\n  ? {}\n  : import(\"stream/web\").WritableStreamDefaultController;\ntype _WritableStreamDefaultWriter<W = any> = typeof globalThis extends {\n  onmessage: any;\n}\n  ? {}\n  : import(\"stream/web\").WritableStreamDefaultWriter<W>;\n\ndeclare module \"stream/web\" {\n  // stub module, pending copy&paste from .d.ts or manual impl\n  // copy from lib.dom.d.ts\n  interface ReadableWritablePair<R = any, W = any> {\n    readable: ReadableStream<R>;\n    /**\n     * Provides a convenient, chainable way of piping this readable stream\n     * through a transform stream (or any other { writable, readable }\n     * pair). It simply pipes the stream into the writable side of the\n     * supplied pair, and returns the readable side for further use.\n     *\n     * Piping a stream will lock it for the duration of the pipe, preventing\n     * any other consumer from acquiring a reader.\n     */\n    writable: WritableStream<W>;\n  }\n  interface StreamPipeOptions {\n    preventAbort?: boolean;\n    preventCancel?: boolean;\n    /**\n     * Pipes this readable stream to a given writable stream destination.\n     * The way in which the piping process behaves under various error\n     * conditions can be customized with a number of passed options. It\n     * returns a promise that fulfills when the piping process completes\n     * successfully, or rejects if any errors were encountered.\n     *\n     * Piping a stream will lock it for the duration of the pipe, preventing\n     * any other consumer from acquiring a reader.\n     *\n     * Errors and closures of the source and destination streams propagate\n     * as follows:\n     *\n     * An error in this source readable stream will abort destination,\n     * unless preventAbort is truthy. The returned promise will be rejected\n     * with the source's error, or with any error that occurs during\n     * aborting the destination.\n     *\n     * An error in destination will cancel this source readable stream,\n     * unless preventCancel is truthy. The returned promise will be rejected\n     * with the destination's error, or with any error that occurs during\n     * canceling the source.\n     *\n     * When this source readable stream closes, destination will be closed,\n     * unless preventClose is truthy. The returned promise will be fulfilled\n     * once this process completes, unless an error is encountered while\n     * closing the destination, in which case it will be rejected with that\n     * error.\n     *\n     * If destination starts out closed or closing, this source readable\n     * stream will be canceled, unless preventCancel is true. The returned\n     * promise will be rejected with an error indicating piping to a closed\n     * stream failed, or with any error that occurs during canceling the\n     * source.\n     *\n     * The signal option can be set to an AbortSignal to allow aborting an\n     * ongoing pipe operation via the corresponding AbortController. In this\n     * case, this source readable stream will be canceled, and destination\n     * aborted, unless the respective options preventCancel or preventAbort\n     * are set.\n     */\n    preventClose?: boolean;\n    signal?: AbortSignal;\n  }\n  interface ReadableStreamGenericReader {\n    readonly closed: Promise<undefined>;\n    cancel(reason?: any): Promise<void>;\n  }\n  type ReadableStreamController<T> = ReadableStreamDefaultController<T>;\n  interface ReadableStreamReadValueResult<T> {\n    done: false;\n    value: T;\n  }\n  interface ReadableStreamReadDoneResult<T> {\n    done: true;\n    value?: T;\n  }\n  type ReadableStreamReadResult<T> =\n    | ReadableStreamReadValueResult<T>\n    | ReadableStreamReadDoneResult<T>;\n  interface ReadableByteStreamControllerCallback {\n    (controller: ReadableByteStreamController): void | PromiseLike<void>;\n  }\n  interface UnderlyingSinkAbortCallback {\n    (reason?: any): void | PromiseLike<void>;\n  }\n  interface UnderlyingSinkCloseCallback {\n    (): void | PromiseLike<void>;\n  }\n  interface UnderlyingSinkStartCallback {\n    (controller: WritableStreamDefaultController): any;\n  }\n  interface UnderlyingSinkWriteCallback<W> {\n    (\n      chunk: W,\n      controller: WritableStreamDefaultController\n    ): void | PromiseLike<void>;\n  }\n  interface UnderlyingSourceCancelCallback {\n    (reason?: any): void | PromiseLike<void>;\n  }\n  interface UnderlyingSourcePullCallback<R> {\n    (controller: ReadableStreamController<R>): void | PromiseLike<void>;\n  }\n  interface UnderlyingSourceStartCallback<R> {\n    (controller: ReadableStreamController<R>): any;\n  }\n  interface UnderlyingByteSource {\n    autoAllocateChunkSize?: number;\n    cancel?: ReadableStreamErrorCallback;\n    pull?: ReadableByteStreamControllerCallback;\n    start?: ReadableByteStreamControllerCallback;\n    type: \"bytes\";\n  }\n  interface UnderlyingSource<R = any> {\n    cancel?: UnderlyingSourceCancelCallback;\n    pull?: UnderlyingSourcePullCallback<R>;\n    start?: UnderlyingSourceStartCallback<R>;\n    type?: undefined;\n  }\n  interface UnderlyingSink<W = any> {\n    abort?: UnderlyingSinkAbortCallback;\n    close?: UnderlyingSinkCloseCallback;\n    start?: UnderlyingSinkStartCallback;\n    type?: undefined;\n    write?: UnderlyingSinkWriteCallback<W>;\n  }\n  interface ReadableStreamErrorCallback {\n    (reason: any): void | PromiseLike<void>;\n  }\n  interface ReadableStreamAsyncIterator<T> extends AsyncIterableIterator<T> {\n    [Symbol.asyncIterator](): ReadableStreamAsyncIterator<T>;\n  }\n  /** This Streams API interface represents a readable stream of byte data. */\n  interface ReadableStream<R = any> {\n    readonly locked: boolean;\n    cancel(reason?: any): Promise<void>;\n    getReader(options: { mode: \"byob\" }): ReadableStreamBYOBReader;\n    getReader(): ReadableStreamDefaultReader<R>;\n    getReader(\n      options?: ReadableStreamGetReaderOptions\n    ): ReadableStreamReader<R>;\n    pipeThrough<T>(\n      transform: ReadableWritablePair<T, R>,\n      options?: StreamPipeOptions\n    ): ReadableStream<T>;\n    pipeTo(\n      destination: WritableStream<R>,\n      options?: StreamPipeOptions\n    ): Promise<void>;\n    tee(): [ReadableStream<R>, ReadableStream<R>];\n    values(options?: {\n      preventCancel?: boolean;\n    }): ReadableStreamAsyncIterator<R>;\n    [Symbol.asyncIterator](): ReadableStreamAsyncIterator<R>;\n  }\n  const ReadableStream: {\n    prototype: ReadableStream;\n    from<T>(iterable: Iterable<T> | AsyncIterable<T>): ReadableStream<T>;\n    new (\n      underlyingSource: UnderlyingByteSource,\n      strategy?: QueuingStrategy<Uint8Array>\n    ): ReadableStream<Uint8Array>;\n    new <R = any>(\n      underlyingSource?: UnderlyingSource<R>,\n      strategy?: QueuingStrategy<R>\n    ): ReadableStream<R>;\n  };\n  type ReadableStreamReaderMode = \"byob\";\n  interface ReadableStreamGetReaderOptions {\n    /**\n     * Creates a ReadableStreamBYOBReader and locks the stream to the new reader.\n     *\n     * This call behaves the same way as the no-argument variant, except that it only works on readable byte streams, i.e. streams which were constructed specifically with the ability to handle \"bring your own buffer\" reading. The returned BYOB reader provides the ability to directly read individual chunks from the stream via its read() method, into developer-supplied buffers, allowing more precise control over allocation.\n     */\n    mode?: ReadableStreamReaderMode;\n  }\n  type ReadableStreamReader<T> =\n    | ReadableStreamDefaultReader<T>\n    | ReadableStreamBYOBReader;\n  interface ReadableStreamDefaultReader<R = any>\n    extends ReadableStreamGenericReader {\n    read(): Promise<ReadableStreamReadResult<R>>;\n    releaseLock(): void;\n  }\n  /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader) */\n  interface ReadableStreamBYOBReader extends ReadableStreamGenericReader {\n    /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader/read) */\n    read<T extends ArrayBufferView>(\n      view: T\n    ): Promise<ReadableStreamReadResult<T>>;\n    /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader/releaseLock) */\n    releaseLock(): void;\n  }\n  const ReadableStreamDefaultReader: {\n    prototype: ReadableStreamDefaultReader;\n    new <R = any>(stream: ReadableStream<R>): ReadableStreamDefaultReader<R>;\n  };\n  const ReadableStreamBYOBReader: {\n    prototype: ReadableStreamBYOBReader;\n    new (stream: ReadableStream): ReadableStreamBYOBReader;\n  };\n  /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBRequest) */\n  interface ReadableStreamBYOBRequest {\n    /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBRequest/view) */\n    readonly view: ArrayBufferView | null;\n    /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBRequest/respond) */\n    respond(bytesWritten: number): void;\n    /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBRequest/respondWithNewView) */\n    respondWithNewView(view: ArrayBufferView): void;\n  }\n  const ReadableStreamBYOBRequest: {\n    prototype: ReadableStreamBYOBRequest;\n    new (): ReadableStreamBYOBRequest;\n  };\n  interface ReadableByteStreamController {\n    readonly byobRequest: undefined;\n    readonly desiredSize: number | null;\n    close(): void;\n    enqueue(chunk: ArrayBufferView): void;\n    error(error?: any): void;\n  }\n  const ReadableByteStreamController: {\n    prototype: ReadableByteStreamController;\n    new (): ReadableByteStreamController;\n  };\n  interface ReadableStreamDefaultController<R = any> {\n    readonly desiredSize: number | null;\n    close(): void;\n    enqueue(chunk?: R): void;\n    error(e?: any): void;\n  }\n  const ReadableStreamDefaultController: {\n    prototype: ReadableStreamDefaultController;\n    new (): ReadableStreamDefaultController;\n  };\n  /**\n   * This Streams API interface provides a standard abstraction for writing\n   * streaming data to a destination, known as a sink. This object comes with\n   * built-in back pressure and queuing.\n   */\n  interface WritableStream<W = any> {\n    readonly locked: boolean;\n    abort(reason?: any): Promise<void>;\n    close(): Promise<void>;\n    getWriter(): WritableStreamDefaultWriter<W>;\n  }\n  const WritableStream: {\n    prototype: WritableStream;\n    new <W = any>(\n      underlyingSink?: UnderlyingSink<W>,\n      strategy?: QueuingStrategy<W>\n    ): WritableStream<W>;\n  };\n  /**\n   * This Streams API interface is the object returned by\n   * WritableStream.getWriter() and once created locks the < writer to the\n   * WritableStream ensuring that no other streams can write to the underlying\n   * sink.\n   */\n  interface WritableStreamDefaultWriter<W = any> {\n    readonly closed: Promise<undefined>;\n    readonly desiredSize: number | null;\n    readonly ready: Promise<undefined>;\n    abort(reason?: any): Promise<void>;\n    close(): Promise<void>;\n    releaseLock(): void;\n    write(chunk?: W): Promise<void>;\n  }\n  const WritableStreamDefaultWriter: {\n    prototype: WritableStreamDefaultWriter;\n    new <W = any>(stream: WritableStream<W>): WritableStreamDefaultWriter<W>;\n  };\n  /**\n   * This Streams API interface represents a controller allowing control of a\n   * WritableStream's state. When constructing a WritableStream, the\n   * underlying sink is given a corresponding WritableStreamDefaultController\n   * instance to manipulate.\n   */\n  interface WritableStreamDefaultController {\n    error(e?: any): void;\n  }\n  const WritableStreamDefaultController: {\n    prototype: WritableStreamDefaultController;\n    new (): WritableStreamDefaultController;\n  };\n  interface QueuingStrategy<T = any> {\n    highWaterMark?: number;\n    size?: QueuingStrategySize<T>;\n  }\n  interface QueuingStrategySize<T = any> {\n    (chunk?: T): number;\n  }\n  interface QueuingStrategyInit {\n    /**\n     * Creates a new ByteLengthQueuingStrategy with the provided high water\n     * mark.\n     *\n     * Note that the provided high water mark will not be validated ahead of\n     * time. Instead, if it is negative, NaN, or not a number, the resulting\n     * ByteLengthQueuingStrategy will cause the corresponding stream\n     * constructor to throw.\n     */\n    highWaterMark: number;\n  }\n  /**\n   * This Streams API interface provides a built-in byte length queuing\n   * strategy that can be used when constructing streams.\n   */\n  interface ByteLengthQueuingStrategy extends QueuingStrategy<ArrayBufferView> {\n    readonly highWaterMark: number;\n    readonly size: QueuingStrategySize<ArrayBufferView>;\n  }\n  const ByteLengthQueuingStrategy: {\n    prototype: ByteLengthQueuingStrategy;\n    new (init: QueuingStrategyInit): ByteLengthQueuingStrategy;\n  };\n  /**\n   * This Streams API interface provides a built-in byte length queuing\n   * strategy that can be used when constructing streams.\n   */\n  interface CountQueuingStrategy extends QueuingStrategy {\n    readonly highWaterMark: number;\n    readonly size: QueuingStrategySize;\n  }\n  const CountQueuingStrategy: {\n    prototype: CountQueuingStrategy;\n    new (init: QueuingStrategyInit): CountQueuingStrategy;\n  };\n\n  global {\n    interface ByteLengthQueuingStrategy extends _ByteLengthQueuingStrategy {}\n    /**\n     * `ByteLengthQueuingStrategy` class is a global reference for `import { ByteLengthQueuingStrategy } from 'node:stream/web'`.\n     * https://nodejs.org/api/globals.html#class-bytelengthqueuingstrategy\n     * @since v18.0.0\n     */\n    var ByteLengthQueuingStrategy: typeof globalThis extends {\n      onmessage: any;\n      ByteLengthQueuingStrategy: infer T;\n    }\n      ? T\n      : typeof import(\"stream/web\").ByteLengthQueuingStrategy;\n\n    interface CountQueuingStrategy extends _CountQueuingStrategy {}\n    /**\n     * `CountQueuingStrategy` class is a global reference for `import { CountQueuingStrategy } from 'node:stream/web'`.\n     * https://nodejs.org/api/globals.html#class-countqueuingstrategy\n     * @since v18.0.0\n     */\n    var CountQueuingStrategy: typeof globalThis extends {\n      onmessage: any;\n      CountQueuingStrategy: infer T;\n    }\n      ? T\n      : typeof import(\"stream/web\").CountQueuingStrategy;\n\n    interface ReadableByteStreamController\n      extends _ReadableByteStreamController {}\n    /**\n     * `ReadableByteStreamController` class is a global reference for `import { ReadableByteStreamController } from 'node:stream/web'`.\n     * https://nodejs.org/api/globals.html#class-readablebytestreamcontroller\n     * @since v18.0.0\n     */\n    var ReadableByteStreamController: typeof globalThis extends {\n      onmessage: any;\n      ReadableByteStreamController: infer T;\n    }\n      ? T\n      : typeof import(\"stream/web\").ReadableByteStreamController;\n\n    interface ReadableStream<R = any> extends _ReadableStream<R> {}\n    /**\n     * `ReadableStream` class is a global reference for `import { ReadableStream } from 'node:stream/web'`.\n     * https://nodejs.org/api/globals.html#class-readablestream\n     * @since v18.0.0\n     */\n    var ReadableStream: typeof globalThis extends {\n      onmessage: any;\n      ReadableStream: infer T;\n    }\n      ? T\n      : typeof import(\"stream/web\").ReadableStream;\n\n    interface ReadableStreamBYOBReader extends _ReadableStreamBYOBReader {}\n    /**\n     * `ReadableStreamBYOBReader` class is a global reference for `import { ReadableStreamBYOBReader } from 'node:stream/web'`.\n     * https://nodejs.org/api/globals.html#class-readablestreambyobreader\n     * @since v18.0.0\n     */\n    var ReadableStreamBYOBReader: typeof globalThis extends {\n      onmessage: any;\n      ReadableStreamBYOBReader: infer T;\n    }\n      ? T\n      : typeof import(\"stream/web\").ReadableStreamBYOBReader;\n\n    interface ReadableStreamBYOBRequest extends _ReadableStreamBYOBRequest {}\n    /**\n     * `ReadableStreamBYOBRequest` class is a global reference for `import { ReadableStreamBYOBRequest } from 'node:stream/web'`.\n     * https://nodejs.org/api/globals.html#class-readablestreambyobrequest\n     * @since v18.0.0\n     */\n    var ReadableStreamBYOBRequest: typeof globalThis extends {\n      onmessage: any;\n      ReadableStreamBYOBRequest: infer T;\n    }\n      ? T\n      : typeof import(\"stream/web\").ReadableStreamBYOBRequest;\n\n    interface ReadableStreamDefaultController<R = any>\n      extends _ReadableStreamDefaultController<R> {}\n    /**\n     * `ReadableStreamDefaultController` class is a global reference for `import { ReadableStreamDefaultController } from 'node:stream/web'`.\n     * https://nodejs.org/api/globals.html#class-readablestreamdefaultcontroller\n     * @since v18.0.0\n     */\n    var ReadableStreamDefaultController: typeof globalThis extends {\n      onmessage: any;\n      ReadableStreamDefaultController: infer T;\n    }\n      ? T\n      : typeof import(\"stream/web\").ReadableStreamDefaultController;\n\n    interface ReadableStreamDefaultReader<R = any>\n      extends _ReadableStreamDefaultReader<R> {}\n    /**\n     * `ReadableStreamDefaultReader` class is a global reference for `import { ReadableStreamDefaultReader } from 'node:stream/web'`.\n     * https://nodejs.org/api/globals.html#class-readablestreamdefaultreader\n     * @since v18.0.0\n     */\n    var ReadableStreamDefaultReader: typeof globalThis extends {\n      onmessage: any;\n      ReadableStreamDefaultReader: infer T;\n    }\n      ? T\n      : typeof import(\"stream/web\").ReadableStreamDefaultReader;\n\n    interface WritableStream<W = any> extends _WritableStream<W> {}\n    /**\n     * `WritableStream` class is a global reference for `import { WritableStream } from 'node:stream/web'`.\n     * https://nodejs.org/api/globals.html#class-writablestream\n     * @since v18.0.0\n     */\n    var WritableStream: typeof globalThis extends {\n      onmessage: any;\n      WritableStream: infer T;\n    }\n      ? T\n      : typeof import(\"stream/web\").WritableStream;\n\n    interface WritableStreamDefaultController\n      extends _WritableStreamDefaultController {}\n    /**\n     * `WritableStreamDefaultController` class is a global reference for `import { WritableStreamDefaultController } from 'node:stream/web'`.\n     * https://nodejs.org/api/globals.html#class-writablestreamdefaultcontroller\n     * @since v18.0.0\n     */\n    var WritableStreamDefaultController: typeof globalThis extends {\n      onmessage: any;\n      WritableStreamDefaultController: infer T;\n    }\n      ? T\n      : typeof import(\"stream/web\").WritableStreamDefaultController;\n\n    interface WritableStreamDefaultWriter<W = any>\n      extends _WritableStreamDefaultWriter<W> {}\n    /**\n     * `WritableStreamDefaultWriter` class is a global reference for `import { WritableStreamDefaultWriter } from 'node:stream/web'`.\n     * https://nodejs.org/api/globals.html#class-writablestreamdefaultwriter\n     * @since v18.0.0\n     */\n    var WritableStreamDefaultWriter: typeof globalThis extends {\n      onmessage: any;\n      WritableStreamDefaultWriter: infer T;\n    }\n      ? T\n      : typeof import(\"stream/web\").WritableStreamDefaultWriter;\n  }\n}\ndeclare module \"node:stream/web\" {\n  export * from \"stream/web\";\n}\n"
  },
  {
    "path": "types/stream.d.ts",
    "content": "declare module \"stream\" {\n  import { EventEmitter } from \"events\";\n  import { Buffer } from \"buffer\";\n\n  class ReadableStreamInner\n    extends EventEmitter\n    implements QuickJS.ReadableStream\n  {\n    /**\n     * The `readable.read()` method reads data out of the internal buffer and\n     * returns it. If no data is available to be read, `null` is returned. By default,\n     * the data is returned as a `Buffer` object unless an encoding has been\n     * specified using the `readable.setEncoding()` method or the stream is operating\n     * in object mode.\n     *\n     * The optional `size` argument specifies a specific number of bytes to read. If\n     * `size` bytes are not available to be read, `null` will be returned _unless_ the\n     * stream has ended, in which case all of the data remaining in the internal buffer\n     * will be returned.\n     *\n     * If the `size` argument is not specified, all of the data contained in the\n     * internal buffer will be returned.\n     *\n     * The `size` argument must be less than or equal to 1 GiB.\n     *\n     * The `readable.read()` method should only be called on `Readable` streams\n     * operating in paused mode. In flowing mode, `readable.read()` is called\n     * automatically until the internal buffer is fully drained.\n     *\n     * ```js\n     * const readable = getReadableStreamSomehow();\n     *\n     * // 'readable' may be triggered multiple times as data is buffered in\n     * readable.on('readable', () => {\n     *   let chunk;\n     *   console.log('Stream is readable (new data received in buffer)');\n     *   // Use a loop to make sure we read all currently available data\n     *   while (null !== (chunk = readable.read())) {\n     *     console.log(`Read ${chunk.length} bytes of data...`);\n     *   }\n     * });\n     *\n     * // 'end' will be triggered once when there is no more data available\n     * readable.on('end', () => {\n     *   console.log('Reached end of stream.');\n     * });\n     * ```\n     *\n     * Each call to `readable.read()` returns a chunk of data, or `null`. The chunks\n     * are not concatenated. A `while` loop is necessary to consume all data\n     * currently in the buffer. When reading a large file `.read()` may return `null`,\n     * having consumed all buffered content so far, but there is still more data to\n     * come not yet buffered. In this case a new `'readable'` event will be emitted\n     * when there is more data in the buffer. Finally the `'end'` event will be\n     * emitted when there is no more data to come.\n     *\n     * Therefore to read a file's whole contents from a `readable`, it is necessary\n     * to collect chunks across multiple `'readable'` events:\n     *\n     * ```js\n     * const chunks = [];\n     *\n     * readable.on('readable', () => {\n     *   let chunk;\n     *   while (null !== (chunk = readable.read())) {\n     *     chunks.push(chunk);\n     *   }\n     * });\n     *\n     * readable.on('end', () => {\n     *   const content = chunks.join('');\n     * });\n     * ```\n     *\n     * A `Readable` stream in object mode will always return a single item from\n     * a call to `readable.read(size)`, regardless of the value of the `size` argument.\n     *\n     * If the `readable.read()` method returns a chunk of data, a `'data'` event will\n     * also be emitted.\n     *\n     * Calling {@link read} after the `'end'` event has\n     * been emitted will return `null`. No runtime error will be raised.\n     * @param size Optional argument to specify how much data to read.\n     */\n    read(size?: number): Buffer | null;\n\n    /**\n     * Destroy the stream. Optionally emit an `'error'` event, and emit a `'close'` event. After this call, the readable\n     * stream will release any internal resources and subsequent calls to `push()` will be ignored.\n     *\n     * Once `destroy()` has been called any further calls will be a no-op and no\n     * further errors except from `_destroy()` may be emitted as `'error'`.\n     *\n     * Implementors should not override this method, but instead implement `readable._destroy()`.\n     * @param error Error which will be passed as payload in `'error'` event\n     */\n    destroy(error?: Error): this;\n\n    /**\n     * Event emitter\n     * The defined events on documents including:\n     * 1. close\n     * 2. data\n     * 3. end\n     * 4. error\n     * 5. readable\n     */\n    addListener(event: EventKey, listener: (...args: any[]) => void): this;\n    addListener(event: \"close\", listener: () => void): this;\n    addListener(event: \"data\", listener: (chunk: Buffer) => void): this;\n    addListener(event: \"end\", listener: () => void): this;\n    addListener(event: \"error\", listener: (err: Error) => void): this;\n    addListener(event: \"readable\", listener: () => void): this;\n    emit(event: EventKey, ...args: any[]): boolean;\n    emit(event: \"close\"): boolean;\n    emit(event: \"data\", chunk: Buffer): boolean;\n    emit(event: \"end\"): boolean;\n    emit(event: \"error\", err: Error): boolean;\n    emit(event: \"readable\"): boolean;\n    on(event: EventKey, listener: (...args: any[]) => void): this;\n    on(event: \"close\", listener: () => void): this;\n    on(event: \"data\", listener: (chunk: Buffer) => void): this;\n    on(event: \"end\", listener: () => void): this;\n    on(event: \"error\", listener: (err: Error) => void): this;\n    on(event: \"readable\", listener: () => void): this;\n    once(event: EventKey, listener: (...args: any[]) => void): this;\n    once(event: \"close\", listener: () => void): this;\n    once(event: \"data\", listener: (chunk: Buffer) => void): this;\n    once(event: \"end\", listener: () => void): this;\n    once(event: \"error\", listener: (err: Error) => void): this;\n    once(event: \"readable\", listener: () => void): this;\n    prependListener(event: EventKey, listener: (...args: any[]) => void): this;\n    prependListener(event: \"close\", listener: () => void): this;\n    prependListener(event: \"data\", listener: (chunk: Buffer) => void): this;\n    prependListener(event: \"end\", listener: () => void): this;\n    prependListener(event: \"error\", listener: (err: Error) => void): this;\n    prependListener(event: \"readable\", listener: () => void): this;\n    prependOnceListener(\n      event: EventKey,\n      listener: (...args: any[]) => void\n    ): this;\n    prependOnceListener(event: \"close\", listener: () => void): this;\n    prependOnceListener(event: \"data\", listener: (chunk: Buffer) => void): this;\n    prependOnceListener(event: \"end\", listener: () => void): this;\n    prependOnceListener(event: \"error\", listener: (err: Error) => void): this;\n    prependOnceListener(event: \"readable\", listener: () => void): this;\n    removeListener(event: EventKey, listener: (...args: any[]) => void): this;\n    removeListener(event: \"close\", listener: () => void): this;\n    removeListener(event: \"data\", listener: (chunk: Buffer) => void): this;\n    removeListener(event: \"end\", listener: () => void): this;\n    removeListener(event: \"error\", listener: (err: Error) => void): this;\n    removeListener(event: \"readable\", listener: () => void): this;\n\n    /**\n     * Calls `readable.destroy()`.\n     */\n    [Symbol.dispose](): void;\n  }\n\n  class WritableStreamInner\n    extends EventEmitter\n    implements QuickJS.WritableStream\n  {\n    /**\n     * The `writable.write()` method writes some data to the stream, and calls the\n     * supplied `callback` once the data has been fully handled. If an error\n     * occurs, the `callback` will be called with the error as its\n     * first argument. The `callback` is usually called asynchronously and before `'error'`\n     * is emitted.\n     *\n     * ```js\n     * function write(data, cb) {\n     *   if (!stream.write(data)) {\n     *     stream.once('drain', cb);\n     *   } else {\n     *     process.nextTick(cb);\n     *   }\n     * }\n     *\n     * // Wait for cb to be called before doing any other write.\n     * write('hello', () => {\n     *   console.log('Write completed, do more writes now.');\n     * });\n     * ```\n     *\n     * A `Writable` stream in object mode will always ignore the `encoding` argument.\n     * @since v0.9.4\n     * @param chunk Optional data to write. `chunk` must be a {string}, {Buffer}, {TypedArray} or {DataView}.\n     * @param [encoding='utf8'] The encoding, if `chunk` is a string.\n     * @param callback Callback for when this chunk of data is flushed.\n     * @return `false` if the stream wishes for the calling code to wait for the `'drain'` event to be emitted before continuing to write additional data; otherwise `true`.\n     */\n    write(\n      chunk:\n        | string\n        | Buffer\n        | QuickJS.ArrayBufferView\n        | ArrayBuffer\n        | SharedArrayBuffer,\n      callback?: (error?: Error | null) => void\n    ): void;\n\n    /**\n     * Calling the `writable.end()` method signals that no more data will be written\n     * to the `Writable`.\n     *\n     * Calling the {@link write} method after calling {@link end} will raise an error.\n     */\n    end(): this;\n\n    /**\n     * Event emitter\n     * The defined events on documents including:\n     * 1. close\n     * 2. error\n     * 3. finish\n     */\n    addListener(event: EventKey, listener: (...args: any[]) => void): this;\n    addListener(event: \"close\", listener: () => void): this;\n    addListener(event: \"error\", listener: (err: Error) => void): this;\n    addListener(event: \"finish\", listener: () => void): this;\n    emit(event: EventKey, ...args: any[]): boolean;\n    emit(event: \"close\"): boolean;\n    emit(event: \"error\", err: Error): boolean;\n    emit(event: \"finish\"): boolean;\n    on(event: EventKey, listener: (...args: any[]) => void): this;\n    on(event: \"close\", listener: () => void): this;\n    on(event: \"error\", listener: (err: Error) => void): this;\n    on(event: \"finish\", listener: () => void): this;\n    once(event: EventKey, listener: (...args: any[]) => void): this;\n    once(event: \"close\", listener: () => void): this;\n    once(event: \"error\", listener: (err: Error) => void): this;\n    once(event: \"finish\", listener: () => void): this;\n    prependListener(event: EventKey, listener: (...args: any[]) => void): this;\n    prependListener(event: \"close\", listener: () => void): this;\n    prependListener(event: \"error\", listener: (err: Error) => void): this;\n    prependListener(event: \"finish\", listener: () => void): this;\n    prependOnceListener(\n      event: EventKey,\n      listener: (...args: any[]) => void\n    ): this;\n    prependOnceListener(event: \"close\", listener: () => void): this;\n    prependOnceListener(event: \"error\", listener: (err: Error) => void): this;\n    prependOnceListener(event: \"finish\", listener: () => void): this;\n    removeListener(event: EventKey, listener: (...args: any[]) => void): this;\n    removeListener(event: \"close\", listener: () => void): this;\n    removeListener(event: \"error\", listener: (err: Error) => void): this;\n    removeListener(event: \"finish\", listener: () => void): this;\n  }\n\n  class DefaultReadableStream extends ReadableStreamInner {}\n\n  class DefaultWritableStream extends WritableStreamInner {}\n\n  class DefaultDuplexStream\n    extends DefaultReadableStream\n    implements DefaultWritableStream\n  {\n    /**\n     * The `writable.write()` method writes some data to the stream, and calls the\n     * supplied `callback` once the data has been fully handled. If an error\n     * occurs, the `callback` will be called with the error as its\n     * first argument. The `callback` is usually called asynchronously and before `'error'`\n     * is emitted.\n     *\n     * ```js\n     * function write(data, cb) {\n     *   if (!stream.write(data)) {\n     *     stream.once('drain', cb);\n     *   } else {\n     *     process.nextTick(cb);\n     *   }\n     * }\n     *\n     * // Wait for cb to be called before doing any other write.\n     * write('hello', () => {\n     *   console.log('Write completed, do more writes now.');\n     * });\n     * ```\n     *\n     * A `Writable` stream in object mode will always ignore the `encoding` argument.\n     * @since v0.9.4\n     * @param chunk Optional data to write. `chunk` must be a {string}, {Buffer}, {TypedArray} or {DataView}.\n     * @param [encoding='utf8'] The encoding, if `chunk` is a string.\n     * @param callback Callback for when this chunk of data is flushed.\n     * @return `false` if the stream wishes for the calling code to wait for the `'drain'` event to be emitted before continuing to write additional data; otherwise `true`.\n     */\n    write(\n      chunk:\n        | string\n        | Buffer\n        | QuickJS.ArrayBufferView\n        | ArrayBuffer\n        | SharedArrayBuffer,\n      callback?: (error?: Error | null) => void\n    ): void;\n\n    /**\n     * Calling the `writable.end()` method signals that no more data will be written\n     * to the `Writable`.\n     *\n     * Calling the {@link write} method after calling {@link end} will raise an error.\n     */\n    end(): this;\n\n    /**\n     * Event emitter\n     * The defined events on documents including:\n     * 1. close\n     * 2. error\n     * 3. finish\n     */\n    addListener(event: EventKey, listener: (...args: any[]) => void): this;\n    addListener(event: \"close\", listener: () => void): this;\n    addListener(event: \"error\", listener: (err: Error) => void): this;\n    addListener(event: \"finish\", listener: () => void): this;\n    emit(event: EventKey, ...args: any[]): boolean;\n    emit(event: \"close\"): boolean;\n    emit(event: \"error\", err: Error): boolean;\n    emit(event: \"finish\"): boolean;\n    on(event: EventKey, listener: (...args: any[]) => void): this;\n    on(event: \"close\", listener: () => void): this;\n    on(event: \"error\", listener: (err: Error) => void): this;\n    on(event: \"finish\", listener: () => void): this;\n    once(event: EventKey, listener: (...args: any[]) => void): this;\n    once(event: \"close\", listener: () => void): this;\n    once(event: \"error\", listener: (err: Error) => void): this;\n    once(event: \"finish\", listener: () => void): this;\n    prependListener(event: EventKey, listener: (...args: any[]) => void): this;\n    prependListener(event: \"close\", listener: () => void): this;\n    prependListener(event: \"error\", listener: (err: Error) => void): this;\n    prependListener(event: \"finish\", listener: () => void): this;\n    prependOnceListener(\n      event: EventKey,\n      listener: (...args: any[]) => void\n    ): this;\n    prependOnceListener(event: \"close\", listener: () => void): this;\n    prependOnceListener(event: \"error\", listener: (err: Error) => void): this;\n    prependOnceListener(event: \"finish\", listener: () => void): this;\n    removeListener(event: EventKey, listener: (...args: any[]) => void): this;\n    removeListener(event: \"close\", listener: () => void): this;\n    removeListener(event: \"error\", listener: (err: Error) => void): this;\n    removeListener(event: \"finish\", listener: () => void): this;\n  }\n\n  global {\n    namespace QuickJS {\n      interface ReadableStream extends EventEmitter {\n        read(size?: number): Buffer | null;\n      }\n\n      interface WritableStream extends EventEmitter {\n        write(\n          chunk:\n            | string\n            | Buffer\n            | QuickJS.ArrayBufferView\n            | ArrayBuffer\n            | SharedArrayBuffer,\n          callback?: (err?: Error | null) => void\n        ): void;\n        end(): this;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "types/string_decoder.d.ts",
    "content": "/**\n * The `string_decoder` module provides an API for decoding `Buffer` objects\n * into strings in a manner that preserves encoded multi-byte UTF-8 and UTF-16\n * characters. It can be accessed using:\n *\n * ```js\n * const { StringDecoder } = require('string_decoder');\n * ```\n *\n * The following example shows the basic use of the `StringDecoder` class.\n *\n * ```js\n * const { StringDecoder } = require('string_decoder');\n * const decoder = new StringDecoder('utf8');\n *\n * const cent = Buffer.from([0xC2, 0xA2]);\n * console.log(decoder.write(cent)); // Prints: ¢\n *\n * const euro = Buffer.from([0xE2, 0x82, 0xAC]);\n * console.log(decoder.write(euro)); // Prints: €\n * ```\n *\n * When a `Buffer` instance is written to the `StringDecoder` instance, an\n * internal buffer is used to ensure that the decoded string does not contain\n * any incomplete multibyte characters. These are held in the buffer until the\n * next call to `stringDecoder.write()` or until `stringDecoder.end()` is called.\n *\n * In the following example, the three UTF-8 encoded bytes of the European Euro\n * symbol (`€`) are written over three separate operations:\n *\n * ```js\n * const { StringDecoder } = require('string_decoder');\n * const decoder = new StringDecoder('utf8');\n *\n * decoder.write(Buffer.from([0xE2]));\n * decoder.write(Buffer.from([0x82]));\n * console.log(decoder.end(Buffer.from([0xAC]))); // Prints: €\n * ```\n */\ndeclare module \"string_decoder\" {\n  import { Buffer, BufferEncoding } from \"buffer\";\n\n  class StringDecoder {\n    constructor(encoding?: BufferEncoding);\n    /**\n     * Returns a decoded string, ensuring that any incomplete multibyte characters at\n     * the end of the `Buffer`, or `TypedArray`, or `DataView` are omitted from the\n     * returned string and stored in an internal buffer for the next call to `stringDecoder.write()` or `stringDecoder.end()`.\n     * @param buffer The bytes to decode.\n     */\n    write(buffer: string | Buffer | QuickJS.ArrayBufferView): string;\n    /**\n     * Returns any remaining input stored in the internal buffer as a string. Bytes\n     * representing incomplete UTF-8 and UTF-16 characters will be replaced with\n     * substitution characters appropriate for the character encoding.\n     *\n     * If the `buffer` argument is provided, one final call to `stringDecoder.write()` is performed before returning the remaining input.\n     * After `end()` is called, the `stringDecoder` object can be reused for new input.\n     * @param buffer The bytes to decode.\n     */\n    end(buffer?: string | Buffer | QuickJS.ArrayBufferView): string;\n  }\n}\n"
  },
  {
    "path": "types/timers.d.ts",
    "content": "declare module \"timers\" {\n  export import setTimeout = globalThis.setTimeout;\n  export import clearTimeout = globalThis.clearTimeout;\n  export import setInterval = globalThis.setInterval;\n  export import clearInterval = globalThis.clearInterval;\n  export import setImmediate = globalThis.setImmediate;\n\n  global {\n    /**\n     * This object is created internally and is returned from `setTimeout()` and `setInterval()`. It can be passed to either `clearTimeout()` or `clearInterval()` in order to cancel the\n     * scheduled actions.\n     */\n    class Timeout {}\n\n    /**\n     * Schedules execution of a one-time `callback` after `delay` milliseconds.\n     *\n     * The `callback` will likely not be invoked in precisely `delay` milliseconds.\n     * LLRT makes no guarantees about the exact timing of when callbacks will fire,\n     * nor of their ordering. The callback will be called as close as possible to the\n     * time specified. The precision is limited to 4ms.\n     *\n     * @param callback The function to call when the timer elapses.\n     * @param [delay=4] The number of milliseconds to wait before calling the `callback`.\n     * @return for use with {@link clearTimeout}\n     */\n    function setTimeout<TArgs extends any[]>(\n      callback: (...args: TArgs) => void,\n      ms?: number\n    ): Timeout;\n\n    /**\n     * Cancels a `Timeout` object created by `setTimeout()`.\n     * @param timeout A `Timeout` object as returned by {@link setTimeout}.\n     */\n    function clearTimeout(timeout: Timeout): void;\n\n    /**\n     * Schedules repeated execution of `callback` every `delay` milliseconds.\n     *\n     * The `callback` will likely not be invoked at precisely `delay` milliseconds.\n     * LLRT makes no guarantees about the exact timing of when callbacks will fire,\n     * nor of their ordering. The callback will be called as close as possible to the\n     * time specified. The precision is limited to 4ms.\n     *\n     * @param callback The function to call when the timer elapses.\n     * @param [delay=4] The number of milliseconds to wait before calling the `callback`.\n     * @return for use with {@link clearInterval}\n     */\n    function setInterval<TArgs extends any[]>(\n      callback: (...args: TArgs) => void,\n      ms?: number\n    ): Timeout;\n\n    /**\n     * Cancels a `Timeout` object created by `setInterval()`.\n     * @param timeout A `Timeout` object as returned by {@link setInterval}\n     */\n    function clearInterval(interval: Timeout): void;\n\n    /**\n     * Schedules the \"immediate\" execution of the `callback` after I/O events'\n     * callbacks.\n     *\n     * @param callback The function to call at the end of this turn of the Node.js `Event Loop`\n     * @return for use with {@link clearImmediate}\n     */\n    function setImmediate<TArgs extends any[]>(\n      callback: (...args: TArgs) => void\n    ): void;\n  }\n}\n"
  },
  {
    "path": "types/timezone.d.ts",
    "content": "// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nexport {};\n\n/**\n * Minimal Intl.DateTimeFormat implementation for timezone support.\n * Enables dayjs and similar libraries to work with timezone conversions.\n */\ndeclare global {\n  namespace Intl {\n    interface DateTimeFormatOptions {\n      localeMatcher?: \"best fit\" | \"lookup\";\n      weekday?: \"long\" | \"short\" | \"narrow\";\n      era?: \"long\" | \"short\" | \"narrow\";\n      year?: \"numeric\" | \"2-digit\";\n      month?: \"numeric\" | \"2-digit\" | \"long\" | \"short\" | \"narrow\";\n      day?: \"numeric\" | \"2-digit\";\n      hour?: \"numeric\" | \"2-digit\";\n      minute?: \"numeric\" | \"2-digit\";\n      second?: \"numeric\" | \"2-digit\";\n      timeZoneName?: \"short\" | \"long\" | \"shortOffset\" | \"longOffset\";\n      formatMatcher?: \"best fit\" | \"basic\";\n      hour12?: boolean;\n      timeZone?: string;\n      fractionalSecondDigits?: 1 | 2 | 3;\n    }\n\n    interface DateTimeFormatPart {\n      type:\n        | \"day\"\n        | \"dayPeriod\"\n        | \"era\"\n        | \"hour\"\n        | \"literal\"\n        | \"minute\"\n        | \"month\"\n        | \"second\"\n        | \"timeZoneName\"\n        | \"weekday\"\n        | \"year\"\n        | \"fractionalSecond\";\n      value: string;\n    }\n\n    interface ResolvedDateTimeFormatOptions {\n      locale: string;\n      calendar: string;\n      numberingSystem: string;\n      timeZone: string;\n      hour12?: boolean;\n      hourCycle?: \"h11\" | \"h12\" | \"h23\" | \"h24\";\n      weekday?: \"long\" | \"short\" | \"narrow\";\n      era?: \"long\" | \"short\" | \"narrow\";\n      year?: \"numeric\" | \"2-digit\";\n      month?: \"numeric\" | \"2-digit\" | \"long\" | \"short\" | \"narrow\";\n      day?: \"numeric\" | \"2-digit\";\n      hour?: \"numeric\" | \"2-digit\";\n      minute?: \"numeric\" | \"2-digit\";\n      second?: \"numeric\" | \"2-digit\";\n      timeZoneName?: \"short\" | \"long\" | \"shortOffset\" | \"longOffset\";\n      fractionalSecondDigits?: 1 | 2 | 3;\n    }\n\n    interface DateTimeFormat {\n      /**\n       * Format a date according to the locale and options.\n       * @param date - Date to format (defaults to current time)\n       */\n      format(date?: Date | number): string;\n\n      /**\n       * Format a date to an array of parts.\n       * @param date - Date to format (defaults to current time)\n       */\n      formatToParts(date?: Date | number): DateTimeFormatPart[];\n\n      /**\n       * Return the resolved options for this formatter.\n       */\n      resolvedOptions(): ResolvedDateTimeFormatOptions;\n\n      readonly [Symbol.toStringTag]: \"Intl.DateTimeFormat\";\n    }\n\n    interface DateTimeFormatConstructor {\n      new (\n        locales?: string | string[],\n        options?: DateTimeFormatOptions\n      ): DateTimeFormat;\n      (\n        locales?: string | string[],\n        options?: DateTimeFormatOptions\n      ): DateTimeFormat;\n    }\n\n    var DateTimeFormat: DateTimeFormatConstructor;\n  }\n\n  var Intl: typeof Intl;\n}\n"
  },
  {
    "path": "types/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"lib\": [\"ESNext\"],\n    \"skipLibCheck\": false,\n    \"strict\": true,\n    \"target\": \"esnext\",\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"disableSolutionSearching\": true,\n    \"noUnusedLocals\": true,\n    \"noEmit\": true,\n    \"resolveJsonModule\": true,\n    \"types\": []\n  },\n  \"exclude\": [\"dist\", \"node_modules\"]\n}\n"
  },
  {
    "path": "types/tty.d.ts",
    "content": "\r\ndeclare module \"tty\" {\r\n  /**\r\n   * The `tty.isatty()` method returns `true` if the given `fd` is associated with\r\n   * a TTY and `false` if it is not, including whenever `fd` is not a non-negative\r\n   * integer.\r\n   * @since v0.5.8\r\n   * @param fd A numeric file descriptor\r\n   */\r\n  function isatty(fd: number): boolean;\r\n}"
  },
  {
    "path": "types/url.d.ts",
    "content": "/**\n * The `url` module provides utilities for URL resolution and parsing. It can\n * be accessed using:\n *\n * ```js\n * import url from 'url';\n * ```\n */\ndeclare module \"url\" {\n  // Output of `url.parse`\n  interface Url {\n    auth: string | null;\n    hash: string | null;\n    host: string | null;\n    hostname: string | null;\n    href: string;\n    path: string | null;\n    pathname: string | null;\n    protocol: string | null;\n    search: string | null;\n    slashes: boolean | null;\n    port: string | null;\n    query: string | null;\n  }\n  interface URLFormatOptions {\n    /**\n     * `true` if the serialized URL string should include the username and password, `false` otherwise.\n     * @default true\n     */\n    auth?: boolean | undefined;\n    /**\n     * `true` if the serialized URL string should include the fragment, `false` otherwise.\n     * @default true\n     */\n    fragment?: boolean | undefined;\n    /**\n     * `true` if the serialized URL string should include the search query, `false` otherwise.\n     * @default true\n     */\n    search?: boolean | undefined;\n    /**\n     * `true` if Unicode characters appearing in the host component of the URL string should be encoded directly as opposed to\n     * being Punycode encoded.\n     * @default false\n     */\n    unicode?: boolean | undefined;\n  }\n  /**\n   * The `url.parse()` method takes a URL string, parses it, and returns a URL\n   * object.\n   *\n   * A `TypeError` is thrown if `urlString` is not a string.\n   *\n   * A `URIError` is thrown if the `auth` property is present but cannot be decoded.\n   *\n   * `url.parse()` uses a lenient, non-standard algorithm for parsing URL\n   * strings. It is prone to security issues such as [host name spoofing](https://hackerone.com/reports/678487) and incorrect handling of usernames and passwords. Do not use with untrusted\n   * input. CVEs are not issued for `url.parse()` vulnerabilities. Use the `WHATWG URL` API instead.\n   * @deprecated Use the WHATWG URL API instead.\n   * @param urlString The URL string to parse.\n   * @param [parseQueryString=false] If `true`, the `query` property will always be set to an object returned by the {@link querystring} module's `parse()` method. If `false`, the `query` property\n   * on the returned URL object will be an unparsed, undecoded string.\n   * @param [slashesDenoteHost=false] If `true`, the first token after the literal string `//` and preceding the next `/` will be interpreted as the `host`. For instance, given `//foo/bar`, the\n   * result would be `{host: 'foo', pathname: '/bar'}` rather than `{pathname: '//foo/bar'}`.\n   */\n  function parse(\n    urlString: string,\n    parseQueryString: boolean,\n    slashesDenoteHost?: boolean\n  ): Url;\n  /**\n   * The `url.format()` method returns a formatted URL string derived from `urlObject`.\n   *\n   * ```js\n   * const url = require('url');\n   * url.format({\n   *   protocol: 'https',\n   *   hostname: 'example.com',\n   *   pathname: '/some/path',\n   *   query: {\n   *     page: 1,\n   *     format: 'json',\n   *   },\n   * });\n   *\n   * // => 'https://example.com/some/path?page=1&#x26;format=json'\n   * ```\n   *\n   * If `urlObject` is not an object or a string, `url.format()` will throw a `TypeError`.\n   *\n   * The formatting process operates as follows:\n   *\n   * * A new empty string `result` is created.\n   * * If `urlObject.protocol` is a string, it is appended as-is to `result`.\n   * * Otherwise, if `urlObject.protocol` is not `undefined` and is not a string, an `Error` is thrown.\n   * * For all string values of `urlObject.protocol` that _do not end_ with an ASCII\n   * colon (`:`) character, the literal string `:` will be appended to `result`.\n   * * If either of the following conditions is true, then the literal string `//` will be appended to `result`:\n   *    * `urlObject.slashes` property is true;\n   *    * `urlObject.protocol` begins with `http`, `https`, `ftp`, `gopher`, or `file`;\n   * * If the value of the `urlObject.auth` property is truthy, and either `urlObject.host` or `urlObject.hostname` are not `undefined`, the value of `urlObject.auth` will be coerced into a string\n   * and appended to `result` followed by the literal string `@`.\n   * * If the `urlObject.host` property is `undefined` then:\n   *    * If the `urlObject.hostname` is a string, it is appended to `result`.\n   *    * Otherwise, if `urlObject.hostname` is not `undefined` and is not a string,\n   *    an `Error` is thrown.\n   *    * If the `urlObject.port` property value is truthy, and `urlObject.hostname` is not `undefined`:\n   *          * The literal string `:` is appended to `result`, and\n   *          * The value of `urlObject.port` is coerced to a string and appended to `result`.\n   * * Otherwise, if the `urlObject.host` property value is truthy, the value of `urlObject.host` is coerced to a string and appended to `result`.\n   * * If the `urlObject.pathname` property is a string that is not an empty string:\n   *    * If the `urlObject.pathname` _does not start_ with an ASCII forward slash\n   *    (`/`), then the literal string `'/'` is appended to `result`.\n   *    * The value of `urlObject.pathname` is appended to `result`.\n   * * Otherwise, if `urlObject.pathname` is not `undefined` and is not a string, an `Error` is thrown.\n   * * If the `urlObject.search` property is `undefined` and if the `urlObject.query`property is an `Object`, the literal string `?` is appended to `result` followed by the output of calling the\n   * `querystring` module's `stringify()` method passing the value of `urlObject.query`.\n   * * Otherwise, if `urlObject.search` is a string:\n   *    * If the value of `urlObject.search` _does not start_ with the ASCII question\n   *    mark (`?`) character, the literal string `?` is appended to `result`.\n   *    * The value of `urlObject.search` is appended to `result`.\n   * * Otherwise, if `urlObject.search` is not `undefined` and is not a string, an `Error` is thrown.\n   * * If the `urlObject.hash` property is a string:\n   *    * If the value of `urlObject.hash` _does not start_ with the ASCII hash (`#`)\n   *    character, the literal string `#` is appended to `result`.\n   *    * The value of `urlObject.hash` is appended to `result`.\n   * * Otherwise, if the `urlObject.hash` property is not `undefined` and is not a\n   * string, an `Error` is thrown.\n   * * `result` is returned.\n   * @legacy Use the WHATWG URL API instead.\n   * @param urlObject A URL object (as returned by `url.parse()` or constructed otherwise). If a string, it is converted to an object by passing it to `url.parse()`.\n   */\n  function format(urlObject: URL, options?: URLFormatOptions): string;\n  /**\n   * Returns the [Punycode](https://tools.ietf.org/html/rfc5891#section-4.4) ASCII serialization of the `domain`. If `domain` is an\n   * invalid domain, the empty string is returned.\n   *\n   * It performs the inverse operation to {@link domainToUnicode}.\n   *\n   * ```js\n   * import url from 'url';\n   *\n   * console.log(url.domainToASCII('español.com'));\n   * // Prints xn--espaol-zwa.com\n   * console.log(url.domainToASCII('中文.com'));\n   * // Prints xn--fiq228c.com\n   * console.log(url.domainToASCII('xn--iñvalid.com'));\n   * // Prints an empty string\n   * ```\n   */\n  function domainToASCII(domain: string): string;\n  /**\n   * Returns the Unicode serialization of the `domain`. If `domain` is an invalid\n   * domain, the empty string is returned.\n   *\n   * It performs the inverse operation to {@link domainToASCII}.\n   *\n   * ```js\n   * import url from 'url';\n   *\n   * console.log(url.domainToUnicode('xn--espaol-zwa.com'));\n   * // Prints español.com\n   * console.log(url.domainToUnicode('xn--fiq228c.com'));\n   * // Prints 中文.com\n   * console.log(url.domainToUnicode('xn--iñvalid.com'));\n   * // Prints an empty string\n   * ```\n   */\n  function domainToUnicode(domain: string): string;\n  /**\n   * This function ensures the correct decodings of percent-encoded characters as\n   * well as ensuring a cross-platform valid absolute path string.\n   *\n   * ```js\n   * import { fileURLToPath } from 'url';\n   *\n   * const __filename = fileURLToPath(import.meta.url);\n   *\n   * new URL('file:///C:/path/').pathname;      // Incorrect: /C:/path/\n   * fileURLToPath('file:///C:/path/');         // Correct:   C:\\path\\ (Windows)\n   *\n   * new URL('file://nas/foo.txt').pathname;    // Incorrect: /foo.txt\n   * fileURLToPath('file://nas/foo.txt');       // Correct:   \\\\nas\\foo.txt (Windows)\n   *\n   * new URL('file:///你好.txt').pathname;      // Incorrect: /%E4%BD%A0%E5%A5%BD.txt\n   * fileURLToPath('file:///你好.txt');         // Correct:   /你好.txt (POSIX)\n   *\n   * new URL('file:///hello world').pathname;   // Incorrect: /hello%20world\n   * fileURLToPath('file:///hello world');      // Correct:   /hello world (POSIX)\n   * ```\n   * @param url The file URL string or URL object to convert to a path.\n   * @return The fully-resolved platform-specific Node.js file path.\n   */\n  function fileURLToPath(url: string | URL): string;\n  /**\n   * This function ensures that `path` is resolved absolutely, and that the URL\n   * control characters are correctly encoded when converting into a File URL.\n   *\n   * ```js\n   * import { pathToFileURL } from 'url';\n   *\n   * new URL('/foo#1', 'file:');           // Incorrect: file:///foo#1\n   * pathToFileURL('/foo#1');              // Correct:   file:///foo%231 (POSIX)\n   *\n   * new URL('/some/path%.c', 'file:');    // Incorrect: file:///some/path%.c\n   * pathToFileURL('/some/path%.c');       // Correct:   file:///some/path%25.c (POSIX)\n   * ```\n   * @param path The path to convert to a File URL.\n   * @return The file URL object.\n   */\n  function pathToFileURL(path: string): URL;\n  /**\n   * This utility function converts a URL object into an ordinary options object as\n   * expected by the `http.request()` and `https.request()` APIs.\n   *\n   * ```js\n   * import { urlToHttpOptions } from 'url';\n   * const myURL = new URL('https://a:b@測試?abc#foo');\n   *\n   * console.log(urlToHttpOptions(myURL));\n   * /*\n   * {\n   *   protocol: 'https:',\n   *   hostname: 'xn--g6w251d',\n   *   hash: '#foo',\n   *   search: '?abc',\n   *   pathname: '/',\n   *   path: '/?abc',\n   *   href: 'https://a:b@xn--g6w251d/?abc#foo',\n   *   auth: 'a:b'\n   * }\n   *\n   * ```\n   * @param url The `WHATWG URL` object to convert to an options object.\n   * @return Options object\n   */\n  function urlToHttpOptions(url: URL): Object;\n  /**\n   * Browser-compatible `URL` class, implemented by following the WHATWG URL\n   * Standard. [Examples of parsed URLs](https://url.spec.whatwg.org/#example-url-parsing) may be found in the Standard itself.\n   * The `URL` class is also available on the global object.\n   *\n   * In accordance with browser conventions, all properties of `URL` objects\n   * are implemented as getters and setters on the class prototype, rather than as\n   * data properties on the object itself. Thus, unlike `legacy urlObject`s,\n   * using the `delete` keyword on any properties of `URL` objects (e.g. `delete myURL.protocol`, `delete myURL.pathname`, etc) has no effect but will still\n   * return `true`.\n   */\n  class URL {\n    /**\n     * Checks if an `input` relative to the `base` can be parsed to a `URL`.\n     *\n     * ```js\n     * const isValid = URL.canParse('/foo', 'https://example.org/'); // true\n     *\n     * const isNotValid = URL.canParse('/foo'); // false\n     * ```\n     * @param input The absolute or relative input URL to parse. If `input` is relative, then `base` is required. If `input` is absolute, the `base` is ignored. If `input` is not a string, it is\n     * `converted to a string` first.\n     * @param base The base URL to resolve against if the `input` is not absolute. If `base` is not a string, it is `converted to a string` first.\n     */\n    static canParse(input: string, base?: string): boolean;\n    /**\n     * Parses a string as a URL. If `base` is provided, it will be used as the base URL for the purpose of resolving non-absolute `input` URLs.\n     * Returns `null` if `input` is not a valid.\n     * @param input The absolute or relative input URL to parse. If `input` is relative, then `base` is required. If `input` is absolute, the `base` is ignored. If `input` is not a string, it is\n     * `converted to a string` first.\n     * @param base The base URL to resolve against if the `input` is not absolute. If `base` is not a string, it is `converted to a string` first.\n     */\n    static parse(input: string, base?: string): URL | null;\n    constructor(\n      input: string | { toString: () => string },\n      base?: string | URL\n    );\n    /**\n     * Gets and sets the fragment portion of the URL.\n     *\n     * ```js\n     * const myURL = new URL('https://example.org/foo#bar');\n     * console.log(myURL.hash);\n     * // Prints #bar\n     *\n     * myURL.hash = 'baz';\n     * console.log(myURL.href);\n     * // Prints https://example.org/foo#baz\n     * ```\n     *\n     * Invalid URL characters included in the value assigned to the `hash` property\n     * are `percent-encoded`. The selection of which characters to\n     * percent-encode may vary somewhat from what the {@link parse} and {@link format} methods would produce.\n     */\n    hash: string;\n    /**\n     * Gets and sets the host portion of the URL.\n     *\n     * ```js\n     * const myURL = new URL('https://example.org:81/foo');\n     * console.log(myURL.host);\n     * // Prints example.org:81\n     *\n     * myURL.host = 'example.com:82';\n     * console.log(myURL.href);\n     * // Prints https://example.com:82/foo\n     * ```\n     *\n     * Invalid host values assigned to the `host` property are ignored.\n     */\n    host: string;\n    /**\n     * Gets and sets the host name portion of the URL. The key difference between`url.host` and `url.hostname` is that `url.hostname` does _not_ include the\n     * port.\n     *\n     * ```js\n     * const myURL = new URL('https://example.org:81/foo');\n     * console.log(myURL.hostname);\n     * // Prints example.org\n     *\n     * // Setting the hostname does not change the port\n     * myURL.hostname = 'example.com';\n     * console.log(myURL.href);\n     * // Prints https://example.com:81/foo\n     *\n     * // Use myURL.host to change the hostname and port\n     * myURL.host = 'example.org:82';\n     * console.log(myURL.href);\n     * // Prints https://example.org:82/foo\n     * ```\n     *\n     * Invalid host name values assigned to the `hostname` property are ignored.\n     */\n    hostname: string;\n    /**\n     * Gets and sets the serialized URL.\n     *\n     * ```js\n     * const myURL = new URL('https://example.org/foo');\n     * console.log(myURL.href);\n     * // Prints https://example.org/foo\n     *\n     * myURL.href = 'https://example.com/bar';\n     * console.log(myURL.href);\n     * // Prints https://example.com/bar\n     * ```\n     *\n     * Getting the value of the `href` property is equivalent to calling {@link toString}.\n     *\n     * Setting the value of this property to a new value is equivalent to creating a\n     * new `URL` object using `new URL(value)`. Each of the `URL` object's properties will be modified.\n     *\n     * If the value assigned to the `href` property is not a valid URL, a `TypeError` will be thrown.\n     */\n    href: string;\n    /**\n     * Gets the read-only serialization of the URL's origin.\n     *\n     * ```js\n     * const myURL = new URL('https://example.org/foo/bar?baz');\n     * console.log(myURL.origin);\n     * // Prints https://example.org\n     * ```\n     *\n     * ```js\n     * const idnURL = new URL('https://測試');\n     * console.log(idnURL.origin);\n     * // Prints https://xn--g6w251d\n     *\n     * console.log(idnURL.hostname);\n     * // Prints xn--g6w251d\n     * ```\n     */\n    readonly origin: string;\n    /**\n     * Gets and sets the password portion of the URL.\n     *\n     * ```js\n     * const myURL = new URL('https://abc:xyz@example.com');\n     * console.log(myURL.password);\n     * // Prints xyz\n     *\n     * myURL.password = '123';\n     * console.log(myURL.href);\n     * // Prints https://abc:123@example.com/\n     * ```\n     *\n     * Invalid URL characters included in the value assigned to the `password` property\n     * are `percent-encoded`. The selection of which characters to\n     * percent-encode may vary somewhat from what the {@link parse} and {@link format} methods would produce.\n     */\n    password: string;\n    /**\n     * Gets and sets the path portion of the URL.\n     *\n     * ```js\n     * const myURL = new URL('https://example.org/abc/xyz?123');\n     * console.log(myURL.pathname);\n     * // Prints /abc/xyz\n     *\n     * myURL.pathname = '/abcdef';\n     * console.log(myURL.href);\n     * // Prints https://example.org/abcdef?123\n     * ```\n     *\n     * Invalid URL characters included in the value assigned to the `pathname` property are `percent-encoded`. The selection of which characters\n     * to percent-encode may vary somewhat from what the {@link parse} and {@link format} methods would produce.\n     */\n    pathname: string;\n    /**\n     * Gets and sets the port portion of the URL.\n     *\n     * The port value may be a number or a string containing a number in the range `0` to `65535` (inclusive). Setting the value to the default port of the `URL` objects given `protocol` will\n     * result in the `port` value becoming\n     * the empty string (`''`).\n     *\n     * The port value can be an empty string in which case the port depends on\n     * the protocol/scheme:\n     *\n     * <omitted>\n     *\n     * Upon assigning a value to the port, the value will first be converted to a\n     * string using `.toString()`.\n     *\n     * If that string is invalid but it begins with a number, the leading number is\n     * assigned to `port`.\n     * If the number lies outside the range denoted above, it is ignored.\n     *\n     * ```js\n     * const myURL = new URL('https://example.org:8888');\n     * console.log(myURL.port);\n     * // Prints 8888\n     *\n     * // Default ports are automatically transformed to the empty string\n     * // (HTTPS protocol's default port is 443)\n     * myURL.port = '443';\n     * console.log(myURL.port);\n     * // Prints the empty string\n     * console.log(myURL.href);\n     * // Prints https://example.org/\n     *\n     * myURL.port = 1234;\n     * console.log(myURL.port);\n     * // Prints 1234\n     * console.log(myURL.href);\n     * // Prints https://example.org:1234/\n     *\n     * // Completely invalid port strings are ignored\n     * myURL.port = 'abcd';\n     * console.log(myURL.port);\n     * // Prints 1234\n     *\n     * // Leading numbers are treated as a port number\n     * myURL.port = '5678abcd';\n     * console.log(myURL.port);\n     * // Prints 5678\n     *\n     * // Non-integers are truncated\n     * myURL.port = 1234.5678;\n     * console.log(myURL.port);\n     * // Prints 1234\n     *\n     * // Out-of-range numbers which are not represented in scientific notation\n     * // will be ignored.\n     * myURL.port = 1e10; // 10000000000, will be range-checked as described below\n     * console.log(myURL.port);\n     * // Prints 1234\n     * ```\n     *\n     * Numbers which contain a decimal point,\n     * such as floating-point numbers or numbers in scientific notation,\n     * are not an exception to this rule.\n     * Leading numbers up to the decimal point will be set as the URL's port,\n     * assuming they are valid:\n     *\n     * ```js\n     * myURL.port = 4.567e21;\n     * console.log(myURL.port);\n     * // Prints 4 (because it is the leading number in the string '4.567e21')\n     * ```\n     */\n    port: string;\n    /**\n     * Gets and sets the protocol portion of the URL.\n     *\n     * ```js\n     * const myURL = new URL('https://example.org');\n     * console.log(myURL.protocol);\n     * // Prints https:\n     *\n     * myURL.protocol = 'ftp';\n     * console.log(myURL.href);\n     * // Prints ftp://example.org/\n     * ```\n     *\n     * Invalid URL protocol values assigned to the `protocol` property are ignored.\n     */\n    protocol: string;\n    /**\n     * Gets and sets the serialized query portion of the URL.\n     *\n     * ```js\n     * const myURL = new URL('https://example.org/abc?123');\n     * console.log(myURL.search);\n     * // Prints ?123\n     *\n     * myURL.search = 'abc=xyz';\n     * console.log(myURL.href);\n     * // Prints https://example.org/abc?abc=xyz\n     * ```\n     *\n     * Any invalid URL characters appearing in the value assigned the `search` property will be `percent-encoded`. The selection of which\n     * characters to percent-encode may vary somewhat from what the {@link parse} and {@link format} methods would produce.\n     */\n    search: string;\n    /**\n     * Gets the `URLSearchParams` object representing the query parameters of the\n     * URL. This property is read-only but the `URLSearchParams` object it provides\n     * can be used to mutate the URL instance; to replace the entirety of query\n     * parameters of the URL, use the {@link search} setter. See `URLSearchParams` documentation for details.\n     *\n     * Use care when using `.searchParams` to modify the `URL` because,\n     * per the WHATWG specification, the `URLSearchParams` object uses\n     * different rules to determine which characters to percent-encode. For\n     * instance, the `URL` object will not percent encode the ASCII tilde (`~`)\n     * character, while `URLSearchParams` will always encode it:\n     *\n     * ```js\n     * const myURL = new URL('https://example.org/abc?foo=~bar');\n     *\n     * console.log(myURL.search);  // prints ?foo=~bar\n     *\n     * // Modify the URL via searchParams...\n     * myURL.searchParams.sort();\n     *\n     * console.log(myURL.search);  // prints ?foo=%7Ebar\n     * ```\n     */\n    readonly searchParams: URLSearchParams;\n    /**\n     * Gets and sets the username portion of the URL.\n     *\n     * ```js\n     * const myURL = new URL('https://abc:xyz@example.com');\n     * console.log(myURL.username);\n     * // Prints abc\n     *\n     * myURL.username = '123';\n     * console.log(myURL.href);\n     * // Prints https://123:xyz@example.com/\n     * ```\n     *\n     * Any invalid URL characters appearing in the value assigned the `username` property will be `percent-encoded`. The selection of which\n     * characters to percent-encode may vary somewhat from what the {@link parse} and {@link format} methods would produce.\n     */\n    username: string;\n    /**\n     * The `toString()` method on the `URL` object returns the serialized URL. The\n     * value returned is equivalent to that of {@link href} and {@link toJSON}.\n     */\n    toString(): string;\n    /**\n     * The `toJSON()` method on the `URL` object returns the serialized URL. The\n     * value returned is equivalent to that of {@link href} and {@link toString}.\n     *\n     * This method is automatically called when an `URL` object is serialized\n     * with [`JSON.stringify()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify).\n     *\n     * ```js\n     * const myURLs = [\n     *   new URL('https://www.example.com'),\n     *   new URL('https://test.example.org'),\n     * ];\n     * console.log(JSON.stringify(myURLs));\n     * // Prints [\"https://www.example.com/\",\"https://test.example.org/\"]\n     * ```\n     */\n    toJSON(): string;\n  }\n  /**\n   * The `URLSearchParams` API provides read and write access to the query of a `URL`. The `URLSearchParams` class can also be used standalone with one of the\n   * four following constructors.\n   * The `URLSearchParams` class is also available on the global object.\n   *\n   * The WHATWG `URLSearchParams` interface and the `querystring` module have\n   * similar purpose, but the purpose of the `querystring` module is more\n   * general, as it allows the customization of delimiter characters (`&#x26;` and `=`).\n   * On the other hand, this API is designed purely for URL query strings.\n   *\n   * ```js\n   * const myURL = new URL('https://example.org/?abc=123');\n   * console.log(myURL.searchParams.get('abc'));\n   * // Prints 123\n   *\n   * myURL.searchParams.append('abc', 'xyz');\n   * console.log(myURL.href);\n   * // Prints https://example.org/?abc=123&#x26;abc=xyz\n   *\n   * myURL.searchParams.delete('abc');\n   * myURL.searchParams.set('a', 'b');\n   * console.log(myURL.href);\n   * // Prints https://example.org/?a=b\n   *\n   * const newSearchParams = new URLSearchParams(myURL.searchParams);\n   * // The above is equivalent to\n   * // const newSearchParams = new URLSearchParams(myURL.search);\n   *\n   * newSearchParams.append('a', 'c');\n   * console.log(myURL.href);\n   * // Prints https://example.org/?a=b\n   * console.log(newSearchParams.toString());\n   * // Prints a=b&#x26;a=c\n   *\n   * // newSearchParams.toString() is implicitly called\n   * myURL.search = newSearchParams;\n   * console.log(myURL.href);\n   * // Prints https://example.org/?a=b&#x26;a=c\n   * newSearchParams.delete('a');\n   * console.log(myURL.href);\n   * // Prints https://example.org/?a=b&#x26;a=c\n   * ```\n   */\n  class URLSearchParams implements Iterable<[string, string]> {\n    constructor(\n      init?:\n        | URLSearchParams\n        | string\n        | Record<string, string | readonly string[]>\n        | Iterable<[string, string]>\n        | ReadonlyArray<[string, string]>\n    );\n    /**\n     * Append a new name-value pair to the query string.\n     */\n    append(name: string, value: string): void;\n    /**\n     * If `value` is provided, removes all name-value pairs\n     * where name is `name` and value is `value`.\n     *\n     * If `value` is not provided, removes all name-value pairs whose name is `name`.\n     */\n    delete(name: string, value?: string): void;\n    /**\n     * Returns an ES6 `Iterator` over each of the name-value pairs in the query.\n     * Each item of the iterator is a JavaScript `Array`. The first item of the `Array` is the `name`, the second item of the `Array` is the `value`.\n     *\n     * Alias for `urlSearchParams[@@iterator]()`.\n     */\n    entries(): IterableIterator<[string, string]>;\n    /**\n     * Iterates over each name-value pair in the query and invokes the given function.\n     *\n     * ```js\n     * const myURL = new URL('https://example.org/?a=b&#x26;c=d');\n     * myURL.searchParams.forEach((value, name, searchParams) => {\n     *   console.log(name, value, myURL.searchParams === searchParams);\n     * });\n     * // Prints:\n     * //   a b true\n     * //   c d true\n     * ```\n     * @param fn Invoked for each name-value pair in the query\n     * @param thisArg To be used as `this` value for when `fn` is called\n     */\n    forEach<TThis = this>(\n      fn: (\n        this: TThis,\n        value: string,\n        name: string,\n        searchParams: URLSearchParams\n      ) => void,\n      thisArg?: TThis\n    ): void;\n    /**\n     * Returns the value of the first name-value pair whose name is `name`. If there\n     * are no such pairs, `null` is returned.\n     * @return or `null` if there is no name-value pair with the given `name`.\n     */\n    get(name: string): string | null;\n    /**\n     * Checks if the `URLSearchParams` object contains key-value pair(s) based on `name` and an optional `value` argument.\n     *\n     * If `value` is provided, returns `true` when name-value pair with\n     * same `name` and `value` exists.\n     *\n     * If `value` is not provided, returns `true` if there is at least one name-value\n     * pair whose name is `name`.\n     */\n    has(name: string, value?: string): boolean;\n    /**\n     * Returns an ES6 `Iterator` over the names of each name-value pair.\n     *\n     * ```js\n     * const params = new URLSearchParams('foo=bar&#x26;foo=baz');\n     * for (const name of params.keys()) {\n     *   console.log(name);\n     * }\n     * // Prints:\n     * //   foo\n     * //   foo\n     * ```\n     */\n    keys(): IterableIterator<string>;\n    /**\n     * Sets the value in the `URLSearchParams` object associated with `name` to `value`. If there are any pre-existing name-value pairs whose names are `name`,\n     * set the first such pair's value to `value` and remove all others. If not,\n     * append the name-value pair to the query string.\n     *\n     * ```js\n     * const params = new URLSearchParams();\n     * params.append('foo', 'bar');\n     * params.append('foo', 'baz');\n     * params.append('abc', 'def');\n     * console.log(params.toString());\n     * // Prints foo=bar&#x26;foo=baz&#x26;abc=def\n     *\n     * params.set('foo', 'def');\n     * params.set('xyz', 'opq');\n     * console.log(params.toString());\n     * // Prints foo=def&#x26;abc=def&#x26;xyz=opq\n     * ```\n     */\n    set(name: string, value: string): void;\n    /**\n     * Sort all existing name-value pairs in-place by their names. Sorting is done\n     * with a [stable sorting algorithm](https://en.wikipedia.org/wiki/Sorting_algorithm#Stability), so relative order between name-value pairs\n     * with the same name is preserved.\n     *\n     * This method can be used, in particular, to increase cache hits.\n     *\n     * ```js\n     * const params = new URLSearchParams('query[]=abc&#x26;type=search&#x26;query[]=123');\n     * params.sort();\n     * console.log(params.toString());\n     * // Prints query%5B%5D=abc&#x26;query%5B%5D=123&#x26;type=search\n     * ```\n     */\n    sort(): void;\n    /**\n     * Returns the search parameters serialized as a string, with characters\n     * percent-encoded where necessary.\n     */\n    toString(): string;\n    /**\n     * Returns an ES6 `Iterator` over the values of each name-value pair.\n     */\n    values(): IterableIterator<string>;\n    [Symbol.iterator](): IterableIterator<[string, string]>;\n  }\n  import { URL as _URL, URLSearchParams as _URLSearchParams } from \"url\";\n  global {\n    interface URLSearchParams extends _URLSearchParams {}\n    interface URL extends _URL {}\n    interface Global {\n      URL: typeof _URL;\n      URLSearchParams: typeof _URLSearchParams;\n    }\n    /**\n     * `URL` class is a global reference for `require('url').URL`\n     */\n    var URL: typeof globalThis extends {\n      onmessage: any;\n      URL: infer T;\n    }\n      ? T\n      : typeof _URL;\n    /**\n     * `URLSearchParams` class is a global reference for `require('url').URLSearchParams`\n     */\n    var URLSearchParams: typeof globalThis extends {\n      onmessage: any;\n      URLSearchParams: infer T;\n    }\n      ? T\n      : typeof _URLSearchParams;\n  }\n}\n"
  },
  {
    "path": "types/util.d.ts",
    "content": "/**\n * The `util` module supports the needs of LLRT internal APIs. Many of the\n * utilities are useful for application and module developers as well. To access\n * it:\n *\n * ```js\n * import util from 'util';\n * ```\n * @see [source](https://github.com/nodejs/node/blob/v22.x/lib/util.js)\n */\ndeclare module \"util\" {\n  /**\n   * The `util.format()` method returns a formatted string using the first argument\n   * as a `printf`-like format string which can contain zero or more format\n   * specifiers. Each specifier is replaced with the converted value from the\n   * corresponding argument. Supported specifiers are:\n   *\n   * If a specifier does not have a corresponding argument, it is not replaced:\n   *\n   * ```js\n   * util.format('%s:%s', 'foo');\n   * // Returns: 'foo:%s'\n   * ```\n   *\n   * Values that are not part of the format string are formatted using `util.inspect()` if their type is not `string`.\n   *\n   * If there are more arguments passed to the `util.format()` method than the\n   * number of specifiers, the extra arguments are concatenated to the returned\n   * string, separated by spaces:\n   *\n   * ```js\n   * util.format('%s:%s', 'foo', 'bar', 'baz');\n   * // Returns: 'foo:bar baz'\n   * ```\n   *\n   * If the first argument does not contain a valid format specifier, `util.format()` returns a string that is the concatenation of all arguments separated by spaces:\n   *\n   * ```js\n   * util.format(1, 2, 3);\n   * // Returns: '1 2 3'\n   * ```\n   *\n   * If only one argument is passed to `util.format()`, it is returned as it is\n   * without any formatting:\n   *\n   * ```js\n   * util.format('%% %s');\n   * // Returns: '%% %s'\n   * ```\n   *\n   * `util.format()` is a synchronous method that is intended as a debugging tool.\n   * Some input values can have a significant performance overhead that can block the\n   * event loop. Use this function with care and never in a hot code path.\n   * @param format A `printf`-like format string.\n   */\n  export function format(format?: any, ...param: any[]): string;\n  /**\n   * Usage of `util.inherits()` is discouraged. Please use the ES6 `class` and `extends` keywords to get language level inheritance support. Also note\n   * that the two styles are [semantically incompatible](https://github.com/nodejs/node/issues/4179).\n   *\n   * Inherit the prototype methods from one [constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor) into another. The\n   * prototype of `constructor` will be set to a new object created from `superConstructor`.\n   *\n   * This mainly adds some input validation on top of`Object.setPrototypeOf(constructor.prototype, superConstructor.prototype)`.\n   * As an additional convenience, `superConstructor` will be accessible\n   * through the `constructor.super_` property.\n   *\n   * ```js\n   * import util from 'util';\n   * import EventEmitter from 'events';\n   *\n   * function MyStream() {\n   *   EventEmitter.call(this);\n   * }\n   *\n   * util.inherits(MyStream, EventEmitter);\n   *\n   * MyStream.prototype.write = function(data) {\n   *   this.emit('data', data);\n   * };\n   *\n   * const stream = new MyStream();\n   *\n   * console.log(stream instanceof EventEmitter); // true\n   * console.log(MyStream.super_ === EventEmitter); // true\n   *\n   * stream.on('data', (data) => {\n   *   console.log(`Received data: \"${data}\"`);\n   * });\n   * stream.write('It works!'); // Received data: \"It works!\"\n   * ```\n   *\n   * ES6 example using `class` and `extends`:\n   *\n   * ```js\n   * import EventEmitter from 'events';\n   *\n   * class MyStream extends EventEmitter {\n   *   write(data) {\n   *     this.emit('data', data);\n   *   }\n   * }\n   *\n   * const stream = new MyStream();\n   *\n   * stream.on('data', (data) => {\n   *   console.log(`Received data: \"${data}\"`);\n   * });\n   * stream.write('With ES6');\n   * ```\n   * @legacy Use ES2015 class syntax and `extends` keyword instead.\n   */\n  export function inherits(\n    constructor: unknown,\n    superConstructor: unknown\n  ): void;\n  /**\n   * An implementation of the [WHATWG Encoding Standard](https://encoding.spec.whatwg.org/) `TextDecoder` API.\n   *\n   * ```js\n   * const decoder = new TextDecoder();\n   * const u8arr = new Uint8Array([72, 101, 108, 108, 111]);\n   * console.log(decoder.decode(u8arr)); // Hello\n   * ```\n   */\n  export class TextDecoder {\n    /**\n     * The encoding supported by the `TextDecoder` instance.\n     */\n    readonly encoding: string;\n    /**\n     * The value will be `true` if decoding errors result in a `TypeError` being\n     * thrown.\n     */\n    readonly fatal: boolean;\n    /**\n     * The value will be `true` if the decoding result will include the byte order\n     * mark.\n     */\n    readonly ignoreBOM: boolean;\n    constructor(\n      encoding?: string,\n      options?: {\n        fatal?: boolean | undefined;\n        ignoreBOM?: boolean | undefined;\n      }\n    );\n    /**\n     * Decodes the `input` and returns a string. If `options.stream` is `true`, any\n     * incomplete byte sequences occurring at the end of the `input` are buffered\n     * internally and emitted after the next call to `textDecoder.decode()`.\n     *\n     * If `textDecoder.fatal` is `true`, decoding errors that occur will result in a `TypeError` being thrown.\n     * @param input An `ArrayBuffer`, `DataView`, or `TypedArray` instance containing the encoded data.\n     */\n    decode(\n      input?: QuickJS.ArrayBufferView | ArrayBuffer | null,\n      options?: {\n        stream?: boolean | undefined;\n      }\n    ): string;\n  }\n  export interface EncodeIntoResult {\n    /**\n     * The read Unicode code units of input.\n     */\n    read: number;\n    /**\n     * The written UTF-8 bytes of output.\n     */\n    written: number;\n  }\n  //// TextEncoder/Decoder\n  /**\n   * An implementation of the [WHATWG Encoding Standard](https://encoding.spec.whatwg.org/) `TextEncoder` API. All\n   * instances of `TextEncoder` only support UTF-8 encoding.\n   *\n   * ```js\n   * const encoder = new TextEncoder();\n   * const uint8array = encoder.encode('this is some data');\n   * ```\n   *\n   * The `TextEncoder` class is also available on the global object.\n   */\n  export class TextEncoder {\n    /**\n     * The encoding supported by the `TextEncoder` instance. Always set to `'utf-8'`.\n     */\n    readonly encoding: string;\n    /**\n     * UTF-8 encodes the `input` string and returns a `Uint8Array` containing the\n     * encoded bytes.\n     * @param [input='an empty string'] The text to encode.\n     */\n    encode(input?: string): Uint8Array;\n    /**\n     * UTF-8 encodes the `src` string to the `dest` Uint8Array and returns an object\n     * containing the read Unicode code units and written UTF-8 bytes.\n     *\n     * ```js\n     * const encoder = new TextEncoder();\n     * const src = 'this is some data';\n     * const dest = new Uint8Array(10);\n     * const { read, written } = encoder.encodeInto(src, dest);\n     * ```\n     * @param src The text to encode.\n     * @param dest The array to hold the encode result.\n     */\n    encodeInto(src: string, dest: Uint8Array): EncodeIntoResult;\n  }\n  import {\n    TextDecoder as _TextDecoder,\n    TextEncoder as _TextEncoder,\n  } from \"util\";\n  global {\n    /**\n     * `TextDecoder` class is a global reference for `import { TextDecoder } from 'util'`\n     * https://nodejs.org/api/globals.html#textdecoder\n     */\n    var TextDecoder: typeof globalThis extends {\n      onmessage: any;\n      TextDecoder: infer TextDecoder;\n    }\n      ? TextDecoder\n      : typeof _TextDecoder;\n    /**\n     * `TextEncoder` class is a global reference for `import { TextEncoder } from 'util'`\n     * https://nodejs.org/api/globals.html#textencoder\n     */\n    var TextEncoder: typeof globalThis extends {\n      onmessage: any;\n      TextEncoder: infer TextEncoder;\n    }\n      ? TextEncoder\n      : typeof _TextEncoder;\n  }\n}\ndeclare module \"util\" {\n  export * from \"util\";\n}\n"
  },
  {
    "path": "types/zlib.d.ts",
    "content": "/**\n * The `zlib` module provides compression functionality implemented using\n * Gzip, Deflate/Inflate, Brotli and Zstandard.\n *\n * To access it:\n *\n * ```js\n * import * as zlib from 'zlib';\n * ```\n *\n * It is possible to compress or decompress data in a single step:\n *\n * ```js\n * mport * as zlib from 'zlib';\n *\n * const input = '.................................';\n * zlib.deflate(input, (err, buffer) => {\n *   if (err) {\n *     console.error('An error occurred:', err);\n *     process.exitCode = 1;\n *   }\n *   console.log(buffer.toString('base64'));\n * });\n *\n * const buffer = Buffer.from('CwWASGVsbG8gV29ybGQD', 'base64');\n * zlib.brotliDecompress(buffer, (err, buffer) => {\n *   if (err) {\n *     console.error('An error occurred:', err);\n *     process.exitCode = 1;\n *   }\n *   console.log(buffer.toString());\n * });\n *\n * ```\n */\ndeclare module \"zlib\" {\n  import { Buffer } from \"buffer\";\n\n  interface ZlibOptions {\n    level?: number | undefined; // compression only\n  }\n  interface ZstdOptions {\n    level?: number | undefined; // compression only\n  }\n  type InputType = string | ArrayBuffer | QuickJS.ArrayBufferView;\n  type CompressCallback = (error: Error | null, result: Buffer) => void;\n\n  /**\n   * Compress a chunk of data with `Deflate`.\n   */\n  function deflate(buf: InputType, callback: CompressCallback): void;\n  function deflate(\n    buf: InputType,\n    options: ZlibOptions,\n    callback: CompressCallback\n  ): void;\n  /**\n   * Compress a chunk of data with `Deflate`.\n   */\n  function deflateSync(buf: InputType, options?: ZlibOptions): Buffer;\n\n  /**\n   * Compress a chunk of data with `DeflateRaw`.\n   */\n  function deflateRaw(buf: InputType, callback: CompressCallback): void;\n  function deflateRaw(\n    buf: InputType,\n    options: ZlibOptions,\n    callback: CompressCallback\n  ): void;\n  /**\n   * Compress a chunk of data with `DeflateRaw`.\n   */\n  function deflateRawSync(buf: InputType, options?: ZlibOptions): Buffer;\n\n  /**\n   * Compress a chunk of data with `Gzip`.\n   */\n  function gzip(buf: InputType, callback: CompressCallback): void;\n  function gzip(\n    buf: InputType,\n    options: ZlibOptions,\n    callback: CompressCallback\n  ): void;\n  /**\n   * Compress a chunk of data with `Gzip`.\n   */\n  function gzipSync(buf: InputType, options?: ZlibOptions): Buffer;\n\n  /**\n   * Decompress a chunk of data with `Inflate`.\n   */\n  function inflate(buf: InputType, callback: CompressCallback): void;\n  function inflate(\n    buf: InputType,\n    options: ZlibOptions,\n    callback: CompressCallback\n  ): void;\n  /**\n   * Decompress a chunk of data with `Inflate`.\n   */\n  function inflateSync(buf: InputType, options?: ZlibOptions): Buffer;\n\n  /**\n   * Decompress a chunk of data with `InflateRaw`.\n   */\n  function inflateRaw(buf: InputType, callback: CompressCallback): void;\n  function inflateRaw(\n    buf: InputType,\n    options: ZlibOptions,\n    callback: CompressCallback\n  ): void;\n  /**\n   * Decompress a chunk of data with `InflateRaw`.\n   */\n  function inflateRawSync(buf: InputType, options?: ZlibOptions): Buffer;\n\n  /**\n   * Decompress a chunk of data with `Gunzip`.\n   */\n  function gunzip(buf: InputType, callback: CompressCallback): void;\n  function gunzip(\n    buf: InputType,\n    options: ZlibOptions,\n    callback: CompressCallback\n  ): void;\n  /**\n   * Decompress a chunk of data with `Gunzip`.\n   */\n  function gunzipSync(buf: InputType, options?: ZlibOptions): Buffer;\n\n  /**\n   * Compress a chunk of data with `BrotliCompress`.\n   */\n  function brotliCompress(buf: InputType, callback: CompressCallback): void;\n  /**\n   * Compress a chunk of data with `BrotliCompress`.\n   */\n  function brotliCompressSync(buf: InputType): Buffer;\n\n  /**\n   * Decompress a chunk of data with `BrotliDecompress`.\n   */\n  function brotliDecompress(buf: InputType, callback: CompressCallback): void;\n  /**\n   * Decompress a chunk of data with `BrotliDecompress`.\n   */\n  function brotliDecompressSync(buf: InputType): Buffer;\n\n  /**\n   * Compress a chunk of data with `ZstdCompress`.\n   */\n  function zstdCompress(buf: InputType, callback: CompressCallback): void;\n  function zstdCompress(\n    buf: InputType,\n    options: ZstdOptions,\n    callback: CompressCallback\n  ): void;\n  /**\n   * Compress a chunk of data with `ZstdCompress`.\n   */\n  function zstdCompressSync(buf: InputType, options?: ZstdOptions): Buffer;\n\n  /**\n   * Decompress a chunk of data with `ZstdDecompress`.\n   */\n  function zstdDecompress(buf: InputType, callback: CompressCallback): void;\n  function zstdDecompress(\n    buf: InputType,\n    options: ZstdOptions,\n    callback: CompressCallback\n  ): void;\n  /**\n   * Decompress a chunk of data with `ZstdDecompress`.\n   */\n  function zstdDecompressSync(buf: InputType, options?: ZstdOptions): Buffer;\n}\n"
  },
  {
    "path": "vitest.config.mjs",
    "content": "import { defineConfig } from \"vitest/config\";\n\nexport default defineConfig({\n  test: {\n    /* for example, use global to avoid globals imports (describe, test, expect): */\n    globals: true,\n    // mockReset: true\n  },\n});\n"
  },
  {
    "path": "wpt_errors.txt",
    "content": "🧪/wpt/FileAPI.blob.test.js \nFileAPI/blob > should pass Blob-newobject.any.js tests\nError: [Blob.stream() returns [NewObject]] not a function\n\nFileAPI/blob > should pass Blob-stream.any.js tests\nError: [Blob.stream()] promise_test: Unhandled rejection with value: object \"TypeError: not a function\"\n\n\n🧪/wpt/WebCryptoAPI.digest.test.js \nWebCryptoAPI/digest > should pass cshake.tentative.https.any.js tests\nError: [cSHAKE128 with 0 bit output and empty source data] promise_test: Unhandled rejection with value: object \"Error: 'cSHAKE128' not available\"\n\nWebCryptoAPI/digest > should pass digest.https.any.js tests\nError: [SHA-1 with short source data and altered buffer after call] assert_true: digest() yielded expected result for sha-1:short expected true got false\n\nWebCryptoAPI/digest > should pass sha3.tentative.https.any.js tests\nError: [SHA3-256 with empty source data] promise_test: Unhandled rejection with value: object \"Error: 'SHA3-256' not available\"\n\n\n🧪/wpt/WebCryptoAPI.test.js \nWebCryptoAPI > should pass crypto_key_cached_slots.https.any.js tests\nError: [CryptoKey.algorithm getter returns cached object] assert_true: expected true got false\n\nWebCryptoAPI > should pass getPublicKey.tentative.https.any.js tests\nError: [getPublicKey works for ECDH] promise_test: Unhandled rejection with value: object \"TypeError: not a function\"\n\nWebCryptoAPI > should pass historical.any.js tests\nError: [Non-secure context window does not have access to crypto.subtle] assert_equals: expected (undefined) undefined but got (object) object \"[object SubtleCrypto]\"\n\nWebCryptoAPI > should pass supports.tentative.https.any.js tests\nError: [SubtleCrypto.supports method exists] assert_true: SubtleCrypto.supports should be a function expected true got false\n\n\n🧪/wpt/console.test.js \nconsole > should pass console-is-a-namespace.any.js tests\nError: [console has the right property descriptors] assert_equals: must not be enumerable expected false but got true\n\nconsole > should pass console-label-conversion.any.js tests\nError: [console.count()'s label gets converted to string via label.toString() when label is an object] not a function\n\nconsole > should pass console-namespace-object-class-string.any.js tests\nError: [@@toStringTag exists on the namespace object with the appropriate descriptor] assert_own_property: expected property symbol \"Symbol(Symbol.toStringTag)\" missing\n\n----- LAST STDOUT: -----\n[ 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'... 9999900 more items ]\nUint8Array [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0... 9999900 more items ]\n\n\n🧪/wpt/encoding.test.js \nencoding > should pass api-surrogates-utf8.any.js tests\nError: [Invalid surrogates encoded into UTF-8: Surrogate half (low)] Conversion from string failed: invalid utf-8 sequence of 1 bytes from index 0\n\nencoding > should pass encodeInto.any.js tests\nError: [encodeInto() into ArrayBuffer with U+d834AU+df06A¥Hi and destination length 10, offset 0, filler 0] Conversion from string failed: invalid utf-8 sequence of 1 bytes from index 0\n\nencoding > should pass textdecoder-arguments.any.js tests\nError: [TextDecoder decode() with explicit undefined] assert_equals: Undefined as first arg should flush the stream expected \"\\ufffd\" but got \"\"\n\nencoding > should pass textdecoder-copy.any.js tests\nError: [Modify buffer after passing it in (ArrayBuffer)] assert_equals: expected \"\" but got \"\\ufffd\"\n\nencoding > should pass textdecoder-eof.any.js tests\nError: [TextDecoder end-of-queue handling using stream: true] Error calling function with 0 argument(s) while 1 where expected\n\nencoding > should pass textdecoder-fatal-single-byte.any.js tests\nError: [Not throw: IBM866 has a pointer 0] The \"IBM866\" encoding is not supported\n\nencoding > should pass textdecoder-fatal-streaming.any.js tests\nError: [Fatal flag, non-streaming cases] assert_equals: Unterminated UTF-8 sequence should emit replacement character if fatal flag is unset expected \"\\ufffd\" but got \"\"\n\nencoding > should pass textdecoder-fatal.any.js tests\nError: [Error seen with fatal does not prevent future decodes] assert_throws_js: decode() should throw on incomplete sequence function \"() => decoder.decode(new DataView(bytes.buffer, 0, 2))\" did not throw\n\nencoding > should pass textdecoder-streaming.any.js tests\nError: [Streaming decode: utf-8, 1 byte window (ArrayBuffer)] Error calling function with 0 argument(s) while 1 where expected\n\nencoding > should pass textencoder-utf16-surrogates.any.js tests\nError: [USVString handling: lone surrogate lead] Conversion from string failed: invalid utf-8 sequence of 1 bytes from index 0\n\n\n🧪/wpt/fetch.api.abort.test.js \nfetch/api/abort > should pass request.any.js tests\nError: [Calling arrayBuffer() on an aborted consumed empty request] promise_test: Unhandled rejection with value: object \"TypeError: not a function\"\n\n\n🧪/wpt/fetch.api.basic.test.js \nfetch/api/basic > should pass conditional-get.any.js tests\nError: [Testing conditional GET with ETags] token is not defined\n\nfetch/api/basic > should pass error-after-response.any.js tests\nError: [Response reader read() promise should reject after a network error happening after resolving fetch promise] promise_test: Unhandled rejection with value: object \"TypeError: cannot read property 'getReader' of undefined\"\n\nfetch/api/basic > should pass gc.any.js tests\nError: [GC/CC should not abruptly close the stream while being consumed by Response] assert_equals: The buffer should be 5-byte long expected 5 but got 15\n\nfetch/api/basic > should pass header-value-combining.any.js tests\nError: [response.headers.get('content-length') expects 0] assert_equals: expected \"0\" but got \"42\"\n\nfetch/api/basic > should pass header-value-null-byte.any.js tests\nError: [Ensure fetch() rejects null bytes in headers] assert_unreached: Should have rejected: undefined Reached unreachable code\n\nfetch/api/basic > should pass http-response-code.any.js tests\nError: [Fetch on 425 response should not be retried for non TLS early data.] promise_test: Unhandled rejection with value: object \"ReferenceError: token is not defined\"\n\nfetch/api/basic > should pass integrity.sub.any.js tests\nError: [Empty string integrity] promise_test: Unhandled rejection with value: object \"TypeError: Invalid scheme\"\n\nfetch/api/basic > should pass keepalive.any.js tests\nError: [[keepalive] simple GET request on 'load' [no payload]; setting up] promise_test: Unhandled rejection with value: object \"ReferenceError: token is not defined\"\n\nfetch/api/basic > should pass mode-no-cors.sub.any.js tests\nError: [Fetch http://{{host}}:{{ports[http][0]}}/fetch/api/resources/top.txt with no-cors mode] promise_test: Unhandled rejection with value: object \"TypeError: Invalid URL :http://{{host}}:{{ports[http][0]}}/fetch/api/resources/top.txt?pipe=header(x-is-filtered,value)\"\n\nfetch/api/basic > should pass mode-same-origin.any.js tests\nError: [Fetch http://{{host}}:{{ports[http][0]}}/fetch/api/resources/top.txt with same-origin mode] promise_test: Unhandled rejection with value: object \"TypeError: Invalid URL :http://{{host}}:{{ports[http][0]}}/fetch/api/resources/top.txt\"\n\nfetch/api/basic > should pass referrer.any.js tests\nError: [origin-when-cross-origin policy on a same-origin URL] assert_equals: Request's referrer is correct expected (string) \"[object Object]\" but got (object) null\n\nfetch/api/basic > should pass request-head.any.js tests\nError: [Fetch with HEAD with body] promise_rejects_js: function \"function() {\n            throw e;\n          }\" threw object \"Error: client error (UserAbsoluteUriRequired)\" (\"Error\") expected instance of function \"function TypeError() {\n    [native code]\n}\" (\"TypeError\")\n\nfetch/api/basic > should pass request-headers-case.any.js tests\nError: [Multiple headers with the same name, different case (THIS-is-A-test first)] promise_test: Unhandled rejection with value: object \"Error: client error (UserAbsoluteUriRequired)\"\n\nfetch/api/basic > should pass request-headers-nonascii.any.js tests\nError: [Non-ascii bytes in request headers] assert_equals: Accept Header expected (string) \"before-æøå-after\" but got (object) null\n\nfetch/api/basic > should pass request-headers.any.js tests\nError: [Fetch with PUT without body] assert_equals: Request should have header origin: http://web-platform.test expected (string) \"http://web-platform.test\" but got (object) null\n\nfetch/api/basic > should pass request-upload.any.js tests\nError: [Fetch with POST with DataView body] assert_equals: expected \"\\0\\0\\0\\0\" but got \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n\nfetch/api/basic > should pass response-null-body.any.js tests\nError: [Response.body is null for responses with status=204 (method=GET)] assert_equals: the body should be null expected (object) null but got (undefined) undefined\n\nfetch/api/basic > should pass response-url.sub.any.js tests\nError: [Testing response url getter with http://{{host}}:{{ports[http][0]}}/ada] promise_test: Unhandled rejection with value: object \"TypeError: Invalid URL :http://{{host}}:{{ports[http][0]}}/ada\"\n\nfetch/api/basic > should pass status.h2.any.js tests\nError: [statusText over H2 for status 200 should be the empty string] promise_test: Unhandled rejection with value: object \"Error: client error (UserAbsoluteUriRequired)\"\n\nfetch/api/basic > should pass stream-response.any.js tests\nError: [Stream response's body when content-type is present] assert_unreached: Body does not exist in response Reached unreachable code\n\nfetch/api/basic > should pass text-utf8.any.js tests\nError: [UTF-8 with BOM with fetched data (UTF-8 charset)] assert_equals: Fetched Response.text() should decode data as UTF-8 expected \"三村かな子\" but got \"{\\\"error\\\": {\\\"code\\\": 404, \\\"message\\\": \\\"404\\\"}}\"\n\n\n🧪/wpt/fetch.api.headers.test.js \nfetch/api/headers > should pass header-setcookie.any.js tests\nError: [Headers iterator is correctly updated with set-cookie changes] assert_array_equals: expected property 0 to be \"set-cookie\" but got \"x-header\" (expected array [\"set-cookie\", \"a=b\"] got [\"x-header\", \"test\"])\n\nfetch/api/headers > should pass headers-basic.any.js tests\nError: [Check keys method] assert_equals: expected object \"[object Iterator]\" but got object \"[object Object]\"\n\nfetch/api/headers > should pass headers-record.any.js tests\nError: [Basic operation with one property] assert_array_equals: lengths differ, expected array [\"get\", object \"[object Object]\", symbol \"Symbol(Symbol.iterator)\", object \"[object Object]\"] length 4, got [\"has\", object \"[object Object]\", symbol \"Symbol(Symbol.iterator)\"] length 3\n\n\n🧪/wpt/fetch.api.request.test.js \nfetch/api/request > should pass request-consume-empty.any.js tests\nError: [Consume request's body as formData with correct multipart type (error case)] assert_unreached: Should have rejected: undefined Reached unreachable code\n\nfetch/api/request > should pass request-consume.any.js tests\nError: [Consume DataView request's body as text] assert_equals: Retrieve and verify request's body expected \"\\\"123456\\\"\" but got \"\\0\\\"123456\\\"\\0\"\n\nfetch/api/request > should pass request-disturbed.any.js tests\nError: [Request's body: initial state] assert_true: non-null body type expected true got false\n\nfetch/api/request > should pass request-error.any.js tests\nError: [RequestInit's window is not null] assert_throws_js: Expect TypeError exception function \"() => new Request(...args)\" did not throw\n\nfetch/api/request > should pass request-headers.any.js tests\nError: [Adding invalid request header \"Accept-Charset: KO\"] assert_equals: expected (object) null but got (string) \"KO\"\n\nfetch/api/request > should pass request-init-002.any.js tests\nError: [Initialize Request's body with \"hi!\", text/plain;charset=UTF-8] assert_true: Content-Type header should be \"text/plain;charset=UTF-8\", not \"null\" expected true got null\n\nfetch/api/request > should pass request-init-priority.any.js tests\nError: [new Request() throws a TypeError if any of RequestInit's members' values are invalid] assert_throws_js: a new Request() must throw a TypeError if RequestInit's priority is an invalid value function \"() => {\n    new Request(\"\", {priority: 'invalid'});\n  }\" did not throw\n\nfetch/api/request > should pass request-init-stream.any.js tests\nError: [Constructing a Request with a stream on which getReader() is called] assert_throws_js: function \"() => new Request(\"...\", { method, body, duplex })\" did not throw\n\nfetch/api/request > should pass request-keepalive.any.js tests\nError: [keepalive flag with stream body] assert_throws_js: function \"() => {new Request('/', init)}\" did not throw\n\nfetch/api/request > should pass request-structure.any.js tests\nError: [Check destination attribute] assert_true: request has destination attribute expected true got false\n\n\n🧪/wpt/fetch.api.response.test.js \nfetch/api/response > should pass json.any.js tests\nError: [Ensure UTF-16 results in an error] promise_test: Unhandled rejection with value: object \"Error: client error (UserAbsoluteUriRequired)\"\n\nfetch/api/response > should pass response-cancel-stream.any.js tests\nError: [Cancelling a starting blob Response stream] cannot read property 'cancel' of undefined\n\nfetch/api/response > should pass response-consume-empty.any.js tests\nError: [Consume response's body as formData with correct multipart type (error case)] assert_unreached: Should have rejected: undefined Reached unreachable code\n\nfetch/api/response > should pass response-consume-stream.any.js tests\nError: [Read empty text response's body as readableStream] cannot read property 'getReader' of undefined\n\nfetch/api/response > should pass response-error-from-stream.any.js tests\nError: [ReadableStream start() Error propagates to Response.arrayBuffer() Promise] assert_unreached: Should have rejected: CustomTestError should propagate Reached unreachable code\n\nfetch/api/response > should pass response-error.any.js tests\nError: [Throws RangeError when responseInit's status is 0] assert_throws_js: Expect RangeError exception when status is 0 function \"function() { new Response(\"\", { \"status\" : status }); }\" did not throw\n\nfetch/api/response > should pass response-from-stream.any.js tests\nError: [Constructing a Response with a stream on which getReader() is called] assert_throws_js: function \"() => new Response(stream)\" did not throw\n\nfetch/api/response > should pass response-headers-guard.any.js tests\nError: [Ensure response headers are immutable] promise_test: Unhandled rejection with value: object \"TypeError: cannot read property 'get' of undefined\"\n\nfetch/api/response > should pass response-init-001.any.js tests\nError: [Check default value for type attribute] assert_equals: Expect default response.type is default expected \"default\" but got \"basic\"\n\nfetch/api/response > should pass response-init-002.any.js tests\nError: [Read Response's body as readableStream] cannot read property 'getReader' of undefined\n\nfetch/api/response > should pass response-static-error.any.js tests\nError: [Check response returned by static method error()] assert_equals: Network error response's body is null expected (object) null but got (undefined) undefined\n\nfetch/api/response > should pass response-static-json.any.js tests\nError: [Check response returned by static json() with init undefined] promise_test: Unhandled rejection with value: object \"TypeError: Error converting from js 'undefined' into type 'object'\"\n\nfetch/api/response > should pass response-static-redirect.any.js tests\nError: [Check default redirect response] assert_equals: expected \"default\" but got \"basic\"\n\nfetch/api/response > should pass response-stream-bad-chunk.any.js tests\nError: [ReadableStream with non-Uint8Array chunk passed to Response.arrayBuffer() causes TypeError] assert_unreached: Should have rejected: TypeError should propagate Reached unreachable code\n\nfetch/api/response > should pass response-stream-disturbed-1.any.js tests\nError: [Getting blob after getting the Response body - not disturbed, not locked (body source: fetch)] promise_test: Unhandled rejection with value: object \"ReferenceError: responseFromBodySource is not defined\"\n\nfetch/api/response > should pass response-stream-disturbed-2.any.js tests\nError: [Getting blob after getting a locked Response body (body source: fetch)] promise_test: Unhandled rejection with value: object \"ReferenceError: responseFromBodySource is not defined\"\n\nfetch/api/response > should pass response-stream-disturbed-3.any.js tests\nError: [Getting blob after reading the Response body (body source: fetch)] promise_test: Unhandled rejection with value: object \"ReferenceError: responseFromBodySource is not defined\"\n\nfetch/api/response > should pass response-stream-disturbed-4.any.js tests\nError: [Getting blob after cancelling the Response body (body source: fetch)] promise_test: Unhandled rejection with value: object \"ReferenceError: responseFromBodySource is not defined\"\n\nfetch/api/response > should pass response-stream-disturbed-5.any.js tests\nError: [Getting a body reader after consuming as blob (body source: fetch)] promise_test: Unhandled rejection with value: object \"ReferenceError: responseFromBodySource is not defined\"\n\nfetch/api/response > should pass response-stream-disturbed-6.any.js tests\nError: [A non-closed stream on which read() has been called] assert_true: After calling stream.read() expected true got false\n\nfetch/api/response > should pass response-stream-disturbed-by-pipe.any.js tests\nError: [using pipeTo on Response body should disturb it synchronously] cannot read property 'pipeTo' of undefined\n\nfetch/api/response > should pass response-stream-with-broken-then.any.js tests\nError: [Attempt to inject {done: false, value: bye} via Object.prototype.then.] assert_equals: The value should be \"hello\". expected \"hello\" but got \"[object Object]\"\n\n\n🧪/wpt/streams.piping.test.js \nstreams/piping > should pass abort.any.js tests\nTypeError: Error converting from js 'object' into type 'AbortSignal'\n    at toString (native)\n    at concat (native)\n    at anonymous (<input>:29:16)\n    at runTestDynamic (/Users/shinya/Workspaces/llrt/bundle/js/__tests__/wpt/streams.piping.test.js:8657:29)\n    at <anonymous> (/Users/shinya/Workspaces/llrt/bundle/js/__tests__/wpt/streams.piping.test.js:8697:24)\n    at <anonymous> (llrt:test/worker:6815:28)\n    at Promise (native)\n    at executeAsyncOrCallbackFn (llrt:test/worker:6806:17)\n    at runTests (llrt:test/worker:6879:45)\n\nstreams/piping > should pass pipe-through.any.js tests\nTypeError: Error converting from js 'object' into type 'AbortSignal'\n    at toString (native)\n    at concat (native)\n    at anonymous (<input>:182:3)\n    at runTestDynamic (/Users/shinya/Workspaces/llrt/bundle/js/__tests__/wpt/streams.piping.test.js:8657:29)\n    at <anonymous> (/Users/shinya/Workspaces/llrt/bundle/js/__tests__/wpt/streams.piping.test.js:8697:24)\n    at <anonymous> (llrt:test/worker:6815:28)\n    at Promise (native)\n    at executeAsyncOrCallbackFn (llrt:test/worker:6806:17)\n    at runTests (llrt:test/worker:6879:45)\n\n\nError: Test did not exit within 1s. It does not properly clean up created resources (servers, timeouts etc)\n    at <anonymous> (llrt:test/index:448:27)\n\n\n🧪/wpt/streams.readable-byte-streams.test.js \nstreams/readable-byte-streams > should pass patched-global.any.js tests\nError: [Patched then() sees byobRequest after filling all pending pull-into descriptors] Error borrowing class: can't borrow a value as it is already borrowed\n\n\n🧪/wpt/streams.readable-streams.test.js \nstreams/readable-streams > should pass from.any.js tests\nError: [ReadableStream.from: cancel() rejects when return() is not a method] promise_test: Unhandled rejection with value: object \"TypeError: Error converting from js 'int' into type 'function'\"\n\nstreams/readable-streams > should pass owning-type-message-port.any.js tests\nError: [Transferred MessageChannel works as expected] promise_test: Unhandled rejection with value: object \"ReferenceError: MessageChannel is not defined\"\n\nstreams/readable-streams > should pass owning-type.any.js tests\nError: [ReadableStream can be constructed with owning type] Error converting from js 'string' into type 'ReadableStreamType'\n\nstreams/readable-streams > should pass patched-global.any.js tests\nError: [tee() should not call Promise.prototype.then()] patched then() called\n\n\n🧪/wpt/streams.writable-streams.test.js \nstreams/writable-streams > should pass general.any.js tests\nError: [WritableStream's strategy.size should not be called as a method] promise_test: Unhandled rejection with value: object \"Error: size called as a method\"\n\n\n🧪/wpt/url.test.js \nurl > should pass url-constructor.any.js tests\nError: [Parsing: <file:///w|/m> without base] assert_equals: href expected \"file:///w:/m\" but got \"file:///w|/m\"\n\nurl > should pass url-origin.any.js tests\nError: [Origin parsing: <blob:blob:https://example.org/> without base] assert_equals: origin expected \"null\" but got \"https://example.org\"\n\nurl > should pass url-setters.any.js tests\nError: [URL: Setting <non-spec:/.//p>.hostname = 'h' Drop /. from path] assert_equals: expected \"non-spec://h//p\" but got \"non-spec://h/.//p\"\n\nurl > should pass urlsearchparams-constructor.any.js tests\nError: [Construct with 2 unpaired surrogates (no trailing)] Conversion from string failed: invalid utf-8 sequence of 1 bytes from index 0\n\nurl > should pass urlsearchparams-sort.any.js tests\nError: [Parse and sort: ﬃ&🌈] assert_array_equals: expected property 0 to be \"🌈\" but got \"ﬃ\" (expected array [\"🌈\", \"\"] got [\"ﬃ\", \"\"])\n\nurl > should pass urlsearchparams-stringifier.any.js tests\nError: [URLSearchParams connected to URL] assert_equals: expected \"http://www.example.com/?a=b%2Cc&x=y\" but got \"http://www.example.com/?a=b,c&x=y\"\n\n\n🧪/wpt/webidl.ecmascript-binding.es-exceptions.test.js \nwebidl/ecmascript-binding/es-exceptions > should pass DOMException-custom-bindings.any.js tests\nError: [Cannot construct without new] assert_throws_js: function \"() => DOMException()\" did not throw\n\nwebidl/ecmascript-binding/es-exceptions > should pass DOMException-is-error.any.js tests\nError: [Untitled] assert_true: expected true got false\n\n\n"
  }
]