diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..df5ce85b --- /dev/null +++ b/.clang-format @@ -0,0 +1,4 @@ +# uses the same styling as V8 +BasedOnStyle: Google +DerivePointerAlignment: false +MaxEmptyLinesToKeep: 1 \ No newline at end of file diff --git a/.clang-format-ignore b/.clang-format-ignore new file mode 100644 index 00000000..687ed7c4 --- /dev/null +++ b/.clang-format-ignore @@ -0,0 +1,12 @@ +# clang format doesn't work properly with * and ** +NativeScript/include/* +NativeScript/include/*/* +NativeScript/include/*/*/* +NativeScript/include/*/*/*/* +NativeScript/include/*/*/*/*/* +NativeScript/ada/* +NativeScript/inspector/third_party/* +NativeScript/inspector/third_party/*/* +NativeScript/inspector/third_party/*/*/* +NativeScript/inspector/third_party/*/*/*/* +NativeScript/third_party/* diff --git a/.github/actions/collect-test-diagnostics/action.yml b/.github/actions/collect-test-diagnostics/action.yml new file mode 100644 index 00000000..08ce858b --- /dev/null +++ b/.github/actions/collect-test-diagnostics/action.yml @@ -0,0 +1,50 @@ +name: Collect test diagnostics +description: > + Gather what a failed simulator test run leaves outside the xcresult bundle: + host-side crash reports (.ips), CoreSimulator logs, and — when a device is + still booted — a targeted slice of the unified log. The xcresult itself + already carries the app's stdout/stderr and testmanagerd logs + (xcrun xcresulttool export diagnostics), so none of that is duplicated here. +inputs: + test-folder: + description: Folder the diagnostics directory is created in + required: true +runs: + using: composite + steps: + - name: Collect crash reports and simulator logs + shell: bash + run: | + DIAG="${{ inputs.test-folder }}/diagnostics" + mkdir -p "$DIAG" + # Crashes of simulator apps land in the *host's* DiagnosticReports. + cp -R ~/Library/Logs/DiagnosticReports/. "$DIAG/DiagnosticReports/" 2>/dev/null || true + cp -R ~/Library/Logs/CoreSimulator/. "$DIAG/CoreSimulator/" 2>/dev/null || true + # Only a booted device can serve its unified log; never boot one + # post-mortem — a fresh boot may pick the wrong device and stalls the + # job for minutes on an already-degraded VM. The pipeline must not leak + # grep's exit status: this shell runs with -e -o pipefail. + UDID="$(xcrun simctl list devices booted | grep -oE '[0-9A-Fa-f-]{36}' | head -1 || true)" + if [ -n "$UDID" ]; then + echo "Collecting unified log slice from booted simulator $UDID" + # simctl blocks forever if CoreSimulatorService is wedged — the very + # state this step tends to run in — so hard-cap it. + xcrun simctl spawn "$UDID" log show --style compact --last 45m \ + --predicate 'process CONTAINS "TestRunner"' \ + > "$DIAG/simulator-unified.log" 2>/dev/null & + LOG_PID=$! + ( sleep 120 && kill -9 "$LOG_PID" ) 2>/dev/null & + KILLER_PID=$! + wait "$LOG_PID" || echo "log show failed or was killed after 120s" + kill "$KILLER_PID" 2>/dev/null || true + else + echo "No booted simulator; relying on the xcresult's captured app output." + fi + echo "Collected diagnostics:" + du -sh "$DIAG"/* 2>/dev/null || true + - name: Upload test diagnostics + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: test-diagnostics + path: ${{ inputs.test-folder }}/diagnostics + if-no-files-found: ignore diff --git a/.github/actions/setup-build-env/action.yml b/.github/actions/setup-build-env/action.yml new file mode 100644 index 00000000..fc8395ab --- /dev/null +++ b/.github/actions/setup-build-env/action.yml @@ -0,0 +1,35 @@ +name: Setup build environment +description: Node + Python + native build dependencies shared by the workflow build/test jobs. +inputs: + node-version: + description: Node.js version to install + default: "22" + registry-url: + description: npm registry URL to configure for publishing (optional) + default: "" + install-test-tools: + description: Also install xcparse and the JUnit report tools ("true"/"false") + default: "false" +runs: + using: composite + steps: + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 + with: + node-version: ${{ inputs.node-version }} + registry-url: ${{ inputs.registry-url }} + # setup-node v6 enables dependency caching by default when it detects a + # package manager — a cache-poisoning vector for the release jobs (see + # npm_release.yml). Disabled everywhere; also keeps pre-v6 behavior. + package-manager-cache: false + - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 + with: + python-version: "3" + - name: Install dependencies + shell: bash + run: ./scripts/install-ci-deps.sh ${{ inputs.install-test-tools == 'true' && '--test-tools' || '' }} + # The V8 libraries and headers are not committed. build_nativescript.sh also + # calls this, but the test job drives xcodebuild directly, so it belongs in + # the shared setup rather than in one job. It is a no-op once installed. + - name: Fetch prebuilt V8 + shell: bash + run: ./download_v8.sh diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..ca0a6a7c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,146 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: monthly + + - package-ecosystem: npm + directory: /AppWithModules/app + schedule: + interval: monthly + time: "23:00" + open-pull-requests-limit: 10 + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major"] + + - package-ecosystem: npm + directory: /TestRunner/app + schedule: + interval: monthly + time: "23:00" + open-pull-requests-limit: 10 + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major"] + + - package-ecosystem: npm + directory: /TestRunner/app/tests + schedule: + interval: monthly + time: "23:00" + open-pull-requests-limit: 10 + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major"] + + - package-ecosystem: npm + directory: /TestRunner/app/tests/shared/Require/PackageJsonApp/io + schedule: + interval: monthly + time: "23:00" + open-pull-requests-limit: 10 + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major"] + + - package-ecosystem: npm + directory: /TestRunner/app/tests/shared/Require/PackageJsonAppNoMain/io + schedule: + interval: monthly + time: "23:00" + open-pull-requests-limit: 10 + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major"] + + - package-ecosystem: npm + directory: /TestRunner/app/tests/shared/Require/PackageJsonAppWithoutExtension/io + schedule: + interval: monthly + time: "23:00" + open-pull-requests-limit: 10 + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major"] + + - package-ecosystem: npm + directory: /TestRunner/app/tests/shared/Require/PackageJsonMainPointsToDir + schedule: + interval: monthly + time: "23:00" + open-pull-requests-limit: 10 + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major"] + + - package-ecosystem: npm + directory: /TestRunner/app/tests/shared/Require/PackageJsonSyntaxError/io + schedule: + interval: monthly + time: "23:00" + open-pull-requests-limit: 10 + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major"] + + - package-ecosystem: npm + directory: /TestRunner/app/tests/shared/Require/ResolveCanonicalPath + schedule: + interval: monthly + time: "23:00" + open-pull-requests-limit: 10 + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major"] + + - package-ecosystem: npm + directory: /TestRunner/app/tests/shared + schedule: + interval: monthly + time: "23:00" + open-pull-requests-limit: 10 + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major"] + + - package-ecosystem: npm + directory: /TestRunner/app/tns_modules/dummy-package + schedule: + interval: monthly + time: "23:00" + open-pull-requests-limit: 10 + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major"] + + - package-ecosystem: npm + directory: /TestRunner/app/tns_modules/tns-core-modules/shared/Require/PackageJsonTns/io + schedule: + interval: monthly + time: "23:00" + open-pull-requests-limit: 10 + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major"] + + - package-ecosystem: npm + directory: /TestRunner/app/tns_modules/tns-core-modules/shared/Require/RequirePriority/dependency5 + schedule: + interval: monthly + time: "23:00" + open-pull-requests-limit: 10 + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major"] + + - package-ecosystem: npm + directory: / + schedule: + interval: monthly + time: "23:00" + open-pull-requests-limit: 10 + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major"] \ No newline at end of file diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 00000000..f9f787ca --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,22 @@ +# Dependency Review Action +# +# This Action will scan dependency manifest files that change as part of a Pull Request, +# surfacing known-vulnerable versions of the packages declared or updated in the PR. +# Once installed, if the workflow run is marked as required, +# PRs introducing known-vulnerable packages will be blocked from merging. +# +# Source repository: https://github.com/actions/dependency-review-action +name: 'Dependency Review' +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: 'Checkout Repository' + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: 'Dependency Review' + uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0 \ No newline at end of file diff --git a/.github/workflows/npm_release.yml b/.github/workflows/npm_release.yml index ea5ebaa3..52d8d8d1 100644 --- a/.github/workflows/npm_release.yml +++ b/.github/workflows/npm_release.yml @@ -1,174 +1,457 @@ on: push: branches: - - main + - main # -> prerelease published under the "next" dist-tag tags: - - 'v*' + - "v*" # -> release published under the "latest" dist-tag + workflow_dispatch: + inputs: + version: + description: "Release version to cut, e.g. 9.1.0 (creates tag v and publishes 'latest'). Leave empty for a manual 'next' build." + required: false + default: "" env: NPM_TAG: "next" + XCODE_VERSION: "^16.0" +# Minimal default token permissions for every job. Jobs that need more declare it +# locally (github-release: contents:write; publish: id-token:write). Cross-repo +# writes to ios-spm use a GitHub App token, not GITHUB_TOKEN. +permissions: + contents: read + +# The runtime xcframeworks are no longer shipped inside the npm packages. Each +# build publishes them as GitHub Release assets and points the SwiftPM manifest +# (github.com/NativeScript/ios-spm) at them via binaryTarget(url:checksum:). The +# slim npm package only carries the Xcode project template + metadata generator. +# +# Flow: setup → build (ios, visionos) → test → github-release (assets) → +# spm-update (generate manifest + tag ios-spm) → publish (npm) → verify-spm +# +# The release half (github-release, spm-update, publish, verify-spm) is gated on +# repo variable ENABLE_SPM_RELEASE. Until it is 'true' (and the ios-spm App +# credentials are set), the workflow runs setup/build/test only and publishes NOTHING — so the +# slim package can never ship before its matching ios-spm tag exists. Turn the +# variable on as part of the cutover. jobs: - build: - name: Build - runs-on: macos-12 + setup: + name: Resolve version + runs-on: ubuntu-latest outputs: - npm_version: ${{ steps.npm_version_output.outputs.NPM_VERSION }} - npm_tag: ${{ steps.npm_version_output.outputs.NPM_TAG }} + npm_version: ${{ steps.out.outputs.NPM_VERSION }} + npm_tag: ${{ steps.out.outputs.NPM_TAG }} + build_matrix: ${{ steps.out.outputs.BUILD_MATRIX }} steps: - - uses: actions/checkout@v3 + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 + persist-credentials: false + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: 22 + # setup-node v6 enables dependency caching by default when it + # detects a package manager — a cache-poisoning vector, worst in the + # jobs that mint App tokens or publish. Disabled on every setup-node + # step in this workflow (also keeps pre-v6 behavior). + package-manager-cache: false + - name: Install deps for version scripts + run: npm install --no-audit --no-fund + - name: Compute version and tag + id: out + env: + # env indirection keeps the dispatch input out of shell interpolation + INPUT_VERSION: ${{ inputs.version }} + run: node ./scripts/resolve-release.mjs --version "$INPUT_VERSION" + + build: + name: Build ${{ matrix.target }} + runs-on: macos-15 + needs: setup + strategy: + fail-fast: false + # Computed in `setup`: ios always; visionos only for real releases + # (npm_tag != "next"), never for the rolling "next" channel. Each entry + # carries `target` (package identity, @nativescript/) and `script` + # (the npm build script; note the vision script is build-vision). + matrix: ${{ fromJSON(needs.setup.outputs.build_matrix) }} + env: + NPM_VERSION: ${{ needs.setup.outputs.npm_version }} + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + - uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1.7.0 + with: + xcode-version: ${{env.XCODE_VERSION}} + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + submodules: true + persist-credentials: false # disable to prevent leaking credentials to build scripts - name: LLVM cache - uses: actions/cache@v3 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ./llvm key: ${{ hashFiles('download_llvm.sh') }} - - uses: actions/setup-node@v3 - with: - node-version: 18 - registry-url: 'https://registry.npmjs.org' - - name: Install Python - uses: actions/setup-python@v4 + - uses: ./.github/actions/setup-build-env with: - python-version: "3" - - name: Install Dependencies - run: | - npm install - python3 -m pip install --upgrade pip six - brew install cmake - [ ! -f /usr/local/bin/cmake ] && ln -s /usr/local/bin/cmake $(which cmake) || true - - name: Get Current Version - run: | - NPM_VERSION=$(node -e "console.log(require('./package.json').version);") - echo NPM_VERSION=$NPM_VERSION >> $GITHUB_ENV - - name: Bump version for dev release - if: ${{ !contains(github.ref, 'refs/tags/') }} - run: | - NPM_VERSION=$(node ./scripts/get-next-version.js) - echo NPM_VERSION=$NPM_VERSION >> $GITHUB_ENV - npm version $NPM_VERSION --no-git-tag-version - - name: Output NPM Version and tag - id: npm_version_output - run: | - NPM_TAG=$(node ./scripts/get-npm-tag.js) - echo NPM_VERSION=$NPM_VERSION >> $GITHUB_OUTPUT - echo NPM_TAG=$NPM_TAG >> $GITHUB_OUTPUT - - name: Build - run: npm run build + registry-url: "https://registry.npmjs.org" + - name: Set package version + run: npm version $NPM_VERSION --no-git-tag-version --allow-same-version + - name: Build (${{ matrix.target }}) + # remote mode: the published package embeds no binaries and pins + # github.com/NativeScript/ios-spm at this version instead (the + # github-release + spm-update jobs make that pin resolvable). + env: + # env indirection keeps matrix values out of shell interpolation + BUILD_SCRIPT: ${{ matrix.script }} + run: npm run "$BUILD_SCRIPT" -- --spm-mode=remote - name: Upload npm package artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: npm-package-${{ matrix.target }} + path: dist/nativescript-*-${{ env.NPM_VERSION }}.tgz + - name: Upload SwiftPM artifacts (xcframework zips + checksums) + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: - name: npm-package - path: dist/nativescript-ios-${{env.NPM_VERSION}}.tgz + name: spm-artifacts-${{ matrix.target }} + path: dist/artifacts/* - name: Upload dSYMs artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: - name: NativeScript-dSYMs + name: dSYMs-${{ matrix.target }} path: dist/dSYMs + test: name: Test - runs-on: macos-12 + runs-on: macos-15 needs: build steps: - - uses: actions/checkout@v3 + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + - uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1.7.0 + with: + xcode-version: ${{env.XCODE_VERSION}} + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + submodules: true + persist-credentials: false # disable to prevent leaking credentials to build scripts - name: LLVM cache - uses: actions/cache@v3 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ./llvm key: ${{ hashFiles('download_llvm.sh') }} - - uses: actions/setup-node@v3 - with: - node-version: 18 - - name: Install Python - uses: actions/setup-python@v4 + - uses: ./.github/actions/setup-build-env with: - python-version: "3" - - name: Install Dependencies - run: | - npm install - python3 -m pip install --upgrade pip six - brew install cmake - [ ! -f /usr/local/bin/cmake ] && ln -s /usr/local/bin/cmake $(which cmake) || true - brew install chargepoint/xcparse/xcparse - npm install -g @edusperoni/junit-cli-report-viewer verify-junit-xml + install-test-tools: "true" - name: Prepare run: npm run setup-ci + - name: Prepare test folder + run: | + mkdir -p dist-test + echo TEST_FOLDER=$(pwd)/dist-test >> $GITHUB_ENV - name: Xcode Tests - uses: nick-fields/retry@v2 + uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 # try to run the tests with xcpretty. If it fails then try again without xcpretty twice for better log output # the xcode tests are a bit flaky and they should never fail on this step, as this step only collects the JS test results as junit xml with: - timeout_minutes: 20 - max_attempts: 3 - command: set -o pipefail && xcodebuild -project v8ios.xcodeproj -scheme TestRunner -resultBundlePath $HOME/test_results -destination platform\=iOS\ Simulator,OS\=16.2,name\=iPhone\ 14\ Pro\ Max build test | xcpretty - on_retry_command: rm -rf $HOME/test_results* - new_command_on_retry: xcodebuild -project v8ios.xcodeproj -scheme TestRunner -resultBundlePath $HOME/test_results -destination platform\=iOS\ Simulator,OS\=16.2,name\=iPhone\ 14\ Pro\ Max build test + # Build (~10m) + the runtime suite's report-wait (now up to 10m, see + # TestRunnerTests.swift) need more than 20m headroom per attempt. + timeout_minutes: 40 + max_attempts: 2 + command: set -o pipefail && xcodebuild -project v8ios.xcodeproj -scheme TestRunner -resultBundlePath $TEST_FOLDER/test_results -destination platform\=iOS\ Simulator,OS\=latest,name\=iPhone\ 16\ Pro build test | xcpretty + # Keep the failed attempt's bundle — it holds the diagnostics of the + # failure being retried. Everything else at the result path must go + # (including extensionless staging leftovers), or the retry dies with + # "Existing file at -resultBundlePath". + on_retry_command: rm -rf $TEST_FOLDER/test_results_attempt1.xcresult; mv $TEST_FOLDER/test_results.xcresult $TEST_FOLDER/test_results_attempt1.xcresult 2>/dev/null; for f in $TEST_FOLDER/test_results*; do [ "$f" = "$TEST_FOLDER/test_results_attempt1.xcresult" ] || rm -rf "$f"; done; xcrun simctl shutdown all + new_command_on_retry: xcodebuild -project v8ios.xcodeproj -scheme TestRunner -resultBundlePath $TEST_FOLDER/test_results -destination platform\=iOS\ Simulator,OS\=latest,name\=iPhone\ 16\ Pro build test - name: Validate Test Results run: | - xcparse attachments $HOME/test_results.xcresult $HOME/test-out - find $HOME/test-out -name "*junit*.xml" -maxdepth 1 -print0 | xargs -n 1 -0 npx junit-cli-report-viewer - find $HOME/test-out -name "*junit*.xml" -maxdepth 1 -print0 | xargs -n 1 -0 npx verify-junit-xml - publish: - runs-on: ubuntu-latest - needs: - - build - - test - permissions: - contents: read - id-token: write - env: - NPM_VERSION: ${{needs.build.outputs.npm_version}} - NPM_TAG: ${{needs.build.outputs.npm_tag}} - steps: - - uses: actions/setup-node@v3 + xcparse attachments $TEST_FOLDER/test_results.xcresult $TEST_FOLDER/test-out + find $TEST_FOLDER/test-out -name "*junit*.xml" -maxdepth 1 -print0 | xargs -n 1 -0 npx junit-cli-report-viewer + find $TEST_FOLDER/test-out -name "*junit*.xml" -maxdepth 1 -print0 | xargs -n 1 -0 npx verify-junit-xml + - name: Collect test diagnostics + if: failure() + uses: ./.github/actions/collect-test-diagnostics with: - node-version: 18 - registry-url: 'https://registry.npmjs.org' - - uses: actions/download-artifact@v3 + test-folder: ${{env.TEST_FOLDER}} + - name: Archive Test Result Data + if: always() + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: - name: npm-package - path: dist - - name: Publish package - run: | - echo "Publishing @nativescript/ios@$NPM_VERSION to NPM with tag $NPM_TAG..." - npm publish ./dist/nativescript-ios-${{env.NPM_VERSION}}.tgz --tag $NPM_TAG --provenance - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }} + name: test-results + path: | + ${{env.TEST_FOLDER}}/test_results.xcresult + ${{env.TEST_FOLDER}}/test_results_attempt1.xcresult + + # Publish the xcframework zips + dSYMs as a GitHub Release asset for EVERY + # version (prerelease unless 'latest'), because the SwiftPM binaryTarget url + # must resolve for `next`/`pr` consumers too — not only tagged releases. github-release: + name: GitHub Release (SPM assets) runs-on: ubuntu-latest - # only runs on tagged commits - if: ${{ contains(github.ref, 'refs/tags/') }} + # Master switch for the SPM release flow. When unset, the workflow runs + # setup/build/test only — nothing is released or published, so landing this + # on main before the token is configured is a no-op for consumers. + if: ${{ vars.ENABLE_SPM_RELEASE == 'true' }} permissions: contents: write needs: + - setup - build - test env: - NPM_VERSION: ${{needs.build.outputs.npm_version}} + NPM_VERSION: ${{ needs.setup.outputs.npm_version }} + NPM_TAG: ${{ needs.setup.outputs.npm_tag }} steps: - - uses: actions/checkout@v3 + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - - uses: actions/setup-node@v3 + persist-credentials: false + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: - node-version: 18 + node-version: 22 + package-manager-cache: false - name: Setup - run: npm install - - uses: actions/download-artifact@v3 + run: npm install --no-audit --no-fund + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: - name: npm-package - path: dist - - uses: actions/download-artifact@v3 + pattern: spm-artifacts-* + path: spm-artifacts + merge-multiple: true + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: - name: NativeScript-dSYMs - path: dist + pattern: dSYMs-* + path: dist/dSYMs + merge-multiple: true - name: Zip dSYMs working-directory: dist/dSYMs - run: find . -maxdepth 1 -name '*.dSYM' -print | xargs -I@ zip -r @.zip @ + run: find . -maxdepth 1 -name '*.dSYM' -print | xargs -I@ zip -r @.zip @ || true - name: Partial Changelog run: npx conventional-changelog -p angular -r2 > body.md - - uses: ncipollo/release-action@v1 + - name: Create / update release with SPM artifacts + uses: ncipollo/release-action@b7eabc95ff50cbeeedec83973935c8f306dfcd0b # v1.20.0 with: - artifacts: "dist/nativescript-ios-*.tgz,dist/dSYMs/*.zip" + tag: "v${{ env.NPM_VERSION }}" + name: "v${{ env.NPM_VERSION }}" + commit: ${{ github.sha }} + artifacts: "spm-artifacts/*.xcframework.zip,dist/dSYMs/*.zip" bodyFile: "body.md" + prerelease: ${{ needs.setup.outputs.npm_tag != 'latest' }} + allowUpdates: true + + # Stamp + tag github.com/NativeScript/ios-spm to point at this release's assets. + # Cross-repo write uses a short-lived GitHub App installation token, minted per + # run and scoped to ios-spm only (no long-lived PAT to rotate). Enable by setting + # repo variable ENABLE_SPM_RELEASE=true plus the App credentials + # (variable APP_CLIENT_ID + secret APP_PRIVATE_KEY); the App must be installed on + # NativeScript/ios-spm with Contents: Read and write. + spm-update: + name: Update ios-spm manifest + runs-on: ubuntu-latest + if: ${{ vars.ENABLE_SPM_RELEASE == 'true' }} + needs: + - setup + - build + - test + - github-release + env: + NPM_VERSION: ${{ needs.setup.outputs.npm_version }} + NPM_TAG: ${{ needs.setup.outputs.npm_tag }} + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + - name: Mint ios-spm App token (short-lived, scoped to ios-spm) + id: app-token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 + with: + client-id: ${{ vars.APP_CLIENT_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + owner: NativeScript + repositories: ios-spm + permission-contents: write + - name: Checkout ios (for stamping script) + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + path: ios + persist-credentials: false + - name: Checkout ios-spm + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: NativeScript/ios-spm + token: ${{ steps.app-token.outputs.token }} + path: ios-spm + persist-credentials: false + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: 22 + package-manager-cache: false + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + pattern: spm-artifacts-* + path: spm-artifacts + merge-multiple: true + - name: Generate Package.swift + # The generator emits the WHOLE manifest, shaped by the checksums it + # finds: "next" builds produce only checksums-ios.env, so the next + # manifest omits the visionOS product/targets whose Release assets + # don't exist (SwiftPM eagerly downloads every binaryTarget in a + # resolved manifest — an unshipped asset 404s for every consumer). + # Any non-"next" --channel requires the full checksum set, so a real + # release can never silently ship an iOS-only manifest. + run: | + node ios/scripts/generate-spm-manifest.mjs \ + --package ios-spm/Package.swift \ + --version "$NPM_VERSION" \ + --checksums-dir spm-artifacts \ + --channel "$NPM_TAG" + - name: Commit and tag ios-spm + working-directory: ios-spm + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: | + git config user.name "NativeScript Bot" + git config user.email "oss@nativescript.org" + # persist-credentials:false keeps the token out of .git/config; push to a + # token-authenticated URL instead (the App token is masked in logs). + REMOTE="https://x-access-token:${GH_TOKEN}@github.com/NativeScript/ios-spm.git" + git add Package.swift + git commit -m "release: $NPM_VERSION" || echo "no changes to commit" + git tag -f "$NPM_VERSION" + git push "$REMOTE" HEAD:main + git push -f "$REMOTE" "refs/tags/$NPM_VERSION" + + publish: + name: Publish ${{ matrix.target }} + runs-on: ubuntu-latest + environment: npm-publish + # Gated + ordered after spm-update so a slim package is never published before + # its matching ios-spm tag exists (which would make it unresolvable). + if: ${{ vars.ENABLE_SPM_RELEASE == 'true' }} + needs: + - setup + - build + - test + - spm-update + permissions: + contents: read + id-token: write + strategy: + fail-fast: false + # Same targets as the build matrix (computed in `setup`): visionos is + # published only for real releases, never for the "next" channel. The + # unused `script` key on each entry is harmless here. + matrix: ${{ fromJSON(needs.setup.outputs.build_matrix) }} + env: + NPM_VERSION: ${{ needs.setup.outputs.npm_version }} + NPM_TAG: ${{ needs.setup.outputs.npm_tag }} + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: 22 + package-manager-cache: false + registry-url: "https://registry.npmjs.org" + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: npm-package-${{ matrix.target }} + path: dist + - name: Update npm (required for OIDC trusted publishing) + run: | + corepack enable npm + corepack install -g npm@11.5.1 + test "$(npm --version)" = "11.5.1" + test "$(npx --version)" = "11.5.1" + - name: Resolve package name + run: | + if [ "${{ matrix.target }}" = "ios" ]; then echo "PKG=ios" >> $GITHUB_ENV; else echo "PKG=visionos" >> $GITHUB_ENV; fi + - name: Publish package (OIDC trusted publishing) + if: ${{ vars.USE_NPM_TOKEN != 'true' }} + run: | + echo "Publishing @nativescript/$PKG@$NPM_VERSION to NPM with tag $NPM_TAG via OIDC trusted publishing..." + unset NODE_AUTH_TOKEN + if [ -n "${NPM_CONFIG_USERCONFIG:-}" ]; then + rm -f "$NPM_CONFIG_USERCONFIG" + fi + npm publish ./dist/nativescript-${PKG}-${NPM_VERSION}.tgz --tag $NPM_TAG --access public --provenance + env: + NODE_AUTH_TOKEN: "" + - name: Publish package (granular token) + if: ${{ vars.USE_NPM_TOKEN == 'true' }} + run: | + echo "Publishing @nativescript/$PKG@$NPM_VERSION to NPM with tag $NPM_TAG via granular token..." + npm publish ./dist/nativescript-${PKG}-${NPM_VERSION}.tgz --tag $NPM_TAG --access public --provenance + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }} + + # Post-publish smoke test: resolve ios-spm at the released tag and verify the + # binary artifact downloads + checksum-validate against the real Release. + # + # One probe for every channel, against the REAL released manifest. The + # manifest's target set is channel-shaped by generate-spm-manifest.mjs + # ("next" manifests only declare the iOS targets, because next Releases have + # no visionos assets), so resolving ios-spm at the released tag exercises + # exactly the artifact set a consumer's xcodebuild will download: iOS-only on + # next, iOS + visionos on real releases (v* tag / manual version). + verify-spm: + name: Verify SPM resolution + runs-on: macos-15 + if: ${{ vars.ENABLE_SPM_RELEASE == 'true' }} + needs: + - setup + - spm-update + env: + NPM_VERSION: ${{ needs.setup.outputs.npm_version }} + NPM_TAG: ${{ needs.setup.outputs.npm_tag }} + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: 22 + package-manager-cache: false + - name: Generate a probe package that depends on ios-spm + # The probe pins ios-spm at the exact released version. Resolving it + # takes the same path a consumer's xcodebuild does, and the released + # manifest only declares targets whose assets exist (channel-shaped by + # generate-spm-manifest.mjs) — so this single probe is valid for every + # channel. --assert-release-manifest additionally guards against the + # tag pointing at a stale (prior version's) manifest, which would + # still resolve and checksum-pass below. + run: | + node scripts/generate-spm-probe.mjs \ + --version "$NPM_VERSION" \ + --dir spmverify \ + --assert-release-manifest + - name: Resolve (downloads the xcframework zips and verifies their checksums) + working-directory: spmverify + run: | + # Resolution fetches each binaryTarget's zip and verifies its SHA-256 + # against the manifest checksum; a mismatch or a missing release asset + # fails the release here. For next the manifest declares the iOS + # artifacts only; real releases also declare (and verify) visionos. + swift package resolve + echo "ios-spm@$NPM_VERSION resolved and checksum-verified." diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index c339a5c7..89c370a7 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -3,33 +3,27 @@ on: env: NPM_TAG: "pr" + XCODE_VERSION: "^16.0" jobs: build: name: Build - runs-on: macos-12 + runs-on: macos-15 steps: - - uses: actions/checkout@v3 + - uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1.7.0 + with: + xcode-version: ${{env.XCODE_VERSION}} + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 + submodules: true + persist-credentials: false # disable to prevent leaking credentials to build scripts - name: LLVM cache - uses: actions/cache@v3 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ./llvm key: ${{ hashFiles('download_llvm.sh') }} - - uses: actions/setup-node@v3 - with: - node-version: 18 - - name: Install Python - uses: actions/setup-python@v4 - with: - python-version: "3" - - name: Install Dependencies - run: | - npm install - python3 -m pip install --upgrade pip six - brew install cmake - [ ! -f /usr/local/bin/cmake ] && ln -s /usr/local/bin/cmake $(which cmake) || true + - uses: ./.github/actions/setup-build-env - name: Get Current Version run: | echo NPM_VERSION=$(node -e "console.log(require('./package.json').version);") >> $GITHUB_ENV @@ -39,55 +33,81 @@ jobs: echo NPM_VERSION=$NPM_VERSION >> $GITHUB_ENV npm version $NPM_VERSION --no-git-tag-version - name: Build - run: npm run build + # Default (embedded) SwiftPM mode: the xcframework zips ship inside the + # package, so the artifact below is self-contained — download it and + # use it directly with `ns platform add ios --framework-path=`. + run: npm run build-ios - name: Upload npm package artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: npm-package path: dist/nativescript-ios-${{env.NPM_VERSION}}.tgz + - name: Upload SwiftPM artifacts (xcframework zips + checksums) + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: spm-artifacts + path: dist/artifacts/* - name: Upload dSYMs artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: NativeScript-dSYMs path: dist/dSYMs test: name: Test - runs-on: macos-12 + runs-on: macos-15 needs: build steps: - - uses: actions/checkout@v3 + - uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1.7.0 + with: + xcode-version: ${{env.XCODE_VERSION}} + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + submodules: true + persist-credentials: false # disable to prevent leaking credentials to build scripts - name: LLVM cache - uses: actions/cache@v3 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ./llvm key: ${{ hashFiles('download_llvm.sh') }} - - uses: actions/setup-node@v3 - with: - node-version: 18 - - name: Install Python - uses: actions/setup-python@v4 + - uses: ./.github/actions/setup-build-env with: - python-version: "3" - - name: Install Dependencies + install-test-tools: "true" + - name: Prepare test folder + id: prepare-test-folder run: | - npm install - python3 -m pip install --upgrade pip six - brew install cmake - [ ! -f /usr/local/bin/cmake ] && ln -s /usr/local/bin/cmake $(which cmake) || true - brew install chargepoint/xcparse/xcparse - npm install -g @edusperoni/junit-cli-report-viewer verify-junit-xml + mkdir -p dist-test + echo TEST_FOLDER=$(pwd)/dist-test >> $GITHUB_ENV - name: Xcode Tests - uses: nick-fields/retry@v2 + uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 # try to run the tests with xcpretty. If it fails then try again without xcpretty twice for better log output # the xcode tests are a bit flaky and they should never fail on this step, as this step only collects the JS test results as junit xml with: - timeout_minutes: 20 - max_attempts: 3 - command: set -o pipefail && xcodebuild -project v8ios.xcodeproj -scheme TestRunner -resultBundlePath $HOME/test_results -destination platform\=iOS\ Simulator,OS\=16.2,name\=iPhone\ 14\ Pro\ Max build test | xcpretty - on_retry_command: rm -rf $HOME/test_results* - new_command_on_retry: xcodebuild -project v8ios.xcodeproj -scheme TestRunner -resultBundlePath $HOME/test_results -destination platform\=iOS\ Simulator,OS\=16.2,name\=iPhone\ 14\ Pro\ Max build test + # Build (~10m) + the runtime suite's report-wait (up to 10m, see + # TestRunnerTests.swift) need more than 20m headroom per attempt. + timeout_minutes: 40 + max_attempts: 2 + command: set -o pipefail && xcodebuild -project v8ios.xcodeproj -scheme TestRunner -resultBundlePath $TEST_FOLDER/test_results -destination platform\=iOS\ Simulator,OS\=latest,name\=iPhone\ 16\ Pro build test | xcpretty + # Keep the failed attempt's bundle — it holds the diagnostics of the + # failure being retried. Everything else at the result path must go + # (including extensionless staging leftovers), or the retry dies with + # "Existing file at -resultBundlePath". + on_retry_command: rm -rf $TEST_FOLDER/test_results_attempt1.xcresult; mv $TEST_FOLDER/test_results.xcresult $TEST_FOLDER/test_results_attempt1.xcresult 2>/dev/null; for f in $TEST_FOLDER/test_results*; do [ "$f" = "$TEST_FOLDER/test_results_attempt1.xcresult" ] || rm -rf "$f"; done; xcrun simctl shutdown all + new_command_on_retry: xcodebuild -project v8ios.xcodeproj -scheme TestRunner -resultBundlePath $TEST_FOLDER/test_results -destination platform\=iOS\ Simulator,OS\=latest,name\=iPhone\ 16\ Pro build test - name: Validate Test Results run: | - xcparse attachments $HOME/test_results.xcresult $HOME/test-out - find $HOME/test-out -name "*junit*.xml" -maxdepth 1 -print0 | xargs -n 1 -0 npx junit-cli-report-viewer - find $HOME/test-out -name "*junit*.xml" -maxdepth 1 -print0 | xargs -n 1 -0 npx verify-junit-xml + xcparse attachments $TEST_FOLDER/test_results.xcresult $TEST_FOLDER/test-out + find $TEST_FOLDER/test-out -name "*junit*.xml" -maxdepth 1 -print0 | xargs -n 1 -0 npx junit-cli-report-viewer + find $TEST_FOLDER/test-out -name "*junit*.xml" -maxdepth 1 -print0 | xargs -n 1 -0 npx verify-junit-xml + - name: Collect test diagnostics + if: failure() + uses: ./.github/actions/collect-test-diagnostics + with: + test-folder: ${{env.TEST_FOLDER}} + - name: Archive Test Result Data + if: always() + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: test-results + path: | + ${{env.TEST_FOLDER}}/test_results.xcresult + ${{env.TEST_FOLDER}}/test_results_attempt1.xcresult diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml new file mode 100644 index 00000000..655301d3 --- /dev/null +++ b/.github/workflows/scorecards.yml @@ -0,0 +1,73 @@ +name: Scorecard supply-chain security +on: + # For Branch-Protection check. Only the default branch is supported. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection + branch_protection_rule: + # To guarantee Maintained check is occasionally updated. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained + schedule: + - cron: '20 7 * * 2' + push: + branches: ["main"] + +# Declare default permissions as read only. +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Needed to publish results and get a badge (see publish_results below). + id-token: write + contents: read + actions: read + # To allow GraphQL ListCommits to work + issues: read + pull-requests: read + # To detect SAST tools + checks: read + + steps: + + - name: "Checkout code" + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4 + with: + results_file: results.sarif + results_format: sarif + # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: + # - you want to enable the Branch-Protection check on a *public* repository, or + # - you are installing Scorecards on a *private* repository + # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. + # repo_token: ${{ secrets.SCORECARD_TOKEN }} + + # Public repositories: + # - Publish results to OpenSSF REST API for easy access by consumers + # - Allows the repository to include the Scorecard badge. + # - See https://github.com/ossf/scorecard-action#publishing-results. + # For private repositories: + # - `publish_results` will always be set to `false`, regardless + # of the value entered here. + publish_results: true + + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF + # format to the repository Actions tab. + - name: "Upload artifact" + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard. + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3 + with: + sarif_file: results.sarif \ No newline at end of file diff --git a/.gitignore b/.gitignore index 9aff7041..7a582455 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,9 @@ Thumbs.db # VSCode .vscode +# Generated by tools/js2c.mjs (Xcode "Generate RuntimeBuiltins" build phase) +NativeScript/runtime/generated/ + # Other node_modules/ package-lock.json @@ -45,8 +48,45 @@ v8 v8_build .npmrc -llvm/ +/llvm/ # v8 build files... .gclient* .cipd/ + +# project template +/project-template-ios/.build_env_vars.sh +/project-template-ios/__PROJECT_NAME__.xcodeproj/project.xcworkspace/xcshareddata/ +/project-template-vision/.build_env_vars.sh +/project-template-vision/__PROJECT_NAME__.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist + +# V8 prebuilts, fetched by download_v8.sh from the release +# pinned in V8_RELEASE. Not committed: the full matrix cannot be built +# on one machine, so hand-assembled binaries are neither reproducible nor +# verifiable. +# +# The headers are ignored along with the libraries on purpose: keeping a +# vendored copy in git is how it drifts out of step with the binaries it +# describes -- the crdtp headers here sat on 10.3 against a 14.9 libcrdtp. +# Sourcing both from one verified artifact makes that impossible. +# tools/v8 holds our scripts, not a V8 checkout; the bare 'v8' rule above +# would otherwise swallow it. +!tools/v8/ +!tools/v8/** + +/.v8-prebuilt/ +NativeScript/lib/*/*.a +!NativeScript/lib/*/libffi.a +NativeScript/lib/.v8-release-stamp +NativeScript/include/** +!NativeScript/include/libffi.h +!NativeScript/include/libffi/ +!NativeScript/include/libffi/** +NativeScript/inspector/src/ +NativeScript/inspector/third_party/ +NativeScript/inspector/absl/ + + +#AI agents +.claude/* +!.claude/settings.json diff --git a/.gitmodules b/.gitmodules index 3c220897..91c1df44 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,8 +1,8 @@ [submodule "libffi"] path = libffi url = https://github.com/NativeScript/libffi.git - branch = darind/v8-ios -[submodule "llvm"] - path = llvm - url = https://github.com/NativeScript/ios-llvm.git + branch = feat/vector-types +[submodule "TestRunner/app/shared"] + path = TestRunner/app/shared + url = https://github.com/NativeScript/common-runtime-tests-app.git branch = master diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 00000000..1238c7b2 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,17 @@ +# Fail early with an accurate message when the toolchain is not set up — a +# missing tool must block the commit, not silently skip validation. Bypass +# deliberately with `git commit --no-verify` if you must. +if [ ! -x node_modules/.bin/eslint ]; then + echo "pre-commit: node_modules missing — run 'npm install' first (or bypass explicitly with --no-verify)" >&2 + exit 1 +fi +if ! command -v git-clang-format >/dev/null 2>&1; then + echo "pre-commit: git-clang-format not found — install clang-format (e.g. 'brew install clang-format')" >&2 + exit 1 +fi + +# --no-install: only the repo-pinned lint-staged may run; a bare npx would +# fetch an arbitrary cached version when the local one is absent. +# Native sources are auto-formatted on the staged hunks only (see +# tools/format-staged-native.sh); JS goes through eslint. +npx --no-install lint-staged diff --git a/CHANGELOG.md b/CHANGELOG.md index 7819d8e0..761ecb2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,262 @@ +## [9.0.3](https://github.com/NativeScript/ios/compare/v9.0.2...v9.0.3) (2026-01-04) + + +### Features + +* remote module security ([#331](https://github.com/NativeScript/ios/issues/331)) ([721ceaf](https://github.com/NativeScript/ios/commit/721ceafe2606ff25786529acb9a4c727cfa84d78)) + + + +## [9.0.2](https://github.com/NativeScript/ios/compare/v9.0.1...v9.0.2) (2025-12-14) + + +### Bug Fixes + +* http realm cache key with query params ([#328](https://github.com/NativeScript/ios/issues/328)) ([f0c9df3](https://github.com/NativeScript/ios/commit/f0c9df35ecf01aaad340d325b0fba3f8ec083eae)) +* http realm normalization ([faa6762](https://github.com/NativeScript/ios/commit/faa67626695f133f5d37dca09aaab957214c7bd2)) +* URLSearchParams.forEach() crash and spec compliance ([#327](https://github.com/NativeScript/ios/issues/327)) ([28242ec](https://github.com/NativeScript/ios/commit/28242ecc3bc52875f7ffe13ae1665224026191a3)) + + + +## [9.0.1](https://github.com/NativeScript/ios/compare/v9.0.0...v9.0.1) (2025-11-25) + + +### Bug Fixes + +* node built-in modules handling ([#319](https://github.com/NativeScript/ios/issues/319)) ([f748751](https://github.com/NativeScript/ios/commit/f748751c74968ea015c8abff30fe86bfacd84930)) +* **runtime:** app path substr considerations ([#314](https://github.com/NativeScript/ios/issues/314)) ([fd2703d](https://github.com/NativeScript/ios/commit/fd2703d59e6ba2472d8baefe014f0afc4c8952df)) + + + +# [9.0.0](https://github.com/NativeScript/ios/compare/v8.9.5...v9.0.0) (2025-11-17) + + +### Bug Fixes + +* optional error parameter for NSError out parameters ([#310](https://github.com/NativeScript/ios/issues/310)) ([99824ec](https://github.com/NativeScript/ios/commit/99824eca41c1ae7fb939a6790ae83f6e2bc41574)) +* **visionos:** build flags ([29e5d79](https://github.com/NativeScript/ios/commit/29e5d79924ae65c32f93f8cb19aece4ef6f370fd)) +* **visionos:** linker robustness ([14355d5](https://github.com/NativeScript/ios/commit/14355d5647e4b61c60be3fb87282d441575f1de0)) + + +### Features + +* Ada 3.3.0 ([#313](https://github.com/NativeScript/ios/issues/313)) ([e24388c](https://github.com/NativeScript/ios/commit/e24388c9261bcbf9c2580abf76cffdc87b6d2bf6)) +* ES modules (ESM) support with conditional esm or commonjs consumption + better error handling ([#276](https://github.com/NativeScript/ios/issues/276)) ([e72977a](https://github.com/NativeScript/ios/commit/e72977ab9a1059a8e9686c169f3090c6fdcee398)) +* http loaded es module realms + HMR DX enrichments ([#312](https://github.com/NativeScript/ios/issues/312)) ([59191d3](https://github.com/NativeScript/ios/commit/59191d3b921c29346bbfeb4f0947f13e5b08288e)) +* support for struct reference index access ([#304](https://github.com/NativeScript/ios/issues/304)) ([d289232](https://github.com/NativeScript/ios/commit/d2892320e773cc12729f3b6edc5da683534aef9b)) + + + +## [8.9.5](https://github.com/NativeScript/ios/compare/v8.9.4...v8.9.5) (2025-10-24) + + +### Bug Fixes + +* make debugger log public ([#302](https://github.com/NativeScript/ios/issues/302)) ([e89067c](https://github.com/NativeScript/ios/commit/e89067cf0f57adcc2479642e4e043b6d6e0d8a0b)) +* prevent crash during debug on fast view churn (like with HMR) ([#294](https://github.com/NativeScript/ios/issues/294)) ([42a5328](https://github.com/NativeScript/ios/commit/42a5328f9e95b2298efe067485ac6775718d0510)) +* properly convert objective-c logs into os_log ([#301](https://github.com/NativeScript/ios/issues/301)) ([5733af1](https://github.com/NativeScript/ios/commit/5733af1abd896ef8902fbd5b0f57888e71d67d1b)) +* symbol loader log true errors only to not confuse terminal output ([#293](https://github.com/NativeScript/ios/issues/293)) ([7101127](https://github.com/NativeScript/ios/commit/710112731a9149020c49c2b2b34a82ebd39a2d49)) +* x86 simulators and add better failsafe around generated class names ([#303](https://github.com/NativeScript/ios/issues/303)) ([bb02623](https://github.com/NativeScript/ios/commit/bb02623415359d11cd9e17f3d6351c3b04c4f01d)) + + +### Features + +* queueMicrotask support ([#291](https://github.com/NativeScript/ios/issues/291)) ([b12d552](https://github.com/NativeScript/ios/commit/b12d5528885086335487bae4c62cab13ccdb841a)) + + + +## [8.9.4](https://github.com/NativeScript/ios/compare/v8.9.2...v8.9.3) (2025-09-09) + + +### Features + +- include dSYMs + +## [8.9.3](https://github.com/NativeScript/ios/compare/v8.9.2...v8.9.3) (2025-09-09) + + +### Bug Fixes + +* **catalyst:** variable-length arrays ([#275](https://github.com/NativeScript/ios/issues/275)) ([6d3dfc2](https://github.com/NativeScript/ios/commit/6d3dfc2558e60da60a9f6cbb45cdfd272eefabe7)) + + +### Features + +* Xcode 26 +* Ada 3.2.7 ([#279](https://github.com/NativeScript/ios/issues/279)) ([fb56643](https://github.com/NativeScript/ios/commit/fb56643b2ec0e41a10f3acf5633e59bcbd2b0514)) +* improve robustness of linking with clang path checks ([#280](https://github.com/NativeScript/ios/issues/280)) ([debc76d](https://github.com/NativeScript/ios/commit/debc76dfd143d26956180c35c8a96534dd7ad152)) +* opt for os_log with graceful backwards compat fallback ([#278](https://github.com/NativeScript/ios/issues/278)) ([3c5d894](https://github.com/NativeScript/ios/commit/3c5d894e670bcb9ef7c48446b6c565a196f0cfd2)) +* search sub framework paths in metadata generator ([#277](https://github.com/NativeScript/ios/issues/277)) ([7bd239f](https://github.com/NativeScript/ios/commit/7bd239fa43e3884bffe06a7fef6f39aa4a156e39)) + + + +## [8.9.2](https://github.com/NativeScript/ios/compare/v8.9.1...v8.9.2) (2025-03-11) + + +### Bug Fixes + +* Intel simulators ([#272](https://github.com/NativeScript/ios/issues/272)) ([0adeabf](https://github.com/NativeScript/ios/commit/0adeabf24aab579bdc10900495a46e9b8287b5d9)) + + +### Reverts + +* "feat: visionOS unit tests" ([f26d72c](https://github.com/NativeScript/ios/commit/f26d72c769c936b3ead647933f5da1af6c5c4434)) + + + +## [8.9.1](https://github.com/NativeScript/ios/compare/v8.9.0...v8.9.1) (2025-02-28) + + +### Features + +* Ada 3.1.3 ([#270](https://github.com/NativeScript/ios/issues/270)) ([7081e5a](https://github.com/NativeScript/ios/commit/7081e5a50ee34f1d9edc1a6c3ae8a0cdbace30ec)) + + + +# [8.9.0](https://github.com/NativeScript/ios/compare/v8.8.2...v8.9.0) (2025-02-24) + + +### Bug Fixes + +* handle gc protection in runtime run loop ([#264](https://github.com/NativeScript/ios/issues/264)) ([5e8214d](https://github.com/NativeScript/ios/commit/5e8214dc7fffa91abd6c870b294259583ec50ce7)) +* possible race condition extending native class ([8b932a3](https://github.com/NativeScript/ios/commit/8b932a31fe735c69b9d72b76eb106037653764ce)) +* **URL:** allow undefined 2nd args and fix pathname return value ([#263](https://github.com/NativeScript/ios/issues/263)) ([4219038](https://github.com/NativeScript/ios/commit/42190388ddfbd42ad3b87244f5f317860f43c327)) + + +### Features + +* ada 3.1.1 including URLPattern support ([#268](https://github.com/NativeScript/ios/issues/268)) ([08d4406](https://github.com/NativeScript/ios/commit/08d4406d36545117a5a7be2db900394f106c4ec2)) +* latest jsi updates ([#267](https://github.com/NativeScript/ios/issues/267)) ([d4f3b68](https://github.com/NativeScript/ios/commit/d4f3b680ba77823d9e03b82548ead26706993b99)) +* use monotonic time for performance object ([8b320a4](https://github.com/NativeScript/ios/commit/8b320a4b15a216d27d43acfda44cd068d84f6e65)) +* visionOS unit tests ([#257](https://github.com/NativeScript/ios/issues/257)) ([ac52442](https://github.com/NativeScript/ios/commit/ac524426242049db2844576cc4f6d4f8776e71d5)) + + + +## [8.8.3-alpha.0](https://github.com/NativeScript/ios/compare/v8.8.2...v8.8.3-alpha.0) (2024-12-05) + + +### Bug Fixes + +* handle gc protection in runtime run loop ([78b5e37](https://github.com/NativeScript/ios/commit/78b5e3799f1305b3eafe7d3deb60a7e56b86b230)) +* possible race condition extending native class ([8b932a3](https://github.com/NativeScript/ios/commit/8b932a31fe735c69b9d72b76eb106037653764ce)) + + + +## [8.8.2](https://github.com/NativeScript/ios/compare/v8.8.1...v8.8.2) (2024-09-06) + + +### Bug Fixes + +* ensure same mtime for js and code cache to prevent loading old code caches ([#261](https://github.com/NativeScript/ios/issues/261)) ([055b042](https://github.com/NativeScript/ios/commit/055b0427cf49e7c4cb37991c9419b899868b6bbd)) +* revert visionOS changes to iOS project template ([55c5c51](https://github.com/NativeScript/ios/commit/55c5c5198f04ff2b5cbe1be6f5add92acb3ed23f)) + + + +## [8.8.1](https://github.com/NativeScript/ios/compare/v8.8.0...v8.8.1) (2024-07-10) + + +### Features + +* Ada 2.9 ([#256](https://github.com/NativeScript/ios/issues/256)) ([d16b144](https://github.com/NativeScript/ios/commit/d16b14436bddac42a12a4bddff92d2bc37dc8669)) + + + +# [8.8.0](https://github.com/NativeScript/ios/compare/v8.7.2...v8.8.0) (2024-07-09) + + +### Bug Fixes + +* ensure copy rule copy *.hpp headers ([3b13e9d](https://github.com/NativeScript/ios/commit/3b13e9dce88015c1e8eab29b9b0c7ec104b4f4d2)) + + +### Features + +* add `[@deprecation](https://github.com/deprecation)` and `[@since](https://github.com/since)` docs ([#246](https://github.com/NativeScript/ios/issues/246)) ([daceac1](https://github.com/NativeScript/ios/commit/daceac129d3b73c46a6de4f557d6c06a0621890f)) +* add protocol information to native types ([#247](https://github.com/NativeScript/ios/issues/247)) ([6286203](https://github.com/NativeScript/ios/commit/6286203ca5293f4a9bec536ee6af7415d8d4d8f5)) +* allow embedding into existing apple host projects ([#231](https://github.com/NativeScript/ios/issues/231)) ([7ab180a](https://github.com/NativeScript/ios/commit/7ab180a7c8788216126abbb985d72332b064217a)) +* expose __dateTimeConfigurationChangeNotification ([#220](https://github.com/NativeScript/ios/issues/220)) ([5088f5f](https://github.com/NativeScript/ios/commit/5088f5fff231023a722a4626e73661ff6b9ad9fd)) +* JSI support for BigInt, Initial TypedArrays & ArrayBuffer creation ([#204](https://github.com/NativeScript/ios/issues/204)) ([4cd869d](https://github.com/NativeScript/ios/commit/4cd869dd678cf875b31efa4b7a75ee0f571ce096)) +* use messaging object to pass message to workers ([#233](https://github.com/NativeScript/ios/issues/233)) ([7ded0c3](https://github.com/NativeScript/ios/commit/7ded0c38bb891b340bd8e1c5137e607447e26e60)) +* xcode 16 support ([#254](https://github.com/NativeScript/ios/issues/254)) ([6ec9a8f](https://github.com/NativeScript/ios/commit/6ec9a8fe7888780d7394a1e21c1041619212be1f)) + + + +## [8.7.2](https://github.com/NativeScript/ios/compare/v8.7.1...v8.7.2) (2024-05-16) + + +### Bug Fixes + +* **ios:** watchOS embedded apps ([#250](https://github.com/NativeScript/ios/issues/250)) ([1df9ea2](https://github.com/NativeScript/ios/commit/1df9ea20b6bfde5163b0486e444e5471fb8343b2)) + + + +## [8.7.1](https://github.com/NativeScript/ios/compare/v8.7.0...v8.7.1) (2024-04-26) + + +### Bug Fixes + +* url href ([#252](https://github.com/NativeScript/ios/issues/252)) ([4a6e9ad](https://github.com/NativeScript/ios/commit/4a6e9adde6950e09ac0c2fd2713e25aa919ad448)) +* Xcode 15.3+ not setting TARGET_OS_IOS correctly ([#248](https://github.com/NativeScript/ios/issues/248)) ([74e1444](https://github.com/NativeScript/ios/commit/74e144432bf17cc043d0e64affc9cb1703e80832)) + + + +# [8.7.0](https://github.com/NativeScript/ios/compare/v8.6.3...v8.7.0) (2024-04-08) + + +### Bug Fixes + +* only generate metadata for the targeted arch ([#236](https://github.com/NativeScript/ios/issues/236)) ([17a5c5f](https://github.com/NativeScript/ios/commit/17a5c5ff118c2803c0385891224fb30168268ac8)) +* Xcode 15.3+ not setting TARGET_OS_IPHONE correctly ([#242](https://github.com/NativeScript/ios/issues/242)) ([0d52056](https://github.com/NativeScript/ios/commit/0d52056fdb102f40887abd47c9bc2af5f3cca94e)) + + +### Features + +* upgrade llvm to 15.0.7 ([#238](https://github.com/NativeScript/ios/issues/238)) ([6e9b51e](https://github.com/NativeScript/ios/commit/6e9b51e48c6b8ddf65c6669a035b97e5d935f202)) +* **visionos:** support for xros platform ([#235](https://github.com/NativeScript/ios/issues/235)) ([bb364f9](https://github.com/NativeScript/ios/commit/bb364f9558c336c43a9c43d3ded46ef1ad8e8bf3)) +* **WinterCG:** URL & URLSearchParams ([#234](https://github.com/NativeScript/ios/issues/234)) ([dc3c76f](https://github.com/NativeScript/ios/commit/dc3c76f1ff74bcd5b800df55210855871bb70563)) + + + +## [8.6.3](https://github.com/NativeScript/ios/compare/v8.6.2...v8.6.3) (2023-11-08) + + +### Bug Fixes + +* prevent crashes during isolate disposal ([3d70c11](https://github.com/NativeScript/ios/commit/3d70c110e1429a1d62c9b9e23020cf7044635511)) + + + +## [8.6.2](https://github.com/NativeScript/ios/compare/v8.6.1...v8.6.2) (2023-11-01) + + +### Bug Fixes + +* only reset timer persistent if Isolate is valid ([4379583](https://github.com/NativeScript/ios/commit/4379583fc0b2fa3eacde50eb471086f55c1eec18)) + + + +## [8.6.0](https://github.com/NativeScript/ios/compare/v8.5.2...v8.6.1) (2023-10-09) + + +### Bug Fixes + +* bridge release adapters ([#224](https://github.com/NativeScript/ios/issues/224)) ([70b1802](https://github.com/NativeScript/ios/commit/70b180202dc0752d01ae5b9249cbaabae65f53cc)) +* delay isolate disposal when isolate is in use ([5a6c2ee](https://github.com/NativeScript/ios/commit/5a6c2ee5efa0c557c94ae56da0d3b3a31911d1b8)) +* don't suppress timer exceptions ([0c4b819](https://github.com/NativeScript/ios/commit/0c4b819941b0327e572772018298cf9cf181436e)) +* fix setInterval not repeating correctly ([022893f](https://github.com/NativeScript/ios/commit/022893f1dcd9a7649db73e9735ff12e9246b3585)) +* prevent JS function to native block leak ([#223](https://github.com/NativeScript/ios/issues/223)) ([a6d7332](https://github.com/NativeScript/ios/commit/a6d73323718a1de12c5a9f4865a6abfe06fd6e03)) + + +### Features + +* add interop.stringFromCString ([#228](https://github.com/NativeScript/ios/issues/228)) ([185c12d](https://github.com/NativeScript/ios/commit/185c12dc85e86747f266867fb208c71caf5fc6b3)) +* add native timers ([#221](https://github.com/NativeScript/ios/issues/221)) ([119470f](https://github.com/NativeScript/ios/commit/119470f249c5aa85c4c2d0b1c9b5b691003c1ec7)) +* add timer strong retainer annotation ([efef961](https://github.com/NativeScript/ios/commit/efef961a67519aed881637ac0291894f3325b111)) +* log the fullMessage with more details about the error ([#229](https://github.com/NativeScript/ios/issues/229)) ([d67588c](https://github.com/NativeScript/ios/commit/d67588cb3866212ccd86b105edf1207fddde2db9)) +* use node logic for globals and modules ([#215](https://github.com/NativeScript/ios/issues/215)) ([a66cc42](https://github.com/NativeScript/ios/commit/a66cc42c768ee7712d1c1f441b8c4e8e88a19eca)) + + + ## [8.5.2](https://github.com/NativeScript/ios/compare/v8.5.1...v8.5.2) (2023-05-24) diff --git a/FINALIZER_DRAIN_DEFERRAL.md b/FINALIZER_DRAIN_DEFERRAL.md new file mode 100644 index 00000000..2b306cdc --- /dev/null +++ b/FINALIZER_DRAIN_DEFERRAL.md @@ -0,0 +1,111 @@ +# Deferring the finalizer drain out of the GC epilogue + +Status: **DEFERRED** — not implemented. The husk-hardening (`tns::GetValueOrReport`) and +the `IterateFinalizerHandlesAsRoots` pending-bit guard were prioritized instead as the +likely fixes for the field crash (BLACKOUT-V3-IOS-41/42, +`ConcurrentMarkingVisitor::RecordSlot` / `MainMarkingVisitor::RecordSlot`, fault addresses +all `<256 KiB page base> | 1`). This note records the design and its constraints for when +the drain move is picked up. + +Background: [docs/knowledge/v8-resurrecting-finalizers.md](docs/knowledge/v8-resurrecting-finalizers.md). +Today `GlobalHandles::InvokeFinalizerCallbacks()` runs inside the GC epilogue +(`PostGarbageCollectionProcessing`), under an `AllowJavascriptExecution` lift, because +finalizers re-enter JS (`DisposeValue` → `-dealloc` → JS overrides). The proposal was to +run the drain from a posted foreground task instead, deleting the lift and the whole +"JS + nested GC inside `Heap::CollectGarbage`" hazard class. + +## Why it was deferred: "cycles are resolved by early release" + +The concern: JS↔ObjC cycles (wrapper W owns native N; N natively retains a JS-backed +object that leads back to W) only collect because disposal is driven by **native retain +count**, not JS reachability — W's finalizer releases N even though surviving JS may still +reach W, and the release cascade is what unwinds the cycle. + +**Analysis: deferral does not change those semantics.** The same callbacks make the same +protect/release decisions; only *when* they run changes. A deferred drain still releases +N, N's dealloc still drops its retains, and the next GC still queues the newly +unprotected handles. Cycle resolution is latency-shifted (one runloop turn per cascade +step, worst case), not broken. + +What genuinely depends on the drain being synchronous with the GC is **promptness**, in +exactly two scenarios: + +1. **Memory pressure.** `Heap::CollectAllAvailableGarbage` loops up to 7 attempts until + nothing more frees. With the epilogue drain, each round's finalizers release native + memory *inside the loop*, so round N+1 reclaims what round N unblocked. Deferred, + every pending finalizer is a strong root, rounds 2–7 free nothing native, and no + native memory is released until the runloop turns — under a jetsam-adjacent memory + warning that latency can kill the process. +2. **Long synchronous JS.** Allocation-pressure full GCs during a heavy synchronous + stretch never reach the runloop; pending finalizers pile up as strong roots and + interop temporaries are unreclaimable until the JS yields. + +Steady-state disposal latency (one extra turn) is invisible. + +## The design to revisit: hybrid, mirroring upstream + +V8 already encodes this exact trade-off for second-pass phantom callbacks, ten lines +below our drain (`global-handles.cc:1002` @ 14.9.207.39): + +```cpp +const bool synchronous_second_pass = + isolate_->MemorySaverModeEnabled() || v8_flags.predictable || + isolate_->heap()->IsTearingDown() || + (gc_callback_flags & + (kGCCallbackFlagForced | kGCCallbackFlagCollectAllAvailableGarbage | + kGCCallbackFlagSynchronousPhantomCallbackProcessing)) != 0; +``` + +Mirror it for the finalizer drain: + +- **Default: defer** to a posted foreground task. The drain then runs in an ordinary JS + context — no `AllowJavascriptExecution` lift, no nested-GC-inside-the-epilogue. +- **Synchronous (keeping the lift) only when V8 itself goes synchronous**: + `kGCCallbackFlagCollectAllAvailableGarbage`, teardown, and *debatably* + `kGCCallbackFlagForced`. + +### Caveats + +- **`gc()` always passes `kGCCallbackFlagForced`** (`gc-extension.cc:204`), and the + Blackout app currently calls `gc()` from a timer (`Utils.queueGC`) — every crash stack + in the field goes through `GCExtension::GC`. If plain Forced stays on the synchronous + path, the hazardous epilogue drain remains the *hot* path in production. Either exclude + plain Forced from the sync set (a `gc()` caller cannot observe native release + synchronously anyway — nothing reachable from JS dies), or pair the change with + removing the app-side `gc()` timer. +- **Scenario 2 (sync-JS starvation) needs its own trigger** if it matters in practice: + `Isolate::RequestInterrupt` fires at JS safepoints on the JS thread, where JS execution + is legal (the inspector's pause-on-interrupt runs a nested message loop from there). + Post a task *and* an interrupt; whichever fires first drains. Needs separate + validation: stack-depth headroom for `-dealloc` → JS chains, reentrancy. Follow-up, + not a blocker. +- **The `IterateFinalizerHandlesAsRoots()` pending-bit guard is load-bearing here, not + hardening.** Deferral widens the window between queueing and draining to a full + runloop turn of arbitrary JS; any GC in that window iterates `pending_finalizers_` + and must skip entries whose bit was cleared (freed or re-armed nodes). The patch + already skips and compacts stale entries — keep that behaviour when reworking the + drain. +- **Teardown** needs a synchronous final drain (`~Runtime` / `DisposeAllRegistered`). +- Ordering relative to second-pass callbacks and Heap epilogue callbacks changes; + nothing known to depend on it, but re-check when implementing. + +## What this does NOT fix + +- The **husk hazard** (a finalized object outliving its native half — the n1→n2 pair in + the knowledge doc). That is created at `IdentifyDeadFinalizerHandles()` snapshot time, + before any drain, and is unaffected by drain timing. The checked-accessor hardening in + the runtime is the fix for that, and is the prime suspect for the field crash. +- Anything the reachability redesign + ([RESURRECTION_TO_REACHABILITY.md](RESURRECTION_TO_REACHABILITY.md)) addresses. That + remains the endgame — tracing collects cycles without early release at all — and this + hybrid is compatible scaffolding until then. + +## Validation plan when picked up + +1. TestRunner suite green with the drain deferred (default path). +2. A memory-pressure test: allocate wrapper-heavy garbage, trigger + `CollectAllAvailableGarbage` (low-memory notification), assert native memory is + reclaimed without a runloop turn. +3. Worker teardown specs (synchronous final drain). +4. Soak on a checked V8 build (`dcheck_always_on=true v8_enable_verify_heap=true`) with + `--verify-heap --stress-incremental-marking --stress-concurrent-marking`. diff --git a/NativeScript/JSIRuntime.h b/NativeScript/JSIRuntime.h index 110d565e..8cfb636a 100644 --- a/NativeScript/JSIRuntime.h +++ b/NativeScript/JSIRuntime.h @@ -6,6 +6,7 @@ // Copyright © 2022 Progress. All rights reserved. // +#pragma once #import #import "v8runtime/V8Runtime.h" #include "runtime/Runtime.h" diff --git a/NativeScript/NativeScript-Prefix.pch b/NativeScript/NativeScript-Prefix.pch index 6623fa25..0082aa76 100644 --- a/NativeScript/NativeScript-Prefix.pch +++ b/NativeScript/NativeScript-Prefix.pch @@ -1,7 +1,7 @@ #ifndef NativeScript_Prefix_pch #define NativeScript_Prefix_pch -#define NATIVESCRIPT_VERSION "8.5.2-alpha.3" +#define NATIVESCRIPT_VERSION "9.0.4-dev.2" #ifdef DEBUG #define SIZEOF_OFF_T 8 diff --git a/NativeScript/NativeScript.h b/NativeScript/NativeScript.h index a8912188..f9bcc9f1 100644 --- a/NativeScript/NativeScript.h +++ b/NativeScript/NativeScript.h @@ -15,6 +15,10 @@ @interface NativeScript : NSObject - (instancetype)initWithConfig:(Config*)config; +- (void)runScriptString: (NSString*) script runLoop: (BOOL) runLoop; +- (void)restartWithConfig:(Config*)config; +- (void)shutdownRuntime; + /** WARNING: this method does not return in most applications. (UIApplicationMain) */ diff --git a/NativeScript/NativeScript.mm b/NativeScript/NativeScript.mm index 5e7fd101..caf37186 100644 --- a/NativeScript/NativeScript.mm +++ b/NativeScript/NativeScript.mm @@ -1,15 +1,17 @@ -#include #include "NativeScript.h" +#include #include "inspector/JsV8InspectorClient.h" #include "runtime/Console.h" -#include "runtime/RuntimeConfig.h" #include "runtime/Helpers.h" #include "runtime/Runtime.h" +#include "runtime/RuntimeConfig.h" #include "runtime/Tasks.h" using namespace v8; using namespace tns; +namespace tns {} + @implementation Config @synthesize BaseDir; @@ -21,63 +23,99 @@ @implementation Config @implementation NativeScript -std::unique_ptr runtime_; +extern char defaultStartOfMetadataSection __asm("section$start$__DATA$__TNSMetadata"); -- (instancetype)initWithConfig:(Config*)config { - - if (self = [super init]) { - RuntimeConfig.BaseDir = [config.BaseDir UTF8String]; - if (config.ApplicationPath != nil) { - RuntimeConfig.ApplicationPath = [[config.BaseDir stringByAppendingPathComponent:config.ApplicationPath] UTF8String]; - } else { - RuntimeConfig.ApplicationPath = [[config.BaseDir stringByAppendingPathComponent:@"app"] UTF8String]; - } - RuntimeConfig.MetadataPtr = [config MetadataPtr]; - RuntimeConfig.IsDebug = [config IsDebug]; - RuntimeConfig.LogToSystemConsole = [config LogToSystemConsole]; - - Runtime::Initialize(); - runtime_ = nullptr; - runtime_ = std::make_unique(); - - std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); - Isolate* isolate = runtime_->CreateIsolate(); - v8::Locker l(isolate); - runtime_->Init(isolate); - std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now(); - auto duration = std::chrono::duration_cast(t2 - t1).count(); - printf("Runtime initialization took %llims (version %s, V8 version %s)\n", duration, NATIVESCRIPT_VERSION, V8::GetVersion()); - - if (config.IsDebug) { - Isolate::Scope isolate_scope(isolate); - HandleScope handle_scope(isolate); - v8_inspector::JsV8InspectorClient* inspectorClient = new v8_inspector::JsV8InspectorClient(runtime_.get()); - inspectorClient->init(); - inspectorClient->registerModules(); - inspectorClient->connect([config ArgumentsCount], [config Arguments]); - Console::AttachInspectorClient(inspectorClient); - } - } - - return self; - +- (void)runScriptString:(NSString*)script runLoop:(BOOL)runLoop { + std::string cppString = std::string([script UTF8String]); + runtime_->RunScript(cppString); + + if (runLoop) { + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); + } + + tns::Tasks::Drain(); } -- (void)runMainApplication { - runtime_->RunMainScript(); +std::unique_ptr runtime_; - CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); +- (void)runMainApplication { + runtime_->RunMainScript(); - tns::Tasks::Drain(); + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); + tns::Tasks::Drain(); } - (bool)liveSync { - if (runtime_ == nullptr) { - return false; + if (runtime_ == nullptr) { + return false; + } + + Isolate* isolate = runtime_->GetIsolate(); + return tns::LiveSync(isolate); +} + +- (void)shutdownRuntime { + if (RuntimeConfig.IsDebug) { + Console::DetachInspectorClient(); + } + tns::Tasks::ClearTasks(); + if (runtime_ != nullptr) { + runtime_ = nullptr; + } +} + +- (instancetype)initializeWithConfig:(Config*)config { + if (self = [super init]) { + RuntimeConfig.BaseDir = [config.BaseDir UTF8String]; + if (config.ApplicationPath != nil) { + RuntimeConfig.ApplicationPath = + [[config.BaseDir stringByAppendingPathComponent:config.ApplicationPath] UTF8String]; + } else { + RuntimeConfig.ApplicationPath = + [[config.BaseDir stringByAppendingPathComponent:@"app"] UTF8String]; } + if (config.MetadataPtr != nil) { + RuntimeConfig.MetadataPtr = [config MetadataPtr]; + } else { + RuntimeConfig.MetadataPtr = &defaultStartOfMetadataSection; + } + RuntimeConfig.IsDebug = [config IsDebug]; + RuntimeConfig.LogToSystemConsole = [config LogToSystemConsole]; + + Runtime::Initialize(); + runtime_ = nullptr; + runtime_ = std::make_unique(); + + std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); + Isolate* isolate = runtime_->CreateIsolate(); + v8::Locker l(isolate); + runtime_->Init(isolate); + std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast(t2 - t1).count(); + printf("Runtime initialization took %llims (version %s, V8 version %s)\n", duration, + NATIVESCRIPT_VERSION, V8::GetVersion()); + + if (config.IsDebug) { + Isolate::Scope isolate_scope(isolate); + HandleScope handle_scope(isolate); + v8_inspector::JsV8InspectorClient* inspectorClient = + new v8_inspector::JsV8InspectorClient(runtime_.get()); + inspectorClient->init(); + inspectorClient->registerModules(); + inspectorClient->connect([config ArgumentsCount], [config Arguments]); + Console::AttachInspectorClient(inspectorClient); + } + } + return self; +} + +- (instancetype)initWithConfig:(Config*)config { + return [self initializeWithConfig:config]; +} - Isolate* isolate = runtime_->GetIsolate(); - return tns::LiveSync(isolate); +- (void)restartWithConfig:(Config*)config { + [self shutdownRuntime]; + [self initializeWithConfig:config]; } @end diff --git a/NativeScript/ada/LICENSE-APACHE b/NativeScript/ada/LICENSE-APACHE new file mode 100644 index 00000000..6f231e7c --- /dev/null +++ b/NativeScript/ada/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2023 Yagiz Nizipli and Daniel Lemire + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/NativeScript/ada/LICENSE-MIT b/NativeScript/ada/LICENSE-MIT new file mode 100644 index 00000000..ed3bee60 --- /dev/null +++ b/NativeScript/ada/LICENSE-MIT @@ -0,0 +1,18 @@ +Copyright 2023 Yagiz Nizipli and Daniel Lemire + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/NativeScript/ada/ada.cpp b/NativeScript/ada/ada.cpp new file mode 100644 index 00000000..fd558881 --- /dev/null +++ b/NativeScript/ada/ada.cpp @@ -0,0 +1,15486 @@ +/* auto-generated on 2026-07-27 16:10:09 -0400. Do not edit! */ +/* begin file src/ada.cpp */ +#include "ada.h" +/* begin file src/checkers.cpp */ + +#include +#include +#include + +namespace ada::checkers { + +ada_really_inline constexpr bool is_ipv4(std::string_view view) noexcept { + // The string is not empty and does not contain upper case ASCII characters. + // + // Optimization. To be considered as a possible ipv4, the string must end + // with 'x' or a lowercase hex character. + // Most of the time, this will be false so this simple check will save a lot + // of effort. + // If the address ends with a dot, we need to prune it (special case). + if (view.ends_with('.')) { + view.remove_suffix(1); + if (view.empty()) { + return false; + } + } + char last_char = view.back(); + bool possible_ipv4 = (last_char >= '0' && last_char <= '9') || + (last_char >= 'a' && last_char <= 'f') || + last_char == 'x'; + if (!possible_ipv4) { + return false; + } + // From the last character, find the last dot. + size_t last_dot = view.rfind('.'); + if (last_dot != std::string_view::npos) { + // We have at least one dot. + view.remove_prefix(last_dot + 1); + } + /** Optimization opportunity: we have basically identified the last number of + the ipv4 if we return true here. We might as well parse it and have at + least one number parsed when we get to parse_ipv4. */ + if (std::ranges::all_of(view, ada::checkers::is_digit)) { + return true; + } + // It could be hex (0x), but not if there is a single character. + if (view.size() == 1) { + return false; + } + // It must start with 0x. + if (!view.starts_with("0x")) { + return false; + } + // We must allow "0x". + if (view.size() == 2) { + return true; + } + // We have 0x followed by some characters, we need to check that they are + // hexadecimals. + view.remove_prefix(2); + return std::ranges::all_of(view, ada::unicode::is_lowercase_hex); +} + +// for use with path_signature, we include all characters that need percent +// encoding. +static constexpr std::array path_signature_table = + []() consteval { + std::array result{}; + for (size_t i = 0; i < 256; i++) { + if (i <= 0x20 || i == 0x22 || i == 0x23 || i == 0x3c || i == 0x3e || + i == 0x3f || i == 0x5e || i == 0x60 || i == 0x7b || i == 0x7d || + i > 0x7e) { + result[i] = 1; + } else if (i == 0x25) { + result[i] = 8; + } else if (i == 0x2e) { + result[i] = 4; + } else if (i == 0x5c) { + result[i] = 2; + } else { + result[i] = 0; + } + } + return result; + }(); + +ada_really_inline constexpr uint8_t path_signature( + std::string_view input) noexcept { + // The path percent-encode set is the query percent-encode set and U+003F (?), + // U+0060 (`), U+007B ({), and U+007D (}). The query percent-encode set is the + // C0 control percent-encode set and U+0020 SPACE, U+0022 ("), U+0023 (#), + // U+003C (<), and U+003E (>). The C0 control percent-encode set are the C0 + // controls and all code points greater than U+007E (~). + size_t i = 0; + uint8_t accumulator{}; + for (; i + 7 < input.size(); i += 8) { + accumulator |= uint8_t(path_signature_table[uint8_t(input[i])] | + path_signature_table[uint8_t(input[i + 1])] | + path_signature_table[uint8_t(input[i + 2])] | + path_signature_table[uint8_t(input[i + 3])] | + path_signature_table[uint8_t(input[i + 4])] | + path_signature_table[uint8_t(input[i + 5])] | + path_signature_table[uint8_t(input[i + 6])] | + path_signature_table[uint8_t(input[i + 7])]); + } + for (; i < input.size(); i++) { + accumulator |= uint8_t(path_signature_table[uint8_t(input[i])]); + } + return accumulator; +} + +ada_really_inline constexpr bool verify_dns_length( + std::string_view input) noexcept { + if (input.empty()) return false; + if (input.back() == '.') { + if (input.size() > 254) return false; + } else if (input.size() > 253) + return false; + + size_t start = 0; + while (start < input.size()) { + auto dot_location = input.find('.', start); + // If not found, it's likely the end of the domain + if (dot_location == std::string_view::npos) dot_location = input.size(); + + auto label_size = dot_location - start; + if (label_size > 63 || label_size == 0) return false; + + start = dot_location + 1; + } + + return true; +} + +} // namespace ada::checkers +/* end file src/checkers.cpp */ +/* begin file src/unicode.cpp */ + + +ADA_PUSH_DISABLE_ALL_WARNINGS +/* begin file src/ada_idna.cpp */ +/* auto-generated on 2026-07-12 20:34:08 -0400. Do not edit! */ +/* begin file src/idna.cpp */ +/* begin file src/unicode_transcoding.cpp */ +/* begin file include/ada/idna/unicode_transcoding.h */ +#ifndef ADA_IDNA_UNICODE_TRANSCODING_H +#define ADA_IDNA_UNICODE_TRANSCODING_H + +#include +#include + +namespace ada::idna { + +size_t utf8_to_utf32(const char* buf, size_t len, char32_t* utf32_output); + +size_t utf8_length_from_utf32(const char32_t* buf, size_t len); + +size_t utf32_length_from_utf8(const char* buf, size_t len); + +size_t utf32_to_utf8(const char32_t* buf, size_t len, char* utf8_output); + +} // namespace ada::idna + +#endif // ADA_IDNA_UNICODE_TRANSCODING_H +/* end file include/ada/idna/unicode_transcoding.h */ + +#include +#include +#include + +namespace ada::idna { + +size_t utf8_to_utf32(const char* buf, size_t len, char32_t* utf32_output) { + const uint8_t* data = reinterpret_cast(buf); + size_t pos = 0; + const char32_t* start{utf32_output}; + while (pos < len) { + // try to convert the next block of 16 ASCII bytes + if (pos + 16 <= len) { // if it is safe to read 16 more + // bytes, check that they are ascii + uint64_t v1; + std::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2; + std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; + if ((v & 0x8080808080808080) == 0) { + size_t final_pos = pos + 16; + while (pos < final_pos) { + *utf32_output++ = char32_t(buf[pos]); + pos++; + } + continue; + } + } + uint8_t leading_byte = data[pos]; // leading byte + if (leading_byte < 0b10000000) { + // converting one ASCII byte !!! + *utf32_output++ = char32_t(leading_byte); + pos++; + } else if ((leading_byte & 0b11100000) == 0b11000000) { + // We have a two-byte UTF-8 + if (pos + 1 >= len) { + return 0; + } // minimal bound checking + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return 0; + } + // range check + uint32_t code_point = + (leading_byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111); + if (code_point < 0x80 || 0x7ff < code_point) { + return 0; + } + *utf32_output++ = char32_t(code_point); + pos += 2; + } else if ((leading_byte & 0b11110000) == 0b11100000) { + // We have a three-byte UTF-8 + if (pos + 2 >= len) { + return 0; + } // minimal bound checking + + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return 0; + } + if ((data[pos + 2] & 0b11000000) != 0b10000000) { + return 0; + } + // range check + uint32_t code_point = (leading_byte & 0b00001111) << 12 | + (data[pos + 1] & 0b00111111) << 6 | + (data[pos + 2] & 0b00111111); + if (code_point < 0x800 || 0xffff < code_point || + (0xd7ff < code_point && code_point < 0xe000)) { + return 0; + } + *utf32_output++ = char32_t(code_point); + pos += 3; + } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 + // we have a 4-byte UTF-8 word. + if (pos + 3 >= len) { + return 0; + } // minimal bound checking + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return 0; + } + if ((data[pos + 2] & 0b11000000) != 0b10000000) { + return 0; + } + if ((data[pos + 3] & 0b11000000) != 0b10000000) { + return 0; + } + + // range check + uint32_t code_point = (leading_byte & 0b00000111) << 18 | + (data[pos + 1] & 0b00111111) << 12 | + (data[pos + 2] & 0b00111111) << 6 | + (data[pos + 3] & 0b00111111); + if (code_point <= 0xffff || 0x10ffff < code_point) { + return 0; + } + *utf32_output++ = char32_t(code_point); + pos += 4; + } else { + return 0; + } + } + return utf32_output - start; +} + +size_t utf8_length_from_utf32(const char32_t* buf, size_t len) { + // We are not BOM aware. + const uint32_t* p = reinterpret_cast(buf); + size_t counter{0}; + for (size_t i = 0; i != len; ++i) { + ++counter; // ASCII + counter += static_cast(p[i] > 0x7F); // two-byte + counter += static_cast(p[i] > 0x7FF); // three-byte + counter += static_cast(p[i] > 0xFFFF); // four-bytes + } + return counter; +} + +size_t utf32_length_from_utf8(const char* buf, size_t len) { + const int8_t* p = reinterpret_cast(buf); + return std::count_if(p, std::next(p, len), [](int8_t c) { + // -65 is 0b10111111, anything larger in two-complement's + // should start a new code point. + return c > -65; + }); +} + +size_t utf32_to_utf8(const char32_t* buf, size_t len, char* utf8_output) { + const uint32_t* data = reinterpret_cast(buf); + size_t pos = 0; + const char* start{utf8_output}; + while (pos < len) { + // try to convert the next block of 2 ASCII characters + if (pos + 2 <= len) { // if it is safe to read 8 more + // bytes, check that they are ascii + uint64_t v; + std::memcpy(&v, data + pos, sizeof(uint64_t)); + if ((v & 0xFFFFFF80FFFFFF80) == 0) { + *utf8_output++ = char(buf[pos]); + *utf8_output++ = char(buf[pos + 1]); + pos += 2; + continue; + } + } + uint32_t word = data[pos]; + if ((word & 0xFFFFFF80) == 0) { + // will generate one UTF-8 bytes + *utf8_output++ = char(word); + pos++; + } else if ((word & 0xFFFFF800) == 0) { + // will generate two UTF-8 bytes + // we have 0b110XXXXX 0b10XXXXXX + *utf8_output++ = char((word >> 6) | 0b11000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); + pos++; + } else if ((word & 0xFFFF0000) == 0) { + // will generate three UTF-8 bytes + // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX + if (word >= 0xD800 && word <= 0xDFFF) { + return 0; + } + *utf8_output++ = char((word >> 12) | 0b11100000); + *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); + pos++; + } else { + // will generate four UTF-8 bytes + // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX + // 0b10XXXXXX + if (word > 0x10FFFF) { + return 0; + } + *utf8_output++ = char((word >> 18) | 0b11110000); + *utf8_output++ = char(((word >> 12) & 0b111111) | 0b10000000); + *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); + pos++; + } + } + return utf8_output - start; +} +} // namespace ada::idna +/* end file src/unicode_transcoding.cpp */ +/* begin file src/mapping.cpp */ +/* begin file include/ada/idna/mapping.h */ +#ifndef ADA_IDNA_MAPPING_H +#define ADA_IDNA_MAPPING_H + +#include +#include + +namespace ada::idna { + +// If the input is ascii, then the mapping is just -> lower case. +void ascii_map(char* input, size_t length); +// Map the characters according to IDNA, returning the empty string on error. +std::u32string map(std::u32string_view input); +// Map into an existing buffer (cleared on entry). Returns false if any code +// point is disallowed. Reusing the buffer avoids repeated heap allocations +// when called in a loop over multiple labels. +bool map(std::u32string_view input, std::u32string& out); + +} // namespace ada::idna + +#endif +/* end file include/ada/idna/mapping.h */ + +#include +#include +#include +#include + +/* begin file src/table_store.hpp */ +// Runtime store for compressed Unicode/IDNA tables. +// Large tables are DEFLATE-compressed (read-only) and expanded once on first +// use into a heap buffer so the working set does not bloat the on-disk binary. +// Hot-path lookups use the same O(1) multi-stage layout as the pre-compression +// code; compression only affects on-disk size and one-time init. +// +// Thread-safe without mutex: atomic CAS + spin-wait. ensure_tables() returns +// false if initialization fails (OOM, corrupt blob); callers must treat that +// as a hard error and not touch table pointers. + +/* begin file src/raw_inflate.hpp */ +// Minimal raw DEFLATE inflater (RFC 1951), enough for zlib raw streams. +// Returns number of output bytes written, or 0 on failure. +#include +#include + +namespace ada::idna::deflate { + +struct BitReader { + const uint8_t* p; + const uint8_t* end; + uint32_t acc = 0; + int bits = 0; + + explicit BitReader(const uint8_t* data, size_t len) + : p(data), end(data + len) {} + + bool ensure(int n) { + while (bits < n) { + if (p >= end) return false; + acc |= uint32_t(*p++) << bits; + bits += 8; + } + return true; + } + uint32_t get(int n) { + if (!ensure(n)) return UINT32_MAX; + uint32_t v = acc & ((1u << n) - 1); + acc >>= n; + bits -= n; + return v; + } + void align_byte() { + acc >>= (bits & 7); + bits -= (bits & 7); + } +}; + +struct Huff { + // canonical codes: for each length, list of symbols + // Fast path: table for codes up to max_bits + static constexpr int MAXBITS = 15; + uint8_t lengths[288]{}; + int counts[MAXBITS + 1]{}; + int first_code[MAXBITS + 1]{}; + int16_t symbols[288]{}; + int nsymbols = 0; + int max_bits = 0; + + // Base index into symbols[] for each code length (used by decode). + int base_idx[MAXBITS + 1]{}; + + bool build(const uint8_t* lens, int n) { + std::memset(counts, 0, sizeof(counts)); + std::memset(first_code, 0, sizeof(first_code)); + std::memset(base_idx, 0, sizeof(base_idx)); + nsymbols = n; + max_bits = 0; + for (int i = 0; i < n; i++) { + lengths[i] = lens[i]; + if (lens[i]) { + counts[lens[i]]++; + if (lens[i] > max_bits) max_bits = lens[i]; + } + } + // Canonical first code for each bit length (RFC 1951). + int code = 0; + for (int bits = 1; bits <= MAXBITS; bits++) { + code = (code + counts[bits - 1]) << 1; + first_code[bits] = code; + } + int idx = 0; + for (int bits = 1; bits <= max_bits; bits++) { + base_idx[bits] = idx; + // assign symbols in symbol order for codes of this length + for (int sym = 0; sym < n; sym++) { + if (lengths[sym] == bits) { + symbols[idx++] = static_cast(sym); + } + } + } + return true; + } + + int decode(BitReader& br) const { + if (max_bits == 0) return -1; + int code = 0; + for (int len = 1; len <= max_bits; len++) { + uint32_t b = br.get(1); + if (b == UINT32_MAX) return -1; + code = (code << 1) | int(b); + int first = first_code[len]; + int cnt = counts[len]; + if (cnt && code - first < cnt) { + return symbols[base_idx[len] + (code - first)]; + } + } + return -1; + } +}; + +// Fixed Huffman tables are built once at dynamic initialization (before main / +// single-threaded), so concurrent first-use of inflate cannot race. +inline Huff make_fixed_litlen_huff() { + Huff h; + uint8_t lens[288]; + // Fixed Huffman: 0-143:8, 144-255:9, 256-279:7, 280-287:8 + for (int i = 0; i <= 143; i++) lens[i] = 8; + for (int i = 144; i <= 255; i++) lens[i] = 9; + for (int i = 256; i <= 279; i++) lens[i] = 7; + for (int i = 280; i <= 287; i++) lens[i] = 8; + h.build(lens, 288); + return h; +} + +inline Huff make_fixed_dist_huff() { + Huff h; + uint8_t lens[32]; + for (int i = 0; i < 32; i++) lens[i] = 5; + h.build(lens, 32); + return h; +} + +// NOLINTNEXTLINE(cert-err58-cpp) -- intentional process-lifetime tables +inline const Huff kFixedLitLenHuff = make_fixed_litlen_huff(); +// NOLINTNEXTLINE(cert-err58-cpp) +inline const Huff kFixedDistHuff = make_fixed_dist_huff(); + +inline int fixed_litlen(BitReader& br) { return kFixedLitLenHuff.decode(br); } + +inline int fixed_dist(BitReader& br) { return kFixedDistHuff.decode(br); } + +// length and distance base tables +static const uint16_t len_base[29] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, + 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258}; +static const uint8_t len_extra[29] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, 0}; +static const uint16_t dist_base[30] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, + 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, + 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; +static const uint8_t dist_extra[30] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, + 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, + 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; + +inline size_t inflate_raw(const uint8_t* src, size_t src_len, uint8_t* dst, + size_t dst_cap) { + BitReader br(src, src_len); + size_t out = 0; + for (;;) { + uint32_t bfinal = br.get(1); + uint32_t btype = br.get(2); + if (bfinal == UINT32_MAX || btype == UINT32_MAX) return 0; + if (btype == 0) { + // stored + br.align_byte(); + if (!br.ensure(16)) return 0; + // read 16+16 from bit buffer awkwardly - use byte path + // Align: bits is multiple of 8 + // Get len from remaining bits then bytes + uint32_t len = br.get(16); + uint32_t nlen = br.get(16); + if (len == UINT32_MAX || nlen == UINT32_MAX) return 0; + if ((len ^ 0xFFFF) != nlen) return 0; + // After get, may have bits in acc from previous - for stored, should be + // byte aligned Copy len bytes from p + if (br.bits != 0) { + // leftover bits should be 0 if aligned + } + if (size_t(br.end - br.p) < len) return 0; + if (out + len > dst_cap) return 0; + std::memcpy(dst + out, br.p, len); + br.p += len; + out += len; + } else if (btype == 1 || btype == 2) { + Huff lit, dist; + if (btype == 1) { + // use fixed via functions + } else { + // dynamic + uint32_t hlit = br.get(5); + if (hlit == UINT32_MAX) return 0; + hlit += 257; + uint32_t hdist = br.get(5); + if (hdist == UINT32_MAX) return 0; + hdist += 1; + uint32_t hclen = br.get(4); + if (hclen == UINT32_MAX) return 0; + hclen += 4; + static const int order[19] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, + 11, 4, 12, 3, 13, 2, 14, 1, 15}; + uint8_t clen[19]{}; + for (uint32_t i = 0; i < hclen; i++) { + uint32_t v = br.get(3); + if (v == UINT32_MAX) return 0; + clen[order[i]] = uint8_t(v); + } + Huff cl; + if (!cl.build(clen, 19)) return 0; + uint8_t lens[288 + 32]{}; + uint32_t n = hlit + hdist; + for (uint32_t i = 0; i < n;) { + int sym = cl.decode(br); + if (sym < 0) return 0; + if (sym < 16) { + lens[i++] = uint8_t(sym); + } else if (sym == 16) { + uint32_t rep = br.get(2); + if (rep == UINT32_MAX) return 0; + rep += 3; + if (i == 0) return 0; + uint8_t v = lens[i - 1]; + while (rep--) lens[i++] = v; + } else if (sym == 17) { + uint32_t rep = br.get(3); + if (rep == UINT32_MAX) return 0; + rep += 3; + while (rep--) lens[i++] = 0; + } else if (sym == 18) { + uint32_t rep = br.get(7); + if (rep == UINT32_MAX) return 0; + rep += 11; + while (rep--) lens[i++] = 0; + } else + return 0; + } + if (!lit.build(lens, int(hlit))) return 0; + if (!dist.build(lens + hlit, int(hdist))) return 0; + } + for (;;) { + int sym; + if (btype == 1) + sym = fixed_litlen(br); + else + sym = lit.decode(br); + if (sym < 0) return 0; + if (sym < 256) { + if (out >= dst_cap) return 0; + dst[out++] = uint8_t(sym); + } else if (sym == 256) { + break; + } else { + int len_code = sym - 257; + if (len_code < 0 || len_code > 28) return 0; + uint32_t extra = br.get(len_extra[len_code]); + if (len_extra[len_code] && extra == UINT32_MAX) return 0; + uint32_t length = + len_base[len_code] + (len_extra[len_code] ? extra : 0); + int dsym; + if (btype == 1) + dsym = fixed_dist(br); + else + dsym = dist.decode(br); + if (dsym < 0 || dsym > 29) return 0; + uint32_t dextra = br.get(dist_extra[dsym]); + if (dist_extra[dsym] && dextra == UINT32_MAX) return 0; + uint32_t distance = dist_base[dsym] + (dist_extra[dsym] ? dextra : 0); + if (distance > out || out + length > dst_cap) return 0; + for (uint32_t k = 0; k < length; k++) { + dst[out] = dst[out - distance]; + out++; + } + } + } + } else { + return 0; // reserved + } + if (bfinal) break; + } + return out; +} + +} // namespace ada::idna::deflate +/* end file src/raw_inflate.hpp */ +/* begin file src/table_blob.inc */ +// Auto-generated by scripts/pack_tables.py - do not edit. +// Compressed Unicode/IDNA tables (raw DEFLATE). +// clang-format off +#ifndef ADA_IDNA_TABLE_BLOB_H +#define ADA_IDNA_TABLE_BLOB_H +#include +#include +namespace ada::idna::table_blob { +constexpr size_t uncompressed_size = 224608; +constexpr size_t compressed_size = 62377; +constexpr uint32_t uncompressed_crc32 = 0x6F4A6B2Eu; +constexpr size_t decomposition_block_rows = 67; +constexpr size_t decomposition_block_cols = 257; +constexpr size_t ccc_block_rows = 67; +constexpr size_t ccc_block_cols = 256; +constexpr size_t composition_block_rows = 67; +constexpr size_t composition_block_cols = 257; +constexpr size_t id_continue_count = 1418; +constexpr size_t id_start_count = 776; +constexpr size_t dir_table_count = 1449; +constexpr size_t combining_range_count = 290; +// Offsets into the decompressed buffer: +constexpr size_t off_idna_stage1 = 0; +constexpr size_t count_idna_stage1 = 3282; +constexpr size_t off_idna_stage2 = 6564; +constexpr size_t count_idna_stage2 = 11456; +constexpr size_t off_idna_bool_blocks = 29480; +constexpr size_t count_idna_bool_blocks = 225; +constexpr size_t off_idna_utf8_mappings = 31280; +constexpr size_t count_idna_utf8_mappings = 17383; +constexpr size_t off_decomposition_index = 48663; +constexpr size_t count_decomposition_index = 4352; +constexpr size_t off_decomposition_block = 53016; +constexpr size_t count_decomposition_block = 17219; +constexpr size_t off_decomposition_data = 87456; +constexpr size_t count_decomposition_data = 9102; +constexpr size_t off_ccc_index = 123864; +constexpr size_t count_ccc_index = 4352; +constexpr size_t off_ccc_block = 128216; +constexpr size_t count_ccc_block = 17152; +constexpr size_t off_composition_index = 145368; +constexpr size_t count_composition_index = 4352; +constexpr size_t off_composition_block = 149720; +constexpr size_t count_composition_block = 17219; +constexpr size_t off_composition_data = 184160; +constexpr size_t count_composition_data = 1883; +constexpr size_t off_id_continue_flat = 191692; +constexpr size_t count_id_continue_flat = 2836; +constexpr size_t off_id_start_flat = 203036; +constexpr size_t count_id_start_flat = 1552; +constexpr size_t off_dir_start = 209244; +constexpr size_t count_dir_start = 1449; +constexpr size_t off_dir_final = 215040; +constexpr size_t count_dir_final = 1449; +constexpr size_t off_dir_value = 220836; +constexpr size_t count_dir_value = 1449; +constexpr size_t off_combining_flat = 222288; +constexpr size_t count_combining_flat = 580; +alignas(8) inline constexpr uint8_t compressed[] = { +0xec,0x9c,0x09,0x40,0x53,0xc7,0xda,0xfe,0x5f,0x08,0x98,0x28,0x4b,0x4c,0xc2,0x12, +0x14,0x09,0x12,0x42,0x12,0x76,0x12,0x20,0xec,0x09,0xd0,0xdd,0x56,0xdb,0xda,0xdd, +0x5b,0x5b,0x97,0x6a,0xdd,0xad,0xb6,0xda,0xc5,0x96,0x23,0xbb,0xa2,0xe0,0xbe,0xb0, +0x8a,0xa8,0xa8,0x88,0x08,0xa8,0xec,0xcb,0x2d,0x2a,0x62,0xad,0x88,0xa8,0xdd,0xeb, +0x56,0x36,0x6d,0x6b,0x5b,0xdb,0xda,0xd6,0x96,0xfc,0x9f,0x73,0x12,0xd4,0xb6,0xf6, +0xb6,0xb7,0xcb,0xfd,0xbe,0xfb,0xfd,0x9b,0xe1,0x37,0x33,0xe7,0x9c,0x99,0x79,0xde, +0x79,0xcf,0x9c,0x73,0x66,0x4e,0x00,0x62,0x88,0x0c,0xc4,0x50,0x33,0x91,0x85,0xc1, +0x82,0xb1,0x68,0xb6,0x20,0x4b,0x83,0x25,0x63,0x49,0x4c,0xb3,0x25,0xf1,0x0c,0x3c, +0x86,0xd7,0xcc,0x23,0x2b,0x83,0x15,0x63,0xd5,0x6c,0x45,0xd6,0x16,0x8c,0x25,0x63, +0xb0,0x26,0x86,0xc7,0x58,0x31,0xd6,0xcc,0x20,0x86,0xcf,0x08,0x98,0xc1,0xcc,0x10, +0xc6,0x86,0x21,0x86,0xb1,0xb6,0x65,0x9a,0xad,0x69,0x90,0x61,0x90,0x1d,0x63,0xcf, +0x08,0x19,0x66,0xd0,0x50,0x46,0xc4,0x88,0x19,0x09,0xe3,0xc0,0x38,0x32,0x4e,0x8c, +0x33,0x23,0x65,0x5c,0x98,0xe6,0x41,0xc3,0x18,0xe2,0x1b,0xf8,0x0c,0xbf,0x99,0x4f, +0x82,0xe1,0xa8,0x47,0x8c,0x41,0xc0,0x08,0xa0,0x27,0x20,0x6e,0xcb,0x95,0x19,0xc1, +0xb8,0x31,0x32,0xc6,0x9d,0x19,0xc9,0xd0,0x60,0xd3,0xbe,0x1f,0x07,0x0f,0x46,0xce, +0x78,0x32,0x0a,0xc6,0x30,0xd8,0x8b,0x61,0x06,0xcb,0x19,0x25,0xa3,0x62,0xd4,0x8c, +0x37,0xe3,0xc3,0xf8,0x32,0x7e,0x8c,0x3f,0x13,0xc0,0x04,0xa2,0x54,0x10,0xd0,0x30, +0x5a,0x26,0x98,0x69,0x1e,0x1c,0xc2,0xd0,0x10,0xc3,0x10,0x66,0x08,0x54,0x86,0x90, +0x8d,0xc1,0x86,0xb1,0x69,0xb6,0x21,0x5b,0x83,0x2d,0x63,0xdb,0x6c,0x4b,0x76,0x06, +0xbb,0x50,0x86,0xb1,0x6b,0xb6,0x23,0x7b,0xd8,0x62,0x6f,0xd2,0x60,0xcc,0xa9,0x8e, +0x69,0xb6,0x27,0xa1,0x41,0x78,0x2b,0x3b,0x6e,0x15,0x18,0x61,0x33,0x5b,0x76,0x28, +0x31,0x61,0xa6,0xbe,0x0d,0x65,0x86,0x36,0x0f,0x25,0x51,0x38,0x63,0x10,0x45,0x30, +0x91,0xd8,0x13,0xc5,0x30,0xa2,0x66,0x11,0x89,0x0d,0x62,0x46,0xdc,0x2c,0x26,0x49, +0x34,0x63,0x90,0x30,0x92,0x66,0x09,0x39,0x18,0x1c,0x62,0x18,0xc6,0xa1,0xd9,0x81, +0x1c,0x0d,0x8e,0x8c,0x63,0xb3,0x23,0x39,0x19,0x9c,0x7e,0xab,0xee,0xdf,0xe1,0xef, +0xf0,0x77,0xf8,0x6b,0x82,0x9e,0x31,0x5c,0xcf,0xc7,0x32,0x8c,0x53,0xb3,0x53,0x1c, +0x43,0xce,0x06,0x67,0xc6,0xb9,0xd9,0x39,0x9e,0x41,0x9e,0xb9,0x0d,0xdc,0x0e,0xee, +0x60,0xee,0x64,0xee,0x42,0x7a,0x37,0x73,0x0f,0x43,0x52,0x83,0x74,0xd4,0xdf,0xde, +0xfb,0x0b,0xc3,0xbd,0xcc,0x7d,0xcc,0xe8,0xbf,0x03,0x17,0x18,0x69,0xb3,0x94,0x5c, +0x0c,0x2e,0x8c,0x4b,0xb3,0x0b,0x0d,0x33,0x0c,0x63,0x86,0x35,0x0f,0xa3,0xe1,0x86, +0xe1,0xcc,0xf0,0xe6,0xe1,0xe4,0x6a,0x70,0x65,0x5c,0x9b,0x5d,0x69,0x84,0x61,0x04, +0x33,0xa2,0x79,0x04,0xb9,0x19,0xdc,0x18,0xb7,0x66,0x37,0x92,0x19,0x64,0x63,0x98, +0xfb,0xe1,0xc9,0x07,0x98,0x07,0x11,0x8f,0x65,0x1e,0xe2,0xda,0x7a,0x98,0x79,0x84, +0x79,0x94,0x79,0x8c,0x79,0x9c,0x79,0x82,0x61,0x64,0x78,0x66,0xca,0xc8,0x7d,0x1c, +0x63,0x70,0x67,0xdc,0xff,0x71,0xdd,0xf7,0x77,0x32,0x4f,0x32,0xcd,0xee,0xa3,0x99, +0xf1,0xcc,0x53,0xcc,0xd3,0xcc,0x04,0x66,0x22,0x33,0x89,0x99,0xcc,0x3c,0xc3,0x4c, +0x61,0xa6,0x32,0xcf,0x32,0xd3,0x98,0xe9,0xcc,0x0c,0x66,0x26,0xda,0x22,0x66,0x16, +0x43,0x23,0x67,0x33,0x73,0x18,0xc3,0xc8,0xb9,0x5c,0xeb,0xcf,0x31,0xf3,0x98,0xf9, +0xcc,0x38,0xe6,0x79,0xe6,0x05,0x66,0x01,0x8e,0x2f,0x64,0x5e,0x64,0x5e,0x62,0x5e, +0x66,0x5e,0x41,0x7e,0x11,0xf3,0x2a,0xf3,0x1a,0x93,0xc0,0x30,0xcc,0x62,0x26,0x91, +0x49,0x62,0x92,0xb1,0x2f,0x05,0xa4,0x72,0x35,0xd3,0xf0,0xec,0x24,0x26,0x9d,0x59, +0xc2,0x2c,0x65,0x32,0x98,0x65,0xdc,0xbe,0xe5,0x6c,0xdf,0x47,0x66,0x32,0x59,0xcc, +0x0a,0x66,0x25,0xb3,0x0a,0xc7,0x57,0x33,0x6b,0x30,0x3f,0x58,0xcb,0xac,0xc3,0x91, +0xf5,0xcc,0x06,0x66,0x23,0x93,0x8d,0x5c,0x0e,0x93,0xcb,0xe4,0x31,0xf9,0x66,0x6f, +0x15,0x30,0x9b,0x98,0x42,0x66,0x33,0x53,0xf4,0x2f,0xc7,0xd7,0x24,0xce,0xfe,0x2d, +0xe6,0xad,0xad,0x7f,0xfa,0x39,0xdb,0xc6,0x14,0xff,0xea,0x18,0xdf,0xce,0xec,0xf8, +0x1f,0xbc,0xc2,0x1e,0xb8,0xc5,0xbe,0x65,0xff,0x27,0xaf,0x9f,0x25,0xbf,0xb3,0xde, +0x4f,0xbd,0x23,0x67,0x76,0x32,0x25,0xcc,0x2e,0xe4,0x4a,0x99,0xdd,0xb7,0x54,0x68, +0x1e,0x49,0x1e,0x65,0x38,0xbe,0x87,0x29,0x67,0x2a,0xfe,0x3f,0xb9,0x53,0x57,0x32, +0x7b,0x39,0x5f,0x15,0xff,0x7d,0xa7,0xfe,0x51,0xd8,0x77,0xdd,0x43,0xfb,0x99,0xaa, +0x9b,0xfc,0xb5,0xfc,0x4f,0x53,0x20,0xa6,0x9a,0x31,0x78,0xfc,0xcf,0xf5,0xd0,0xbc, +0x2a,0xf2,0xb8,0x79,0x34,0xd4,0x30,0xb5,0x4c,0x1d,0x37,0xa7,0xda,0x6a,0xde,0xa3, +0x62,0xea,0x99,0x66,0x0f,0x92,0x1b,0xe4,0xc4,0x34,0xa0,0x56,0x23,0xf6,0x35,0x99, +0x9e,0x6b,0xf2,0x66,0x39,0x79,0x1a,0x3c,0x19,0xcf,0x66,0x4f,0x52,0x18,0x14,0x8c, +0xa2,0x59,0x41,0x5e,0x06,0x2f,0xc6,0xab,0xd9,0x8b,0x94,0x06,0xe5,0xad,0x46,0x5b, +0xf3,0x6f,0xb0,0xeb,0x9f,0x03,0xcf,0x4d,0x65,0xb3,0xf2,0x75,0xa4,0x2d,0xcc,0x81, +0xeb,0xc7,0x0e,0x32,0x87,0x7e,0x52,0xba,0xd5,0x9c,0x1e,0x36,0xa7,0x6d,0xe6,0xf4, +0x88,0x59,0xf1,0x0d,0x86,0x54,0x47,0x7f,0x41,0xe9,0x4d,0xe6,0x18,0xe2,0x76,0xf3, +0x96,0x41,0xc5,0xa8,0x9a,0x55,0xc7,0xaf,0x1f,0xf5,0x41,0xed,0x0e,0xe6,0x04,0x43, +0x6a,0x83,0x9a,0x51,0x77,0x32,0xcd,0x6a,0xf2,0xbe,0xd5,0x7d,0xe5,0xc7,0xe1,0xa4, +0x39,0x3d,0xc5,0x9c,0x66,0xde,0x62,0xde,0x66,0xde,0xb9,0xe9,0xd8,0xbb,0xcc,0x7b, +0xcc,0xfb,0x5c,0xee,0x03,0xc6,0xe0,0xfd,0xef,0xde,0xbf,0xfe,0x0e,0x7f,0x87,0xbf, +0xc3,0xdf,0xe1,0xef,0xf0,0xaf,0xc2,0xb3,0xff,0x6b,0x2c,0xf9,0xf0,0xbf,0xd0,0x7b, +0x75,0xff,0xdf,0x8c,0x93,0x33,0xb7,0xd8,0x17,0xf5,0xe7,0xae,0xfb,0xbd,0x9b,0xbd, +0xc9,0xc7,0xe0,0xc3,0xf8,0x34,0xfb,0x90,0xaf,0xc1,0x97,0xf1,0xfd,0x63,0xeb,0x97, +0xff,0x3d,0xe1,0xec,0xdf,0xf7,0x19,0x2e,0x2c,0x61,0x8c,0x46,0x0b,0xe2,0x91,0x35, +0xf1,0x69,0x30,0xd9,0x90,0x1d,0x09,0x49,0x44,0x12,0x72,0x24,0x67,0x72,0xa1,0xe1, +0x34,0x82,0x64,0x34,0x92,0xe4,0xa4,0x20,0x25,0xa9,0xc9,0x87,0xfc,0x28,0x80,0x82, +0x48,0x4b,0xc6,0x3f,0xed,0xd3,0xff,0x07,0x43,0xc8,0x4f,0x6c,0xd1,0x11,0xdb,0x23, +0x36,0x47,0x88,0x23,0xb9,0x9c,0x9e,0x62,0x29,0x9e,0xee,0xe4,0xf2,0xf7,0xd0,0x68, +0xf4,0xca,0x68,0xbc,0x9f,0x1e,0xa1,0x7f,0x20,0x9d,0x48,0xcf,0xd0,0xb3,0x34,0x83, +0x66,0xd3,0x73,0xf4,0x3c,0x2d,0xa4,0x97,0xe9,0x55,0x38,0x26,0x89,0x52,0x69,0x09, +0x2d,0xa3,0x2c,0x5a,0x45,0x6b,0x69,0x03,0xe5,0x50,0x3e,0x15,0xd2,0x16,0x94,0x2f, +0xa6,0x9d,0x54,0x4a,0x7b,0xa8,0x92,0xf6,0x53,0xcd,0x9f,0xe0,0x87,0x7a,0xb4,0xd1, +0x04,0x5e,0x07,0x07,0xc1,0x61,0xf0,0x06,0x38,0x06,0x3a,0xc0,0x49,0xf0,0x16,0x78, +0x17,0x7c,0x00,0xce,0x82,0x0b,0xa0,0x1b,0xf4,0x81,0x8f,0xc1,0x65,0xf0,0x05,0xf8, +0x0a,0x7c,0x03,0xae,0x81,0x7e,0xd6,0x0f,0x16,0x46,0xa3,0x15,0x10,0x58,0x08,0x2c, +0x6c,0x90,0xda,0x5b,0xb0,0x8a,0x22,0xc4,0x0e,0xc0,0x19,0x0c,0xb3,0x18,0x66,0xe1, +0x86,0x74,0x24,0xf0,0x04,0x4a,0xe0,0x6d,0xe1,0x8f,0x38,0x08,0x04,0x03,0x1d,0x88, +0x00,0xd1,0xc0,0x00,0xe2,0xc1,0x1d,0xe0,0x6e,0x70,0x2f,0x18,0x03,0x1e,0x04,0x0f, +0x83,0xc7,0xc0,0x38,0x30,0x1e,0x4c,0x00,0x93,0xc1,0x54,0x30,0x1d,0xcc,0x02,0x73, +0xc1,0x7c,0x8b,0x05,0x88,0x5f,0x02,0x8b,0x80,0x02,0x56,0x26,0x58,0x24,0x22,0x97, +0x02,0xd2,0x2d,0x32,0x10,0x67,0x5a,0xac,0xb4,0x58,0xc3,0x59,0xba,0xde,0x22,0xdb, +0x22,0xcf,0x62,0x13,0xf2,0x45,0x16,0xdb,0x10,0xef,0xb0,0xd8,0x65,0x51,0x66,0x61, +0xf2,0x5b,0x85,0xc5,0x3e,0xe4,0xaa,0x2d,0xea,0x10,0x37,0x82,0x7f,0x82,0x03,0x16, +0xad,0x88,0x8f,0x70,0x25,0xde,0x44,0x7c,0xdc,0xa2,0x13,0xf1,0x69,0x8b,0x77,0x2c, +0xde,0x47,0x7a,0x06,0x9c,0xb7,0xe8,0x32,0xd7,0xef,0xb5,0xf8,0xf1,0x79,0xb8,0x64, +0xc1,0x86,0xcb,0x5c,0xf8,0x82,0x0b,0x5f,0xa1,0xc4,0x37,0xe0,0x1a,0xe8,0x07,0x16, +0x96,0xf0,0x26,0xe0,0x83,0x21,0x96,0x6c,0x1d,0x3b,0xc4,0x43,0x81,0x04,0x38,0x01, +0x17,0xe0,0x0a,0x64,0xc0,0x03,0x28,0xb8,0x52,0x2a,0x4b,0x36,0xf8,0x20,0xef,0x6f, +0x19,0x64,0x19,0x8c,0x54,0x07,0x22,0x40,0x34,0x30,0x80,0x78,0x70,0x07,0xb8,0x1b, +0xdc,0x0b,0xc6,0x80,0x07,0xc1,0xc3,0xe0,0x31,0x30,0x0e,0x8c,0x07,0x13,0xc0,0x64, +0x30,0x15,0x4c,0x07,0xb3,0xc0,0x5c,0x30,0x1f,0x2c,0x00,0x2f,0x81,0x45,0x20,0x01, +0x24,0x82,0x14,0x90,0x0e,0x32,0x2c,0x7f,0xdc,0xd7,0x4c,0xcb,0x55,0xd8,0xb3,0xd6, +0x72,0x03,0xb7,0x3f,0x17,0x71,0x81,0xe5,0x66,0xcb,0xad,0x96,0xdb,0x91,0x2b,0x01, +0xbb,0x41,0x39,0xd8,0x6b,0x69,0xfc,0xaf,0xff,0x08,0xa9,0xca,0x52,0x82,0x3b,0x58, +0xad,0x65,0x83,0x65,0xb3,0xa5,0x1f,0xee,0x5e,0x7f,0xac,0xbd,0x16,0xcb,0x56,0xcb, +0x37,0x2c,0xdb,0x2d,0x3b,0x2d,0xdf,0xe2,0xbc,0xb3,0xcd,0xc2,0x19,0x77,0xc7,0x00, +0x7a,0xef,0x77,0xfa,0xea,0x43,0xcb,0x73,0xa8,0xf9,0x91,0x65,0x8f,0xe5,0xc7,0xb7, +0x68,0x81,0xfe,0xf0,0x1d,0xe6,0x32,0x5a,0xfd,0x02,0x7c,0x05,0xbe,0xb1,0x34,0xdd, +0x6f,0xaf,0x0d,0x28,0x59,0x5a,0xf0,0x06,0xee,0xa3,0xf1,0x64,0xc5,0x1b,0xc2,0xb3, +0xe3,0x0d,0xe5,0x49,0x78,0x4e,0xd8,0xeb,0x02,0x5c,0x79,0x32,0x1e,0x46,0x32,0x4f, +0xc1,0x53,0xf1,0x7c,0x78,0xfe,0xbc,0x20,0x5e,0x30,0x4f,0xc7,0xfb,0xd8,0x32,0x82, +0x17,0xcd,0xbb,0x93,0x0c,0xbc,0x78,0xde,0x1d,0xbc,0xbb,0x79,0xf7,0xa2,0xe4,0x18, +0xde,0x83,0xbc,0x87,0x79,0x8f,0xf1,0xc6,0xf1,0xc6,0xf3,0x26,0xf0,0x26,0xf3,0xa6, +0xf2,0xfe,0x9c,0xb3,0x37,0x1d,0xda,0x3a,0xb4,0xec,0x8a,0x16,0x1f,0x83,0x16,0xc6, +0x3c,0x98,0x0b,0xe6,0x83,0x05,0xe0,0x25,0xb0,0x08,0x24,0x80,0x44,0x90,0x02,0xd2, +0x41,0x06,0xc8,0x04,0x11,0xb0,0x6f,0x0c,0x52,0x1d,0xec,0x37,0x1a,0x57,0x82,0x31, +0xbc,0x35,0x9c,0x75,0xeb,0x79,0xd9,0xbc,0x3c,0xde,0x26,0x5e,0x11,0x6f,0x1b,0x6f, +0x07,0x6f,0x17,0xaf,0x8c,0x57,0xc1,0xdb,0xc7,0xab,0xe6,0xd5,0xf1,0x1a,0x79,0xff, +0xe4,0x1d,0xe0,0xb5,0xf2,0x8e,0xf0,0xde,0xe4,0x1d,0xe7,0x75,0xf2,0x4e,0xf3,0xde, +0xe1,0xbd,0xcf,0x3b,0xc3,0x3b,0xcf,0xeb,0xe2,0xf5,0xf2,0x2e,0xf1,0x3e,0xe5,0x7d, +0xce,0xfb,0x92,0x77,0x95,0xf7,0x1d,0xef,0x07,0x1e,0xdc,0x66,0x35,0xc8,0x6a,0xb0, +0x95,0xad,0x95,0xd0,0x4a,0x6c,0xe5,0x68,0x25,0xb5,0x1a,0x6e,0xe5,0x66,0x35,0xd2, +0xca,0xd3,0x4a,0x69,0xe5,0x6d,0xe5,0x67,0xf5,0x57,0x8f,0xef,0x40,0x28,0x68,0x41, +0x28,0x08,0x07,0x51,0x40,0x0f,0xe2,0xc0,0xed,0xe0,0x2e,0x30,0x0a,0x8c,0x06,0x0f, +0x80,0x87,0xc0,0xa3,0xe0,0x09,0xf0,0x24,0x78,0xfa,0x16,0x16,0x4e,0xc2,0xbe,0x29, +0x60,0x1a,0x98,0x09,0xe6,0x80,0x79,0xe0,0x05,0xf0,0x22,0x78,0x05,0xbc,0x06,0x16, +0x83,0x64,0x90,0x06,0x96,0x82,0xe5,0x60,0x05,0x58,0x0d,0xd6,0x81,0x8d,0x20,0x17, +0x14,0x80,0xcd,0x60,0x2b,0xd8,0x0e,0x4a,0xc0,0x6e,0x50,0x0e,0xf6,0x5a,0x55,0x21, +0xae,0x05,0x0d,0xa0,0x19,0xb4,0x80,0x43,0xa0,0x8d,0xb3,0xec,0x28,0xe2,0x76,0x70, +0x02,0x9c,0x02,0x6f,0x83,0xf7,0xc0,0x87,0xe0,0x1c,0xf8,0x08,0xf4,0x80,0x8b,0xe0, +0x13,0xf0,0x19,0xb8,0x02,0xbe,0x06,0xdf,0x82,0xef,0xd9,0x56,0x80,0xa5,0xb5,0xd1, +0x68,0x0d,0x04,0xc0,0x06,0xd8,0x03,0x11,0x70,0x00,0xce,0x60,0x18,0x18,0x01,0xdc, +0x81,0x1c,0x78,0x01,0x35,0xf0,0x05,0x01,0x40,0x03,0x42,0x40,0x18,0x88,0x04,0x31, +0x20,0x16,0xdc,0x06,0xee,0x04,0xf7,0x80,0xfb,0xc0,0xfd,0x60,0x2c,0x78,0x04,0x3c, +0x6e,0xcd,0x5e,0x6f,0xff,0xb0,0x7e,0xca,0x7a,0xa2,0xf5,0x33,0xd6,0xcf,0x5a,0xcf, +0xb0,0x9e,0x6d,0xfd,0x9c,0xf5,0xf3,0xd6,0x0b,0xad,0x5f,0xb6,0x7e,0xd5,0x9a,0xb1, +0x4e,0xb2,0x4e,0xb5,0x5e,0x62,0xbd,0xcc,0x3a,0xcb,0x7a,0x95,0xf5,0x5a,0xeb,0x0d, +0xd6,0x39,0xd6,0xf9,0xd6,0x85,0xd6,0x5b,0xac,0x8b,0xad,0x77,0x5a,0x97,0x5a,0xef, +0xb1,0xae,0xb4,0xde,0x6f,0x5d,0x63,0x5d,0x6f,0xdd,0x64,0xfd,0xba,0xf5,0x41,0xeb, +0xc3,0xd6,0x6f,0x58,0xb3,0x57,0xea,0x5f,0xf9,0x39,0x66,0x7d,0x63,0x56,0x36,0x90, +0xfb,0xbf,0xf2,0xe9,0xb4,0x7e,0xdb,0xfa,0x03,0xeb,0xf3,0xd6,0x7f,0xac,0x95,0x1e, +0xeb,0x4f,0xad,0xbf,0xb2,0xfe,0xde,0x9a,0x37,0x68,0xc8,0x20,0xd1,0x20,0xe9,0xa0, +0x3f,0x77,0x26,0xfc,0x63,0xdf,0xff,0x7c,0x76,0x7c,0x63,0x8f,0x6c,0x90,0xd7,0xa0, +0x7e,0xa3,0xdf,0xa0,0x9f,0xd6,0xfe,0x7d,0x9a,0x3f,0x3d,0xcf,0x37,0xf4,0xfe,0xfd, +0x96,0xfb,0x6f,0xb1,0x1d,0x3c,0x88,0x8d,0x23,0x07,0xdd,0xdc,0x62,0xff,0xaf,0xea, +0xfd,0xb4,0xcf,0xa6,0x10,0x37,0xe8,0xee,0x41,0xf7,0x0f,0x62,0xf7,0x3e,0x3a,0xe8, +0xa7,0xde,0xf9,0xf7,0x57,0x1b,0xff,0xca,0xff,0xb7,0x2a,0x39,0xb0,0x35,0x7e,0xd0, +0x33,0x83,0xfa,0x6f,0xe9,0xc9,0xdf,0x6f,0xc1,0x5f,0xf7,0x99,0x39,0xc8,0xf8,0x0b, +0xe7,0xb7,0xff,0xfa,0x39,0xea,0xff,0x17,0xe7,0xf0,0xb7,0x9d,0xf5,0x5f,0xae,0x35, +0x7f,0xd0,0xbf,0x1e,0x7d,0xbf,0xd4,0x42,0xff,0x2f,0xfa,0xf0,0xe5,0x41,0x8b,0x07, +0xfd,0x19,0xeb,0xc7,0x5f,0xfa,0xa4,0x0f,0xfa,0x4f,0xde,0x9b,0x96,0x0d,0xfa,0x79, +0x8f,0x57,0x5f,0xdf,0x97,0x7d,0x3d,0x57,0x78,0x3d,0xb7,0xfd,0x17,0xed,0x2b,0x1b, +0xf4,0xf3,0x6b,0x6a,0x3f,0xf6,0x35,0x0c,0x3a,0x30,0xe8,0x8d,0x41,0xa7,0x06,0xbd, +0xff,0x93,0x9a,0xdd,0xbf,0xa1,0xa7,0x9f,0xdc,0xc2,0xbe,0x2f,0xaf,0xef,0xbb,0x76, +0x3d,0x67,0xc9,0x1f,0xc8,0x0d,0xe6,0xff,0x52,0x5b,0x43,0xf9,0x7f,0xe6,0x93,0xc5, +0x99,0x3f,0x9c,0x2f,0xe3,0xcb,0xf9,0x4a,0xbe,0x0f,0x3f,0x80,0xaf,0xe5,0xeb,0xf8, +0x91,0x7c,0x3d,0x3f,0x9e,0x7f,0x27,0x7f,0x14,0x7f,0x0c,0x7f,0x2c,0xff,0x51,0xfe, +0x38,0xfe,0x53,0xfc,0x49,0xfc,0xa9,0xfc,0x19,0xfc,0x39,0xfc,0xf9,0xfc,0x85,0xfc, +0x57,0xf8,0x09,0xfc,0x24,0x7e,0x1a,0x3f,0x83,0x9f,0xc5,0x5f,0xcd,0x5f,0xcf,0xcf, +0xe1,0x17,0xf0,0x8b,0xf8,0xc5,0xfc,0x12,0x7e,0xbf,0xb1,0x8c,0x7f,0x63,0x64,0x54, +0xf2,0xff,0xca,0xab,0xb3,0x8a,0xff,0x67,0xb4,0x42,0x44,0x64,0xfc,0xaf,0xf9,0xb0, +0xfe,0xac,0xe3,0x37,0xf1,0x5b,0xf8,0xad,0xfc,0x37,0xf8,0xed,0xfc,0xfe,0xff,0xe0, +0xec,0xe2,0xdf,0xf3,0x14,0x5d,0xff,0xfc,0xda,0x3d,0xfc,0x8f,0x7e,0x4e,0x63,0x65, +0xf1,0x1d,0x8f,0x5d,0x43,0x0c,0xc2,0xba,0x41,0x6b,0xd5,0xc9,0x7f,0x8b,0x7f,0xb3, +0xc2,0x7b,0xfc,0x33,0xfc,0x0b,0xfc,0x1e,0xfe,0x25,0xfe,0x65,0xfe,0x15,0xfe,0x55, +0xfe,0x35,0xbe,0x91,0xcf,0x13,0xf0,0x05,0x55,0x7c,0x1b,0x81,0x50,0x20,0x11,0x38, +0x0b,0x86,0x0b,0x64,0x02,0xb9,0x40,0x29,0xf0,0x11,0x04,0x08,0xb4,0x02,0x9d,0x20, +0x52,0xa0,0x17,0xc4,0x0b,0xee,0x14,0x8c,0x12,0x8c,0x11,0x8c,0x15,0x3c,0x2a,0x18, +0x27,0x78,0x4a,0x30,0x49,0x30,0x55,0x30,0x43,0x30,0x47,0x30,0x5f,0xb0,0x50,0xf0, +0x8a,0x20,0x41,0xc0,0xb6,0x9c,0x24,0x48,0x13,0x64,0x08,0xfe,0x2a,0x7f,0x5b,0xd0, +0xf3,0xc4,0x83,0xf7,0xd8,0xf7,0x8a,0xeb,0x2d,0x7e,0xfa,0x5e,0x11,0x73,0x6d,0x9a, +0x6f,0x29,0xc3,0xba,0x9c,0x7d,0xaf,0xe8,0x47,0x16,0x94,0x25,0x58,0x25,0x58,0x2b, +0xe0,0x71,0xef,0x21,0xd9,0xb7,0x3e,0x1b,0x05,0x76,0x28,0xe5,0x88,0xd2,0xfe,0x16, +0x23,0x28,0xdd,0x22,0x57,0xb0,0x49,0x20,0xe3,0x4a,0x6f,0x11,0x54,0x58,0xf8,0xd0, +0x76,0x81,0x69,0x55,0xca,0xae,0x39,0x45,0x68,0x87,0x7d,0x3b,0xc9,0xee,0xb9,0x97, +0xdb,0xf3,0xcb,0x76,0x5d,0xfd,0x53,0x56,0xa6,0xbb,0x04,0xd6,0x54,0x26,0x58,0x45, +0x1b,0x05,0x36,0x54,0x21,0xd8,0x27,0xa8,0x16,0xec,0xb2,0xd8,0x61,0x51,0x27,0x68, +0x14,0xbc,0x2e,0x38,0x28,0x38,0x2c,0x38,0x2a,0x68,0x17,0x9c,0x10,0xec,0xb3,0x38, +0x25,0x78,0x5b,0x50,0x6d,0xf1,0x9e,0xe0,0x43,0xc1,0x11,0x8b,0x73,0x82,0xcd,0x96, +0xa7,0x2d,0x3e,0x12,0xbc,0x63,0xb1,0xd5,0x52,0x4b,0xbd,0x82,0x4b,0x82,0xf3,0x16, +0x3a,0xde,0xa7,0x38,0x03,0x5f,0x80,0xaf,0xc1,0x77,0xa0,0x1f,0x58,0x0e,0x36,0x1a, +0x07,0x81,0x21,0xc0,0x1e,0x88,0x81,0x13,0x18,0x06,0xdc,0x80,0x07,0xf0,0x02,0xde, +0xc0,0x1f,0x68,0x40,0x28,0x88,0x00,0x31,0x20,0x0e,0xdc,0x01,0xee,0x01,0xa3,0xc1, +0x83,0xe0,0x11,0xf0,0x04,0x18,0x0f,0x26,0x82,0x29,0x60,0x3a,0x98,0x0d,0xe6,0x81, +0x05,0xe0,0x65,0xf0,0x1a,0x48,0x04,0xa9,0x60,0x29,0xc8,0x04,0xab,0xc0,0x3a,0x90, +0x0d,0xf2,0xc1,0x66,0xb0,0x0d,0xec,0x04,0xbb,0x41,0x05,0xd8,0x0f,0x6a,0x41,0x23, +0x78,0x1d,0x1c,0x02,0x47,0xc0,0x31,0x70,0x02,0x9c,0x06,0xef,0x82,0x0f,0xc1,0x79, +0xd0,0x0d,0x2e,0x82,0x4f,0xc1,0x17,0xe0,0x6b,0xf0,0x1d,0xe8,0x07,0x96,0x43,0xd0, +0x7f,0x30,0x04,0xd8,0x03,0x31,0x70,0x1a,0x72,0xc3,0xfb,0xc3,0x86,0xb0,0xaa,0xf0, +0x05,0xf6,0x8d,0x04,0x0a,0xa0,0x06,0x7e,0x20,0x08,0x84,0x80,0x70,0x10,0x0d,0x62, +0xc1,0xed,0xe0,0x6e,0x70,0x1f,0x78,0x00,0x3c,0x0c,0x1e,0x07,0x4f,0x82,0x09,0xe0, +0x19,0x30,0x0d,0xcc,0x02,0xcf,0x81,0x17,0xc0,0x4b,0xe0,0x55,0xb0,0x18,0xa4,0x80, +0x25,0x60,0x39,0x58,0x09,0xd6,0x82,0x8d,0x20,0x0f,0x14,0x82,0xad,0x60,0x07,0x28, +0x05,0xe5,0x60,0x1f,0xa8,0x01,0x0d,0xe0,0x9f,0xe0,0x20,0x68,0x03,0x6f,0x82,0x0e, +0x70,0x0a,0xbc,0x03,0x3e,0x18,0xf2,0xf3,0x91,0x75,0x6e,0x48,0xd7,0x90,0xbe,0x21, +0x9f,0x0c,0xf9,0x7c,0xc8,0x57,0x43,0xbe,0x1d,0xf2,0xc3,0x90,0x9f,0xde,0x77,0x2c, +0x6c,0xac,0x6d,0x06,0xdb,0xd8,0xd9,0x88,0x6c,0x1c,0x6d,0x6e,0x75,0xff,0x71,0xb1, +0x19,0x61,0x33,0xd2,0x46,0x61,0xa3,0xb6,0xf1,0xb3,0x09,0xb2,0x09,0xb1,0xf9,0xe9, +0xf1,0x70,0x9b,0x68,0x9b,0x58,0x9b,0xdb,0x6d,0xee,0xb6,0xb9,0xcf,0xe6,0x01,0x9b, +0x87,0x6d,0x7e,0xda,0xfe,0xe3,0x36,0x4f,0xda,0x4c,0xb0,0x79,0xc6,0x66,0x9a,0xcd, +0xac,0x5b,0xb6,0xdf,0x6f,0x7c,0x0e,0xfb,0x5f,0x00,0x2f,0x81,0x57,0x7f,0xd6,0xfe, +0x62,0x9b,0x14,0x9b,0x25,0x36,0xcb,0x6d,0x56,0xda,0xac,0xb5,0xd9,0x68,0x93,0x87, +0xe3,0x43,0x70,0xc5,0x0d,0x05,0x12,0xe0,0x04,0x5c,0x80,0x2b,0x90,0x71,0xef,0x9e, +0x0a,0x6d,0x8a,0x6d,0x4a,0x6d,0x2a,0x6d,0x6a,0x6c,0x9a,0x6c,0x0e,0xda,0xbc,0x61, +0xf3,0xd3,0xed,0x0e,0x9b,0xb7,0x6c,0x3e,0xb0,0xb9,0x60,0xd3,0x67,0x73,0xd9,0xe6, +0x2b,0x9b,0x6b,0x3f,0xdb,0xb6,0xb0,0xe5,0xdb,0xda,0xd9,0x4a,0x6c,0x5d,0x6c,0x65, +0xb6,0x0a,0x5b,0x1f,0xdb,0x9f,0x6e,0xb3,0x36,0x05,0xd9,0xea,0x6c,0xa3,0x6c,0xd9, +0xbe,0xc4,0xda,0xde,0x69,0x3b,0xca,0x76,0x8c,0xed,0x10,0x9e,0xce,0x76,0xac,0xed, +0xc7,0x96,0x63,0x6d,0x1f,0xb5,0x1d,0x67,0x3b,0xc1,0x76,0xaa,0xed,0x4c,0xee,0xf8, +0x73,0xb6,0x0b,0x6d,0x87,0xf2,0x5e,0xb1,0x95,0xf0,0xa6,0xda,0x26,0xd8,0xa6,0xd8, +0x66,0xd8,0x9a,0x7a,0xb5,0xd2,0x76,0xc0,0x17,0x6b,0x6c,0x37,0xd8,0xe6,0xda,0xb2, +0x6f,0xc8,0x36,0xd9,0x6e,0xb3,0xdd,0x65,0x3e,0x5e,0x61,0x3b,0xd0,0xff,0x7d,0xb6, +0x35,0xb6,0x0d,0xb6,0xae,0xbc,0x7f,0xda,0x1e,0xb4,0xb5,0xe2,0xbd,0xc1,0xd5,0x7b, +0xd3,0xb6,0xd3,0xf6,0x6d,0xae,0xfd,0x0f,0x6c,0x2f,0xd8,0xba,0xf0,0x7a,0x6c,0x65, +0xbc,0x4e,0xdb,0x78,0xba,0x64,0xcb,0x7e,0x7f,0x71,0xab,0x60,0x7a,0xee,0x98,0x34, +0x2f,0xdb,0xde,0xf0,0xee,0x15,0xdb,0x7f,0xbd,0xae,0x30,0xfe,0xc2,0xb7,0x23,0x57, +0x6d,0xfb,0x51,0x53,0x60,0x27,0xb4,0xbb,0x3e,0x4e,0x90,0x73,0xb5,0xfb,0x69,0x2b, +0xee,0x76,0x72,0x3b,0x2f,0xbb,0x5f,0xbe,0xef,0xa9,0x7f,0x72,0x2c,0xe4,0xc6,0x83, +0x92,0x6e,0xa8,0xde,0xb4,0x93,0x42,0xed,0x44,0xdc,0x91,0x30,0xbb,0x08,0xbb,0x28, +0xbb,0x18,0x3b,0x83,0x5d,0x9c,0xdd,0x6d,0x76,0x77,0xd8,0xdd,0x63,0x77,0xaf,0xdd, +0x68,0xbb,0xe1,0x38,0x3e,0x9a,0xd8,0xef,0x67,0x6e,0x7d,0x1c,0xe3,0x1d,0xcf,0x83, +0x11,0x14,0x80,0x67,0x82,0xf0,0xfa,0xd3,0x43,0xc6,0x7d,0x1f,0x75,0xeb,0xe7,0xef, +0xfd,0x76,0xff,0xde,0x9d,0x7c,0xac,0xdd,0xa3,0x76,0xd6,0x34,0x0e,0xb5,0x9e,0xb2, +0x9b,0x64,0x97,0xc7,0x7e,0x63,0x61,0xc7,0x3e,0xad,0x4c,0xe1,0x2b,0x3c,0xb5,0x44, +0x50,0x75,0x86,0x1f,0x87,0xd3,0x0c,0xae,0x6d,0xd3,0x37,0x62,0x6c,0x60,0xb7,0x66, +0xdb,0x3d,0x67,0xf7,0x02,0xf6,0xb3,0xdf,0x89,0x4d,0xe0,0x99,0x52,0x47,0x7a,0x8e, +0xfb,0x4e,0x0d,0xb3,0x60,0xee,0x5b,0xb5,0x17,0xed,0x5c,0xd0,0x87,0x45,0x76,0x09, +0x76,0x89,0x76,0x29,0xf0,0x07,0x56,0x17,0x76,0x77,0xe3,0x59,0xa5,0xe2,0xdd,0xcd, +0x5b,0x76,0xdd,0x5e,0x3e,0xf7,0xec,0x63,0x9f,0x92,0x37,0xdb,0xb7,0xc2,0x6e,0x9d, +0x5d,0xae,0x5d,0x91,0xdd,0x0e,0xbb,0x32,0xbb,0x7d,0x76,0x75,0x76,0xff,0xb4,0x6b, +0xb5,0x7b,0xd3,0xae,0xd3,0xee,0x1d,0xbb,0x33,0x76,0x5d,0x76,0x97,0xd0,0xda,0x67, +0x76,0x57,0xec,0xae,0xda,0xf9,0xd0,0x77,0x76,0x3f,0xd8,0x59,0xd8,0x0f,0xb2,0x0f, +0xa0,0xc1,0xf6,0xb6,0xf6,0xce,0xdc,0x77,0x7a,0x2e,0xf4,0x6b,0xc7,0xcd,0x73,0x72, +0xfb,0x1b,0x8a,0x0e,0xf6,0x3f,0x5d,0x3d,0xfc,0x37,0x7e,0x86,0xd9,0x8f,0x44,0x3f, +0x7c,0xec,0x35,0xf6,0xff,0x69,0xe5,0x28,0x7b,0xc3,0x1f,0xd6,0xfc,0xed,0xeb,0xd7, +0x5b,0x5c,0x3d,0xf6,0x77,0xda,0xdf,0x63,0x7f,0x9f,0xfd,0xfd,0xf6,0x63,0xed,0x1f, +0xb1,0x7f,0xdc,0xfe,0x1f,0xf6,0x4f,0xd9,0x4f,0xb4,0x7f,0xc6,0x7e,0x9a,0xfd,0x2c, +0xfb,0xe7,0xec,0x5f,0xb0,0x7f,0xc9,0xfe,0x55,0xfb,0xc5,0xf6,0x29,0xf6,0x4b,0xec, +0x33,0xed,0x57,0xdb,0x6f,0xb0,0xcf,0xb3,0xdf,0x6c,0x5f,0x6c,0xbf,0xcb,0xbe,0xdc, +0x7e,0xbf,0x7d,0x9d,0xfd,0x6f,0xd5,0x6d,0xb6,0x3f,0x60,0x7f,0xd8,0xfe,0xa8,0xfd, +0x71,0xfb,0x93,0xf6,0x6f,0xdb,0xbf,0x6f,0x7f,0xd6,0xfe,0x23,0xfb,0x5e,0xfb,0x8f, +0xed,0x3f,0xb3,0xff,0xd2,0xfe,0x1b,0xfb,0xef,0xed,0x49,0x68,0x25,0x14,0x08,0x6d, +0x85,0x43,0x85,0x0e,0x42,0xa9,0xd0,0x55,0xe8,0x2e,0xf4,0x14,0xfe,0x9e,0x6f,0x9a, +0x7f,0x4f,0x9d,0x50,0xbb,0x3f,0x7e,0x16,0x55,0x42,0xe3,0xff,0xa9,0x4f,0x88,0x30, +0x5c,0x18,0xf5,0x27,0xf6,0xc9,0xf0,0x27,0xb5,0x75,0x87,0xf0,0x1e,0xe1,0x68,0xe1, +0x83,0xc2,0x47,0x84,0x4f,0x08,0xc7,0x0b,0x27,0x0a,0xa7,0x08,0xa7,0x0b,0x67,0x0b, +0xe7,0x09,0x17,0x08,0x5f,0x16,0xbe,0x26,0x4c,0x14,0xa6,0x0a,0x97,0x0a,0x33,0x85, +0xab,0x84,0xeb,0x84,0xd9,0xc2,0x7c,0xe1,0x66,0xe1,0x36,0xe1,0x4e,0xe1,0x6e,0x61, +0x85,0x70,0xbf,0xb0,0x56,0xd8,0x28,0x7c,0x5d,0x78,0x48,0x78,0x44,0x78,0x4c,0x78, +0x42,0x78,0x5a,0xf8,0xae,0xf0,0x43,0xe1,0x79,0x61,0xb7,0xf0,0xa2,0xf0,0x53,0xe1, +0x17,0xc2,0xaf,0x85,0xdf,0x09,0xfb,0x85,0x96,0x43,0xff,0x6a,0xbf,0x0e,0x82,0xc2, +0x90,0xa1,0x76,0x43,0x45,0x9c,0x92,0x03,0x62,0x29,0x70,0x05,0xab,0xb0,0x06,0xc8, +0x12,0xec,0xc2,0x7c,0xde,0x9d,0x3b,0xe6,0xf9,0x23,0x5b,0x24,0x18,0xaf,0xaa,0xa1, +0x3e,0x43,0xfd,0xb1,0x57,0x03,0x42,0x41,0x04,0x88,0x01,0x71,0xe0,0x0e,0x70,0x0f, +0x18,0x0d,0x1e,0x04,0x8f,0x80,0x27,0xc0,0x78,0x30,0x11,0x4c,0x01,0xd3,0xc1,0x6c, +0x30,0x0f,0x2c,0x00,0x2f,0x83,0xd7,0x40,0x22,0x48,0x05,0x4b,0x41,0x26,0x6b,0x09, +0x58,0x07,0xb2,0x41,0x3e,0xd8,0x0c,0xb6,0x81,0x9d,0x60,0x37,0xa8,0x00,0xfb,0x41, +0x2d,0x68,0x04,0xaf,0x83,0x43,0xe0,0x08,0x38,0x06,0x4e,0x80,0xd3,0xe0,0x5d,0xf0, +0x21,0x38,0x0f,0xba,0xc1,0x45,0xf0,0x29,0xf8,0xe2,0x67,0x5e,0xfe,0x1a,0x7b,0xbe, +0xbb,0xbe,0xb7,0x7f,0xa8,0xf1,0x3f,0xf6,0xbe,0xf3,0xc7,0x77,0x29,0x4b,0x91,0xf1, +0x77,0xbd,0xfd,0xfb,0xad,0x6f,0xb8,0x07,0x89,0xfe,0x3b,0xae,0xfe,0x21,0xa2,0x5f, +0xf2,0x80,0xbd,0x48,0x2c,0x72,0x12,0x0d,0x13,0xb9,0x89,0x3c,0x44,0x5e,0x22,0x6f, +0x91,0xbf,0x48,0x23,0x0a,0x15,0x45,0x88,0x62,0x44,0x71,0xa2,0x3b,0x44,0xf7,0x88, +0x46,0x8b,0x1e,0x14,0x3d,0x22,0x7a,0x42,0x34,0x5e,0x34,0x51,0x34,0x45,0x34,0x5d, +0x34,0x5b,0x34,0x4f,0xb4,0x40,0xf4,0xb2,0xe8,0x35,0x51,0xa2,0x28,0x55,0xb4,0x54, +0x94,0x29,0x5a,0x25,0x5a,0x27,0xca,0x16,0xe5,0x8b,0x36,0x8b,0xb6,0x89,0x76,0x8a, +0x76,0x8b,0x2a,0x44,0xfb,0x45,0xb5,0xa2,0x46,0xd1,0xeb,0xa2,0x43,0xa2,0x23,0xa2, +0x63,0xa2,0x13,0xa2,0xd3,0xa2,0x77,0x45,0x1f,0x8a,0xce,0x8b,0xba,0x45,0x17,0x45, +0x9f,0x8a,0xbe,0x10,0x7d,0x2d,0xfa,0x4e,0xd4,0x2f,0xb2,0x14,0x0f,0x12,0x0f,0x11, +0xdb,0x8b,0xc5,0x62,0x27,0xf1,0x30,0xb1,0x9b,0xd8,0x43,0xec,0x25,0xf6,0x16,0xfb, +0x8b,0x35,0xe2,0x50,0x71,0x84,0x38,0x46,0x1c,0x27,0xbe,0x43,0x7c,0x8f,0x78,0xb4, +0xf8,0x41,0xf1,0x23,0xe2,0x27,0xc4,0xe3,0xc5,0x13,0xc5,0x53,0xc4,0xd3,0xc5,0xb3, +0xc5,0xf3,0xc4,0x0b,0xc4,0x2f,0x8b,0x5f,0x13,0x27,0x8a,0x53,0xc5,0x4b,0xc5,0x99, +0xe2,0x55,0xe2,0x75,0xe2,0x6c,0x71,0xbe,0x78,0xb3,0x78,0x9b,0x78,0xa7,0x78,0xb7, +0xb8,0x42,0xbc,0x5f,0x5c,0x2b,0x6e,0x14,0xbf,0x2e,0x3e,0x24,0x3e,0x22,0x3e,0x26, +0x3e,0x21,0x3e,0x2d,0x7e,0x57,0xfc,0xa1,0xf8,0xbc,0xb8,0x5b,0x7c,0x51,0xfc,0xa9, +0xf8,0x0b,0xf1,0xd7,0xe2,0xef,0xc4,0xfd,0x62,0x4b,0xc9,0x20,0xc9,0x10,0x89,0xbd, +0x44,0x2c,0x71,0x92,0x0c,0x93,0xb8,0x49,0x3c,0x24,0x5e,0x12,0x6f,0x89,0xbf,0x44, +0x23,0x09,0x95,0x44,0x48,0x62,0x24,0x71,0x92,0x3b,0x24,0xf7,0x48,0x46,0x4b,0x1e, +0x94,0x3c,0x22,0x79,0x42,0x32,0x5e,0x32,0x51,0x32,0x45,0x32,0x5d,0x32,0x5b,0x32, +0x4f,0xb2,0x40,0xf2,0xb2,0xe4,0x35,0x49,0xa2,0x24,0x55,0xb2,0x54,0x92,0x29,0x59, +0x25,0x59,0x27,0xc9,0x96,0xe4,0x4b,0x36,0x4b,0xb6,0x49,0x76,0x4a,0x76,0x4b,0x2a, +0x24,0xfb,0x25,0xb5,0x92,0x46,0xc9,0xeb,0x92,0x43,0x92,0x23,0x92,0x63,0x92,0x13, +0x92,0xd3,0x92,0x77,0x25,0x1f,0x4a,0xce,0x4b,0xba,0x25,0x17,0x25,0x9f,0x4a,0xbe, +0x90,0x7c,0x2d,0xf9,0x4e,0xd2,0x2f,0xb1,0x74,0x18,0xe4,0x30,0xc4,0xc1,0xde,0x41, +0xec,0xe0,0xe4,0x30,0xcc,0xc1,0xcd,0xc1,0xc3,0xc1,0xcb,0xc1,0xdb,0xc1,0xdf,0x41, +0xe3,0x10,0xea,0x10,0xe1,0x10,0xe3,0x10,0xe7,0x70,0x87,0xc3,0x3d,0x0e,0xa3,0x1d, +0x1e,0x74,0x78,0xc4,0xe1,0x09,0x87,0xf1,0x0e,0x13,0x1d,0xfa,0x8d,0x7f,0x7e,0x60, +0x57,0x08,0x53,0x1c,0xfe,0x33,0xa3,0xf0,0x59,0xe8,0x4c,0x17,0xcd,0x74,0x98,0xeb, +0xf0,0x47,0xae,0x6e,0xf6,0xf3,0xbc,0xc3,0x4b,0x5c,0x1b,0xaf,0x39,0xfc,0x77,0x3f, +0x95,0x53,0x1c,0xfe,0xea,0xfb,0x62,0xbf,0x71,0x99,0xc3,0x0a,0x87,0x35,0x0e,0x1b, +0x1c,0x72,0x1d,0x36,0x39,0x6c,0x71,0xd8,0xee,0xb0,0xcb,0x61,0x8f,0xc3,0x5e,0x87, +0x6a,0x87,0x7a,0x87,0x66,0x87,0x03,0x0e,0x87,0x1d,0x8e,0x3a,0x1c,0x77,0x38,0xe9, +0xf0,0xb6,0xc3,0xfb,0x0e,0x67,0x1d,0x3e,0x72,0xe8,0x75,0xf8,0xd8,0xe1,0x33,0x87, +0x2f,0x1d,0xbe,0x71,0xf8,0xde,0x81,0x1c,0xad,0x1c,0x05,0x8e,0xb6,0x8e,0x43,0x1d, +0x1d,0x1c,0xa5,0x8e,0xae,0x8e,0xee,0x8e,0x9e,0x8e,0x2a,0x47,0x5f,0xc7,0x40,0xc7, +0x60,0xc7,0x30,0xc7,0x28,0x47,0x83,0xe3,0x6d,0x8e,0x77,0x39,0xde,0xeb,0x78,0xbf, +0xe3,0x43,0x8e,0x44,0x8f,0x39,0xfe,0xc3,0xf1,0x69,0xc7,0xc9,0x8e,0xcf,0x3a,0xce, +0x74,0x9c,0xeb,0xf8,0xbc,0xe3,0x8b,0x8e,0x8b,0x1c,0x19,0xc7,0x64,0xc7,0x74,0xc7, +0x65,0x8e,0x2b,0x1c,0xd7,0x38,0x6e,0x70,0xcc,0x75,0xdc,0xe4,0xb8,0xc5,0x71,0xbb, +0xe3,0x2e,0xc7,0x3d,0x8e,0x7b,0x1d,0xab,0x1d,0xeb,0x1d,0x9b,0x1d,0x0f,0x38,0x1e, +0x76,0x3c,0xea,0x78,0xdc,0xf1,0xa4,0xe3,0xdb,0x8e,0xef,0x3b,0x9e,0x75,0xfc,0xc8, +0xb1,0xd7,0xf1,0x63,0xc7,0xcf,0x1c,0xbf,0x74,0xfc,0xc6,0xf1,0x7b,0x47,0x93,0x57, +0xec,0x71,0x67,0x22,0x27,0x2b,0x27,0x81,0x93,0xad,0xd3,0x50,0x27,0x07,0x27,0x37, +0x91,0xd4,0xc9,0xd5,0xc9,0xdd,0xc9,0xd3,0xc9,0xff,0x0f,0xdf,0x7f,0x55,0x4e,0xfe, +0x4e,0xc1,0x4e,0x11,0x4e,0x06,0xa7,0x3b,0x9c,0xee,0x75,0x7a,0xd0,0xe9,0x31,0xa7, +0xf1,0x4e,0x93,0x9d,0xa6,0x3b,0xcd,0x75,0x5a,0xe0,0xb4,0xc8,0x29,0xd1,0x29,0xdd, +0x29,0xd3,0x69,0x8d,0x53,0xb6,0xd3,0x26,0xa7,0x6d,0x4e,0xbb,0x9c,0x2a,0x9c,0xaa, +0x9d,0x1a,0x9d,0x0e,0x38,0x1d,0x71,0x3a,0xee,0x74,0xda,0xe9,0x8c,0x53,0xbf,0xb1, +0xd7,0xe9,0x53,0xa7,0x2f,0x9d,0xbe,0x73,0x22,0xe7,0x41,0xce,0xb6,0xce,0x62,0x67, +0xa9,0xb3,0x9b,0xb3,0xa7,0xb3,0xb7,0x73,0xa0,0x73,0xa8,0x73,0x94,0x73,0x9c,0xf3, +0x5d,0xce,0xa3,0x9d,0x1f,0x72,0x7e,0xc2,0xf9,0x69,0xe7,0x29,0xce,0x33,0x9d,0xe7, +0x39,0xbf,0xe8,0xfc,0x9a,0x73,0xb2,0xf3,0x52,0xe7,0x15,0xce,0xeb,0x9c,0x73,0x9d, +0x37,0x3b,0x6f,0x77,0xde,0xed,0xbc,0xd7,0xb9,0xd6,0xb9,0xd9,0xf9,0x80,0xb3,0x93, +0xf8,0xb0,0xf3,0x4f,0xed,0x3b,0xea,0x7c,0xdc,0xb9,0xd3,0xf9,0xb4,0xf3,0x3b,0xce, +0xef,0x3b,0x9f,0x71,0x3e,0xef,0xdc,0xe5,0xdc,0xeb,0x7c,0xc9,0xf9,0x53,0xe7,0xcf, +0x9d,0xbf,0x74,0xbe,0xea,0xfc,0x9d,0xf3,0x32,0x9c,0xd9,0x2d,0x38,0xa7,0xec,0x59, +0x7c,0x9f,0x3b,0x7f,0x37,0xce,0xde,0x0f,0xce,0x16,0x52,0x6b,0xe9,0x60,0xa9,0x9d, +0x54,0x24,0x75,0x94,0xba,0x48,0x47,0x48,0x47,0x4a,0x15,0x52,0xb5,0xd4,0x4f,0x1a, +0x24,0x0d,0x91,0x46,0x49,0xe3,0xa5,0x37,0x7c,0x7b,0xa7,0x74,0x94,0x74,0x8c,0x34, +0x42,0x34,0x56,0x3a,0x5d,0xa4,0xc1,0xbd,0x76,0x3c,0xee,0xc2,0xdb,0x24,0x4b,0x45, +0xde,0xe2,0x47,0xa5,0xe3,0xa4,0x4f,0x49,0x27,0x49,0xa7,0x4a,0x67,0x48,0xe7,0x48, +0xe7,0x4b,0x17,0x4a,0x5f,0x91,0x6e,0x16,0x25,0x48,0x93,0xa4,0x69,0xd2,0x0c,0x69, +0x96,0x74,0xb5,0x74,0xbd,0x34,0x47,0x6a,0x3a,0x37,0x05,0xd2,0x22,0x69,0xb1,0xb4, +0x44,0x5a,0x26,0xad,0x94,0x56,0x49,0xeb,0xa4,0x4d,0xd2,0x16,0x69,0xab,0xf4,0x88, +0xf4,0x4d,0xe9,0x71,0x69,0xa7,0xf4,0xb4,0xf4,0x1d,0xe9,0xfb,0xd2,0x33,0xd2,0xf3, +0xd2,0x2e,0x69,0xaf,0xf4,0x92,0xf4,0x53,0xe9,0xe7,0xd2,0x2f,0xa5,0xdf,0x4a,0xfb, +0xa5,0x3c,0x17,0x81,0x8b,0x9d,0x8b,0xd8,0xc5,0xd9,0xc5,0xd5,0x65,0xa4,0x8b,0xd2, +0xc5,0xcf,0x45,0xeb,0x12,0xea,0x12,0xe1,0x12,0xed,0x12,0xeb,0x72,0xbb,0xcb,0xdd, +0x2e,0xf7,0xb9,0x3c,0xe0,0xf2,0xb0,0xcb,0xe3,0x2e,0x4f,0xba,0x4c,0x70,0x79,0xc6, +0x65,0x9a,0xcb,0x2c,0x97,0xe7,0x5c,0x5e,0x70,0x79,0xc9,0xe5,0x55,0x97,0xc5,0x2e, +0x29,0x2e,0x4b,0x5c,0x96,0xbb,0xac,0x74,0x59,0xeb,0xb2,0xd1,0x25,0xcf,0xa5,0xd0, +0x65,0xab,0xcb,0x0e,0x97,0x52,0x97,0x72,0x97,0x7d,0x2e,0x35,0x2e,0x0d,0x2e,0xff, +0x74,0x39,0xe8,0xd2,0xe6,0xf2,0xa6,0x4b,0x87,0xcb,0x29,0x97,0x77,0x5c,0x3e,0x70, +0x39,0xe7,0xd2,0xe5,0xd2,0xe7,0xf2,0x89,0xcb,0xe7,0x2e,0x5f,0xb9,0x7c,0xeb,0xf2, +0x83,0x8b,0xd5,0x30,0xd1,0x30,0xb7,0x61,0x3e,0xc3,0x42,0x86,0xc5,0x0d,0xbb,0x77, +0xd8,0x23,0xc3,0xa6,0x0c,0x9b,0x3f,0xec,0xd5,0x61,0x69,0xc3,0x56,0x0e,0xcb,0x1f, +0x56,0x32,0x6c,0xdf,0xb0,0xa6,0x61,0x87,0x86,0x1d,0x1f,0xf6,0xc1,0xb0,0x8b,0xc3, +0x3e,0x1f,0x66,0x31,0xdc,0x61,0xb8,0xe7,0x70,0xff,0xe1,0x31,0xc3,0x47,0x0f,0x1f, +0x37,0xfc,0x99,0xe1,0x73,0x86,0xbf,0x34,0x3c,0x75,0xf8,0xba,0xe1,0x45,0xc3,0x4b, +0x87,0x57,0x0d,0xff,0xe7,0xf0,0xc3,0xc3,0xdb,0x87,0x9f,0x1e,0xfe,0xc1,0xf0,0x9e, +0xe1,0x9f,0x0f,0xb7,0x70,0xb5,0x71,0x95,0xba,0xaa,0x5c,0x35,0xae,0xe1,0xae,0x06, +0xd7,0xfb,0x5d,0x9f,0x74,0x9d,0xe5,0xba,0xd0,0x35,0xcd,0x35,0xd3,0x75,0x83,0xeb, +0x66,0xd7,0x5d,0xae,0xfb,0x5d,0x9b,0x5d,0xdf,0x74,0x7d,0xcb,0xf5,0x43,0xd7,0x5e, +0xd7,0x2f,0x5c,0xbf,0x77,0x1d,0x3c,0x42,0x32,0x62,0xc4,0x08,0xe5,0x08,0xdd,0x88, +0xdb,0x46,0x8c,0x1a,0x31,0x6e,0xc4,0xc4,0x11,0x73,0x46,0x2c,0x1a,0x91,0x3a,0x62, +0xc5,0x88,0xec,0x11,0xc5,0x23,0x76,0x8f,0xa8,0x1e,0x71,0x70,0xc4,0xd1,0x11,0xef, +0x8f,0xe8,0x1e,0x71,0x69,0xc4,0x67,0x23,0xbe,0x1a,0xf1,0xdd,0x08,0xe3,0x08,0x2b, +0xb7,0xc1,0x6e,0xf6,0x6e,0x12,0x37,0xa9,0x9b,0x9b,0x9b,0xa7,0x9b,0xb7,0x5b,0xa0, +0x5b,0xa8,0x5b,0x94,0x5b,0x9c,0xdb,0x5d,0x6e,0xa3,0xdd,0x1e,0x72,0x7b,0xc2,0xed, +0x69,0xb7,0x29,0x6e,0x33,0xdd,0xe6,0xb9,0x2d,0x70,0x7b,0xc9,0x6d,0x91,0x1b,0xe3, +0x96,0xe4,0x96,0xea,0xb6,0xc4,0x6d,0xb9,0xdb,0x4a,0xb7,0x35,0x6e,0x39,0x6e,0x9b, +0xdd,0x76,0xb8,0xed,0x71,0x6b,0x70,0x6b,0x76,0x6b,0x71,0x6b,0x75,0x3b,0xe2,0xf6, +0xa6,0xdb,0x71,0xb7,0x4e,0xb7,0xd3,0x6e,0xef,0xba,0x9d,0x71,0x3b,0xef,0xd6,0xe5, +0xd6,0xe7,0xf6,0x89,0xdb,0x67,0x6e,0x57,0xdc,0xbe,0x76,0xfb,0xce,0xad,0xdf,0xcd, +0x52,0x36,0x48,0x36,0x44,0x66,0x27,0x1b,0x2a,0x93,0xc8,0x9c,0x64,0x2e,0xb2,0x11, +0x32,0x77,0x99,0x5c,0xe6,0x25,0xf3,0x96,0xf9,0xcb,0x82,0x64,0x21,0xb2,0x70,0x59, +0xb4,0xcc,0x20,0xbb,0x4d,0x76,0x8f,0xac,0xc1,0xed,0x01,0xd9,0xc3,0xb2,0xc7,0x65, +0x4f,0xca,0x26,0xc8,0xa6,0xc9,0xe6,0xc9,0x5e,0x90,0xbd,0x28,0x5b,0x24,0x4b,0x90, +0x25,0xca,0x52,0x64,0x4b,0x64,0xcb,0x40,0x96,0x6c,0x95,0x6c,0xad,0x6c,0xa3,0x2c, +0x17,0x14,0xc8,0x8a,0x64,0xfd,0xc6,0x62,0xd9,0x4e,0x59,0xa9,0x6c,0x0f,0x72,0x55, +0xb2,0x5a,0x59,0x83,0xac,0x59,0xd6,0x22,0x3b,0x84,0xf6,0xdb,0x64,0x47,0x65,0xed, +0xb2,0x13,0xb2,0xd3,0xb2,0xe3,0x6e,0xef,0xc8,0x3e,0x90,0x9d,0x43,0x89,0x8f,0x64, +0xbd,0xb2,0x4b,0xb2,0x4f,0x65,0x9f,0xcb,0xbe,0x94,0x7d,0x27,0x23,0x77,0x6b,0xf7, +0x21,0xee,0x42,0x77,0x07,0x77,0x17,0x77,0x37,0x77,0xb9,0xbb,0xca,0xdd,0xcf,0x5d, +0xeb,0x1e,0xee,0xae,0x77,0xbf,0xdd,0x7d,0x94,0xfb,0x03,0xee,0x8f,0xba,0x3f,0xe9, +0x3e,0xc9,0x7d,0x9a,0xfb,0x1c,0xf7,0x17,0xdc,0x5f,0x71,0x5f,0xec,0x9e,0xe6,0xbe, +0xdc,0x7d,0xb5,0xfb,0x46,0xf7,0x02,0xf7,0xad,0xee,0x25,0xee,0xe5,0xee,0xfb,0xdc, +0x8d,0xc6,0x1a,0xd0,0x00,0xfe,0x09,0x0e,0x82,0x4e,0xbe,0xd1,0xd8,0x86,0xf4,0x4d, +0xd0,0x01,0x4e,0x81,0x77,0xc0,0x07,0xe0,0x1c,0xe8,0x02,0x7d,0xe0,0x13,0xf0,0x39, +0xf8,0x0a,0x7c,0x0b,0x7e,0x00,0x16,0x23,0x8d,0x46,0x6b,0x30,0x78,0xe4,0x6f,0xbb, +0xff,0xd8,0xa1,0x9c,0x08,0x38,0x02,0x17,0x30,0x02,0x8c,0x04,0x0a,0xa0,0x06,0x7e, +0x20,0x08,0x84,0x80,0x70,0x10,0x0d,0x62,0x81,0x9b,0x95,0xa7,0xd5,0xff,0x96,0xa7, +0xd8,0xed,0xb0,0xe7,0x6e,0x70,0x1f,0x78,0x00,0x3c,0x0c,0x1e,0x07,0x4f,0x9a,0x7d, +0x30,0x01,0xe9,0x33,0x60,0x1a,0x98,0x05,0x9e,0x03,0x2f,0x80,0x97,0xc0,0xab,0x60, +0x31,0x48,0x01,0x4b,0xc0,0x72,0xb0,0x12,0xac,0x05,0x1b,0x41,0x1e,0x28,0x04,0x5b, +0xc1,0x0e,0x50,0x0a,0xca,0xc1,0x3e,0x50,0x03,0x1a,0xc0,0x3f,0xc1,0x41,0xd0,0x06, +0xde,0x04,0x1d,0xe0,0x14,0x78,0xc7,0xcc,0x8f,0x3f,0x1f,0x60,0xcf,0x39,0xd0,0x35, +0xb2,0x0f,0xf1,0x27,0xe0,0x73,0xf0,0x15,0xf8,0xf6,0x7a,0xd9,0x1f,0x90,0xab,0xe6, +0xbe,0x1b,0xb3,0xf0,0xc0,0xf9,0xf4,0x30,0x7f,0xa7,0x8d,0xd4,0x0e,0x88,0x80,0x23, +0x70,0x01,0x23,0xc0,0x48,0xa0,0x00,0x6a,0xe0,0x07,0xaa,0x2c,0x37,0x0a,0xf6,0x09, +0x82,0x3c,0xea,0xd0,0x42,0xb0,0x87,0xce,0xe3,0x75,0x41,0x84,0x47,0x0c,0xf6,0xc7, +0x81,0x3b,0xc0,0x3d,0x60,0x34,0x78,0x10,0x3c,0x02,0x9e,0x00,0xe3,0x3d,0x3e,0x14, +0x4c,0xf4,0x98,0x82,0xdc,0x74,0x30,0xdb,0xe3,0x39,0xc4,0x2f,0x80,0x97,0xc0,0xab, +0x60,0x31,0x48,0x01,0x4b,0xc0,0x72,0xb0,0xd2,0xe3,0xb7,0xce,0xf0,0x14,0x64,0x4d, +0x36,0x34,0x92,0xd6,0x70,0xbd,0xf8,0x8a,0x22,0x2c,0xfe,0x8c,0x73,0x7e,0xdf,0xc8, +0x0d,0x1e,0x43,0x86,0xe6,0x7a,0xfc,0xfc,0xc8,0x26,0x8f,0x9b,0xd7,0x61,0x45,0x1e, +0xc5,0x1e,0x25,0x1e,0x65,0x1e,0x95,0x1e,0x55,0x1e,0x75,0x1e,0x4d,0x1e,0x2d,0x1e, +0xad,0x1e,0x6f,0x78,0xb4,0x7b,0x74,0x7a,0xbc,0xe5,0xf1,0x9e,0xc7,0x19,0x8f,0x0b, +0x1e,0x3d,0x1e,0x97,0x3c,0x2e,0x7b,0x5c,0xf1,0xb8,0xea,0x71,0xcd,0xc3,0xe8,0xc1, +0x93,0xf3,0xe5,0x36,0x72,0xa1,0x5c,0x22,0x77,0x96,0x0f,0x97,0xcb,0xe4,0x72,0xb9, +0x52,0xee,0x23,0x0f,0x90,0x6b,0xe5,0x3a,0x79,0xa4,0x5c,0x2f,0x8f,0x97,0xdf,0x29, +0x1f,0x25,0x1f,0x23,0x1f,0x2b,0x7f,0x54,0x3e,0x4e,0xfe,0x94,0x7c,0x92,0x7c,0xaa, +0x7c,0x86,0x7c,0x8e,0x7c,0xbe,0x7c,0xa1,0xfc,0x15,0x79,0x82,0x3c,0x49,0x9e,0x26, +0xcf,0x90,0x67,0xc9,0x57,0xcb,0xd7,0xcb,0x73,0xe4,0x05,0xf2,0x22,0x79,0xb1,0xbc, +0x44,0x5e,0x26,0xaf,0x94,0x57,0xc9,0xeb,0xe4,0x4d,0xf2,0x16,0x79,0xab,0xfc,0x0d, +0x79,0xbb,0xbc,0x53,0xfe,0x96,0xfc,0x3d,0xf9,0x19,0xf9,0x05,0x79,0x8f,0x3c,0x55, +0x72,0x49,0x7e,0x59,0x7e,0x45,0x7e,0x55,0x3e,0x1e,0xf3,0xec,0x6b,0xf2,0x6d,0x12, +0xa3,0x9c,0xe7,0xc9,0xf7,0xb4,0xf1,0x14,0x7a,0x4a,0x3c,0x9d,0x3d,0x87,0x7b,0xca, +0x3c,0xe5,0x9e,0x4a,0x4f,0x1f,0xcf,0x00,0x4f,0xad,0xa7,0xce,0x33,0xd2,0x53,0xef, +0x19,0xef,0x79,0xa7,0xe7,0x28,0xcf,0x31,0x9e,0x63,0x3d,0x1f,0xf5,0x1c,0xe7,0xf9, +0x94,0xe7,0x24,0xcf,0xa9,0x9e,0x33,0x3c,0xe7,0x78,0xce,0xf7,0x5c,0xe8,0xf9,0x8a, +0x67,0x82,0x67,0x92,0x67,0x9a,0x67,0x86,0x67,0x96,0xe7,0x6a,0xcf,0xf5,0x9e,0x39, +0x9e,0x05,0x9e,0xfd,0xe2,0x22,0xcf,0x62,0xcf,0x12,0xcf,0x32,0xcf,0x4a,0xcf,0x2a, +0xcf,0x3a,0xcf,0x26,0xcf,0x16,0xcf,0x56,0xcf,0x37,0x3c,0x3d,0x1c,0xda,0x3d,0x3b, +0x3d,0xdf,0xf2,0x7c,0xcf,0xf3,0x8c,0xe7,0x05,0xcf,0x1e,0xcf,0x4b,0x9e,0x97,0x3d, +0xaf,0x78,0x5e,0xf5,0xbc,0xe6,0x69,0xf4,0xe4,0x29,0xf8,0x0a,0x1b,0x85,0x50,0x21, +0x51,0x38,0x2b,0x86,0x2b,0x64,0x0a,0xb9,0x42,0xa9,0xf0,0x51,0x04,0x28,0xb4,0x0a, +0x9d,0x42,0xee,0x19,0xa9,0xd0,0x2b,0xe2,0x15,0x77,0x2a,0x46,0x29,0xc6,0x28,0xc6, +0x2a,0x1e,0x55,0x8c,0x53,0x3c,0xa5,0x98,0xa4,0x98,0xaa,0x98,0xa1,0x98,0xa3,0x98, +0xaf,0x58,0xa8,0x78,0x45,0x91,0xa0,0x48,0x52,0xa4,0x29,0x32,0x25,0x19,0x8a,0x2c, +0xc5,0x6a,0xc5,0x7a,0x45,0x8e,0xa2,0x40,0x51,0xa4,0x28,0x56,0x94,0x28,0xca,0x14, +0x95,0x8a,0x2a,0x45,0x9d,0xa2,0x49,0xd1,0xa2,0xd8,0x2c,0x6a,0x55,0xbc,0xa1,0x68, +0x57,0x74,0x2a,0xde,0x52,0xbc,0xa7,0x38,0xa3,0xb8,0xa0,0x78,0x44,0xd4,0xa3,0xb8, +0xa4,0xb8,0xac,0xb8,0xa2,0xb8,0xaa,0xb8,0xa6,0x30,0x2a,0x78,0x5e,0x7c,0x2f,0x1b, +0x2f,0xa1,0x97,0xc4,0xcb,0xd9,0x6b,0xb8,0x97,0xcc,0x4b,0xee,0xa5,0xf4,0xf2,0xf1, +0x0a,0xf0,0xd2,0x7a,0xe9,0xbc,0x22,0xbd,0x92,0x14,0x7a,0xaf,0x78,0xaf,0x3b,0xbd, +0x46,0x79,0x8d,0xf1,0x1a,0xeb,0xf5,0xa8,0xd7,0x38,0xaf,0x78,0xc5,0x53,0x5e,0x93, +0xbc,0xa6,0x7a,0xcd,0xf0,0x9a,0xe3,0x35,0xdf,0x6b,0xa1,0xd7,0x2b,0x5e,0x09,0x5e, +0x49,0x5e,0x69,0x5e,0x19,0x5e,0x59,0x5e,0xab,0xbd,0xd6,0x7b,0xe5,0x78,0x15,0x78, +0x15,0x79,0x15,0x7b,0x95,0x78,0xc9,0x3d,0xcb,0xbc,0x2a,0xbd,0xaa,0xbc,0xea,0xbc, +0x9e,0x70,0x68,0xf2,0x6a,0xf1,0x6a,0xf5,0x7a,0xc3,0xab,0xdd,0xab,0xd3,0xeb,0x2d, +0xaf,0xf7,0xbc,0xce,0x78,0x5d,0xf0,0xea,0xf1,0xba,0xe4,0x35,0x4a,0x7a,0xd9,0xeb, +0x8a,0xd7,0x55,0xaf,0x6b,0x5e,0x46,0x2f,0x9e,0x92,0xaf,0xb4,0x51,0x0a,0x95,0xa3, +0x14,0x12,0xa5,0xb3,0x72,0xb8,0x52,0xa6,0x94,0x2b,0x95,0x4a,0x1f,0x65,0x80,0x52, +0xab,0xd4,0x29,0x23,0x95,0x7a,0x65,0xbc,0x72,0xb3,0xe4,0x4e,0xe5,0x28,0xe5,0x18, +0xe5,0x58,0xe5,0xa3,0xca,0x71,0xca,0xa7,0x94,0x93,0x94,0x53,0x95,0x33,0x94,0x73, +0x94,0xf3,0x95,0x0b,0x95,0x1f,0x8a,0x5f,0x51,0x26,0x28,0x93,0x94,0x69,0xca,0x0c, +0x65,0x96,0x72,0xb5,0x72,0xbd,0x32,0x47,0x59,0xa0,0x2c,0x52,0x16,0x2b,0x4b,0x94, +0x65,0xca,0x4a,0x65,0x95,0xf2,0x1e,0x49,0x9d,0xf2,0x11,0x49,0x93,0xb2,0x45,0xd9, +0xaa,0x64,0xc7,0xf1,0x1b,0x88,0xdb,0xb9,0x5c,0xa7,0xf2,0x2d,0xe5,0x7b,0xca,0x33, +0xca,0x0b,0xca,0x1e,0xe5,0x25,0xe5,0x65,0xe5,0x15,0xe5,0x77,0x62,0xa3,0xf1,0x2a, +0x8e,0x5d,0xe3,0x8e,0x1b,0x95,0x3c,0x95,0xf9,0x4d,0xbe,0xca,0x46,0x25,0x54,0x49, +0x54,0xce,0xaa,0xe1,0x2a,0x99,0x4a,0xae,0x52,0xaa,0x7c,0x54,0x01,0x2a,0xad,0x4a, +0xa7,0x8a,0x54,0xe9,0x55,0xf1,0xaa,0x3b,0x55,0xa3,0x54,0x8d,0xa2,0x31,0xaa,0xb1, +0xaa,0x47,0x55,0xe3,0x54,0x4f,0xa9,0x26,0xa9,0xa6,0xaa,0x66,0xa8,0xe6,0xa8,0xe6, +0xab,0x16,0xaa,0x5e,0x51,0x25,0xa8,0x92,0x54,0x69,0xaa,0xa7,0xa4,0x19,0xaa,0x2c, +0xd5,0x6a,0xd5,0x7a,0xd5,0x1c,0x69,0x8e,0xaa,0x40,0x55,0xa4,0x2a,0x56,0x95,0xa8, +0x24,0x5e,0x65,0xaa,0x4a,0x55,0x95,0xaa,0x4e,0xd5,0xa4,0x6a,0x41,0x68,0x55,0xbd, +0xa1,0x6a,0x57,0x75,0xaa,0xde,0x52,0xbd,0xa7,0x3a,0xa3,0xba,0xa0,0x32,0x2a,0x7b, +0x54,0x97,0x54,0x97,0x55,0x57,0x54,0x57,0x55,0xdf,0xab,0xb8,0xef,0x62,0xd4,0x56, +0x6a,0x81,0xda,0x56,0x3d,0x54,0xed,0xa0,0x96,0xaa,0x5d,0xd5,0x3a,0x95,0xbb,0xda, +0x53,0xad,0x52,0xbf,0xa1,0xf4,0x55,0x07,0xaa,0x83,0xd5,0x61,0xea,0x28,0xb5,0x41, +0x7d,0x9b,0xfa,0x2e,0xf5,0xbd,0xea,0xfb,0xd5,0x0f,0xa9,0x1f,0x53,0x3f,0xaa,0xfa, +0x87,0x7a,0x9c,0xea,0x69,0xf5,0x64,0xf5,0xb3,0xea,0x99,0xea,0xb9,0xea,0x76,0xe5, +0x42,0xcf,0xe7,0xd5,0x2f,0xaa,0xe3,0xc4,0x69,0x8a,0x4e,0xaf,0x45,0x6a,0x46,0xbd, +0x50,0x95,0xac,0x7e,0x45,0x95,0xae,0x5e,0xa6,0x5e,0xa1,0x7e,0x4b,0xb9,0x46,0xbd, +0x41,0x9d,0xab,0xde,0xa4,0xde,0xa2,0x7e,0x4f,0xb9,0x5d,0xbd,0x4b,0xbd,0x47,0xbd, +0x57,0x5d,0xad,0xae,0x57,0x97,0xa8,0x9a,0xd5,0x07,0xd4,0x12,0xaf,0xc3,0xea,0x3a, +0xd5,0x51,0xf5,0x71,0xf5,0x49,0xf5,0xdb,0xea,0xf7,0xd5,0xed,0xaa,0xb3,0xea,0x6b, +0xca,0x8f,0xd4,0x9d,0xaa,0x48,0x45,0xaf,0xfa,0x2d,0xd5,0xc7,0xea,0x33,0xaa,0xcf, +0xd4,0x5f,0xaa,0xbf,0x51,0x7f,0xaf,0x26,0xef,0x1e,0xd5,0x65,0xa5,0x95,0xf7,0x25, +0x95,0xc0,0xfb,0xb2,0xca,0xd6,0x7b,0xbc,0xc3,0x50,0x6f,0x47,0xef,0x61,0xde,0x32, +0x6f,0xb9,0xb7,0xd2,0xdb,0xc7,0x3b,0xd0,0x3b,0xc4,0x3b,0xc2,0x3b,0xc6,0xfb,0xcf, +0x5c,0xff,0xc6,0x79,0xdf,0xee,0x7d,0x97,0xf7,0x28,0xef,0x31,0xde,0x63,0x11,0x7e, +0xa9,0xd4,0x23,0xde,0xe3,0xbc,0x9f,0xf6,0x7e,0xc6,0x7b,0xfa,0x4d,0x25,0xe6,0x78, +0x63,0x1d,0xea,0xfd,0x92,0xf7,0x22,0xbb,0x14,0xbb,0x45,0xde,0x09,0xde,0x89,0xde, +0x29,0xde,0xe9,0xde,0x19,0xde,0xb7,0xd9,0x65,0x7a,0xaf,0xf6,0xde,0xe0,0x5d,0xe0, +0xbd,0xcd,0xbb,0xc4,0x7b,0x8f,0xf7,0x3e,0xef,0x5a,0xef,0x26,0xef,0x03,0xde,0x6d, +0xde,0xc7,0x50,0xbb,0xd3,0xfb,0x6d,0xef,0x0f,0xbc,0xcf,0x7b,0xf7,0x20,0xff,0x31, +0xf8,0xdc,0xfb,0x6b,0xc4,0xd7,0xbc,0xc9,0xa7,0xdf,0x68,0xed,0x33,0xc4,0x47,0xe8, +0xe3,0xe0,0xe3,0xe2,0xe3,0xe6,0x23,0xf7,0x51,0xf9,0xf8,0xf9,0x68,0x7c,0x74,0x08, +0x11,0xe6,0x10,0x6d,0x0e,0x06,0x73,0x88,0x37,0x87,0x3b,0xcc,0xe1,0x6e,0x73,0xb8, +0xd7,0x1c,0xc6,0x98,0xc3,0x83,0xe6,0xf0,0xb0,0x39,0x3c,0x66,0x0e,0xe3,0xcc,0x61, +0x3c,0xc2,0x04,0x84,0xc9,0x08,0x53,0x11,0xa6,0x23,0xcc,0x42,0x98,0x6b,0x0e,0xf3, +0xcd,0x61,0x81,0x39,0xbc,0x64,0x0e,0x8b,0x10,0x12,0xcc,0x21,0x11,0x21,0xc5,0x1c, +0xd2,0xcd,0x21,0x03,0x21,0x13,0xe1,0x8f,0x3f,0x6d,0x56,0xfa,0x98,0xc2,0x1a,0x84, +0xf5,0x08,0xd9,0x08,0x1f,0x58,0xe7,0xf9,0xe4,0xf9,0x6c,0x42,0x28,0x42,0xd8,0x66, +0x0e,0x3b,0x10,0x76,0x21,0x94,0x23,0xec,0x47,0xa8,0x43,0x68,0x46,0x38,0x88,0x70, +0x84,0x0b,0xed,0x5c,0x38,0x69,0x0e,0x6f,0xf9,0xbc,0xef,0x73,0x0e,0xdb,0xdd,0x3e, +0x97,0x7c,0x3e,0xf3,0xf9,0xca,0xe7,0x3b,0x1f,0xa3,0x8f,0x95,0xef,0x60,0x5f,0x7b, +0x5f,0x89,0xaf,0xd4,0x77,0x84,0xaf,0x87,0xaf,0xd2,0xd7,0xd7,0x37,0xc8,0x37,0xd4, +0x37,0xd2,0xd7,0xe0,0x7b,0xbb,0xef,0x3d,0xbe,0x63,0x7c,0x1f,0xf2,0x7d,0xdc,0x77, +0xbc,0xef,0x24,0xdf,0x67,0x7d,0x67,0xf9,0xce,0xf3,0x5d,0xe8,0xbb,0xc8,0x77,0xb1, +0x6f,0xaa,0x6f,0x86,0xef,0x0a,0xdf,0xb5,0xbe,0xd9,0xbe,0x05,0xbe,0x5b,0x7c,0x77, +0xf8,0xee,0xf6,0xad,0xf4,0xad,0xf6,0x6d,0xf0,0x7d,0xdd,0xb7,0xd5,0xf7,0xa8,0x6f, +0x87,0xef,0x69,0xdf,0xf7,0x7c,0xcf,0xfa,0x76,0xf9,0x5e,0xf4,0xbd,0xec,0xfb,0xa5, +0xef,0xb7,0xbe,0xfd,0xbe,0x3c,0x3f,0x81,0x9f,0x9d,0x9f,0xd8,0xcf,0xd9,0xcf,0xd5, +0x6f,0xa4,0x9f,0x97,0x9f,0x8f,0x5f,0xa0,0x5f,0x88,0x5f,0x84,0x9f,0xde,0xef,0x36, +0xbf,0xbb,0xfd,0x46,0xfb,0x8d,0xf5,0x7b,0xcc,0xef,0x49,0xbf,0x89,0x7e,0x53,0xfd, +0x66,0xfa,0x3d,0xe7,0xb7,0xc0,0xef,0x15,0x3f,0xc6,0x2f,0xc5,0x6f,0xa9,0x5f,0x96, +0xdf,0x1a,0xbf,0x8d,0x7e,0xf9,0x7e,0x45,0x7e,0xdb,0xfd,0x76,0xfb,0xed,0xf5,0xab, +0xf5,0x6b,0xf6,0x3b,0xe4,0x77,0xd4,0xaf,0xc3,0xef,0x9c,0xcf,0x69,0x3f,0xb6,0x27, +0xef,0xf9,0x9d,0xf5,0xfb,0xce,0xa7,0xcb,0x8f,0xed,0xc9,0x45,0xbf,0xcb,0x7e,0x52, +0xdf,0x2f,0xfd,0xd8,0x9e,0x7c,0xeb,0xd7,0xef,0xe7,0xeb,0xcb,0xf3,0x67,0x7b,0xc3, +0x5a,0x65,0xb2,0x68,0xc0,0x16,0x93,0x15,0x02,0xff,0x08,0x3f,0x3b,0x7f,0xb1,0xff, +0x63,0x7e,0xce,0xfe,0xac,0x7a,0x91,0x9f,0xab,0xff,0x48,0xff,0xa5,0x7e,0x5e,0xfe, +0xac,0x2e,0xeb,0x2d,0x1f,0xff,0x73,0x3e,0x81,0xfe,0x03,0xde,0x0a,0xf1,0x1f,0xf0, +0x55,0x84,0xbf,0xef,0x4d,0x3e,0xba,0xd9,0x43,0x7a,0xff,0x9b,0x7d,0xf4,0x73,0x0f, +0xb1,0xde,0xb9,0xe1,0x97,0x01,0x9f,0xdc,0xe6,0x3f,0xe0,0x91,0x01,0x6f,0xdc,0xed, +0xcf,0xfa,0x62,0xb4,0xff,0x80,0x27,0xc6,0x72,0x96,0xb0,0x36,0x98,0xd4,0x1f,0xf3, +0x9f,0xe5,0xfb,0xa4,0xff,0x44,0xff,0xa9,0xfe,0x6c,0x3b,0xae,0x5c,0x0d,0xb6,0xd4, +0x4c,0xff,0xf9,0xfe,0x2f,0xfb,0x2f,0xf6,0x4f,0xf5,0xcf,0xf0,0x5f,0xe1,0xbf,0xd6, +0x3f,0xdb,0xbf,0xc0,0x7f,0x8b,0xff,0x0e,0xff,0xdd,0xfe,0x95,0xfe,0xd5,0xfe,0x0d, +0xfe,0xaf,0xfb,0xb7,0xfa,0x1f,0xf5,0xef,0xf0,0x3f,0xed,0xff,0x9e,0xff,0x59,0xff, +0x2e,0xff,0x8b,0xfe,0x97,0xd1,0xca,0x97,0xfe,0xdf,0xfa,0xf7,0xfb,0xf3,0x02,0x7e, +0x6f,0xbd,0x81,0xed,0x27,0x61,0xcf,0x5a,0xb3,0x37,0x4c,0xfb,0xd8,0x51,0x22,0x08, +0x10,0x04,0xfc,0xa6,0xf5,0x41,0x80,0x03,0xc2,0xf0,0x00,0x8f,0x00,0x75,0x40,0x60, +0x80,0x2e,0x20,0x06,0xe1,0xf6,0x80,0x7b,0x03,0xc6,0x06,0x3c,0x11,0x30,0x21,0xe0, +0x59,0x84,0x39,0x01,0x0b,0x10,0x5e,0x45,0x48,0x0e,0xc8,0x40,0x58,0x15,0xb0,0x11, +0x61,0x13,0x42,0x71,0xc0,0x6e,0x84,0x7d,0x08,0xf5,0x01,0x2d,0x01,0x47,0x02,0x3a, +0x10,0xde,0x0e,0x38,0x13,0xd0,0x1d,0xf0,0x49,0xc0,0x97,0x08,0xd7,0x02,0x2c,0x03, +0x07,0x07,0x0e,0x0d,0x74,0x0e,0xc4,0xd2,0x31,0x50,0x81,0xe0,0x8b,0xa0,0x0d,0x8c, +0x08,0x8c,0x0d,0xbc,0x2b,0x70,0x4c,0xe0,0x23,0x81,0x4f,0x06,0xb2,0x36,0x4c,0x0e, +0x9c,0x11,0x38,0x2f,0xf0,0xa5,0x40,0x26,0x30,0x0d,0x21,0x33,0x70,0x6d,0x60,0x6e, +0x60,0x11,0xc2,0xce,0xc0,0xf2,0xc0,0xea,0xc0,0xa6,0xc0,0x43,0x81,0x6f,0x06,0x9e, +0x0c,0x7c,0x2f,0xf0,0x7c,0x60,0x5f,0xe0,0x67,0x81,0x57,0x03,0xfb,0x03,0xad,0x83, +0x6c,0x83,0x24,0x41,0xc3,0x82,0x46,0x06,0xa9,0x82,0x02,0x82,0x42,0x83,0xa2,0x83, +0xae,0x05,0x0c,0x0e,0xbc,0x2d,0x68,0x54,0xd0,0x83,0x41,0x8f,0x07,0x3d,0x1d,0x34, +0x15,0x3c,0x18,0x34,0x3b,0xe8,0x85,0xa0,0x45,0x41,0x49,0x41,0x4b,0xb1,0x7d,0x04, +0xd6,0xaf,0x0c,0xda,0x10,0xf4,0xfb,0xbf,0x09,0xbd,0x75,0x28,0x08,0xda,0x16,0x54, +0x1a,0xb4,0x3f,0xa8,0x29,0xe8,0x70,0x50,0x47,0xd0,0xbb,0x41,0x17,0x82,0x3e,0x0e, +0xba,0x12,0xe4,0xa8,0x51,0x68,0x7e,0xfa,0x9b,0x7e,0xb7,0xfe,0xf8,0x6b,0x02,0x35, +0xfd,0xc6,0x60,0x8d,0xd1,0x32,0x54,0x13,0xa6,0x89,0xd0,0xc4,0x68,0xfe,0xbd,0x6f, +0x10,0xf0,0x84,0xd1,0xdc,0xa1,0xb9,0x07,0x81,0xfd,0x7d,0x86,0x7b,0x35,0xa3,0x35, +0xf7,0x6b,0x1e,0xd2,0x3c,0xa6,0xf9,0x87,0xe6,0x69,0xcd,0x64,0x0d,0xfb,0x5d,0xf1, +0xb3,0x9a,0x99,0x9a,0xb9,0x9a,0xe7,0x39,0x7b,0x5e,0xd4,0xbc,0xac,0x71,0xb5,0x33, +0x85,0x7b,0xb8,0x5a,0x26,0x7d,0xe8,0x58,0x06,0x43,0x3f,0x54,0x13,0xf7,0xa3,0x76, +0x16,0x69,0x5e,0xd3,0x30,0x9a,0xdb,0xec,0x12,0x35,0xc9,0x9a,0x54,0xcd,0x3d,0x76, +0xfd,0xc6,0x74,0xcd,0x52,0xcd,0x32,0x4d,0xe6,0x75,0x2b,0x57,0x68,0xd6,0x68,0x36, +0xa2,0xed,0x3c,0xec,0x29,0xd4,0x6c,0xd5,0xec,0xd4,0xec,0xd6,0x54,0x6a,0xaa,0x34, +0xf5,0x9a,0x66,0xcd,0x41,0x4d,0x9b,0xe6,0x98,0xa6,0x03,0xe1,0x24,0xc2,0x5b,0x08, +0xef,0x22,0x7c,0x60,0x0e,0x67,0x11,0x2e,0x98,0x43,0x37,0x42,0x9f,0x39,0x7c,0x6c, +0x0e,0x97,0xcd,0xe1,0x0b,0x73,0xf8,0xca,0x1c,0xbe,0x41,0xb8,0x86,0xd0,0x8f,0x60, +0xa1,0xb5,0xd0,0x5a,0x99,0x03,0xdf,0x1c,0x86,0x98,0x83,0x9d,0x39,0x0c,0x35,0x07, +0x89,0x39,0x38,0x99,0x83,0x8b,0x39,0xb8,0x9a,0x83,0xcc,0x1c,0x3c,0xcc,0x41,0x61, +0x0e,0x2a,0x73,0xf0,0x31,0x07,0x7f,0x73,0x08,0x42,0x60,0x9f,0x06,0xc1,0x5a,0x53, +0xd0,0x21,0x44,0x21,0xc4,0x22,0xdc,0x81,0x60,0xfa,0x4d,0x95,0x7e,0x63,0xa8,0x66, +0x94,0x76,0x11,0xe7,0xb5,0xd7,0x34,0xf7,0x69,0x59,0xef,0xb2,0x1e,0xf5,0xd7,0x24, +0x6a,0xa6,0x38,0x8c,0xd1,0xde,0xea,0xf7,0x53,0xd8,0xd1,0x90,0x0c,0x6f,0xa7,0xe2, +0x8c,0x64,0x6a,0x7e,0xcf,0x37,0xd4,0x2f,0x6a,0xd2,0x71,0xa6,0x1f,0xd0,0xde,0xa3, +0x79,0xc3,0xf6,0xf7,0xd4,0xbf,0x57,0x33,0x56,0x3b,0x5a,0xf3,0xb0,0xf6,0x51,0xed, +0x38,0xed,0x14,0x07,0x76,0x04,0x05,0x6a,0x9e,0xd2,0x7e,0xeb,0x32,0x49,0x3b,0x55, +0x3b,0x43,0x3b,0x47,0x3b,0x5f,0xbb,0x50,0xfb,0x8a,0x36,0x41,0x9b,0xa4,0x4d,0xd3, +0xfe,0x55,0x6f,0xd0,0x32,0xb4,0x59,0xda,0xd5,0x5a,0xa2,0x3f,0xf2,0x7e,0xd9,0x34, +0x46,0x6f,0x7e,0xcb,0xcc,0x6e,0xdf,0xfc,0xa6,0x99,0xdd,0xbe,0xf9,0x6d,0x33,0xbb, +0x6d,0x7a,0xe3,0x6c,0xaa,0xbb,0x5e,0x9b,0xad,0xcd,0xd3,0x46,0xd2,0x26,0x6d,0x91, +0x76,0x1b,0xce,0xe9,0x4e,0xed,0x6e,0x6d,0x85,0x76,0xbf,0xb6,0x56,0xdb,0xa8,0x7d, +0x5d,0xfb,0xeb,0xf7,0x87,0x43,0xda,0x37,0xb4,0xc7,0xb5,0xa7,0xb4,0xef,0x6a,0xcf, +0x68,0x3f,0xd2,0xf6,0x69,0x3f,0xd5,0x5e,0xd1,0x7e,0xa3,0xfd,0x41,0x6b,0x19,0xcc, +0x0f,0xb6,0x0d,0x16,0x05,0x3b,0x05,0x0f,0x0f,0x76,0x0f,0x56,0x04,0x7b,0x07,0x07, +0x04,0x07,0x07,0x87,0x07,0xc7,0x04,0xc7,0x07,0xdf,0x15,0x7c,0x5f,0xf0,0x83,0xc1, +0x8f,0x06,0xff,0x23,0x78,0x42,0xf0,0x94,0xe0,0x19,0xc1,0x73,0x83,0x5f,0x08,0x7e, +0x39,0x38,0x21,0x38,0x39,0x78,0x49,0xf0,0x7f,0xfa,0xf7,0xa9,0x7f,0xed,0x3b,0xd0, +0xcc,0xe0,0xd5,0xc1,0x1b,0x82,0xf3,0x82,0x37,0x07,0x17,0x07,0xef,0x0a,0x2e,0x0f, +0xde,0x1f,0x5c,0x17,0xdc,0x1c,0x7c,0x30,0xf8,0x48,0x70,0x7b,0xf0,0xc9,0xe0,0x77, +0x82,0x3f,0x0c,0xbe,0x10,0xdc,0x1b,0xfc,0x49,0xf0,0x17,0xc1,0x57,0x83,0xbf,0x0f, +0xb6,0x08,0x19,0x14,0x62,0x13,0x32,0x34,0xc4,0x31,0x64,0x58,0x88,0x2c,0xc4,0x33, +0x44,0x1d,0xe2,0x1f,0xa2,0x0d,0x09,0x0b,0x89,0x0e,0xf9,0xb3,0xbf,0xa5,0xf8,0xab, +0xda,0xfb,0xe9,0xdd,0x39,0x2e,0xe4,0xce,0x90,0x7b,0x43,0x1e,0x08,0x79,0x24,0x64, +0x5c,0xc8,0xd3,0x21,0xcf,0x84,0x4c,0x0f,0x99,0x13,0xf2,0x3c,0x7a,0xf3,0x52,0xc8, +0x6b,0x21,0x49,0x21,0xe9,0x21,0xcb,0x43,0x56,0x85,0xac,0x0f,0xc9,0x0d,0x29,0x0c, +0xd9,0x16,0x52,0x12,0xb2,0x27,0x64,0x5f,0x48,0x6d,0x48,0x13,0x8e,0x1f,0x08,0x69, +0x0b,0x39,0x16,0xd2,0x19,0xf2,0x76,0xc8,0x07,0x21,0xe7,0xb1,0xdd,0x13,0xf2,0x71, +0x48,0xff,0xaf,0x7e,0x1f,0xfc,0xdb,0x8e,0xf7,0xff,0xe8,0x37,0xf6,0x3e,0x0f,0xf9, +0x32,0xe4,0x79,0xba,0x1a,0x92,0x60,0xd1,0x6f,0xfc,0x2e,0xe4,0x87,0x10,0x8b,0x50, +0xab,0x50,0xf6,0x6f,0xe0,0xf9,0xa1,0x36,0xa1,0xf6,0xa1,0xa2,0xd0,0xd9,0x1e,0x0e, +0xa1,0x45,0x16,0xce,0xa1,0x5f,0xd1,0xb0,0xd0,0x11,0xa1,0xee,0xa1,0xf2,0x50,0xaf, +0xd0,0x20,0x0f,0x75,0xa8,0x7f,0xa8,0x26,0x34,0x24,0x34,0x22,0x34,0x3a,0xb4,0x98, +0xe2,0x42,0x6f,0x0f,0x1d,0x49,0x77,0x85,0x8e,0x0a,0x15,0x0d,0xbd,0x3f,0xf4,0x80, +0xc5,0xd8,0xd0,0x47,0x42,0x1f,0x0f,0x7d,0x32,0xf4,0xb8,0xc5,0xd3,0xa1,0xfd,0xc6, +0xc9,0xa1,0x53,0x43,0xa7,0x87,0xce,0x0a,0x9d,0x1b,0x3a,0x3f,0x74,0x41,0xe8,0x4b, +0xa1,0xaf,0x85,0xde,0xf0,0x50,0x52,0x68,0x7a,0xe8,0xf2,0xd0,0x55,0xa1,0xeb,0x43, +0x73,0x43,0x0b,0x43,0xb7,0x85,0x96,0x84,0xee,0x09,0xdd,0x17,0x5a,0x1b,0xda,0x14, +0x7a,0x20,0xb4,0x2d,0xf4,0x58,0x68,0x67,0xe8,0xdb,0xa1,0x1f,0x84,0x9e,0x0f,0xed, +0x09,0xfd,0x38,0xf4,0xf3,0xd0,0xaf,0x43,0xaf,0x85,0x92,0xce,0x5a,0x37,0x44,0x27, +0xd4,0x39,0xe8,0x5c,0x74,0x6e,0x3a,0xb9,0x4e,0xa5,0xf3,0xd3,0x69,0x74,0x3a,0x5d, +0x94,0x2e,0x56,0x77,0x87,0x6e,0x94,0xee,0x7e,0xdd,0xc3,0xba,0x27,0x74,0x4f,0xe9, +0x26,0xeb,0xa6,0xe9,0x66,0xeb,0xe6,0xeb,0x5e,0xd4,0xbd,0xaa,0xfb,0xfd,0xdf,0xc0, +0x27,0xea,0xd2,0x74,0xcb,0x74,0x2b,0x75,0xeb,0x74,0x39,0xba,0x4d,0xba,0xad,0xba, +0x9d,0xba,0x32,0xdd,0x5e,0x5d,0x8d,0xae,0x51,0xd7,0xa2,0x3b,0xac,0x7b,0x53,0x77, +0x42,0xf7,0x96,0xee,0x7d,0xdd,0x39,0x5d,0xb7,0xee,0x92,0xee,0xf7,0x8c,0xa8,0x3f, +0x3a,0xbf,0xf8,0x4c,0xf7,0x95,0xee,0x3b,0x9d,0x51,0x67,0x15,0x36,0x38,0xcc,0x3e, +0x4c,0x12,0x26,0x0d,0x1b,0x11,0xe6,0x11,0xa6,0x0c,0xf3,0x0d,0x0b,0x0a,0x0b,0x0d, +0x8b,0x0c,0x33,0x84,0xdd,0x1e,0x76,0x4f,0xd8,0x98,0xb0,0x87,0xc2,0x1e,0x0f,0x1b, +0x1f,0x36,0x29,0xec,0xd9,0xb0,0x59,0x61,0xf3,0xc2,0x16,0x86,0x2d,0x0a,0x5b,0x1c, +0x96,0x1a,0x96,0x11,0xb6,0x22,0x6c,0x6d,0x58,0x76,0x58,0x41,0xd8,0x96,0xb0,0x1d, +0x61,0xbb,0xc3,0x2a,0xc3,0xaa,0xc3,0x1a,0xc2,0x5e,0x0f,0x6b,0x0d,0x3b,0x1a,0xd6, +0x11,0x76,0x3a,0xec,0xbd,0xb0,0xb3,0x61,0x5d,0x61,0x17,0xc3,0x2e,0x87,0x7d,0x19, +0xf6,0x6d,0x58,0x7f,0x18,0x2f,0x5c,0x10,0x6e,0x17,0x2e,0x0e,0x77,0x0e,0x77,0x0d, +0x1f,0x19,0xee,0x15,0xee,0x13,0xfe,0x3f,0xf7,0x97,0x1c,0xa6,0x10,0x18,0x1e,0x12, +0x1e,0x11,0xae,0x0f,0xbf,0x2d,0xfc,0xee,0xf0,0xd1,0xe1,0x63,0xc3,0x1f,0x0b,0x7f, +0x32,0x7c,0x62,0xf8,0xd4,0xf0,0x99,0xe1,0xcf,0x85,0x2f,0x08,0x7f,0x25,0x9c,0x09, +0x4f,0x09,0x5f,0x1a,0x9e,0x15,0xbe,0x26,0x7c,0x63,0x78,0x7e,0x78,0x51,0xf8,0xf6, +0xf0,0x5f,0x3b,0x47,0xbf,0x3e,0x3e,0x6e,0xde,0xff,0xf3,0xdf,0x3e,0xfd,0x73,0xfe, +0xfe,0xeb,0xd6,0x7f,0xd3,0xf0,0x7b,0x7e,0x17,0xed,0xe7,0xf3,0x87,0x1f,0xff,0xc6, +0xee,0xef,0xff,0x94,0x86,0xef,0x0f,0x6f,0x0a,0x3f,0x1a,0xfe,0x4e,0x78,0x77,0xf8, +0x95,0xf0,0xdf,0xf6,0xf7,0x2c,0xbf,0xfc,0x57,0x2d,0xff,0xc9,0x0f,0x45,0x0c,0x8e, +0x10,0x47,0xc8,0x22,0x7c,0x23,0xc2,0x23,0xfe,0xfa,0xdf,0x02,0xfa,0x57,0xe1,0x3f, +0xf5,0x3b,0x89,0x7f,0xbc,0x4e,0xbf,0xf1,0x7f,0x97,0x6d,0xfd,0x46,0xb6,0x0e,0xeb, +0x43,0x3b,0x2e,0x66,0xeb,0xb0,0xe9,0x40,0x1d,0xf6,0x9b,0x87,0x5b,0xeb,0xf4,0x1b, +0x6d,0xc0,0x8f,0x75,0xfa,0x8d,0xff,0xf3,0xbe,0xee,0x37,0xde,0xf0,0xb5,0xa9,0x3f, +0x37,0xd7,0xf9,0x69,0x7f,0x7e,0xff,0xd8,0xb9,0x59,0xe7,0x46,0x9d,0x7e,0xe3,0x08, +0x1a,0xf8,0xc6,0xe6,0xcf,0xd1,0xf9,0xbb,0xce,0xdf,0x75,0xfe,0x53,0x75,0xee,0x88, +0xb8,0x3b,0x82,0x1d,0xbb,0xbf,0xfe,0xdf,0x62,0x74,0xbc,0x1f,0xff,0xb7,0x98,0x7b, +0x23,0x7e,0xbd,0xce,0x98,0x9f,0xd4,0xb9,0x3f,0xc2,0x1f,0xe5,0x22,0xb0,0x7d,0x2f, +0x8e,0xff,0xad,0xf9,0x7f,0x4b,0x73,0x3e,0x02,0x3b,0x96,0x6e,0x35,0x77,0xfa,0xb3, +0xf7,0xfd,0x7b,0x2b,0xb9,0x5b,0xaf,0xba,0xfb,0x7f,0x56,0xf7,0xc6,0xfc,0xe2,0xe7, +0xff,0x3f,0xc8,0xf4,0xdf,0x83,0x6e,0xfd,0xbf,0x83,0x46,0x72,0xff,0x35,0x68,0xc4, +0xc8,0xb7,0xad,0x2a,0x78,0xd5,0xbc,0xcf,0xac,0x36,0x5a,0xed,0xb5,0xba,0x75,0x0b, +0x6c,0x7d,0xde,0x8f,0xea,0xb2,0xff,0x75,0x68,0x26,0xea,0x95,0xf1,0xde,0xe4,0xad, +0xb6,0xea,0x70,0xcf,0xb5,0xfa,0x2d,0xf3,0x9f,0x87,0x22,0x1e,0x8f,0x18,0x1f,0x31, +0x29,0xe2,0xd9,0x88,0x59,0x11,0xf3,0x22,0x16,0x46,0x2c,0x8a,0x58,0x1c,0x91,0x1a, +0x91,0x11,0xb1,0x22,0x62,0x6d,0x44,0x76,0x44,0x41,0xc4,0x96,0x88,0x1d,0x11,0xbb, +0x23,0x2a,0x23,0xaa,0x23,0x1a,0x22,0x5e,0x8f,0x68,0x8d,0x38,0x1a,0xd1,0x11,0x71, +0x3a,0xe2,0xbd,0x88,0xb3,0x11,0x5d,0x11,0x17,0x23,0x2e,0x47,0x7c,0x19,0xf1,0xed, +0x1f,0x9a,0xc1,0xb1,0xef,0x18,0x2f,0x6b,0xbe,0xd1,0xf4,0x1b,0x83,0xb4,0x16,0xda, +0x2f,0x34,0x43,0xb5,0xc1,0xdc,0xbb,0x3d,0xf6,0x7d,0x9e,0x95,0xd6,0x49,0xeb,0xaa, +0x1d,0xa2,0x95,0x69,0xfb,0x35,0x7c,0x2d,0xfb,0xe6,0xf1,0x2b,0xcd,0x35,0x8d,0x9d, +0x56,0xa2,0x75,0xd1,0xf6,0x47,0x2c,0xf2,0xb1,0x88,0xb4,0x8a,0xec,0x37,0xb2,0xf5, +0xfb,0x8d,0xfe,0xdc,0xbb,0x9e,0x2f,0xd8,0x77,0xb5,0xb7,0xaa,0x6f,0x1c,0xa8,0x8f, +0xd9,0x0a,0xb6,0x5c,0x7e,0xf4,0x66,0xe8,0xf2,0xf5,0xb7,0xa5,0xa6,0xfa,0x78,0x02, +0x03,0x53,0xfd,0x7e,0xe3,0x40,0x7d,0xf6,0xf8,0xcd,0xf5,0x17,0xf9,0xf4,0x1b,0x7f, +0xae,0x6f,0xb2,0xbf,0xdf,0xf8,0xaf,0xf4,0x4d,0xf6,0xe3,0xb9,0x8e,0xda,0x03,0xfd, +0x67,0xdf,0x57,0x0e,0xf4,0x9f,0xd5,0xff,0xd5,0xfe,0x5f,0xb7,0xfe,0xe7,0xfe,0xfb, +0xf7,0xea,0xf3,0x23,0x87,0x44,0xda,0x45,0x0e,0x8d,0x94,0x44,0x3a,0x45,0xba,0x44, +0xba,0x46,0xca,0x22,0x3d,0x22,0x6f,0x9c,0x9f,0xdf,0xf3,0x77,0x3e,0x8a,0x48,0x6b, +0x3c,0x21,0x4a,0x65,0x7e,0x91,0xbf,0x6f,0xcd,0x14,0x18,0xb9,0x44,0xa6,0x8d,0x0c, +0x8d,0x0c,0x8f,0x8c,0x8e,0xfc,0x5d,0x7f,0x9b,0x12,0x19,0x1f,0x79,0x47,0xe4,0x9f, +0xb3,0x92,0xb8,0x3b,0xf2,0xaf,0x5d,0x85,0xdc,0x1b,0x39,0x36,0x72,0x9a,0xcb,0x2f, +0x1f,0x1f,0x22,0x7e,0x22,0x72,0x7c,0xe4,0xc4,0x48,0x2f,0xd1,0x94,0xc8,0xe9,0x91, +0xee,0x4e,0xb3,0x23,0xe7,0x45,0x2e,0x88,0x2c,0xf1,0x7a,0x39,0xf2,0xb5,0xc8,0xc4, +0xc8,0xd4,0xc8,0xa5,0x91,0x99,0x91,0xd9,0xe2,0x55,0x91,0xeb,0x22,0xb3,0x23,0xf3, +0x23,0x37,0x47,0x6e,0x8b,0xb4,0x17,0x91,0xd3,0xce,0xc8,0x02,0xa9,0xad,0x53,0x91, +0x74,0x77,0xe4,0xcb,0x92,0x8a,0xc8,0xfd,0x91,0xb5,0x91,0x8d,0x91,0xaf,0x47,0x8e, +0x93,0x6a,0xc4,0x87,0x22,0x8f,0x44,0x1e,0x8b,0x3c,0x11,0x39,0xd0,0xfe,0xe9,0xc8, +0xb3,0x91,0x17,0x23,0xbf,0x8c,0xec,0x8f,0x14,0x44,0x89,0xa3,0x5c,0xa3,0xbc,0xa2, +0x7e,0xac,0x1f,0x18,0x15,0x1c,0xf5,0x5b,0xd7,0xcf,0x7f,0xf5,0xfa,0xfb,0xf7,0x7c, +0x6e,0x7d,0xcf,0xbf,0xa1,0x1f,0x16,0x15,0x15,0x65,0x88,0xba,0x2d,0xea,0xee,0x28, +0x99,0xea,0xbe,0xa8,0x07,0xa2,0x1e,0x8e,0x7a,0x3c,0x4a,0xae,0x7a,0x32,0x6a,0x42, +0xd4,0x33,0x51,0x4a,0xd5,0xf4,0xa8,0xd9,0x51,0xf3,0xa2,0x16,0x44,0xbd,0x12,0x95, +0x10,0x95,0x18,0x99,0x14,0x95,0x1e,0xb5,0x2c,0x6a,0x45,0xd4,0x9a,0x28,0x2b,0xf5, +0x86,0xa8,0xd1,0xa2,0xbc,0xa8,0xc2,0xa8,0xad,0x51,0x3b,0xa2,0x8e,0x44,0x96,0x46, +0x95,0x47,0x49,0xd5,0xec,0x6f,0x79,0xb8,0xaa,0xf7,0x45,0xd5,0x44,0x8d,0x55,0x34, +0x44,0x69,0x55,0xff,0x8c,0x3a,0x18,0xd5,0x16,0xf5,0x26,0x17,0x3a,0xa2,0x4e,0x47, +0xbd,0x1b,0xf5,0x61,0xd4,0xf9,0xa8,0x9e,0xa8,0x4b,0x51,0x97,0xa3,0xae,0x44,0x5d, +0x8d,0xba,0x16,0x65,0x8c,0xe2,0x45,0xf3,0xa3,0x6d,0xa2,0x85,0xd1,0x92,0x68,0x67, +0x04,0x4f,0xf5,0xf0,0x68,0x59,0xb4,0x3c,0x5a,0x19,0x1d,0xa9,0xf2,0x89,0x0e,0x88, +0xd6,0x46,0xe7,0x28,0x75,0xd1,0x91,0xd1,0xfa,0xe8,0xf8,0xe8,0x3b,0xa3,0x47,0x45, +0x8f,0x89,0x1e,0x1b,0xfd,0x68,0xf4,0x3f,0xa2,0x9f,0x8e,0x9e,0x1c,0x3d,0x25,0xf2, +0xd9,0xe8,0x99,0xd1,0x73,0xa3,0x5f,0x88,0x7e,0x39,0xfa,0xb5,0xe8,0xc4,0xe8,0xd4, +0xe8,0xa5,0xd1,0x99,0xd1,0xab,0xa2,0xd7,0x45,0x67,0x23,0xe4,0x47,0x17,0x45,0x17, +0x47,0xc7,0x2b,0x4a,0xa2,0xcb,0xa2,0xf7,0x46,0x57,0x47,0xd7,0x47,0xef,0x17,0x35, +0x47,0x1f,0x88,0x6e,0x14,0x1d,0x8e,0x3e,0x1a,0x7d,0x3c,0xfa,0x54,0xf4,0x3b,0xd1, +0x1f,0x46,0x9f,0x8f,0xee,0x8e,0xbe,0x18,0xfd,0x69,0xf4,0x17,0xd1,0x5f,0x47,0x7f, +0x17,0xdd,0x1f,0x6d,0x19,0x33,0x28,0x66,0x48,0x8c,0x30,0x46,0x12,0xe3,0x1c,0x33, +0x3c,0x66,0xbe,0xa7,0x2c,0xa6,0x5b,0xe4,0x19,0xe3,0x19,0xa3,0x8e,0xf1,0x43,0x08, +0x8a,0x09,0x89,0x89,0x88,0xd1,0xc7,0xc4,0xc7,0xdc,0x19,0x33,0x2a,0x66,0x4c,0xcc, +0xd8,0x98,0x47,0x63,0xc6,0xc5,0x3c,0x15,0x33,0x29,0x66,0x8c,0x6a,0x6a,0xcc,0xcc, +0x98,0xb9,0x31,0xcf,0xc7,0x3c,0xa4,0x7e,0x3e,0xe6,0xc5,0x98,0x47,0x55,0x8b,0x62, +0x98,0x98,0xe4,0x98,0xf4,0x98,0x71,0x2a,0xbe,0xe7,0xb2,0x98,0x15,0x31,0x6b,0x62, +0x36,0xc4,0xe4,0xc6,0x6c,0x8a,0xd9,0x12,0xb3,0x23,0xa6,0x34,0xa6,0x3c,0x66,0x5f, +0x4c,0x4d,0x4c,0x43,0xcc,0xeb,0x31,0x87,0x62,0x8e,0xc4,0x1c,0x8b,0x39,0x11,0x73, +0x3a,0xe6,0xdd,0x98,0x0f,0x63,0xce,0xc7,0x3c,0xa5,0xea,0x8e,0xb9,0x18,0x73,0x39, +0xe6,0x4a,0xcc,0xd5,0x98,0x6b,0x31,0x53,0x55,0xc6,0x18,0x9e,0x9e,0xaf,0xb7,0xd1, +0x0b,0xf5,0x12,0xbd,0xb3,0x7e,0xb8,0x9e,0xfd,0x5d,0x14,0x99,0x5e,0xae,0x57,0xea, +0x7d,0xf4,0x81,0xfa,0x60,0x7d,0x98,0x3e,0x4a,0x3f,0x43,0x65,0xd0,0xdf,0xae,0xbf, +0x5b,0x7f,0x9f,0x5e,0xe6,0xfd,0x80,0xfe,0x61,0xfd,0xe3,0xfa,0x27,0xf5,0x13,0xf4, +0x53,0xf4,0xd3,0xf5,0xb3,0xf5,0xf3,0xf4,0x0b,0xf5,0xaf,0xe8,0x13,0xf4,0x49,0xfa, +0x34,0x45,0x9a,0x3e,0x43,0xbf,0x42,0xbf,0x56,0x9f,0xad,0xcf,0xd7,0x17,0xe9,0x8b, +0xf5,0x25,0xfa,0x32,0x7d,0xa5,0x7e,0x8e,0xaa,0xd3,0xab,0x4a,0x5f,0xa7,0x6f,0xd2, +0xb7,0xe8,0x0f,0xeb,0x8f,0xea,0x8f,0xeb,0x4f,0xea,0x19,0xf5,0xdb,0xfa,0xf7,0xf5, +0xe7,0xf4,0x5d,0xfa,0x3e,0xfd,0xa7,0xfa,0x2b,0xfa,0xab,0xfa,0x64,0xf5,0x35,0xbd, +0x51,0xcf,0x33,0xf0,0x0d,0x36,0x06,0xa1,0x41,0x62,0x90,0x1a,0x5c,0x0d,0x23,0x0d, +0x0a,0x83,0xb7,0x61,0x99,0xda,0xdf,0xa0,0x31,0xe8,0x0c,0x91,0x06,0xbd,0xe1,0x36, +0xc3,0xdd,0x86,0xfb,0x0c,0x0f,0x18,0x1e,0x36,0x3c,0x8e,0xf0,0xa4,0x61,0x82,0x61, +0x8d,0xfa,0x19,0xc3,0x34,0xc3,0x2c,0xc3,0x73,0x86,0x17,0x0c,0x2f,0x1b,0x5e,0x33, +0x8c,0x51,0x24,0x19,0xd2,0x0d,0xcb,0x0c,0x2b,0x0d,0xeb,0x0c,0x39,0x86,0x02,0xc3, +0x2e,0x75,0x91,0x61,0xbb,0xa1,0xd4,0x50,0x61,0xa8,0x32,0xd4,0x21,0xec,0x51,0x2b, +0xbd,0x9b,0x0c,0x2d,0x86,0x56,0xc3,0x1b,0x86,0xe3,0x86,0x3a,0xcf,0x6a,0xf5,0x49, +0xc3,0xdb,0x86,0xf5,0xaa,0x0f,0x0c,0xe7,0x0d,0x97,0x94,0x3d,0x86,0x4b,0x86,0x22, +0xd5,0x65,0xc3,0x15,0xc3,0x55,0xc3,0xf7,0x08,0x16,0xb1,0xd6,0xb1,0x83,0x63,0xed, +0x63,0xc5,0xb1,0x4e,0xb1,0xc3,0x62,0x65,0xb1,0xf2,0x58,0x65,0xac,0x4f,0x6c,0x40, +0xac,0x36,0x36,0x2c,0x36,0x2a,0xd6,0x10,0x7b,0x5b,0xec,0x5d,0xb1,0xf7,0xc6,0xde, +0x1f,0xfb,0x70,0xec,0x13,0xb1,0xe3,0x63,0x27,0xc5,0x4e,0x8d,0x9d,0x19,0x3b,0x37, +0xb6,0x4e,0xf5,0x7c,0xec,0x4b,0xb1,0xaf,0xc5,0x26,0xc6,0xa6,0xc5,0x66,0xc4,0xae, +0x88,0x5d,0x13,0xbb,0x21,0x36,0x37,0x76,0x53,0xec,0x96,0xd8,0xed,0xb1,0xa5,0xb1, +0x15,0xb1,0x55,0xb1,0xea,0x98,0xfa,0xd8,0xe6,0xd8,0x03,0xb1,0x87,0x63,0x8f,0xc6, +0x1e,0x8f,0x3d,0x19,0xfb,0x76,0xec,0xfb,0xb1,0x67,0x63,0x3f,0x8a,0xed,0x8d,0x5d, +0xad,0xf8,0x24,0xf6,0xf3,0xd8,0xaf,0x62,0xbf,0x8d,0xfd,0x21,0xd6,0x22,0xae,0x55, +0x65,0x1d,0x37,0x38,0xce,0x2e,0x4e,0x14,0xe7,0x18,0x37,0x2c,0x4e,0x16,0xe7,0x19, +0xa7,0x8a,0xf3,0x8d,0x0b,0x8c,0x0b,0x8e,0x0b,0x8f,0x8b,0x8e,0x8b,0x8b,0xbb,0x23, +0xee,0x9e,0xb8,0x31,0x71,0x0f,0xc5,0x3d,0x16,0x57,0xec,0xf9,0x8f,0xb8,0xa7,0xe3, +0x26,0xc7,0x3d,0x1b,0x37,0x33,0x6e,0x6e,0xdc,0x49,0xf5,0xf3,0x71,0x2f,0xc6,0x2d, +0x8a,0x63,0xe2,0x92,0xe3,0xd2,0xe3,0x96,0xc5,0xad,0x88,0x1b,0x2d,0x59,0x13,0xb7, +0x31,0x2e,0x2f,0xae,0x30,0x6e,0x6b,0xdc,0x8e,0xb8,0xd2,0xb8,0x8a,0xb8,0xaa,0xb8, +0xba,0xb8,0xa6,0xb8,0x5e,0xf5,0xc7,0xea,0xe9,0x92,0x96,0xb8,0xc3,0x71,0x47,0xe3, +0x8e,0xc7,0x9d,0x8c,0x7b,0x3b,0xee,0x83,0xb8,0xf3,0x71,0xdd,0x71,0x17,0xe3,0x3e, +0x8d,0xbb,0x12,0xf7,0x99,0xfa,0x6a,0xdc,0xf7,0x71,0x16,0xf1,0xd6,0xf1,0x83,0xe3, +0xed,0xe2,0xc5,0xf1,0x4e,0xf1,0xc3,0xe2,0xdd,0xe2,0x3d,0xe2,0xbd,0xe2,0xbd,0xe3, +0xfd,0xe3,0xb5,0xf1,0xba,0xf8,0xc8,0x78,0x7d,0xfc,0x6d,0xf1,0x77,0xc5,0xdf,0x1b, +0x7f,0x7f,0xfc,0x43,0xf1,0x8f,0xc7,0x8f,0x8f,0x9f,0x18,0x3f,0x25,0x7e,0x7a,0xfc, +0x9c,0xf8,0xf9,0xf1,0x02,0x6f,0x81,0xf7,0x8b,0xf1,0x8b,0xe2,0x17,0xc7,0xa7,0xc4, +0x2f,0x89,0x5f,0x1e,0xbf,0x32,0x7e,0x6d,0xfc,0xc6,0xf8,0xbc,0x78,0x5b,0xef,0xcd, +0xf1,0xdb,0xe2,0x77,0xc6,0xef,0x8e,0xaf,0x88,0xdf,0x1f,0x5f,0x17,0xdf,0x14,0x7f, +0x20,0xbe,0x2d,0xde,0xdb,0xe1,0x58,0x7c,0x84,0xc3,0x89,0xf8,0xd3,0xf1,0xef,0xc6, +0x7f,0x18,0x3f,0xda,0xe1,0x7c,0xfc,0x9f,0xf1,0xfb,0x47,0x3f,0x7a,0x1b,0xc7,0xe6, +0xd2,0x64,0xd4,0x6c,0x34,0x5e,0x36,0xef,0x39,0xc3,0xc5,0x7a,0xf3,0x56,0xcf,0xcd, +0x77,0x36,0x1e,0xfd,0x68,0xaf,0xde,0x98,0x80,0x78,0x8c,0x91,0xfb,0xbf,0x42,0xcc, +0xf5,0x52,0xd7,0xd8,0xff,0x20,0x50,0xf0,0xad,0xd1,0xf8,0xc3,0xc1,0x2b,0x9f,0x36, +0x61,0xeb,0x87,0x4f,0xae,0x34,0x45,0x5a,0x50,0xbb,0x91,0xd7,0xff,0x29,0xb7,0xff, +0x93,0x2b,0x1f,0xb7,0x46,0x9f,0x96,0xb6,0x1a,0x5b,0x5a,0xa3,0x17,0xb3,0xda,0x7c, +0xe3,0x99,0x1f,0xb0,0xdf,0x78,0xe5,0x4c,0xf4,0xd3,0xba,0x76,0xb6,0x2d,0x6e,0xfb, +0x32,0xbb,0x3d,0xb7,0xdd,0x68,0x4f,0xdc,0x36,0x6b,0xdc,0x0f,0x9f,0x19,0xdb,0x91, +0x7e,0x6a,0x4c,0xf8,0x1e,0x4a,0x01,0x09,0xc9,0x4f,0x19,0x9b,0x8d,0xae,0xac,0x5d, +0x42,0xae,0x5f,0x67,0x8c,0x7c,0x2e,0x8d,0x4e,0x88,0xe6,0x2a,0x70,0x31,0xbb,0x91, +0x60,0xb6,0x2e,0xda,0x78,0x53,0x1f,0x64,0x6c,0xa7,0xcc,0x33,0x69,0xd9,0xcd,0xaf, +0x5d,0xd1,0x39,0x18,0x91,0x40,0x6c,0xb3,0xc6,0x33,0xec,0xff,0x85,0x41,0x6f,0x79, +0xa6,0xb2,0xc6,0xeb,0xff,0x47,0x49,0xcf,0xee,0x4f,0x30,0x0a,0x8d,0xc2,0xcf,0xb9, +0x4d,0x99,0xc9,0x3f,0x42,0xae,0xd5,0x56,0x73,0xa1,0x76,0x73,0xca,0x1a,0x50,0xc0, +0xb5,0xa1,0x37,0x7b,0x4f,0xc8,0xd9,0x7b,0xd3,0x47,0xf8,0x99,0x39,0xf3,0x8d,0xf1, +0xc2,0x4d,0xe7,0x07,0x8a,0x26,0xcf,0x9b,0xfe,0xcb,0x34,0x4e,0x03,0xdd,0xdc,0x74, +0x93,0x3b,0xd7,0x3c,0x25,0x98,0x3f,0xd7,0x8d,0xe3,0xde,0x51,0xdf,0xf8,0x70,0xd6, +0x9a,0x7b,0x99,0x70,0xf3,0xfb,0x58,0xe1,0xf5,0xf1,0x60,0x4a,0x65,0x46,0x9e,0xbe, +0xd9,0xdc,0x57,0xa3,0x90,0xe1,0xf6,0x34,0x19,0x5b,0xcc,0x7d,0x30,0xd5,0xd6,0x1b, +0xaf,0x98,0xfe,0x83,0x00,0x7d,0xc3,0x6e,0xbf,0xf6,0xda,0x6b,0x74,0x43,0xd9,0x54, +0x57,0xc8,0xfe,0xa7,0xe5,0x6f,0x06,0x14,0xcc,0x6f,0x81,0x2f,0x73,0x8d,0x54,0xa1, +0x8c,0xfe,0xa6,0x71,0xc8,0x4f,0xe3,0x92,0x2c,0xf6,0xa0,0xcc,0xe2,0xc6,0xfb,0x62, +0xfd,0x0d,0x8b,0xb9,0xbe,0x73,0x7f,0x01,0x2c,0x3c,0x7b,0xfd,0x1c,0xb0,0x71,0x93, +0xc9,0xe5,0xfa,0x1b,0xb5,0xe8,0x46,0xc7,0xb8,0x5e,0x63,0xbf,0x9e,0x1b,0x3e,0x4d, +0x2b,0xcd,0xc5,0xb9,0x4e,0x30,0xc6,0x81,0x37,0xd3,0xba,0x6f,0x4c,0xe2,0xc6,0x24, +0x93,0x77,0xaf,0xdb,0x85,0xf3,0xf1,0x3d,0x97,0x99,0xf3,0xd9,0x65,0xb8,0x52,0x9f, +0x86,0x91,0x61,0x71,0xf3,0x1b,0x6e,0xae,0xa1,0x6f,0x06,0xbc,0xa9,0xef,0x37,0x99, +0xcc,0x9a,0xc5,0x73,0xa3,0x7e,0x1c,0xb7,0xb8,0xf9,0xed,0x37,0xff,0x7b,0xb3,0x7d, +0xf0,0xef,0x8f,0xde,0x8c,0x9b,0x3c,0x17,0xc9,0xa3,0xef,0x4d,0x35,0xbe,0xbf,0x7e, +0x96,0x07,0xac,0xe1,0xce,0x11,0xeb,0x77,0xf6,0x90,0x7e,0xe0,0x62,0x3b,0xc3,0x27, +0x6e,0xb4,0xf2,0xae,0x5f,0xba,0x74,0xe3,0xec,0xb2,0xef,0x37,0x4d,0x57,0xa3,0xb9, +0x19,0x7c,0x12,0x1a,0xe0,0x80,0x81,0xff,0x47,0xc4,0x37,0xf2,0x4c,0xd7,0xe9,0x27, +0xd7,0x0a,0xc2,0x17,0x9f,0x6d,0x97,0xa1,0xfc,0x28,0xce,0x4f,0xc6,0xad,0x57,0x9b, +0x2c,0x06,0x99,0x94,0x2f,0xb3,0x75,0x59,0x9b,0x6f,0xf4,0x43,0xcf,0xb6,0xcc,0x43, +0x34,0xe0,0x27,0xee,0xca,0x10,0x9a,0x8e,0xf7,0xb0,0x67,0x29,0xe1,0xc7,0x6f,0xfd, +0xcd,0x7f,0xb9,0xcd,0x67,0x12,0xbe,0x98,0xc3,0xb6,0xff,0x6d,0x02,0x5d,0x37,0x89, +0xcc,0x2e,0xfe,0x5e,0x66,0xd2,0x31,0xde,0xf8,0xef,0x14,0x37,0x19,0xce,0x1d,0x33, +0xb5,0xc7,0x63,0xb5,0x7f,0x30,0x5d,0x52,0x37,0xc6,0x34,0x1a,0xe9,0xc7,0x35,0xc0, +0x75,0x37,0x61,0x2f,0x6b,0x6f,0x13,0x5b,0x26,0xe1,0xda,0x80,0x77,0x84,0x03,0x6d, +0x99,0xae,0x6f,0xae,0x81,0x56,0xd3,0x10,0x1e,0xf8,0x98,0xaf,0x2f,0x23,0xcf,0xe4, +0xdf,0x04,0x19,0x09,0x6f,0xf9,0xfd,0x05,0x9f,0x06,0x46,0x80,0xf9,0xaa,0x32,0x19, +0xd3,0x72,0xbd,0x40,0x02,0xa7,0xa9,0xd7,0x63,0x1e,0x68,0xbc,0x06,0x93,0xce,0x1a, +0xaf,0x8f,0x35,0x53,0x8b,0xc6,0x34,0x73,0x49,0xe6,0xc6,0x37,0x25,0x32,0x4a,0x20, +0xf3,0x65,0xcb,0x18,0x6f,0xb8,0x10,0x9f,0xcb,0x73,0x4c,0xaa,0x56,0xc8,0x2b,0xe9, +0xb3,0xeb,0x57,0xcd,0xc0,0xb5,0x21,0xfc,0xde,0x74,0x7d,0x58,0xd0,0xcd,0xf7,0xee, +0x84,0x7e,0x73,0x6b,0x66,0x5d,0xf3,0x15,0x69,0xea,0xbf,0x90,0xbe,0xe9,0x37,0xfd, +0xaf,0xe7,0x84,0xb3,0xac,0x07,0x98,0x9b,0x7a,0x29,0x43,0x0b,0x2d,0x37,0x8f,0xce, +0xeb,0xbd,0x4f,0xa2,0x1f,0xdf,0x81,0xd2,0x4c,0x63,0xd7,0x34,0x9a,0x13,0xe6,0x18, +0x13,0x0a,0xcc,0x66,0xc3,0xdb,0x2d,0x37,0xff,0x9f,0x16,0xd3,0x47,0x36,0x90,0x33, +0x9b,0xc5,0x33,0xd9,0x94,0x30,0x30,0x2f,0x37,0xed,0x6e,0x36,0x95,0xf9,0x1c,0x76, +0x98,0xee,0xcf,0x42,0x0b,0x1a,0x18,0x41,0xec,0x79,0xbd,0x7e,0x8d,0xe3,0x0e,0xca, +0x33,0x5f,0x61,0xdc,0x1e,0x0c,0xcb,0x81,0xbb,0x6e,0xc2,0x39,0xdc,0x6b,0xd9,0xab, +0xd5,0x78,0xf5,0xfa,0xed,0xef,0xc6,0x77,0x6a,0x37,0xee,0xe1,0x34,0x81,0x26,0xd2, +0x24,0x9a,0x4c,0xcf,0xd0,0x14,0x9a,0x4a,0xcf,0xd2,0x34,0x9a,0x4e,0x33,0x68,0x26, +0xcd,0xa2,0xd9,0x34,0x87,0xe6,0xd2,0x73,0x34,0x8f,0xe6,0xd3,0xf3,0xf4,0x02,0x2d, +0xa0,0x85,0xf4,0x22,0xbd,0x44,0x2f,0x93,0x3b,0xb9,0x1f,0x4d,0x07,0xc9,0xa4,0xc1, +0xd2,0xd1,0xfd,0xe8,0x62,0x3a,0x56,0x8f,0xa4,0x18,0x2b,0xc9,0xa0,0xf3,0x8b,0x93, +0x83,0xb9,0x18,0x87,0xb8,0x7c,0xcb,0x26,0x6a,0x29,0xa4,0x96,0xcd,0xd4,0x52,0x44, +0x2d,0x5b,0xa8,0x65,0x2b,0xb5,0x6c,0xa3,0x96,0x62,0x6a,0xd9,0x4e,0x2d,0x3b,0xa8, +0x65,0x27,0xb5,0x94,0x50,0xcb,0x2e,0x6a,0x29,0xa5,0x96,0xdd,0xd4,0x52,0x46,0x2d, +0x7b,0xa8,0xa5,0x9c,0x5a,0x2a,0xa8,0xa5,0x92,0x5a,0xf6,0x52,0xcb,0x3e,0x6a,0xd9, +0x4f,0x2d,0xd5,0xd4,0x52,0x43,0x2d,0xb5,0xd4,0x52,0x47,0x2d,0xf5,0xd4,0xd2,0x40, +0x2d,0x8d,0x74,0x60,0x31,0x1d,0x48,0xa2,0x03,0x29,0x74,0x20,0x8d,0x0e,0x2c,0xa1, +0x03,0x19,0x74,0x60,0x39,0x1d,0xc8,0xa2,0x03,0x2b,0xe9,0xc0,0x6a,0x3a,0xb0,0x96, +0x0e,0xac,0xa7,0x03,0x1b,0xe9,0x40,0x0e,0x1d,0xc8,0xa3,0x03,0x05,0x74,0xa0,0x90, +0x0e,0x14,0xd1,0x81,0xad,0x74,0xa0,0x98,0x0e,0xec,0xa0,0x03,0x25,0x74,0xa0,0x94, +0x0e,0x94,0xd1,0xb4,0xa3,0x69,0x34,0x6d,0x3a,0x1d,0xd8,0x47,0x07,0xaa,0xe8,0x40, +0x2d,0x1d,0xa8,0xa7,0x03,0x8d,0x34,0xf3,0xf5,0x2a,0x3a,0x98,0x48,0x07,0x93,0xe9, +0x60,0x2a,0x1d,0x4c,0xa7,0x23,0xf5,0xb3,0xe9,0x60,0x06,0x1d,0x5c,0x4e,0x07,0xb3, +0xe8,0xe0,0x4a,0x3a,0xb8,0x9a,0x0e,0xae,0xa5,0x83,0xeb,0xe9,0xe0,0x46,0x3a,0x98, +0x43,0x07,0xf3,0xe8,0x60,0x01,0x1d,0x2c,0xa4,0x83,0x45,0x74,0x70,0x2b,0x1d,0x2c, +0xa6,0x83,0x3b,0xe8,0x60,0x09,0x1d,0x2c,0xa5,0x83,0x65,0x74,0xb0,0x9c,0x0e,0x56, +0xd2,0xc1,0x7d,0x74,0xb0,0x8a,0x5a,0x9a,0xe8,0x60,0x2d,0x1d,0xac,0xa7,0x83,0x8d, +0xd4,0xb6,0x9a,0x0e,0x25,0xd1,0xa1,0x14,0x6a,0x5b,0x43,0x87,0xd2,0xa9,0x6d,0x1d, +0xb5,0xad,0xa7,0x43,0xcb,0xa8,0x35,0x8f,0xda,0x36,0x52,0x5b,0x0e,0x1d,0x5a,0x45, +0x6d,0x9b,0xa8,0xad,0x88,0xda,0x76,0x50,0xdb,0x76,0x3a,0x84,0x9d,0x65,0xd4,0x56, +0x41,0x6d,0xfb,0xe8,0x50,0x21,0x1d,0x2a,0xa2,0x43,0x5b,0xe9,0x08,0x43,0x87,0xb6, +0xd3,0x11,0xb4,0x53,0x4a,0x47,0xd2,0xe9,0xd0,0x1e,0x3a,0xb2,0x94,0x8e,0x64,0xd0, +0xa1,0xbd,0x74,0x68,0x3f,0x1d,0x59,0x45,0x87,0x6a,0xe8,0x50,0x03,0x4d,0x86,0xde, +0xcc,0xe9,0x34,0x7b,0x3a,0xb5,0x66,0x52,0xeb,0x0a,0x6a,0x5d,0x45,0xad,0x6b,0xa8, +0x75,0x1d,0xb5,0x6e,0xa0,0xd6,0x6c,0x6a,0xcd,0xa5,0xd6,0x02,0x6a,0x2d,0xa4,0xd6, +0x22,0x6a,0xdd,0x4a,0xad,0xc5,0xd4,0xba,0x83,0x5a,0x4b,0xa8,0xb5,0x94,0x5a,0xcb, +0x68,0xf2,0xcb,0xd4,0x0a,0xc9,0xb5,0x74,0xa8,0x89,0x5a,0x6b,0xa8,0xb5,0x8e,0x5a, +0x1b,0xa8,0xb5,0x89,0x0e,0x2f,0xa6,0xc3,0x49,0x74,0x38,0x85,0x0e,0xa7,0xd1,0xe1, +0x25,0x74,0x38,0x83,0x0e,0x2f,0xa7,0xc3,0x59,0x74,0x78,0x25,0x1d,0x5e,0x4d,0x87, +0xd7,0xd2,0xe1,0xf5,0x74,0x78,0x23,0x1d,0xce,0xa1,0xc3,0x79,0x74,0xb8,0x80,0x0e, +0xe5,0xd3,0xe1,0x22,0x3a,0xbc,0x95,0x0e,0x17,0xd3,0xe1,0x1d,0x74,0xb8,0x84,0x0e, +0x97,0xd2,0xe1,0x32,0x3a,0x5c,0x4e,0x87,0x2b,0xe9,0x7c,0x39,0x0e,0xd4,0xd3,0xa1, +0x6c,0xe4,0xb6,0x51,0x5b,0x22,0x1d,0x62,0xe8,0xc8,0x12,0x3a,0xb2,0x8c,0xda,0xd2, +0xa8,0x6d,0x09,0xb5,0x65,0x50,0xdb,0x72,0x6a,0xcb,0xa2,0x36,0x1c,0xad,0xa1,0xb6, +0x3a,0x3a,0xb2,0x18,0x03,0x2f,0x15,0xa4,0x81,0xa5,0x60,0x3b,0x48,0x02,0x19,0x74, +0x64,0x2d,0x1d,0x65,0x08,0x83,0xf3,0xe8,0x6a,0x3a,0x9a,0xce,0x0e,0xd2,0x1a,0x7a, +0xb3,0x9c,0xde,0xac,0xa4,0x23,0xc8,0x54,0x91,0x3b,0xb6,0x23,0xa9,0xbd,0x92,0x1d, +0xcc,0xec,0xd1,0x5d,0x84,0x33,0x7e,0xac,0x94,0x8e,0xed,0xa6,0x63,0x65,0xd4,0xbe, +0x8c,0xda,0x97,0x53,0x7b,0x26,0x1d,0x2b,0xa7,0x63,0x15,0x74,0xac,0x92,0x8e,0xed, +0xa5,0x63,0xfb,0xe8,0xd8,0x7e,0x3a,0x86,0x62,0xd5,0x74,0xac,0x96,0x8e,0xd5,0xd1, +0xb1,0x06,0x3a,0xd6,0x48,0xc7,0x9a,0xa8,0x9d,0xa1,0xf6,0xc5,0xd4,0x9e,0x44,0xed, +0xc9,0xd4,0x9e,0x42,0xed,0xa9,0xd4,0x9e,0x46,0xed,0xe9,0xd4,0xbe,0x84,0xda,0x97, +0x52,0x7b,0x06,0xb5,0xaf,0xa7,0xf6,0x8d,0xd4,0x9e,0x43,0xed,0x79,0xd4,0x5e,0x40, +0xed,0x85,0xd4,0x5e,0x44,0xed,0x5b,0xa9,0xbd,0x98,0xda,0x77,0x50,0x7b,0x09,0xb5, +0x97,0x52,0x3b,0x74,0xab,0xa9,0xbd,0x8e,0xde,0xc4,0x4f,0x3d,0xbd,0xd9,0x40,0x1d, +0x2b,0xa8,0x63,0x25,0x75,0xac,0xa2,0x8e,0xd5,0xd4,0xb1,0x86,0x3a,0xd6,0x52,0xc7, +0x3a,0xea,0x58,0x4f,0x1d,0x1b,0xa8,0x63,0x23,0x75,0x64,0x53,0x47,0x0e,0x75,0xe4, +0x52,0x47,0x1e,0x75,0xe4,0x53,0x47,0x01,0x1d,0xdf,0x43,0xc7,0xcb,0xe9,0x78,0x05, +0x1d,0xaf,0xa4,0xe3,0x7b,0xe9,0xf8,0x3e,0x3a,0xbe,0x9f,0x8e,0x57,0xd1,0xf1,0x6a, +0x3a,0x5e,0x43,0xc7,0x6b,0xe9,0x78,0x1d,0x1d,0xaf,0xa7,0xe3,0x0d,0x74,0xbc,0x91, +0x8e,0x37,0x51,0x07,0x43,0x1d,0x8b,0xa9,0x23,0x91,0x3a,0x92,0xa8,0x23,0x99,0x3a, +0x52,0xa8,0x23,0x95,0x3a,0xd2,0xa8,0x23,0x9d,0x3a,0x96,0x50,0xc7,0x52,0xea,0xc8, +0xa0,0x8e,0x65,0xd4,0xb1,0x9c,0x3a,0x32,0xa9,0x23,0x8b,0x3a,0x0a,0xa9,0xa3,0x88, +0x3a,0xb6,0x52,0x47,0x31,0x75,0xec,0xa0,0x8e,0x12,0xea,0x28,0xa5,0x8e,0x32,0xea, +0x28,0xa7,0x8e,0x4a,0xea,0xd8,0x47,0x1d,0x55,0xd4,0x51,0x43,0x1d,0x75,0xd4,0x01, +0xe3,0x9b,0xe8,0xc4,0x62,0x3a,0x91,0x41,0x27,0x96,0xd3,0x89,0x2c,0x3a,0xb1,0x92, +0x4e,0xac,0xa6,0x13,0x6b,0xe9,0xc4,0x7a,0x3a,0xb1,0x91,0x4e,0xe4,0xd0,0x89,0x3c, +0x3a,0x51,0x40,0x27,0x0a,0xe9,0x44,0x11,0x9d,0xd8,0x4a,0x27,0x8a,0xe9,0xc4,0x0e, +0x3a,0x51,0x42,0x27,0x4a,0xe9,0x44,0x19,0x9d,0x28,0xa7,0x13,0x95,0x74,0x62,0x1f, +0x9d,0xa8,0xa2,0x13,0x35,0x74,0xa2,0x8e,0x4e,0x34,0xd0,0x89,0x26,0xea,0xcc,0xa2, +0xce,0x44,0xea,0x4c,0xa6,0xce,0x54,0xea,0x4c,0xa7,0xce,0xa5,0xd4,0xb9,0x8c,0x3a, +0x33,0xa9,0x73,0x25,0x75,0xae,0xa6,0xce,0xb5,0xd4,0xb9,0x9e,0x3a,0x37,0x52,0x67, +0x0e,0x75,0xe6,0x51,0x67,0x01,0x75,0x16,0x52,0x67,0x11,0x75,0x6e,0xa5,0xce,0x62, +0xea,0xdc,0x41,0x9d,0x25,0xd4,0x59,0x4a,0x9d,0x65,0xd4,0x59,0x4e,0x9d,0x95,0xd4, +0xb9,0x8f,0x3a,0xab,0xa8,0xb3,0x86,0x3a,0xeb,0xa8,0xb3,0x81,0x3a,0x9b,0xe8,0xe4, +0x62,0x3a,0x99,0x44,0x27,0x53,0xe8,0x64,0x1a,0x9d,0x5c,0x42,0x27,0x33,0xe8,0xe4, +0x72,0x3a,0x99,0x45,0x27,0x57,0xd2,0xc9,0xd5,0x74,0x72,0x2d,0x9d,0x5c,0x4f,0x27, +0x37,0xd2,0xc9,0x1c,0x3a,0x99,0x47,0x27,0x0b,0xe8,0x64,0x21,0x9d,0x2c,0xa2,0x93, +0x5b,0xe9,0x64,0x31,0x9d,0xdc,0x41,0x27,0x4b,0xe8,0x64,0x29,0x9d,0x2c,0xa3,0x53, +0x85,0x74,0x6a,0x33,0x9d,0x2a,0xa2,0x53,0x5b,0xe8,0xd4,0x56,0x3a,0xb5,0x8d,0x4e, +0x15,0xd3,0xa9,0xed,0x74,0x6a,0x07,0x9d,0xda,0x49,0xa7,0x4a,0xe8,0xd4,0x2e,0x3a, +0x55,0x4a,0xa7,0x76,0xd3,0x29,0x14,0xde,0x43,0xa7,0xca,0xe9,0x54,0x05,0x9d,0xaa, +0xa4,0x53,0x7b,0xe9,0xd4,0x3e,0x3a,0xb5,0x9f,0x4e,0x55,0xd1,0xa9,0x6a,0x3a,0x55, +0x43,0xa7,0x6a,0xe9,0x54,0x1d,0x9d,0xaa,0xa7,0x53,0x0d,0x74,0xaa,0x91,0x4e,0x35, +0xd1,0x69,0x86,0x4e,0x2f,0xa6,0xd3,0x89,0x74,0x3a,0x89,0x4e,0x27,0xd3,0xe9,0x14, +0x3a,0x9d,0x0a,0x15,0xec,0x78,0xbb,0xf8,0x9d,0xbd,0xf4,0x4e,0x3a,0xa2,0xf7,0xd2, +0xd8,0xdc,0x52,0x44,0x67,0xb7,0xac,0x3d,0xbb,0xa5,0x1e,0xc9,0x3a,0x53,0xb2,0xde, +0x94,0xe4,0x9a,0x92,0x42,0x53,0xb2,0xd9,0x94,0x94,0x98,0x92,0x32,0x2e,0xd9,0x56, +0x78,0x76,0x1b,0x9b,0x6c,0x36,0x25,0x65,0x5c,0xb2,0xbd,0xe2,0xec,0x76,0x36,0xa9, +0x36,0x25,0xeb,0x4c,0xc9,0x7a,0x53,0x92,0x6b,0x4a,0x4a,0xb8,0x64,0x57,0xe1,0xd9, +0x5d,0x6c,0xb2,0x99,0x4b,0x6a,0x96,0x9f,0xad,0xae,0xa0,0xb3,0x75,0xcb,0xcf,0xd6, +0x22,0xa9,0x2d,0x39,0x5b,0xbb,0xd1,0x94,0x14,0xd2,0xd9,0xfa,0x0c,0x3a,0xdb,0x90, +0x78,0xb6,0xb1,0x0a,0xc9,0x32,0x53,0xb2,0xd2,0x94,0xac,0x33,0x25,0x39,0xa6,0x84, +0x39,0xdb,0xb8,0x0f,0x49,0xf9,0xd9,0x86,0x0a,0x53,0x82,0xce,0x35,0x56,0x9c,0x6d, +0x64,0xb8,0x04,0x3b,0xb8,0x5c,0xe5,0x40,0x62,0xde,0x31,0xb0,0x7f,0x15,0xd7,0x48, +0x63,0xae,0x29,0x29,0x34,0x25,0xdb,0x4c,0x49,0x89,0x29,0x59,0xc1,0x0a,0x9c,0xdf, +0xcb,0x80,0xc5,0x20,0x11,0x24,0x81,0x64,0x90,0x02,0x52,0x41,0x1a,0x48,0x07,0x4b, +0xc0,0x52,0x90,0x01,0x96,0x81,0xe5,0x20,0x13,0x64,0x81,0x15,0x60,0x25,0x58,0x05, +0x56,0x83,0x35,0x60,0x2d,0x58,0x07,0xd6,0x83,0x0d,0x60,0x23,0xc0,0xad,0x6e,0x6f, +0x0e,0xc8,0x05,0x79,0x20,0x1f,0x14,0x80,0x4d,0xa0,0x10,0x6c,0x06,0x45,0x60,0x0b, +0xd8,0x0a,0x8a,0x41,0x29,0x9d,0x4b,0xca,0xa5,0x73,0x59,0x7b,0x40,0x39,0xa8,0x00, +0x95,0x60,0x2f,0xd8,0x47,0x17,0x37,0x66,0xd0,0xb9,0x8a,0xa5,0x28,0xb3,0x02,0xac, +0x04,0xab,0xc0,0x6a,0xb0,0x06,0xac,0x05,0xeb,0xc0,0x7a,0xb0,0x01,0x6c,0x04,0xd9, +0x20,0x07,0xe4,0x81,0x7c,0x50,0x00,0x36,0x81,0x42,0xb0,0x19,0x14,0x81,0x2d,0x60, +0x2b,0xd8,0x06,0x8a,0xc1,0x76,0xb0,0x03,0xec,0x04,0x25,0x60,0x17,0x60,0xed,0xda, +0x0d,0xca,0x00,0x6c,0x4b,0x82,0x6d,0x49,0xb0,0x2d,0x09,0xb6,0x25,0xc1,0xb6,0xa4, +0x7d,0x60,0x3f,0xa8,0x02,0xd5,0xa0,0x06,0xd4,0x82,0x06,0xd0,0x08,0x9a,0xa8,0x6d, +0x05,0xb5,0xc1,0x62,0x78,0xbd,0x0d,0x1d,0x84,0xb3,0xce,0xc1,0x59,0xe7,0xe0,0x98, +0x73,0xe8,0x7c,0x1b,0x9e,0x85,0x6b,0xa9,0xad,0x80,0xda,0x0a,0xa9,0x0d,0x9b,0x90, +0xde,0x87,0x27,0x00,0x1e,0x95,0x10,0xde,0x9f,0x42,0x47,0x70,0xa4,0x9c,0xda,0xf6, +0x50,0x5b,0x25,0xb5,0xed,0xa5,0xb6,0x6a,0x3a,0x82,0x27,0x08,0x8c,0x83,0x73,0x8f, +0xac,0xa0,0x23,0x68,0xb8,0x7a,0x31,0x48,0x02,0x29,0x20,0x0d,0x2c,0x01,0x70,0x57, +0xf5,0x72,0x90,0x05,0xd8,0x32,0x70,0x55,0x35,0xdc,0x54,0x0d,0xe5,0x6a,0xb8,0xa7, +0x1a,0xae,0xa9,0x86,0x05,0xd5,0x70,0x4b,0x35,0x5c,0x52,0x0d,0x77,0x54,0xc3,0x15, +0xd5,0x70,0x43,0x35,0x5c,0x50,0x0d,0x85,0x6a,0x58,0x50,0x8d,0x6e,0x57,0xa3,0xcb, +0xd5,0xe8,0x6e,0x35,0xba,0x5a,0x8d,0x6e,0x56,0xa3,0x8b,0xd5,0x75,0x00,0x5d,0xac, +0x6e,0xa2,0x73,0x35,0xd0,0xaf,0x81,0x7e,0x0d,0xf4,0x6b,0xa0,0x5f,0x03,0xfd,0x1a, +0xe8,0xd7,0x40,0xbf,0x06,0xfa,0x35,0xd0,0xaf,0x81,0x7e,0x0d,0xf4,0x6b,0xa0,0x5f, +0x03,0xfd,0x1a,0xe8,0xd7,0x40,0xbf,0x06,0xfa,0x35,0xd0,0xaf,0x81,0x7e,0x0d,0xf4, +0x6b,0xa0,0x5f,0x03,0xfd,0x1a,0xe8,0xd7,0x40,0xbf,0x06,0xfa,0x35,0xd0,0xaf,0x81, +0x7e,0x0d,0xf4,0x6b,0xa0,0x5f,0x03,0xfd,0x1a,0xe8,0xd7,0x40,0xbf,0x06,0xfa,0xb5, +0xd0,0xaf,0x85,0x7e,0x2d,0xf4,0x6b,0xa1,0x5f,0x0b,0xfd,0x5a,0xe8,0xd7,0x42,0xbf, +0x16,0xfa,0xb5,0xd0,0xaf,0x85,0x7e,0xed,0x5a,0x9a,0x70,0xa4,0x91,0x5a,0x20,0x89, +0x8b,0xf3,0x5c,0x2d,0x24,0x6b,0x21,0x59,0x0b,0xc9,0x5a,0x48,0xd6,0x42,0xb2,0x16, +0x92,0xb5,0x90,0xac,0x85,0x64,0x2d,0x24,0x6b,0x21,0x59,0x0b,0xc9,0x5a,0x48,0xd6, +0x42,0xb2,0x16,0x92,0xb5,0x90,0xac,0x83,0x64,0x1d,0x24,0xeb,0x20,0x59,0x07,0xc9, +0x3a,0x48,0xd6,0x41,0xb2,0x0e,0x92,0x75,0x90,0xac,0x83,0x64,0x1d,0x24,0xeb,0xd0, +0xe5,0x3a,0x74,0xb9,0x0e,0x5d,0xae,0x43,0x97,0xeb,0xd0,0xe5,0x3a,0xe8,0xd7,0x41, +0xbf,0x0e,0xfa,0x75,0xd0,0xaf,0x83,0x7e,0x1d,0xf4,0xeb,0xa0,0x5f,0x07,0xfd,0x3a, +0xe8,0xd7,0x41,0xbf,0x0e,0xfa,0x75,0xd0,0xaf,0x83,0x7e,0x1d,0xf4,0xeb,0xa0,0x5f, +0x07,0xfd,0x3a,0xe8,0xd7,0x33,0x00,0x36,0xd4,0x27,0x02,0xd8,0x51,0x9f,0x0c,0x60, +0x4b,0x7d,0x2a,0x80,0x3d,0xf5,0xb8,0x4a,0xea,0x61,0x43,0x3d,0xae,0x92,0x7a,0xd8, +0x51,0x8f,0xab,0xa4,0x1e,0xb6,0xd4,0xe3,0x0a,0xa8,0x87,0x76,0x3d,0xae,0x80,0x7a, +0xe8,0xd7,0xe3,0x0a,0xa8,0x87,0x0d,0xf5,0xb8,0x02,0xea,0x61,0x47,0x3d,0x46,0x78, +0x3d,0xb4,0xeb,0x31,0xc2,0xeb,0xa1,0x5f,0x8f,0x11,0x5e,0x0f,0x1b,0xea,0x31,0xc2, +0xeb,0x61,0x47,0x03,0x74,0x1b,0xa0,0xdb,0x00,0xdd,0x06,0xe8,0x36,0x40,0xb7,0x01, +0xba,0x0d,0xd0,0x6a,0x80,0x4e,0x03,0x34,0x1a,0xd0,0xdf,0x06,0xe8,0x34,0x40,0xa7, +0x01,0x3a,0x0d,0xd0,0x69,0x80,0x4e,0x03,0x74,0x1a,0xa0,0xd3,0xc0,0xea,0x30,0x98, +0xa7,0xa0,0x07,0x5c,0x9c,0xc8,0xc5,0x49,0x5c,0x9c,0xcc,0xc5,0x29,0x5c,0x9c,0xca, +0xc5,0x69,0x5c,0xbc,0x89,0x8b,0x0b,0xb9,0x78,0x33,0x17,0x17,0x71,0xf1,0x16,0x2e, +0xde,0xca,0xc5,0xdb,0xb8,0xb8,0x98,0x8d,0x1b,0xb8,0xf2,0x0d,0x5c,0xf9,0x06,0xae, +0x7c,0x03,0x57,0xbe,0x81,0x2b,0xdf,0xc0,0x95,0x6f,0xe0,0xca,0x37,0x98,0xca,0xef, +0x41,0x7c,0xac,0x9c,0x8d,0x76,0xb1,0xdb,0x8d,0xfb,0xb9,0x18,0xde,0x68,0x2c,0x67, +0x8f,0x62,0x3a,0xb5,0x9a,0xdc,0xdf,0x4c,0x64,0xa7,0x55,0x6f,0xb2,0x7d,0xdf,0xcb, +0x16,0xad,0x62,0xa3,0xdd,0x6c,0xc9,0x26,0xce,0x56,0xdc,0xbd,0x71,0x84,0x2d,0x8b, +0x39,0x1a,0x1b,0xb3,0xf3,0xb8,0xd5,0x28,0x7f,0x0c,0xa7,0xa3,0x89,0x85,0x75,0xd3, +0x7e,0xec,0x5c,0xc3,0x15,0x58,0xc3,0x15,0x58,0xc3,0x16,0x80,0x52,0x13,0x7c,0xd6, +0xc4,0xfa,0x0c,0x77,0x8f,0xa6,0xad,0xdc,0x04,0x8e,0xa1,0xa7,0xb1,0x5d,0x8f,0xb6, +0xdb,0x97,0xb0,0x51,0x26,0xa7,0xc5,0xd9,0xd6,0x50,0xcd,0x1e,0x61,0xab,0xd3,0x79, +0x66,0x05,0x52,0x4c,0x34,0x99,0x0a,0xfc,0x98,0x13,0x53,0x6e,0x1f,0x7e,0xcc,0x09, +0x9b,0x1b,0x39,0x12,0x05,0x53,0x88,0x5d,0xc2,0x8e,0xa4,0x91,0xfa,0x1b,0x45,0xd9, +0xd2,0x81,0x14,0x4c,0x21,0x14,0x4a,0x3a,0x0a,0xa3,0x70,0xf2,0xa1,0xf3,0xe9,0xab, +0x28,0x9a,0x54,0xa4,0xa6,0x79,0xf3,0x69,0x42,0xc0,0x24,0x30,0x9f,0x5e,0xdf,0x33, +0x89,0x26,0x05,0xcc,0x01,0x2f,0x20,0x3f,0x85,0x66,0xcf,0xa1,0xf9,0xb3,0xe8,0xf9, +0x67,0x66,0xd2,0xf3,0xb3,0xe8,0x7c,0x4a,0x26,0xbd,0xb5,0x82,0xde,0x5a,0x49,0x6f, +0xad,0xa2,0xb7,0x56,0xd3,0x94,0x09,0x2f,0xa2,0x95,0x95,0xdc,0xca,0x49,0xc7,0xc5, +0xe1,0x5c,0x1c,0x14,0xc8,0x25,0x5a,0xd2,0x70,0x31,0x9b,0x0f,0xe1,0xf2,0x21,0xdc, +0xf2,0x2a,0x84,0x82,0xb9,0x98,0xdd,0x1f,0x4a,0x21,0x5c,0xcc,0xe6,0xc3,0xb8,0xa3, +0x61,0xdc,0x9e,0x30,0xd2,0x71,0x31,0xbb,0x9f,0xa6,0x4d,0xc3,0x0f,0x58,0x40,0x0b, +0xa6,0xe1,0x87,0x03,0x9b,0x2f,0xd2,0x8b,0xd3,0xf0,0x33,0x8d,0xce,0xa7,0x26,0x53, +0x20,0x27,0x75,0x3e,0xbd,0x04,0x3f,0xe6,0xc4,0x94,0xdb,0x8d,0x1f,0x73,0xc2,0xe6, +0x2e,0x30,0xe9,0x60,0x09,0xb1,0x36,0x62,0xe5,0xa7,0xa1,0x20,0x18,0x88,0xc5,0x1f, +0xcc,0x81,0x15,0xe8,0x05,0x34,0xc3,0x49,0x13,0x48,0xaa,0x20,0x35,0xa9,0x34,0x40, +0x0b,0x82,0x41,0x08,0x08,0x05,0x3a,0x10,0x06,0xc2,0x41,0x50,0x20,0x1b,0xb1,0x25, +0x83,0xd8,0xa2,0x41,0x6c,0xd9,0x20,0xb6,0x70,0x10,0x5b,0x3a,0x88,0x2d,0x1e,0xc4, +0x96,0x0f,0x62,0x2b,0x04,0xb1,0x35,0x34,0x6c,0x8d,0x09,0x60,0x22,0x98,0x04,0x26, +0x83,0x67,0xc0,0x14,0x30,0x15,0x3c,0x0b,0xa6,0x81,0xe9,0x60,0x06,0x98,0x09,0x66, +0x81,0xd9,0x60,0x0e,0x98,0x0b,0x9e,0x03,0xf3,0xc0,0x7c,0xf0,0x3c,0x78,0x01,0x2c, +0x00,0x0b,0xc1,0x8b,0xe0,0x25,0xf0,0xb2,0xfa,0x86,0x1b,0x58,0x4f,0x44,0x44,0x44, +0x53,0x34,0xfb,0x13,0x4d,0xe7,0x4b,0xf2,0x8e,0x56,0xd3,0xf9,0x3d,0x7b,0x40,0x39, +0xc0,0x48,0xda,0x83,0xe1,0xb5,0x67,0x2f,0xc0,0x70,0xda,0xb3,0x1f,0x54,0x01,0xb6, +0x4c,0x0d,0xa8,0x05,0x75,0xa0,0x1e,0x34,0x80,0x46,0xd0,0x84,0xd5,0x0e,0xa6,0x1b, +0xe5,0x98,0x6e,0x94,0x63,0xba,0x51,0x8e,0xe9,0x46,0x39,0xa6,0x1b,0xe5,0x98,0x6e, +0x94,0x63,0xba,0x51,0x8e,0xe9,0x46,0x39,0xa6,0x1b,0xe5,0x98,0x6e,0x94,0x63,0xba, +0x51,0x8e,0xe9,0x46,0x39,0xa6,0x1b,0xe5,0x98,0x6e,0x94,0x63,0xba,0x51,0x8e,0xe9, +0x46,0x39,0xa6,0x1b,0xe5,0x98,0x6e,0x94,0x63,0xba,0x51,0x8e,0xe9,0x46,0x39,0x86, +0x7a,0x39,0xa6,0x1b,0xe5,0x98,0x6e,0x94,0x63,0xba,0x51,0x8e,0xe9,0x46,0x39,0xa6, +0x1b,0xe5,0xec,0xca,0x0a,0xd3,0x8d,0x72,0x4c,0x37,0xca,0x31,0xdd,0x28,0xc7,0x74, +0xa3,0x1c,0xd3,0x8d,0x72,0x3c,0x51,0x71,0x4f,0xdd,0xd7,0x40,0x6d,0xb0,0xaa,0x7c, +0x3b,0xd8,0x09,0x76,0x01,0x76,0x55,0xb6,0x9f,0x0e,0xe3,0xd9,0x0c,0x1b,0x2b,0x60, +0x63,0x05,0xec,0xab,0x80,0x6d,0x15,0xb0,0xab,0x02,0x36,0x55,0xc0,0x9e,0x0a,0xd8, +0x52,0x01,0x3b,0x2a,0x60,0x43,0x05,0xf4,0x2b,0xa0,0x5d,0x01,0xdd,0x0a,0x68,0x56, +0x40,0xaf,0x02,0x5a,0x15,0xd0,0xa9,0xc0,0x94,0xa6,0x02,0xd3,0x99,0x0a,0x4c,0x65, +0x2a,0x30,0x95,0xa9,0xd8,0x01,0x30,0xb4,0x2a,0x4a,0x41,0x19,0x80,0x0f,0x2b,0xa0, +0x58,0x01,0xdf,0x55,0xc0,0x6f,0x15,0xf0,0x59,0x05,0xfc,0x55,0x01,0xab,0x2a,0xe0, +0xa7,0x4a,0xe8,0x57,0x42,0xbf,0x12,0xfa,0x95,0xd0,0xaf,0x84,0x7e,0x25,0xf4,0x2b, +0xa1,0x5f,0x09,0xfd,0x4a,0xe8,0x57,0x42,0xbf,0x12,0xfa,0x95,0xd0,0xaf,0x84,0x7e, +0x25,0xf4,0x2b,0xa1,0x5f,0x09,0xfd,0x4a,0xe8,0x57,0x42,0xbf,0x12,0x3d,0xab,0xc4, +0x58,0xae,0x84,0xd6,0xbe,0x42,0xea,0x2e,0x5b,0x4e,0x7d,0x8d,0x05,0xf4,0x51,0x35, +0x03,0xb6,0x83,0xfd,0xa0,0x89,0x3e,0xc2,0xf3,0xf7,0x23,0x3c,0x2b,0x3f,0xaa,0x5d, +0x06,0x36,0x81,0x5a,0xea,0x4a,0x6e,0xa2,0xae,0x94,0xad,0xa0,0x84,0xba,0x52,0x13, +0xc1,0x3a,0x80,0x7c,0xda,0x26,0xb0,0x8f,0xba,0xd2,0x19,0xea,0x5a,0x9a,0x43,0x5d, +0x19,0x35,0xd4,0xb5,0x6c,0x2d,0xc8,0x06,0xd5,0xd4,0xb5,0x7c,0x31,0xc8,0x05,0x3b, +0xa8,0x2b,0x13,0xf5,0x32,0xf7,0x53,0x57,0x56,0x3a,0x28,0xa2,0xae,0x9c,0xf5,0xd4, +0x95,0x5b,0x40,0x5d,0x45,0x68,0x67,0x0b,0x8e,0x6d,0x59,0x0a,0x50,0x77,0x4b,0x31, +0x75,0x6d,0xad,0xa4,0xae,0xd2,0x15,0xd4,0xb5,0x1b,0xed,0x96,0xa1,0x9d,0x3d,0x59, +0x60,0x33,0x40,0xbe,0x7c,0x37,0x28,0xa7,0xae,0x2a,0xe8,0x55,0xc1,0xa6,0x2a,0x36, +0xdf,0x48,0x5d,0x35,0x15,0x00,0xb6,0xe2,0x99,0xdf,0x55,0xb7,0x17,0x60,0x1f,0x66, +0xd8,0x5d,0x78,0xc0,0x75,0x35,0xa0,0x2d,0x3c,0x70,0xba,0x1a,0xd0,0x6e,0x53,0x12, +0x75,0xa7,0xa7,0x83,0xfd,0xd4,0xbd,0x24,0x83,0xba,0xd7,0x94,0x81,0xbd,0xd4,0xbd, +0x2e,0x0d,0xac,0x07,0x5b,0x40,0x0d,0x75,0xaf,0xdf,0x04,0xb6,0x52,0x77,0xce,0x1e, +0xea,0xce,0x45,0xf9,0xdc,0xed,0xd4,0xbd,0x0b,0xfb,0x4a,0x37,0x03,0x1c,0xdf,0x5d, +0x09,0x1f,0xa2,0x7e,0xd9,0x1a,0x90,0x43,0xdd,0xb0,0xb1,0x7b,0x0f,0xf2,0xb8,0x0e, +0x7a,0x16,0x97,0x50,0x4f,0xfa,0x4e,0xb0,0x1f,0xd4,0x81,0x26,0xea,0x59,0x92,0x06, +0x36,0x82,0x1c,0xea,0x59,0xba,0x8b,0x7a,0x32,0x93,0xc1,0x12,0xea,0x59,0x9d,0x0b, +0xb6,0x51,0xcf,0x9a,0x0d,0xa0,0x00,0x6c,0x07,0x7b,0xa8,0x67,0x5d,0x06,0x58,0x45, +0x3d,0x1b,0xd1,0xc6,0xc6,0x06,0xea,0xc9,0xde,0x0d,0xd0,0x4e,0x0e,0xd2,0x02,0xb4, +0x51,0xb0,0x19,0x54,0x52,0xcf,0x96,0x5a,0xea,0xd9,0x56,0x0d,0x1a,0xa9,0x67,0x07, +0xb4,0x4b,0x50,0xaf,0xa4,0x86,0x7a,0x30,0x8a,0x7b,0x2a,0xb1,0x1f,0x0f,0xe7,0x1e, +0x3c,0x80,0x7b,0x1a,0x97,0x82,0x06,0xea,0x65,0x16,0x83,0x65,0x60,0x15,0xa8,0xa4, +0xde,0xc5,0x4d,0xd4,0x9b,0xb8,0x84,0x7a,0xd3,0x8a,0xc0,0x4e,0x80,0x7d,0x69,0xf5, +0xd4,0x9b,0x8e,0x32,0xe9,0x39,0xa0,0x80,0x7a,0x97,0xec,0x06,0x15,0xa0,0x9a,0x7a, +0x37,0x2e,0x07,0x25,0xd4,0x5b,0xc8,0x00,0x94,0x29,0x44,0xbd,0xad,0x8d,0xd4,0xbb, +0x2d,0x83,0x7a,0x8b,0xd1,0xe6,0x76,0xec,0xc7,0xf5,0xdf,0x8b,0xeb,0xb8,0x17,0xd7, +0x63,0x6f,0x39,0xea,0xe0,0x5a,0xe8,0xdd,0xb7,0x05,0xec,0xa1,0xde,0xfd,0x68,0x1f, +0x93,0xa9,0xde,0xba,0xa5,0xd4,0xdb,0x88,0xf6,0xf1,0x18,0xed,0xc5,0xf2,0xa3,0x2f, +0x71,0x25,0xf5,0xa5,0x2c,0xa1,0xbe,0xb4,0x54,0xb0,0x0c,0x60,0x7b,0x6d,0x15,0xf5, +0xad,0x63,0xa8,0x6f,0x43,0x2e,0xf5,0x65,0xef,0x07,0x35,0xd4,0x97,0xb3,0x9d,0xfa, +0xf2,0x70,0x2c,0x2f,0x1f,0x6c,0x06,0x3b,0xa8,0xaf,0x20,0x03,0x94,0x82,0x4a,0xea, +0xdb,0xb4,0x98,0xfa,0x36,0xa3,0x4c,0x51,0x0e,0x28,0xa0,0xbe,0x6d,0xeb,0xc0,0x46, +0xb0,0x8b,0xfa,0x76,0x62,0x7f,0xc9,0x06,0x80,0xfd,0xbb,0xb6,0x82,0x32,0x50,0x01, +0xea,0xa9,0xaf,0x34,0x9b,0xfa,0x2a,0xb1,0x0f,0xf3,0xc8,0x3e,0x8c,0xa1,0x3e,0x4c, +0xfe,0xfa,0x30,0xa9,0xeb,0xc3,0x44,0xae,0x0f,0x13,0xb7,0x3e,0x4c,0xda,0xfa,0x30, +0xd1,0xea,0xc3,0x24,0xab,0xaf,0x3e,0x13,0xac,0x06,0x9b,0x00,0xca,0x34,0x2c,0x05, +0xab,0x70,0x3d,0xb1,0xd7,0x14,0x6c,0x6d,0xdc,0x44,0xfe,0x78,0x4e,0xac,0xc2,0xc8, +0x4f,0x06,0x29,0xe4,0x7e,0x21,0x71,0x23,0x1b,0x65,0xd3,0x85,0xc4,0xf4,0x0b,0x89, +0x4b,0x91,0x54,0x5e,0x48,0x4a,0xa7,0x73,0xc9,0x98,0x32,0x25,0x63,0xca,0x94,0x8a, +0x99,0x7d,0x32,0xa6,0x0e,0xa9,0x58,0x54,0xa4,0x62,0x9a,0x97,0x8c,0xe9,0x53,0x32, +0xa6,0x4f,0xc9,0x98,0x3e,0xa5,0xe2,0xf1,0x9f,0x8a,0x89,0x46,0x2a,0x26,0x10,0xa9, +0x98,0x76,0xa5,0x62,0xda,0x95,0x8a,0x69,0x57,0x32,0x16,0x31,0xc9,0x98,0xd2,0x25, +0x63,0x4a,0x97,0xcc,0xb6,0x85,0xe9,0x41,0x32,0xa6,0x9a,0xc9,0x58,0x08,0x25,0x63, +0xba,0x99,0xbc,0x0c,0x60,0xca,0x99,0x9c,0x09,0x30,0xed,0x4c,0xc6,0x1c,0x23,0x19, +0x73,0x8c,0x64,0x4c,0xfb,0x52,0x50,0x36,0x05,0xd3,0xaf,0x14,0x4c,0xbf,0x52,0x30, +0xfd,0xc2,0xd5,0x7d,0x2e,0x05,0xd3,0xaf,0x14,0x4c,0xbf,0x52,0xb0,0xd0,0x49,0xc1, +0x94,0x33,0x05,0x36,0xe1,0x8a,0x3f,0x97,0x02,0x9b,0x52,0x60,0x53,0x0a,0x16,0x3a, +0x29,0x98,0x7e,0xa6,0xc0,0x9e,0x14,0xd8,0x93,0x02,0x7b,0x52,0x60,0x4f,0x0a,0xec, +0x49,0x61,0xed,0xc1,0x34,0x32,0x19,0x53,0xbc,0x34,0xd8,0x93,0x06,0x7b,0x70,0x16, +0xcf,0xa5,0x41,0x3b,0x0d,0x53,0xbf,0x34,0x4c,0xfb,0xd2,0x30,0xcd,0x4d,0xc6,0x1a, +0x27,0x0d,0xd3,0xdc,0x34,0x4c,0x73,0x93,0x91,0x26,0x63,0xf1,0x95,0x8c,0xa9,0x4d, +0x32,0x6c,0x49,0x86,0x2d,0xc9,0xd0,0x4f,0x86,0x76,0x32,0x74,0x93,0xa1,0x9b,0xcc, +0xfa,0x02,0xba,0xc9,0xd0,0x4d,0x86,0x5e,0x32,0xa6,0x9a,0x29,0xf0,0x59,0x0a,0x34, +0x52,0xd8,0xf6,0x61,0x47,0x1a,0x6b,0x07,0xda,0x4f,0xc1,0xe2,0x2e,0x05,0x1a,0x78, +0x9e,0x9f,0x4b,0x65,0xfd,0x06,0x1b,0x52,0xd1,0xdf,0x54,0xf4,0x37,0x15,0xb6,0xa5, +0x42,0x2b,0xb5,0x10,0x77,0xb9,0x25,0xb8,0xfb,0xe4,0x20,0x5d,0x0a,0x4a,0x01,0xae, +0x98,0x35,0x15,0x48,0x71,0xe7,0xc3,0x6a,0xa9,0x6b,0x0b,0xee,0x56,0xb9,0x7b,0x48, +0x85,0x93,0xa3,0x66,0xe3,0x44,0x2e,0x4e,0xe2,0xe2,0x14,0x2e,0x4e,0xe5,0xe2,0x34, +0x2e,0x5e,0xc2,0xc5,0x19,0x5c,0xbc,0x8c,0x8b,0x33,0xb9,0x38,0x8b,0x8b,0x57,0x70, +0xf1,0x4a,0x2e,0x5e,0x85,0xf8,0xe2,0x1e,0xb6,0xcd,0x4b,0x89,0x1b,0xd8,0x38,0x63, +0x0b,0x1b,0xe7,0xd5,0xb3,0x71,0x71,0x3a,0x1b,0xef,0x59,0x83,0xf8,0xe3,0xc4,0x5d, +0x6c,0xbc,0x36,0x99,0x8d,0xf3,0xd9,0x16,0x3e,0xde,0xb3,0x9d,0x8d,0x6b,0xf6,0x22, +0xfe,0x24,0x89,0x6d,0xe1,0x93,0x65,0xac,0xd6,0x27,0x6b,0xd9,0x76,0x3e,0x2e,0x62, +0x5b,0xf8,0x78,0xc3,0x96,0x8f,0x37,0x25,0x9b,0x32,0x9f,0xe4,0xb0,0x19,0xdc,0xda, +0xd9,0xb8,0x76,0x19,0x97,0x67,0xed,0x44,0xb7,0xb9,0x3d,0xac,0x4a,0x57,0x4a,0x29, +0xb7,0x3f,0x89,0xcb,0x97,0xb0,0xf9,0x9a,0x3c,0x36,0xbf,0x7c,0x31,0x62,0xdc,0xf2, +0x10,0xe3,0x46,0xc6,0xe6,0xf7,0xec,0xe5,0xf6,0xb0,0x36,0xe0,0xb2,0x64,0xcb,0xe4, +0x16,0xb0,0x7b,0xd6,0x6f,0x65,0xe3,0x4d,0x3b,0xb9,0xa3,0x6c,0xfb,0x3d,0x5b,0x1a, +0xd9,0xa3,0x2b,0x96,0xb3,0xf9,0x25,0x35,0x88,0x7b,0x2b,0x0a,0xd9,0xfc,0x56,0xae, +0xe5,0xa5,0x6c,0x3b,0x1f,0xd5,0x15,0xb1,0xf9,0x95,0xac,0xcd,0x5d,0xa5,0xdb,0xd8, +0xa3,0x39,0xec,0x9e,0x8f,0xea,0x59,0xdd,0xde,0xca,0x34,0xce,0x86,0x35,0x5c,0x2d, +0xce,0xc2,0x7a,0x56,0x11,0xb7,0x26,0x2e,0xae,0x54,0x53,0xd7,0x5a,0x3c,0x0d,0x6a, +0xea,0xa9,0x67,0x77,0x16,0xcd,0x7d,0xfe,0x19,0xd2,0x04,0x91,0x46,0x43,0x1a,0xcc, +0x17,0x83,0x49,0x83,0x99,0x62,0x28,0x69,0x74,0xa4,0x09,0x23,0x4d,0x38,0x69,0x03, +0x49,0x1b,0x44,0x5a,0x0d,0x69,0xb5,0xa4,0x0d,0x26,0x6d,0x08,0xc1,0xff,0x04,0xef, +0x13,0x7c,0x4f,0xf0,0x3c,0xc1,0xef,0x04,0xaf,0x13,0x7c,0x4e,0xf0,0x38,0xc1,0xdf, +0x04,0x6f,0x13,0x7c,0x4d,0xf0,0x34,0xc1,0xcf,0x04,0x2f,0x63,0x5f,0xf5,0xc5,0xca, +0x4d,0x04,0x57,0x7f,0x9c,0x87,0xad,0xec,0x3d,0x78,0x30,0xae,0xc1,0x03,0x91,0x1d, +0x3e,0x49,0x78,0x68,0xe6,0x11,0xfc,0x80,0x87,0x04,0x6e,0xe8,0x5b,0xf0,0xe0,0x59, +0xb1,0x1c,0x37,0xfa,0x1a,0xdc,0xf8,0x0a,0x09,0x7d,0xc7,0xc3,0x11,0x37,0xe6,0x62, +0xf6,0x06,0x8f,0x1b,0xda,0x62,0x0c,0xaf,0xe4,0x9d,0xb8,0x2d,0xe0,0xc1,0x52,0x89, +0x1b,0xd2,0x26,0x3c,0x6c,0xb1,0x1a,0xeb,0x4a,0xdd,0x88,0x07,0x0b,0x1e,0x8c,0x55, +0xdb,0xf0,0x80,0xc4,0x83,0x6a,0x59,0x1d,0x1e,0x80,0x78,0x48,0x96,0xe2,0xe1,0x90, +0x53,0x84,0x32,0xb8,0x71,0x63,0x02,0x00,0xdf,0x60,0x88,0xe6,0x92,0x36,0x94,0xb4, +0x3a,0xd2,0x62,0xda,0x1b,0x4e,0xc1,0x98,0x9d,0x07,0x51,0xb0,0x86,0x82,0xb5,0x14, +0x1c,0x4c,0xc1,0x98,0x23,0x87,0x52,0xb0,0x8e,0x82,0xc3,0x28,0x38,0x9c,0x42,0x30, +0x59,0x65,0x1f,0x61,0x1a,0x36,0xd2,0xb2,0x51,0x30,0x1b,0x85,0xb0,0x51,0x28,0x1b, +0xe9,0xd8,0x28,0x8c,0x8d,0xc2,0xd9,0x28,0x28,0x90,0x8b,0xb9,0x3a,0x41,0x5c,0xa5, +0x67,0xa7,0xd2,0x33,0xf3,0xc0,0x02,0x9a,0xf9,0xfc,0x64,0xdc,0xbb,0x36,0x83,0x2d, +0x60,0x1b,0xd8,0x0e,0x76,0x82,0x12,0x50,0x0a,0xca,0x40,0x39,0x7b,0x7f,0x03,0xfb, +0x40,0x15,0xa8,0x01,0x75,0xa0,0x01,0x34,0xd1,0x85,0xa4,0xc5,0x20,0x19,0xa4,0x12, +0x7b,0x13,0xbc,0x90,0x84,0xfb,0x61,0x52,0x06,0x58,0x06,0x96,0x83,0x4c,0x90,0x05, +0x56,0x81,0xb5,0x60,0x03,0xc8,0x01,0xf9,0xa0,0x00,0x6c,0x02,0x85,0x00,0x76,0x24, +0xc1,0x8e,0x24,0xd8,0x91,0x04,0x3b,0x92,0x76,0x00,0xd8,0x92,0x04,0x5b,0x92,0x76, +0x01,0xd8,0x93,0x04,0x7b,0x92,0xf6,0x00,0xd8,0x94,0x84,0x8b,0xbc,0x6e,0x4b,0xd7, +0xaa,0x65,0x6c,0x17,0x2e,0x24,0xad,0xbc,0x90,0x54,0xcf,0xe9,0xb3,0x1b,0x25,0x50, +0xba,0x90,0x58,0x68,0xda,0xc0,0xbd,0x39,0xdb,0xd4,0xcb,0xcd,0x5c,0x19,0xb6,0x6f, +0x5b,0x60,0x22,0x7b,0x24,0x71,0x8f,0x69,0xa3,0x92,0xeb,0x46,0xe2,0xb6,0x0b,0x89, +0x3b,0xb0,0xc1,0x3a,0x02,0xfd,0x44,0xf7,0xb9,0x0a,0x4b,0xb8,0x6d,0xe4,0x12,0xd1, +0x6e,0x3d,0xeb,0x21,0xae,0x6a,0x8d,0x29,0x57,0xcf,0xf5,0x00,0x87,0xd8,0x76,0x38, +0xdf,0xc1,0xf4,0x0b,0x49,0x49,0x26,0x63,0xb0,0x51,0x8a,0xdd,0xa6,0x7a,0xbb,0xb8, +0x8d,0x4a,0x53,0xae,0x92,0xf3,0x40,0xe2,0x6e,0x6c,0x70,0x09,0x6b,0x10,0x5b,0x08, +0x25,0xb6,0x5e,0xaf,0xb1,0x9b,0xeb,0x0b,0x73,0xfd,0x48,0xa9,0x39,0x81,0xe1,0x9c, +0xca,0xa6,0x81,0xed,0xa4,0x42,0x53,0xff,0x4d,0xdd,0x33,0xed,0x2a,0xbb,0x6e,0xc5, +0x8d,0xc2,0xe6,0x1c,0x57,0x92,0x35,0xa4,0x8c,0x15,0x48,0xac,0xe7,0x8c,0x2f,0x35, +0x6d,0x97,0x72,0x2d,0x2d,0x67,0xcf,0x3c,0xd7,0xe9,0x1a,0xd3,0xf3,0xad,0x84,0x3b, +0xb3,0x6c,0x0e,0x47,0xf3,0xd8,0xf1,0xc0,0x56,0xe2,0x1a,0xe0,0x36,0x38,0x1f,0x5e, +0x77,0x47,0x15,0xd7,0x05,0xb3,0x83,0xeb,0xae,0x3b,0xd8,0x94,0x63,0x47,0x09,0x33, +0xd0,0x76,0x52,0x1a,0x37,0xac,0x92,0x96,0x98,0xce,0xb4,0xc9,0xae,0xa4,0xa5,0xa6, +0x71,0x93,0x39,0xd0,0x85,0xa4,0x2c,0xce,0x44,0x76,0x9c,0x71,0x67,0xfa,0xa6,0x96, +0x4c,0x67,0x9e,0x3d,0xb2,0x82,0xcb,0xed,0x32,0x35,0xb4,0x86,0x3d,0xdf,0x38,0x89, +0x66,0x9f,0xb0,0xdb,0x65,0xd7,0x73,0xac,0xc4,0x6a,0xd3,0x16,0x3b,0x50,0x06,0xce, +0xd8,0x12,0xd3,0x76,0xd1,0xc0,0x58,0x4a,0x5a,0xc7,0xee,0x46,0x67,0x12,0x8b,0x07, +0x0a,0x27,0x99,0x06,0x48,0xd2,0x06,0xb6,0xb9,0xc4,0xa6,0x81,0x11,0xc5,0x0e,0xb1, +0x06,0x2e,0x61,0xcf,0xe3,0x2a,0xae,0x00,0xeb,0xb2,0x64,0xd3,0x3e,0xd3,0x70,0x61, +0x73,0x30,0xbd,0x1a,0xb9,0x8d,0x5c,0x8e,0xbd,0x7c,0xf2,0x06,0x06,0x20,0xab,0x97, +0xcb,0x55,0x62,0x73,0x39,0x26,0x99,0x3c,0xee,0xd0,0x12,0xd3,0x0e,0xb3,0x94,0x29, +0xc7,0x1e,0xcd,0x1f,0x38,0x05,0xa5,0x03,0x1b,0x5c,0x81,0x7c,0xae,0x33,0x59,0xa6, +0x5c,0x09,0x77,0x15,0xb3,0xb9,0x4a,0xee,0xb4,0x14,0x9b,0xaa,0x16,0x0c,0x9c,0x6b, +0xd3,0x06,0x77,0xa5,0x15,0x70,0x27,0x6d,0xc5,0x75,0xa1,0x42,0x6e,0x6c,0x72,0xc9, +0xf5,0x13,0x73,0xf3,0x38,0x4b,0xda,0x32,0x70,0x7d,0x98,0x73,0xec,0xbe,0x6d,0xa6, +0x8b,0x8e,0xb8,0xb6,0x92,0xae,0x17,0xdd,0x69,0xba,0xa0,0x4b,0x58,0xf7,0xb3,0xa3, +0x99,0xcd,0xd5,0x73,0x0e,0xe6,0xae,0x6f,0xd3,0x6d,0xc0,0x74,0x59,0x60,0x4e,0x55, +0x61,0x6a,0x61,0x60,0x04,0x07,0xf6,0xc0,0x7d,0x41,0x6c,0xa4,0x61,0x23,0x2d,0x1b, +0x05,0xb3,0x51,0x08,0x1b,0x85,0xb2,0x91,0x8e,0x8d,0xc2,0xd8,0x28,0x9c,0x2b,0x6c, +0xaa,0xc2,0xd5,0x09,0xe2,0x2a,0x05,0x71,0xb5,0x82,0xb8,0x6a,0x41,0x5c,0xbd,0x20, +0xae,0x62,0x10,0x57,0x33,0x88,0xab,0x1a,0xc4,0xd5,0xd5,0x70,0x75,0x35,0x26,0x3d, +0xae,0xae,0x86,0xab,0xab,0xe1,0xea,0x3e,0x3b,0x77,0x02,0x4d,0x9e,0x40,0x13,0x5e, +0xa0,0x89,0x13,0xe6,0xd1,0x9c,0x05,0x34,0x77,0x12,0x4d,0x9e,0x85,0x1f,0x0d,0xd0, +0xd2,0xb4,0x17,0xf0,0x3c,0xab,0xec,0x4e,0x5f,0x41,0xdd,0x1b,0x4a,0xd9,0xbb,0x13, +0xd6,0x40,0xec,0x93,0xa0,0x7b,0x43,0x66,0x37,0x56,0x82,0x78,0xb0,0x74,0xd5,0x67, +0x7d,0x54,0x9f,0xcd,0x3e,0x59,0xd0,0xd2,0xec,0x09,0x74,0xac,0x7e,0x02,0xcd,0x9a, +0x40,0x33,0xf0,0x33,0x91,0x66,0x4d,0xa4,0xa9,0x13,0x69,0xd2,0x84,0x99,0x34,0x83, +0x8d,0xe6,0x4e,0xa1,0xd9,0x53,0x50,0x82,0x65,0x2a,0xcd,0x9a,0x4a,0x33,0xa6,0xd2, +0xb3,0x2f,0xd3,0x0c,0x30,0x0b,0x4c,0x05,0xcf,0x83,0x63,0xf5,0x33,0x69,0xd6,0x4c, +0x9a,0x8c,0x5a,0x33,0x69,0xca,0x2c,0x9a,0x3d,0x0b,0xbb,0x66,0xd1,0xac,0x59,0x34, +0x69,0x16,0xcd,0x60,0x33,0x1a,0xe4,0x34,0x84,0x9f,0x19,0x6c,0x02,0x3b,0x27,0x01, +0xfc,0xcc,0x60,0x93,0xf3,0xe9,0x6b,0xe7,0x9b,0x62,0x1c,0x87,0x51,0xb3,0xc0,0x54, +0x30,0x6f,0xc2,0x64,0x16,0xee,0xb0,0x39,0xd5,0xd0,0xdc,0xf9,0x34,0x7b,0x3e,0x9a, +0x47,0x8d,0xf9,0x34,0x77,0x01,0xcd,0x5e,0x80,0x8d,0x05,0x34,0x6b,0x01,0xcd,0x80, +0x2f,0x16,0xd2,0xec,0x85,0xd8,0x5e,0x48,0xb3,0x16,0xd2,0x0c,0xfc,0xb4,0x2f,0xa1, +0x59,0x60,0xe2,0x73,0x34,0x69,0x12,0x4d,0x9a,0x4c,0x93,0xd0,0x08,0xfa,0x30,0x19, +0xdd,0x7c,0x89,0x9e,0x9d,0x00,0x6f,0xd2,0xb4,0xd9,0x34,0x63,0x06,0xcd,0x78,0x9e, +0x66,0xce,0xa2,0x99,0xb3,0x69,0xe6,0x9c,0xa9,0x34,0xf3,0x45,0x9a,0x35,0x0d,0x5d, +0x9a,0x03,0x0f,0x3c,0x4b,0x73,0xe7,0xce,0xa2,0xb9,0xf3,0x68,0x3e,0x7e,0x16,0xd0, +0xc2,0x89,0xb4,0x00,0x6d,0xcc,0xa2,0x09,0x5c,0x1c,0xc4,0x2e,0xeb,0x34,0x6c,0xa4, +0x65,0xa3,0x60,0x36,0x0a,0x61,0xa3,0x50,0x36,0xd2,0xb1,0x51,0x18,0x1b,0x85,0xb3, +0x11,0x9e,0x85,0x6c,0xcc,0xd5,0x09,0xe2,0x2a,0x05,0x71,0xb5,0x82,0xb8,0x6a,0x41, +0x5c,0xbd,0x20,0xae,0x62,0x10,0x57,0x33,0x88,0xab,0x1a,0xc4,0xd5,0xd5,0x70,0x75, +0x35,0x26,0x3d,0xae,0xae,0x86,0xab,0xab,0xe1,0xea,0x6a,0xb8,0xba,0x1a,0xae,0xae, +0x86,0xab,0xab,0xe1,0xea,0x6a,0xb8,0xba,0x5a,0xae,0xae,0x96,0xab,0x3b,0x15,0x67, +0xf5,0xe2,0xc6,0xc5,0x20,0x09,0xa4,0x80,0x34,0xb0,0x04,0x2c,0x07,0x59,0x60,0x25, +0x58,0x0d,0xd6,0x82,0xf5,0x60,0x23,0xc8,0x01,0x79,0xa0,0x00,0x14,0x82,0x22,0xb0, +0x15,0x14,0x83,0x1d,0xa0,0x04,0x94,0xd2,0xc5,0x6c,0xb4,0x9b,0x8d,0x76,0xb3,0xd1, +0x6e,0x36,0xda,0xcd,0x46,0xbb,0xd9,0x19,0x00,0x6d,0x67,0xa3,0xed,0x6c,0xb4,0x9d, +0x8d,0xb6,0xb3,0xd1,0x76,0x36,0xda,0xce,0x46,0xdb,0xd9,0x68,0x3b,0x17,0xed,0xe5, +0xa2,0xbd,0x5c,0xb4,0x97,0x8b,0xf6,0x72,0xd1,0x5e,0x2e,0xda,0xcb,0x2d,0x03,0x95, +0x60,0x1f,0xa8,0x02,0x35,0xa0,0x0e,0x34,0x80,0x26,0xba,0x98,0x07,0xbd,0x3c,0xe8, +0xe5,0x41,0x2f,0x0f,0x7a,0x79,0xd0,0xcb,0x83,0x5e,0x1e,0xf4,0xf2,0xa0,0x87,0xa5, +0xdd,0xc5,0x3c,0xe8,0xe5,0x41,0x2f,0x0f,0x7a,0x79,0xd0,0xcb,0x83,0x5e,0x1e,0xfa, +0x92,0x87,0xbe,0xe4,0xa1,0x2f,0x79,0xd0,0xce,0x83,0x76,0x1e,0xb4,0xb1,0xfc,0xbb, +0x98,0x07,0xed,0x3c,0x68,0xe7,0x41,0x3b,0xaf,0x16,0xd4,0xd3,0xb9,0x7d,0xd0,0xcd, +0x83,0x5e,0x3e,0xf4,0xf2,0xa1,0x97,0x0f,0xbd,0x7c,0xe8,0xe5,0x2f,0x03,0xd0,0xc8, +0x87,0x46,0x3e,0xda,0xcf,0x47,0xfb,0xf9,0x68,0x3f,0x1f,0xed,0xe7,0xa3,0xfd,0x7c, +0xb4,0x9f,0x8f,0xf6,0xf3,0xd1,0x7e,0x3e,0xda,0xcf,0xdf,0x41,0x6d,0xbb,0xe8,0x48, +0x3e,0x1d,0x41,0xe5,0x52,0xb6,0x12,0x3a,0x96,0x8f,0x8e,0xe5,0x43,0x20,0x1f,0x1d, +0xcb,0x47,0xc7,0xf2,0x21,0x54,0x00,0xa1,0x02,0x56,0x08,0x2b,0x8d,0xfd,0x99,0xc8, +0xa7,0x83,0xa5,0xd4,0xb6,0x05,0x09,0xfa,0x56,0x80,0xbe,0x15,0x40,0xb7,0x00,0x4d, +0x14,0xa0,0x6f,0x05,0xd0,0x2e,0x80,0x36,0x96,0xf2,0x87,0x20,0x5f,0xb0,0x9f,0x2e, +0xee,0x42,0xab,0xa5,0xab,0xe8,0x08,0x96,0x6c,0x99,0x58,0x12,0x65,0x62,0x89,0x96, +0x89,0x65,0x51,0x26,0x96,0x45,0x99,0x58,0xa2,0x65,0x62,0x89,0x96,0x89,0x25,0x5a, +0x26,0x96,0x48,0x99,0x58,0xa2,0x65,0x62,0x99,0x94,0x89,0x25,0x5a,0x26,0x96,0x4a, +0x99,0x58,0x2a,0x65,0x62,0xa9,0x94,0x89,0xa5,0x52,0x26,0x96,0x4a,0x99,0x58,0xa2, +0x65,0x62,0x69,0x94,0x89,0xa5,0x51,0x26,0x96,0x68,0x99,0x58,0xa2,0x65,0x62,0x89, +0x96,0x89,0xe5,0x53,0x66,0x15,0xa8,0x06,0x35,0xa0,0x16,0xd4,0x01,0x78,0x2c,0xb3, +0x01,0x34,0x82,0x26,0x3a,0x97,0x85,0x25,0x56,0x16,0x96,0xa5,0x59,0x58,0x92,0x66, +0x61,0x29,0x9a,0x85,0x25,0x55,0x16,0x96,0x54,0x59,0x58,0x6e,0x66,0x61,0xe9,0x95, +0x85,0xa5,0x55,0x16,0x96,0x9a,0x59,0x58,0x6a,0x66,0x61,0xa9,0x99,0x85,0xa5,0x58, +0x16,0xec,0xce,0xc2,0x72,0x2f,0x0b,0x4b,0xcd,0x2c,0x2c,0x35,0xb3,0xb0,0xf4,0xca, +0xc2,0xd2,0x2b,0x0b,0xcb,0xbf,0x2c,0x38,0x25,0x0b,0x4b,0xc3,0xac,0x75,0x00,0x4b, +0xb5,0x2c,0x2c,0xd5,0xb2,0xb0,0x54,0xcb,0xc2,0x12,0x36,0x2b,0x07,0xb0,0xdf,0xed, +0x61,0x39,0x98,0x85,0x25,0x5a,0x16,0x96,0x86,0x59,0xe8,0x7f,0x16,0xfa,0x9f,0x85, +0xfe,0x67,0xa1,0xff,0x59,0xe8,0x7f,0x16,0xfa,0x9f,0x85,0xfe,0x67,0xa1,0xff,0x59, +0xe8,0x7f,0x16,0xfa,0x9f,0x85,0xfe,0x67,0xa1,0xff,0x59,0xe8,0x7f,0x16,0xfa,0x9f, +0x85,0xfe,0x67,0x95,0x51,0x6f,0x79,0x3a,0x75,0xe7,0xec,0xc5,0x7c,0x19,0x29,0x16, +0xee,0x1f,0x55,0x57,0x60,0x4e,0xbd,0x95,0xba,0xb6,0x62,0x9e,0xbd,0x0e,0x73,0xe8, +0xad,0xd8,0x9f,0xc6,0xbe,0x58,0xd9,0x41,0x3d,0x8d,0x29,0xd4,0xbb,0xa1,0x89,0x7a, +0xf3,0x6b,0xa9,0xb7,0xa8,0x9a,0xfa,0x12,0xb3,0xa8,0x7b,0x7b,0x22,0x75,0xef,0xcd, +0xa1,0x9e,0xa4,0x8d,0xd4,0x03,0x9b,0x7a,0x57,0x60,0xd1,0x8f,0xe5,0x70,0x5f,0x71, +0x39,0xe6,0xfd,0x89,0x98,0x83,0xef,0xa3,0xee,0x5d,0xc9,0xd4,0xc3,0xbe,0x20,0xd9, +0x50,0x4a,0x7d,0xd5,0xf9,0xd4,0xb5,0x0f,0xf7,0xef,0xa6,0x12,0xea,0x5d,0xbf,0x9c, +0x7a,0xb7,0x6e,0xa1,0xee,0x0c,0xf6,0xa5,0xca,0x06,0xea,0xdd,0x54,0x40,0x5d,0x75, +0x4b,0xb1,0x36,0x58,0x4f,0xdd,0xfb,0x76,0x52,0x4f,0x46,0x3d,0xf5,0x61,0xa6,0xf2, +0x51,0x63,0x2a,0xe6,0xfc,0x55,0xd4,0x95,0x91,0x4f,0xdd,0xab,0x93,0xa9,0xbb,0x64, +0x35,0xda,0x5b,0x81,0xb9,0x7e,0x31,0xda,0x4c,0xa5,0xde,0x8d,0xb9,0xd4,0x5b,0x55, +0x46,0x7d,0xb9,0x15,0xd4,0x57,0x8a,0xb4,0xaa,0x96,0x7a,0x36,0x2f,0xc3,0x7a,0xa2, +0x89,0x7a,0xf6,0x6f,0xa2,0x5e,0xf8,0xbf,0x6f,0x59,0x32,0xf5,0x96,0xac,0xa3,0xae, +0x22,0x68,0xd4,0xc3,0x9e,0x72,0xec,0x5f,0xdc,0x88,0xb5,0xc7,0x66,0xea,0x29,0x5a, +0x8a,0xfe,0x27,0x52,0x5f,0x0e,0x34,0x8a,0x36,0x50,0x57,0xf9,0x66,0xf4,0x6b,0x35, +0x75,0x57,0x65,0x53,0x77,0x7d,0x16,0xf5,0xec,0x2d,0xa3,0x9e,0x6a,0xac,0x47,0x36, +0x66,0xc0,0x86,0x55,0xd4,0x9b,0x88,0x34,0x2d,0x17,0x40,0x63,0x7b,0x2e,0x34,0x1a, +0xa1,0x51,0x8e,0xe3,0xfb,0xa8,0x77,0x37,0x83,0xfe,0x64,0x41,0xab,0x11,0xbe,0xac, +0xa1,0xae,0xb2,0x62,0xea,0x66,0x56,0x51,0x4f,0x66,0x1a,0xf5,0xac,0xdd,0x83,0xb5, +0xca,0x7a,0xe8,0xd5,0xa1,0x4f,0x4d,0xd4,0xd5,0xb8,0x03,0x65,0x96,0x63,0x6d,0xb3, +0x8c,0xba,0xd7,0x56,0x43,0x67,0x33,0x7c,0x9f,0x44,0x5d,0x85,0xf9,0xd4,0x93,0x8b, +0x35,0xcc,0x4a,0xf8,0x65,0x27,0xd6,0x4a,0xbb,0x6b,0xa9,0xbb,0x02,0xe7,0x21,0x03, +0x3a,0x19,0x5b,0xa9,0x1b,0x63,0xbe,0x67,0xed,0x56,0xf8,0x77,0x37,0xd6,0x55,0x58, +0x23,0xa5,0x2d,0xa1,0xee,0xcd,0x8b,0xa9,0xa7,0x12,0xfe,0x58,0x82,0x73,0x5a,0xb2, +0x8a,0xfa,0xd2,0xb0,0xf4,0xcb,0xd8,0x47,0x5d,0x2b,0x71,0x0e,0xea,0x76,0x51,0xf7, +0xfa,0x14,0xf8,0x1c,0xfd,0xdd,0x82,0x73,0xb3,0x0e,0xe7,0x61,0x07,0xd2,0xda,0xf5, +0xd4,0x57,0x97,0x89,0xf3,0x9f,0x8a,0xf5,0x54,0x15,0xf5,0x36,0x40,0x1f,0xab,0xb9, +0xee,0x54,0x9c,0x9f,0x74,0xf4,0x63,0x15,0xdb,0xff,0x22,0xea,0x49,0xc1,0x5a,0x6d, +0x15,0x28,0x5e,0x4a,0x3d,0x55,0x18,0x2b,0x8b,0xa1,0x51,0xbf,0x8d,0x7a,0x57,0xef, +0xa6,0x3e,0xa6,0x88,0xfa,0x96,0x2f,0xa5,0xae,0x74,0xac,0xbf,0x96,0x62,0x4d,0xb6, +0xaa,0x01,0x63,0x21,0x1d,0xe3,0x83,0xd5,0x5d,0x42,0x5d,0x4d,0x38,0xff,0xcb,0xf1, +0x68,0xde,0xbd,0x9b,0x7a,0xf6,0x40,0x1f,0xe3,0x01,0x2b,0x0b,0xea,0xca,0x81,0x6f, +0xf6,0xa3,0x5f,0x0c,0xfc,0x87,0x6b,0xaf,0x67,0x25,0x3b,0xbe,0xb2,0xd1,0x76,0x2a, +0xf5,0xa5,0xef,0xc5,0xb9,0xd8,0x4f,0x7d,0x79,0xe9,0x58,0xf3,0x6d,0x80,0xaf,0x32, +0xa8,0x67,0x1b,0xb4,0x52,0xb1,0x3f,0xbb,0x9a,0xba,0xb1,0xa2,0xf9,0xa8,0x16,0x63, +0x22,0x29,0x1b,0xfe,0x85,0x0f,0xf6,0x34,0x51,0xf7,0x3a,0x8c,0xbf,0xb4,0x4c,0x8c, +0xd3,0x44,0xd8,0x85,0x71,0xb3,0xb8,0x9e,0xba,0xb3,0x51,0x7f,0x03,0x8e,0x2f,0x85, +0x7f,0xf2,0x60,0x43,0x41,0x25,0xc6,0xd5,0x62,0xea,0xae,0x85,0xe6,0x0a,0xf4,0x67, +0x2d,0xea,0x14,0x96,0xc0,0xef,0x2b,0xa8,0x0f,0x3e,0xef,0x4e,0x87,0xc6,0xc6,0x6a, +0xea,0x62,0x4a,0xa8,0x6b,0x2f,0xd6,0x98,0x55,0x3b,0xd1,0x4f,0xac,0x3f,0xa1,0xdf, +0x9d,0x82,0x71,0xb7,0x09,0xfe,0xca,0x86,0x6e,0x3a,0x7c,0xbe,0x02,0xfe,0x2d,0xc7, +0xb9,0xd8,0x80,0x71,0x92,0x07,0x1f,0x6e,0xde,0x8e,0xf3,0xb8,0x15,0xed,0xa6,0x52, +0xcf,0x7a,0x8c,0xa9,0x06,0xac,0x69,0x8b,0x30,0x0e,0x8a,0x0a,0xd1,0x17,0xf8,0x75, +0x19,0x6c,0x64,0x5f,0x10,0xaf,0xc8,0x83,0x9d,0x18,0xbb,0xab,0x30,0xde,0xd7,0xd7, +0xfe,0x3f,0xf6,0xde,0x06,0xa8,0xa9,0x6b,0xed,0xfb,0x5e,0x51,0x50,0xa2,0x50,0x82, +0x82,0x82,0x82,0x05,0x25,0x0a,0x96,0x40,0x52,0x93,0x96,0x20,0xb4,0xa0,0xa0,0x04, +0x12,0xbe,0xa3,0x44,0x41,0xa1,0x05,0x4c,0x20,0x91,0x04,0x12,0x20,0x90,0x40,0x02, +0x49,0x48,0x42,0x62,0x49,0x05,0x0a,0x2d,0xb4,0xa0,0xa0,0x60,0xc1,0x8a,0x10,0x05, +0x0b,0x56,0xee,0x91,0xe7,0x96,0x3e,0x32,0x23,0x33,0x72,0x17,0x5a,0x79,0x47,0x4e, +0x09,0xc2,0x3d,0xf2,0x0e,0xcc,0xc8,0x8c,0xcc,0xc8,0xcc,0xbb,0x56,0xd8,0xf6,0xf5, +0x9c,0xe7,0x9c,0xfb,0x7c,0xf5,0x9c,0xe7,0x7c,0x90,0x5f,0xd7,0x7f,0xed,0xf5,0xb1, +0xf7,0x5e,0xeb,0xba,0xae,0xb5,0xf6,0x8e,0x61,0xa6,0xf0,0x7a,0xd0,0x7e,0xdd,0xf0, +0xba,0x77,0xbe,0x02,0xb3,0x70,0x97,0x9d,0xbd,0x5d,0x05,0xd7,0x42,0x3b,0x78,0xd6, +0x09,0x7d,0x7c,0x13,0xc6,0x4d,0x95,0x02,0x3c,0x2b,0x6f,0x00,0x73,0x5d,0xd0,0x0e, +0xdf,0x2a,0xc0,0x9c,0xe1,0x16,0xbc,0x3f,0xbc,0x8e,0x16,0xae,0xcd,0x3b,0x57,0x60, +0x4c,0xc0,0xb5,0xd0,0x03,0xe3,0xfa,0x3a,0xf4,0x6f,0x2f,0x9c,0xc3,0xe7,0xd0,0x3f, +0xe8,0x1f,0xda,0xe0,0x13,0xcf,0xf2,0xed,0x45,0x18,0x1f,0x0a,0x60,0xf9,0x0c,0xa6, +0x16,0xe8,0xcb,0x86,0x5e,0x18,0x2b,0x30,0xb6,0x0c,0x70,0x6d,0x7d,0x01,0x7d,0xd9, +0x3a,0x00,0xd7,0x08,0x2c,0xb7,0xc1,0x71,0x5f,0xf9,0x04,0xda,0xbb,0x0e,0xde,0x13, +0xc6,0x58,0x3d,0x8c,0xf1,0xaf,0xe1,0xfa,0x56,0xc0,0x54,0x01,0xd7,0xf3,0x65,0xb8, +0xa6,0x2e,0x43,0x9b,0xb6,0xc2,0xef,0xe0,0xb7,0xa0,0x0f,0xe0,0x77,0xab,0xf9,0xcf, +0x6f,0x43,0xbf,0x40,0xdb,0x56,0x5c,0x85,0xf7,0x80,0xf7,0x82,0x6b,0xd8,0x52,0x05, +0xfd,0x6a,0x44,0xfb,0x06,0xfc,0x1e,0x0f,0xd7,0xa5,0xa5,0xa1,0x1d,0xde,0x17,0xde, +0x1b,0xda,0xc6,0xd2,0x0d,0xd7,0x79,0x79,0x0d,0xb4,0x23,0xb4,0x93,0x06,0xda,0xab, +0xf2,0x26,0x8c,0x79,0xb8,0x7f,0x40,0x5b,0xcd,0xc2,0x27,0xe7,0xec,0x25,0x38,0x7e, +0xf3,0x6d,0x30,0xdb,0x87,0x62,0x0e,0xda,0x4f,0x0d,0xe3,0x45,0x0b,0x7d,0x53,0x0d, +0x8f,0x2f,0x99,0xe0,0x18,0xa1,0xbf,0xe0,0x5e,0xf4,0xac,0x0d,0xda,0xae,0x0d,0x8e, +0xf3,0x8a,0x11,0x26,0xe8,0xef,0x0e,0x68,0x9f,0x6b,0x30,0xf6,0xbf,0x81,0x79,0x1f, +0xec,0xd3,0x0f,0x8f,0x07,0x6f,0x82,0x39,0x05,0xdc,0xab,0x2a,0xbb,0xe0,0x7a,0x80, +0x7e,0x30,0x7d,0x06,0xe6,0x5a,0xab,0xc1,0xdc,0x95,0x3a,0x30,0xd7,0x09,0xd7,0x55, +0x27,0xac,0xeb,0xb9,0x08,0xe6,0x7a,0x61,0x9c,0xde,0x85,0x71,0xf6,0x05,0xf4,0xc1, +0x57,0xdf,0xc1,0x58,0x83,0x31,0xa2,0x34,0x83,0xc5,0xd6,0xaa,0xeb,0x60,0x4e,0x0b, +0x0d,0xde,0x77,0x05,0x6e,0x3c,0x70,0x11,0xc1,0x41,0xcf,0xdc,0x85,0x13,0x51,0xab, +0x61,0x19,0xe6,0x55,0xd0,0xf8,0x55,0xd0,0x09,0xb5,0xb5,0x70,0xb2,0x0d,0xd0,0xc0, +0xd0,0xc1,0x97,0x7a,0xe0,0x66,0xa9,0x82,0xa9,0x06,0x58,0x3a,0x60,0xb9,0x13,0x4e, +0xfa,0xdb,0x4f,0x61,0x82,0xed,0x83,0x30,0x60,0xee,0x76,0xc1,0xc0,0xad,0x87,0x06, +0x80,0x93,0x57,0xc1,0xc5,0xac,0x6e,0x86,0x01,0x07,0x17,0x1b,0x7c,0x60,0xcc,0x56, +0x37,0x82,0x59,0xd3,0xa7,0xd0,0x20,0x75,0x70,0xf3,0xfb,0x02,0x06,0x14,0xcc,0xbf, +0x85,0xf9,0xb7,0x30,0xf0,0x15,0xd0,0x41,0xf0,0xf1,0xfa,0x4c,0x6b,0x06,0xcf,0xf4, +0x70,0x23,0x32,0x75,0x83,0x67,0x35,0x30,0xc8,0x6a,0xbe,0x05,0xcf,0xea,0x61,0x30, +0xd5,0x7f,0x05,0x9d,0x09,0x37,0x60,0xb8,0x89,0x3f,0x6b,0x82,0x4e,0x6d,0x82,0x86, +0xb8,0x0c,0x37,0xa6,0x6b,0xb0,0x5f,0x37,0xec,0x63,0x86,0x6d,0x03,0xd0,0xa9,0x46, +0xe8,0x54,0xb4,0xe1,0x37,0xc1,0xc9,0xb7,0x41,0x23,0x5c,0x81,0x1b,0xe7,0x35,0xb8, +0x99,0x7f,0x0d,0x03,0xee,0x6b,0x68,0xa8,0xeb,0x70,0x13,0x1c,0x80,0x0e,0x57,0xc2, +0x4d,0x54,0xd3,0x00,0xe6,0x75,0xd0,0x30,0x0d,0xd0,0xe9,0xf0,0xb1,0x3b,0xdf,0x5c, +0x05,0xe6,0x3b,0x3f,0x05,0x8b,0x97,0x5a,0xf4,0x48,0x54,0x60,0xf1,0x32,0x7c,0x46, +0xfd,0x7c,0xbd,0x09,0xcc,0x28,0xa0,0x99,0x14,0xfd,0x60,0xb1,0x4d,0xa7,0x83,0xd2, +0x53,0x0d,0x16,0xaf,0xc2,0xb0,0x9b,0x1f,0xac,0x00,0xf3,0x77,0x2f,0x80,0xac,0x2c, +0x90,0xc5,0x03,0x59,0xf0,0xbd,0x19,0x65,0x30,0xcf,0x17,0x83,0xf1,0x5e,0xf4,0xc7, +0x4b,0xbd,0xe8,0x8f,0x9e,0x7a,0xd1,0xdf,0x39,0xdd,0x5d,0x2b,0x76,0x81,0x1f,0x1a, +0xfe,0xab,0x17,0xfc,0x70,0xf3,0xbf,0x6e,0x83,0x1f,0x2e,0x81,0x1f,0x6a,0xc0,0x0f, +0x5f,0x80,0x1f,0x1a,0xc1,0x0f,0x4d,0xe0,0x87,0x76,0xf0,0xc3,0x35,0xf0,0x43,0xc7, +0x0f,0x4a,0x24,0xe5,0x50,0xfe,0x6b,0xc0,0x7a,0x0c,0x33,0x58,0xaa,0x46,0x67,0x54, +0xff,0x57,0x1f,0x92,0x01,0xf0,0x83,0x09,0xc9,0xa7,0x48,0x2e,0x22,0xa9,0x41,0x52, +0x8b,0xa4,0x0e,0x49,0x3d,0x92,0x06,0x24,0x9f,0x23,0xf9,0x02,0x49,0x23,0x92,0x2f, +0x91,0x34,0x23,0x69,0x41,0x72,0x19,0x49,0x2b,0x92,0x2b,0x48,0xae,0x22,0x69,0x47, +0xd2,0x81,0xe4,0xda,0xda,0x45,0xfb,0xd1,0xdd,0xbe,0x43,0x57,0xf9,0x0e,0x75,0x86, +0x52,0x0d,0x47,0x3c,0xd9,0x0d,0x26,0xbf,0x05,0x93,0x77,0xc1,0x8f,0x0a,0x30,0x79, +0x07,0x4c,0x7e,0x07,0x26,0xfb,0xc1,0x8f,0xad,0xe0,0xc7,0x2b,0xe0,0x47,0x15,0xf8, +0xb1,0x02,0xfc,0xa8,0x01,0x3f,0x56,0x82,0x1f,0x8d,0xe0,0x47,0x03,0xf8,0xf1,0x02, +0xf8,0x51,0x0b,0x7e,0xac,0x07,0x3f,0x9a,0xc0,0x8f,0x1d,0xe0,0xc7,0x6f,0xc0,0x8f, +0x3d,0xe0,0xc7,0x6e,0xf0,0xe3,0x1d,0xf0,0xe3,0xb7,0xe0,0x27,0x05,0xf8,0x49,0x09, +0x7e,0xbc,0x0b,0x7e,0xfa,0x14,0xfc,0x74,0x11,0xfc,0xd8,0x05,0x7e,0xaa,0x04,0x3f, +0x69,0xc0,0x4f,0x5a,0xf0,0x53,0x15,0xf8,0x49,0x0d,0x7e,0xd2,0x81,0x9f,0xaa,0xc1, +0xa4,0x0e,0x4c,0x5c,0x99,0xb8,0x0a,0xe5,0xa7,0x5a,0x28,0x93,0x5a,0x74,0x54,0x89, +0x44,0x83,0xc4,0x5a,0xac,0x46,0x0d,0xb0,0xb7,0x01,0x75,0xed,0x44,0xd2,0x85,0x6a, +0xd4,0x48,0xf4,0x60,0xa2,0x1d,0xd5,0xb5,0xa3,0xba,0xf6,0x89,0xeb,0x50,0x50,0x43, +0x3b,0xba,0x6e,0x3b,0x6a,0xbd,0x86,0x5a,0xaf,0xa1,0xd6,0x6b,0xa8,0xf5,0x1a,0x6a, +0xbd,0x86,0x5a,0xaf,0xa1,0xd6,0xaf,0x51,0xeb,0xd7,0xa8,0xee,0x6b,0x54,0xf7,0x35, +0xaa,0xeb,0x44,0x9d,0x3b,0x51,0x5d,0x17,0x6a,0xed,0x42,0x47,0xd7,0xd1,0xd1,0x75, +0xd4,0x70,0x1d,0x15,0x7b,0x50,0xb1,0x07,0x15,0x7b,0xd0,0x45,0x7b,0x50,0x9d,0x19, +0x15,0xcd,0xe8,0xe8,0x16,0x6a,0xbd,0x85,0x8a,0xb7,0x50,0xeb,0x2d,0x54,0x77,0x1b, +0x15,0x6f,0xa3,0xa3,0x3e,0x24,0xfd,0xa8,0x4b,0x3f,0x3a,0xba,0x83,0x8e,0xee,0xc0, +0xa3,0x49,0x25,0x3c,0x82,0xd2,0x85,0xe4,0x3a,0x14,0x6b,0x1d,0x1c,0x15,0x14,0x3d, +0x98,0x2c,0x47,0x0d,0xe5,0xa8,0xae,0x1c,0xd5,0x95,0xa3,0xba,0x0a,0x68,0x38,0x28, +0x9d,0x48,0xba,0x90,0xc0,0xd3,0x2a,0x26,0x55,0x48,0xd4,0x48,0x74,0x48,0x60,0x3f, +0x15,0xea,0xa2,0x42,0x5d,0x54,0xa8,0x8b,0x0a,0xb5,0xaa,0x50,0xab,0x0a,0xb5,0xaa, +0x51,0xab,0x1a,0xb5,0xaa,0x51,0xab,0x1a,0xb5,0xaa,0x51,0xab,0x1a,0xb5,0x6a,0x50, +0xab,0x06,0xb5,0x6a,0x50,0xab,0x06,0xb5,0x6a,0x50,0xab,0x06,0xb5,0x56,0xa2,0xd6, +0x4a,0x54,0x57,0x89,0xea,0x2a,0x51,0x9d,0x1e,0xd5,0xe9,0xd1,0x19,0x7a,0x74,0x86, +0x1e,0xb5,0xea,0x51,0xab,0x1e,0x59,0xf7,0xc6,0xe4,0x0d,0x30,0xd1,0x0d,0x65,0x52, +0x07,0xc5,0x73,0xd2,0x30,0x69,0x82,0x6a,0xb4,0xea,0x05,0xab,0x7e,0x62,0xd5,0x6a, +0xab,0x9a,0x50,0xef,0x2b,0x13,0xdd,0x48,0x6e,0x22,0x7f,0x6b,0x90,0x97,0xbb,0x91, +0xdc,0x44,0x0e,0xd6,0x20,0xb7,0x76,0x23,0xb9,0x89,0x3c,0xaa,0x41,0x1e,0xed,0x46, +0x72,0x13,0x39,0x53,0x83,0xa6,0x74,0x15,0x8d,0xbc,0x1b,0xc9,0x4d,0x34,0x68,0x0d, +0x1a,0x56,0x37,0x92,0x9b,0x68,0x44,0x28,0xca,0x90,0x93,0xae,0x4c,0x56,0xa2,0xeb, +0x55,0xa2,0xab,0x54,0x22,0x67,0x5a,0xed,0x54,0x89,0xce,0xa8,0x44,0xf3,0xba,0x81, +0x3a,0x57,0xa2,0x8b,0x56,0x22,0x7f,0x43,0xe9,0x45,0xde,0xeb,0x45,0xad,0x0a,0xeb, +0xc0,0x61,0xf6,0xc9,0x5a,0x86,0x86,0x0e,0x7d,0xad,0x43,0xa2,0x47,0x6e,0xd6,0x21, +0xd1,0x23,0x37,0xeb,0x90,0xe8,0xd1,0x15,0x74,0x48,0xf4,0xe8,0x0a,0x3a,0x24,0x7a, +0x14,0x68,0x3a,0x24,0x28,0x02,0xd1,0x51,0x27,0x3a,0xba,0x8e,0x8e,0xae,0xa3,0x23, +0x33,0x3a,0x32,0xa3,0xa3,0x5b,0xe8,0xe8,0x96,0xf5,0x5c,0x14,0x3b,0xbd,0x28,0xb2, +0x7a,0xd1,0x1c,0x7a,0xd1,0xd4,0x7b,0x90,0x98,0x91,0xdc,0x42,0x72,0x75,0xb2,0xca, +0xba,0x06,0xac,0x61,0xbf,0x16,0xd0,0xd7,0xd6,0x42,0xfa,0xda,0x5a,0x28,0x5f,0xb3, +0xfa,0xdf,0x9a,0x75,0xad,0x65,0xd7,0xad,0xd1,0x8f,0x4a,0x5d,0xd6,0x10,0xb0,0x66, +0x3a,0x6b,0xbc,0xaf,0x85,0x7d,0xe7,0x5a,0xe0,0x77,0xae,0xcd,0xc1,0xda,0xb3,0x67, +0xed,0x2a,0x3d,0xd6,0xe8,0x41,0x4b,0x01,0x5b,0x0c,0x56,0x1b,0xad,0xdd,0xaf,0x77, +0x6d,0x46,0xbd,0x6b,0x77,0xe8,0x5d,0x6b,0xbb,0xb5,0x36,0xeb,0x5b,0x6b,0x63,0xb9, +0xbd,0x76,0xb1,0xdb,0x6b,0x6d,0xb7,0xd7,0xee,0xde,0xbf,0x36,0xf8,0xfe,0xb5,0xca, +0xfe,0xb5,0xb1,0xdc,0x59,0x2b,0xdd,0x59,0xeb,0x72,0x67,0x2d,0x5e,0x95,0xd6,0xab, +0xa0,0x45,0x82,0xad,0x15,0x6b,0x9c,0x5b,0xef,0x6e,0xcd,0xf4,0x6b,0x99,0xce,0xba, +0x20,0xd6,0x96,0xc4,0xf5,0xb5,0xa5,0x80,0x45,0x7f,0x17,0xb6,0x12,0xac,0x2b,0x60, +0xed,0x04,0xb5,0x75,0xb6,0x28,0x5b,0xab,0xbc,0xbe,0xd6,0xe5,0xfa,0x5a,0xa9,0x13, +0x85,0x49,0xe5,0xda,0x0a,0xaa,0x5c,0xbb,0x9f,0x66,0xed,0x74,0xcd,0xda,0x8d,0x34, +0x6b,0xe7,0x69,0xac,0xc6,0x42,0x8b,0xc7,0xba,0xa4,0xd6,0x86,0xab,0x5f,0x9b,0x43, +0xfb,0x9a,0x7f,0xaf,0xad,0x99,0xe7,0xda,0x9a,0x59,0xaf,0xbd,0xae,0xbc,0xbe,0xb6, +0x55,0x59,0xa7,0x79,0x6d,0x6d,0xee,0x9d,0x6b,0xa5,0xce,0x35,0xd3,0x75,0xbe,0x76, +0x8e,0xb5,0xa7,0x79,0x2d,0x80,0x7a,0xd7,0xb2,0x5b,0xaf,0x27,0xdd,0x69,0xcd,0xd6, +0xee,0xae,0x5f,0xab,0xd4,0xaf,0x55,0xea,0xd7,0x2a,0xd5,0x6b,0x59,0xf9,0xeb,0x35, +0xdf,0xb5,0x16,0xb8,0xd6,0x52,0xc5,0x2f,0x1b,0x01,0xb6,0x47,0xbc,0xbe,0xa6,0x7a, +0xad,0x4d,0xbd,0x36,0x16,0xbd,0x75,0xbf,0xc4,0x6c,0x86,0x32,0xe5,0xda,0x38,0xdb, +0xd7,0xda,0x7a,0xd6,0xce,0xd3,0xac,0x4d,0xd3,0x3c,0xa9,0x82,0xcf,0x05,0x78,0x3f, +0x94,0xc1,0x20,0x55,0x59,0x17,0x1b,0x3c,0xa8,0xb0,0x2e,0xef,0x35,0x27,0x4c,0x7c, +0x63,0xed,0xb8,0xb6,0x4f,0x76,0xc3,0xe0,0xd2,0xc2,0xbd,0x0d,0x96,0x54,0xd6,0xa5, +0x38,0xa9,0x85,0x35,0x2a,0x6b,0xb8,0x59,0x37,0xb3,0xb5,0xcc,0xf3,0xf5,0xc5,0x3c, +0x5f,0x77,0xf4,0xfc,0xff,0x3b,0x76,0x4e,0xaa,0x3c,0x91,0x58,0xfb,0xc0,0xdb,0x75, +0xff,0x64,0x40,0x87,0xc0,0x0f,0xfc,0xac,0x50,0x82,0x20,0xe0,0x05,0x3e,0x84,0x47, +0x75,0x30,0x7d,0x06,0x7e,0xa3,0x40,0x7f,0x56,0x75,0x11,0x9c,0x05,0x25,0x40,0x0e, +0x6b,0x6a,0x60,0x82,0x2f,0x0e,0x8a,0x6a,0x98,0x4c,0x30,0xe9,0x61,0xaa,0x82,0xc9, +0x00,0x93,0x11,0xa6,0x0b,0x30,0x7d,0x02,0x4e,0x83,0x54,0xb0,0x0f,0xec,0x07,0x07, +0x01,0x09,0x04,0x83,0x0f,0x40,0x0a,0xf0,0x06,0x44,0x10,0x0a,0x77,0xb2,0x2a,0xb4, +0x33,0x54,0xa1,0x0d,0x0f,0x6d,0x77,0x68,0xb3,0xb3,0x6e,0x1c,0x68,0xbf,0xb3,0x6e, +0x1d,0x68,0xcb,0xb3,0x6e,0x1e,0x68,0xd7,0x43,0x07,0x68,0xfb,0xfb,0x14,0x1d,0x40, +0x03,0xb5,0x80,0x89,0x4b,0x60,0xe2,0x32,0x98,0x68,0x05,0x13,0x6d,0x70,0xb3,0x02, +0xe8,0x89,0xd9,0x0e,0x26,0x3a,0x60,0x50,0xc0,0x3d,0x09,0x58,0x9f,0x53,0x00,0xad, +0x2b,0x68,0x32,0xb4,0xbf,0x02,0xb4,0x01,0xf6,0xc0,0x40,0x80,0x66,0x81,0x71,0x00, +0x17,0x13,0x7c,0xf0,0x40,0xdb,0xc1,0xb5,0x02,0x1d,0x03,0x0d,0x0f,0x5d,0x07,0xd0, +0x93,0x02,0x05,0x27,0xb0,0x5a,0x13,0xac,0xb9,0xf5,0x12,0x92,0xcb,0x48,0xda,0x90, +0x5c,0x05,0x7b,0xc1,0x01,0x10,0x00,0xce,0x00,0x19,0x28,0x05,0xbf,0xb9,0xa2,0x86, +0x09,0xfd,0xa2,0x83,0x7e,0xe9,0x41,0x3f,0xa4,0x5c,0x86,0xa9,0x0d,0xa6,0xab,0x30, +0xa1,0x7f,0xc8,0x85,0xe5,0x0a,0x58,0x86,0xef,0xd6,0x3f,0x57,0x54,0x80,0xb5,0x7f, +0xd2,0x45,0x3f,0x28,0x34,0x00,0xf4,0xc3,0xf8,0x7f,0x5c,0x02,0xff,0x71,0x19,0xfc, +0x47,0x27,0xf8,0x8f,0x2b,0xe0,0x3f,0xda,0xc0,0x6f,0xe0,0x29,0xbf,0xa9,0x29,0x07, +0xbf,0x81,0x5f,0xdb,0x7e,0xa3,0x31,0xc1,0xf4,0x29,0x4c,0x17,0xc1,0x6f,0xea,0x9a, +0xc1,0x6f,0x3e,0xab,0x02,0x8b,0xd5,0xd5,0xed,0x48,0x3a,0x90,0x5c,0x43,0xf2,0x35, +0x92,0x4e,0x24,0x5d,0x48,0xae,0x23,0xf9,0x06,0xc9,0x0d,0x24,0xdd,0x48,0x6e,0x22, +0xe9,0x41,0xd2,0x8b,0xc4,0x8c,0xe4,0x16,0x92,0xdb,0x48,0xfa,0x90,0xf4,0x23,0xb9, +0x83,0xe4,0x5b,0x24,0x03,0x48,0x06,0x91,0xdc,0x45,0xf2,0x1d,0x14,0x93,0x02,0x89, +0x12,0x49,0x39,0x92,0x0a,0x24,0x2a,0x24,0x6a,0x24,0x1a,0x24,0x95,0x48,0xb4,0x48, +0x74,0x48,0xf4,0x48,0xd0,0x98,0x4d,0x06,0x24,0x46,0x24,0x17,0x90,0x7c,0x02,0xe5, +0x62,0x3d,0x92,0x06,0x24,0x9f,0x23,0xf9,0x02,0x49,0x23,0x92,0x26,0x24,0x5f,0x22, +0xf9,0x0a,0x49,0x33,0x92,0x16,0x24,0x97,0x90,0x5c,0x46,0xd2,0x8a,0xa4,0x0d,0xc9, +0x15,0x24,0x57,0x91,0x20,0xbb,0x5c,0x44,0x76,0xb9,0x88,0xec,0x72,0x11,0xd9,0xe5, +0x22,0xb2,0xcb,0x45,0x64,0x97,0x8b,0xc8,0x2e,0x17,0x91,0x5d,0x2e,0x22,0xbb,0x5c, +0x44,0x76,0xb9,0x88,0xec,0x72,0x11,0xd9,0xe5,0x22,0xb2,0xcb,0x45,0x64,0x97,0x8b, +0xc8,0x2e,0x17,0x91,0x5d,0x2e,0x22,0xbb,0x5c,0x44,0x76,0xb9,0x88,0xec,0x72,0x11, +0xd9,0xa5,0xee,0x33,0x24,0x68,0xe0,0x75,0x68,0xe0,0x75,0x68,0xe0,0x75,0x68,0xe0, +0x75,0x68,0xe0,0x75,0x68,0xe0,0x75,0x68,0xe0,0x75,0x68,0xe0,0x75,0x68,0xe0,0x75, +0x68,0xe0,0x75,0x68,0xcc,0x75,0x68,0xcc,0x75,0x68,0xcc,0x75,0x68,0xcc,0x75,0x68, +0xcc,0x75,0x68,0xcc,0x75,0x68,0xcc,0x75,0x68,0xcc,0x75,0x68,0xcc,0x75,0x68,0xcc, +0x75,0x68,0xcc,0x75,0x68,0xcc,0x75,0x68,0xcc,0x75,0x68,0xcc,0x75,0x68,0xcc,0x75, +0x68,0xb8,0x75,0x68,0xb8,0x75,0x68,0xb8,0x75,0x68,0xb8,0x75,0x68,0xb8,0x75,0x68, +0xb8,0x75,0x68,0xb8,0x75,0xd6,0x91,0x0e,0x80,0xff,0x5d,0x0d,0xfe,0xb7,0x09,0x7c, +0xdf,0x00,0xbe,0xbf,0x0c,0xfe,0xbb,0xeb,0x0a,0xf8,0xbe,0x0d,0x7c,0xdf,0x0a,0xa6, +0x6f,0x99,0xc0,0x48,0x3d,0x18,0xf9,0x12,0x7c,0xdf,0x01,0x46,0x2e,0x81,0xef,0xbf, +0x00,0xdf,0x37,0x82,0x91,0xab,0xe0,0x7b,0x15,0xf8,0xfe,0x1a,0xf8,0x1e,0x0e,0xa1, +0x69,0x40,0x05,0xfe,0xfb,0xcb,0x0b,0x60,0xe4,0x3a,0x3a,0x56,0x83,0xef,0x2f,0xa0, +0x5c,0x03,0x46,0x6e,0x81,0x91,0xdb,0x60,0xe4,0x0e,0x2a,0x69,0xc1,0xc8,0x5d,0xf0, +0x7d,0x3b,0xf8,0xfe,0x0a,0xbc,0x36,0x3c,0xf9,0x2a,0xf8,0x4d,0x77,0x37,0xf8,0xfe, +0x13,0xf0,0x7d,0x0b,0xf8,0x1e,0x5e,0xb5,0x1e,0xfc,0xa7,0x02,0xfc,0xa7,0x12,0xfc, +0x67,0x39,0xea,0xad,0x47,0x82,0x0c,0xd3,0x83,0x82,0xa8,0x07,0x05,0x51,0x0f,0x0a, +0xa2,0x1e,0x14,0x44,0x3d,0x28,0x88,0x7a,0x50,0x10,0xf5,0xa0,0x20,0xea,0x41,0x41, +0xd4,0x83,0x82,0xa8,0x07,0x05,0x51,0x0f,0x0a,0xa2,0x1e,0x14,0x44,0x3d,0x28,0x88, +0x7a,0x50,0x10,0xf5,0xa0,0x20,0xea,0x41,0x41,0x84,0xbe,0xa2,0x54,0xf7,0x98,0x90, +0x7c,0x8a,0xe4,0x22,0x92,0x1a,0x24,0xb5,0x48,0xea,0x90,0x20,0x9f,0xf5,0x20,0x9f, +0xf5,0x20,0x9f,0xf5,0x20,0x9f,0xf5,0x20,0x9f,0xf5,0x20,0x9f,0xf5,0x20,0x9f,0xf5, +0x58,0x87,0x86,0x7c,0xd6,0x83,0x7c,0xd6,0x83,0x7c,0xd6,0x83,0x82,0xad,0x07,0x39, +0xae,0x07,0x39,0xae,0x07,0x39,0xae,0x07,0x39,0xae,0x07,0x39,0xae,0x07,0x39,0xae, +0x07,0x39,0xae,0x07,0x39,0xae,0x07,0x39,0xae,0x07,0x39,0xae,0x07,0x39,0xae,0x07, +0x39,0xae,0x07,0x39,0xae,0x07,0x39,0xae,0x07,0x39,0xae,0x07,0x05,0x9b,0x19,0x15, +0xcd,0xa8,0x68,0xb6,0x16,0x91,0x33,0xcd,0xc8,0x99,0x66,0xe4,0x4c,0x33,0x72,0xa6, +0x19,0x39,0xd3,0x8c,0x9c,0x69,0x46,0xce,0x34,0xa3,0xd8,0x33,0x23,0x8f,0x9a,0xd1, +0x9a,0x34,0xa3,0x35,0x69,0x46,0x6b,0xd2,0x8c,0xd6,0xe4,0x2d,0x64,0xce,0x5b,0xc8, +0x9c,0xb7,0x90,0x39,0x6f,0x21,0x73,0xde,0x42,0xe6,0xbc,0x05,0xcd,0x69,0xba,0xac, +0x40,0xa2,0x44,0x52,0x8e,0xa4,0x02,0x89,0x0a,0x89,0xb5,0x55,0x83,0xa4,0x12,0x89, +0x16,0x89,0x0e,0x89,0x1e,0x49,0x15,0x12,0x03,0x12,0x23,0x92,0x0b,0x48,0x3e,0x41, +0x52,0x8d,0xc4,0x84,0xe4,0x53,0x24,0x17,0x91,0xd4,0x20,0xa9,0x45,0x52,0x87,0xe4, +0x33,0x24,0xf5,0x48,0x1a,0x90,0x7c,0x8e,0xe4,0x0b,0x24,0x8d,0x48,0x9a,0x90,0x7c, +0x89,0x04,0x1a,0xbb,0xae,0xbf,0x19,0x49,0x0b,0x92,0x4b,0x48,0x2e,0x23,0x69,0x45, +0xd2,0x86,0xe4,0x0a,0x92,0xab,0x48,0xda,0x91,0x74,0x20,0xb9,0x86,0xe4,0x6b,0x24, +0x9d,0x48,0xba,0x90,0x5c,0x47,0xf2,0x0d,0x92,0x1b,0x48,0xba,0x91,0xdc,0x44,0xd2, +0x83,0xa4,0x17,0x89,0x19,0xc9,0x2d,0x24,0xb7,0x91,0xf4,0x21,0xe9,0x47,0x72,0x07, +0xc9,0xb7,0x48,0x06,0x90,0x0c,0x22,0xb9,0x8b,0x04,0x5a,0xb7,0xee,0x0e,0x6a,0xb8, +0x83,0x1a,0xee,0xa0,0x86,0x3b,0xa8,0xe1,0x0e,0x6a,0xf8,0x56,0x81,0x44,0x89,0xa4, +0x1c,0x49,0x05,0x12,0x15,0x12,0x35,0x12,0x0d,0x92,0x4a,0x24,0x5a,0x24,0x3a,0x24, +0x7a,0x24,0x55,0x48,0x0c,0x48,0x8c,0x48,0x2e,0x20,0xf9,0x04,0x49,0x35,0x12,0x13, +0x92,0x4f,0x91,0x40,0xc3,0x36,0xa9,0x3f,0x83,0xa9,0x0d,0x1d,0xd4,0xff,0xd6,0x01, +0x4c,0xd7,0xdf,0x2c,0x7c,0xf3,0x66,0xe1,0xc6,0x9b,0x85,0xee,0x37,0x0b,0xd0,0x20, +0x4d,0x9a,0x7e,0xec,0x4a,0x9a,0x3b,0xaf,0x0f,0xfa,0xdf,0xb8,0xe4,0x5a,0xed,0xeb, +0x42,0xff,0x1b,0xd7,0xff,0xa5,0xe5,0x1b,0x70,0xbf,0x1b,0x3c,0xb8,0x0d,0x7e,0xa3, +0xad,0x84,0x09,0xce,0xfd,0xcb,0xd6,0x4b,0x48,0x2e,0x23,0x69,0x45,0xd2,0x86,0xe4, +0x0a,0x92,0xab,0x48,0xda,0x91,0x74,0x20,0xb9,0x86,0xe4,0x6b,0x24,0x9d,0x48,0xba, +0x90,0x5c,0x47,0xf2,0x0d,0x92,0x1b,0x48,0xba,0x91,0xdc,0x44,0xd2,0x83,0xa4,0x17, +0x89,0x19,0xc9,0x2d,0x24,0xb7,0x91,0xf4,0x21,0xe9,0x47,0x72,0x07,0xc9,0xb7,0x48, +0x06,0x90,0x0c,0x22,0xb9,0x8b,0x04,0x3a,0xe8,0xcb,0x36,0x05,0x12,0x25,0x12,0x34, +0xc8,0x36,0xf8,0x60,0xbf,0x0e,0x7e,0x6c,0x01,0x93,0xdf,0x00,0xb2,0x1f,0xa0,0xf8, +0x81,0x77,0xfd,0xc0,0x21,0x3f,0x40,0xf5,0x03,0x34,0x3f,0xf0,0x9e,0x1f,0x78,0xdf, +0x0f,0x04,0xfa,0x01,0x3a,0x7a,0xe9,0xa9,0xc9,0x47,0x2f,0x35,0x85,0xc5,0x80,0x5b, +0x00,0xf2,0x33,0x40,0x7e,0x3e,0x10,0x0a,0x0b,0x40,0xe1,0xc7,0x40,0x00,0xff,0xcb, +0x00,0x82,0x3c,0x90,0x91,0x0d,0x7e,0x56,0x7e,0xfb,0xb3,0xb2,0xca,0xfa,0x1b,0x7f, +0x39,0xfa,0x9b,0xcd,0xcf,0x80,0xe5,0x13,0xf4,0x47,0x1c,0x95,0xc0,0xd2,0xfa,0x39, +0x98,0xbb,0x7a,0x19,0xcc,0xdc,0x69,0x05,0xb3,0xf5,0xcd,0xe0,0x99,0xaa,0x05,0x58, +0x74,0x46,0x60,0xb9,0x6b,0x00,0x16,0x8d,0x11,0xcc,0xc2,0xad,0xdc,0xa2,0x6d,0x02, +0xcf,0xcc,0xe5,0x60,0xee,0x66,0x07,0xb0,0x5c,0x86,0x65,0xf8,0xf4,0x9d,0x1d,0xa8, +0x01,0xb3,0xfa,0x5a,0x30,0x6b,0xac,0x05,0xf3,0x4a,0x3d,0x98,0x35,0x54,0x82,0x59, +0xdd,0x45,0xf0,0xec,0x8a,0x12,0x3c,0xeb,0x40,0xff,0xd4,0xa8,0x05,0xb3,0x77,0x14, +0xe0,0x59,0x0d,0xbc,0x9f,0xee,0x26,0xb0,0xc0,0x9d,0x7f,0x5e,0x8d,0xde,0xb2,0x6a, +0x66,0x1b,0x3b,0xd7,0xde,0xc3,0x6a,0x66,0xfa,0x74,0xaf,0x8f,0xee,0x18,0xb0,0x23, +0xcb,0xf5,0xd7,0x75,0xcf,0xca,0xfb,0xb1,0x23,0x78,0xe1,0xd7,0x75,0x5f,0x7c,0xf6, +0xba,0x5f,0x55,0xd3,0xeb,0xd6,0x5a,0x6b,0x9d,0xe5,0x2e,0x9a,0xd5,0x37,0x60,0xa6, +0x6f,0x10,0xa6,0x3e,0x30,0xd3,0x0f,0xed,0xd9,0xac,0xba,0x04,0x66,0x06,0x9b,0xc1, +0xcc,0xdd,0x6f,0x81,0x45,0x51,0x0e,0x2c,0x4a,0x38,0x34,0xf8,0x26,0x63,0x41,0xbf, +0xa1,0x7f,0x0a,0x57,0x76,0x73,0x3d,0xac,0x50,0xa3,0x3f,0x11,0x6a,0x85,0x09,0xfa, +0xac,0xb9,0xa6,0x11,0xb6,0xf4,0xc3,0x02,0x0c,0x88,0xe6,0xda,0x2a,0x68,0x05,0x78, +0x5d,0x4d,0x2b,0x98,0xf9,0x16,0x59,0x04,0x06,0x43,0x47,0xe5,0x57,0xd0,0x24,0xf0, +0xcd,0xe8,0x22,0xca,0xe1,0x75,0x75,0x1a,0x98,0x6e,0x83,0x9f,0x6b,0xd0,0x9f,0xd4, +0xaa,0x61,0x82,0x65,0xa3,0x0e,0xa6,0xcf,0x61,0x82,0xd3,0x37,0x0e,0xc2,0x04,0xdd, +0xdc,0xdc,0xde,0x09,0x9e,0x29,0xa1,0xfd,0x3e,0xd1,0xc3,0x04,0x77,0x94,0x66,0xf4, +0x77,0x44,0x9f,0x7c,0x0d,0x53,0x37,0x34,0x18,0x3c,0x0b,0x8e,0xc8,0x02,0xdf,0x6f, +0x2c,0xf0,0x9d,0xc4,0x62,0x6a,0x87,0xe5,0x4b,0xc0,0x02,0x9f,0xf0,0x96,0x9a,0x6a, +0x60,0xa9,0xbd,0x08,0x13,0xec,0x5f,0xa7,0x82,0x09,0x9e,0x03,0x9f,0xac,0x96,0xcf, +0xe0,0x8c,0x1a,0xeb,0x60,0x82,0x43,0x6c,0x30,0xc1,0xd4,0x0b,0x1d,0x74,0x1d,0x58, +0xbe,0xba,0x00,0x13,0x3c,0x6e,0x86,0x8e,0xfc,0x12,0x4e,0xa1,0x19,0x3a,0xa0,0x19, +0xde,0xe3,0x12,0x1c,0x7e,0x0b,0x7c,0x19,0xb1,0x5c,0x86,0x15,0x97,0x6f,0x43,0xef, +0xc3,0x9b,0xc2,0x25,0x61,0x69,0x83,0xcb,0xa2,0xe5,0x73,0x18,0xfd,0x2d,0x5f,0x5c, +0x03,0x96,0xab,0x9d,0xc0,0xd2,0xfe,0x05,0x4c,0x57,0xe1,0x71,0x3d,0xb0,0x74,0x5c, +0x01,0x3f,0x7f,0x71,0x1d,0xa6,0x01,0x60,0xe9,0x84,0x43,0xeb,0x84,0x81,0xdb,0x72, +0x15,0x1e,0x7c,0x53,0x01,0x13,0xec,0xf0,0x0d,0x5c,0x00,0x2d,0x9d,0xe8,0xe0,0x3b, +0x60,0xb9,0x01,0xaf,0x39,0x78,0x11,0xfc,0xfc,0xa5,0x12,0x58,0xba,0x9b,0x81,0x05, +0x3e,0x43,0x2d,0x37,0xe1,0x06,0xd2,0x72,0x1b,0xde,0xd8,0x5c,0x81,0x0e,0xae,0xc0, +0x03,0x38,0x4c,0x33,0x9c,0x06,0x7c,0x4c,0x58,0x6e,0xc3,0x98,0xbb,0x7d,0x09,0xfc, +0xdc,0xfc,0x0d,0xcc,0xa1,0xb1,0xfa,0xe0,0xd4,0xa1,0x17,0x2d,0x70,0x0f,0xfd,0xb9, +0x05,0x8e,0xec,0x92,0x06,0x5a,0xbb,0x05,0x76,0xbc,0x03,0x8d,0x77,0x07,0xce,0xfb, +0x0e,0x5c,0x61,0xd7,0x2e,0xa0,0x7f,0x13,0x34,0x74,0x83,0x39,0x2d,0xbc,0xd1,0x00, +0x3c,0x1d,0x3d,0x1c,0x2e,0xeb,0xe1,0x92,0xbb,0x52,0x09,0x2d,0x8f,0x7e,0x4f,0x18, +0xfc,0x1a,0xd6,0x42,0x9b,0xdd,0x85,0xe5,0xef,0xa0,0x2d,0xbe,0x83,0x76,0xfa,0x0e, +0x06,0x6f,0xb9,0x12,0xfc,0x0c,0x57,0xe4,0xcf,0xad,0x70,0x97,0xbf,0xf4,0x05,0x8c, +0x64,0xb8,0x12,0x66,0xd5,0xe8,0xdf,0x45,0x0d,0x30,0xdd,0x01,0xb3,0x9a,0x9b,0x30, +0xc1,0x15,0xa1,0xf9,0x06,0xcc,0x56,0xa2,0x7f,0x9c,0x47,0x3f,0x4a,0x7c,0x01,0x23, +0xbc,0x09,0x46,0x7d,0x37,0x98,0xad,0x82,0xe7,0x18,0xe1,0x2e,0x78,0xa9,0x13,0x9e, +0x60,0x18,0x84,0x15,0x03,0xb0,0xa2,0x1d,0xcc,0x5e,0xa8,0x00,0xb3,0x9f,0xc0,0x9d, +0xe5,0xd2,0x37,0xb0,0x57,0xf5,0x25,0x58,0x50,0xc3,0x4a,0x38,0x8f,0xf6,0xeb,0x60, +0xd6,0xd4,0x01,0xd3,0x5d,0x30,0xfb,0x29,0xbc,0x8a,0x09,0x06,0x4c,0x47,0x27,0x98, +0xad,0x85,0x2e,0xb9,0x0c,0xbf,0x8a,0xcc,0x7e,0x76,0x19,0xcc,0x7e,0xd1,0x07,0x66, +0x1b,0x74,0xe0,0xe7,0x4e,0xf8,0xae,0x0d,0x0d,0xfd,0xf3,0xd7,0xd0,0x62,0xf0,0x85, +0xda,0xa2,0x81,0x0b,0xad,0x51,0x01,0x66,0x3f,0x6f,0x04,0x73,0xe5,0x5d,0x60,0xe6, +0x93,0x06,0x58,0x6e,0x01,0xb3,0x4d,0x70,0x68,0x4d,0x17,0xd1,0x3f,0x88,0x42,0x03, +0x75,0xe9,0xc0,0xec,0x57,0x70,0xec,0x5f,0xc2,0x3b,0xb6,0x40,0xdb,0x5c,0x36,0x75, +0x81,0xd9,0x4b,0x17,0xc0,0x6c,0xf3,0x57,0x60,0xb6,0x15,0x0e,0x18,0xee,0x2d,0xb3, +0x57,0xe0,0x5d,0xae,0x5e,0x03,0xb3,0xd7,0xa0,0xaf,0x2f,0x7f,0x0e,0x0b,0x5f,0x7f, +0x01,0x7e,0xbe,0x51,0x0f,0x66,0x3b,0xe1,0x73,0xed,0xf2,0xa5,0xab,0x60,0xb6,0x0b, +0x7e,0x4d,0xea,0x86,0x67,0x75,0x41,0x13,0x5c,0x87,0x67,0x5e,0x87,0x9b,0xd6,0xe5, +0x6b,0xc8,0x7f,0xbd,0xf0,0x79,0x70,0xf9,0x6b,0x78,0x07,0xd8,0xbc,0x78,0xf9,0x26, +0x9c,0xf1,0xcd,0xef,0xc0,0x2c,0x7c,0xc3,0x99,0xed,0x86,0xe7,0xf5,0xd6,0xc1,0x04, +0x27,0x67,0x86,0x93,0x84,0xef,0x03,0xb3,0xe8,0x91,0x7e,0x19,0xfd,0x28,0xd0,0xdb, +0x0b,0x66,0xfb,0xa0,0x1d,0xe1,0x83,0xef,0xe7,0xde,0x1e,0x30,0x8b,0x1e,0x35,0x97, +0xe1,0xd3,0x63,0xf6,0x36,0xf4,0xc4,0x20,0xdc,0x53,0x2f,0x0f,0xc2,0x85,0x78,0xf9, +0x2e,0xbc,0xe7,0x77,0x1a,0xf0,0x4c,0xd1,0x0f,0x13,0x1c,0xd4,0xad,0x3a,0xb8,0x58, +0xf4,0x30,0x0d,0xc2,0x74,0x1b,0x3c,0x83,0xf3,0x86,0x8b,0xb3,0x0d,0x3c,0x53,0xc3, +0x0b,0xb7,0xea,0x2e,0x83,0x67,0x1a,0xe8,0xbd,0xd6,0x0b,0xe8,0x6f,0xb8,0xdb,0xc1, +0x33,0x1d,0xf4,0x46,0x6b,0xbd,0x16,0x3c,0xd3,0xc3,0x4d,0x07,0x6e,0x4c,0x8b,0xad, +0x8d,0xe8,0x1f,0xd3,0x9b,0x6b,0xc0,0x33,0xe3,0x1d,0xf0,0xec,0x02,0xdc,0xfd,0xee, +0xa0,0x3f,0xe7,0x86,0xdf,0x6c,0xee,0xf4,0x81,0x67,0xf0,0xd5,0xff,0x99,0xa9,0x11, +0x3c,0xfb,0x54,0x0d,0x9e,0x5d,0x84,0x5f,0x04,0x07,0xbe,0x80,0x5b,0x15,0xf4,0x5b, +0xeb,0x8d,0x5b,0xf0,0x00,0xc6,0x77,0xeb,0x4d,0x14,0x5e,0x9a,0xaf,0xc0,0xb3,0x7a, +0x74,0xe5,0xbb,0x2d,0x48,0x60,0x6c,0xb5,0x29,0x55,0xe0,0xe7,0xef,0x06,0xc0,0x8c, +0x02,0x3e,0x2c,0xdb,0xe0,0x17,0x23,0x28,0xf0,0x19,0xd0,0xa6,0x6a,0x40,0xd2,0x03, +0x9e,0x35,0xa2,0xdf,0xcf,0xe0,0x69,0x70,0xdd,0xcd,0x28,0x35,0x60,0xa6,0x1c,0xbe, +0x67,0xb4,0xa1,0x1f,0x5e,0x5a,0x2e,0x80,0x19,0xf8,0xe5,0x6a,0xb1,0xad,0x1e,0x3e, +0x6f,0xda,0x3e,0x87,0xaf,0x1a,0x6d,0x5f,0xc0,0xbb,0x5f,0xfd,0x1a,0xcc,0xa8,0xbe, +0x81,0x9b,0x26,0x9c,0x6b,0x07,0x7c,0xba,0xb6,0xb5,0xc1,0x07,0x44,0xdb,0xb5,0xab, +0xe0,0xd9,0xd7,0xd7,0xc1,0x0c,0x7a,0x68,0xb5,0x5d,0x87,0x73,0xfc,0x06,0x9a,0xe6, +0x1b,0x1d,0xac,0x80,0xdb,0x52,0xdb,0x4d,0x38,0x47,0xf8,0x02,0x39,0xa3,0x87,0x1b, +0x36,0x7c,0xb5,0x7b,0x06,0xdf,0xfb,0x9e,0xf5,0xc2,0x67,0x48,0xdb,0x5d,0xd8,0xcb, +0x0c,0x77,0x73,0x03,0xdc,0x85,0x6f,0xc3,0x29,0xf6,0x95,0x83,0x67,0xfd,0x6a,0x58, +0x86,0x0f,0xa7,0x2b,0xd0,0x4c,0x8b,0x57,0x74,0x95,0x60,0xc6,0x08,0xc7,0x7a,0xa5, +0xaa,0x01,0x3c,0x1b,0x84,0x4f,0xa5,0x2b,0x86,0xbb,0xe0,0xd9,0xdd,0x5a,0xf0,0xec, +0x3b,0x54,0x40,0xdf,0x6d,0xae,0xd4,0x5c,0x06,0x73,0x4a,0xf8,0xb2,0x73,0x05,0xbe, +0xef,0xcf,0xc1,0x0d,0x6b,0xf1,0xb2,0xf1,0x2b,0x18,0x74,0xb5,0x30,0xf8,0x6e,0x82, +0x39,0x55,0x05,0x98,0xa9,0xae,0x82,0xf9,0x5d,0x60,0xb9,0x06,0x6d,0x7c,0xe5,0xcb, +0xab,0x48,0xe0,0xd1,0xe5,0x0b,0x28,0x16,0x2f,0xc0,0x20,0xd5,0xaa,0xc0,0xdc,0xdd, +0x2f,0xc1,0x8c,0xe9,0x6b,0x30,0xa7,0x37,0xc1,0x04,0xfb,0xeb,0xd1,0x1f,0x58,0xf6, +0xc0,0x1c,0x2e,0x59,0x6b,0x3e,0x08,0xe6,0xaa,0xa0,0x29,0xae,0x74,0x0e,0x80,0x39, +0x43,0x13,0x98,0x33,0xc2,0xdb,0x5e,0xe8,0x82,0xc7,0x28,0x87,0x8d,0x9f,0x5c,0x85, +0x75,0x17,0x61,0xae,0x87,0xc9,0x00,0x13,0xf4,0xf7,0x15,0xe8,0x9f,0xc5,0x2b,0x70, +0xe3,0x58,0xbc,0x02,0x5f,0x99,0x67,0x6a,0xe0,0xf5,0xe1,0x77,0xa3,0x39,0xf8,0xad, +0x68,0xae,0x06,0x1a,0xfa,0x2a,0xea,0x5b,0x0b,0xfd,0x78,0x65,0xa0,0x13,0xcc,0xd4, +0x36,0xc1,0x04,0x1d,0x77,0xe5,0x2e,0x7c,0x54,0x5f,0xad,0x80,0x06,0xab,0x85,0xfd, +0x1b,0xaa,0x61,0x82,0x97,0x6e,0xe8,0x00,0x73,0x9f,0xa3,0xa4,0x05,0x73,0x8d,0x17, +0xc0,0xdc,0x17,0x97,0x60,0x0e,0x27,0xdc,0x04,0xfb,0x7c,0x09,0x1d,0xf7,0xd9,0x67, +0x60,0xee,0xab,0x16,0x30,0xd7,0xac,0x84,0xc7,0xfd,0x60,0xae,0x05,0x5a,0xe4,0x2a, +0x3a,0x11,0xbe,0x34,0xce,0xc1,0xb7,0xc2,0x99,0x7a,0x33,0xcc,0xe1,0x2e,0xf2,0x29, +0x5c,0x21,0x57,0x2f,0xc1,0x40,0xbe,0xda,0x76,0x05,0xcc,0x7c,0x7e,0x17,0xcc,0x7c, +0x51,0x09,0xe6,0xae,0xa1,0xee,0x37,0xe1,0xf5,0x6e,0xc2,0xeb,0xc1,0xaf,0x10,0x73, +0xbd,0x5f,0x80,0x39,0xf4,0xb6,0x7c,0x75,0x00,0xbe,0x42,0x34,0x37,0x43,0x0b,0xa1, +0x9f,0xdb,0x6e,0xc1,0xc9,0xdf,0x86,0x26,0x6e,0x86,0x57,0x9c,0xfb,0x16,0xbe,0x9d, +0xb6,0x7f,0xf6,0x29,0x92,0x2e,0x30,0x5f,0x5e,0x03,0xe6,0x2b,0xba,0xc1,0xbc,0x0a, +0xbe,0x69,0xb5,0x37,0x5e,0x87,0x07,0x5f,0x80,0x79,0x6d,0x1f,0x98,0xaf,0xfa,0x0c, +0xa6,0x7a,0x30,0xaf,0x1b,0x00,0xf3,0x9f,0xf4,0x83,0xf9,0x6a,0x18,0xee,0xed,0xdf, +0xdc,0x01,0xf3,0x75,0x30,0xe6,0xae,0xc0,0x07,0x32,0xfa,0x86,0xd5,0x0e,0xef,0x35, +0x73,0xf5,0x0a,0x98,0xff,0x02,0x6e,0xd2,0xb7,0x6e,0x82,0xf9,0x46,0x18,0x7b,0x1d, +0x68,0xf1,0x74,0x68,0x3f,0x07,0x33,0x1d,0x30,0xb8,0x3a,0xe0,0x33,0xf9,0x2b,0x38, +0xcc,0x8e,0x6a,0x3d,0x98,0xb9,0x06,0xa3,0xb8,0xe3,0xd3,0x3a,0x30,0xdf,0x0c,0xdf, +0x7f,0x3a,0xd0,0xe3,0xfa,0x32,0x7c,0x76,0x76,0xf6,0x80,0x79,0xf8,0x42,0x34,0x7f, +0xe5,0x2a,0x98,0xbf,0x5a,0x0e,0x13,0x9c,0xdd,0x37,0x70,0xf9,0x77,0x74,0xde,0x00, +0xf3,0xdd,0x0a,0x30,0xdf,0x03,0x9f,0xb6,0xf0,0xfb,0xcd,0x0c,0xfc,0x22,0x31,0x6f, +0x86,0x81,0x70,0x0d,0xfd,0x66,0xde,0x03,0x17,0xca,0x35,0x15,0xbc,0xd5,0x35,0x2d, +0xec,0x7b,0x0d,0x46,0xc0,0x8c,0x19,0x5e,0xf9,0xdb,0xbb,0x60,0x1e,0x7e,0x3f,0x9b, +0x1f,0xf8,0x04,0x26,0xe8,0xad,0x6b,0xf5,0x0a,0x00,0x70,0x1b,0x36,0xda,0xd8,0x6e, +0xda,0xbc,0xd9,0x0e,0xbf,0x65,0xab,0xbd,0xc3,0x5b,0x8e,0x9b,0x7f,0xf9,0x10,0x36, +0x3b,0x6d,0xdb,0xee,0xec,0xb2,0x63,0xa7,0xab,0xb5,0xe8,0xb6,0x79,0xd7,0x6e,0x77, +0x8f,0x3d,0x6f,0x7b,0x7a,0x6d,0xfe,0xbb,0x7f,0xf6,0xee,0x83,0xe2,0xfd,0xab,0x5e, +0x92,0xb8,0xff,0x80,0x8f,0xef,0xc1,0x77,0xb0,0x92,0xdf,0xeb,0x6a,0x92,0xff,0xe6, +0x00,0x32,0x05,0x1e,0xbc,0xbb,0xf9,0x9f,0xf3,0x73,0x68,0x33,0x95,0xf6,0xde,0xfb, +0x81,0xaf,0x8b,0xf4,0x37,0xdb,0x82,0x0e,0x6f,0x0e,0x0e,0xf9,0xe0,0x75,0xe9,0xc3, +0xcd,0xff,0xc6,0x9f,0xd0,0xb0,0x23,0x9b,0xd7,0x3f,0xeb,0x9f,0xf5,0xcf,0xfa,0x67, +0xfd,0xb3,0xfe,0x59,0xff,0xac,0x7f,0xd6,0x3f,0xeb,0x9f,0xf5,0xcf,0xfa,0x67,0xfd, +0xf3,0xef,0xf3,0x01,0x36,0xeb,0xfc,0x55,0xd8,0x02,0xbb,0xdf,0x02,0x0f,0x08,0xc0, +0x09,0x38,0x63,0xb8,0x00,0x77,0x88,0x07,0xf0,0x02,0x44,0x40,0x02,0x64,0x08,0x05, +0xd0,0x41,0x08,0x08,0x05,0x61,0x80,0x05,0x38,0x20,0x03,0xc2,0x07,0x62,0x20,0x03, +0x2a,0x60,0x00,0x35,0x90,0x46,0xd0,0x0a,0x3a,0x41,0x2f,0x18,0x00,0xf7,0xc1,0x43, +0xf0,0x18,0x3c,0x81,0xcc,0x80,0xe7,0xe0,0x05,0x78,0x05,0x6c,0x70,0xf6,0x56,0x9c, +0x71,0xee,0x38,0x6f,0x9c,0x1f,0x8e,0x6a,0x25,0x18,0x17,0x8e,0x63,0xe2,0x92,0x70, +0x29,0xb8,0x0c,0x08,0x1f,0x27,0xc6,0xc9,0x70,0x2a,0x9c,0x01,0x57,0x83,0x6b,0xc4, +0xb5,0xe2,0x3a,0x21,0xbd,0xb8,0x01,0xdc,0x7d,0xdc,0x43,0xdc,0x63,0xdc,0x13,0x2b, +0x33,0xb8,0xe7,0xb8,0x17,0xb8,0x57,0x38,0x9b,0x0d,0x36,0x1b,0xec,0x21,0xce,0x1b, +0xdc,0x37,0x78,0x6f,0xf0,0xdb,0x40,0xdd,0x10,0xbc,0x21,0x7c,0x03,0x73,0x43,0xd2, +0x86,0x94,0x0d,0x19,0x1b,0xf8,0x1b,0xc4,0x1b,0x64,0x1b,0x54,0x1b,0x0c,0x56,0x6a, +0x36,0x34,0x6e,0x68,0xdd,0xd0,0xb9,0xa1,0x77,0xc3,0xc0,0x86,0xfb,0x1b,0x1e,0x6e, +0x78,0xbc,0xe1,0xc9,0x86,0x99,0x0d,0xcf,0x37,0xbc,0xd8,0xf0,0x6a,0x83,0xcd,0x46, +0xfb,0x8d,0xce,0x1b,0xdd,0x37,0x7a,0x6f,0xf4,0xb3,0x42,0xdd,0x18,0xbc,0x31,0x7c, +0x23,0x73,0x63,0xd2,0xc6,0x94,0x8d,0x19,0x1b,0xf9,0x1b,0xc5,0x1b,0x25,0x1b,0xe5, +0x1b,0x55,0x1b,0x0d,0x1b,0x6b,0x36,0x36,0x6e,0x6c,0x85,0x74,0x6e,0xec,0xdd,0x38, +0xb0,0xf1,0xfe,0xc6,0x87,0x1b,0xc7,0x37,0x4e,0x6d,0x9c,0xb1,0xf2,0x7c,0xe3,0x8b, +0x8d,0xaf,0x36,0xda,0xd8,0xd8,0xdb,0xb8,0xd8,0xb8,0x5b,0xf1,0xb6,0xf1,0xb3,0xa1, +0xda,0x04,0xdb,0x84,0xdb,0x30,0xad,0x24,0xd9,0xa4,0xd8,0x64,0xd8,0xf0,0x6d,0xc4, +0x36,0x32,0x1b,0x95,0x8d,0xc1,0xa6,0xc6,0xa6,0xd1,0xa6,0xd5,0xa6,0xd3,0xa6,0xd7, +0x66,0xc0,0xe6,0xbe,0xcd,0x43,0x9b,0xc7,0x36,0x4f,0xac,0xcc,0xd8,0x3c,0xb7,0x79, +0x61,0xf3,0xca,0xc6,0xc6,0xd6,0xde,0xd6,0xd9,0xd6,0xdd,0xd6,0xdb,0xd6,0xcf,0x96, +0x6a,0x1b,0x6c,0x1b,0x6e,0xcb,0xb4,0x4d,0xb2,0x4d,0xb1,0xcd,0xb0,0xe5,0xdb,0x8a, +0x6d,0x65,0xb6,0x2a,0x5b,0x83,0x6d,0xad,0x6d,0xfd,0x5f,0x4d,0xb3,0x6d,0xfb,0xff, +0xc0,0x0d,0xdb,0xbe,0x3f,0x89,0x7e,0xdb,0x61,0xdb,0x31,0xdb,0x29,0x5b,0x8b,0xed, +0x82,0xed,0xb2,0xed,0xaa,0xad,0xed,0x26,0xfb,0x4d,0xce,0x9b,0xdc,0x37,0x79,0x6f, +0xf2,0xdb,0x44,0xdd,0x14,0xbc,0x29,0x7c,0x13,0x73,0x53,0xf2,0xa6,0x8c,0x4d,0xc2, +0x4d,0xb2,0x4d,0xda,0x4d,0x35,0x9b,0x9a,0x37,0x75,0x42,0xfa,0x36,0xdd,0xdf,0xf4, +0x68,0xd3,0x93,0x4d,0x33,0x9b,0x9e,0x5b,0x79,0xb1,0xe9,0xd5,0x26,0x9b,0xcd,0xf6, +0x9b,0x9d,0x37,0xbb,0x6f,0xf6,0xd9,0x4c,0xdd,0x1c,0xbc,0x39,0x7c,0x33,0x6b,0x33, +0x7b,0x73,0xea,0xe6,0x8c,0xcd,0xfc,0xcd,0x62,0x2b,0xb2,0xcd,0xaa,0xcd,0xd5,0x9b, +0x1b,0x37,0xb7,0x6e,0xee,0xdc,0xdc,0xbb,0x79,0x00,0x72,0x7f,0xf3,0xc3,0xcd,0x8f, +0x37,0x3f,0xd9,0x3c,0xb3,0xf9,0xf9,0xe6,0x17,0x9b,0x5f,0x6d,0xb6,0xb1,0xb3,0xb7, +0x73,0xb6,0x73,0xb7,0xf3,0xb6,0xf3,0xb3,0xa3,0xda,0x05,0xdb,0x85,0xdb,0x31,0xed, +0x92,0xec,0x52,0xec,0x32,0xec,0xf8,0x76,0x62,0x3b,0x99,0x9d,0xca,0xce,0x60,0x57, +0x63,0xd7,0x68,0xa5,0xd5,0xae,0xf3,0xb7,0xe8,0xb5,0x1b,0xb0,0xbb,0x6f,0xf7,0xd0, +0x6e,0xc2,0x6e,0xc6,0x6e,0xd1,0xee,0x95,0x9d,0x0d,0xde,0x1e,0xef,0x8a,0xf7,0xc6, +0xfb,0xe1,0xa9,0xff,0xa6,0xd0,0xf0,0x74,0x7c,0x08,0x3e,0x0c,0x1f,0x81,0x67,0xe0, +0x59,0xf8,0x78,0x3c,0x1b,0x9f,0xfc,0x57,0xc1,0xc1,0xa7,0xe3,0x79,0x78,0x11,0x5e, +0x8a,0x57,0xe2,0xb5,0x10,0x1d,0xde,0x88,0x37,0xe1,0x6b,0xf1,0x0d,0xf8,0xc6,0x7f, +0x5a,0x9a,0xf1,0xad,0x90,0x76,0xfc,0x8d,0xbf,0x31,0xbd,0xbf,0x60,0xc6,0x0f,0x60, +0xdc,0xfb,0x85,0x21,0xfc,0xf7,0xf8,0x47,0xf8,0x09,0xfc,0x13,0xfc,0x0c,0xfe,0x39, +0xfe,0x05,0xe4,0x15,0xc4,0x66,0x8b,0xfd,0x16,0xd7,0xbf,0x00,0xcf,0x2d,0x3e,0x5b, +0xc8,0x5b,0x02,0xb7,0x84,0x6e,0x89,0xdc,0x92,0xf4,0x17,0x90,0xb2,0x25,0x63,0x0b, +0x7f,0x8b,0x78,0x8b,0x6c,0x8b,0x7c,0x8b,0x72,0x8b,0x7a,0x8b,0x7e,0xcb,0xa7,0x5b, +0x1a,0xb6,0x34,0x6d,0x69,0xfe,0xb3,0x69,0xd9,0xd2,0xb6,0xa5,0x63,0x4b,0xe7,0x96, +0xae,0x2d,0xdd,0x5b,0x7a,0xad,0x98,0xb7,0xf4,0xfd,0x0e,0xf7,0xb6,0x3c,0x80,0x3c, +0xc2,0x98,0xf8,0x85,0xa7,0x5b,0xe6,0xb6,0x2c,0xfe,0x5e,0x5e,0xfe,0x95,0x80,0xad, +0x7f,0x0e,0x76,0x5b,0x09,0x10,0x57,0x0c,0xcf,0x5f,0xf0,0xd9,0x4a,0xde,0x1a,0xf8, +0x67,0x12,0xba,0x35,0xf2,0x1f,0x90,0xb8,0xad,0xc9,0xff,0x03,0x69,0x5b,0xb9,0x5b, +0x85,0x5b,0x8b,0xac,0x28,0xb6,0x6a,0xad,0x54,0x6f,0xad,0xdf,0xda,0xbc,0xb5,0x7d, +0xeb,0x8d,0xad,0x7d,0x56,0xee,0x6d,0x7d,0xb0,0xf5,0xd1,0xd6,0x89,0xad,0x4f,0xb7, +0xce,0x59,0x59,0xdc,0xfa,0x72,0x2b,0xb0,0xb7,0xb3,0x27,0xd8,0xbb,0xda,0x7b,0xda, +0xfb,0xd8,0x93,0xed,0x03,0xed,0x43,0xed,0x23,0xad,0xc4,0xd9,0x27,0xaf,0xf3,0x07, +0xe1,0xd8,0xa7,0xad,0xf3,0x17,0xc1,0xb5,0x17,0xda,0x17,0xd9,0x2b,0xec,0xb5,0xff, +0xc0,0xe8,0xec,0x4d,0xf6,0x0d,0xf6,0x2d,0xf6,0xed,0xff,0x60,0xdc,0x80,0xf4,0xfd, +0x51,0xee,0xfd,0xcd,0x00,0xeb,0x9f,0x7f,0xf3,0xcf,0xdf,0x22,0xaa,0x1e,0xfc,0x0e, +0x8f,0xac,0x4c,0xfc,0x4a,0x3c,0xb5,0x9f,0xb3,0x5f,0xb4,0x7f,0x69,0x0f,0x1c,0xec, +0x1c,0x08,0x0e,0xae,0xff,0xa2,0x78,0x3a,0xf8,0xfc,0x11,0xc8,0x0e,0x81,0x90,0xd0, +0x7f,0x1a,0x22,0xad,0xc4,0xfd,0x2a,0x24,0x3b,0xa4,0x39,0x70,0xad,0x08,0xd7,0xf9, +0x17,0xa4,0xc8,0x8a,0xc2,0x41,0xfb,0x47,0xa8,0x76,0xa8,0xff,0xbb,0xd2,0xfc,0x77, +0xa4,0xdd,0xe1,0x86,0x43,0xdf,0xbf,0x2d,0xf7,0xfe,0xcd,0x78,0xf0,0x5b,0x3c,0x72, +0x98,0x80,0x3c,0x75,0x78,0xfe,0x6f,0xce,0x0b,0x87,0x57,0x0e,0x36,0x6f,0xad,0xf3, +0x87,0xb0,0x87,0x38,0xbf,0xe5,0xf9,0x96,0xcf,0x3f,0x0d,0xbe,0x6f,0x91,0xff,0xad, +0xa1,0xbc,0x15,0xf8,0x2b,0x43,0x7f,0x2b,0xec,0xad,0xc8,0xbf,0x29,0x8c,0xb7,0x98, +0x7f,0x57,0x92,0x7e,0x0f,0x29,0xbf,0x90,0xf1,0x0b,0xfc,0x5f,0x10,0xff,0x41,0x64, +0xbf,0x07,0x15,0xc4,0xf0,0x56,0xed,0x5b,0xcd,0x6f,0x75,0xbc,0xd5,0xfb,0x3b,0x0c, +0xfc,0x09,0xdc,0xff,0x3d,0x3c,0xfc,0x85,0xc7,0xbf,0xf0,0xe4,0x17,0x66,0xfe,0x20, +0xcf,0xff,0x85,0x79,0xb1,0xce,0x3f,0x09,0xcb,0x6f,0xbd,0xfc,0xbd,0x00,0x47,0xe0, +0x68,0x07,0x21,0x40,0x5c,0x21,0x9e,0x18,0x3e,0xbf,0x3a,0x64,0x48,0xa0,0x95,0x50, +0xc7,0x48,0x48,0xdc,0x3a,0xff,0x62,0xc4,0x3b,0xb2,0x1d,0x39,0x8e,0x29,0x8e,0xa9, +0x8e,0xe9,0x8e,0x99,0x8e,0x3c,0x47,0x81,0xa3,0xc8,0x51,0xe2,0x28,0x75,0x94,0x3b, +0x2a,0x1d,0xd5,0x8e,0x5a,0x47,0x9d,0xa3,0xd1,0xd1,0xe4,0x58,0xeb,0xd8,0xe0,0xd8, +0xe4,0xd8,0xe2,0xd8,0xe6,0xd8,0xe1,0xd8,0xe5,0xd8,0xed,0x68,0x76,0xec,0x77,0x1c, +0x74,0x1c,0x72,0x1c,0x76,0x1c,0x71,0x1c,0x75,0x7c,0xe4,0x38,0xe6,0x38,0xee,0x38, +0xe9,0x38,0xe5,0x38,0xed,0x68,0x71,0x9c,0x77,0x5c,0x70,0x5c,0x72,0x5c,0x76,0x5c, +0x71,0x5c,0x75,0xc4,0x11,0x6c,0x09,0x78,0x82,0x03,0xc1,0x89,0xe0,0x42,0x70,0x23, +0x78,0x10,0xbc,0x08,0x44,0x82,0x2f,0x81,0x44,0xa0,0x10,0x68,0x04,0x3a,0x21,0x84, +0x10,0xfa,0x07,0x09,0x23,0x84,0xff,0x0a,0x44,0x10,0x18,0x04,0x16,0x21,0x9e,0xc0, +0x26,0x70,0x08,0xa9,0x84,0x74,0x42,0x26,0x81,0x47,0x10,0x10,0x44,0x04,0x09,0x41, +0x4a,0x90,0x13,0x94,0x04,0x35,0x41,0x47,0x30,0x12,0x4c,0x84,0x5a,0x42,0x03,0xa1, +0x89,0xd0,0x42,0x68,0x23,0x74,0x10,0xba,0x08,0xdd,0x04,0x33,0xa1,0x9f,0x30,0x48, +0x18,0x22,0x0c,0x13,0x46,0x08,0xa3,0x84,0x31,0xc2,0x38,0x61,0xe2,0x1f,0x80,0xa7, +0x84,0x39,0xc2,0x22,0xe1,0x25,0x01,0x38,0xd9,0x39,0x11,0x9c,0x5c,0x9d,0xbc,0x9d, +0xc8,0x4e,0x81,0x4e,0xa1,0x4e,0x91,0x4e,0x71,0x4e,0xc9,0x4e,0x69,0x4e,0x5c,0x27, +0xa1,0x53,0x91,0x93,0xc2,0xc9,0xe0,0x54,0xef,0xd4,0xea,0x74,0xc3,0xa9,0xcf,0xe9, +0x9e,0xd3,0x03,0xa7,0x47,0x4e,0x4f,0x9c,0xe6,0x9c,0x16,0x9d,0x5e,0x3a,0x81,0x6d, +0x76,0xdb,0x08,0xdb,0x5c,0xb7,0x79,0x6e,0xf3,0xd9,0x46,0xde,0x16,0xb8,0x2d,0x74, +0x5b,0xe4,0xb6,0xb8,0x6d,0xc9,0xdb,0xd2,0xb6,0x71,0xb7,0x89,0xb7,0x29,0xb6,0x69, +0xb7,0x55,0x6f,0xab,0xdf,0xd6,0xbc,0xad,0x7d,0xdb,0x8d,0x6d,0x7d,0xdb,0xee,0x6d, +0x7b,0xb8,0x6d,0x62,0xdb,0xd3,0x6d,0x73,0xdb,0x16,0xb7,0xbd,0xdc,0x06,0xb6,0xdb, +0x6d,0x27,0x6c,0x77,0xdd,0xee,0xb9,0xdd,0x67,0x3b,0x79,0x7b,0xe0,0xf6,0xd0,0xed, +0x91,0xdb,0xe3,0xb6,0x27,0x6f,0x4f,0xdb,0xce,0xdd,0x2e,0xde,0xae,0xd8,0x6e,0xd8, +0x5e,0xbf,0xbd,0x75,0xfb,0x8d,0xed,0x03,0xdb,0x1f,0x6c,0x7f,0xb4,0x7d,0x62,0xfb, +0xd3,0xed,0x73,0xdb,0x17,0xb7,0xbf,0xdc,0x0e,0x9c,0xed,0x9c,0x9d,0x9d,0x3d,0x9d, +0x7d,0x9c,0xc9,0xce,0x81,0xce,0xa1,0xce,0x91,0xce,0x71,0xce,0x29,0xce,0x5c,0x67, +0xb1,0xb3,0xc2,0xd9,0xe0,0x5c,0xef,0xdc,0xec,0xdc,0xee,0x7c,0xc3,0xb9,0xcf,0xf9, +0x9e,0xf3,0x03,0xe7,0x47,0xce,0x13,0xce,0x4f,0x9d,0xe7,0x9c,0x17,0x9d,0x5f,0x3a, +0x03,0x17,0x3b,0x17,0x67,0x17,0x4f,0x17,0x3f,0x97,0x40,0x97,0x50,0x97,0x48,0x97, +0x38,0x97,0x64,0x97,0x34,0x17,0xae,0x8b,0xd0,0xa5,0xc8,0x45,0xe1,0xa2,0x75,0xa9, +0x76,0xa9,0x77,0x69,0x76,0x69,0x77,0xb9,0xe1,0xd2,0xe7,0x72,0xcf,0xe5,0x81,0xcb, +0x23,0x97,0x09,0x97,0xa7,0x2e,0x73,0x2e,0x8b,0x2e,0x2f,0x5d,0xc0,0x0e,0xbb,0x1d, +0x84,0x1d,0xae,0x3b,0x3c,0x77,0xf8,0xee,0x78,0x77,0x47,0xe0,0x2f,0x84,0xee,0x88, +0xdc,0x11,0xb7,0x23,0x79,0x47,0xc6,0x0e,0xe1,0x0e,0xd9,0x0e,0xed,0x8e,0x9a,0x1d, +0xcd,0x3b,0x3a,0x77,0xf4,0xed,0xb8,0xbf,0xe3,0xd1,0x8e,0x27,0x3b,0xe6,0x76,0xbc, +0xd8,0x01,0x76,0xda,0xef,0x74,0xdd,0xe9,0xbd,0x93,0xbc,0x33,0x78,0x67,0xe4,0xce, +0xb8,0x9d,0xc9,0x3b,0xd3,0x76,0x72,0x77,0x0a,0x77,0x16,0xed,0x54,0xed,0xac,0xde, +0xd9,0xb8,0xb3,0x7d,0x67,0xef,0xce,0x7b,0x3b,0x1f,0xee,0x9c,0xd8,0x39,0xb3,0x73, +0x71,0xe7,0xcb,0x9d,0xc0,0xd5,0xce,0x95,0xe0,0xea,0xea,0xea,0xe9,0xea,0xe3,0x4a, +0x76,0x0d,0x76,0x8d,0x74,0x4d,0x72,0x4d,0x73,0xe5,0xbb,0x16,0xb9,0xaa,0x5c,0xab, +0x5d,0x1b,0x5d,0xdb,0x5d,0x7b,0x5d,0xef,0xb9,0x3e,0x74,0x9d,0x70,0x9d,0x71,0x5d, +0x74,0x7d,0xe5,0x6a,0xe7,0xe6,0xec,0xe6,0xe9,0xe6,0xe3,0x46,0x76,0x0b,0x74,0x0b, +0x75,0x63,0xba,0x25,0xbb,0x65,0xb8,0x09,0xdd,0x64,0x6e,0x5a,0xb7,0x1a,0xb7,0x66, +0xb7,0x4e,0xb7,0x3e,0xb7,0x7b,0x6e,0x0f,0xdc,0x1e,0xb9,0x4d,0xb8,0x3d,0x75,0x9b, +0x73,0x5b,0x74,0x7b,0xf9,0x3b,0x80,0x5d,0x76,0xbb,0x9c,0x77,0x79,0xee,0xf2,0xdb, +0x15,0xb8,0x2b,0x7c,0x57,0xdc,0xae,0xe4,0x5d,0x69,0xbb,0xf8,0xbb,0x8a,0x76,0xa9, +0x76,0x55,0xef,0x6a,0xdc,0xd5,0xbe,0xeb,0xc6,0xae,0xbe,0x5d,0xf7,0x77,0x3d,0xda, +0xf5,0x64,0xd7,0x9c,0x95,0xc5,0x5d,0x2f,0x77,0xd9,0xec,0x26,0xec,0x76,0xdf,0xed, +0x63,0x85,0xbc,0x3b,0x70,0x77,0xf8,0xee,0xb8,0xdd,0x29,0xbb,0xb9,0xbb,0xc5,0xbb, +0x15,0xbb,0xb5,0xbb,0xab,0x77,0x37,0xee,0x6e,0xdf,0xdd,0xbb,0xfb,0xde,0xee,0x87, +0xbb,0x27,0x76,0x3f,0xdd,0x3d,0xb7,0xfb,0xc5,0x6e,0xe0,0x6e,0xef,0xee,0xea,0xee, +0xed,0x4e,0x76,0x0f,0x74,0x0f,0x75,0x67,0xba,0x27,0xbb,0x67,0xb8,0x0b,0xdd,0x65, +0xee,0x5a,0xf7,0x6a,0xf7,0x7a,0xf7,0x56,0xf7,0x1b,0xee,0x03,0xee,0x0f,0xac,0x3c, +0x72,0x9f,0x70,0x9f,0x71,0x5f,0x74,0x7f,0xe5,0x6e,0xe7,0x81,0x20,0x78,0xb8,0x7a, +0x78,0x7b,0x90,0x3d,0x82,0x3d,0x22,0x3d,0x92,0x3c,0xd2,0x20,0x5c,0x88,0x18,0xa2, +0x80,0x18,0x3c,0x6a,0x3c,0x1a,0x3d,0xda,0x3d,0x7a,0x3d,0xee,0x79,0x3c,0xf4,0x98, +0xf0,0x98,0xf1,0x78,0xee,0xf1,0xc2,0x03,0xec,0xb1,0xdf,0xe3,0xba,0xc7,0x7b,0x0f, +0x79,0x4f,0xf0,0x9e,0xf0,0x3d,0xcc,0x3d,0x49,0x7b,0x52,0xf6,0x64,0xec,0xe1,0xef, +0x11,0xef,0x91,0xed,0x51,0xed,0x31,0xec,0xa9,0xd9,0xd3,0xb8,0xa7,0x75,0x4f,0xa7, +0x95,0xbe,0x3d,0xf7,0xf7,0x3c,0xde,0x33,0xb3,0xe7,0xc5,0x1e,0x9b,0xb7,0x9d,0xdf, +0xf6,0x7e,0x9b,0xfc,0x76,0xf0,0xdb,0xcc,0xb7,0x53,0xde,0xe6,0xbf,0x2d,0x7b,0xdb, +0xf0,0x76,0xe3,0xdb,0xed,0x6f,0xf7,0xbe,0x7d,0xff,0xed,0xc7,0x6f,0xcf,0xbc,0xfd, +0xe2,0x6d,0x1b,0x4f,0x67,0x4f,0x4f,0x4f,0x3f,0xcf,0x60,0x4f,0xa6,0x67,0x8a,0x27, +0xdf,0x53,0xe6,0x69,0xf0,0xac,0xf7,0x6c,0xf5,0xec,0xf5,0xbc,0xef,0xf9,0xd8,0x73, +0xc6,0xf3,0x85,0xa7,0x8d,0x17,0xc1,0xcb,0xdd,0xcb,0xcf,0x2b,0xd8,0x8b,0xe9,0x95, +0xe2,0xc5,0xf7,0x92,0x79,0xa9,0xbc,0x0c,0x5e,0xf5,0x5e,0xcd,0x5e,0x9d,0x90,0x5e, +0xaf,0x7b,0x5e,0x0f,0xbc,0x1e,0x79,0x4d,0x78,0x3d,0xf5,0x9a,0xf7,0x5a,0xf4,0x5a, +0xf6,0x5a,0xf5,0xda,0xb4,0xd7,0x7e,0xaf,0xeb,0x5e,0xcf,0xbd,0x7e,0x10,0xea,0xde, +0xd0,0xbd,0x91,0x7b,0xe3,0xf6,0x26,0xef,0x4d,0xdb,0x9b,0xbd,0x37,0x6f,0x6f,0xf1, +0x5e,0xc5,0x5e,0xed,0xde,0xea,0xbd,0x8d,0x7b,0xdb,0xad,0xdc,0xd8,0x3b,0xb0,0xf7, +0xfe,0xde,0x87,0x7b,0x1f,0xef,0x7d,0xb2,0xf7,0xff,0xd9,0x3b,0xbb,0xf7,0xff,0xdd, +0xfb,0x62,0xef,0xab,0xbd,0x36,0xfb,0x08,0xfb,0xdc,0xf7,0x79,0xef,0xf3,0xdb,0x47, +0xdd,0x17,0xba,0x2f,0x72,0x5f,0xdc,0xbe,0xe4,0x7d,0x69,0xfb,0xb2,0xf7,0xe5,0xed, +0x2b,0xda,0x27,0xb3,0xa2,0xdd,0x57,0xbd,0xaf,0x11,0xd2,0xba,0xef,0xc6,0xbe,0xbe, +0x7d,0xf7,0xf6,0x3d,0xd8,0xf7,0x68,0xdf,0x8f,0xfb,0xa6,0xf6,0xcd,0xec,0x9b,0x85, +0xfc,0xf7,0xbe,0x85,0x7d,0x4b,0xfb,0x96,0xf7,0xad,0xec,0x5b,0xdd,0x87,0xf3,0xb6, +0xf5,0xc6,0x7b,0x3b,0x78,0x13,0xde,0xc0,0xc9,0xdb,0xf9,0x17,0x5c,0xbc,0xdd,0xff, +0x00,0x1e,0xde,0x5e,0xde,0xbe,0xde,0xd4,0xdf,0x81,0xe6,0x1d,0x68,0x85,0xee,0x1d, +0xe6,0xcd,0xf4,0x66,0x79,0xb3,0xbd,0xd3,0x30,0xd2,0xbd,0xb9,0xde,0x3c,0x6f,0xe1, +0xef,0x20,0xf2,0x96,0x7a,0x2b,0xbd,0xb5,0x7f,0x10,0x9d,0x77,0xfd,0x6f,0xd1,0xe0, +0xdd,0xf8,0x47,0x68,0xf2,0x6e,0xf1,0x6e,0x85,0xb4,0x79,0x77,0x78,0x77,0x79,0x77, +0x7b,0x9b,0xbd,0xfb,0xbd,0x07,0xbd,0x87,0xbc,0x87,0xbd,0x47,0xbc,0x47,0xbd,0xc7, +0xbc,0xc7,0xbd,0x27,0xbd,0xa7,0xbc,0xa7,0xbd,0x2d,0xde,0xf3,0xde,0x0b,0xde,0x4b, +0xde,0xcb,0xde,0x2b,0xde,0xab,0xde,0x38,0xa2,0x2d,0x11,0x4f,0x74,0x20,0x12,0x88, +0x4e,0x44,0x17,0xa2,0x1b,0xd1,0x83,0xe8,0x45,0x24,0x12,0x7d,0x89,0x24,0x22,0x85, +0x48,0x23,0xd2,0x89,0x21,0xc4,0x30,0x62,0xf8,0xef,0x25,0x82,0xc8,0xfc,0xa7,0x82, +0x05,0xe1,0x10,0x33,0x89,0x3c,0xa2,0x90,0x28,0x22,0xca,0x89,0x3a,0xa2,0x81,0x68, +0x24,0xd6,0x12,0x1b,0x88,0x4d,0xc4,0x16,0x62,0x1b,0xb1,0x83,0xd8,0x45,0xec,0x26, +0x9a,0x89,0xfd,0xc4,0x01,0xe2,0x20,0x71,0x88,0xf8,0x00,0x32,0x42,0x1c,0x25,0x8e, +0x11,0xc7,0x89,0x93,0xc4,0x27,0x90,0x29,0xa2,0x85,0xb8,0x44,0x7c,0x49,0x5c,0x21, +0xbe,0x82,0x80,0xfd,0xb8,0xfd,0x36,0x10,0xbb,0xfd,0x4e,0xfb,0x5d,0xf6,0xbb,0xee, +0x77,0xdb,0xef,0xb1,0xdf,0x6b,0xbf,0xf7,0x7e,0xe2,0x7e,0xdf,0xfd,0xa4,0xfd,0x94, +0xfd,0xb4,0xfd,0xf4,0xfd,0x21,0xfb,0x43,0xf7,0x87,0xed,0x67,0xed,0x8f,0xdf,0xcf, +0xde,0xcf,0xd9,0x9f,0xba,0x3f,0x0d,0x23,0x7d,0x7f,0xe6,0x7e,0xde,0x7e,0xc1,0x7e, +0xd1,0x7e,0xf1,0x1b,0x48,0xf6,0x2b,0xf7,0x1b,0xf7,0x37,0xed,0xef,0xd8,0x6f,0xde, +0x3f,0xb4,0x7f,0x74,0xff,0xe4,0x7e,0xcb,0xfe,0xa5,0xfd,0xab,0xfb,0xf1,0x07,0x5c, +0x0e,0x78,0x1d,0x20,0x1d,0xa0,0x1d,0xa0,0x1f,0x08,0x3b,0xc0,0x3a,0xc0,0x3e,0xc0, +0x39,0x90,0x7e,0x40,0x70,0x40,0x7e,0x40,0x7d,0x40,0x77,0xc0,0x74,0xa0,0xe9,0x40, +0xcb,0x81,0xb6,0x03,0x1d,0x07,0xba,0x0e,0x74,0x1f,0xe8,0x3f,0x30,0x7c,0x60,0xf4, +0xc0,0xd8,0x81,0xc9,0x03,0x96,0x03,0xcb,0x07,0x56,0x0f,0xe0,0x7c,0xf0,0x3e,0x2e, +0x3e,0x6e,0x3e,0x1e,0x3e,0x5e,0x3e,0xde,0xff,0x07,0x44,0x1f,0xf2,0x1f,0x25,0xd0, +0x27,0xf4,0x4f,0x22,0xf2,0xaf,0x22,0xce,0x27,0xd9,0x27,0xed,0xef,0x08,0xf7,0x17, +0x84,0x56,0x8a,0xfe,0x4c,0x14,0x10,0xed,0x2f,0xe8,0x7c,0x4c,0x3e,0x8d,0x3e,0x4d, +0x3e,0x6d,0x3e,0x37,0xfe,0x28,0x7d,0x56,0xee,0x59,0x79,0x00,0x79,0xf4,0x67,0x31, +0x01,0x79,0xfa,0x7b,0x99,0xf3,0x59,0xf4,0x79,0xe9,0x03,0x7c,0xed,0xac,0x10,0x7c, +0x5d,0xad,0x78,0xfa,0xfa,0xfc,0x16,0x64,0xdf,0x40,0x2b,0xa1,0xbe,0x91,0x56,0xe2, +0x7c,0x93,0x7f,0x15,0xd2,0x7c,0xb9,0xbe,0x42,0xdf,0xa2,0xbf,0x39,0x0a,0x5f,0xad, +0x6f,0xb5,0x6f,0xfd,0x6f,0xd1,0xec,0xdb,0xee,0x7b,0xc3,0xb7,0xef,0xff,0x1a,0x03, +0xbe,0xf7,0xd6,0x59,0xe7,0xef,0xc4,0x90,0xef,0xb0,0xef,0x88,0xef,0xa8,0xef,0x98, +0xef,0xb8,0xef,0xa4,0xef,0x94,0xef,0xb4,0xaf,0xc5,0x77,0xc1,0x77,0xd9,0x77,0xd5, +0xd7,0xf6,0xa0,0xc3,0x41,0x97,0x83,0x1e,0x07,0x89,0x07,0x49,0x07,0x69,0x07,0x43, +0x0e,0x32,0x0e,0xb2,0x0f,0xa6,0x1f,0x14,0x1c,0x94,0x1e,0x54,0x1f,0x34,0x1d,0x6c, +0x3a,0xd8,0x71,0xb0,0xff,0xe0,0xc8,0xc1,0xc9,0x83,0xf3,0x07,0x57,0x0e,0xe2,0xdf, +0x71,0x7b,0xc7,0xf7,0x1d,0xfa,0x3b,0x8c,0x77,0x38,0xef,0xa4,0xbf,0xc3,0x7b,0x47, +0xf4,0x8e,0xf4,0x1d,0xe5,0x3b,0xba,0x77,0x4c,0xef,0x34,0xbc,0xd3,0xf2,0x4e,0xd7, +0x3b,0xfd,0xef,0x0c,0xbf,0x33,0xf6,0xce,0xd4,0x3b,0xf3,0xef,0x2c,0xbf,0x83,0xf3, +0x73,0xf0,0x73,0xf3,0x23,0xfa,0x51,0xfc,0x42,0xfc,0x18,0x7e,0x6c,0xbf,0x74,0x3f, +0x81,0x9f,0xd4,0x4f,0xed,0x67,0xf2,0x6b,0xf2,0xeb,0xf0,0x33,0xfb,0x0d,0xf9,0x8d, +0xfa,0x4d,0xfa,0x59,0xfc,0x96,0xfc,0x56,0xfd,0xf0,0x24,0x17,0x92,0x17,0x89,0x44, +0xa2,0x93,0x22,0x48,0xf1,0xa4,0x54,0x52,0x3a,0x29,0x93,0xc4,0x23,0x09,0x48,0x22, +0x92,0x84,0x24,0x25,0xc9,0x49,0x4a,0x92,0x9a,0xa4,0x23,0x19,0x49,0x26,0x52,0x2d, +0xa9,0x81,0xd4,0x44,0x6a,0x21,0xb5,0x91,0x3a,0x48,0x5d,0xa4,0x6e,0x92,0x99,0xd4, +0x4f,0x1a,0x24,0x0d,0x91,0x86,0x49,0x23,0xa4,0x51,0xd2,0x18,0x69,0x9c,0x34,0x49, +0x9a,0x22,0x4d,0x93,0x2c,0xa4,0x79,0xd2,0x02,0x69,0x89,0xb4,0x4c,0x5a,0x21,0xad, +0x92,0x70,0xfe,0xb6,0xfe,0x78,0x7f,0x07,0x7f,0x27,0x7f,0x17,0x7f,0x37,0x7f,0x0f, +0x7f,0x2f,0x7f,0xa2,0xbf,0xaf,0x3f,0xc9,0x9f,0xfc,0x2b,0x40,0xf1,0x0f,0xfd,0x97, +0x22,0xcc,0x9f,0xe5,0xcf,0xf6,0x4f,0xfb,0x17,0x82,0xbb,0xce,0x5f,0x05,0xcf,0x5f, +0xe0,0x2f,0x5c,0xe7,0x5f,0x1e,0x91,0xbf,0x78,0x9d,0x75,0xfe,0x86,0x48,0xfc,0x8b, +0xfe,0x29,0x90,0xfa,0xcb,0xfe,0x00,0x72,0x88,0xd2,0x5f,0xed,0xaf,0xf3,0x37,0xfa, +0x9b,0xfc,0x6b,0xfd,0x1b,0xfc,0x9b,0xfc,0x5b,0xfc,0xdb,0xfc,0x3b,0xfc,0xbb,0xfc, +0xbb,0xfd,0xcd,0xfe,0xfd,0xfe,0x83,0xfe,0x43,0xfe,0xc3,0xfe,0x23,0xfe,0xa3,0xfe, +0x63,0xfe,0xe3,0xfe,0x93,0xfe,0x53,0xfe,0xd3,0xfe,0x16,0xff,0x79,0xff,0x05,0xff, +0x25,0xff,0x65,0xff,0x15,0xff,0x55,0x7f,0x5c,0x80,0x6d,0x00,0x3e,0xc0,0x21,0xc0, +0x29,0xc0,0x25,0xc0,0x2d,0xc0,0x23,0xc0,0x2b,0x80,0x18,0xe0,0x1b,0x40,0x0a,0xa0, +0x04,0xd0,0x02,0xe8,0x01,0x21,0x01,0x61,0x01,0x11,0x01,0x8c,0x00,0x56,0x40,0x7c, +0x00,0x3b,0x80,0x13,0x90,0x1a,0x90,0x1e,0x90,0x19,0xc0,0x0b,0x10,0x04,0x88,0x02, +0x24,0x01,0xd2,0x00,0x79,0x80,0x32,0x40,0x1d,0xa0,0x0b,0x30,0x06,0x98,0x02,0x6a, +0x03,0x1a,0x02,0x9a,0x02,0x5a,0x02,0xda,0x02,0x3a,0x02,0xba,0x02,0xba,0x03,0xcc, +0x01,0xfd,0x01,0x83,0x01,0x43,0x01,0xc3,0x01,0x23,0x01,0xa3,0x01,0x63,0x01,0xe3, +0x01,0x93,0x01,0x53,0x01,0xd3,0x01,0x96,0x80,0xf9,0x80,0x85,0x80,0xa5,0x80,0xe5, +0x80,0x95,0x80,0xd5,0x00,0x1c,0xd9,0x96,0x8c,0x27,0x3b,0x90,0x9d,0xc8,0x2e,0x64, +0x37,0xb2,0x07,0xd9,0x8b,0x4c,0x24,0xfb,0x92,0x49,0x64,0x0a,0x99,0x46,0xa6,0x93, +0x43,0xc8,0x61,0xe4,0x08,0x32,0x83,0xcc,0x22,0xc7,0x93,0xd9,0x64,0x0e,0x39,0x95, +0x9c,0x4e,0xce,0x24,0xf3,0xc8,0x02,0xb2,0x88,0x2c,0x21,0x4b,0xc9,0x72,0xb2,0x92, +0xac,0x26,0xeb,0xc8,0x46,0xb2,0x89,0x5c,0x4b,0x6e,0x20,0x37,0x91,0x5b,0xc8,0x6d, +0xe4,0x0e,0x72,0x17,0xb9,0x9b,0x6c,0x26,0xf7,0x93,0x07,0xc9,0x43,0xe4,0x61,0xf2, +0x08,0x79,0x94,0x3c,0x46,0x1e,0x27,0x4f,0x92,0xa7,0xc8,0xd3,0x64,0x0b,0x79,0x9e, +0xbc,0x40,0x5e,0x22,0x2f,0x93,0x57,0xc8,0xab,0x64,0x1c,0xc5,0x96,0x82,0xa7,0x38, +0x50,0x9c,0x28,0x2e,0x14,0x37,0x8a,0x07,0xc5,0x8b,0x42,0xa4,0xf8,0x52,0x48,0x14, +0x0a,0x85,0x46,0xa1,0x53,0x42,0x28,0x61,0x94,0x08,0x0a,0x83,0xc2,0xa2,0xc4,0x53, +0xd8,0x14,0x0e,0x25,0x95,0x92,0x4e,0xc9,0xa4,0xf0,0x28,0x02,0x8a,0x88,0x22,0xa1, +0x48,0x29,0x72,0x8a,0x92,0xa2,0xa6,0xe8,0x28,0x46,0x8a,0x89,0x52,0x4b,0x69,0xa0, +0x34,0x51,0x5a,0x28,0x6d,0x94,0x0e,0x4a,0x17,0xa5,0x9b,0x62,0xa6,0xf4,0x53,0x06, +0x29,0x43,0x94,0x61,0xca,0x08,0x65,0x94,0x32,0x46,0x79,0xfc,0x37,0x60,0x1c,0x32, +0xf1,0x77,0x63,0x92,0xf2,0x84,0x32,0x45,0x99,0xa6,0x58,0x28,0x73,0x7f,0x02,0x8b, +0x90,0x97,0x10,0xf0,0x2e,0x78,0xd7,0x0e,0x42,0x80,0xb8,0x42,0x3c,0x21,0x3e,0x10, +0x32,0x24,0x10,0x12,0x0a,0x89,0xb4,0x12,0x07,0x49,0x86,0xa4,0xfd,0x16,0xdc,0x77, +0x85,0x90,0xa2,0x77,0x15,0x10,0xed,0xbb,0xd5,0x90,0xfa,0x77,0x9b,0x21,0xed,0xef, +0xde,0xf8,0xb3,0xe8,0x7b,0x83,0xfe,0x77,0x87,0xde,0x7d,0x00,0x19,0x7b,0x77,0xe2, +0x0f,0xf2,0x14,0x32,0x07,0x59,0x84,0xbc,0x84,0x80,0x43,0xe0,0x90,0x1d,0x84,0x00, +0x71,0x85,0x78,0x42,0x7c,0x20,0x64,0x48,0xa0,0x95,0x50,0x48,0x24,0x24,0xee,0xb7, +0x48,0x3e,0x94,0x06,0xe1,0x1e,0x12,0x42,0x8a,0x0e,0x29,0x20,0xda,0x43,0xd5,0x90, +0xfa,0x43,0xcd,0x7f,0x16,0xed,0x56,0x6e,0x1c,0xea,0x3b,0x74,0xef,0xd0,0x03,0x8c, +0xb1,0x43,0x13,0x7f,0x07,0x26,0x0f,0x4d,0x1d,0x9a,0x3e,0x64,0x39,0x34,0x7f,0x68, +0xe1,0xd0,0xd2,0xa1,0xe5,0x43,0x2b,0x87,0x56,0x0f,0xe1,0xa8,0xb6,0x54,0x3c,0xd5, +0x81,0xea,0x44,0x75,0xa1,0xba,0x51,0x3d,0xa8,0x5e,0x54,0x22,0xd5,0x97,0x4a,0xa2, +0x52,0xa8,0x34,0x2a,0x9d,0x1a,0x42,0x0d,0xa3,0x46,0x50,0x19,0x54,0x16,0x35,0x9e, +0xca,0xa6,0x72,0xa8,0xa9,0xd4,0x74,0x6a,0x26,0x95,0x47,0x15,0x50,0x45,0x54,0x09, +0x55,0x4a,0x95,0x53,0x95,0x54,0x35,0x55,0x47,0x35,0x52,0x4d,0xd4,0x5a,0x6a,0x03, +0xb5,0x89,0xda,0x42,0x6d,0xa3,0x76,0x50,0xbb,0xa8,0xdd,0x54,0x33,0xb5,0x9f,0x3a, +0x48,0x1d,0xa2,0x0e,0x53,0x47,0xa8,0xa3,0xd4,0x31,0xea,0x38,0x75,0x92,0x3a,0x45, +0x9d,0xa6,0x5a,0xa8,0xf3,0xd4,0x05,0xea,0x12,0x75,0x99,0xba,0x42,0x5d,0xa5,0xe2, +0x68,0xb6,0x34,0x3c,0xcd,0x81,0xe6,0x44,0x73,0xa1,0xb9,0xd1,0x3c,0x68,0x5e,0x34, +0x22,0xcd,0x97,0x46,0xa2,0x51,0x68,0x34,0x1a,0x9d,0x16,0x42,0x0b,0xa3,0x45,0xd0, +0x18,0x34,0x16,0x2d,0xce,0x4a,0x3c,0x8d,0x4d,0xe3,0xd0,0x52,0x69,0xe9,0xb4,0x4c, +0x1a,0x8f,0x26,0xa0,0x89,0x68,0x12,0x9a,0x94,0x26,0xa7,0x29,0x69,0x6a,0x9a,0xf6, +0x9f,0x1c,0x1d,0xa4,0x96,0xd6,0x42,0xeb,0xa2,0xf5,0xd3,0x86,0x69,0x63,0xb4,0x29, +0xda,0x3c,0x6d,0x99,0x86,0x7b,0xcf,0xe1,0x3d,0xb7,0xf7,0x88,0xef,0x51,0xde,0x0b, +0x7b,0x2f,0xfe,0xbd,0xf4,0xf7,0x44,0xef,0x29,0xdf,0x33,0xbd,0xd7,0xf2,0x5e,0xf7, +0x7b,0x43,0xef,0x8d,0xbd,0x37,0xfd,0xde,0xd2,0x7b,0xb8,0xf7,0x9d,0xde,0xf7,0x7a, +0x3f,0xe4,0xfd,0xa4,0xf7,0xd9,0xef,0xa7,0xbf,0x2f,0x78,0x5f,0xfa,0xbe,0xfa,0x7d, +0xd3,0xfb,0x4d,0xef,0x77,0xbc,0x6f,0x7e,0x7f,0xe8,0xfd,0xd1,0xf7,0x27,0xdf,0xb7, +0xbc,0xbf,0xf4,0xfe,0xea,0xfb,0xf8,0x40,0x97,0x40,0xaf,0x40,0x52,0x20,0x3d,0x30, +0x22,0x30,0x3e,0x30,0x35,0x90,0x17,0x28,0x09,0x54,0x06,0x1a,0x03,0x1b,0x02,0xdb, +0x02,0xbb,0x03,0x07,0x03,0x47,0x02,0xc7,0x03,0xa7,0x03,0x17,0x02,0x57,0x02,0x6d, +0xe9,0x78,0xba,0x03,0xdd,0x89,0xee,0xfc,0x3b,0xb8,0xd0,0xbd,0xe8,0xbe,0x74,0x0a, +0x9d,0x4e,0x0f,0xa3,0x33,0xe8,0xf1,0x74,0x0e,0x3d,0x9d,0xce,0xa3,0x8b,0xe8,0x52, +0xba,0x92,0xae,0xa3,0x9b,0xe8,0x0d,0xf4,0x26,0x7a,0x0b,0xbd,0x8d,0xde,0x41,0xef, +0xa2,0x77,0xd3,0xcd,0xf4,0x7e,0xfa,0x20,0x7d,0x88,0x3e,0x4c,0x1f,0xa1,0x8f,0xd2, +0xc7,0xe8,0x93,0xf4,0x69,0xfa,0x3c,0x7d,0x89,0xbe,0x42,0xc7,0x05,0xe1,0x83,0x9c, +0x82,0xdc,0x82,0xbc,0x82,0x7c,0x83,0x28,0x41,0xf4,0xa0,0xb0,0x20,0x76,0x50,0x66, +0x10,0x3f,0x48,0x10,0x24,0x0a,0x92,0x04,0x49,0x83,0xe4,0x41,0xca,0x20,0x75,0x90, +0x2e,0xc8,0x18,0x64,0x0a,0xaa,0x0d,0x6a,0x08,0x6a,0x0a,0x6a,0x09,0x6a,0x0b,0xea, +0x08,0xea,0x0a,0xea,0x0e,0x32,0x07,0xf5,0x07,0x0d,0x06,0x0d,0x05,0x0d,0x07,0x8d, +0x04,0x8d,0x06,0x8d,0x05,0x8d,0x07,0x4d,0x06,0x4d,0x05,0x4d,0x07,0x59,0x82,0xe6, +0x83,0x16,0x82,0x96,0x82,0x96,0x83,0x56,0x82,0x56,0x83,0x70,0x87,0x6d,0x0f,0xe3, +0x0f,0x3b,0x1c,0x76,0x3a,0xec,0x72,0xd8,0xed,0xb0,0xc7,0x61,0xaf,0xc3,0xc4,0xc3, +0xbe,0x87,0x49,0x87,0x29,0x87,0xe9,0x87,0xc3,0x0e,0x33,0x0e,0xc7,0x1f,0xe6,0x1c, +0x4e,0x3f,0xcc,0x3b,0x2c,0x3a,0x2c,0x3d,0xac,0x3c,0xac,0x3b,0x6c,0x3a,0xdc,0x70, +0xb8,0xe5,0x70,0xc7,0xe1,0xee,0xc3,0xfd,0x87,0x87,0x0e,0x8f,0x1c,0x1e,0x3b,0x3c, +0x79,0x78,0xfa,0xf0,0xfc,0xe1,0xa5,0xc3,0xab,0x87,0xf1,0xc1,0x2e,0xc1,0x1e,0xc1, +0xbe,0xc1,0x94,0xe0,0x90,0xe0,0xb0,0xe0,0x88,0x60,0x46,0x30,0x2b,0x38,0x3e,0x98, +0x1d,0xcc,0x09,0x4e,0x0d,0x4e,0x0f,0xce,0x0c,0xe6,0x05,0x0b,0x82,0x45,0xc1,0x92, +0x60,0x69,0xb0,0x3c,0x58,0x19,0xac,0x0e,0xd6,0x05,0x1b,0x83,0x4d,0xc1,0xb5,0xc1, +0x0d,0xc1,0x4d,0xc1,0x2d,0xc1,0x6d,0xc1,0x1d,0xc1,0x5d,0xc1,0xdd,0xc1,0xe6,0xe0, +0xfe,0xe0,0xc1,0xe0,0xa1,0xe0,0xe1,0xe0,0x91,0xe0,0xd1,0xe0,0xb1,0xe0,0xf1,0xe0, +0xc9,0xe0,0xa9,0xe0,0xe9,0x60,0x4b,0xf0,0x7c,0xf0,0x42,0xf0,0x52,0xf0,0x72,0xf0, +0x4a,0x30,0x2e,0x04,0x17,0xe2,0x12,0x42,0x0c,0xa1,0x87,0x44,0x84,0x70,0x42,0x32, +0x43,0x44,0x21,0xba,0x90,0x86,0x90,0xb6,0x90,0xee,0x90,0xc1,0x90,0xd1,0x90,0xa9, +0x90,0x85,0x90,0xd5,0x10,0x87,0x0f,0x3c,0x3e,0x20,0x7d,0x10,0xf1,0x01,0xeb,0x83, +0xcc,0x0f,0xe4,0x1f,0x98,0x3e,0x68,0xf9,0xa0,0xff,0x83,0xb1,0x0f,0xa6,0x3f,0x58, +0xf8,0x60,0xe5,0x03,0xfc,0x87,0x6e,0x1f,0x92,0x3e,0x0c,0xfb,0x90,0xf5,0x21,0xe7, +0x43,0xde,0x87,0x92,0x0f,0x95,0x1f,0xea,0x3e,0x34,0x7d,0xd8,0xf4,0x61,0xc7,0x87, +0x43,0x1f,0x8e,0x7d,0x68,0xf9,0x70,0xf5,0x43,0x87,0x50,0xb7,0x50,0x62,0x68,0x48, +0x28,0x2b,0x34,0x33,0x54,0x14,0xaa,0x0e,0x35,0x85,0xb6,0x84,0x76,0x85,0x0e,0x86, +0x8e,0x85,0x4e,0x87,0x2e,0x87,0xda,0x86,0x39,0x84,0x79,0x85,0x91,0xc2,0xe8,0x61, +0x8c,0x30,0x76,0x58,0x7a,0x98,0x20,0x4c,0x19,0x66,0x0a,0x6b,0x08,0xeb,0x0e,0x1b, +0x0c,0x1b,0x0b,0x9b,0x0e,0x5b,0x0a,0x5b,0x0d,0xc3,0x1f,0x71,0x3b,0xe2,0x75,0x84, +0x72,0x24,0xe2,0x08,0xeb,0x48,0xe6,0x11,0xd1,0x11,0xe9,0x11,0xe5,0x11,0xdd,0x11, +0xd3,0x91,0x86,0x23,0x2d,0x47,0x3a,0x8e,0x74,0x1f,0xe9,0x3f,0x32,0x74,0x64,0xf4, +0xc8,0xe4,0x11,0xcb,0x91,0xa5,0x23,0xab,0x47,0xf0,0x47,0x5d,0x8e,0x7a,0x1d,0x25, +0x1d,0xa5,0x1f,0x8d,0x38,0x1a,0x7f,0x34,0xf5,0x28,0xef,0xa8,0xe4,0xa8,0xf2,0xa8, +0xee,0xa8,0xe9,0x68,0xd3,0xd1,0xb6,0xa3,0x5d,0x47,0xcd,0x47,0x87,0x8e,0x8e,0x1e, +0x1d,0x3f,0x3a,0x75,0xd4,0x72,0x74,0xe1,0xe8,0xf2,0x51,0xdb,0x70,0x87,0x70,0x97, +0x70,0x8f,0x70,0x62,0x38,0x29,0x9c,0x16,0x1e,0x12,0x1e,0x11,0x1e,0x1f,0x9e,0x1e, +0xce,0x0b,0x17,0x85,0x4b,0xc3,0x95,0xe1,0xba,0x70,0x53,0x78,0x43,0x78,0x5b,0x78, +0x77,0xf8,0x60,0xf8,0x48,0xf8,0x58,0xf8,0x64,0xf8,0x74,0xf8,0x7c,0xf8,0x52,0xf8, +0x4a,0x38,0x2e,0x02,0x1f,0xe1,0x14,0xe1,0x16,0x41,0x8c,0xa0,0x44,0xd0,0x23,0x22, +0x22,0xe2,0x23,0x52,0x23,0x32,0x23,0x44,0x11,0xf2,0x08,0x63,0x44,0x6d,0x44,0x4b, +0x44,0x57,0x44,0x7f,0xc4,0x70,0xc4,0x64,0xc4,0x52,0xc4,0x4a,0x04,0xee,0x18,0xfe, +0x98,0xd3,0x31,0xb7,0x63,0x5e,0xc7,0x7c,0x8f,0x51,0x8e,0xd1,0x8f,0x85,0x1d,0x63, +0x1c,0x8b,0x3f,0xc6,0x39,0x96,0x7e,0x8c,0x77,0x4c,0x74,0x4c,0x7a,0x4c,0x79,0xcc, +0x74,0xac,0xe1,0x58,0xcb,0xb1,0x8e,0x63,0xfd,0xc7,0x86,0x8f,0x8d,0x1e,0x1b,0x3f, +0x36,0x75,0xcc,0x72,0x6c,0xe1,0xd8,0xf2,0xb1,0xd5,0x63,0xb6,0xc7,0x1d,0x8e,0xbb, +0x1c,0xf7,0x3a,0xee,0x7b,0x9c,0x72,0x3c,0xe4,0x38,0xe3,0x78,0xfc,0xf1,0xf4,0xe3, +0x82,0xe3,0x92,0xe3,0xf2,0xe3,0xea,0xe3,0xc6,0xe3,0x0d,0xc7,0xdb,0x8e,0x77,0x1d, +0x37,0x1f,0x1f,0x3c,0x3e,0x7c,0x7c,0xf4,0xf8,0xf8,0xf1,0xa9,0xe3,0x96,0xe3,0x0b, +0xc7,0x57,0x8e,0xdb,0x46,0x3a,0x45,0x7a,0x44,0xfa,0x46,0xd2,0x22,0xc3,0x22,0x59, +0x91,0x9c,0xc8,0xcc,0x48,0x51,0xa4,0x3c,0x52,0x17,0x59,0x1b,0xd9,0x12,0xd9,0x15, +0xd9,0x1f,0x39,0x1c,0x39,0x16,0x39,0x15,0x39,0x1f,0xb9,0x1c,0x09,0x18,0xeb,0xfc, +0x65,0xe0,0x18,0xb6,0x0c,0xbb,0x75,0xfe,0x09,0xc0,0x33,0xec,0xff,0xed,0x71,0x60, +0x38,0x31,0x5c,0x18,0xae,0x56,0xdc,0x18,0x1e,0x0c,0xcf,0x7f,0x09,0xbc,0x18,0x44, +0x86,0x2f,0x83,0xc4,0x20,0xff,0x1f,0x50,0x18,0xd4,0x75,0xfe,0x2c,0x02,0x19,0xc1, +0x8c,0x50,0x46,0x38,0x23,0x92,0xc1,0x64,0xc4,0x31,0x92,0x18,0xc9,0x8c,0x14,0x46, +0x1a,0x23,0x83,0xc1,0x65,0xf0,0x19,0x42,0x86,0x98,0x51,0xc4,0x90,0x31,0x14,0x0c, +0x15,0x43,0xcb,0x30,0x30,0xaa,0x19,0x35,0x8c,0x7a,0x46,0x23,0xa3,0x99,0xd1,0xca, +0x68,0x67,0x74,0x32,0x6e,0x30,0x7a,0x19,0x7d,0x8c,0x01,0xc6,0x3d,0xc6,0x7d,0xc6, +0x03,0xc6,0x43,0xc6,0x23,0xc6,0x63,0xc6,0x04,0xe3,0x09,0xe3,0x29,0x63,0x86,0x31, +0xc7,0x78,0xce,0x58,0x64,0xbc,0x60,0xbc,0x64,0xbc,0x62,0x80,0x28,0x9b,0x28,0xbb, +0x28,0xfb,0x28,0x42,0x94,0x73,0x94,0x6b,0x94,0x7b,0x94,0x67,0x94,0x77,0x94,0x4f, +0x94,0x5f,0x14,0x39,0x8a,0x1a,0x15,0x18,0x15,0x1c,0x15,0x1a,0x15,0x1e,0x15,0x19, +0xc5,0x8c,0x8a,0x8b,0x4a,0x8a,0x4a,0x8e,0x4a,0x89,0x4a,0x8b,0xca,0x88,0xe2,0x46, +0xf1,0xa3,0x84,0x51,0xe2,0xa8,0xa2,0x28,0x59,0x94,0x22,0x4a,0x15,0xa5,0x8d,0x32, +0x44,0x55,0x47,0xd5,0x44,0xd5,0x47,0x35,0x46,0x35,0x47,0xb5,0x46,0xb5,0x47,0x75, +0x46,0xdd,0x88,0xea,0x8d,0xea,0x8b,0x1a,0x88,0xba,0x17,0x75,0x3f,0xea,0x41,0xd4, +0xc3,0xa8,0x47,0x51,0x8f,0xa3,0x26,0xa2,0x9e,0x44,0x3d,0x8d,0x9a,0x89,0x9a,0x8b, +0x7a,0x1e,0xb5,0x18,0xf5,0x22,0xea,0x65,0xd4,0xab,0x28,0x10,0x6d,0x13,0x6d,0x17, +0x6d,0x1f,0x4d,0x88,0x76,0x8e,0x76,0x8d,0x76,0x8f,0xf6,0x8c,0xf6,0x8e,0xf6,0x89, +0xf6,0x8b,0x26,0x47,0x53,0xa3,0x03,0xa3,0x83,0xa3,0x43,0xa3,0xc3,0xa3,0x23,0xa3, +0x99,0xd1,0x71,0xd1,0x49,0xd1,0xc9,0xd1,0x29,0xd1,0x69,0xd1,0x19,0xd1,0xdc,0x68, +0x7e,0xb4,0x30,0x5a,0x1c,0x5d,0x14,0x2d,0x8b,0x56,0x44,0xab,0xa2,0xb5,0xd1,0x86, +0xe8,0xea,0xe8,0x9a,0xe8,0xfa,0xe8,0xc6,0xe8,0xe6,0xe8,0xd6,0xe8,0xf6,0xe8,0xce, +0xe8,0x1b,0xd1,0xbd,0xd1,0x7d,0xd1,0x03,0xd1,0xf7,0xa2,0xef,0x47,0x3f,0x88,0x7e, +0x18,0xfd,0x28,0xfa,0x71,0xf4,0x44,0xf4,0x93,0xe8,0xa7,0xd1,0x33,0xd1,0x73,0xd1, +0xcf,0xa3,0x17,0xa3,0x5f,0x44,0xbf,0x8c,0x7e,0x15,0x0d,0x98,0x36,0x4c,0x3b,0xa6, +0x3d,0x93,0xc0,0x74,0x66,0xba,0x32,0xdd,0x99,0x9e,0x4c,0x6f,0xa6,0x0f,0xd3,0x8f, +0x49,0x66,0x52,0x99,0x81,0xcc,0x60,0x66,0x28,0x33,0x9c,0x19,0xc9,0x64,0x32,0xe3, +0x98,0x49,0xcc,0x64,0x66,0x0a,0x33,0x8d,0x99,0xc1,0xe4,0x32,0xf9,0x4c,0x21,0x53, +0xcc,0x2c,0x62,0xca,0x98,0x0a,0xa6,0x8a,0xa9,0x65,0x1a,0x98,0xd5,0xcc,0x1a,0x66, +0x3d,0xb3,0x91,0xd9,0xcc,0x6c,0x65,0xb6,0x33,0x3b,0x99,0x37,0x98,0xbd,0xcc,0x3e, +0xe6,0x00,0xf3,0x1e,0xf3,0x3e,0xf3,0x01,0xf3,0x21,0xf3,0x11,0xf3,0x31,0x73,0x82, +0xf9,0x84,0xf9,0x94,0x39,0xc3,0x9c,0x63,0x3e,0x67,0x2e,0x32,0x5f,0x30,0x5f,0x32, +0x5f,0x31,0x01,0xcb,0x86,0x65,0xc7,0xb2,0x67,0x11,0x58,0xce,0x2c,0x57,0x96,0x3b, +0xcb,0x93,0xe5,0xcd,0xf2,0x61,0xf9,0xb1,0xc8,0x2c,0xf8,0x85,0x8b,0x15,0xc8,0x0a, +0x66,0x85,0xb2,0xc2,0x59,0x91,0x2c,0x26,0x2b,0x8e,0x95,0xc4,0x4a,0x66,0xa5,0xb0, +0xd2,0x58,0x19,0x2c,0x2e,0x8b,0x6f,0x45,0x08,0x11,0x5b,0x29,0x62,0xc9,0x58,0x0a, +0x96,0x8a,0xa5,0x65,0x19,0x58,0xd5,0xac,0x1a,0x56,0x3d,0xab,0x11,0xd2,0x0c,0x69, +0xb5,0xd2,0xce,0xea,0xc4,0xb8,0xc1,0xea,0x65,0xf5,0xb1,0x06,0x58,0xf7,0x58,0xf7, +0x59,0x0f,0x58,0x0f,0x59,0x8f,0x58,0x8f,0x59,0x13,0xac,0x27,0xac,0xa7,0xac,0x19, +0xd6,0x1c,0xeb,0x39,0x6b,0x91,0xf5,0x82,0xf5,0x92,0xf5,0x8a,0x05,0x62,0x6c,0x62, +0xec,0x62,0xec,0x63,0x08,0x31,0xce,0x31,0xae,0x31,0xee,0x31,0x9e,0x31,0xde,0x31, +0x3e,0x31,0x7e,0x31,0xe4,0x18,0x6a,0x4c,0x60,0x4c,0x70,0x4c,0x68,0x4c,0x78,0x4c, +0x64,0x0c,0x33,0x26,0x2e,0x26,0x29,0x26,0x39,0x26,0x25,0x26,0x2d,0x26,0x23,0x86, +0x1b,0xc3,0x8f,0x11,0xc6,0x88,0x63,0x8a,0x62,0x64,0x31,0x8a,0x18,0x55,0x8c,0x36, +0xc6,0x10,0x53,0x1d,0x53,0x13,0x53,0x1f,0xd3,0x18,0xd3,0x1c,0xd3,0x1a,0xd3,0x1e, +0xd3,0x19,0x73,0x23,0xa6,0x37,0xa6,0x2f,0x66,0xc0,0xca,0xbd,0x98,0xfb,0x31,0x0f, +0x62,0x1e,0xc6,0x3c,0x8a,0x79,0x1c,0x33,0x11,0xf3,0x24,0xe6,0x69,0xcc,0x4c,0xcc, +0x5c,0xcc,0xf3,0x98,0xc5,0x98,0x17,0x31,0x2f,0x63,0x5e,0xc5,0x80,0x58,0x9b,0x58, +0xbb,0x58,0xfb,0x58,0x42,0xac,0x73,0xac,0x6b,0xac,0x7b,0xac,0x67,0xac,0x77,0xac, +0x4f,0xac,0x5f,0x2c,0x39,0x96,0x1a,0x1b,0x18,0x1b,0x1c,0x1b,0x1a,0x1b,0x1e,0x1b, +0x19,0xcb,0x8c,0x8d,0x8b,0x4d,0x8a,0x4d,0x8e,0x4d,0x89,0x4d,0x8b,0xcd,0x88,0xe5, +0xc6,0xf2,0x63,0x85,0xb1,0xe2,0xd8,0xa2,0x58,0x59,0xac,0x22,0x56,0x15,0xab,0x8d, +0x35,0xc4,0x56,0xc7,0xd6,0xc4,0xd6,0xc7,0x36,0xc6,0x36,0xc7,0xb6,0xc6,0xb6,0xc7, +0x76,0xc6,0xde,0x88,0xed,0x8d,0xed,0x8b,0x1d,0x88,0xbd,0x17,0x7b,0x3f,0xf6,0x41, +0xec,0xc3,0xd8,0x47,0xb1,0x8f,0x63,0x27,0x62,0x9f,0xc4,0x3e,0x8d,0x9d,0x89,0x9d, +0x8b,0x7d,0x1e,0xbb,0x18,0xfb,0x22,0xf6,0x65,0xec,0xab,0x58,0x10,0x67,0x13,0x67, +0x17,0x67,0x1f,0x47,0x88,0x73,0x8e,0x73,0x8d,0x73,0x8f,0xf3,0x8c,0xf3,0x8e,0xf3, +0x89,0xf3,0x8b,0x23,0xc7,0x51,0xe3,0x02,0xe3,0x82,0xe3,0x42,0xe3,0xc2,0xe3,0x22, +0xe3,0x98,0x71,0x71,0x71,0x49,0x71,0xc9,0x71,0x29,0x71,0x69,0x71,0x19,0xbf,0x22, +0x99,0x10,0x41,0x9c,0x24,0x4e,0x1e,0xa7,0x8b,0xab,0x8d,0x6b,0x8a,0x6b,0xfd,0x03, +0xb4,0xc5,0x75,0xc5,0x99,0xe3,0x06,0xe3,0x86,0xe3,0x1e,0xbe,0xc1,0x63,0xc8,0x54, +0xdc,0x74,0x9c,0x25,0x6e,0x3e,0x6e,0x21,0x6e,0x29,0x6e,0x39,0x6e,0x25,0x6e,0x35, +0x0e,0x17,0x6f,0x13,0x6f,0x1f,0xef,0x1c,0xef,0x19,0xef,0x17,0x4f,0x8d,0x0f,0x8e, +0x0f,0x8f,0x67,0xc6,0x27,0xc5,0xa7,0xc4,0x67,0xc4,0xf3,0xe3,0xc5,0x10,0x59,0xbc, +0x2a,0xde,0x10,0x5f,0x13,0xdf,0x08,0x69,0x85,0x74,0xc6,0xf7,0x42,0x06,0xe2,0xef, +0x43,0x1e,0xc6,0x3f,0x8e,0x7f,0x12,0x3f,0x13,0xff,0x3c,0xfe,0x45,0xfc,0xab,0x78, +0x9b,0x04,0x87,0x04,0x97,0x04,0xb7,0x04,0x8f,0x04,0xaf,0x04,0x62,0x82,0x6f,0x02, +0x29,0x81,0x92,0x40,0x4b,0xa0,0x27,0x84,0x24,0x84,0x25,0x44,0x24,0x30,0x12,0x58, +0x09,0xf1,0x09,0xec,0x04,0x4e,0x42,0x6a,0x42,0x7a,0x42,0x66,0x02,0x2f,0x41,0x90, +0x20,0x4a,0x90,0x24,0x48,0x13,0xe4,0x09,0xca,0x04,0x75,0x82,0x2e,0xc1,0x98,0x60, +0x4a,0xa8,0x4d,0x68,0x48,0x68,0x4a,0x68,0x49,0x68,0x4b,0xe8,0x48,0xe8,0x4a,0xe8, +0x4e,0x30,0x27,0xf4,0x27,0x0c,0x26,0x0c,0x25,0x0c,0x27,0x8c,0x24,0x8c,0x26,0x8c, +0x25,0x8c,0x27,0x4c,0x26,0x4c,0x25,0x4c,0x27,0x58,0x12,0xe6,0x13,0x16,0x12,0x96, +0x12,0x96,0x13,0x56,0x12,0x56,0x13,0x70,0x89,0xb6,0x89,0xf8,0x44,0x87,0x44,0xa7, +0x44,0x97,0x44,0xb7,0x44,0x8f,0x44,0xaf,0x44,0x62,0xa2,0x6f,0x22,0x29,0x91,0x92, +0x48,0x4b,0xa4,0x27,0x86,0x24,0x86,0x25,0x46,0x24,0x32,0x12,0x59,0x89,0xf1,0x89, +0xec,0x44,0x4e,0x62,0x6a,0x62,0x7a,0x62,0x66,0xa2,0x20,0x51,0x92,0x28,0x4d,0x94, +0x27,0x2a,0x13,0xd5,0x89,0xba,0x44,0x63,0xa2,0x29,0xb1,0x36,0xb1,0x21,0xb1,0x29, +0xb1,0x2d,0xb1,0xf3,0xaf,0xa6,0x2b,0xb1,0x3b,0xd1,0x9c,0xd8,0x9f,0x38,0x98,0x38, +0x94,0x38,0x9c,0x38,0x92,0x38,0x9a,0x38,0x96,0x38,0x9e,0x38,0x95,0x38,0x9d,0x68, +0x49,0x9c,0x4f,0x5c,0x48,0x5c,0x4a,0x5c,0x4e,0x5c,0x49,0x5c,0x4d,0xc4,0x25,0xd9, +0x26,0xe1,0x93,0x1c,0x92,0xdc,0x92,0x88,0x49,0x94,0xa4,0x90,0x24,0x46,0x12,0x3b, +0x29,0x3d,0x49,0x90,0x24,0x4d,0x52,0x27,0x99,0x92,0x9a,0x92,0x3a,0x92,0xcc,0x49, +0x43,0x49,0xa3,0x49,0x93,0x49,0x96,0xa4,0xf9,0xa4,0x85,0xa4,0xa5,0xa4,0x65,0x08, +0x8e,0xed,0xc0,0x76,0x63,0x13,0xd9,0x14,0x36,0x9d,0x1d,0xc6,0x66,0xb0,0xe3,0xd9, +0x1c,0x76,0x3a,0x9b,0xc7,0x16,0xb1,0xa5,0x6c,0x25,0x5b,0xc7,0x36,0xb1,0x1b,0xd8, +0x2d,0xec,0x0e,0x76,0x37,0xbb,0x9f,0x3d,0xc4,0x1e,0x61,0x8f,0xb1,0x27,0xd9,0xd3, +0xec,0x79,0xf6,0x12,0x7b,0x85,0x8d,0x3b,0x81,0x3f,0xe1,0x74,0xc2,0xed,0x84,0xd7, +0x09,0xdf,0x13,0x94,0x13,0xf4,0x13,0x61,0x27,0x18,0x27,0xe2,0x4f,0x70,0x4e,0xa4, +0x9f,0xe0,0x9d,0x10,0x9d,0x90,0x9e,0x50,0x9e,0xd0,0x9d,0x30,0x9d,0x68,0x38,0xd1, +0x72,0xa2,0xe3,0x44,0xf7,0x89,0xfe,0x13,0x43,0x27,0x46,0x4e,0x8c,0x9d,0x98,0x3c, +0x31,0x7d,0x62,0xfe,0xc4,0xd2,0x89,0x95,0x13,0xb8,0x93,0xf8,0x93,0x4e,0x27,0xdd, +0x4e,0x7a,0x9d,0xf4,0x3d,0x49,0x39,0x49,0x3f,0x19,0x76,0x92,0x71,0x32,0xfe,0x24, +0xe7,0x64,0xfa,0x49,0xde,0x49,0xd1,0x49,0xe9,0x49,0xe5,0x49,0xdd,0x49,0xd3,0xc9, +0x86,0x93,0x2d,0x27,0x3b,0x4e,0x76,0x9f,0xec,0x3f,0x39,0x74,0x72,0xe4,0xe4,0xd8, +0xc9,0xc9,0x93,0xd3,0x27,0xe7,0x4f,0x2e,0x9d,0x5c,0x39,0x69,0x9b,0xec,0x94,0xec, +0x91,0xec,0x9b,0x4c,0x4b,0x0e,0x4b,0x66,0x25,0x73,0x92,0x33,0x93,0x45,0xc9,0xf2, +0x64,0x5d,0xb2,0x29,0xb9,0x21,0xb9,0x25,0xb9,0x23,0xb9,0x3b,0xb9,0x3f,0x79,0x28, +0x79,0x24,0x79,0x2c,0x79,0x32,0x79,0x3a,0x79,0x3e,0x79,0x29,0x79,0x25,0x19,0xc7, +0xc1,0x73,0x9c,0x38,0x6e,0x1c,0x2f,0x8e,0x2f,0x87,0xc2,0xa1,0x73,0xc2,0x38,0x0c, +0x4e,0x3c,0x87,0xc3,0x49,0xe7,0xf0,0x38,0x22,0x8e,0x94,0xa3,0xe4,0xe8,0x38,0x26, +0x4e,0x03,0xa7,0x85,0xd3,0xc1,0xe9,0xe6,0xf4,0x73,0x86,0x38,0x23,0x9c,0x31,0xce, +0x24,0x67,0x9a,0x33,0xcf,0x59,0xe2,0xac,0x72,0xf0,0xa7,0x5c,0x4e,0x79,0x9d,0x22, +0x9d,0xa2,0x9d,0x0a,0x39,0x15,0x71,0x8a,0x75,0x8a,0x7d,0x2a,0xf5,0x54,0xe6,0x29, +0xc1,0x29,0xc9,0x29,0xf9,0x29,0xf5,0x29,0xe3,0xa9,0xda,0x53,0x4d,0xa7,0xda,0x4e, +0x75,0x9d,0x32,0x9f,0x1a,0x3c,0x35,0x7c,0x6a,0xf4,0xd4,0xf8,0xa9,0xa9,0x53,0x96, +0x53,0x0b,0xa7,0x96,0x4f,0xad,0x9e,0xb2,0x3d,0xed,0x70,0xda,0xe5,0xb4,0xc7,0x69, +0xe2,0x69,0xd2,0x69,0xda,0xe9,0x90,0xd3,0x11,0xa7,0x59,0xa7,0xd9,0xa7,0x53,0x4f, +0x67,0x9e,0x16,0x9c,0x96,0x9c,0x96,0x9f,0x56,0x9f,0x36,0x9e,0xae,0x3d,0xdd,0x74, +0xba,0xed,0x74,0xd7,0x69,0xf3,0xe9,0xc1,0xd3,0xc3,0xa7,0x47,0x4f,0x8f,0x9f,0x9e, +0x3a,0x6d,0x39,0xbd,0x70,0x7a,0xf9,0xf4,0xea,0x69,0xdb,0x14,0x87,0x14,0x97,0x14, +0x8f,0x14,0x62,0x0a,0x29,0x85,0x96,0x12,0x92,0x12,0x91,0x12,0x9f,0x92,0x9a,0x92, +0x99,0x22,0x48,0x91,0xa4,0xc8,0x53,0xd4,0x29,0xc6,0x94,0xda,0x94,0xa6,0x94,0xb6, +0x94,0xae,0x14,0x73,0xca,0x60,0xca,0x70,0xca,0x68,0xca,0x78,0xca,0x54,0x8a,0x25, +0x65,0x29,0x65,0x35,0x05,0x9f,0xea,0x94,0xea,0x96,0xea,0x95,0xea,0x9b,0x4a,0x49, +0xa5,0xa7,0x86,0xa5,0x32,0x52,0xe3,0x53,0x39,0xa9,0xe9,0x10,0x5e,0xaa,0x28,0x55, +0x9a,0xaa,0x4c,0xd5,0xa5,0x9a,0x52,0x1b,0x52,0x5b,0x52,0x3b,0x52,0xbb,0x53,0xfb, +0x53,0x87,0x52,0x47,0x52,0xc7,0x52,0x27,0x53,0xa7,0x53,0xe7,0x53,0x97,0x52,0x57, +0x52,0x71,0x67,0xf0,0x67,0x9c,0xce,0xb8,0x9d,0xf1,0x3a,0xe3,0x7b,0x86,0x72,0x86, +0x7e,0x26,0xec,0x0c,0xe3,0x4c,0xfc,0x19,0xce,0x99,0xf4,0x33,0xbc,0x33,0xa2,0x33, +0xd2,0x33,0xca,0x33,0xba,0x33,0xa6,0x33,0x0d,0x67,0x5a,0xce,0x74,0x9c,0xe9,0x3e, +0xd3,0x7f,0x66,0xe8,0xcc,0xc8,0x99,0xb1,0x33,0x93,0x67,0xa6,0xcf,0xcc,0x9f,0x59, +0x3a,0xb3,0x72,0x06,0x77,0x16,0x7f,0xd6,0xe9,0xac,0xdb,0x59,0xaf,0xb3,0xbe,0x67, +0x29,0x67,0xe9,0x67,0xc3,0xce,0x32,0xce,0xc6,0xfd,0x09,0xc4,0x9f,0x4d,0x3d,0xcb, +0x3b,0x2b,0x39,0xab,0x3c,0x6b,0x3c,0xdb,0x70,0xb6,0xed,0x6c,0xf7,0xd9,0xc1,0xb3, +0x23,0x67,0xc7,0xcf,0x4e,0x9f,0x5d,0x38,0xbb,0x72,0xd6,0x36,0xcd,0x29,0xcd,0x23, +0xcd,0x37,0x8d,0x96,0x16,0x96,0xc6,0x4a,0xe3,0xa4,0x65,0xa6,0x89,0xd2,0xe4,0x69, +0xba,0xb4,0xda,0xb4,0x96,0xb4,0xae,0xb4,0xfe,0xb4,0xe1,0xb4,0xb1,0xb4,0xa9,0xb4, +0xf9,0xb4,0xe5,0x34,0x5c,0xba,0x43,0xba,0x5b,0x3a,0x31,0x9d,0x92,0x1e,0x92,0xce, +0x48,0x67,0xa7,0xa7,0xa7,0x0b,0xd2,0xa5,0xe9,0xea,0x74,0x53,0x7a,0x53,0x7a,0x47, +0xba,0x39,0x7d,0x28,0x7d,0x34,0x7d,0x32,0xdd,0x92,0xbe,0x94,0xbe,0x9a,0x8e,0xff, +0xc8,0xe5,0x23,0xaf,0x8f,0x48,0x1f,0xd1,0x3f,0x8a,0xf8,0x28,0x0e,0x12,0xff,0x51, +0xea,0x47,0xbc,0x8f,0x24,0x1f,0x29,0x3f,0x32,0x7e,0xd4,0xf0,0x51,0xdb,0x47,0xdd, +0x1f,0x0d,0x7e,0x34,0xf2,0xd1,0xf8,0x47,0xd3,0x1f,0x2d,0x7c,0xb4,0xf2,0x91,0xed, +0xc7,0x4e,0x1f,0x7b,0x7c,0xec,0xfb,0x31,0xed,0xe3,0xb0,0x8f,0x59,0x1f,0x73,0x3e, +0xce,0xfc,0x58,0xf4,0xb1,0xfc,0x63,0xdd,0xc7,0xb5,0x1f,0xb7,0x7c,0xdc,0xf5,0x71, +0xff,0xc7,0xc3,0x1f,0x8f,0x7d,0x3c,0xf5,0xf1,0xfc,0xc7,0xcb,0x1f,0xe3,0x32,0x1c, +0x32,0xdc,0x32,0x88,0x19,0x94,0x8c,0x90,0x0c,0x46,0x06,0x3b,0x23,0x3d,0x43,0x90, +0x21,0xcd,0x50,0x67,0x98,0x32,0x9a,0x32,0x3a,0x32,0xcc,0x19,0x43,0x19,0xa3,0x19, +0x13,0xbf,0x32,0x93,0x19,0x96,0x8c,0xa5,0x0c,0x5c,0xa6,0x53,0xa6,0x57,0x26,0x25, +0x33,0x2c,0x33,0x3e,0x33,0x3d,0x53,0x90,0x69,0xce,0x1c,0xcf,0x9c,0xf9,0x13,0xb1, +0x64,0xce,0x67,0x2e,0x64,0x2e,0x65,0x2e,0x67,0xae,0x64,0xae,0x66,0xe2,0xb2,0x6c, +0xb3,0xf0,0x59,0xce,0x7f,0x06,0x2e,0x59,0x1e,0x59,0x5e,0x59,0xc4,0x2c,0xdf,0x2c, +0x52,0x16,0x25,0x8b,0x96,0x45,0xcf,0x0a,0xc9,0x0a,0xcb,0x8a,0xc8,0x62,0x64,0xb1, +0xb2,0xe2,0xb3,0xd8,0x59,0x9c,0xac,0xd4,0xac,0xf4,0xac,0xcc,0x2c,0x5e,0x16,0x1f, +0x22,0xc8,0x12,0x65,0x49,0xb2,0xe4,0x59,0xea,0x2c,0x63,0x56,0x6d,0x56,0x43,0x56, +0x53,0x56,0x4b,0x56,0x5b,0x56,0x47,0x56,0x67,0x56,0x57,0x56,0x77,0x96,0x39,0xab, +0x3f,0x6b,0x30,0x6b,0x28,0x6b,0x38,0x6b,0x24,0x6b,0x34,0x6b,0x2c,0x6b,0x3c,0x6b, +0x32,0x6b,0x2a,0x6b,0x3a,0xcb,0x92,0x35,0x9f,0xb5,0x90,0xb5,0x94,0xb5,0x9c,0xf5, +0x32,0x6b,0x25,0x6b,0x35,0x0b,0x77,0xce,0xf6,0x9c,0x1d,0x06,0xfe,0x9c,0xd3,0x39, +0xb7,0x73,0x9e,0xe7,0xbc,0xce,0xf9,0x9c,0xf3,0x3d,0x47,0x39,0x47,0x3f,0x17,0x76, +0x8e,0x71,0x2e,0xfe,0x1c,0xe7,0x5c,0xfa,0x39,0xde,0x39,0xd1,0x39,0xe9,0x39,0xf9, +0x39,0xf5,0x39,0xe3,0xb9,0xda,0x73,0x4d,0xe7,0xda,0xce,0x75,0x9d,0x33,0x9f,0x1b, +0x3c,0x37,0x7c,0x6e,0xf4,0xdc,0xf8,0xb9,0xa9,0x73,0xd3,0xe7,0x2c,0xe7,0xe6,0xcf, +0x2d,0x9c,0x5b,0x3a,0xb7,0x7c,0x6e,0xe5,0xdc,0xea,0x39,0x1c,0xd7,0x96,0x8b,0xe7, +0x3a,0x70,0x9d,0xb8,0x2e,0x5c,0x37,0xae,0x07,0xd7,0x8b,0x4b,0xe4,0xfa,0x72,0x49, +0x5c,0x0a,0x97,0xc6,0xa5,0x73,0x43,0xb8,0x61,0xdc,0x08,0x2e,0x83,0xcb,0xe2,0xc6, +0x73,0xd9,0x5c,0x0e,0x37,0x95,0x9b,0xce,0xcd,0xe4,0xf2,0xb8,0x02,0xae,0x88,0x2b, +0xe1,0x4a,0xb9,0x72,0xae,0x92,0xab,0xe6,0xea,0xb8,0x46,0xae,0x89,0x5b,0xcb,0x6d, +0xe0,0x36,0x71,0x5b,0xb8,0x6d,0xdc,0x0e,0x6e,0x17,0xb7,0x9b,0x6b,0xe6,0xf6,0x73, +0x07,0xb9,0x43,0xdc,0x61,0xee,0x08,0x77,0x94,0x3b,0xc6,0x1d,0xe7,0x4e,0x72,0xa7, +0xb8,0xd3,0x5c,0x0b,0x77,0x9e,0xbb,0xc0,0x5d,0xe2,0x2e,0x73,0x57,0xb8,0xab,0x5c, +0x1c,0xcf,0x96,0x87,0xe7,0x39,0xf0,0x9c,0x78,0x2e,0x3c,0x37,0x9e,0x07,0xcf,0x8b, +0x47,0xe4,0xf9,0xf2,0x48,0x3c,0x0a,0x8f,0xc6,0xa3,0xf3,0x42,0x78,0x61,0xbc,0x08, +0x1e,0x83,0xc7,0xe2,0xc5,0xf3,0xd8,0x3c,0x0e,0x2f,0x95,0x97,0xce,0xcb,0xe4,0xf1, +0x78,0x02,0x9e,0x88,0x27,0xe1,0x49,0x79,0x72,0x9e,0x8e,0x57,0xcb,0x6b,0xe1,0x75, +0xf1,0xfa,0x79,0xc3,0xbc,0x51,0xde,0xe3,0x5f,0x18,0xe7,0x4d,0xf2,0xa6,0x78,0xd3, +0x3c,0x0b,0x6f,0x9e,0xb7,0xc0,0x5b,0xe2,0x2d,0xf3,0x56,0x78,0xab,0x3c,0x5c,0xb6, +0x6d,0x36,0x3e,0xdb,0x21,0xdb,0x29,0xdb,0x25,0xdb,0x2d,0xdb,0x23,0xdb,0x2b,0x9b, +0x98,0xed,0x9b,0x4d,0xca,0xa6,0x64,0xd3,0xb2,0xe9,0xd9,0x21,0xd9,0x61,0xd9,0x11, +0xd9,0x8c,0x6c,0x56,0x76,0x7c,0x36,0x3b,0x9b,0x93,0x9d,0x9a,0x9d,0x9e,0x9d,0x99, +0xcd,0xcb,0x16,0x64,0x8b,0xb2,0x25,0xd9,0xd2,0x6c,0x79,0xb6,0x32,0x5b,0x9d,0xad, +0xcb,0x36,0x66,0x9b,0xb2,0x6b,0xb3,0x1b,0xb2,0x9b,0xb2,0x5b,0xb2,0xdb,0xb2,0x3b, +0xb2,0xbb,0xb2,0xbb,0xb3,0xcd,0xd9,0xfd,0xd9,0x83,0xd9,0x43,0xd9,0xc3,0xd9,0x23, +0xd9,0xa3,0xd9,0x63,0xd9,0xe3,0xd9,0x93,0xd9,0x53,0xd9,0xd3,0xd9,0x96,0xec,0xf9, +0xec,0x85,0xec,0xa5,0xec,0xe5,0xec,0x95,0xec,0xd5,0x6c,0x5c,0x8e,0x6d,0x0e,0x3e, +0xc7,0x21,0xc7,0x29,0xc7,0x25,0xc7,0x2d,0xc7,0x23,0xc7,0x2b,0x87,0x98,0xe3,0x9b, +0x43,0xca,0xa1,0xe4,0xd0,0x72,0xe8,0x39,0x21,0x39,0x61,0x39,0x11,0x39,0x8c,0x1c, +0x56,0x4e,0x7c,0x0e,0x3b,0x87,0x93,0x93,0x9a,0x93,0x9e,0x93,0x99,0xc3,0xcb,0x11, +0xe4,0x88,0x72,0x24,0x39,0xd2,0x1c,0x79,0x8e,0x32,0x47,0x9d,0xa3,0xcb,0x31,0xe6, +0x98,0x72,0x6a,0x73,0x1a,0x72,0x9a,0x72,0x5a,0x72,0xda,0x72,0x3a,0x72,0xba,0x72, +0xba,0x73,0xcc,0x39,0xfd,0x39,0x83,0x39,0x43,0x39,0xc3,0x39,0x23,0x39,0xa3,0x39, +0x63,0x39,0xe3,0x39,0x93,0x39,0x53,0x39,0xd3,0x39,0x96,0x9c,0xf9,0x9c,0x85,0x9c, +0xa5,0x9c,0xe5,0x9c,0x95,0x9c,0xd5,0x1c,0x1c,0xdf,0x96,0x8f,0xe7,0x3b,0xf0,0x9d, +0xf8,0x2e,0x7c,0x37,0xbe,0x07,0xdf,0x8b,0x4f,0xe4,0xfb,0xf2,0x49,0x7c,0x0a,0x9f, +0xc6,0xa7,0xf3,0x43,0xf8,0x61,0xfc,0x08,0x3e,0x03,0xbe,0x28,0xc7,0xf3,0xd9,0x7c, +0x0e,0x3f,0x95,0x9f,0xce,0xcf,0xe4,0xf3,0xf8,0x02,0xbe,0x88,0x2f,0xe1,0x4b,0xf9, +0x72,0xbe,0x92,0xaf,0xe6,0xeb,0xf8,0x46,0xbe,0x89,0x5f,0xcb,0x6f,0xe0,0x37,0xf1, +0x5b,0xf8,0x6d,0xfc,0x0e,0x7e,0x17,0xbf,0x9b,0x6f,0xe6,0xf7,0xf3,0x07,0xf9,0x43, +0xfc,0x61,0xfe,0x08,0xff,0xa1,0x95,0x51,0xfe,0x18,0x7f,0x9c,0x3f,0xc9,0x9f,0xe2, +0x4f,0xf3,0x67,0x20,0x16,0xfe,0x3c,0x7f,0x81,0xbf,0xc4,0x5f,0xe6,0xaf,0xf0,0x5f, +0x41,0x56,0xf9,0x38,0x81,0xad,0x00,0x2f,0x70,0x10,0x38,0x09,0x9c,0x21,0x2e,0x02, +0x37,0x81,0x87,0xc0,0xd3,0x8a,0x97,0x80,0x28,0xf0,0x15,0x90,0x04,0x34,0x01,0x5d, +0x10,0x22,0x08,0x15,0x84,0x09,0x22,0x04,0x0c,0x01,0x4b,0x10,0x2f,0x60,0x0b,0x38, +0x82,0x94,0x75,0xfe,0x04,0x52,0x05,0xe9,0x82,0x4c,0x01,0x4f,0x20,0x10,0x08,0x05, +0x22,0x81,0x44,0x20,0x15,0xc8,0x05,0x4a,0x81,0x5a,0xa0,0x13,0x18,0x05,0x26,0x41, +0xad,0xa0,0x41,0xd0,0x24,0x68,0x11,0xb4,0x09,0x3a,0x04,0x5d,0x82,0x6e,0x81,0x59, +0xd0,0x2f,0x18,0x14,0x0c,0x09,0x86,0x05,0x23,0x82,0x51,0xc1,0x98,0x60,0x5c,0x30, +0x29,0x98,0x12,0x4c,0x0b,0x2c,0x82,0x79,0xc1,0x82,0x60,0x49,0xb0,0x2c,0x58,0x11, +0xac,0x0a,0x70,0xe7,0x6d,0xcf,0xe3,0xcf,0x3b,0x9c,0x77,0x3a,0xef,0x72,0xde,0xf5, +0xbc,0xdb,0x79,0x8f,0xf3,0x5e,0xe7,0x89,0xe7,0x7d,0xcf,0x93,0xce,0x53,0xce,0xd3, +0xce,0xd3,0xcf,0x07,0xaf,0xf3,0x4f,0x4e,0x38,0x84,0xf9,0x3f,0x92,0xb4,0x8e,0x95, +0x94,0xf3,0x19,0xeb,0xac,0xf3,0x17,0xc1,0x3f,0x2f,0x5e,0x67,0x9d,0x7f,0x61,0x64, +0xe7,0x55,0x10,0xc3,0x3a,0xff,0xa6,0xd4,0x9c,0x6f,0xfc,0x37,0xa6,0x75,0x9d,0x75, +0x7e,0x35,0x3a,0xcf,0xf7,0x9e,0xbf,0x77,0xfe,0xe1,0xf9,0x89,0xf3,0x33,0xe7,0x17, +0xff,0xa9,0x78,0x79,0x1e,0xe4,0xda,0xe7,0xba,0xe6,0x7a,0xe7,0x92,0xd7,0x59,0xe7, +0xff,0x22,0x14,0x08,0x2d,0x97,0x9e,0x1b,0x92,0x1b,0x96,0x1b,0x91,0xcb,0xc8,0x65, +0xe5,0xc6,0xe7,0xb2,0x73,0x39,0xb9,0xa9,0xb9,0xe9,0xb9,0x99,0xb9,0xbc,0x5c,0x41, +0xae,0x28,0x57,0x92,0x2b,0xcd,0x95,0xe7,0x2a,0x73,0xd5,0xb9,0xba,0x5c,0x63,0xae, +0x29,0xb7,0x36,0xb7,0x21,0xb7,0x29,0xb7,0x25,0xb7,0x2d,0xb7,0x23,0xb7,0x2b,0xb7, +0x3b,0xd7,0x9c,0xdb,0x9f,0x3b,0x98,0x3b,0x94,0x3b,0x9c,0x3b,0x92,0x3b,0x9a,0x3b, +0x96,0x3b,0x9e,0x3b,0x99,0x3b,0x95,0x3b,0x9d,0x6b,0xc9,0x9d,0xcf,0x5d,0xc8,0x5d, +0xca,0x5d,0xce,0x5d,0xc9,0x5d,0xcd,0xc5,0x09,0x6d,0x85,0x78,0xa1,0x83,0xd0,0x49, +0xe8,0x22,0x74,0x13,0x7a,0x08,0xbd,0x84,0x44,0xa1,0xaf,0x90,0x24,0xa4,0x08,0x69, +0x42,0xba,0x30,0x44,0x18,0x26,0x8c,0x10,0x32,0x84,0x2c,0x61,0xbc,0x90,0x2d,0xe4, +0x08,0x53,0x85,0xe9,0xc2,0x4c,0x21,0x4f,0x28,0x10,0x8a,0x84,0x12,0xa1,0x54,0x28, +0x17,0x2a,0x85,0x2a,0xa1,0x5a,0xa8,0x13,0x1a,0x85,0x26,0x61,0xad,0xb0,0x41,0xd8, +0x24,0x6c,0x11,0xb6,0x09,0x3b,0x84,0x5d,0xc2,0x6e,0xa1,0x59,0xd8,0x2f,0x1c,0x14, +0x0e,0x09,0x87,0x85,0x23,0xc2,0x51,0xe1,0x98,0x70,0x5c,0x38,0x29,0x9c,0x12,0x4e, +0x0b,0x2d,0xc2,0x79,0xe1,0x82,0x70,0x49,0xb8,0x2c,0x5c,0x11,0xae,0x0a,0x71,0x22, +0x5b,0x11,0x5e,0xe4,0x20,0x72,0x12,0xb9,0x88,0xdc,0x44,0x1e,0x22,0x2f,0x11,0x51, +0xe4,0x2b,0x22,0x89,0x28,0x22,0x9a,0x88,0x2e,0x0a,0x11,0x85,0x89,0x22,0x44,0x0c, +0x11,0x4b,0x14,0x2f,0x62,0x8b,0x38,0xa2,0x54,0x51,0xba,0x28,0x53,0xc4,0x13,0x09, +0x44,0x22,0x91,0x44,0x24,0x15,0xc9,0x45,0x4a,0x91,0x5a,0xa4,0x13,0x19,0x45,0x26, +0x51,0xad,0xa8,0x41,0xd4,0x24,0x6a,0x16,0xb5,0x88,0xda,0x44,0xed,0x90,0x0e,0x51, +0x27,0xa4,0x4b,0xd4,0x2d,0xea,0x85,0x98,0x45,0xfd,0xa2,0x41,0xd1,0x90,0xe8,0xbe, +0x68,0x58,0x34,0x22,0x1a,0x15,0x8d,0x89,0xc6,0x45,0x93,0xa2,0x29,0xd1,0xb4,0xc8, +0x22,0x9a,0x17,0x2d,0x88,0x96,0x44,0x2f,0x44,0xcb,0xa2,0x97,0xa2,0x15,0xd1,0xaa, +0x08,0x97,0x67,0x9b,0x87,0xcf,0x73,0xc8,0x73,0xca,0x73,0xce,0x73,0xc9,0x73,0xcb, +0xf3,0xc8,0xf3,0xca,0x23,0xe6,0xf9,0xe6,0x91,0xf2,0x28,0x79,0xb4,0x3c,0x7a,0x5e, +0x48,0x5e,0x58,0x5e,0x44,0x1e,0x23,0x8f,0x95,0x17,0x9f,0xc7,0xce,0xe3,0xe4,0xa5, +0xe6,0xa5,0xe7,0x65,0xe6,0xf1,0xf2,0x04,0x79,0xa2,0x3c,0x49,0x9e,0x34,0x4f,0x9e, +0xa7,0xcc,0x53,0xe7,0xe9,0xf2,0x8c,0x79,0xa6,0xbc,0xda,0xbc,0x86,0xbc,0xa6,0xbc, +0x96,0xbc,0xb6,0xbc,0x8e,0xbc,0xae,0xbc,0xee,0x3c,0x73,0x5e,0x7f,0xde,0x60,0xde, +0x50,0xde,0x70,0xde,0x48,0xde,0x68,0xde,0x58,0xde,0x78,0xde,0x64,0xde,0x54,0xde, +0x74,0x9e,0x25,0x6f,0x3e,0x6f,0x21,0x6f,0x29,0x6f,0x39,0x6f,0x25,0x6f,0x35,0x0f, +0x97,0x8f,0xcb,0xb7,0xcd,0xc7,0xe7,0x3b,0xe4,0x3b,0xe5,0xbb,0xe4,0xbb,0xe6,0xbb, +0xe5,0x7b,0xe4,0x7b,0xe5,0x13,0xf3,0x7d,0x20,0xbe,0xf9,0xa4,0x7c,0x4a,0x3e,0x2d, +0x9f,0x9e,0x1f,0x92,0x1f,0x96,0x1f,0x91,0x1f,0x99,0xcf,0xc8,0x67,0xe5,0xc7,0xe7, +0xb3,0xf3,0x39,0xf9,0xa9,0xf9,0xe9,0xf9,0x19,0xf9,0x99,0xf9,0xbc,0x7c,0x41,0xbe, +0x28,0x5f,0x92,0x2f,0xcd,0x97,0xe7,0x2b,0xf3,0xd5,0xf9,0xba,0x7c,0x63,0xbe,0x29, +0xbf,0x36,0xbf,0x21,0xbf,0x29,0xbf,0x25,0xbf,0x2d,0xbf,0x23,0xbf,0x2b,0xbf,0x3b, +0xdf,0x9c,0xdf,0x9f,0x3f,0x98,0x3f,0x94,0x3f,0x9c,0x3f,0x92,0x3f,0x9a,0x3f,0x96, +0xff,0x38,0x7f,0x3c,0x7f,0x32,0x7f,0x2a,0x7f,0x3a,0x7f,0x26,0xdf,0x92,0x3f,0x9f, +0xbf,0x90,0xbf,0x94,0xbf,0x9c,0xff,0x32,0x7f,0x25,0xff,0x95,0x95,0xd5,0x7c,0x9c, +0xd8,0x56,0x8c,0x17,0x3b,0x88,0x9d,0xc4,0x2e,0x62,0x57,0xb1,0x9b,0xd8,0x43,0xec, +0x25,0x26,0x8a,0x7d,0xc5,0x24,0x31,0x45,0x4c,0x13,0xd3,0xc5,0x21,0xe2,0x30,0x71, +0x84,0x98,0x21,0x66,0x89,0xe3,0xc5,0x6c,0x31,0x47,0x9c,0x2a,0x4e,0x17,0x67,0x8a, +0x79,0x62,0x81,0x58,0x24,0x96,0x88,0xa5,0x62,0xb9,0x58,0x29,0x56,0x8b,0x75,0x62, +0xa3,0xd8,0x24,0xae,0x15,0x37,0x88,0x9b,0xc4,0x2d,0xe2,0x36,0x71,0x87,0xb8,0x4b, +0xdc,0x2d,0x36,0x8b,0xfb,0xc5,0x83,0xe2,0x21,0xf1,0xb0,0x78,0x44,0x3c,0x2a,0x1e, +0x13,0x8f,0x8b,0x27,0xc5,0x53,0xe2,0x69,0xb1,0x45,0x3c,0x2f,0x5e,0x10,0x2f,0x89, +0x97,0xc5,0x2b,0xe2,0x55,0x31,0x4e,0x62,0x2b,0xc1,0x4b,0x1c,0x24,0x4e,0x12,0x17, +0x89,0x9b,0xc4,0x43,0xe2,0x25,0x21,0x4a,0x7c,0x25,0x24,0x09,0x45,0x42,0x93,0xd0, +0x25,0x21,0x92,0x30,0x49,0x84,0x84,0x21,0x61,0x49,0xe2,0x25,0x6c,0x09,0x47,0x92, +0x2a,0x49,0x97,0x64,0x4a,0x78,0x12,0x81,0x44,0x24,0x91,0x48,0xa4,0x12,0xb9,0x44, +0x29,0x51,0x4b,0x74,0x12,0xa3,0xc4,0x24,0xa9,0x95,0x34,0x48,0x9a,0x24,0x2d,0x92, +0x36,0x49,0x87,0xa4,0x4b,0xd2,0x2d,0x31,0x4b,0xfa,0x25,0x83,0x92,0x21,0xc9,0xb0, +0x64,0x44,0x32,0x2a,0x19,0x93,0x8c,0x4b,0x26,0x25,0x53,0x92,0x69,0x89,0x45,0x32, +0x2f,0x59,0x90,0x2c,0x49,0x96,0x25,0x2b,0x92,0x55,0x09,0xae,0xc0,0xb6,0x00,0x5f, +0xe0,0x50,0xe0,0x54,0xe0,0x52,0xe0,0x56,0xe0,0x51,0xe0,0x55,0x40,0x2c,0xf0,0x2d, +0x20,0x15,0x50,0x0a,0x68,0x05,0xf4,0x82,0x90,0x82,0xb0,0x82,0x88,0x02,0x46,0x01, +0xab,0x20,0xbe,0x80,0x5d,0xc0,0x29,0x48,0x2d,0x48,0x2f,0xc8,0x2c,0xe0,0x15,0x08, +0x0a,0x44,0x05,0x92,0x02,0x69,0x81,0xbc,0x40,0x59,0xa0,0x2e,0xd0,0x15,0x18,0x0b, +0x4c,0x05,0xb5,0x05,0x0d,0x05,0x4d,0x05,0x2d,0x05,0x6d,0x05,0x1d,0x05,0x5d,0x05, +0xdd,0x05,0xe6,0x82,0xfe,0x82,0xc1,0x82,0xa1,0x82,0xe1,0x82,0x91,0x82,0xd1,0x82, +0x31,0xc8,0x78,0xc1,0x64,0xc1,0x54,0xc1,0x74,0x81,0xa5,0x60,0xbe,0x60,0xa1,0x60, +0xa9,0x60,0xb9,0x60,0xa5,0x60,0xb5,0x00,0x57,0x68,0x5b,0x88,0x2f,0x74,0x28,0x74, +0x2a,0x74,0x29,0x74,0x2b,0xf4,0x28,0xf4,0x2a,0x24,0x16,0xfa,0x16,0x92,0x0a,0x29, +0x85,0xb4,0x42,0x7a,0x61,0x48,0x61,0x58,0x61,0x44,0x21,0xa3,0x90,0x55,0x18,0x5f, +0xc8,0x2e,0xe4,0x14,0xa6,0x16,0xa6,0x17,0x66,0x16,0xf2,0x0a,0x05,0x85,0xa2,0x42, +0x49,0xa1,0xb4,0x50,0x5e,0xa8,0x2c,0x54,0x17,0xea,0x0a,0x8d,0x85,0xa6,0xc2,0xda, +0xc2,0x86,0xc2,0xa6,0xc2,0x96,0xc2,0xb6,0xc2,0x8e,0xc2,0xae,0xc2,0xee,0x42,0x73, +0x61,0x7f,0xe1,0x60,0xe1,0x50,0xe1,0x70,0xe1,0x48,0xe1,0x68,0xe1,0x58,0xe1,0x78, +0xe1,0x64,0xe1,0x54,0xe1,0x74,0xa1,0xa5,0x70,0xbe,0x70,0xa1,0x70,0xa9,0x70,0xb9, +0x70,0xa5,0x70,0xb5,0x10,0x57,0x64,0x5b,0x84,0x2f,0x72,0x28,0x72,0x2a,0x72,0x29, +0x72,0x2b,0xf2,0x28,0xf2,0x2a,0x22,0x16,0xf9,0x16,0x91,0x8a,0x28,0x45,0xb4,0x22, +0x7a,0x51,0x48,0x51,0x58,0x51,0x44,0x11,0xa3,0x88,0x55,0x14,0x5f,0xc4,0x2e,0xe2, +0x14,0xa5,0x16,0xa5,0x17,0x65,0x16,0xf1,0x8a,0x04,0x45,0xa2,0x22,0x49,0x91,0xb4, +0x48,0x5e,0xa4,0x2c,0x52,0x17,0xe9,0x8a,0x8c,0x45,0xa6,0xa2,0xda,0xa2,0x86,0xa2, +0xa6,0xa2,0x96,0xa2,0xb6,0xa2,0x8e,0xa2,0xae,0xa2,0xee,0x22,0x73,0x51,0x7f,0xd1, +0x60,0xd1,0x50,0xd1,0x70,0xd1,0x48,0xd1,0x68,0xd1,0x58,0xd1,0x78,0xd1,0x64,0xd1, +0x54,0xd1,0x74,0x91,0xa5,0x68,0xbe,0x68,0xa1,0x68,0xa9,0x68,0xb9,0x68,0xa5,0x68, +0xb5,0x08,0x27,0xb5,0x95,0xe2,0xa5,0x0e,0x52,0x27,0xa9,0x8b,0xd4,0x4d,0xea,0x21, +0xf5,0x92,0x12,0xa5,0xbe,0x52,0x92,0x94,0x22,0xa5,0x49,0xe9,0xd2,0x10,0x69,0x98, +0x34,0x42,0xca,0x90,0xb2,0xa4,0xf1,0x52,0xb6,0x94,0x23,0x4d,0x95,0xa6,0x4b,0x33, +0xa5,0x5c,0x08,0x4f,0x2a,0x90,0x8a,0xa4,0x12,0xa9,0x54,0x2a,0x97,0x2a,0xa5,0x6a, +0xa9,0x4e,0x6a,0x94,0x9a,0xa4,0xb5,0xd2,0x06,0x69,0x93,0xb4,0x45,0xda,0x26,0xed, +0x90,0x76,0x49,0xbb,0xa5,0x66,0x69,0xbf,0x74,0x50,0x3a,0x24,0x1d,0x96,0x8e,0x48, +0x47,0xa5,0x63,0xd2,0x71,0xe9,0xa4,0x74,0x4a,0x3a,0x2d,0xb5,0x48,0xe7,0xa5,0x0b, +0xd2,0x25,0xe9,0xb2,0x74,0x45,0xba,0x2a,0xc5,0x15,0xdb,0x16,0xe3,0x8b,0x1d,0x8a, +0x9d,0x8a,0x5d,0x8a,0xdd,0x8a,0x3d,0x8a,0xbd,0x8a,0x89,0xc5,0xbe,0xc5,0xa4,0x62, +0x4a,0x31,0xad,0x98,0x5e,0x1c,0x52,0x1c,0x56,0x1c,0x51,0xcc,0x28,0x66,0x15,0xc7, +0x17,0xb3,0x8b,0x39,0xc5,0xa9,0xc5,0xe9,0xc5,0x99,0xc5,0xbc,0x62,0x41,0xb1,0xa8, +0x58,0x52,0x2c,0x2d,0x96,0x17,0x2b,0x8b,0xd5,0xc5,0xba,0x62,0x63,0xb1,0xa9,0xb8, +0xb6,0xb8,0xa1,0xb8,0xa9,0xb8,0xa5,0xb8,0xad,0xb8,0xa3,0xb8,0xab,0xb8,0xbb,0xd8, +0x5c,0xdc,0x5f,0x3c,0x58,0x3c,0x54,0x3c,0x5c,0x3c,0x02,0x19,0x2d,0x1e,0x2b,0x1e, +0x2f,0x9e,0x2c,0x9e,0x2a,0x9e,0x2e,0xb6,0x14,0xcf,0x17,0x2f,0x14,0x2f,0x15,0x2f, +0x17,0xaf,0x14,0xaf,0x16,0xe3,0x4a,0x6c,0x4b,0xf0,0x25,0x0e,0x25,0x4e,0x25,0x2e, +0x25,0x6e,0x25,0x1e,0x25,0x5e,0x25,0xc4,0x12,0xdf,0x12,0x52,0x09,0xa5,0x84,0x56, +0x42,0x2f,0x09,0x29,0x09,0x2b,0x89,0x28,0x61,0x94,0xb0,0x4a,0xe2,0x4b,0xd8,0x25, +0x9c,0x92,0xd4,0x92,0xf4,0x92,0xcc,0x12,0x5e,0x89,0xa0,0x44,0x54,0x22,0x29,0x91, +0x96,0xc8,0x4b,0x94,0x25,0xea,0x12,0x5d,0x89,0xb1,0xc4,0x54,0x52,0x5b,0xd2,0x50, +0xd2,0x54,0xd2,0x52,0xd2,0x56,0xd2,0x51,0xd2,0x55,0xd2,0x5d,0x62,0x2e,0xe9,0x2f, +0x19,0x2c,0x19,0x2a,0x19,0x2e,0x19,0x29,0x19,0x2d,0x19,0x2b,0x19,0x2f,0x99,0x2c, +0x99,0x2a,0x99,0x2e,0xb1,0x94,0xcc,0x97,0x2c,0x94,0x2c,0x95,0x2c,0x97,0xac,0x94, +0xac,0x96,0xe0,0x64,0xb6,0x32,0xbc,0xcc,0x41,0xe6,0x24,0x73,0x91,0xb9,0xc9,0x3c, +0x64,0x5e,0x32,0xa2,0xcc,0x57,0x46,0x92,0x51,0x64,0x34,0x19,0x5d,0x16,0x22,0x0b, +0x93,0x45,0xc8,0x18,0x32,0x96,0x2c,0x5e,0xc6,0x96,0x71,0x64,0xa9,0xb2,0x74,0x59, +0xa6,0x8c,0x27,0x13,0xc8,0x44,0x32,0x89,0x4c,0x2a,0x93,0xcb,0x94,0x32,0xb5,0x4c, +0x27,0x33,0xca,0x4c,0xb2,0x5a,0x59,0x83,0xac,0x49,0xd6,0x22,0x6b,0x93,0x75,0xc8, +0xba,0x64,0xdd,0x32,0xb3,0xac,0x5f,0x36,0x28,0x1b,0x92,0x0d,0xcb,0x46,0x64,0xa3, +0xb2,0x31,0xd9,0xb8,0x6c,0x52,0x36,0x25,0x9b,0x96,0x59,0x64,0xf3,0xb2,0x05,0xd9, +0x92,0x6c,0x59,0xb6,0x22,0x5b,0x95,0xe1,0xe4,0xb6,0x72,0xbc,0xdc,0x41,0xee,0x24, +0x77,0x91,0xbb,0xc9,0x3d,0xe4,0x5e,0x72,0xa2,0xdc,0x57,0x4e,0x92,0x53,0xe4,0x34, +0x39,0x5d,0x1e,0x22,0x0f,0x93,0x47,0xc8,0x19,0x72,0x96,0x3c,0x5e,0xce,0x96,0x73, +0xe4,0xa9,0xf2,0x74,0x79,0xa6,0x9c,0x27,0x17,0xc8,0x45,0x72,0x89,0x5c,0x2a,0x97, +0xcb,0x95,0x72,0xb5,0x5c,0x27,0x37,0xca,0x4d,0xf2,0x5a,0x79,0x83,0xbc,0x49,0xde, +0x22,0x6f,0x93,0x77,0xc8,0xbb,0xe4,0xdd,0x72,0xb3,0xbc,0x5f,0x3e,0x28,0x1f,0x92, +0x0f,0xcb,0x47,0xe4,0xa3,0xf2,0x31,0xf9,0xb8,0x7c,0x52,0x3e,0x25,0x9f,0x96,0x5b, +0xe4,0xf3,0xf2,0x05,0xf9,0x92,0x7c,0x59,0xfe,0x12,0xb2,0x22,0x5f,0x95,0xe3,0x4a, +0x6d,0x4b,0xf1,0xa5,0x0e,0xa5,0x4e,0xa5,0x2e,0xa5,0x6e,0xa5,0x1e,0xa5,0x5e,0xa5, +0xc4,0x52,0xdf,0x52,0x52,0x29,0xa5,0x94,0x56,0x4a,0x2f,0x0d,0x29,0x0d,0x2b,0x8d, +0x28,0x65,0x94,0xb2,0x4a,0xe3,0x4b,0xd9,0xa5,0x9c,0xd2,0xd4,0xd2,0xf4,0xd2,0xcc, +0x52,0x5e,0xa9,0xa0,0x54,0x54,0x2a,0x29,0x95,0x96,0xca,0x4b,0x95,0xa5,0xea,0x52, +0x5d,0xa9,0xb1,0xd4,0x54,0x5a,0x5b,0xda,0x50,0xda,0x54,0xda,0x52,0xda,0x56,0xda, +0x51,0xda,0x55,0xda,0x5d,0x6a,0x2e,0xed,0x2f,0x1d,0x2c,0xbd,0xf7,0x37,0x67,0xa8, +0x74,0xb8,0x74,0xa4,0x74,0xb4,0x74,0xac,0x74,0xbc,0x74,0xb2,0x74,0xaa,0x74,0xba, +0xd4,0x52,0x3a,0x5f,0xba,0x50,0xba,0x54,0xba,0x5c,0xba,0x52,0xba,0x5a,0x8a,0x2b, +0xb3,0x2d,0xc3,0x97,0x39,0x94,0x39,0x95,0xb9,0x94,0xb9,0x95,0x79,0x94,0x79,0x95, +0x11,0xcb,0x7c,0xcb,0x48,0x65,0x94,0x32,0x5a,0x19,0xbd,0x2c,0xa4,0x2c,0xac,0x2c, +0xa2,0x8c,0x51,0xc6,0x2a,0x8b,0x2f,0x63,0x97,0x71,0xca,0x52,0xcb,0xd2,0xcb,0x32, +0xcb,0x78,0x65,0x82,0x32,0x51,0x99,0xa4,0x4c,0x5a,0x26,0x2f,0x53,0x96,0xa9,0xcb, +0x74,0x65,0xc6,0x32,0x53,0x59,0x6d,0x59,0x43,0x59,0x53,0x59,0x4b,0x59,0x5b,0x59, +0x47,0x59,0x57,0x59,0x77,0x99,0xb9,0xac,0x6f,0x9d,0x75,0xd6,0xf9,0x23,0xf4,0x43, +0x06,0xcb,0x86,0xca,0x86,0xcb,0x1e,0x94,0x8d,0x94,0x8d,0x96,0x8d,0x95,0x8d,0x97, +0x4d,0x96,0x4d,0x95,0x4d,0x97,0x59,0xca,0xe6,0xcb,0x16,0xca,0x96,0xca,0x96,0xcb, +0x56,0xca,0x56,0xcb,0x70,0x0a,0x5b,0x05,0x5e,0xe1,0xa0,0x70,0x52,0xb8,0x28,0xdc, +0x14,0x1e,0x0a,0x2f,0x05,0x51,0xe1,0xab,0x20,0x29,0x28,0x0a,0xaa,0x82,0xa6,0xa0, +0x2b,0x82,0x15,0x21,0x8a,0x50,0x48,0x98,0x22,0x5c,0x11,0xa1,0x60,0x28,0x58,0x8a, +0x78,0x05,0x5b,0xc1,0x51,0xa4,0x2a,0xd2,0x15,0x99,0x0a,0x9e,0x82,0xaf,0x10,0x28, +0x44,0x0a,0x89,0x42,0xaa,0x90,0x29,0xe4,0x0a,0x85,0x42,0xa9,0x50,0xbd,0x81,0x5a, +0xa1,0xc5,0xd0,0x29,0x0c,0x0a,0xa3,0xa2,0x5a,0x61,0x52,0xd4,0x28,0x6a,0x15,0x0d, +0x8a,0x26,0x45,0xb3,0xa2,0x45,0xd1,0xa6,0x68,0x57,0x74,0x28,0x3a,0x21,0x5d,0x8a, +0x1b,0x8a,0x6e,0x45,0xaf,0xc2,0xac,0xe8,0x53,0xf4,0x2b,0x06,0x14,0x83,0x8a,0x7b, +0x8a,0x21,0xc5,0xb0,0xe2,0x81,0x62,0x44,0xf1,0x10,0x32,0xaa,0x18,0x53,0x8c,0x2b, +0x26,0x15,0x4f,0x14,0x53,0x8a,0x69,0x85,0x45,0x31,0xaf,0x58,0x50,0x2c,0x29,0x96, +0x15,0x2f,0x15,0x2b,0x8a,0x55,0x05,0x4e,0x69,0xab,0xb4,0x53,0xe2,0x95,0x0e,0x4a, +0x27,0xa5,0x8b,0xd2,0x55,0xe9,0xa6,0x74,0x57,0x7a,0x28,0xbd,0x94,0x44,0xa5,0xaf, +0x92,0xa4,0xa4,0x28,0x69,0x4a,0xba,0x32,0x44,0x19,0xa6,0x0c,0x57,0x46,0x28,0x19, +0x4a,0x96,0x32,0x5e,0xc9,0x56,0x72,0x94,0xa9,0xca,0x74,0x65,0xa6,0x92,0xa7,0x14, +0x28,0x45,0x4a,0x89,0x52,0xaa,0x94,0x2b,0x95,0x4a,0xb5,0x52,0xfb,0x0b,0x3a,0xa5, +0x51,0x69,0x52,0xd6,0x28,0x6b,0x95,0x0d,0xca,0x26,0x65,0x8b,0xb2,0x4d,0xd9,0xae, +0xec,0x50,0x76,0x29,0xbb,0x95,0x66,0x65,0xbf,0x72,0x50,0x39,0xa4,0x1c,0x56,0x8e, +0x28,0x47,0x95,0x63,0xca,0x71,0xe5,0xa4,0x72,0x4a,0x39,0xad,0xb4,0x28,0xe7,0x95, +0xcf,0xd7,0x59,0xe7,0x1f,0x82,0x05,0xc8,0xb2,0x72,0x55,0x69,0x5b,0xee,0x50,0xee, +0x52,0xee,0x51,0x4e,0x2c,0x27,0x95,0xd3,0xca,0x43,0xca,0xc3,0x7f,0x21,0xa2,0x3c, +0xbe,0x3c,0xb5,0x9c,0x57,0x2e,0x29,0x57,0x96,0x1b,0xcb,0x1b,0xca,0xdb,0xca,0xbb, +0xcb,0x07,0xcb,0x47,0xca,0xc7,0xcb,0xa7,0xcb,0x17,0xca,0x57,0xca,0x6d,0x2b,0x9c, +0x2a,0x3c,0x2a,0x7c,0x2b,0x68,0x15,0x61,0x15,0xac,0x0a,0x4e,0x45,0x66,0x85,0xa8, +0x42,0x5e,0xa1,0xab,0x30,0x56,0x98,0x2a,0x1a,0x2a,0x9a,0x2b,0x5a,0x2a,0xda,0x2a, +0x3a,0x2a,0xba,0x2a,0xba,0x2b,0xcc,0x15,0xfd,0x15,0x83,0x15,0x43,0x15,0xc3,0x15, +0x23,0x15,0xa3,0x15,0x63,0x15,0xe3,0x15,0x93,0x15,0x53,0x15,0xd3,0x15,0x96,0x8a, +0xf9,0x8a,0x85,0x8a,0xa5,0x8a,0xe5,0x8a,0x95,0x8a,0xd5,0x0a,0x9c,0xca,0x56,0x85, +0x57,0x39,0xa9,0xdc,0x54,0x5e,0x2a,0x5f,0x15,0x4d,0x15,0xfc,0x17,0x10,0xa2,0x8a, +0x50,0xb1,0x54,0x49,0xbf,0x0a,0x6c,0x55,0xca,0xbf,0x34,0xa9,0x90,0x4c,0x95,0x40, +0x25,0xfc,0x83,0x88,0x54,0x12,0x95,0x54,0x25,0x57,0xa9,0x55,0x3a,0x95,0x51,0x65, +0x52,0xd5,0xaa,0x1a,0x54,0x4d,0xaa,0x16,0x55,0x9b,0xaa,0x43,0xd5,0xa5,0xea,0x56, +0x99,0x55,0xfd,0xaa,0x41,0xd5,0x90,0x6a,0x58,0x35,0xa2,0x1a,0x55,0x8d,0xa9,0xc6, +0x55,0x93,0xaa,0x29,0xd5,0xb4,0xca,0xa2,0x9a,0x57,0x2d,0xa8,0x96,0x54,0xcb,0xaa, +0x15,0xd5,0xaa,0x0a,0xa7,0xb6,0x55,0xe3,0xd5,0x0e,0x6a,0x27,0xb5,0x8b,0xda,0x4d, +0xed,0xa1,0xf6,0x52,0x7b,0x63,0x10,0xd5,0x14,0x75,0x88,0x9a,0xa1,0x66,0xab,0xd3, +0xd5,0x02,0xb5,0x54,0xad,0x56,0x57,0xff,0x16,0x26,0x75,0xad,0xba,0x7e,0x9d,0x75, +0xd6,0xf9,0x0b,0x69,0x50,0x37,0xa9,0x5b,0xd4,0x6d,0xea,0x0e,0x75,0x97,0xba,0x5b, +0x6d,0x56,0xf7,0xab,0x07,0xd5,0xf7,0x7e,0x87,0xfb,0xea,0x07,0xea,0x87,0xea,0x47, +0xea,0xc7,0xea,0x09,0xf5,0x13,0xf5,0x53,0xf5,0x8c,0x7a,0x4e,0xfd,0x5c,0xbd,0xa8, +0x7e,0xa1,0x7e,0xa9,0x7e,0xa5,0x06,0x1a,0x1b,0x8d,0x9d,0xc6,0x5e,0x43,0xd0,0x38, +0x6b,0x5c,0x35,0xee,0x1a,0x4f,0x8d,0xb7,0xc6,0x47,0xe3,0xa7,0x21,0x6b,0xa8,0x9a, +0x40,0x4d,0xb0,0x26,0x54,0x13,0xae,0x89,0xd4,0x30,0x35,0x71,0x9a,0x24,0x4d,0xb2, +0x26,0x45,0x93,0xa6,0xc9,0xd0,0x70,0x35,0x7c,0x8d,0x50,0x23,0xd6,0x14,0x69,0x64, +0x1a,0x85,0x46,0xa5,0xd1,0x6a,0x0c,0x9a,0x6a,0x4d,0x8d,0xa6,0x5e,0xd3,0xa8,0x69, +0xd6,0xb4,0x6a,0xda,0x35,0x9d,0x9a,0x1b,0x9a,0x5e,0x4d,0x9f,0x66,0x40,0x73,0x4f, +0x73,0x5f,0xf3,0x40,0xf3,0x50,0xf3,0x48,0xf3,0x58,0x33,0xa1,0x79,0xa2,0x79,0xaa, +0x99,0xd1,0xcc,0x69,0x9e,0x6b,0x16,0x35,0x2f,0x34,0x2f,0x35,0xaf,0x34,0xa0,0xd2, +0xa6,0xd2,0xae,0xd2,0xbe,0x92,0x50,0xe9,0x5c,0xe9,0x5a,0xe9,0x5e,0xe9,0x59,0xe9, +0x5d,0xe9,0x53,0xe9,0x57,0x49,0xae,0xa4,0x56,0x06,0x56,0x06,0x57,0x86,0x56,0x86, +0x57,0x46,0x56,0x32,0x2b,0xe3,0x2a,0x93,0x2a,0x93,0x2b,0x53,0x2a,0xd3,0x2a,0x33, +0x2a,0xb9,0x95,0xfc,0x4a,0x61,0xa5,0xb8,0xb2,0xa8,0x52,0x56,0xa9,0xa8,0x54,0x55, +0x6a,0x2b,0x0d,0x95,0xd5,0x95,0x35,0x95,0xf5,0x95,0x8d,0x95,0xcd,0x95,0xad,0x95, +0xed,0x95,0x9d,0x95,0x37,0x2a,0x7b,0x2b,0xfb,0x2a,0x07,0x2a,0xef,0x55,0xde,0xaf, +0x7c,0x50,0xf9,0xb0,0xf2,0x51,0xe5,0xe3,0xca,0x89,0xca,0x27,0x95,0x4f,0x2b,0x67, +0x2a,0xe7,0x2a,0x9f,0x57,0x2e,0x56,0xbe,0xa8,0x7c,0x59,0xf9,0xaa,0x12,0x68,0x6d, +0xb4,0x76,0x5a,0x7b,0x2d,0x41,0xeb,0xac,0x75,0xd5,0xba,0x6b,0x3d,0xb5,0xde,0x5a, +0x1f,0xad,0x9f,0x96,0xac,0xa5,0x6a,0x03,0xb5,0xc1,0xda,0x50,0x6d,0xb8,0x36,0x52, +0xcb,0xd4,0xc6,0x69,0x93,0xb4,0xc9,0xda,0x14,0x6d,0x9a,0x36,0x43,0xcb,0xd5,0xf2, +0xb5,0x42,0xad,0x58,0x5b,0xa4,0x95,0xc1,0xd7,0x5b,0x95,0x56,0xab,0x35,0x68,0xab, +0xb5,0x35,0xda,0x7a,0x6d,0xa3,0xb6,0x59,0xdb,0xaa,0x6d,0xd7,0x76,0x6a,0x6f,0x68, +0x7b,0xb5,0x7d,0xda,0x01,0xed,0x3d,0xed,0x7d,0xed,0x03,0xed,0x43,0xed,0x23,0xed, +0x63,0xed,0x84,0xf6,0x89,0xf6,0xa9,0x76,0x46,0x3b,0xa7,0x7d,0xae,0x5d,0xd4,0xbe, +0xd0,0xbe,0xd4,0xbe,0xd2,0x02,0x9d,0x8d,0xce,0x4e,0x67,0xaf,0x23,0xe8,0x9c,0x75, +0xae,0x3a,0x77,0x9d,0xa7,0xce,0x5b,0xe7,0xa3,0xf3,0xd3,0x91,0x75,0x54,0x5d,0xa0, +0x2e,0x58,0x17,0xaa,0x0b,0xd7,0x45,0xea,0x98,0xba,0x38,0x5d,0x92,0x2e,0x59,0x97, +0xa2,0x4b,0xd3,0x65,0xe8,0xb8,0x3a,0xbe,0x4e,0xa8,0x13,0xeb,0x8a,0x74,0x32,0x9d, +0x42,0xa7,0xd2,0x69,0x75,0x06,0x5d,0xb5,0xae,0x46,0x57,0xaf,0x6b,0xd4,0x35,0xeb, +0x5a,0x75,0xed,0xba,0x4e,0xdd,0x0d,0x5d,0xaf,0xae,0x4f,0x37,0xa0,0xbb,0x07,0xb9, +0xaf,0x7b,0xa0,0x7b,0xa8,0x7b,0xa4,0x7b,0xac,0x9b,0xd0,0x3d,0xd1,0x3d,0xd5,0xcd, +0xe8,0xe6,0x74,0xcf,0x75,0x8b,0xba,0x17,0xba,0x97,0xba,0x57,0x3a,0xa0,0xb7,0xd1, +0xdb,0xe9,0xed,0xf5,0x04,0xbd,0xb3,0xde,0x55,0xef,0xae,0xf7,0xd4,0x7b,0xeb,0x7d, +0xf4,0x7e,0x7a,0xb2,0x9e,0xaa,0x0f,0xd4,0x07,0xeb,0x43,0xf5,0xe1,0xfa,0x48,0x3d, +0x53,0x1f,0xa7,0x4f,0xd2,0x27,0xeb,0x53,0xf4,0x69,0xfa,0x0c,0x3d,0x57,0xcf,0xd7, +0x0b,0xf5,0x62,0x7d,0x91,0x5e,0xa6,0x57,0xe8,0x55,0x7a,0xad,0xde,0xa0,0xaf,0xd6, +0xd7,0xe8,0xeb,0xf5,0x8d,0xfa,0x66,0x7d,0xab,0xbe,0x5d,0xdf,0xa9,0xbf,0xa1,0xef, +0xd5,0xf7,0xe9,0x07,0xf4,0xf7,0xf4,0xf7,0xf5,0x0f,0xf4,0x0f,0xf5,0x8f,0xf4,0x8f, +0xf5,0x13,0xfa,0x27,0xfa,0xa7,0xfa,0x19,0xfd,0x9c,0xfe,0xb9,0x7e,0x51,0xff,0x42, +0xff,0x52,0xff,0x4a,0x0f,0xaa,0x6c,0xaa,0xec,0xaa,0xec,0xab,0x08,0x55,0xce,0x55, +0xae,0x55,0xee,0x55,0x9e,0x55,0xde,0x55,0x3e,0x55,0x7e,0x55,0xe4,0x2a,0x6a,0x55, +0x60,0x55,0x70,0x55,0x68,0x55,0x78,0x55,0x64,0x15,0xb3,0x2a,0xae,0x2a,0xa9,0x2a, +0xb9,0x2a,0xa5,0x2a,0xad,0x2a,0xa3,0x8a,0x5b,0xc5,0xaf,0x12,0x56,0x89,0xab,0x8a, +0xaa,0x64,0x55,0x8a,0x2a,0x55,0x95,0xb6,0xca,0x50,0x55,0x5d,0x55,0x53,0x55,0x5f, +0xd5,0x58,0xd5,0x5c,0xd5,0x5a,0xd5,0x5e,0xd5,0x59,0x75,0xa3,0xaa,0xb7,0xaa,0xaf, +0x6a,0xa0,0xea,0x5e,0xd5,0xfd,0xaa,0x07,0x55,0x0f,0xab,0x1e,0x55,0x3d,0xae,0x9a, +0xa8,0x7a,0x52,0xf5,0xb4,0x6a,0xa6,0x6a,0xae,0xea,0x79,0xd5,0x62,0xd5,0x8b,0xaa, +0x97,0x55,0xaf,0xaa,0x80,0xc1,0xc6,0x60,0x67,0xb0,0x37,0x10,0x0c,0xce,0x06,0x57, +0x83,0xbb,0xc1,0xd3,0xe0,0x6d,0xf0,0x31,0xf8,0x19,0xc8,0x06,0xaa,0x21,0xd0,0x10, +0x6c,0x08,0x35,0x84,0x1b,0x22,0x0d,0x4c,0x43,0x9c,0x21,0xc9,0x90,0x6c,0x48,0x31, +0xa4,0x19,0x32,0x0c,0x5c,0x03,0xdf,0x20,0x34,0x88,0x0d,0x45,0x06,0x99,0x41,0x61, +0x50,0x19,0xb4,0x06,0x83,0xa1,0xda,0x50,0x63,0xa8,0x37,0x34,0x1a,0x9a,0x0d,0xad, +0x86,0x76,0x43,0xa7,0xe1,0x86,0xa1,0xd7,0xd0,0x67,0x18,0x30,0xdc,0x33,0xdc,0x37, +0x3c,0x30,0x3c,0x34,0x3c,0x32,0x3c,0x36,0x4c,0x18,0x9e,0x18,0x9e,0x1a,0x66,0x0c, +0x73,0x86,0xe7,0x86,0x45,0xc3,0x0b,0xc3,0x4b,0xc3,0x2b,0x03,0x30,0xda,0x18,0xed, +0x8c,0xf6,0x46,0x82,0xd1,0xd9,0xe8,0x6a,0x74,0x37,0x7a,0x1a,0xbd,0x8d,0x3e,0x46, +0x3f,0x23,0xd9,0x48,0x35,0x06,0x1a,0x83,0x8d,0xa1,0xc6,0x70,0x63,0xa4,0x91,0x69, +0x8c,0x33,0x26,0x19,0x93,0x8d,0x29,0xc6,0x34,0x63,0x86,0x91,0x6b,0xe4,0x1b,0x85, +0x46,0xb1,0xb1,0xc8,0x28,0x33,0x2a,0x8c,0x2a,0xa3,0xd6,0x68,0x30,0x56,0x1b,0x6b, +0x8c,0xf5,0xc6,0x46,0x63,0xb3,0xb1,0xd5,0xd8,0x6e,0xec,0x34,0xde,0x30,0xf6,0x1a, +0xfb,0x8c,0x03,0xc6,0x7b,0x90,0xfb,0xc6,0x07,0xc6,0x87,0xc6,0x47,0xc6,0xc7,0xc6, +0x09,0xe3,0x13,0xe3,0x53,0xe3,0x8c,0x71,0xce,0xf8,0xdc,0xb8,0x68,0x7c,0x61,0x7c, +0x69,0x7c,0x65,0x04,0x17,0x6c,0x2e,0xd8,0x5d,0xb0,0xbf,0x40,0xb8,0xe0,0x7c,0xc1, +0xf5,0x82,0xfb,0x05,0xcf,0x0b,0xde,0x17,0x7c,0x2e,0xf8,0x5d,0x20,0x5f,0xa0,0x5e, +0x08,0x5c,0xe7,0x5f,0x80,0xb5,0xff,0xf7,0xac,0x27,0x96,0xec,0x36,0x02,0x90,0x8e, +0x1d,0xdb,0xc0,0xe3,0x77,0x61,0x7e,0x08,0x2b,0xe3,0x60,0x79,0x60,0xe3,0xda,0xf1, +0x01,0x98,0x53,0x60,0x9e,0x0b,0xd6,0xf2,0x70,0x58,0x49,0x7d,0xe3,0xf8,0xf5,0x79, +0xaf,0xeb,0xc3,0xd0,0x4d,0x36,0xae,0xe5,0x38,0x2c,0xdf,0x80,0xe5,0x1b,0xb1,0xdc, +0x0e,0xcb,0xb7,0xc0,0xfc,0x28,0x76,0x8f,0x08,0xec,0xbc,0x08,0xec,0xbc,0x08,0xec, +0xbc,0x08,0xac,0x3f,0x03,0x6b,0x67,0x60,0xed,0x0c,0xac,0x9d,0x81,0xb5,0xc7,0x60, +0xd7,0x8f,0xc5,0xfa,0xc5,0x62,0xfd,0x62,0xb1,0x7e,0xb1,0x6f,0xb4,0xa3,0xfe,0x6c, +0xac,0x1f,0x1b,0xeb,0xc7,0xc6,0xfa,0xb1,0xb1,0x76,0x0e,0x56,0x9f,0x8e,0xf5,0x4b, +0x7f,0xa3,0xbc,0x01,0xcb,0x37,0x62,0xf9,0x6b,0x5b,0xa2,0xf9,0x7c,0x8c,0xcd,0x27, +0x13,0x3b,0x2f,0x13,0x3b,0x2f,0x13,0x3b,0x2f,0x13,0xeb,0xcf,0xc3,0xda,0x79,0x58, +0x3b,0x0f,0x6b,0xe7,0x61,0xed,0xe7,0xb1,0xeb,0xe7,0x62,0xfd,0x72,0xb1,0x7e,0xb9, +0x58,0xbf,0xdc,0x37,0xda,0x51,0x7f,0x09,0xd6,0x4f,0x82,0xf5,0x93,0x60,0xfd,0x24, +0x58,0xbb,0x14,0xab,0x97,0xbe,0x61,0x7f,0x1b,0x6c,0xdc,0x36,0x58,0x79,0x13,0x56, +0xde,0x84,0x95,0x7d,0xb0,0xb2,0x0f,0xe6,0x27,0x1c,0x36,0x3f,0x1c,0x56,0xde,0x80, +0x95,0x37,0x60,0xe5,0xcd,0x58,0x79,0x33,0x56,0xb6,0xc7,0xca,0x28,0x0f,0xc7,0xf2, +0x0c,0x2c,0x8f,0xc0,0xee,0x9b,0x89,0xe5,0x11,0xd8,0x7d,0x33,0xb1,0x3c,0x02,0xbb, +0x4e,0x26,0x96,0x47,0x60,0xe3,0xc8,0xc4,0xf2,0x08,0xec,0x3a,0x99,0x58,0x7e,0x1c, +0x1b,0xc7,0x39,0x2c,0x3f,0x8e,0x5d,0xe7,0x1c,0x96,0x1f,0xc7,0xae,0x73,0x0e,0xcb, +0x8f,0x63,0x7e,0x3a,0x87,0xe5,0x91,0xd8,0x79,0xdc,0x37,0xe2,0x6a,0x23,0xe6,0x8f, +0x8d,0x58,0xd9,0x06,0x2b,0xdb,0x60,0xe5,0x4d,0x58,0x79,0x13,0x56,0xf6,0xc1,0xca, +0x3e,0x58,0x79,0x33,0x96,0x47,0x81,0xb5,0xfa,0x6c,0xec,0x18,0x5d,0x3f,0x1b,0xcb, +0xa3,0xb1,0xfb,0xe7,0x60,0x39,0x13,0xb3,0x2f,0x1f,0xcb,0x99,0x58,0x3d,0xff,0x8d, +0x76,0x7b,0xac,0x6c,0x8f,0x95,0x6f,0x83,0xb5,0x32,0xca,0x63,0xb0,0xf3,0xce,0x63, +0x79,0x0c,0x76,0xde,0x79,0x2c,0x8f,0xc1,0xce,0x3b,0x8f,0xe5,0x03,0x1b,0xd6,0x8e, +0x63,0xb1,0x79,0xe5,0x62,0x79,0x2c,0x36,0xaf,0x5c,0x2c,0x47,0xe5,0xad,0x58,0x19, +0xe5,0x09,0xd8,0xf5,0xf3,0xb0,0x3c,0x01,0xbb,0x7e,0x1e,0x96,0x27,0x60,0xd7,0xcf, +0xc3,0xf2,0x44,0xac,0x5f,0x3e,0x96,0x27,0x62,0xf3,0xcf,0xc7,0xf2,0x44,0xec,0xbc, +0x7c,0x2c,0x4f,0xc4,0xce,0xcb,0xc7,0xf2,0x24,0xac,0x5e,0x8c,0xe5,0x49,0x58,0xbd, +0x18,0xcb,0xd9,0x98,0x9f,0x24,0x58,0xce,0xc6,0xe6,0x21,0xc1,0x72,0x36,0x36,0x0f, +0x09,0x96,0xb3,0xb1,0xf5,0x2a,0xc1,0x72,0x36,0x36,0x2f,0x09,0x96,0xb3,0x31,0x3f, +0x4a,0xb0,0xfc,0x24,0x36,0xce,0x42,0x2c,0xe7,0x60,0xb9,0xf4,0x8d,0x32,0x5a,0x57, +0xa7,0xb0,0xf9,0x15,0x63,0xf9,0x29,0x2c,0x0e,0x8a,0xb1,0xfc,0x14,0x36,0xde,0xe2, +0x37,0xe6,0x87,0x6c,0xbb,0x1b,0xb3,0xed,0x6e,0xec,0xde,0xbb,0xb1,0x7b,0xef,0xc6, +0xd6,0xce,0xa9,0x37,0xd6,0x51,0xf1,0x1b,0x6b,0xa9,0xf8,0x8d,0x38,0x40,0xb1,0xc5, +0xc4,0xe2,0x8c,0x8f,0xe5,0x31,0x58,0x7d,0x0c,0x56,0x3e,0x8f,0xe5,0x61,0xd8,0x79, +0xe9,0x58,0xce,0xc0,0x72,0x1e,0x96,0xc7,0x62,0x79,0xee,0x1b,0xf6,0xb5,0xc7,0xc6, +0x64,0xff,0xc6,0x3e,0x69,0xf3,0xc6,0x1e,0x63,0xf3,0x46,0x3d,0xee,0x8d,0x7a,0xdc, +0x1b,0xf5,0xf6,0x6f,0xd4,0xbf,0x79,0x1d,0xf0,0x46,0x3d,0x78,0xe3,0x39,0x61,0xf3, +0xc6,0x1e,0xfb,0x7a,0x9f,0xda,0xfc,0x46,0xfd,0xeb,0xe3,0xff,0x85,0xf9,0x79,0x16, +0xcb,0x8f,0x63,0xe3,0x3c,0x87,0xe5,0xd1,0x58,0x9e,0xf3,0xc6,0xfc,0x7c,0xb0,0xf9, +0xf9,0xbc,0x51,0xb6,0x79,0xa3,0x0e,0x1d,0xdf,0xc6,0xad,0xf5,0xff,0x74,0xc3,0x5a, +0x9e,0xfd,0x86,0x1f,0x90,0x4f,0x5e,0xfb,0xe3,0xb5,0x2f,0x8e,0x63,0x7e,0x3f,0xf7, +0xc6,0xfa,0x03,0xd8,0x7a,0x03,0x6f,0x3c,0xf7,0x70,0x6f,0x3c,0x33,0x70,0xd8,0xf8, +0x71,0xd8,0xf8,0x51,0x3e,0x81,0xe5,0x2f,0xff,0x3f,0xf6,0xce,0x04,0x40,0xc7,0xe2, +0xf1,0xe3,0xcf,0xfb,0xee,0xbe,0xbb,0xd6,0x7d,0x76,0x29,0xd7,0x16,0xc2,0xae,0xbd, +0x59,0xe7,0x5a,0xd6,0x99,0x90,0x90,0x54,0xae,0x90,0x5c,0xeb,0x08,0x95,0xca,0x91, +0xd2,0x49,0x87,0x4a,0x27,0x9d,0xa4,0x72,0x25,0x54,0xce,0x0a,0x91,0x12,0x15,0x65, +0x8b,0x90,0x44,0x42,0xba,0x48,0xf5,0xff,0xcc,0x3e,0xdf,0x27,0xe3,0xf9,0xdb,0x1f, +0xaa,0x5f,0xbf,0x8e,0xf7,0x19,0x1f,0xdf,0x99,0x79,0xe6,0x99,0x67,0x66,0x9e,0x99, +0x79,0x9e,0xf7,0x99,0x79,0x66,0xad,0xfb,0x68,0x11,0x1d,0x53,0x44,0xee,0x62,0x72, +0x17,0x53,0x7f,0x58,0x44,0xfd,0x61,0x11,0xb9,0x8b,0xc9,0x5d,0x4c,0xd7,0xb7,0x88, +0xae,0x6f,0x11,0xb9,0x8b,0xc9,0x5d,0x4c,0xf9,0x2f,0xa2,0xbc,0x17,0x91,0xbb,0x98, +0xdc,0xc5,0xd4,0x9e,0x8b,0xa8,0x3d,0x17,0x91,0xbb,0x98,0xdc,0xc5,0x74,0x1d,0x8b, +0xe8,0x1a,0x16,0x91,0xbb,0x98,0xdc,0xc5,0xd4,0x9e,0x2b,0xaa,0xbe,0x57,0x54,0xfb, +0xad,0xa8,0xf6,0x5b,0x51,0xfd,0x6f,0x41,0xf5,0xbf,0x05,0xad,0xeb,0xdc,0xd5,0xea, +0xff,0xbd,0xfb,0x6a,0x25,0xeb,0x3e,0x1e,0x69,0xdd,0x03,0x23,0xad,0xfb,0x7c,0xa4, +0x75,0x8f,0xf4,0xfc,0xa3,0xe5,0x17,0x6d,0xb9,0x23,0x2d,0xbf,0x48,0xb5,0xe3,0x48, +0xb5,0xeb,0x48,0xa5,0xa7,0x67,0xd0,0xbd,0xee,0x26,0xaf,0x57,0x63,0xbf,0x16,0x46, +0x05,0xdd,0xbe,0xe0,0x6a,0x3d,0x33,0x45,0xe9,0x79,0x29,0x5a,0x9a,0x5f,0x5a,0x59, +0x1a,0x21,0x35,0x7d,0x4b,0xf7,0xa0,0xdb,0x3e,0x4d,0x59,0x0c,0x87,0x89,0x41,0xb7, +0x6e,0x98,0xeb,0x5c,0x22,0xe2,0x48,0x9b,0x59,0x10,0x74,0x8f,0xc9,0xc2,0x5e,0xdb, +0x7a,0x36,0x9b,0x2a,0xbd,0x4b,0xe1,0x4c,0xbf,0x3f,0x51,0xf6,0xfb,0xa5,0x93,0xa4, +0x8f,0x49,0x9f,0x92,0x4e,0xf3,0xe2,0xb6,0xce,0x33,0x49,0xf6,0xa7,0xa4,0xb3,0xe4, +0x3f,0xd7,0x8b,0xdf,0x3a,0xc6,0xe8,0x1b,0x76,0x1a,0x65,0xf7,0xfc,0x16,0x5b,0x61, +0x8c,0xbe,0x29,0x9d,0x0d,0xf3,0x75,0x8e,0x75,0xf2,0x5b,0xa7,0x63,0x96,0xc3,0x12, +0x78,0x19,0x96,0xc2,0x32,0x78,0x40,0xe7,0x7f,0x02,0x4a,0x45,0xba,0xe5,0x63,0xd4, +0x84,0x2f,0x11,0xe9,0x1e,0x1f,0x25,0xf7,0x19,0x72,0x9f,0xa6,0x70,0xb1,0x91,0xee, +0xf5,0x38,0x4d,0x5a,0x53,0x9a,0xaa,0xfd,0xa9,0x3a,0x2e,0x59,0xc7,0xb5,0x97,0xbb, +0x96,0xdc,0x35,0x15,0xae,0xa1,0x8e,0x1b,0x12,0xa9,0xba,0x2d,0x3d,0x45,0xfe,0x69, +0xd2,0xa2,0xd2,0x04,0xcb,0x9d,0x4f,0xee,0x7c,0x4a,0xb7,0x77,0x7e,0xa3,0x1b,0xe5, +0xff,0xa1,0xf4,0x14,0x69,0x9a,0xf4,0x54,0x69,0x0d,0xa9,0xc9,0x47,0xa4,0xd2,0x15, +0x29,0x77,0x3e,0xb9,0x8d,0x96,0x91,0xd6,0x93,0xee,0x94,0x7e,0x21,0x8d,0x93,0xb6, +0x94,0xc6,0x2a,0x9e,0x86,0xd2,0x58,0xf9,0x37,0xb4,0xf6,0x17,0x90,0xdb,0x68,0x25, +0xf9,0x37,0x91,0x56,0x95,0xb6,0x90,0xf6,0x08,0x39,0xce,0x68,0xa8,0x14,0x45,0x3b, +0x8f,0x72,0xf5,0x42,0x68,0x2a,0x35,0xee,0x76,0xd0,0xdc,0x72,0x0f,0xd1,0x7e,0xa3, +0x2b,0xa4,0xcd,0xa5,0xef,0x2b,0xdc,0x52,0xe9,0x3a,0x69,0xe5,0x18,0xc7,0xa9,0x03, +0x09,0xd2,0x64,0x69,0x29,0xe9,0x29,0xd2,0x53,0xa5,0x67,0x4a,0xcb,0x4b,0x2b,0x48, +0xab,0x4a,0xab,0x4b,0x57,0xc0,0x22,0xe9,0x06,0x98,0x02,0xaf,0xc2,0xe3,0xd2,0x19, +0xd2,0xa4,0xfc,0x84,0x87,0x9a,0xd2,0x53,0xa4,0xa7,0x4a,0xcf,0x94,0x56,0x95,0x36, +0x29,0x40,0xdd,0x2a,0xe0,0x6a,0x3d,0x69,0x07,0x28,0x0f,0x75,0xa0,0x82,0xf4,0x6e, +0xd8,0x00,0xcb,0x61,0x11,0xac,0x90,0x2e,0x97,0x7f,0xe3,0x82,0xc4,0x03,0x8b,0xe1, +0x7d,0x58,0x6e,0xe9,0x07,0xd2,0x65,0x96,0x9a,0x7d,0x8d,0x0b,0x71,0x4e,0x68,0x22, +0x35,0xee,0x0e,0xf0,0x21,0xac,0x92,0xbe,0x63,0xa9,0xe7,0xb7,0x19,0x5a,0x16,0x26, +0xaf,0xb0,0x06,0x66,0xc3,0x74,0x98,0x24,0x9d,0x02,0x05,0x8a,0x38,0x4e,0x26,0xcc, +0x83,0xf3,0xa4,0x6d,0xa4,0xed,0xa5,0x9d,0xa4,0x19,0x30,0x17,0x06,0xc2,0x20,0xe9, +0x10,0x98,0x0d,0x23,0xa5,0x03,0x65,0x9f,0x63,0xa9,0xe7,0xe7,0xe9,0xdd,0x8a,0xef, +0x61,0xe9,0x14,0xe9,0xd3,0xd2,0xe9,0xd2,0x09,0x3a,0xdf,0x39,0x45,0x1d,0x27,0x1e, +0x72,0x20,0x54,0x9a,0xb6,0x07,0xd1,0xd2,0x18,0x69,0x01,0x69,0x21,0x69,0x31,0x69, +0x2d,0x69,0x1d,0x69,0x3d,0x69,0x7d,0x69,0xa6,0xd4,0xdc,0xa3,0xcc,0x7d,0x3b,0x53, +0xcf,0x01,0xe6,0x1e,0x75,0x67,0xc0,0x7d,0x06,0x30,0xf7,0x33,0xef,0xd9,0xbf,0x85, +0x9e,0xcb,0x5a,0xea,0x39,0xcc,0xdc,0x7b,0x2a,0xd0,0xb7,0xb7,0x76,0xdc,0xfb,0xa8, +0xb9,0x17,0x9a,0xfb,0xa5,0x79,0xc6,0x34,0xf7,0xbb,0xd6,0xec,0x6b,0x03,0xc1,0xb3, +0x1c,0xa7,0x9b,0x9e,0x2d,0xcc,0x7d,0xaf,0x23,0x7e,0x9d,0xe0,0x92,0xa0,0xfb,0x7c, +0x61,0x9e,0x65,0xfa,0x99,0xf8,0x03,0xee,0x3d,0xec,0x42,0xfc,0x4f,0xe1,0x98,0x53, +0x21,0xdb,0x71,0xef,0xad,0xe6,0xfe,0x7b,0x16,0xee,0x01,0xec,0x1b,0x8a,0xfd,0x9c, +0xb3,0xdc,0xbe,0x78,0x0e,0xbc,0xa8,0xbe,0x77,0x85,0x9e,0x03,0x06,0x29,0xbc,0x09, +0xe7,0x85,0x59,0x6a,0x85,0xa9,0x4b,0x7b,0xbf,0x20,0xe8,0xfe,0xa6,0x6b,0x87,0xee, +0x73,0xdc,0xb4,0xf4,0x44,0x3b,0xa3,0x5d,0xa1,0x07,0x5c,0x01,0xbd,0xcd,0x3d,0xd3, +0xdc,0x2b,0x39,0xdf,0x23,0x68,0x3f,0x18,0x8b,0xfd,0x31,0x74,0x20,0x64,0xc3,0x20, +0x18,0x0c,0x43,0xe0,0x2a,0x18,0x0e,0xa3,0x61,0x0c,0x4c,0x27,0x4f,0xb7,0xa0,0xb7, +0xc2,0x99,0x1c,0x77,0x1b,0x7a,0x7b,0xd0,0x7d,0xc6,0x9a,0x80,0xde,0x15,0x74,0x9f, +0xc9,0xe6,0xeb,0x59,0xe1,0x1c,0x3d,0x2b,0x18,0xcd,0xd4,0x7d,0xb8,0x9b,0xd4,0xb8, +0x63,0xe5,0x8e,0x95,0x3b,0x51,0xee,0x44,0xeb,0x1d,0x44,0xc0,0xfa,0xfd,0x1e,0xd0, +0x33,0x5e,0xb4,0x9e,0xb3,0xa3,0xe5,0x8e,0x95,0x3b,0x56,0xee,0x44,0xb9,0x13,0xe5, +0xae,0x24,0x77,0x25,0xb9,0xe3,0xe4,0x8e,0xb3,0x7e,0xf3,0x3a,0xd6,0xef,0x5e,0xc7, +0xf2,0x0f,0x58,0xfe,0xde,0x3b,0x90,0x38,0xf9,0x79,0xc7,0x27,0xc8,0x9d,0x60,0x3d, +0x13,0x45,0x59,0xcf,0x45,0xc6,0xde,0x58,0xe9,0xed,0x69,0xfd,0xd6,0x8d,0xd4,0x33, +0x69,0xa4,0x9e,0xb5,0xa2,0xf5,0x6c,0x13,0x2d,0x77,0xac,0xdc,0xb1,0x72,0xe7,0x93, +0x3b,0x9f,0xdc,0x95,0xe4,0xf6,0x7e,0x2b,0xc7,0xcb,0x1d,0xaf,0x67,0xc9,0x04,0xd5, +0xa1,0x04,0xeb,0x9d,0x4c,0xc0,0x7a,0x9f,0x11,0xd0,0x33,0x78,0x40,0xcf,0xe0,0x9e, +0x3b,0x56,0xee,0x58,0xb9,0x13,0xe5,0x4e,0xd4,0x6f,0x9a,0x58,0xfd,0xd6,0x8d,0xb5, +0xdc,0x91,0x96,0x5f,0xa4,0xfc,0x13,0xe5,0xe7,0x1d,0x17,0x27,0xb7,0xd1,0x96,0x3a, +0x5f,0x3f,0x69,0x4b,0xe5,0xbb,0x9f,0xb4,0xa5,0xe2,0xea,0x27,0x3d,0x5f,0xfe,0xfd, +0xa5,0xe7,0xcb,0xbf,0xbf,0xb5,0x3f,0x51,0xee,0x44,0xb9,0xe3,0xe4,0x8e,0xb3,0x9e, +0x41,0x03,0xd6,0x33,0x68,0xc0,0xf2,0xcf,0x67,0xf9,0xe7,0x8b,0x38,0xf2,0xdb,0xdb, +0xb1,0x7e,0x7f,0x3b,0x96,0x7f,0xc0,0xf2,0x37,0xf6,0xd6,0xca,0x47,0xb6,0x73,0xc4, +0x1d,0x2d,0x77,0xb4,0x9e,0xcd,0xa3,0xf5,0x6c,0xee,0xb9,0x63,0xe5,0x8e,0xb5,0xdc, +0x91,0x96,0x5f,0xa4,0xfc,0x13,0xe5,0x97,0xa8,0x67,0xf6,0x68,0x3d,0xb3,0x47,0xcb, +0x1d,0x2b,0x77,0xac,0xf5,0x9b,0x3e,0xda,0xfa,0x5d,0x1f,0x6d,0xfd,0x76,0x8f,0xb6, +0x7e,0xbf,0xdb,0xc7,0x47,0x5b,0x71,0x44,0xeb,0xb7,0x40,0xb4,0x7e,0x0b,0x78,0xee, +0x58,0xb9,0x63,0xe5,0x4e,0x94,0x3b,0x51,0xee,0x38,0xb9,0xe3,0xf4,0x5b,0xe3,0x6c, +0xfd,0xd6,0x38,0x5b,0xee,0x04,0xb9,0x13,0xe4,0x8e,0x93,0x3b,0xce,0x7a,0x57,0x10, +0xb0,0xde,0x17,0x04,0xac,0x77,0x06,0xf9,0xac,0xf7,0x06,0xc6,0xde,0x5e,0x61,0x86, +0x4a,0xdb,0x2b,0x5d,0x43,0xa5,0x1d,0xf4,0xdb,0x6e,0x98,0xb4,0x83,0xca,0x62,0x98, +0xb4,0x83,0xda,0xc0,0x30,0x69,0x07,0xe5,0x73,0x98,0xb4,0x83,0xe2,0x19,0x26,0xbd, +0x48,0xfe,0xc3,0xa5,0x17,0xe9,0xb8,0xe1,0xd6,0xbb,0xc9,0x68,0xfd,0x46,0xf1,0xde, +0x29,0x04,0xf5,0x4e,0x21,0x28,0x77,0xac,0xdc,0xb1,0x72,0x27,0xca,0x9d,0xa8,0x76, +0xeb,0x95,0xa7,0x97,0xae,0xfc,0x8a,0x2f,0xbf,0xfa,0xd1,0x45,0xf4,0xad,0x37,0x04, +0xdc,0xf8,0x1b,0x28,0x9e,0xae,0x52,0xe3,0x8e,0x91,0x3b,0xc6,0x7a,0xc7,0x6b,0xbf, +0x1f,0xb5,0xdf,0xfd,0x3a,0x96,0xbf,0x63,0xf9,0xc7,0x58,0xfe,0x76,0x3c,0x11,0x96, +0x7f,0x84,0x75,0xfe,0xa0,0x95,0x86,0xa0,0xf5,0xce,0x32,0x60,0xbd,0xb7,0x0c,0x58, +0xfe,0x8e,0xe5,0xef,0x58,0xfe,0x31,0x96,0x7f,0x8c,0xe5,0x1f,0x61,0xf9,0xdb,0xe7, +0x8d,0xb2,0xce,0xeb,0xbd,0x9b,0x8c,0x55,0x9f,0x1b,0x2b,0x77,0x8c,0xdc,0x31,0x72, +0x47,0xc8,0x1d,0x61,0xbd,0xcb,0xb6,0xdf,0x03,0xdb,0xef,0xb8,0x1d,0xcb,0xdf,0xb1, +0xfc,0x63,0x2c,0xff,0x18,0xcb,0x3f,0xc2,0xf2,0x8f,0xb0,0xd2,0x13,0xb4,0xd2,0xe4, +0xbd,0xc3,0x8c,0x51,0x1f,0x1c,0x23,0x77,0xac,0xdc,0xb1,0xea,0x5f,0x62,0xd5,0xb7, +0x78,0xee,0x18,0xb9,0x63,0xac,0x77,0xe7,0xf6,0x7b,0x67,0xfb,0x9d,0xba,0x63,0xf9, +0x3b,0x96,0x7f,0x8c,0xe5,0x6f,0xc7,0x13,0x61,0xf9,0x47,0x58,0xe7,0x0f,0x5a,0x69, +0xf0,0xde,0xd5,0x97,0xb6,0xce,0x5b,0xda,0x3a,0x6f,0x69,0xeb,0xbc,0xa5,0xad,0xf3, +0x96,0xb6,0xce,0x5b,0xda,0x3a,0x6f,0x69,0xeb,0xbc,0xa5,0xad,0xf3,0x1a,0x7b,0xac, +0xe5,0x1f,0xab,0xf6,0x1f,0xab,0xb6,0xef,0xb9,0x63,0xe4,0x8e,0xb1,0xde,0xcb,0x05, +0xac,0x77,0x73,0x01,0xcb,0xdf,0xb1,0xfc,0x1d,0xcb,0x3f,0xc6,0xf2,0xb7,0xe3,0x89, +0xb0,0xfc,0x23,0x2c,0xff,0x58,0xcb,0x3f,0x56,0xed,0xdd,0x51,0xfb,0x74,0xe4,0x8e, +0x95,0xdb,0xdb,0x1f,0x23,0x77,0x8c,0xdc,0x11,0x72,0x47,0xe8,0xf7,0x7c,0x09,0x69, +0x49,0xcb,0xed,0x58,0x7e,0x8e,0xe5,0x1f,0xb0,0xfc,0x03,0x96,0x7f,0xa6,0xe5,0x9f, +0xa9,0xf7,0x0f,0x25,0xa4,0x25,0x2d,0xb7,0x63,0xf9,0x39,0x96,0x7f,0xc0,0xf2,0x0f, +0x58,0xfe,0x99,0x96,0x7f,0xa6,0x7e,0xf7,0x97,0x90,0x96,0xb4,0xdc,0x8e,0xe5,0xe7, +0x58,0xfe,0x01,0xcb,0xdf,0xd8,0x27,0xca,0x7f,0xa2,0xfc,0x26,0x5a,0xc7,0x4f,0xb4, +0x8e,0x9f,0x68,0x1d,0x3f,0xd1,0x3a,0x7e,0x9e,0xfc,0xe7,0xc9,0x6f,0x9e,0x75,0xfc, +0x3c,0xeb,0xf8,0x79,0xd6,0xf1,0xf3,0x8e,0x71,0x7c,0xa6,0xe5,0x9f,0xa9,0x77,0x33, +0x25,0xa4,0x25,0x2d,0xb7,0x63,0xf9,0x39,0x96,0x7f,0xc0,0xf2,0x0f,0x58,0xfe,0x99, +0x96,0x7f,0xa6,0xde,0xc1,0x94,0x90,0x96,0xb4,0xdc,0x8e,0xe5,0xe7,0x58,0xfe,0x01, +0xcb,0x3f,0x60,0xf9,0x67,0x5a,0xfe,0x99,0x7a,0x2f,0x54,0x42,0x5a,0xd2,0x72,0x3b, +0x96,0x9f,0x63,0xf9,0x07,0x2c,0xff,0x80,0xe5,0x9f,0x69,0xf9,0x67,0xea,0x1d,0x51, +0x09,0x69,0x49,0xcb,0xed,0x58,0x7e,0x8e,0xe5,0x1f,0xb0,0xfc,0xbd,0x77,0x5a,0x25, +0xa4,0x25,0x2d,0xb7,0x63,0xf9,0x39,0x96,0x7f,0xc0,0xf2,0xf7,0xde,0x4d,0x95,0x90, +0x96,0xb4,0xdc,0x8e,0xe5,0xe7,0x58,0xfe,0x01,0xcb,0xdf,0x3e,0x3e,0xd3,0xf2,0xcf, +0xd4,0xbb,0xad,0x92,0x96,0x3a,0x96,0x3d,0x60,0xd9,0x33,0xf5,0x5e,0xac,0x84,0xb4, +0xa4,0xe5,0x76,0x2c,0x3f,0xc7,0xf2,0x0f,0x58,0xfe,0x01,0xcb,0x3f,0xd3,0xf2,0xcf, +0xd4,0xfb,0xbd,0x12,0xd2,0x92,0x96,0xdb,0xb1,0xfc,0x1c,0xcb,0x3f,0x60,0xf9,0x07, +0x2c,0xff,0x4c,0xcb,0xdf,0x6b,0xf7,0x8e,0xef,0xdd,0xa0,0xe3,0x7b,0x47,0xe8,0xf8, +0xde,0x15,0x3a,0xd6,0x3b,0xc3,0xc5,0xd6,0x35,0xf5,0xca,0xd0,0xf1,0xbd,0x27,0x74, +0xac,0xf7,0x85,0x5e,0x9f,0x93,0x65,0xf5,0x39,0x59,0xbe,0xbe,0x2b,0xcb,0xd7,0x7f, +0x65,0xf9,0xfa,0xb0,0x2c,0x5f,0x3f,0x96,0xe5,0xeb,0xcb,0xb2,0x7c,0xfd,0x59,0x96, +0xd5,0x27,0x65,0x59,0x7d,0x52,0x96,0xaf,0x6f,0xcb,0xf2,0xf5,0x6f,0x59,0xbe,0x3e, +0x2e,0xcb,0xd7,0xcf,0x65,0xf9,0xfa,0xba,0x2c,0x5f,0x7f,0x97,0x65,0xf5,0x19,0x59, +0x56,0x9f,0x91,0xe5,0xeb,0x7b,0xb2,0x7c,0xfd,0x4f,0x96,0xaf,0x0f,0xca,0xf2,0xf5, +0x43,0x59,0xbe,0xbe,0x28,0xcb,0xd7,0x1f,0x65,0x59,0x7d,0x4a,0x96,0xd5,0xa7,0x64, +0xf9,0xfa,0xa6,0x2c,0x5f,0xff,0x94,0xe5,0xeb,0xa3,0xb2,0x7c,0xfd,0x54,0x96,0xaf, +0xaf,0xca,0xf2,0xf5,0x57,0x59,0x56,0xfd,0xcd,0xb2,0xea,0x6f,0x96,0xaf,0x1d,0x64, +0xf9,0xda,0x42,0x96,0xaf,0x3d,0x64,0xf9,0xda,0x44,0x96,0xaf,0x5d,0x64,0xf9,0xda, +0x46,0x96,0x55,0xbf,0xb3,0xac,0xfa,0x9d,0xe5,0x6b,0x27,0x59,0xbe,0xb6,0x92,0xe5, +0x6b,0x2f,0x59,0xbe,0x36,0x93,0xe5,0x6b,0x37,0x59,0xbe,0xb6,0xe3,0xd5,0xb3,0x28, +0x69,0xa4,0xd5,0x9e,0xbc,0x7d,0x59,0x56,0xdb,0xf2,0xec,0x99,0x96,0x7a,0x75,0x26, +0x4a,0x1a,0x29,0x75,0xac,0x71,0x80,0xbb,0x14,0xce,0x8c,0x13,0x78,0xf7,0x03,0xcf, +0x6e,0x34,0x53,0x63,0x07,0x99,0x56,0x7b,0xf5,0xea,0x44,0x96,0xd5,0x76,0x3d,0x7b, +0xa6,0xa5,0x59,0xba,0x47,0x7a,0xf7,0x4d,0xef,0x7e,0xe4,0x58,0x63,0x0e,0xf7,0x2b, +0xdc,0xe2,0xb2,0x6a,0xeb,0x65,0xd5,0xf6,0xcb,0x1e,0xb9,0xb7,0x44,0x49,0x23,0xad, +0xb1,0x03,0xc7,0x37,0x1e,0xb1,0xc0,0xba,0x17,0xe5,0xb3,0xee,0x1f,0x51,0xd2,0x48, +0xa9,0x63,0x8d,0x73,0xfc,0xac,0x73,0xfe,0x5c,0xf6,0x88,0xdb,0xeb,0x9f,0xa3,0xa4, +0x91,0xd6,0x38,0x85,0xe3,0x1b,0xc7,0x58,0xaa,0xeb,0xb7,0xd4,0xba,0x27,0x64,0x5a, +0x61,0xbc,0xfe,0x3d,0x4a,0x1a,0x29,0x75,0xac,0xb1,0x95,0x29,0x3a,0x76,0xaa,0x9e, +0xd3,0xbc,0x71,0x9a,0x2e,0xce,0x91,0xfe,0xcd,0xab,0x93,0x59,0x56,0x5f,0xe7,0xd9, +0x33,0x2d,0xcd,0xd2,0x3d,0xcb,0xb1,0xc6,0x70,0xa6,0x59,0x7d,0xb7,0xe7,0x36,0xe1, +0x5e,0xd4,0xd8,0x90,0x39,0x77,0x10,0x4b,0x44,0xb9,0x23,0xf3,0x7c,0xfe,0x13,0x45, +0x15,0x2e,0x99,0xe3,0xe2,0x9d,0x63,0x63,0xf6,0x27,0x95,0xfb,0xff,0xa4,0x1e,0x83, +0xf2,0x8e,0x8b,0x39,0x26,0x44,0x9c,0xf5,0x9d,0x23,0x78,0xfb,0xea,0x1f,0x23,0x3e, +0x13,0x3e,0x41,0x73,0x24,0xcc,0x1c,0xa2,0x54,0x48,0x83,0x1a,0x50,0x13,0xd2,0xa1, +0x2a,0x14,0xaf,0xe0,0x38,0x75,0xcd,0x98,0x1a,0x9c,0xab,0xb1,0xec,0x04,0xcd,0x45, +0xf2,0xe6,0x21,0x9d,0xcc,0xf1,0x5d,0xf5,0x5e,0x75,0x80,0xc6,0xe1,0xcc,0xfb,0xd5, +0x2b,0xf4,0x5e,0xb5,0xaf,0xde,0xad,0x9a,0x73,0x64,0x6b,0xac,0x6e,0x88,0xde,0xd7, +0x0e,0xd6,0xb1,0xd5,0x1d,0xf7,0x7d,0xa1,0x67,0x37,0xfe,0xe6,0x5d,0xe2,0x4c,0x69, +0x77,0xf9,0x0f,0xb0,0xec,0xe6,0xb9,0x7e,0x42,0xc0,0x0d,0x63,0xde,0xd3,0xf5,0xd2, +0xbb,0x62,0x8f,0xdc,0x77,0x6c,0x01,0xf7,0xb7,0x5a,0x33,0xbd,0x37,0xee,0xab,0xf7, +0xc6,0xe7,0x2b,0x2e,0xf3,0xbe,0xa7,0x8d,0xd2,0xe2,0xd1,0x56,0xef,0x97,0x2f,0xd4, +0x7b,0xe8,0xf3,0x64,0x6f,0xa9,0x71,0xea,0x69,0x7a,0x0f,0xd0,0xc2,0x39,0x32,0x06, +0x9d,0xa9,0x74,0xf6,0xd0,0x31,0x8d,0x15,0xde,0x9c,0x63,0x6d,0xc8,0x71,0xde,0x85, +0x75,0xb0,0x3e,0xe4,0x5e,0x9b,0xc6,0x3a,0xd6,0xbc,0x8f,0x58,0xa2,0xf7,0xc3,0xf7, +0xc0,0x64,0x28,0x56,0xc1,0x7d,0xdf,0xe9,0xbd,0xab,0xf6,0xe6,0xbb,0x78,0xf3,0xc4, +0x6a,0x58,0xf6,0x74,0xcb,0x9e,0x68,0x5d,0x43,0xe3,0x4e,0xd6,0xb5,0xf4,0xec,0x9e, +0x7f,0xaa,0xe5,0x9f,0x6a,0xcd,0x39,0x4b,0xd5,0x35,0xf7,0xec,0x5e,0xf8,0x34,0xd5, +0x03,0xcf,0xee,0xf9,0xd7,0xb4,0x8e,0xad,0x69,0x85,0xa9,0xa9,0xfa,0xe2,0xd9,0xbd, +0xf0,0xde,0x75,0x38,0x16,0xed,0x2d,0x9a,0x59,0xea,0xb7,0x7b,0x5c,0x64,0xd1,0xcc, +0x52,0xef,0x3a,0x37,0xd4,0x38,0x42,0x4b,0x95,0x5f,0x5e,0x0c,0xb5,0xe8,0x6d,0xa9, +0xdf,0xee,0x31,0xdc,0xa2,0xb7,0xa5,0xbd,0x55,0xb7,0xba,0xeb,0xba,0xf5,0xd3,0xb5, +0xf0,0xca,0x7e,0x02,0x0d,0xb6,0xa6,0x99,0xfb,0x20,0xbd,0x57,0xba,0x56,0xfa,0x9e, +0x74,0x9d,0x34,0xa2,0x82,0xab,0xf9,0xa4,0x05,0xa4,0xb1,0xd2,0x73,0xa4,0x55,0x2b, +0xfc,0x7f,0xe2,0x8f,0x41,0x1d,0x85,0x6f,0x28,0xcd,0x92,0x36,0x95,0x9a,0xb6,0x6c, +0xb4,0xab,0xdc,0x2d,0xa5,0x75,0xe4,0x5f,0x4f,0x7a,0xb9,0xfc,0x7b,0x48,0x07,0x49, +0x07,0x4b,0x87,0x4a,0x87,0x49,0xaf,0x91,0x5e,0x2b,0x1d,0x2d,0x1d,0x23,0xbd,0x49, +0x7a,0xb3,0xf4,0x71,0xe9,0x54,0xe9,0x34,0xe9,0x74,0xe9,0x08,0xe9,0x75,0xd2,0xbb, +0xa4,0x77,0x4b,0x67,0x4b,0xe7,0x48,0x5f,0x94,0xce,0xf5,0xca,0x93,0x8b,0x12,0x93, +0x70,0x62,0xfd,0x9c,0xdd,0x9e,0x12,0xad,0xbe,0x31,0xd1,0x39,0xd2,0x9e,0xbc,0xf9, +0x9b,0x5e,0x7b,0xf1,0xda,0x87,0xd7,0x46,0xbd,0xfa,0x9f,0xae,0x63,0x13,0xd4,0x67, +0x26,0xaa,0xdf,0xac,0x2c,0x7f,0xcf,0x9e,0x6c,0xd9,0x53,0x2c,0x7b,0xaa,0x65,0x4f, +0xb3,0xec,0x35,0x2c,0x7b,0x4d,0xcb,0x9e,0x6e,0xd9,0xbd,0x7c,0xd8,0xee,0x44,0x9f, +0x3b,0xc9,0xe7,0x4e,0xf6,0xb9,0x53,0x7c,0xee,0x54,0x9f,0x3b,0xcd,0xe7,0xae,0xe1, +0x73,0xd7,0xf4,0xb9,0xd3,0x7d,0xf9,0xf7,0xd2,0x97,0xa8,0x7b,0x65,0x92,0x34,0x59, +0x9a,0x22,0x4d,0x95,0xa6,0x49,0x6b,0x48,0x6b,0x4a,0xd3,0xa5,0x5e,0x9e,0xe3,0xad, +0xfc,0xc6,0x5b,0x79,0x8d,0xb7,0xf2,0x19,0x6f,0xe5,0x31,0xde,0xca,0x5f,0xbc,0x95, +0xb7,0x78,0x2b,0x5f,0xf1,0x56,0x9e,0xe2,0xad,0xfc,0xc4,0x5b,0x79,0x89,0x57,0xde, +0xba,0x5a,0xf9,0xec,0x66,0xd9,0xbb,0x5b,0xf6,0xcb,0x2d,0x7b,0x0f,0xcb,0xde,0xd3, +0xb2,0xf7,0xb2,0xec,0x57,0x58,0xf6,0xde,0x96,0xfd,0x4a,0xcb,0xde,0xc7,0xb2,0xf7, +0xb5,0xec,0xfd,0x2c,0x7b,0x7f,0xcb,0x3e,0xc0,0xb2,0x67,0x5b,0xf6,0x81,0x96,0x7d, +0x90,0x65,0x1f,0x6c,0xd9,0x87,0x58,0xf6,0xab,0x2c,0xfb,0x50,0xcb,0x3e,0xcc,0xb2, +0x0f,0xb7,0xec,0x57,0x5b,0xf6,0x6b,0x64,0x6f,0xe0,0x1c,0xb9,0x9f,0x36,0xb2,0xee, +0xa7,0x27,0x32,0x16,0x6c,0xdf,0xcf,0xdb,0x5a,0xe3,0xc1,0xed,0x35,0x26,0x6c,0xee, +0x13,0x1d,0x75,0x1f,0xef,0xaa,0x6b,0xd2,0xdd,0xba,0xd7,0xf6,0x54,0x59,0x5f,0x61, +0xdd,0x77,0xfd,0xcf,0x30,0x03,0x54,0x46,0x03,0x55,0x26,0x83,0xad,0xf1,0xe1,0xa1, +0xca,0xeb,0x70,0xe5,0xed,0x1a,0xd5,0x07,0x7f,0x1f,0x5d,0xcb,0x71,0xa9,0x9b,0x07, +0x1f,0x57,0x71,0xfb,0xab,0x2b,0x95,0xf6,0xae,0x71,0x8e,0xb3,0x86,0x84,0x3c,0xf6, +0x98,0x9b,0xd9,0xca,0x90,0x06,0xf5,0xa1,0x23,0x8c,0x85,0xdb,0x61,0x32,0xbc,0x6c, +0xfc,0x29,0x84,0x1e,0xd0,0x07,0x46,0xc3,0x7d,0x30,0x1d,0xb6,0xc0,0xb7,0x2a,0xa0, +0x87,0xe0,0x20,0x94,0xa2,0xa0,0xce,0x80,0x9a,0xd0,0x00,0x2e,0x81,0xde,0x30,0x1a, +0x5e,0x82,0x95,0xb0,0x0d,0x36,0x90,0x90,0xb2,0x14,0xe2,0x6e,0x0a,0x31,0x48,0x21, +0xe6,0x87,0x52,0x50,0x09,0x06,0x43,0xeb,0x4e,0x8e,0x33,0x12,0x7e,0x80,0x22,0x97, +0x38,0x4e,0x05,0xa8,0x09,0xfd,0x61,0x20,0x6c,0xba,0xd4,0x71,0x3e,0x83,0xfd,0xf0, +0x33,0x0c,0xba,0x8c,0xf2,0x81,0x1b,0xe0,0x1b,0xf8,0x19,0x0a,0x74,0xe6,0xb7,0x03, +0xb4,0x86,0xae,0x30,0x18,0x5e,0x83,0x7c,0x5c,0xa8,0x34,0x68,0x01,0xd5,0xb9,0x50, +0x29,0x70,0x33,0xdc,0x0f,0x4f,0xc2,0x02,0xd8,0x02,0x9f,0xc1,0x3e,0x2e,0x62,0x3e, +0x2e,0x62,0x65,0x28,0x47,0x99,0x75,0x83,0xab,0x61,0x0e,0xac,0x86,0xf7,0x60,0x13, +0x14,0xe1,0xa2,0x96,0x84,0x14,0xe8,0xc3,0x05,0xad,0xc2,0xc5,0x4c,0x83,0xda,0x50, +0x1f,0x9a,0x40,0x47,0xe8,0x04,0xcf,0xc1,0x8d,0x5c,0xe8,0x5b,0x20,0x87,0x8b,0xbd, +0x03,0x4e,0xe3,0x82,0x97,0x85,0xca,0x90,0x00,0xb7,0xc1,0xdd,0x30,0x94,0x4a,0x70, +0x1d,0xbc,0x00,0x8b,0xe1,0x2b,0xd8,0x44,0xa5,0xd8,0x0a,0x07,0xa0,0x16,0x15,0x63, +0x3e,0x2c,0x82,0x21,0x54,0x90,0xd5,0x70,0x10,0x06,0x8f,0xa0,0xec,0x20,0xed,0x06, +0xea,0x30,0xdc,0x0a,0x0b,0x21,0x30,0xd2,0x71,0x0a,0x42,0x71,0x48,0x86,0x1b,0xe0, +0x16,0xd8,0x36,0xca,0x71,0x76,0xc1,0x01,0x38,0x0c,0x05,0x47,0x3b,0x4e,0x69,0x28, +0x0b,0xfd,0x61,0x10,0x0c,0x87,0x96,0x37,0x91,0x3f,0xc8,0x18,0x47,0x7b,0x81,0xee, +0x70,0xfd,0x2d,0xa4,0x17,0xd6,0x81,0x73,0x2b,0xfd,0xda,0xed,0xb4,0x31,0x68,0x07, +0xc3,0xe1,0x11,0xb8,0xfc,0x0e,0xea,0x39,0xcc,0x81,0xe9,0x77,0x3a,0xce,0x2a,0x78, +0x68,0x3c,0xcf,0xdb,0x30,0x17,0xee,0x9a,0x40,0x5b,0xbc,0xcb,0x71,0x96,0xc3,0x5b, +0xf0,0x2e,0x0c,0x9b,0x48,0x1d,0x80,0x33,0xef,0xa3,0xee,0xc0,0x02,0xd8,0x09,0x6d, +0xee,0x77,0x9c,0xcb,0xa0,0x1b,0xf4,0x86,0xd5,0xb0,0x07,0x0e,0x40,0xe0,0x01,0xee, +0xf7,0xb0,0x09,0x36,0xc3,0x7d,0x93,0xf8,0x2d,0x0a,0xcf,0xc1,0xd4,0x07,0x1d,0x67, +0x23,0x6c,0x86,0x73,0x1e,0xe2,0xda,0x43,0x12,0xd4,0x81,0x8b,0xe1,0xb3,0x87,0x69, +0x77,0x8f,0x52,0x26,0xf0,0x14,0xbc,0x02,0xaf,0xc1,0x1a,0x78,0x17,0x0e,0xc2,0x4f, +0x50,0x98,0x76,0x53,0x02,0xca,0x41,0x6d,0x68,0x0e,0x17,0xc0,0x1d,0xf0,0x30,0x4c, +0x7e,0xcc,0xfd,0xed,0x54,0x3c,0xc1,0x6d,0x03,0x8d,0x20,0x0b,0x5a,0xe0,0x9e,0x04, +0x2d,0xa5,0xad,0xa4,0x6d,0xa4,0x6d,0xa5,0xed,0xa4,0x1d,0xa4,0x1d,0xa5,0x9d,0xa4, +0x97,0x4a,0x3b,0x4b,0xbb,0x4a,0x2f,0x97,0xf6,0x94,0x5e,0x21,0x1d,0x60,0xe9,0x83, +0x30,0x48,0xee,0x41,0x72,0x5f,0x25,0xf7,0x55,0x72,0x0f,0x97,0x7b,0xb8,0xdc,0xd7, +0xca,0x7d,0xad,0xdc,0x8d,0xe5,0x36,0x79,0xf4,0xd4,0xf8,0x3f,0x22,0xff,0x71,0x70, +0x2b,0x4c,0x97,0xfb,0x79,0xe9,0x0c,0xe9,0x2c,0xe9,0x1c,0xe9,0x5c,0xe9,0x3c,0xe9, +0x02,0xe9,0x2b,0xd2,0x85,0xd2,0xc5,0xd2,0xa5,0xd2,0xd7,0xa5,0xcb,0xa5,0x2b,0xa5, +0xef,0x58,0x6a,0xd2,0xb5,0x4e,0xee,0x75,0x72,0xbf,0x2f,0xf7,0xfb,0x72,0x6f,0x94, +0x7b,0xa3,0xdc,0x9b,0xe4,0xde,0x24,0xf7,0xd3,0x72,0xef,0x95,0xee,0x93,0xee,0x97, +0x7e,0x2d,0xfd,0xc9,0xca,0x97,0x49,0x8b,0x53,0x8c,0xfa,0x08,0xcf,0x42,0x10,0x9e, +0x83,0xe7,0x21,0x02,0x22,0x21,0x04,0x33,0x61,0x16,0xcc,0x86,0x39,0xf0,0x22,0xcc, +0x85,0x33,0x20,0x0a,0xa2,0x21,0x1f,0x94,0x87,0x18,0xc8,0x0f,0x05,0xa0,0x20,0x14, +0x82,0xc2,0x50,0x04,0x8a,0x42,0x31,0x28,0x0e,0x5d,0xa1,0x1b,0x74,0x87,0xcb,0xa1, +0x07,0xf4,0x84,0x5e,0x70,0x05,0xf4,0x86,0x2b,0xa1,0x0f,0xf4,0x85,0x7e,0xd0,0x1f, +0x06,0x40,0x36,0x0c,0x84,0x41,0x30,0x18,0x86,0xc0,0x55,0xd0,0x05,0x4a,0x42,0x29, +0x58,0x01,0x2b,0xe1,0x2d,0x78,0x1b,0xd6,0xc3,0x06,0xf8,0x10,0xce,0x84,0x8f,0x61, +0x33,0x9c,0x05,0x65,0xa0,0x1c,0x54,0x80,0x58,0xa8,0x04,0xe7,0x42,0x55,0xa8,0x06, +0x71,0x10,0x0f,0xd5,0x21,0x09,0xd2,0x20,0x03,0x9a,0xc0,0x79,0xb0,0x1f,0xbe,0x86, +0x0e,0x70,0x11,0x74,0x84,0x1b,0x61,0x2c,0x8c,0x83,0xbb,0xe0,0x6e,0xb8,0x17,0x1e, +0x85,0x29,0xc5,0xdc,0x7b,0x9a,0xb9,0x7f,0xc5,0xc0,0x26,0xee,0x33,0xf9,0xd1,0x38, +0x28,0x00,0x49,0x57,0xb9,0xf7,0xb8,0xd3,0x21,0x00,0xe7,0x72,0xaf,0x49,0xe8,0xe0, +0xde,0xe7,0xcc,0x73,0x83,0xb9,0x66,0xde,0x33,0x44,0xd0,0xb2,0x47,0x58,0xf6,0x90, +0x65,0x8f,0xb2,0xec,0xd1,0x96,0x3d,0xc6,0xb2,0x17,0xb0,0xec,0x05,0x2d,0x7b,0x61, +0xcb,0x5e,0xc4,0xb2,0x17,0xb5,0xec,0xc5,0x2c,0x7b,0x71,0xcb,0xee,0xe8,0x3a,0xdb, +0x69,0xed,0xea,0x4b,0x6f,0x57,0x5f,0x9a,0xbb,0xfa,0xd2,0xdd,0xd5,0x97,0xf6,0xae, +0xbe,0xf4,0x77,0xf5,0xe5,0xa1,0xab,0x2f,0x1f,0x5d,0x7d,0x79,0xe9,0xea,0xcb,0x4f, +0x57,0x5f,0x9e,0xba,0xfa,0xf2,0xd5,0xd5,0x97,0x37,0x7f,0xfc,0xfd,0x7d,0xe7,0xef, +0xad,0x7a,0x6f,0xea,0xf3,0xf4,0x63,0xec,0x2b,0xee,0x3b,0xc6,0xd4,0x03,0xcf,0x7e, +0xbb,0x65,0x8f,0xb1,0xec,0xa6,0x7e,0x78,0xf6,0x7b,0x2d,0xff,0x7e,0x6d,0xac,0xb2, +0xb4,0xfc,0xfb,0x58,0xfe,0x97,0x5a,0xfe,0xa6,0x9f,0xf7,0xec,0xe6,0x79,0xe1,0xd7, +0xf0,0xd9,0xd6,0x6f,0xb0,0xbe,0x47,0xec,0x95,0xad,0x30,0xe6,0x5e,0xe7,0xd9,0xcd, +0x33,0x91,0x67,0x37,0xcf,0x1f,0x9e,0xbd,0xca,0x15,0x56,0xfa,0xad,0x63,0xeb,0x5d, +0x7d,0xc4,0x5e,0xe8,0x42,0xeb,0x59,0x78,0xd0,0x11,0xfb,0x94,0xdb,0xad,0x34,0x5b, +0xe1,0x5f,0xbc,0xe0,0x88,0x7d,0x9b,0x95,0x97,0x11,0x56,0x3c,0x3d,0x3b,0x59,0x61, +0x86,0x1e,0xb1,0x07,0x5a,0x1d,0xb1,0xaf,0xb0,0xe2,0xbf,0xd0,0x2a,0x87,0x7e,0xd6, +0xb9,0x8a,0x59,0xe1,0xcd,0x73,0x86,0x67,0x3f,0x20,0x7b,0x2b,0x1e,0xac,0x47,0x5c, +0xe6,0x3e,0x87,0x8d,0xbf,0xd6,0x7d,0xf6,0xf6,0xde,0x99,0x25,0x59,0xbf,0xb5,0x92, +0xac,0xdf,0xda,0x49,0xfa,0x9d,0x95,0xe4,0x1c,0x79,0x0f,0x95,0x26,0xad,0x21,0xad, +0x29,0x4d,0xd7,0x31,0x09,0xd6,0xef,0xed,0x64,0x2b,0xae,0x64,0xeb,0xf7,0x7b,0xb2, +0xe2,0x73,0xd4,0x6f,0x47,0xa8,0xaf,0xf6,0xfa,0xe3,0x18,0xab,0x0f,0x3e,0x56,0xff, +0xeb,0xb5,0x4d,0xaf,0x4d,0x7a,0x6d,0xd1,0x6b,0x83,0x5e,0xdb,0xf3,0xda,0x9c,0xd7, +0xd6,0xbc,0x36,0xe6,0xb5,0x2d,0xaf,0x4d,0x79,0x6d,0xc9,0x6b,0x43,0x5e,0xdb,0x29, +0xee,0x0b,0x37,0x4f,0xe7,0xf6,0xda,0x49,0x7f,0xc5,0x39,0x44,0xda,0xff,0x18,0x7d, +0xa3,0xa9,0xf3,0xa6,0xae,0x9b,0x3a,0x6e,0xea,0xb6,0xa9,0xd3,0xa6,0x2e,0x9b,0x3a, +0x6c,0xea,0xae,0xa9,0xb3,0xa6,0xae,0x9a,0x3a,0x6a,0xea,0xa6,0xa9,0x93,0xa6,0x2e, +0x9a,0x3a,0x68,0xea,0x9e,0xa9,0x73,0xa6,0xae,0x99,0x3a,0x66,0xea,0x96,0xa9,0x53, +0x1b,0xd1,0x1a,0x57,0xb9,0xcf,0xf1,0xbd,0x79,0xae,0xab,0x42,0xbc,0xd9,0xc4,0xb9, +0x93,0xb8,0x42,0x0f,0xb8,0x75,0x61,0x12,0x7e,0xdd,0xfb,0x1c,0xdd,0x37,0xef,0xe0, +0x39,0xfe,0x00,0xe1,0x6a,0xc3,0xfd,0x9d,0xdc,0xba,0x67,0xea,0x9c,0xa9,0x6b,0xa6, +0x8e,0x99,0xba,0x75,0x66,0x47,0xf7,0xfa,0xa4,0xe9,0x3a,0xd5,0x90,0x7a,0xef,0x0f, +0xd3,0x75,0x0d,0x13,0xac,0xf7,0x29,0x29,0x56,0x5d,0xf1,0xae,0x71,0x8a,0xf5,0xae, +0x26,0x45,0xf1,0xa5,0x28,0xbe,0x14,0xc5,0x97,0xa2,0xf8,0x52,0xad,0x77,0x37,0xa6, +0x5c,0x92,0xa4,0xc9,0xd2,0x14,0x69,0xaa,0x34,0x4d,0x5a,0x43,0x5a,0x53,0x9a,0x2e, +0xf5,0xde,0x27,0x78,0xf6,0x44,0xcb,0xee,0xc5,0xdd,0x54,0xbf,0x1d,0x7b,0xe8,0x77, +0xa1,0x67,0x6f,0x6f,0xbd,0x43,0x36,0xbf,0x67,0x1f,0x27,0xa2,0x27,0xf5,0x8c,0x32, +0x15,0x9e,0xd5,0x73,0xd7,0xf3,0x7a,0xde,0x9a,0xa5,0xe7,0x91,0xb9,0x7a,0xbe,0x5a, +0xa0,0xe7,0xaa,0x85,0x7a,0x9e,0x5a,0xaa,0xe7,0xa8,0xe5,0x7a,0x66,0x59,0x05,0xab, +0xe1,0x2d,0x58,0x03,0x6f,0xeb,0x39,0x6a,0x9d,0x9e,0x97,0x36,0xea,0xb9,0xe8,0x13, +0xd8,0x0c,0x5b,0xe0,0x53,0xd8,0x0a,0xdb,0x61,0x07,0xec,0x84,0x2f,0x60,0x17,0xec, +0x86,0x2f,0x61,0x8f,0x9e,0x9f,0xf6,0xe9,0xb9,0xc9,0x3c,0x33,0x6d,0x37,0x75,0xf1, +0x42,0x37,0x0f,0xde,0xb3,0xda,0x61,0xa5,0xe3,0x71,0x1d,0x6b,0xce,0x39,0x45,0xee, +0x03,0xd6,0x33,0xda,0xe3,0xe2,0xb0,0xc2,0x3d,0xa9,0x74,0x1f,0xb0,0x9e,0x33,0x9f, +0x94,0x7b,0xa9,0xca,0x67,0x9a,0xdc,0x53,0x55,0x0e,0x33,0xac,0xf3,0x4d,0x92,0xff, +0x61,0x95,0xdf,0x61,0x95,0xe5,0x01,0x85,0x7d,0x56,0x7e,0x5b,0xb4,0xff,0x49,0xe5, +0x6f,0xba,0xf2,0xfa,0x9a,0xe2,0x99,0xae,0xbc,0xee,0xb2,0xe2,0x9a,0x24,0xbf,0x03, +0x96,0xfb,0x80,0xca,0xd0,0x7b,0x36,0xf6,0x3f,0x2b,0xaf,0xd6,0xf1,0xc6,0xfd,0x99, +0x15,0x9f,0xb7,0x7f,0xb7,0xf5,0x3c,0xec,0xf9,0xef,0xb1,0xd4,0x2b,0x83,0x2f,0x94, +0x66,0xcf,0xff,0x53,0x2b,0xcf,0xbb,0x2d,0xff,0xbd,0x56,0x1e,0xfc,0xc7,0xfa,0xdd, +0x2b,0xad,0x72,0xde,0x6d,0x3d,0xa7,0x3f,0x69,0x9d,0x7b,0x8f,0xce,0xb3,0x46,0x75, +0xf0,0xb0,0xca,0x71,0x8e,0x8e,0x59,0x25,0xfb,0x61,0xeb,0x39,0x7b,0xae,0xe2,0xf0, +0xe2,0x9d,0x6b,0x5d,0x3f,0xaf,0xec,0xe7,0xa9,0x2c,0xec,0xeb,0xfc,0x8a,0x15,0xce, +0xb3,0xaf,0xf4,0x95,0xcf,0x02,0xeb,0x77,0xc2,0x3c,0xeb,0x9a,0xef,0xb6,0xf2,0xb3, +0x4a,0xf5,0xfd,0x6d,0xab,0x2c,0xde,0x51,0x9a,0x5e,0xf7,0xd5,0x51,0xfb,0x3c,0xb6, +0xff,0xeb,0xd6,0xef,0x8f,0xc3,0xaa,0xfb,0xbb,0xad,0xdf,0x1e,0x8f,0x2b,0x2d,0x2b, +0x7d,0xfe,0x33,0x7c,0xee,0x39,0xd6,0xef,0x16,0xbb,0x1d,0xd8,0x75,0xcd,0xfb,0x0d, +0xf3,0x84,0x75,0x4d,0xbd,0xdf,0x36,0xaf,0x29,0x9f,0xcf,0x58,0xc7,0x7f,0x61,0xb5, +0xa1,0x19,0x2a,0x1f,0xaf,0xfd,0x78,0xed,0x6a,0xa1,0x65,0x5f,0xad,0x34,0x6c,0x54, +0x98,0xd7,0xad,0x7d,0x5e,0xbb,0xd8,0x68,0xe5,0x7d,0x9e,0xf5,0x3b,0xca,0xcb,0xff, +0x62,0xeb,0xfa,0x3e,0x69,0x95,0xd9,0x26,0x5f,0xf9,0x6f,0xd2,0xbe,0x4d,0x56,0xfc, +0x2b,0xad,0xdf,0x61,0x5e,0x3a,0x3d,0xbb,0xd7,0x7e,0x9e,0xb4,0xea,0x9b,0xe7,0xde, +0x2d,0xfb,0x6b,0xba,0x16,0x9f,0xc8,0x6f,0x86,0xec,0x07,0x94,0xd6,0xcf,0x65,0xdf, +0x6c,0xc5,0xe1,0xb9,0x77,0x59,0x6a,0x5f,0xcf,0xdd,0x6a,0x43,0x5e,0x7b,0xb5,0xed, +0x5e,0x3d,0xf2,0xb7,0xb1,0xed,0xbe,0x7e,0x66,0xbb,0x15,0xd7,0x0e,0xab,0x6f,0xdb, +0x65,0x5d,0xdb,0xdd,0x72,0x7f,0xe1,0xab,0x17,0xde,0x71,0x87,0xad,0x6b,0xed,0xf5, +0xb1,0x5b,0xa4,0x5e,0xd9,0xcd,0xb2,0xfa,0x1a,0xbb,0x7d,0x9b,0x7b,0xcf,0x82,0x6c, +0xf7,0x7e,0x63,0x34,0x49,0x9a,0x2c,0x4d,0x91,0xa6,0x4a,0xd3,0xa4,0x35,0xa4,0x35, +0xa5,0xe9,0x56,0x3c,0x76,0x9c,0x89,0x96,0x3d,0xc9,0xb2,0x27,0x5b,0xf6,0x14,0xcb, +0x9e,0x6a,0xd9,0xd3,0x2c,0x7b,0x0d,0xcb,0x5e,0xd3,0xb2,0xa7,0x5b,0xe9,0x4e,0xb0, +0xec,0x76,0x7e,0x92,0x2c,0x7b,0xb2,0x65,0xf7,0xce,0x7b,0x85,0xde,0xef,0x76,0xd5, +0xfb,0xda,0xae,0x7a,0x57,0xdc,0x4e,0xef,0x71,0xbb,0xea,0xbe,0x3b,0x40,0xf7,0xdc, +0x6c,0xdf,0x78,0x9c,0xa7,0x49,0x96,0x3d,0x59,0xef,0x93,0x4d,0x1c,0x83,0x79,0x96, +0x2d,0x4a,0x44,0x71,0x3d,0xdd,0x7b,0x9c,0x79,0xaf,0x69,0x9e,0x77,0x0a,0xe3,0x7e, +0xa5,0xaf,0xfb,0x0c,0x55,0xa4,0x33,0xbf,0xf3,0x5b,0xb9,0xcf,0x51,0xd9,0x3a,0x7f, +0x7f,0xe9,0xab,0x9a,0xe7,0xdc,0x4f,0xee,0x3e,0xd2,0x16,0x7a,0x9f,0xdd,0x52,0xda, +0x44,0xea,0x8d,0x77,0xf7,0x55,0x58,0xdb,0x9d,0xad,0x77,0xde,0xfd,0xa5,0xaf,0x46, +0x1c,0xd1,0x5e,0x3a,0x87,0xf7,0xdd,0x92,0x37,0xee,0x7d,0x8d,0xdc,0x9e,0xbd,0xa5, +0x65,0x6f,0x62,0xd9,0x2f,0xb4,0xec,0xaf,0x46,0x1c,0x79,0xb7,0xdd,0x57,0xe5,0xd2, +0xd7,0x7a,0xe7,0xdd,0xd3,0x7a,0xef,0xdd,0x4f,0xe1,0xfb,0x39,0x47,0xe8,0x2e,0xed, +0xe3,0x1c,0xed,0x9f,0x64,0xed,0x4b,0xb2,0xb4,0x8f,0xcf,0xcf,0xbb,0x06,0xdd,0x2d, +0xbb,0xa7,0x7d,0x7c,0x7e,0xa5,0x2a,0xb8,0xef,0xda,0x6d,0x7b,0x92,0x55,0x27,0xfa, +0x58,0xf6,0x96,0x96,0xbd,0x89,0x65,0x1f,0x64,0xd5,0x1f,0xdb,0xee,0xc5,0x77,0x2c, +0xbf,0x24,0x6b,0xde,0x42,0x7f,0xe9,0xab,0x11,0x47,0xd2,0x32,0x58,0xfb,0xdb,0x6b, +0x7f,0x7b,0xed,0x6f,0xaf,0xfd,0xed,0x95,0xb6,0xf6,0x4a,0x97,0x57,0x37,0x3b,0x28, +0x7c,0x07,0x85,0xef,0xa0,0xf0,0x1d,0x14,0xbe,0x83,0xc2,0x7b,0xee,0x69,0xfa,0xbe, +0x66,0x9a,0xe6,0xd0,0xc7,0x2b,0x7c,0xbc,0xea,0xd3,0x40,0x95,0x63,0x77,0xab,0xde, +0x37,0x54,0x3e,0xbc,0x7a,0xd2,0x50,0xed,0x23,0x5e,0xfb,0xbd,0xfa,0x78,0xb5,0xc6, +0x3c,0xba,0xaa,0x6e,0xb4,0xd6,0xf8,0x47,0x7f,0xd5,0x5f,0x8f,0x96,0x4a,0xcb,0x10, +0xe7,0xe8,0x7a,0xd3,0x5f,0x3a,0x40,0xe7,0xe9,0xab,0x31,0x90,0x7e,0x6a,0x9b,0xfd, +0xac,0x31,0xf2,0x7e,0x0a,0xd7,0x57,0xe7,0x69,0xaa,0xf2,0xb0,0xf3,0xd3,0x5a,0x78, +0xd7,0xd1,0x9b,0x2b,0x32,0x48,0xe3,0x3a,0x43,0x55,0x2e,0xdd,0x54,0x9e,0x26,0x8f, +0x5e,0xbb,0xf3,0xec,0x89,0xfa,0x3d,0x9e,0x24,0x4d,0x96,0xa6,0x48,0x53,0xa5,0x69, +0xd2,0x1a,0xd2,0x9a,0xd2,0x74,0xa9,0xd7,0x57,0x7a,0xf6,0x44,0xcb,0x9e,0x64,0xd9, +0x93,0x2d,0x7b,0x8a,0x65,0x4f,0xb5,0xec,0x69,0x96,0xbd,0x86,0x65,0xaf,0x69,0xd9, +0xd3,0xad,0x74,0x27,0x58,0x76,0x3b,0x3f,0x49,0x96,0x3d,0xd9,0xb2,0xa7,0x58,0xf6, +0x54,0xcb,0x9e,0x66,0xd9,0x6b,0x58,0xf6,0x9a,0x96,0x3d,0xdd,0x2a,0xa7,0x04,0xcb, +0xee,0x9d,0xb7,0x97,0xd5,0x3f,0x35,0x8f,0xe4,0x37,0x0d,0x0c,0x78,0xc6,0xad,0x53, +0x8d,0x35,0xee,0x56,0x31,0xc0,0xf5,0x81,0x4a,0xf8,0xd7,0x98,0x4e,0x5d,0x09,0x72, +0xed,0xd0,0x3b,0xd0,0xa6,0xfc,0x1e,0xfc,0xa6,0xa7,0x3b,0x8e,0xb0,0x12,0xfb,0xbb, +0x54,0x9a,0x24,0x7e,0x4f,0x7c,0xd6,0xd6,0x7d,0x07,0x6f,0x68,0xd3,0xd1,0xfd,0xdd, +0x7a,0x33,0x1d,0x72,0x53,0xec,0xdf,0x71,0xc2,0xde,0x5c,0xec,0xb1,0x37,0x38,0x4e, +0xfd,0x9b,0x1c,0xe7,0xe5,0x9b,0x1d,0xe7,0x87,0x71,0x8e,0x33,0x9e,0xdf,0xa8,0xc1, +0x2b,0x1d,0xa7,0x34,0x17,0xfa,0x43,0x2a,0xcf,0x27,0x54,0x8e,0xba,0x37,0x3a,0xce, +0x95,0x1c,0xbb,0x7f,0x92,0xe3,0x8c,0x26,0xde,0xab,0x88,0x37,0x92,0xca,0x5a,0x9a, +0x4a,0x13,0xc7,0xb1,0x65,0x1e,0xa5,0x2e,0xf1,0x7b,0x75,0x37,0x95,0x6f,0xcd,0x58, +0xea,0xff,0x2d,0x8e,0xf3,0x26,0x15,0x68,0xe3,0x28,0x7e,0x27,0x13,0xe7,0x2a,0xfa, +0xff,0x53,0xc9,0xe4,0x95,0xc4,0x79,0x98,0x63,0xde,0xe6,0x1c,0x37,0xd1,0xd7,0xcf, +0x23,0x63,0x9f,0x50,0x01,0x5f,0xa7,0xc1,0xac,0xe7,0x9c,0x45,0xd9,0xf7,0xf9,0x50, +0x77,0x5c,0x26,0x8a,0x78,0x2f,0x81,0xbd,0x77,0x90,0x97,0xfb,0x29,0x8f,0x87,0x1c, +0xe7,0xd0,0x23,0xdc,0x3f,0xa8,0xfc,0x37,0xd0,0xa8,0x26,0x5f,0xc7,0x39,0xc6,0x90, +0x8e,0x7b,0xdc,0x31,0x8a,0x0f,0x6e,0xe5,0x19,0xe5,0x22,0xdc,0xdc,0x47,0xba,0x8c, +0x70,0x9c,0xeb,0x89,0xa3,0x1b,0xf1,0xad,0x22,0xfc,0x32,0xca,0xe4,0xfb,0xfb,0x48, +0x0f,0xfb,0xbb,0x5d,0xe2,0x38,0x25,0x38,0xd7,0x47,0xa4,0xa5,0x08,0xe9,0xad,0x4e, +0x3c,0x35,0xae,0xa7,0x0d,0xb2,0x7f,0x1d,0x69,0xb9,0x8d,0xe3,0x72,0x48,0xd7,0x5b, +0x70,0x26,0x1d,0xf9,0x22,0xf6,0xef,0xe7,0x3c,0x57,0xb1,0x7f,0xe4,0x6d,0x3c,0xff, +0x74,0x73,0xcb,0xe7,0x67,0xce,0x97,0x4e,0x59,0x7c,0xce,0xef,0xf2,0xe2,0x5d,0x28, +0x57,0xca,0x29,0x9b,0xdf,0xf9,0xa7,0x52,0x36,0x3f,0x72,0xce,0xc5,0xe4,0x6f,0x1a, +0x69,0x29,0x44,0x98,0xb7,0xb8,0xb0,0xc3,0xb9,0xce,0x15,0x88,0xeb,0x35,0xf6,0x5f, +0x46,0x3a,0x02,0xc3,0xb8,0x3f,0x52,0xae,0xcf,0x12,0xcf,0xcb,0x7d,0xdc,0xb1,0x9f, +0x71,0x84,0xfb,0x99,0xf8,0x3f,0x1b,0x4d,0xfe,0xe8,0x68,0x7a,0x10,0xdf,0x0b,0x1c, +0xdf,0x9b,0xb4,0xbc,0x09,0xa3,0xe8,0x48,0x3e,0x27,0x6f,0x03,0xd8,0xbf,0x8e,0xe3, +0xde,0xe1,0x9a,0x7c,0x4b,0x9a,0x33,0x2f,0x74,0xdf,0x2f,0x7c,0x49,0x39,0xbf,0xc1, +0x79,0x7e,0x26,0x5f,0x55,0x28,0xa3,0xe7,0x27,0x52,0xe6,0x0f,0x3a,0xce,0xfd,0x94, +0xcf,0xdb,0x8f,0xba,0xe3,0x92,0xcb,0xa9,0x27,0xc3,0xcc,0xd8,0x1d,0xe7,0x1b,0x42, +0xf8,0x09,0x1a,0xac,0x7d,0x90,0x6b,0x10,0xcb,0x71,0xcd,0xe8,0xec,0x6e,0xa1,0x13, +0x5a,0xc5,0xf1,0xdf,0x90,0xde,0x01,0x94,0x47,0x45,0xc2,0x7e,0x45,0x5a,0x63,0xb9, +0x6e,0xcd,0x29,0xef,0x53,0x89,0xe7,0x09,0x58,0xc8,0x79,0x57,0x52,0x47,0x96,0x8d, +0x73,0xf3,0xf1,0x26,0xf1,0x7d,0x4b,0x9e,0xaf,0x25,0xed,0x2f,0x70,0x8e,0x7a,0xa4, +0xf5,0xaa,0xc1,0xee,0x6f,0xdb,0x83,0xed,0xdd,0xb2,0x7a,0x99,0x7a,0x72,0x26,0xe5, +0x35,0x1b,0xff,0xde,0x9c,0xe7,0x41,0xea,0x5f,0x63,0xce,0x91,0x72,0x37,0x75,0x92, +0x32,0x6e,0xca,0xb5,0x3e,0xed,0x01,0xae,0x03,0xe5,0xf7,0x82,0x79,0x87,0x42,0x1e, +0xe7,0xe3,0xff,0x29,0xc7,0xdc,0x44,0x3c,0x1f,0xd1,0x69,0x7d,0x45,0x3c,0xf5,0xb9, +0x8e,0x93,0x7a,0xb8,0xd7,0xe2,0x6d,0xd2,0x9c,0x49,0xbd,0x39,0x4c,0x1a,0x47,0x4c, +0x70,0xc7,0x9e,0xc6,0x91,0xcf,0x78,0x8e,0xbb,0x85,0x74,0x5e,0x4b,0xdd,0x3b,0x00, +0x0d,0xb8,0xe6,0x0f,0xd3,0x36,0x62,0x38,0x6f,0x47,0xca,0xb6,0x0f,0xd7,0xa9,0x28, +0x79,0xbc,0xec,0x01,0xf7,0xbd,0x4f,0x3c,0xe5,0x30,0x9c,0x63,0xaa,0x72,0x8e,0xd3, +0x49,0xe7,0x2e,0xc2,0x57,0x21,0xef,0xb7,0x91,0xa7,0x46,0x94,0xd3,0xa9,0x57,0xb8, +0xd7,0xf9,0x26,0xc2,0x9c,0x4b,0xbc,0x45,0xc8,0x7f,0x0f,0x53,0x9f,0x38,0xd7,0xf9, +0xc4,0x3f,0x95,0xfd,0x9f,0x71,0x0d,0xa3,0x88,0x7f,0x2b,0xf1,0x5f,0x4d,0xde,0xde, +0xa1,0x6c,0x3e,0x1d,0xe7,0x8e,0xe3,0x6d,0xe5,0xb8,0xfa,0x5c,0xff,0x97,0x49,0xc3, +0x59,0x1c,0xbb,0x96,0x74,0x3f,0x40,0xd8,0x43,0xb4,0x99,0x27,0xd8,0xd7,0xe1,0x61, +0xc7,0x79,0x8c,0xeb,0x74,0x3f,0x71,0xad,0xe6,0xdc,0x3b,0x47,0xb9,0x63,0x98,0xe5, +0xae,0x75,0x9c,0xbb,0x29,0xcb,0x25,0xd4,0xe7,0x49,0x94,0xf7,0x45,0xd4,0xc3,0x25, +0x66,0x9c,0x9a,0x7a,0x59,0x8b,0x74,0x44,0xc3,0xd3,0x94,0xfd,0x7a,0xd2,0xff,0x01, +0xe1,0xc6,0x52,0x3e,0x65,0x38,0xfe,0x45,0xd2,0x55,0x7b,0xbc,0x3b,0x36,0xd9,0xf2, +0x3e,0x77,0x5c,0x72,0x3d,0xe1,0x32,0xc8,0xeb,0x12,0xfa,0x81,0x8b,0xa9,0x87,0x43, +0x08,0xf3,0x09,0xee,0x2a,0xe4,0x6b,0x15,0x65,0x58,0x87,0x32,0xbf,0x0c,0x7a,0xc0, +0x78,0x68,0xcf,0xf5,0x58,0x34,0xc2,0x1d,0x2f,0x2d,0x4e,0x7b,0xfc,0x81,0xeb,0x5c, +0x93,0x32,0xfe,0x09,0xf6,0x52,0x6e,0x87,0xa1,0x32,0xfd,0xc2,0x8b,0xb4,0xcd,0x4f, +0xf0,0x9b,0xc7,0x79,0x5e,0xe0,0xda,0x7d,0x4e,0x19,0xb6,0x34,0xf5,0x96,0xb4,0x6d, +0x87,0x36,0xe4,0xfb,0x11,0xce,0x19,0x45,0x3d,0xb8,0x02,0x32,0x38,0xf7,0x54,0xb8, +0x5c,0xe3,0xd8,0xf7,0x72,0x7d,0xaf,0xa0,0x8c,0xef,0x84,0xaf,0xa1,0x15,0xd7,0x76, +0x2b,0xdc,0x45,0xfa,0xc6,0x52,0xae,0xc3,0xc8,0xcf,0x19,0x94,0x5b,0x05,0xea,0x68, +0x7f,0xca,0xad,0x2a,0x65,0x51,0x81,0xb2,0xbb,0x6b,0xb8,0xfb,0xcc,0xd8,0x0c,0x9a, +0x42,0x6b,0x93,0xe6,0xab,0xdd,0xf7,0x6f,0x77,0xc0,0x9d,0x90,0x41,0x19,0x8e,0x82, +0x25,0xd7,0xba,0x75,0x3a,0x86,0xf6,0xde,0x00,0x06,0x91,0xa7,0x10,0x75,0x6f,0x0f, +0xe5,0x7c,0xf5,0x68,0x97,0x0e,0xd4,0xa1,0xa2,0x94,0xd3,0x7d,0x10,0xa0,0x9c,0xd3, +0x61,0x3d,0xfd,0x47,0x3e,0xfa,0xa1,0x97,0xc6,0xbb,0x79,0xdf,0x46,0x1e,0x7f,0xa1, +0x5c,0x6a,0x93,0xf7,0xab,0x48,0xf7,0x57,0x99,0x41,0xe7,0x34,0x8e,0xad,0xc8,0x35, +0x99,0x4b,0x9e,0xaf,0x80,0x91,0x94,0x41,0x96,0x51,0x58,0x41,0xfe,0x0f,0x5d,0xe0, +0xe6,0xbf,0x1d,0x4c,0x82,0xad,0x2a,0xff,0x39,0xd0,0x88,0xb6,0x7b,0x21,0x74,0xbb, +0x98,0xb2,0xe4,0xda,0xad,0xe3,0x1a,0x7d,0x08,0xbd,0xa9,0x77,0xcf,0xc3,0x46,0xce, +0x71,0x3e,0x65,0x92,0x4f,0xe5,0xd3,0x45,0x65,0x94,0xc2,0xf5,0x7e,0x9d,0xb6,0x76, +0x26,0x6d,0xf7,0x02,0x68,0xdf,0xc3,0xbd,0x9e,0xa6,0xaf,0x2d,0x0d,0xed,0x7b,0xb9, +0xe3,0xf3,0xa6,0x7f,0x31,0x75,0x7f,0x13,0xe5,0xb7,0x5a,0x65,0x58,0x26,0xdb,0x2d, +0xc7,0x67,0xe8,0x87,0x52,0x29,0xcb,0x19,0x83,0xdc,0x3a,0x30,0x90,0x32,0x8d,0xa2, +0xee,0xd6,0x86,0xb3,0xa8,0x0f,0x65,0x87,0xba,0xf5,0x62,0x13,0x7c,0x03,0xcd,0x09, +0x9f,0x01,0x6f,0x51,0xee,0xb3,0x54,0xa6,0xd7,0x52,0x3f,0x3a,0x5d,0xe7,0x96,0x6d, +0x3d,0x95,0xe9,0x05,0xd4,0xcd,0xbd,0x70,0x35,0xf7,0x95,0x06,0x94,0xe5,0x4d,0x2a, +0xd3,0xc5,0xb7,0xba,0x75,0x68,0xf5,0xad,0x6e,0xf9,0x9a,0x7e,0x74,0xcf,0xad,0x6e, +0x39,0xdf,0x7a,0x9b,0x5b,0xce,0x35,0x29,0xe7,0x41,0x94,0xf3,0x24,0xda,0xcc,0x50, +0xfa,0x85,0x11,0xf7,0xb9,0x65,0x6e,0xea,0xe2,0xa6,0xfb,0xdd,0xb2,0x2f,0xf0,0x80, +0x5b,0xfe,0xc5,0x1f,0x72,0xef,0x6f,0xcd,0x2b,0x07,0x9d,0x46,0xf0,0x7e,0x72,0xd0, +0x79,0xa4,0x36,0x7d,0x48,0x06,0x71,0x42,0xb3,0x0b,0x82,0xce,0xda,0x4b,0x82,0xce, +0xfa,0xeb,0x83,0x4e,0x43,0xc2,0xdd,0xf9,0x98,0xfb,0xec,0xed,0xd1,0x5b,0xda,0xf7, +0x18,0x7e,0x9e,0xbf,0x37,0x0f,0xc5,0xd3,0x21,0x21,0xd2,0x15,0x72,0xb5,0x87,0xb4, +0x0f,0x5c,0x6f,0xf9,0xf7,0x83,0x0f,0xe1,0x45,0xf8,0x1a,0xe6,0xc1,0xd6,0x90,0x3b, +0x67,0xd5,0xcc,0x55,0x7d,0x0f,0x36,0x41,0x0e,0x7c,0x0c,0x3b,0x61,0x57,0xc8,0x9d, +0x03,0xfc,0x05,0xba,0x34,0xe4,0xea,0x32,0xe9,0xab,0x96,0xdf,0xab,0xf2,0x5f,0xab, +0x78,0x8d,0xce,0x97,0xbe,0xaa,0x39,0xb1,0xaf,0x6a,0x5e,0xec,0xab,0x3a,0xdf,0xab, +0x3a,0xa7,0xd1,0xf7,0xa5,0x1f,0x48,0x37,0x4a,0x3f,0x94,0x7e,0x24,0xdd,0x24,0xcd, +0x91,0x7e,0x22,0xdd,0x22,0xfd,0x54,0xba,0x4d,0xba,0x5d,0xba,0x43,0xfa,0xb9,0x74, +0xa7,0xd4,0x4b,0xfb,0x2e,0x2b,0x1d,0x0b,0x94,0xde,0xc5,0x3a,0xdf,0x62,0xc5,0xb3, +0x58,0xf9,0x31,0xe7,0x1e,0x18,0xe5,0x72,0xad,0x8f,0xeb,0x7d,0x8c,0xf4,0x71,0x8d, +0x8f,0x1b,0x7c,0x5c,0xed,0xe3,0x49,0x1f,0x4f,0xfb,0xb8,0xd1,0xc7,0x18,0x1f,0x37, +0xf9,0xb8,0xd9,0xc7,0x1d,0xe2,0x76,0x71,0xa7,0x18,0x27,0x1e,0x10,0x77,0x89,0x69, +0x3e,0x66,0xf8,0x98,0xe3,0x63,0x96,0x8f,0x97,0xc5,0x2b,0x3e,0xbc,0xb5,0x6b,0xec, +0x35,0x6c,0x6c,0x16,0xf9,0x58,0x67,0x61,0xaf,0x75,0xf3,0xbc,0x8f,0x15,0x62,0xb9, +0x58,0x29,0xbc,0xb5,0x73,0x56,0x8b,0x37,0xc4,0x9b,0x62,0xad,0x8f,0x66,0xc2,0x5e, +0x8b,0xe7,0x58,0xf6,0xf7,0xf3,0xb0,0x37,0xcd,0xc3,0xbe,0x22,0x0f,0xfb,0xf2,0x3c, +0xec,0x2b,0xf3,0xb0,0xaf,0x3d,0x01,0x7b,0xb3,0xff,0x60,0x7f,0xcb,0x87,0xb7,0xaf, +0x9a,0x65,0x8f,0xb3,0xec,0x59,0x79,0xc4,0x65,0xb4,0xb2,0x8e,0xab,0xac,0x63,0x8c, +0xc6,0x4b,0xb3,0xa4,0xcd,0xa4,0x26,0x7c,0x15,0x85,0xaf,0xa2,0xf0,0x55,0x14,0xbe, +0x8a,0xc2,0x57,0x51,0xf8,0x2a,0x0a,0x5f,0x55,0xe1,0xab,0x6a,0x7f,0x55,0xed,0xaf, +0xaa,0xfd,0xd5,0x14,0x4f,0x35,0xed,0x8f,0xb3,0xfc,0xb2,0x14,0x77,0x35,0x69,0x9c, +0xd4,0xf8,0x27,0xcb,0x3f,0x59,0xfe,0xc9,0xda,0x97,0xac,0xfd,0xa9,0xf2,0x4f,0x95, +0x3b,0x4d,0xe1,0xd3,0xe4,0x9f,0xa6,0xf0,0x69,0xda,0x5f,0x43,0xfe,0x35,0xe4,0xae, +0x29,0x4d,0xd7,0x71,0xe9,0x72,0xd7,0x92,0xbb,0x96,0xdc,0x0d,0xe4,0x6e,0xa0,0xe3, +0x1b,0x28,0xde,0x06,0xd6,0xfe,0x66,0x52,0x93,0xdf,0x4c,0x85,0xcb,0xd4,0xfe,0x4c, +0xed,0xcf,0xd4,0xfe,0x86,0xaa,0xa3,0x0d,0x15,0x6f,0x43,0x85,0x6f,0xa8,0x78,0x8d, +0x36,0x92,0x66,0x49,0x9b,0x49,0x9b,0x6b,0x5f,0x35,0x69,0x9c,0x34,0x5e,0x9a,0x25, +0x6d,0x26,0x6d,0x2e,0x3f,0xbb,0xec,0xb3,0xac,0x32,0xf6,0x68,0x66,0xd5,0xa1,0xc6, +0x0a,0xdf,0x58,0xe1,0x1b,0x2b,0x7c,0x63,0x85,0x69,0xac,0xf0,0x8d,0x15,0xbe,0x89, +0xc2,0x37,0xd1,0xfe,0x26,0xda,0xdf,0x44,0xfb,0x9b,0x5b,0xf5,0xd6,0xab,0xb3,0xf1, +0x56,0xda,0x9a,0x5b,0x75,0xd6,0x90,0x00,0xd9,0x90,0x28,0x6d,0x26,0x35,0xf3,0xa6, +0xce,0x43,0xdb,0xc8,0xde,0xd2,0xb2,0x9f,0x6f,0xd9,0x5b,0x59,0xf6,0xd6,0x96,0xbd, +0x8d,0xe2,0xf1,0xda,0x46,0xa2,0x65,0x4f,0xca,0xa3,0x2d,0x35,0x3e,0x4e,0xbb,0x4a, +0x94,0x26,0xf9,0xda,0x53,0xe3,0x3c,0xda,0x55,0xa2,0x34,0xc9,0xd7,0x9e,0x1a,0xe7, +0xd1,0xae,0x12,0xa5,0x49,0xbe,0xf6,0xd5,0xf8,0x18,0xed,0xec,0x58,0xf5,0x30,0xaf, +0x7a,0x77,0xbc,0xfa,0x95,0x57,0x3d,0xaa,0x64,0xd5,0x99,0xc6,0x4a,0x5f,0x63,0xa5, +0xcf,0xae,0x1f,0x8d,0x8f,0x51,0x4f,0x9a,0x59,0xe5,0xef,0x95,0x7d,0x92,0xaf,0x1e, +0x34,0x3e,0x46,0x7d,0x38,0x5e,0xdf,0x17,0x9f,0xc7,0xb5,0x6b,0x72,0x82,0x7d,0x5f, +0x93,0x13,0xec,0xf3,0x9a,0x58,0xd7,0xe0,0x64,0xfa,0xb4,0x93,0xed,0xcb,0xe2,0x7f, +0x43,0x9f,0xf6,0x47,0xf5,0x65,0xfe,0xbe,0xeb,0x44,0xfb,0xa8,0x13,0xe9,0x93,0x9a, +0x9c,0x40,0x5f,0x74,0x22,0x7d,0x4f,0x93,0x3c,0xfa,0x9c,0xec,0x13,0xec,0x6b,0x9a, +0x1c,0xa7,0xbe,0xf8,0xeb,0xc5,0xb1,0xae,0x7f,0x55,0xb9,0x93,0xad,0xeb,0x6b,0xdc, +0x29,0x72,0xa7,0xc8,0x7d,0xac,0x72,0xca,0x3a,0x46,0x7e,0xfc,0xe9,0xcb,0x88,0x3a, +0xd2,0xa7,0x19,0x7b,0x2b,0xcb,0xee,0xf5,0x69,0x35,0xd4,0x4e,0x6a,0xe8,0xb8,0x74, +0xb9,0xd3,0xe5,0xae,0x25,0x77,0x2d,0xb9,0x93,0xe5,0x4e,0x96,0x3b,0x45,0xee,0x14, +0xab,0xbc,0x9a,0x59,0xe5,0x56,0x4d,0xee,0x6a,0x56,0x39,0x36,0xb3,0xca,0x33,0x55, +0xee,0x54,0xb9,0xd3,0xe4,0x4e,0xb3,0xe2,0xaf,0x26,0x8d,0x93,0xc6,0xfb,0xca,0x28, +0x51,0xe9,0x49,0x54,0x3c,0x89,0x3a,0x3e,0xf1,0x5f,0x90,0xbf,0xe3,0x1d,0x6f,0xd7, +0xa9,0x26,0xd6,0x73,0x4b,0x5e,0x7d,0x49,0x5e,0xf1,0xf9,0x9f,0x77,0x4c,0x1f,0xde, +0xc2,0xd2,0x2a,0x56,0x9b,0xac,0x62,0xf5,0x65,0xc7,0xb2,0x67,0x59,0x7d,0x63,0x96, +0xd5,0x3e,0xaa,0x59,0xf6,0x38,0xcb,0x1e,0x7f,0x8c,0x3e,0xd2,0xb3,0xc7,0x59,0x75, +0x3e,0xce,0x7a,0x0e,0x49,0xb6,0xc2,0x26,0x5b,0xfd,0x6a,0xb2,0x75,0xcd,0x92,0xad, +0x78,0x8e,0x65,0xaf,0x66,0xd9,0xb3,0x7c,0xf6,0x54,0xeb,0xfc,0x7e,0x7b,0x96,0x75, +0xed,0xe2,0xf2,0xb0,0x57,0xb3,0xae,0x7f,0x96,0xef,0x9a,0xd9,0xf6,0x2c,0x9f,0x3d, +0xcd,0xaa,0x83,0x69,0x56,0x19,0xda,0xf6,0x1a,0x56,0x5e,0x8e,0x65,0xb7,0xc3,0x34, +0xb7,0xfa,0xfb,0x2c,0xab,0xcf,0xcf,0xcb,0xde,0xcc,0xba,0x0f,0x64,0x59,0xf6,0xe6, +0x96,0xbd,0x99,0x75,0x4f,0xc8,0xf2,0xd9,0x33,0xad,0xf4,0x64,0x5a,0xf1,0x34,0xb2, +0xca,0xa7,0x91,0xd5,0xbe,0x1a,0x59,0xf9,0xf5,0xee,0x0f,0xd5,0x8e,0x61,0x8f,0xb7, +0x8e,0x8d,0xf7,0xf5,0x93,0x71,0x3e,0xfb,0xb1,0xea,0x51,0x96,0x65,0x6f,0xee,0xbb, +0x3f,0xdb,0xf7,0x1b,0x7f,0x7d,0xb4,0xef,0x3b,0xde,0xbd,0xda,0xbe,0x47,0x35,0xf1, +0xdd,0x97,0xe2,0x7c,0xf6,0x66,0xd6,0xfd,0x2a,0x2b,0x0f,0x7b,0x33,0xab,0xaf,0x6f, +0x6e,0xd9,0x9b,0x59,0x69,0xcd,0xf2,0xd9,0x2b,0x5b,0x7d,0x50,0x15,0xab,0xbe,0x55, +0xb1,0xe2,0xac,0xe2,0x0b,0x13,0x6f,0xf9,0x67,0x59,0xfe,0x59,0x56,0x1f,0x97,0xe5, +0xfb,0x3d,0x66,0xfb,0x37,0xb3,0xfa,0x91,0x66,0x56,0xbb,0x68,0x6e,0xd5,0xff,0xe6, +0x56,0x1d,0xb6,0x7f,0x87,0xd8,0xcf,0x8c,0xcd,0x7d,0xf7,0x5e,0xfb,0x7e,0xdc,0xfc, +0x18,0x79,0x6d,0x6e,0xd5,0xa5,0xe6,0x56,0xd9,0x36,0xf7,0xd5,0x37,0xbb,0x8e,0xa5, +0x5b,0xe1,0x1b,0x1e,0xe3,0x77,0x8b,0xfd,0x5c,0x61,0xa7,0x33,0xcb,0x0a,0x9f,0xe5, +0xf3,0x6f,0xec,0x7b,0xa6,0x8b,0xb3,0xf2,0x51,0xcd,0x57,0xaf,0x9a,0x5b,0xcf,0x4b, +0xcd,0xad,0x67,0xcb,0xe6,0xbe,0xf8,0xed,0xb6,0x99,0xea,0xeb,0x8b,0xe2,0x7d,0x69, +0xf6,0xee,0x37,0x8d,0xf4,0xee,0x24,0xd3,0xb2,0x57,0x92,0xdd,0x7b,0x86,0xf2,0x9e, +0xe1,0xbd,0xdf,0x1f,0x76,0x3b,0xa8,0x6e,0xc5,0xe3,0x95,0x93,0x77,0x0f,0x6a,0x6a, +0xf9,0x37,0xb2,0x9e,0x35,0x9a,0x6a,0x7f,0x23,0x2b,0xad,0x8d,0xac,0x7a,0xe0,0xd9, +0x73,0xff,0x8e,0x8a,0x2f,0x2d,0xc6,0xcf,0x1f,0x9f,0xf1,0xf3,0xc7,0xe9,0xb5,0x75, +0xb3,0xcf,0xb3,0x57,0xb2,0xe2,0x49,0xd4,0x7b,0x0e,0xcf,0xaf,0x9a,0x99,0x33,0x9d, +0xe0,0x38,0xc1,0x04,0xf7,0x5b,0xbd,0xda,0xd6,0xba,0x0b,0xa7,0xe0,0x77,0x6a,0xc2, +0xb1,0xd7,0x79,0x28,0xc9,0x09,0x4a,0x40,0x67,0xc7,0xc5,0x5b,0x23,0xe1,0x5a,0xb8, +0xce,0xec,0xe7,0xb8,0x52,0x50,0x14,0x8a,0x41,0x7e,0x28,0x90,0x70,0xe4,0xdb,0xe4, +0x82,0x50,0x08,0x0a,0x43,0x11,0xf3,0x0d,0x91,0x99,0x03,0x6e,0xad,0x05,0x91,0x97, +0x7a,0xe7,0x33,0x78,0x69,0x8f,0x57,0xba,0x6b,0x59,0x6b,0x47,0x98,0xf4,0xe5,0x95, +0xa6,0x58,0x33,0x86,0x6b,0xe6,0xae,0x6b,0x9d,0x87,0x38,0xc7,0xfd,0x06,0xbc,0x9e, +0xbe,0x4b,0xbc,0xc4,0xac,0x0b,0x69,0xd6,0x86,0x85,0x0c,0xa5,0xa9,0x85,0x9e,0x09, +0x5b,0x58,0xbf,0x8f,0xbd,0xdf,0xc6,0xde,0xef,0x62,0xef,0x59,0xd2,0xfb,0x6d,0xec, +0x3d,0x4f,0x7a,0xbf,0x8f,0xbd,0x67,0x4a,0xef,0x37,0x72,0x86,0xf5,0x9b,0xf9,0x02, +0xb9,0x8d,0x96,0x8f,0x3a,0x7a,0x6d,0x6c,0x7b,0x8d,0x6c,0xff,0x5a,0xd9,0xfe,0x35, +0xb3,0xfd,0x6b,0x67,0xe7,0xa5,0x95,0x44,0x65,0x1f,0xe7,0x8a,0x2a,0x3e,0xaa,0xfa, +0xa8,0xe6,0x23,0xce,0x47,0xbc,0x8f,0xea,0x22,0x41,0x24,0x8a,0x24,0x91,0xec,0x23, +0xc5,0x47,0xaa,0x8f,0x34,0x1f,0x35,0x7c,0xd4,0xf4,0x91,0xee,0xa3,0x96,0x8f,0x06, +0x3e,0x32,0x7d,0x34,0xf4,0xd1,0xc8,0x47,0x96,0x8f,0xc6,0x3e,0x9a,0xf8,0x68,0x2a, +0x9a,0x1d,0xe3,0x37,0x78,0x73,0xab,0xdd,0xb6,0xcd,0xc3,0x7e,0x61,0x1e,0xf6,0x76, +0x79,0xd8,0x3d,0x35,0x6d,0xa3,0x82,0xe3,0xb6,0x01,0xaf,0x8e,0x9b,0xb6,0x50,0xc9, +0x6a,0xc3,0x5e,0xbb,0xa8,0xa6,0xb6,0x11,0xaf,0xb5,0x48,0x4e,0x74,0xed,0x14,0xaf, +0x1f,0xa9,0xa3,0xf6,0x54,0x4f,0xed,0x32,0xe3,0x4f,0xfc,0xee,0xb9,0x93,0xda,0xb1, +0xe9,0x53,0x2e,0x53,0x7f,0xd1,0xe5,0x4f,0xfc,0x1e,0xda,0xf4,0x39,0x23,0xd4,0xef, +0x5c,0x0f,0x63,0x29,0xd8,0x9b,0xce,0x75,0xfb,0x59,0xaf,0xef,0x33,0x7d,0xd7,0x8f, +0x9a,0x73,0x3e,0x45,0xf3,0x65,0x9f,0xd2,0xdc,0x58,0x33,0x27,0x7c,0x9b,0xe6,0x58, +0x7f,0xae,0x39,0x92,0x87,0x13,0xfe,0x7e,0xf3,0xea,0x0f,0x68,0xae,0xa7,0x99,0x23, +0xda,0xa5,0xd8,0x3f,0xeb,0xdb,0xc3,0xc7,0xc9,0xce,0x13,0xf0,0x9c,0xf5,0x77,0xd1, +0x9e,0x46,0x9f,0x32,0xf3,0xd7,0xf0,0x08,0x9e,0xe3,0xae,0x89,0x72,0x57,0x79,0x77, +0x4d,0x94,0x7b,0x60,0x32,0x7e,0xab,0x61,0x6d,0xd0,0x71,0xde,0x0d,0xba,0x7f,0xbf, +0x65,0x12,0xda,0x16,0x9e,0x30,0x6b,0xa3,0x4f,0xe7,0x78,0xf4,0x49,0x68,0x0f,0x1d, +0xcc,0xda,0xe5,0x67,0x51,0xb7,0xd1,0xcb,0x60,0x1a,0x5c,0x0e,0xdd,0xa0,0x0b,0x3c, +0x14,0x74,0xd7,0xff,0x79,0xd8,0xac,0xf1,0x0e,0x37,0xc2,0xb3,0x66,0x3d,0x74,0xf3, +0x37,0x43,0x20,0x72,0x73,0xc0,0xb9,0xf3,0x19,0xf2,0x82,0x3d,0x64,0xec,0x68,0x14, +0x6a,0xfe,0x4e,0xcc,0x50,0xf3,0x37,0x49,0x82,0x6e,0x9d,0xbe,0x06,0xcd,0x87,0xff, +0x75,0xe8,0xf5,0x30,0x12,0xa6,0xc2,0xd3,0x26,0x5e,0xd2,0xf4,0x0c,0x3a,0xce,0x84, +0xa5,0x53,0x18,0x8f,0x4e,0x81,0xc7,0xe1,0x01,0x58,0xc2,0xf9,0x97,0xc2,0x32,0xc8, +0x4f,0x1c,0x65,0x60,0x52,0xd1,0x80,0xf3,0x32,0x3c,0x24,0x7d,0x4a,0x9a,0x58,0x2c, +0xe0,0x54,0x82,0x24,0x69,0x93,0x12,0x01,0xa7,0x5e,0x09,0x57,0x3b,0xc0,0x82,0x92, +0x84,0x2b,0xe9,0xea,0x4c,0xe9,0x42,0x98,0x5f,0x2a,0xe0,0xcc,0x80,0x05,0xd2,0xd4, +0xd3,0x03,0x4e,0x02,0x74,0x78,0x37,0xe0,0xf4,0x80,0x8b,0x7c,0xda,0xdf,0xb2,0x0f, +0xb0,0xec,0xd9,0x96,0x7d,0xa0,0x65,0x1f,0x04,0x0b,0x64,0x7f,0x59,0xba,0xc0,0x8a, +0xeb,0x65,0xcb,0xbe,0xc0,0x8a,0xf7,0x65,0xcb,0xfe,0x4f,0x5b,0xd3,0xe1,0xaf,0x90, +0x9f,0x7f,0x52,0x5e,0xfe,0xe8,0x6b,0xe3,0xe5,0xa5,0x89,0x95,0x76,0x7f,0x9a,0x4f, +0x36,0xbd,0x3d,0x8f,0x93,0xce,0x7f,0x7b,0x99,0x67,0x1e,0x23,0x2f,0xc7,0xcb,0xc3, +0x7f,0x4a,0xff,0xff,0x3a,0xed,0xc7,0xba,0x06,0xad,0xfe,0x62,0x69,0x0e,0xf7,0xa7, +0xe1,0xfc,0x84,0xf3,0x13,0xce,0xcf,0x3f,0x2d,0x3f,0x89,0x3c,0x2f,0xd7,0x08,0xba, +0xeb,0xf0,0xde,0xad,0xb5,0x31,0xef,0xd5,0x7a,0xb9,0xf7,0x69,0x7d,0xdc,0x07,0xb4, +0x66,0xed,0x83,0xf0,0x10,0x3c,0x0c,0x8f,0xc0,0xa3,0x5a,0xe7,0x75,0xb2,0xd6,0x91, +0x7d,0x40,0x7f,0xfb,0xee,0x49,0xad,0x2f,0xfb,0x34,0x3c,0x63,0xd6,0x18,0xd4,0xba, +0xaf,0xd1,0x15,0xdc,0xb5,0x81,0xed,0xbf,0xe5,0x64,0xd6,0xe2,0x7e,0x49,0x6b,0xf6, +0xce,0xd7,0xfa,0xb9,0xe6,0x6f,0xea,0xbd,0xa2,0xbf,0xe7,0xbc,0x10,0x16,0x69,0x0d, +0xee,0x25,0xd6,0xdf,0xda,0x7b,0x0d,0x5e,0xd7,0x5a,0xb7,0xde,0xdf,0x7a,0x5a,0xa9, +0xb5,0x68,0x83,0x15,0xdc,0x78,0xe7,0x2b,0xae,0xe5,0x3a,0x6e,0x49,0x44,0x38,0x9f, +0xe1,0x7c,0x86,0xf3,0xf9,0x57,0xce,0x67,0x0e,0x7c,0x1c,0x71,0xe2,0xef,0xf9,0xfe, +0xf2,0xe1,0x22,0x09,0x07,0x49,0x91,0xee,0xdf,0xee,0x4c,0x89,0x74,0xff,0xa6,0xa6, +0xf9,0xbb,0x99,0xe6,0x6f,0x65,0x9a,0xbf,0x87,0x69,0xfe,0x86,0x67,0x6d,0xa8,0x13, +0xe9,0xfe,0x3d,0xcc,0xfa,0x90,0x01,0x0d,0x20,0x33,0xd2,0xfd,0x9b,0x96,0x8d,0x20, +0x0b,0x1a,0x47,0xba,0x7f,0xd3,0xb2,0x69,0xa4,0xfb,0xb7,0x2c,0xcd,0xdf,0xc7,0x3c, +0x1f,0x6e,0x79,0xda,0xfd,0xdb,0x9c,0xe6,0xef,0x82,0x5e,0x14,0xe9,0xfe,0x1d,0xcd, +0x19,0xf0,0x4e,0xe4,0xc9,0xa5,0xc1,0x3b,0x7f,0x83,0xff,0x70,0xde,0xe6,0x3a,0xf7, +0x5d,0x3a,0x5f,0x3b,0xe8,0x0c,0xd3,0xa1,0x0d,0xe9,0x98,0x15,0x79,0xe4,0xbd,0x7e, +0x35,0xbd,0x73,0x6f,0xaa,0x77,0xec,0x71,0xd6,0x1c,0x8f,0x86,0xbe,0x39,0x32,0xc9, +0x7a,0x2f,0xde,0x40,0xef,0xd7,0x33,0xad,0xb9,0x13,0xde,0xfb,0xff,0x78,0xbd,0xbb, +0x4f,0xd3,0x3b,0x75,0xf3,0xde,0xbc,0xbf,0xe6,0x35,0x4f,0x81,0x01,0xd6,0x79,0x9b, +0xf8,0xc6,0xea,0x8e,0x77,0x2e,0xff,0x79,0xd2,0xac,0x39,0x55,0xf6,0x38,0xa8,0x7d, +0xbc,0x7d,0xac,0x7d,0xcc,0xcb,0x79,0xa4,0xa5,0x86,0x6f,0xec,0xf0,0x64,0xd2,0x62, +0xe7,0x77,0x4a,0xd4,0xff,0x2f,0xe3,0x26,0x79,0x94,0xf3,0x1f,0x51,0xc6,0xc7,0xbb, +0x96,0x7f,0xc4,0x39,0xbc,0xf5,0x5c,0x13,0xf4,0xde,0x3f,0x51,0x9a,0x24,0x4d,0x96, +0xa6,0x48,0x53,0xa5,0x69,0xd2,0x1a,0xd2,0x9a,0xd2,0x74,0x69,0x65,0x3d,0xb7,0x79, +0xeb,0x2a,0x65,0x5a,0xf6,0x86,0x96,0xbd,0x91,0x65,0xcf,0xb2,0xec,0x8d,0x2d,0x7b, +0x13,0xcb,0xde,0xd4,0xb2,0x37,0xb3,0xec,0xcd,0x2d,0x7b,0x0b,0xcb,0x7e,0x9e,0x65, +0x6f,0x69,0xd9,0xcf,0xb7,0xec,0xad,0x2c,0x7b,0x6b,0xcb,0xde,0xc6,0xb2,0x5f,0x60, +0xd9,0xdb,0x5a,0xf6,0x0b,0x2d,0x7b,0x3b,0xcb,0xde,0xde,0xb2,0x77,0xb0,0xec,0x17, +0x59,0xf6,0x8e,0x96,0xfd,0x62,0xd9,0xcd,0x58,0xa5,0x89,0xdf,0x8c,0x57,0x36,0xd4, +0x79,0xbd,0xe7,0xde,0x0e,0x0a,0xf7,0x67,0x3d,0x0f,0x37,0xf5,0x7d,0xd7,0xdd,0x56, +0xe7,0x6b,0x2b,0xbc,0xef,0x98,0xbd,0x63,0x1b,0x2a,0xac,0xa7,0xde,0x1a,0xe5,0x17, +0xc8,0x6e,0xd2,0x64,0xd6,0x6c,0x6c,0xa1,0xb1,0x0a,0x6f,0xbc,0xc2,0xac,0x7b,0xda, +0xa1,0x93,0xe3,0xbc,0xd5,0xf6,0xc8,0x9a,0x28,0x66,0x4d,0xa8,0x33,0x48,0xc8,0xb6, +0x5b,0xdc,0x35,0xf1,0x9e,0xc4,0x5d,0x8e,0x87,0xf1,0xf2,0x03,0xdd,0x6f,0x0e,0x5b, +0x12,0xe9,0xed,0x9d,0x1d,0xe7,0x0e,0x32,0x33,0x13,0xf7,0x59,0xe6,0x1b,0xcc,0xeb, +0xdc,0x35,0x4b,0xa7,0xdd,0xee,0x38,0xfb,0xc8,0x48,0x3a,0x99,0x2b,0xc9,0xc3,0xf9, +0x44,0xe2,0x6f,0xd7,0xdd,0x2d,0x04,0xb3,0xce,0x54,0xf3,0x09,0xee,0xda,0x4e,0x66, +0x9d,0x27,0xb3,0xbe,0x53,0x74,0x77,0x77,0x2d,0xd0,0xb6,0x84,0x1b,0xc5,0x43,0xfa, +0x35,0x3c,0xa4,0xe7,0xe3,0xd8,0x91,0xfd,0xdd,0x75,0xa5,0x72,0xd7,0x56,0x22,0xde, +0x41,0x9c,0xe3,0x25,0x0a,0xab,0xe5,0x5d,0xee,0x75,0xaa,0xd6,0xcb,0xbd,0x4e,0xc6, +0x6e,0xe2,0xf5,0xec,0xb7,0x5b,0xf6,0x5b,0x3a,0x1d,0xb1,0x9b,0x75,0x1e,0x3c,0xbb, +0x39,0x97,0x67,0xdf,0x30,0xf4,0x88,0xfd,0xe3,0x0b,0x8e,0xd8,0x3b,0xf4,0x70,0xed, +0xf7,0x93,0xcf,0xbd,0x6d,0x4f,0xfc,0xfe,0x57,0x97,0xf3,0xd7,0x34,0xeb,0x66,0x41, +0x85,0x40,0xd0,0xe9,0xd2,0xca,0xfd,0x1e,0xf0,0x15,0x08,0x72,0xc1,0xae,0x81,0x49, +0xad,0xdd,0xef,0x03,0xdf,0x81,0x47,0x53,0x4c,0x5f,0x10,0xcc,0xfd,0x56,0xf0,0x42, +0xb8,0x1c,0x86,0x99,0x6f,0x6f,0x43,0x41,0x67,0x01,0xfb,0x7a,0xb5,0x71,0xcb,0xb9, +0x05,0xee,0xfb,0xd1,0x27,0xcd,0xb7,0xb9,0xc4,0xfd,0x5c,0x1b,0xf7,0x5b,0xbb,0xcd, +0x77,0x05,0x73,0xd7,0xdd,0x8d,0x20,0xed,0x9b,0x09,0x5f,0x1b,0x6d,0x7c,0x81,0x5b, +0x5e,0xc3,0x4c,0x7e,0x52,0xdd,0xef,0xef,0xbc,0xef,0x10,0xcd,0x77,0x78,0x21,0xf2, +0x13,0xd5,0xd6,0xfd,0x56,0xb7,0x59,0x5b,0xf7,0xdb,0xc4,0x8b,0x61,0x30,0x5c,0x07, +0x37,0x58,0x54,0xcb,0x1f,0x74,0xb2,0x29,0xbb,0x55,0xd8,0x37,0x43,0xf7,0x02,0x41, +0x67,0x37,0xba,0xdf,0xc4,0xc1,0x75,0x7a,0x14,0x6a,0x42,0x53,0xb8,0xc2,0xac,0xdf, +0x04,0xdf,0x41,0x51,0xae,0x55,0x5b,0xe8,0x0e,0x37,0x0a,0xf3,0xdd,0xdf,0x74,0x98, +0x03,0xcb,0xe0,0x94,0x0e,0xee,0xf7,0x90,0xa7,0xa2,0x6d,0xd0,0x21,0xed,0xdd,0x6f, +0x39,0xbf,0xa2,0xfe,0xbc,0x8d,0xdf,0x37,0x50,0x08,0xfb,0x6d,0x68,0x12,0x9a,0x08, +0xcf,0xc1,0xf6,0x92,0x41,0xe7,0x6b,0xf4,0x7b,0x88,0xea,0xe8,0xd6,0xd5,0x0a,0xe6, +0xfb,0x41,0x98,0x7a,0x4a,0xd0,0xd9,0x05,0x5f,0x62,0x2f,0x4d,0x43,0xaa,0x04,0x1b, +0xb1,0xf7,0x44,0xbf,0xe2,0x62,0x1d,0x86,0x7c,0xd4,0x8b,0x7a,0x62,0xe5,0xe9,0x41, +0xe7,0x35,0x74,0x63,0x27,0xf7,0xfb,0xdc,0x03,0x70,0x5a,0xe9,0xa0,0xf3,0x0b,0x1a, +0x75,0x09,0x79,0xe8,0xec,0xae,0x37,0x3c,0x8a,0x8b,0xdc,0x45,0xdf,0x6a,0x2e,0x81, +0x3b,0x60,0xfb,0x59,0x41,0xa7,0x21,0x75,0x79,0x07,0xda,0x1f,0xed,0x03,0x23,0xe0, +0x53,0xd8,0x0a,0xd5,0xa9,0x14,0x3f,0xa1,0x95,0x2f,0xa3,0x5e,0x98,0xef,0x19,0xa1, +0x1b,0x7e,0x63,0xca,0x07,0x9d,0x11,0xe8,0x4c,0xdc,0x73,0xe0,0xa5,0xcb,0xdc,0x6f, +0xc4,0xef,0x7e,0x22,0x98,0xbb,0x56,0x71,0x62,0x6c,0x30,0x97,0xc0,0x68,0xce,0xdd, +0xd9,0x65,0x05,0xe1,0xe7,0x27,0x05,0x9d,0x8f,0xba,0x06,0x9d,0x6e,0xb8,0xfb,0xc0, +0x36,0xfc,0x1e,0x44,0xd7,0xc0,0x06,0x38,0x08,0xa3,0xba,0x50,0x9f,0xa8,0x88,0x67, +0xa6,0xbb,0xdf,0x94,0xbe,0x57,0x31,0xe8,0xac,0x40,0x9b,0xf2,0x03,0xfb,0xbc,0xae, +0xee,0x77,0x94,0x46,0xaf,0xd1,0xb7,0x94,0xb3,0xe1,0x49,0x98,0x01,0x9f,0xe8,0xbb, +0x4a,0xf3,0x6d,0xbc,0x59,0xaf,0xa4,0x34,0x5c,0x0a,0xb3,0xe0,0x3d,0x68,0x4d,0x5b, +0x2d,0x58,0x35,0xe8,0xd4,0x45,0x0f,0xe3,0xbe,0x02,0x1d,0x03,0xdb,0x61,0x3f,0xfe, +0x15,0xf8,0xe1,0xfe,0x06,0xf6,0x69,0x10,0x5f,0x8b,0xfc,0xe2,0xbe,0x1e,0x1e,0x81, +0x61,0xd0,0xb7,0x96,0xfb,0x5d,0x6b,0xdf,0x1e,0x66,0x6e,0x4a,0xd0,0xd9,0x86,0xfe, +0x40,0xbf,0xd2,0x0c,0x4e,0xaf,0xed,0x7e,0xeb,0x9a,0x0f,0xdd,0x4e,0xb8,0xbb,0xa9, +0xd3,0x13,0xdb,0xb8,0x2f,0x00,0x1e,0xc6,0xff,0xf9,0x91,0x3c,0xef,0x35,0x3c,0xf2, +0x6d,0x67,0x79,0xb8,0x0c,0xda,0xc2,0x6b,0xc9,0x41,0xa7,0x19,0xc7,0x1d,0xc2,0x3e, +0x16,0x2e,0xb8,0xc2,0xfd,0x66,0xb6,0x5f,0x4a,0xd0,0xb9,0x13,0x2d,0x0b,0x25,0x7b, +0x3b,0xb9,0xdf,0x45,0x66,0xa2,0x4f,0xc0,0x2e,0x98,0x7a,0x25,0xf6,0xb4,0xa0,0xb3, +0x09,0x3d,0xad,0x0e,0x71,0xf6,0xe1,0xf7,0x41,0xcd,0xa0,0x73,0x21,0x7a,0x3e,0xee, +0x41,0x66,0x5d,0x6c,0x7d,0x3f,0xfa,0x0a,0xdc,0x51,0x2b,0xe8,0x14,0xe0,0x5a,0x1f, +0x42,0xcf,0xef,0xcb,0xef,0x81,0x3a,0x41,0x67,0x31,0xba,0x06,0x7a,0xc1,0x29,0xfd, +0xa8,0x53,0xfd,0xdc,0x6f,0x75,0xcd,0xf7,0xa6,0xbd,0x61,0x38,0x8c,0x85,0x32,0x75, +0x83,0x4e,0x0a,0x5a,0x9d,0x7e,0xad,0x3f,0x24,0xd7,0x75,0xbf,0x45,0x5d,0x01,0xef, +0xd6,0x0b,0x3a,0x07,0xd9,0xd7,0x9f,0xfe,0xf2,0xb2,0xfa,0xa4,0x19,0x96,0x63,0x4f, +0xcf,0x76,0xbf,0x53,0x2d,0x0d,0xf7,0x11,0xbe,0x39,0x7a,0x1d,0x0c,0x83,0xe7,0xe1, +0x1c,0xfa,0x84,0x2c,0xfa,0xe4,0xee,0x99,0x41,0xe7,0x61,0x74,0x7a,0xc3,0xa0,0x53, +0x79,0x90,0xfb,0x3d,0x6b,0x6b,0xc8,0xd7,0x38,0xe8,0x8c,0x44,0x27,0x1a,0xbf,0x26, +0x41,0xa7,0x64,0xd3,0xa0,0x73,0xcd,0x60,0xda,0x13,0x3c,0x57,0x8f,0xdf,0x44,0xe8, +0xfc,0x7a,0x2e,0x4d,0x86,0x38,0xce,0x25,0x43,0xdc,0xef,0x5f,0xc7,0x9a,0xef,0xdf, +0xa1,0x74,0x7d,0xc7,0x39,0x9b,0xbe,0x37,0xed,0xbc,0xa0,0x53,0xcf,0xac,0x41,0x8d, +0x9a,0x6f,0xfc,0x1f,0xa3,0xfe,0x16,0xa5,0xdf,0x9c,0xd2,0x2a,0xe8,0xcc,0x87,0x46, +0xad,0x83,0xce,0x61,0xc2,0xe6,0xcb,0x70,0xbf,0x91,0x3d,0x80,0xfb,0x6b,0x38,0xbd, +0x4d,0xd0,0x49,0x86,0x32,0xc3,0xb8,0x06,0xc2,0x7c,0x3f,0x6b,0xbe,0x4b,0xbd,0x0d, +0x6d,0x8c,0xde,0x97,0x61,0xbe,0x05,0xa7,0x3c,0x87,0xbb,0x6b,0x1b,0x98,0xef,0x6a, +0xb7,0xe1,0x57,0xb1,0x7d,0x30,0xf7,0x3b,0xe6,0x07,0xd1,0x37,0xc0,0x7c,0x8b,0xbd, +0x1b,0xaa,0x37,0x70,0xbf,0x67,0x6e,0x0e,0xad,0x60,0x44,0xc7,0xa0,0xf3,0xcc,0xc5, +0x2e,0x5f,0xe1,0x0e,0x72,0x73,0x9e,0xde,0x89,0xf2,0xbb,0x96,0x3e,0x0f,0x2a,0xe1, +0x1e,0x79,0x49,0xd0,0x59,0x37,0x82,0xdf,0x85,0xd8,0x77,0xa2,0xdb,0x34,0x49,0xe0, +0xa6,0xce,0x41,0xa7,0x3b,0x1a,0xa0,0x5e,0xad,0x40,0x83,0xd7,0x73,0x3f,0x87,0x14, +0xdc,0x95,0xbb,0x05,0x9d,0x26,0xd0,0x11,0xfb,0x87,0xe8,0x35,0x37,0x70,0x6d,0xbb, +0x07,0x9d,0x89,0xe8,0x21,0x7d,0xe3,0xfb,0xd1,0xe5,0x41,0x27,0xb6,0x07,0x7d,0x3c, +0xf6,0xa9,0x68,0x36,0xda,0x99,0xba,0xf8,0x3e,0xc7,0xcc,0xc6,0x1e,0x31,0xca,0x71, +0x0a,0x70,0xf3,0xad,0x87,0xce,0xa5,0xff,0x79,0xa6,0x57,0xd0,0x99,0x0b,0xf7,0x10, +0xe6,0xe1,0x64,0xb7,0x7d,0x47,0xc2,0xa3,0xe3,0x69,0xcf,0x84,0xbb,0x0b,0xfb,0x6d, +0xf0,0x08,0xcc,0xa1,0x1f,0x9c,0x65,0x14,0x16,0xc2,0x0e,0xa8,0xd3,0x27,0x98,0xbb, +0x36,0xc2,0x59,0x63,0xb8,0xe6,0xf0,0x3c,0xc4,0xc2,0x42,0xf8,0x7c,0x8c,0xfb,0xed, +0x76,0x5b,0x74,0x15,0xbc,0x05,0x39,0x90,0xd6,0x37,0xe8,0xf4,0xe9,0x47,0x9a,0xd0, +0xaa,0x3c,0xac,0xec,0x27,0xcc,0x01,0x38,0x65,0x2c,0xe1,0x06,0x07,0x9d,0xcb,0xd1, +0x6a,0x03,0x82,0xce,0xa5,0xec,0xeb,0x0a,0xb3,0xb0,0xaf,0xcb,0xe6,0x18,0xec,0xad, +0xb5,0x06,0x45,0x2f,0xe8,0x0d,0xd3,0x60,0x1c,0x14,0xbe,0x99,0xfe,0xed,0x26,0xf7, +0xdb,0xe6,0xca,0xd0,0x07,0x6e,0x82,0x0d,0x1c,0xf3,0x29,0x1a,0x18,0x47,0x5f,0x84, +0xbd,0x8b,0xd6,0x04,0xef,0x35,0x34,0xe8,0x6c,0x40,0x3f,0x81,0x54,0x1e,0x96,0x0e, +0xa1,0xaf,0x70,0xaf,0x7a,0x61,0x78,0xd0,0xe9,0x79,0x75,0xd0,0x59,0x84,0xdf,0x0a, +0x98,0xac,0x6f,0xa1,0xcd,0x77,0xd0,0x66,0xbd,0xf0,0xa9,0x23,0x82,0xce,0x74,0x74, +0x29,0x94,0xe6,0x19,0x61,0x18,0x54,0xbf,0x21,0xe8,0x44,0xe6,0x0b,0x3a,0xab,0xb1, +0xbf,0x0a,0xfb,0xe0,0x13,0xdc,0xef,0xdd,0xe9,0x7e,0x37,0xbd,0x6e,0x6c,0xd0,0xd9, +0x03,0xf7,0xf2,0x9c,0xb1,0x1f,0x8a,0xf1,0xbc,0x10,0x7f,0x73,0xd0,0x29,0x8d,0xd6, +0xbc,0x9b,0x34,0xc2,0x46,0xf3,0x4d,0x35,0x1c,0xbc,0x87,0xfb,0xe3,0xbd,0xa4,0xe7, +0xb6,0xa0,0x73,0xdb,0x44,0xda,0x09,0x0f,0x6f,0xf3,0x26,0x9a,0xf3,0x04,0x9d,0x1d, +0xd8,0x5f,0xbb,0x8f,0xeb,0x48,0xff,0x1d,0x7b,0x3f,0xf5,0x82,0xfb,0xec,0x19,0x77, +0xd3,0xcf,0xf3,0x20,0x35,0x14,0xb6,0xe0,0x97,0xff,0xde,0xa0,0x33,0x1b,0xfb,0x7d, +0xa8,0xf9,0x1e,0xdb,0x70,0x2e,0xbc,0x34,0x31,0xe8,0x6c,0x45,0x93,0x79,0x08,0x3c, +0x77,0x12,0xd7,0x1d,0x96,0xc1,0xcf,0xf0,0x36,0x7e,0x09,0x0f,0x05,0x73,0xbf,0xdb, +0xce,0x78,0x98,0xfb,0x03,0xbc,0xcd,0x83,0xe2,0x1e,0xe8,0xf5,0x08,0xf6,0xc9,0x41, +0xe7,0x07,0xec,0xa1,0x29,0x41,0xa7,0xf0,0xe3,0x41,0xe7,0x2e,0x30,0x6b,0x8f,0xb7, +0x6f,0xe9,0xae,0x39,0xfe,0x33,0x84,0x1e,0x73,0x9c,0x22,0x70,0x8a,0xd6,0x1c,0xcf, +0x9d,0x30,0x40,0xb1,0x07,0x23,0x22,0x43,0x51,0xd1,0xf9,0x62,0xf2,0x17,0x28,0x58, +0xa8,0x30,0x41,0x72,0x97,0xda,0x2d,0x5e,0xa2,0x64,0xa9,0x53,0xe8,0x37,0x9d,0x23, +0xdb,0x69,0xa7,0x73,0xcf,0x74,0xfe,0x17,0x5b,0x69,0xe7,0xcc,0xb3,0xca,0x94,0xfd, +0x83,0x23,0x75,0xff,0xaa,0x55,0x85,0xd8,0xb3,0x5d,0xe7,0x39,0x74,0x1e,0x95,0x2a, +0x9f,0x5b,0xa5,0x6a,0xb5,0xb8,0xf8,0xea,0x09,0x89,0x49,0xc9,0x4e,0x4a,0x6a,0xee, +0x63,0xda,0x1f,0xb4,0xd5,0xf0,0x1e,0xf5,0xfe,0xb0,0xad,0xd6,0xb1,0x3c,0x6b,0xd7, +0x39,0xca,0x59,0xb7,0x66,0x3d,0x77,0x3e,0x57,0x03,0x27,0xbc,0x85,0xb7,0xf0,0x16, +0xde,0xc2,0x5b,0x78,0x0b,0x6f,0xe1,0x2d,0xbc,0x85,0xb7,0xf0,0x16,0xde,0xc2,0x5b, +0x78,0x0b,0x6f,0xff,0xd2,0x6d,0xc7,0xb1,0xb6,0x9d,0x39,0x6c,0x3b,0x37,0x9a,0xff, +0x73,0x56,0xad,0x3a,0xf2,0xbf,0xb6,0x80,0xd9,0x8c,0xc5,0x0b,0xbf,0x6f,0x87,0xeb, +0xc8,0xc9,0x71,0x72,0xff,0xc7,0x41,0x14,0x3b,0xbe,0xd8,0xb5,0xcb,0xfc,0x3b,0x2a, +0xea,0x70,0x89,0x1f,0xfb,0x12,0x84,0x8b,0x41,0x5b,0x6e,0xa5,0x32,0xff,0x7d,0xa2, +0xea,0xe5,0xd6,0xb9,0x5c,0xbf,0x4f,0xb6,0xef,0xc8,0x7d,0x47,0x59,0xc4,0xbc,0x9e, +0xcc,0x7d,0x3f,0x79,0xaa,0x79,0x29,0xb9,0x23,0xc7,0x29,0xfe,0x47,0xb7,0x87,0x32, +0x65,0xcb,0x9d,0xec,0xa1,0xa5,0xcd,0x3b,0xca,0x72,0xe5,0x2b,0x98,0x24,0xef,0x50, +0x2e,0x72,0xfc,0x81,0x62,0xff,0xcc,0x56,0xed,0x5a,0x72,0x72,0xd5,0x39,0x56,0x6a, +0x8e,0xb1,0x9d,0x7d,0x9c,0x98,0xdd,0x2b,0x61,0xae,0x88,0xf9,0x97,0x1b,0xbd,0x6b, +0x76,0xfc,0x4d,0xba,0xba,0x9c,0x23,0x09,0xcd,0xf9,0x4f,0x41,0x8f,0x74,0x8d,0xce, +0xaf,0xae,0x93,0xa9,0xc7,0x39,0x39,0xbf,0x2b,0xb1,0xea,0x5e,0x4f,0x32,0x7b,0x39, +0x76,0xb7,0xac,0xd4,0xeb,0x8a,0xb9,0x7b,0xa9,0xa4,0xaa,0x99,0x39,0xbf,0xbb,0xdf, +0x89,0xf6,0x7b,0xc4,0xa8,0x82,0xfc,0x49,0x17,0xf4,0x98,0xe7,0x3f,0xb9,0x52,0xfe, +0x1f,0x9f,0xdf,0x09,0x9f,0xff,0x8f,0xdc,0xfe,0x2a,0xf9,0xbf,0xb0,0xd3,0xbf,0xa1, +0xfc,0x63,0x62,0xfe,0x52,0xd7,0xff,0xcf,0x3d,0x79,0xaf,0x5e,0x47,0x9f,0xaf,0x0f, +0xdb,0x9f,0x79,0xfe,0xa1,0x43,0x8f,0x3e,0xff,0x35,0xd7,0x98,0x19,0x70,0x7f,0xe0, +0x63,0xd8,0x7f,0xba,0x7b,0xe5,0x60,0x36,0xfe,0xc6,0x88,0x47,0x8d,0x76,0x6e,0xcc, +0xb5,0x8c,0x66,0xe3,0x7f,0xee,0x5b,0x31,0xce,0xef,0xbd,0x65,0xe4,0xfc,0xd9,0x95, +0x2d,0xfa,0x18,0xb5,0xff,0x0f,0x28,0xf4,0x7f,0xde,0x2f,0x9b,0xbf,0x63,0xb2,0x8f, +0x77,0x69,0x63,0xfe,0xda,0xa9,0xff,0xa3,0x1e,0x6f,0xfe,0x5a,0xdb,0xf6,0xbf,0x58, +0x7a,0x3e,0xd9,0xf1,0x4f,0x6b,0xad,0x47,0xff,0xfc,0xf8,0x6f,0xde,0x95,0x8f,0xbc, +0x0c,0x3a,0xe9,0xd3,0x1c,0xfd,0x4a,0xc0,0xc9,0xc9,0xb1,0x7f,0x6d,0xff,0x49,0xdd, +0x4d,0xf4,0x6f,0xeb,0x0f,0x76,0xe4,0xfc,0xae,0x77,0x60,0xbf,0xe7,0x86,0x13,0xfd, +0x07,0xc5,0x93,0xf7,0xa3,0xe7,0x5f,0xe9,0x96,0x13,0xf0,0xaa,0x87,0xf9,0xdf,0x09, +0xb8,0x9b,0x75,0x7f,0xdd,0x91,0x1b,0xee,0x9f,0x72,0x8b,0xcd,0xf9,0xf5,0xbd,0xc6, +0x8e,0x5d,0x1f,0xe4,0xac,0xda,0x71,0x22,0xdb,0xce,0xed,0xdb,0x73,0x3e,0xda,0xf1, +0x45,0xce,0x3f,0xaf,0x0f,0xdb,0xb1,0x23,0x10,0x30,0x39,0x0c,0x18,0xf1,0x2e,0x36, +0xf6,0x9c,0x1d,0x7a,0x65,0xed,0xfc,0xab,0xb7,0xbf,0xda,0x13,0x59,0xcc,0x9f,0x90, +0xe1,0xff,0xb8,0x9d,0x78,0x4c,0x1f,0x6d,0xdf,0xf9,0xc9,0x96,0x2d,0x7f,0x5a,0xc9, +0xe4,0xcb,0xf7,0x8f,0xac,0x7f,0x47,0x5f,0x93,0xe3,0x5f,0xbd,0x3f,0xbe,0x3e,0xfc, +0xf6,0x6a,0xf8,0x57,0x7d,0xee,0x8f,0x39,0xa9,0xfa,0xff,0x3b,0x5e,0x09,0xe4,0xfc, +0x25,0x8a,0x29,0xfa,0xef,0xf3,0x5b,0xec,0xbf,0xd1,0x80,0x72,0x87,0x71,0x74,0x19, +0xcd,0xb8,0xc4,0x5f,0xb2,0xdb,0xfd,0xfb,0x35,0x94,0x63,0x6e,0x67,0x38,0xff,0xf6, +0x6d,0x87,0x3d,0x08,0x9b,0x13,0x1e,0xa7,0xfe,0x47,0x6d,0x39,0xe1,0x2c,0xfe,0x0f, +0x5b,0xd5,0x5f,0xb1,0xb0,0x4e,0x38,0x51,0x3b,0x02,0x39,0x7f,0x9f,0x1b,0xc9,0xef, +0xfc,0x99,0x1b,0x9e,0x9f,0xf3,0x17,0x69,0x34,0x7f,0x78,0x7d,0xcf,0xc9,0xf9,0xa3, +0x22,0x72,0x27,0xc2,0xfc,0x96,0x08,0x77,0xfc,0x03,0xde,0xc2,0xc4,0xfc,0xd6,0x90, +0xbf,0xbd,0xff,0x88,0x89,0xfe,0x83,0x2a,0xd5,0x49,0xd7,0xaa,0xdf,0xfb,0x02,0x35, +0xfa,0xbf,0x53,0xf2,0x7f,0xe2,0x2b,0xd9,0x98,0xe8,0xbf,0x5f,0x15,0x8d,0xfe,0xc3, +0x6f,0x55,0xd1,0x27,0x3e,0xff,0xe2,0xc8,0x4f,0xef,0x7f,0xde,0x64,0xcf,0x98,0xff, +0x50,0xf7,0x76,0x84,0x2b,0xe3,0x3f,0x3b,0xf3,0x31,0xff,0xa2,0x6c,0xc7,0x38,0xe1, +0x2d,0xdc,0xec,0xfe,0xff,0x93,0xc0,0x5f,0xba,0x20,0x62,0xfe,0x9c,0x38,0x63,0xfe, +0xa5,0xad,0x2d,0xdc,0x27,0xfc,0x77,0xa6,0xc2,0xc5,0xfc,0xcd,0xfa,0x80,0xf0,0xf6, +0x37,0xd9,0x7e,0x9d,0x0b,0xf2,0xdb,0x7f,0x2f,0x86,0x5f,0x07,0xfd,0x8d,0xb7,0xa8, +0xa8,0xbf,0x55,0x6d,0xfd,0x67,0x14,0xfa,0xc6,0x8d,0x6e,0xa3,0xdb,0xba,0xd1,0x6c, +0x9e,0xaf,0xf7,0x39,0xe9,0xaf,0x93,0xfa,0x8e,0xdf,0xf2,0xfe,0x8a,0x99,0xfb,0x7b, +0xf7,0x06,0xd6,0x27,0x6e,0xfe,0x69,0x02,0x47,0x76,0xfd,0x79,0x6f,0x2d,0xc2,0x1d, +0xeb,0x7f,0xb1,0x78,0xfe,0xed,0x37,0xae,0x9d,0x3b,0xff,0xf9,0xd3,0xff,0x7e,0xed, +0x53,0xff,0xf4,0x3e,0x24,0xfc,0x3e,0xe0,0xef,0xf9,0x40,0x9c,0xbb,0xfa,0x67,0x28, +0x14,0x1d,0xca,0x17,0x93,0x3f,0x14,0x2a,0x10,0xfa,0x75,0x2b,0x18,0x0a,0x15,0x2a, +0x1c,0x2a,0x52,0x34,0x64,0x6f,0xc5,0x42,0xff,0xec,0xad,0x78,0x89,0x50,0xc9,0x52, +0xa7,0x60,0x39,0x35,0x14,0xde,0xc2,0x5b,0x78,0x0b,0x6f,0xe1,0x2d,0xbc,0x85,0xb7, +0xf0,0x16,0xde,0xc2,0x5b,0x78,0x0b,0x6f,0xe1,0x2d,0xbc,0x85,0xb7,0x7f,0xc8,0x16, +0x70,0xfe,0x57,0x26,0xc2,0x09,0x39,0xd1,0xb9,0xa6,0x92,0x13,0xe7,0xd4,0x70,0x1a, +0x3a,0x3d,0x9c,0x5e,0xce,0x55,0xce,0x18,0x67,0x8a,0xf3,0x84,0xf3,0xbc,0xb3,0xc0, +0x59,0xec,0xbc,0xeb,0xec,0x77,0xbe,0xc5,0x84,0x02,0x25,0x02,0xe5,0x03,0x4d,0x02, +0x2d,0x02,0x1d,0x02,0x9d,0x02,0xfd,0x02,0x57,0x1f,0x65,0x26,0x05,0x1e,0x0b,0x4c, +0x0b,0xcc,0x0d,0x6c,0x08,0x7c,0x18,0xf8,0x3c,0xf0,0x7d,0xa0,0x44,0xf0,0xd4,0x60, +0xf9,0x60,0x5c,0x30,0x39,0x98,0x15,0xec,0x11,0xec,0x8d,0xb9,0x3a,0x78,0x73,0xf0, +0xfe,0xe0,0xc2,0xe0,0xd2,0xe0,0x3b,0xc1,0xf5,0xc1,0xcf,0x83,0x07,0xfe,0x8b,0xe6, +0xe0,0x6f,0x30,0x81,0x88,0x40,0x44,0x44,0x44,0x28,0x22,0x26,0xa2,0x40,0xae,0x29, +0xf1,0xab,0x29,0xf5,0xab,0x39,0x2b,0x22,0x36,0xe2,0x1c,0x4c,0x25,0x99,0xea,0x96, +0xa9,0x81,0x49,0x8f,0xa8,0x1d,0x51,0x3f,0xa2,0x41,0xae,0x69,0xf6,0xab,0x69,0xf1, +0xab,0x69,0x1b,0xd1,0x31,0xa2,0x13,0xe6,0x52,0x99,0x1e,0x47,0x99,0x7e,0x11,0x57, +0xfd,0x47,0x73,0x75,0xc4,0x75,0x7f,0xba,0x19,0x15,0x31,0x36,0x4f,0x73,0x73,0xc4, +0x2d,0xbf,0x9a,0xdb,0x22,0xee,0x38,0xca,0x8c,0x8f,0xb8,0x2b,0xe2,0x9e,0x88,0x89, +0x27,0x68,0xee,0xff,0xdd,0x66,0x4a,0xc4,0xf4,0xff,0x60,0xe6,0x46,0x2c,0x3e,0xca, +0x2c,0xfd,0x53,0xcc,0x6b,0x11,0x6f,0xfc,0x8f,0xcc,0x8a,0x88,0x37,0x23,0x56,0x47, +0xac,0xf9,0xd5,0xbc,0x13,0xf1,0xee,0x3f,0xc2,0xac,0x0f,0x9b,0x7f,0xb5,0xf9,0x54, +0xe6,0x0b,0xcc,0x01,0x4c,0x20,0xf2,0x88,0x89,0xc1,0x14,0x90,0x39,0x55,0xa6,0x7c, +0xae,0x89,0xc5,0x9c,0x93,0x6b,0x52,0x65,0xea,0x62,0x9a,0x61,0x3a,0x5a,0xa6,0x2b, +0xa6,0x87,0xcc,0x55,0x32,0xa3,0x22,0x6f,0x8e,0xbc,0x23,0xd7,0x8c,0x97,0xb9,0xe7, +0x4f,0x33,0x13,0x8f,0x61,0x26,0xe5,0x9a,0x87,0x30,0x53,0x22,0x9f,0x8a,0x7c,0x26, +0x72,0x06,0x66,0x96,0xcc,0x9c,0x5f,0xcd,0x2b,0x32,0x0b,0x65,0x16,0x63,0x96,0xe6, +0x9a,0x37,0x72,0xcd,0x0a,0xcc,0x9a,0xc8,0x77,0x23,0xd7,0x47,0x6e,0xc2,0x7c,0x2c, +0xb3,0xf9,0x57,0xf3,0xb9,0xcc,0x17,0x32,0xbb,0x31,0x7b,0xfe,0x9f,0xd9,0xfb,0x3b, +0xcc,0xfe,0xc8,0x03,0xff,0x08,0xf3,0x6d,0xe4,0xf7,0xff,0xd1,0x1c,0x8c,0xfc,0xf1, +0xa4,0x4c,0x78,0x28,0xf0,0xdf,0xbe,0xfd,0x18,0xf9,0xc7,0x9a,0x40,0xe8,0xf7,0x1a, +0x1e,0x89,0xff,0x65,0xbf,0xc7,0xa2,0x8f,0x6b,0x62,0x72,0x4d,0x81,0xbf,0x89,0x29, +0xe4,0x33,0x45,0x72,0x4d,0xb1,0xb0,0x39,0x21,0x53,0xea,0x5f,0x6f,0x4a,0xff,0x25, +0xcd,0x59,0x7f,0x92,0x29,0x1f,0x8a,0xfd,0x97,0x9b,0x73,0xfe,0x75,0xa6,0xd2,0x51, +0x26,0x4e,0xa6,0xfa,0xbf,0xd6,0x24,0x87,0x52,0xc3,0xe6,0xb8,0xa6,0x76,0xae,0xa9, +0xfb,0x17,0x34,0xf5,0xc3,0xe6,0x6f,0x6e,0x1a,0x60,0x1a,0x62,0xb2,0x30,0x4d,0x30, +0xcd,0x64,0x5a,0xfc,0xe1,0xa6,0x25,0xa6,0x15,0xa6,0x4d,0xa8,0x6d,0xae,0x69,0x17, +0x36,0xff,0x12,0xd3,0x21,0xd4,0xf1,0x0f,0x31,0x9d,0x42,0x97,0x1e,0x65,0x3a,0x87, +0xba,0xfe,0xcf,0x4c,0x8f,0x50,0xef,0x93,0x32,0x7d,0x42,0xfd,0x4e,0xc8,0x0c,0x08, +0x0d,0xfc,0x93,0xcc,0xd5,0xa1,0x51,0xa1,0x31,0xa1,0xb1,0xa1,0x9b,0x43,0xb7,0x84, +0x6e,0x0b,0xdd,0x11,0x9a,0x18,0x7a,0x24,0xf4,0x58,0x68,0x4a,0xe8,0x89,0xd0,0x53, +0xa1,0x67,0x42,0xd3,0x42,0xcf,0x87,0x66,0x1d,0x65,0xe6,0x86,0x16,0x1c,0x65,0x96, +0x86,0xde,0x0c,0xad,0x0e,0xad,0x09,0xbd,0x13,0x7a,0x37,0xb4,0x3e,0xf4,0x7e,0xe8, +0xe3,0xd0,0x67,0xa1,0xcf,0x43,0x5f,0x84,0x76,0x87,0xf6,0x84,0xf6,0x86,0xf6,0x87, +0xbe,0x0f,0xfd,0x74,0x94,0x89,0x88,0x8a,0x39,0xca,0x14,0x8a,0x2a,0x76,0x94,0x29, +0x15,0x75,0xfa,0x51,0xa6,0x6c,0xd4,0x39,0x3e,0x53,0xf5,0x28,0x93,0x1c,0x55,0x3b, +0xaa,0x6e,0x54,0xfd,0xa8,0x06,0x51,0x0d,0xa3,0xb2,0xa2,0x9a,0x44,0xb5,0x8a,0xea, +0x10,0xd5,0x31,0xaa,0x53,0xd4,0xa5,0x51,0x9d,0xa3,0xba,0x46,0x75,0x8f,0xea,0x21, +0xd3,0xcb,0x67,0x7a,0xff,0x0f,0x4c,0x9f,0xff,0x67,0x06,0x1e,0x65,0x06,0xff,0x97, +0xcd,0x55,0x3e,0x73,0x6d,0xd8,0x9c,0x80,0xb9,0x0e,0x73,0x03,0x66,0xd4,0xff,0xc8, +0x8c,0xc1,0x8c,0xc5,0xdc,0xfc,0x5f,0x36,0xb7,0xfc,0x6a,0x6e,0xcb,0x35,0x77,0x9c, +0xa4,0x19,0x8f,0xb9,0xeb,0xa4,0xcc,0x3d,0x47,0x99,0x89,0x98,0xfb,0x73,0xcd,0xa4, +0x5f,0xcd,0x43,0x27,0x68,0x1e,0xc9,0x35,0x8f,0x45,0x4d,0xc9,0xd3,0x3c,0x11,0xf5, +0x54,0xae,0x79,0x26,0x6a,0x5a,0xae,0x99,0x1e,0xf5,0x7c,0xd4,0x8c,0xa8,0x59,0xbf, +0x9a,0x39,0x51,0x73,0x73,0xcd,0xbc,0xa8,0x05,0xc7,0x30,0xaf,0x44,0x2d,0x3c,0x8e, +0x59,0x6c,0x99,0xa5,0x51,0xaf,0x61,0xde,0x38,0xca,0xac,0x88,0x7a,0x33,0x6a,0x75, +0xd4,0x9a,0xb0,0x39,0xae,0x79,0xe7,0x57,0xf3,0x2e,0x66,0x3d,0xe6,0x7d,0xcc,0x06, +0xcc,0x87,0x98,0x4d,0x98,0x8f,0x31,0x9b,0x31,0x9f,0x62,0xb6,0x61,0x3e,0xc3,0x7c, +0x9e,0x6b,0xbe,0xc0,0xec,0xc6,0xec,0x39,0xca,0xec,0xcf,0x35,0xdf,0xe6,0x9a,0x83, +0xb9,0xe6,0xa7,0x5c,0x13,0x88,0xfe,0xfd,0x26,0xe2,0xff,0x99,0x23,0x2f,0x72,0xcd, +0x16,0x83,0x29,0x80,0x29,0x84,0x29,0x82,0x29,0x86,0x29,0x81,0x29,0x85,0x39,0x15, +0x73,0x3a,0xa6,0x34,0xe6,0xac,0x5c,0x53,0x16,0x53,0x1e,0x13,0x7b,0x94,0xa9,0x94, +0x6b,0xaa,0xe6,0x9a,0xea,0xb9,0x26,0x39,0xd7,0xd4,0x38,0x41,0x93,0x1e,0x5d,0x3b, +0xba,0x6e,0x74,0xfd,0x63,0x9a,0x06,0x61,0xf3,0x1b,0x4d,0x43,0x4c,0xd6,0x31,0x4c, +0x93,0xb0,0xc9,0xc3,0x34,0x8b,0x6e,0x11,0x36,0x61,0x73,0x82,0xa6,0x55,0xd8,0x84, +0xcd,0x3f,0xde,0xb4,0x0b,0x9b,0x7f,0xb5,0xe9,0x10,0xdd,0xf1,0x5f,0x6b,0x3a,0x85, +0xcd,0x5f,0xd0,0x84,0x67,0x49,0x85,0xb7,0xf0,0x16,0xde,0xc2,0x5b,0x78,0x0b,0x6f, +0xe1,0x2d,0xbc,0x85,0xb7,0xf0,0x16,0xde,0xc2,0x5b,0x78,0x0b,0x6f,0xe1,0x2d,0xbc, +0x85,0xb7,0xf0,0x16,0xde,0xc2,0x5b,0x78,0x0b,0x6f,0xe1,0x2d,0xbc,0x85,0xb7,0xf0, +0x16,0xde,0xc2,0x5b,0x78,0x0b,0x6f,0xe1,0x2d,0xbc,0x85,0xb7,0xf0,0x16,0xde,0xc2, +0x5b,0x78,0x0b,0x6f,0xe1,0x2d,0xbc,0x85,0xb7,0xf0,0x16,0xde,0xc2,0x5b,0x78,0x0b, +0x6f,0xe1,0x2d,0xbc,0x85,0xb7,0xf0,0x16,0xde,0xc2,0x5b,0x78,0x0b,0x6f,0xe1,0x2d, +0xbc,0x85,0xb7,0xf0,0x16,0xde,0xc2,0x5b,0x78,0x0b,0x6f,0xe1,0x2d,0xbc,0x85,0xb7, +0xf0,0x16,0xde,0xc2,0x5b,0x78,0x0b,0x6f,0xe1,0x2d,0xbc,0x85,0xb7,0xf0,0x16,0xde, +0xc2,0x5b,0x78,0x0b,0x6f,0xe1,0x2d,0xbc,0x85,0xb7,0xf0,0x16,0xde,0xc2,0xdb,0xdf, +0x6f,0xab,0x19,0xe1,0x38,0xfd,0x2b,0xb8,0xda,0x45,0x3a,0x00,0x75,0xd0,0x25,0x48, +0x00,0x5d,0x8a,0x06,0xd1,0x65,0xc6,0x1b,0x7d,0x0d,0x8d,0x8c,0x30,0x3b,0x1d,0x27, +0x0a,0x0d,0xa2,0xd1,0x68,0xc5,0xa0,0xe3,0xe4,0x43,0x5f,0x67,0x57,0x0c,0xfa,0x78, +0x19,0xc7,0xc9,0x8f,0xbe,0x81,0xbb,0x20,0xba,0x86,0x70,0x45,0xcc,0x71,0x84,0x2b, +0x66,0x8e,0x43,0x63,0xd1,0xc9,0x84,0x3b,0xc7,0xf8,0xa3,0x95,0xd1,0x48,0xc5,0x17, +0x2c,0xe3,0xee,0x8f,0x44,0x13,0xd1,0xa8,0x32,0x6e,0x7a,0xa2,0x02,0x6e,0x7a,0xf2, +0x29,0x5c,0xfe,0x80,0x1b,0x7f,0x41,0xb4,0x12,0xba,0xc2,0x91,0x7f,0x19,0xd7,0xbf, +0x70,0xc0,0x8d,0xa7,0x60,0x19,0x77,0x7f,0x51,0x34,0x0e,0x2d,0xae,0x78,0x0b,0x97, +0x71,0xf3,0xbb,0x52,0xf9,0x7d,0x53,0xf9,0x5d,0xa5,0xfc,0xbe,0x5a,0xc6,0xcd,0x6f, +0x71,0xe5,0xb7,0xa4,0xce,0x7b,0x4a,0xc0,0xcd,0xef,0x6a,0xe5,0xf7,0x65,0x9d,0xef, +0x0c,0xe5,0x33,0x52,0xf9,0x8c,0x52,0x3e,0xe7,0xeb,0xfc,0x95,0x83,0x6e,0x3e,0x4f, +0x0b,0xb8,0xe9,0x38,0x0d,0xff,0x04,0x73,0x5c,0x19,0x37,0xde,0x32,0xca,0xe7,0x37, +0xca,0xe7,0x99,0x01,0xf7,0xfc,0xe5,0xca,0xb8,0xe7,0x2f,0xa3,0xf3,0x97,0x53,0xbe, +0x77,0x28,0xdf,0x15,0x14,0xfe,0x6c,0xed,0xaf,0x50,0xc6,0x4d,0x5f,0x45,0xa5,0xab, +0x8c,0xd2,0x71,0xb6,0x97,0x0e,0x34,0x1e,0xad,0xa2,0xfc,0xbf,0xa5,0xfc,0xaf,0x51, +0xfe,0xdf,0x56,0xfe,0x2b,0xeb,0xfc,0x55,0x94,0xff,0x6a,0x8a,0x3f,0x41,0xf9,0x7f, +0x47,0xf9,0x5f,0xa9,0xf3,0xbc,0xa3,0xfc,0xe7,0x53,0xfe,0xf3,0xeb,0xbc,0xab,0x74, +0x7d,0xe3,0x03,0x6e,0x7e,0xab,0x95,0x71,0xcf,0x93,0x12,0x70,0xcf,0x9b,0xa0,0xe3, +0x77,0xea,0x7a,0x25,0x29,0x9d,0x69,0x01,0xf7,0x3a,0xa5,0xa8,0x5c,0xd2,0x95,0xef, +0xba,0x0a,0x97,0xa6,0x70,0xb5,0x55,0x9e,0x75,0x74,0x5d,0x6b,0x29,0x7c,0x3d,0x95, +0x6b,0x86,0xea,0x53,0xa6,0xf2,0xfb,0x83,0xce,0xdb,0x30,0xe0,0xe6,0xf3,0x5d,0xd5, +0x9b,0x46,0x4a,0x47,0x13,0xc5,0xdf,0x58,0xf1,0x67,0x29,0xfe,0xe6,0x8a,0xbf,0xa9, +0xe2,0x59,0xa7,0x72,0x5b,0xaf,0x72,0x7b,0x4f,0xe5,0xf6,0xbe,0xda,0xc9,0x79,0x2a, +0xb7,0xf3,0x55,0x6e,0xf1,0x6a,0x27,0x1f,0xa8,0xdc,0xde,0x26,0x9e,0x02,0x68,0x6b, +0xe5,0xeb,0x5d,0x95,0x5f,0x41,0x95,0x5f,0x61,0xb4,0xb4,0x69,0x27,0x4a,0xcf,0x5b, +0x2a,0xc7,0x5d,0x4a,0xff,0x85,0xca,0x5f,0x7b,0xe5,0xf7,0x42,0x9d,0xe7,0x22,0xe5, +0xe3,0x22,0xc5,0x57,0x54,0xf1,0x15,0xd7,0xf5,0xb8,0x58,0xf9,0x6a,0xaf,0xf2,0xbd, +0x4c,0xc7,0x5f,0xac,0x7a,0x74,0x89,0xe2,0xe9,0xa2,0x78,0xba,0xe8,0xfc,0xdd,0x70, +0x57,0x34,0xf5,0x36,0xe8,0x1e,0x7f,0x99,0xc2,0x5d,0xa9,0x70,0x97,0x2b,0x5c,0x5f, +0x85,0x3b,0x43,0xe1,0xba,0xa9,0xfc,0xb2,0x55,0x7e,0xfd,0x55,0x7e,0x1f,0xaa,0xfc, +0x3e,0x52,0xf9,0x6d,0x52,0xf9,0x5d,0xa1,0x7a,0x77,0xa5,0xca,0xaf,0xaf,0xea,0x5b, +0x8e,0xca,0x6d,0x87,0xfa,0x97,0xfe,0x01,0xb7,0xfc,0xb2,0x55,0x7e,0xeb,0x95,0xdf, +0x92,0xca,0xef,0x29,0x2a,0xbf,0x19,0x4a,0xd7,0x76,0x8e,0x3b,0x1b,0x1d,0xa4,0x72, +0x1c,0xa4,0x74,0x0d,0x55,0x3b,0x1c,0x52,0xc6,0x3d,0xff,0x08,0xd5,0x97,0xeb,0x95, +0xce,0x91,0x2a,0x9f,0xd1,0xaa,0xb7,0x43,0x94,0xef,0x9b,0xd4,0xce,0x6e,0x54,0xf8, +0x71,0xba,0x1e,0xb7,0xca,0xff,0x76,0x1d,0xff,0xb5,0x8e,0xff,0x58,0xf9,0x1c,0xaa, +0x7a,0xf7,0x83,0xfa,0x97,0xa4,0xa0,0x7b,0xdc,0x9d,0x3a,0x6e,0x78,0xc0,0xcd,0xe7, +0x77,0x8a,0xf7,0x1b,0x1d,0x7f,0xb5,0xae,0xcf,0x04,0x9d,0xe7,0x5a,0xe5,0xfb,0x3a, +0xe5,0xef,0x6e,0x95,0xef,0xbd,0x3a,0xef,0x16,0x95,0xef,0xa7,0x3a,0xef,0x56,0x95, +0xef,0x36,0xd5,0xcf,0x80,0xca,0x37,0x42,0xf9,0xa9,0xa4,0xfa,0xb9,0x5d,0xe5,0xfc, +0x84,0xca,0xf9,0x33,0xf5,0xe3,0x6f,0xab,0x7c,0x03,0x2a,0xdf,0x08,0xd5,0xa7,0x29, +0xea,0xc7,0x03,0x2a,0xd7,0x90,0xe2,0x8b,0x50,0xfa,0x43,0x4a,0x57,0xb4,0xf2,0x11, +0xad,0x7c,0xc4,0x28,0x5c,0x01,0xe5,0xa3,0x90,0xfa,0xb3,0xcf,0xd5,0x1e,0x0b,0xa8, +0x5e,0x15,0x51,0xfe,0x0a,0xa9,0xde,0x16,0x53,0x3f,0x5e,0x42,0xf1,0x16,0x51,0x7e, +0x77,0x2a,0xbf,0x5f,0x28,0xbf,0xbb,0x94,0xdf,0x85,0x2a,0xe7,0x12,0xca,0x6f,0x29, +0x9d,0xf7,0x54,0xd5,0xab,0xdd,0xca,0xef,0x2b,0x3a,0x5f,0x69,0xe5,0x33,0xa4,0x7c, +0x46,0x2b,0x9f,0x0b,0x74,0xfe,0x73,0xd5,0x8f,0x9f,0xae,0xfa,0x73,0xba,0xea,0x4f, +0x69,0x5d,0x97,0xb2,0xca,0xe7,0xb7,0xca,0xe7,0x59,0xaa,0xcf,0xe5,0xd5,0x8f,0x97, +0xd5,0xf9,0xcb,0x2b,0xdf,0x9f,0x2b,0xdf,0xb1,0x0a,0x7f,0x8e,0xf6,0xc7,0xaa,0x3e, +0x54,0x52,0xba,0xca,0x2a,0x1d,0xe7,0x78,0xe9,0x50,0x3f,0x5e,0x55,0xe5,0x70,0x9f, +0xca,0xe1,0x4b,0x95,0xc3,0x1e,0x95,0xc3,0x57,0x2a,0x87,0x73,0x95,0x8e,0xaa,0x2a, +0x87,0x38,0xe5,0x7f,0xaf,0xf2,0xff,0xa6,0xce,0xb3,0x56,0xf9,0x8f,0x51,0xfe,0x0b, +0xe8,0xbc,0xab,0x75,0x7d,0xab,0xab,0x1f,0x8f,0x53,0x7b,0x48,0x55,0x3e,0xf6,0xa9, +0x5f,0x4a,0x54,0x3c,0x5f,0xe8,0xba,0x25,0x2b,0xbd,0x35,0xd4,0xdf,0xa4,0xaa,0x7c, +0x6a,0xe9,0xb8,0x7a,0x0a,0x57,0x43,0xe1,0xea,0xa8,0x5c,0xeb,0x2a,0x5f,0xb5,0x15, +0xbe,0xbe,0xca,0xb7,0x81,0xea,0x55,0x43,0xe5,0xf7,0xa0,0xce,0xdb,0x48,0xed,0x6a, +0xbf,0xea,0x4f,0x96,0xd2,0xd1,0x54,0xf1,0x37,0x51,0xfc,0x8d,0x15,0x7f,0x0b,0xc5, +0xdf,0xcc,0x6b,0xa7,0x2a,0xb7,0x03,0x2a,0xb7,0x6f,0x54,0x6e,0xdf,0xaa,0xbd,0xb4, +0x54,0xb9,0xb5,0xd2,0xf5,0xa9,0xae,0xf6,0xf2,0x9d,0xca,0xef,0x1d,0xf5,0xe7,0x6d, +0x94,0xaf,0x75,0x2a,0xc7,0x42,0x2a,0xc7,0x22,0xea,0x8f,0xa6,0x28,0x3d,0x6b,0x54, +0x9e,0xbb,0x95,0xfe,0x76,0xca,0x5f,0x07,0xe5,0xb7,0x9d,0xce,0xd3,0x51,0xf9,0xe8, +0xa8,0xf8,0x8a,0x29,0xbe,0x12,0xba,0x2e,0x9d,0x94,0xaf,0x0e,0x2a,0xdf,0xce,0x3a, +0xbe,0x93,0xea,0xd3,0xa5,0x8a,0xa7,0xab,0xe2,0xe9,0xaa,0xf3,0x77,0x57,0x3f,0x7d, +0xba,0xfa,0xe9,0xce,0x0a,0xd7,0x47,0xf5,0xee,0x7e,0x85,0xef,0xa1,0xf0,0xfd,0x14, +0xbe,0xb4,0xc2,0x77,0x57,0x39,0x0e,0x54,0x39,0x0e,0xf0,0xae,0x87,0xca,0xf1,0x90, +0xca,0xf1,0x47,0x95,0x63,0x6f,0xd5,0xbf,0x3e,0x2a,0xc7,0x7e,0xaa,0x7f,0x87,0x55, +0x7e,0x9f,0xab,0xbf,0x19,0xa0,0x7e,0x7d,0xa0,0xca,0xf1,0x3d,0xe5,0xbb,0x94,0xf2, +0x7d,0xaa,0xca,0x71,0xa6,0xd2,0xf5,0x99,0xfa,0xf5,0xc1,0x2a,0xcf,0xc1,0x4a,0xd7, +0x30,0xb5,0xcb,0xab,0xd4,0xaf,0x5f,0xa7,0x7a,0x73,0x83,0xd2,0x39,0x4a,0xe5,0x34, +0x46,0xf5,0xf8,0x2a,0xe5,0xff,0x66,0xe5,0x7f,0xac,0xd2,0xf3,0x80,0x8e,0xbb,0x45, +0xd7,0xe7,0x36,0xed,0xbf,0x43,0xf1,0x1c,0x50,0x3c,0x3f,0x29,0xbf,0xc3,0x54,0x0f, +0x0f,0xaa,0xdf,0x49,0x56,0xff,0x3e,0x5e,0xc7,0xfd,0xa2,0xfc,0x7e,0xaf,0xf8,0x27, +0x29,0xfe,0x6f,0x15,0xcf,0x35,0xba,0x6e,0x77,0xe9,0x7c,0x23,0x54,0x0e,0xd7,0x2b, +0xbf,0xf7,0xa8,0xbc,0x27,0xea,0xfc,0x7b,0xca,0xba,0xc7,0x8d,0x35,0xcf,0x38,0xe6, +0xb9,0xbd,0xac,0xeb,0xff,0xb4,0xe2,0x7b,0x52,0xf9,0x7f,0xb6,0x8c,0x7b,0xde,0xa9, +0x4a,0xd7,0x27,0xaa,0x77,0x87,0xa4,0x87,0x75,0x7d,0xb6,0xca,0x9d,0x4f,0xf1,0x2f, +0x51,0x3c,0x8b,0x14,0xcf,0xeb,0x8a,0x67,0x99,0xfc,0xe3,0xbd,0xe7,0x21,0xb9,0xd7, +0x2a,0xdc,0x07,0x0a,0xf7,0x9e,0xfc,0xcf,0xd3,0x79,0xab,0xa9,0xdd,0x9c,0x2f,0x77, +0x95,0xa0,0xbb,0xff,0xe7,0x80,0x1b,0xcf,0x26,0x9d,0x7f,0x83,0xd2,0xf3,0xbe,0xf2, +0xff,0xa1,0xf6,0x3f,0xa3,0xf8,0x9e,0xd2,0x79,0xa6,0xeb,0x3c,0xd3,0x14,0xdf,0x66, +0x1d,0xff,0xa3,0xf4,0x27,0xc5,0xb3,0x4d,0xee,0x18,0xa5,0x77,0xa9,0xe2,0x59,0xac, +0x78,0xde,0x50,0x3c,0xaf,0xc9,0xbf,0xba,0xc2,0xad,0x97,0xfb,0x5d,0x85,0xdb,0xa0, +0x70,0xef,0xcb,0xbf,0xa5,0xce,0x1b,0xa7,0x7c,0xb5,0x92,0xbb,0xaa,0xf2,0xf5,0x8b, +0xd2,0x9d,0xa3,0xf3,0x6f,0x54,0x7a,0x3e,0x50,0xbe,0x3e,0xd2,0xfe,0x99,0x8a,0xef, +0x05,0x9d,0xe7,0x45,0x9d,0x67,0xb6,0xd2,0x31,0x4b,0xfb,0x67,0x68,0xff,0x5c,0xed, +0x9f,0xa3,0xfd,0x25,0xb5,0xff,0x14,0xb9,0x4b,0xc9,0x7d,0xaa,0xdc,0xad,0xe5,0xbe, +0x40,0xee,0x36,0x72,0xb7,0x55,0x3d,0xbb,0x5c,0xda,0x43,0xda,0x53,0xda,0x4b,0xe1, +0x86,0x7b,0xcf,0x21,0xaa,0xc7,0xd7,0x48,0xaf,0x55,0xb8,0x87,0x14,0x6f,0x8e,0xc2, +0x7d,0xa4,0x74,0x6e,0x51,0x3a,0x3f,0x51,0x3d,0xdf,0xaa,0x70,0x1f,0x2b,0xdc,0x26, +0x85,0xfb,0x54,0xe1,0x36,0x2b,0xdc,0x36,0x85,0xdb,0xa5,0x70,0x3b,0x15,0xee,0x2b, +0x85,0xfb,0x52,0xe1,0xf6,0x29,0xdc,0x6e,0x85,0xfb,0x42,0xe1,0xf6,0x2a,0xdc,0x1e, +0x85,0xdb,0xaf,0xfe,0xec,0x2b,0x95,0xff,0x97,0xd2,0x3d,0xd2,0x2d,0xd2,0x4f,0xd5, +0x3f,0x9d,0xa9,0xfb,0xf5,0x59,0xba,0x9e,0x09,0x41,0x57,0x13,0x83,0x6e,0x3c,0x7b, +0x75,0xdd,0x5e,0x56,0xfb,0xbb,0x29,0xc2,0xdd,0xbf,0xa0,0xac,0x7b,0xdc,0x7c,0xb4, +0x84,0x69,0x47,0x68,0x49,0x53,0xef,0xd0,0x2c,0xf3,0xbb,0x52,0xed,0x73,0xa5,0x8e, +0x1b,0x17,0xe1,0x86,0x3b,0x4d,0xe1,0x4e,0xd7,0xfe,0x55,0xda,0x7f,0x8b,0xf6,0x57, +0xd6,0xfe,0x73,0x15,0xcf,0x5b,0x0a,0xf7,0x91,0xc2,0xdd,0xaa,0xf3,0x7f,0xa8,0xf3, +0x6f,0x2c,0xeb,0x5e,0x9f,0x67,0x75,0x7c,0x4d,0x1d,0x9f,0xae,0xe3,0x7e,0xd0,0x71, +0xb7,0x6b,0x7f,0x53,0xed,0x6f,0x26,0xfd,0x52,0xe1,0x76,0x29,0xdc,0x9d,0x8a,0xff, +0x0b,0xc5,0xbf,0x53,0xf1,0x4f,0x8f,0x70,0xc3,0x77,0x54,0xf8,0x43,0x0a,0x3f,0x5e, +0xf1,0x5e,0xa1,0xf8,0x7a,0x2b,0xdd,0x87,0xa5,0x2f,0x4a,0x5f,0xd7,0x71,0xd9,0x3a, +0xee,0x39,0x9d,0x67,0x96,0xce,0x33,0x53,0xe5,0xe8,0x28,0x9e,0x40,0x59,0xb7,0x9f, +0x7b,0x49,0xc7,0xcf,0xd1,0xf1,0x83,0x74,0xfc,0xf3,0x3a,0x6f,0x51,0x85,0x2f,0xa6, +0xfd,0x43,0xb4,0xff,0x05,0xed,0x2f,0xa7,0xfd,0xe5,0x15,0xdf,0x72,0xc5,0xf7,0x9a, +0xc2,0x0f,0x55,0xf8,0x19,0x4a,0xcf,0xbb,0x4a,0xcf,0x5a,0xe5,0x7b,0x95,0xe2,0x49, +0x50,0x3c,0x89,0x8a,0xe7,0x03,0x1d,0x3f,0x5c,0xc7,0xbf,0xa5,0x70,0x19,0x0a,0xd7, +0x40,0xf9,0xd9,0x2e,0xf7,0x67,0x0a,0x7f,0x8d,0xc2,0xaf,0xd1,0xf9,0x3e,0xd5,0xf9, +0xb6,0xe8,0x7c,0xab,0x15,0x4f,0x6b,0x1d,0xd7,0x46,0xe7,0xdb,0xa1,0xe3,0x47,0xe8, +0xf8,0xb7,0x15,0xae,0x8b,0xc2,0x75,0x55,0xb8,0xef,0x94,0xbf,0x03,0x0a,0xbf,0x4e, +0xe1,0x27,0xe8,0xbe,0xb1,0x41,0xfe,0x5b,0xe5,0x3f,0x53,0xfe,0x9f,0xeb,0xb8,0x6f, +0xe4,0xbf,0x3e,0xc2,0x4d,0xcf,0x7b,0xd2,0xe8,0x48,0x95,0x4b,0xa4,0xeb,0x5e,0x17, +0xe9,0x86,0x8b,0x88,0x74,0xe3,0x73,0xb4,0xff,0x03,0xed,0x0f,0xc8,0xbd,0x54,0xee, +0x1c,0xe9,0x27,0x0a,0x5f,0x28,0x52,0xf7,0x21,0x85,0x3b,0x5d,0xfb,0xb7,0x2b,0xde, +0x82,0x72,0xef,0x50,0xb8,0xaf,0x14,0xae,0xb0,0xfc,0xf7,0x45,0xba,0xcf,0x0f,0x5f, +0xcb,0xfd,0x8d,0xf4,0x07,0xe9,0x97,0x0a,0xff,0xae,0xdc,0xeb,0x15,0x6f,0x5b,0x9d, +0xbf,0xb5,0xf6,0x6f,0xd0,0xfe,0x36,0x72,0x2f,0x93,0xfb,0x63,0xe9,0x66,0x85,0xbf, +0x54,0xe9,0xd8,0xa6,0x70,0xe9,0xda,0xff,0x99,0xe2,0xbd,0x44,0xee,0xcf,0x15,0x6e, +0xaf,0xc2,0x5d,0x26,0xff,0xfd,0x4a,0xef,0x01,0xb9,0xbf,0x95,0x1e,0x94,0xee,0x91, +0x76,0x88,0x74,0x9f,0x83,0x86,0x4a,0x87,0xc9,0xff,0x23,0xe9,0x26,0xe9,0x2e,0xe9, +0x6e,0xb4,0x6d,0x94,0xe3,0x54,0x80,0x0b,0x21,0x16,0xda,0xc1,0x39,0x72,0x9f,0x2d, +0xad,0x28,0x5d,0x26,0x5d,0x2f,0x5d,0x02,0x75,0x62,0xe8,0x6f,0x62,0x5c,0x4d,0x94, +0xa6,0xc0,0x22,0x58,0x0d,0x1b,0xe0,0x2d,0xa8,0x57,0x80,0xe7,0x69,0x68,0x0f,0x4d, +0xa1,0x03,0x9c,0x07,0x1b,0xe0,0x5e,0x58,0x04,0xab,0xe4,0x7e,0x4b,0xee,0xd5,0x26, +0x7c,0x41,0xc2,0xc3,0xfb,0xb0,0x04,0x96,0xc1,0x2a,0xb9,0x57,0xc0,0x07,0xb0,0x52, +0xee,0xd5,0x50,0xaf,0x90,0xe3,0x34,0x87,0x0e,0x70,0x5e,0x21,0xd7,0xdd,0x02,0x56, +0xc1,0x47,0xf0,0x0e,0xe4,0xc0,0x66,0xf8,0x44,0xfe,0x1f,0x43,0x7c,0x51,0xf2,0x09, +0xa9,0xa5,0x29,0xfb,0xd2,0xae,0xe6,0x93,0xe6,0x97,0x16,0x94,0x16,0x96,0x16,0x97, +0xd6,0x96,0xd6,0x95,0x66,0x48,0x1b,0x48,0x1b,0x96,0x76,0xaf,0x6b,0x4d,0xdd,0x27, +0xd2,0xa5,0x97,0x48,0x2f,0xd5,0xfd,0xf1,0x0a,0x69,0x6f,0x3d,0x6f,0x3e,0xa7,0xfb, +0xcb,0x4b,0x72,0x3f,0x2f,0xf7,0x3c,0xb9,0x97,0x4b,0x57,0x48,0x37,0x4a,0x3f,0xd4, +0xfd,0x2e,0xa8,0xf6,0x18,0xa9,0xf6,0x1d,0xa5,0x76,0x3a,0x52,0xed,0x38,0x42,0xfb, +0x43,0xda,0x1f,0xad,0xfd,0xa3,0xa4,0xa3,0xa5,0x63,0xa4,0x37,0x4a,0xc7,0x4a,0x6f, +0x92,0xde,0xac,0xf8,0xf2,0x2b,0xbe,0x82,0x8a,0xaf,0xb0,0xf6,0x8f,0xd3,0xfe,0x02, +0xda,0x5f,0x48,0xfb,0x8b,0x68,0xff,0x2d,0xd2,0x5b,0xa5,0xb7,0x49,0x6f,0x97,0xde, +0x21,0xbd,0x53,0x3a,0x5e,0xf1,0x15,0x57,0x7c,0x25,0xe5,0x2e,0x21,0x77,0x29,0xb9, +0xcf,0x90,0xfb,0x4c,0xb9,0x4b,0xcb,0x7d,0x96,0xdc,0x15,0xe4,0x3e,0x5b,0xe9,0xa9, +0xa8,0xf8,0x27,0x68,0x7f,0xac,0xf6,0x9f,0xa3,0xfd,0x95,0xb4,0xff,0x2e,0xe9,0xdd, +0xd2,0x7b,0xa4,0xf7,0x4a,0x27,0x4a,0xef,0x93,0xde,0xaf,0xf8,0xaa,0x28,0xbe,0x6a, +0x8a,0x2f,0x5e,0xfb,0x1f,0xd0,0xfe,0xaa,0xda,0x1f,0xa7,0xfd,0xd5,0xb5,0x7f,0x92, +0xf4,0x41,0xe9,0x43,0xd2,0x87,0xa5,0x8f,0x48,0x1f,0x95,0x3e,0xa6,0xf8,0x92,0x14, +0x5f,0x8a,0xe2,0x4b,0x93,0x7f,0xb2,0xfc,0x53,0xe5,0x5f,0x43,0xfe,0xb5,0xe4,0x5f, +0x47,0xfe,0xf5,0xe4,0x5f,0x5b,0xfe,0x75,0xe5,0x5f,0x5f,0xfe,0x99,0xf2,0x6f,0x24, +0x77,0x43,0xb9,0xb3,0xe4,0x6e,0x2e,0xf7,0x79,0x72,0xb7,0x90,0xbb,0xa5,0xdc,0x17, +0xc8,0x7d,0xa1,0xe2,0x6d,0x2f,0xff,0xb6,0xf2,0x6f,0x27,0xff,0x0e,0xf2,0xef,0x24, +0xff,0x4b,0xe5,0xdf,0x59,0xfe,0xdd,0xe4,0x7f,0xb9,0xfc,0x7b,0xaa,0x1c,0x26,0x6b, +0x7f,0x77,0xed,0xef,0xa1,0xfd,0xbd,0xb4,0x7f,0x8a,0xf4,0x71,0xe9,0x13,0xd2,0x27, +0xa5,0x4f,0x49,0x9f,0x96,0x3e,0xa3,0xf8,0xae,0x54,0x7c,0x7d,0x15,0x5f,0x7f,0xed, +0x9f,0xaa,0xfd,0x7d,0xb4,0xbf,0x9f,0xf6,0x0f,0xd0,0xfe,0x69,0xd2,0x67,0xa5,0xd3, +0xa5,0xcf,0x49,0x9f,0x97,0xbe,0x20,0x9d,0x21,0x9d,0x2d,0x5d,0x26,0xfd,0x5a,0x3a, +0x4f,0xe7,0x5b,0xe3,0xdd,0xd7,0x75,0xbe,0x77,0xb4,0x7f,0x85,0xf4,0x7b,0x85,0xfb, +0x58,0xe1,0x3e,0x51,0xb8,0xcd,0x65,0xdd,0x71,0x9d,0x07,0xcb,0xbb,0xfa,0x90,0xf4, +0x05,0xe9,0x1a,0xe9,0x3b,0xd2,0xb7,0xa5,0x91,0x1a,0x0f,0x8a,0x91,0x16,0x94,0x9e, +0x2d,0xad,0x28,0x6d,0x20,0x6d,0x24,0x6d,0x22,0x6d,0x26,0xed,0x27,0xed,0x26,0xcd, +0x96,0x0e,0x94,0x0e,0x91,0x5e,0x25,0x1d,0x2e,0xbd,0x5a,0x3a,0x52,0x3a,0x4a,0xba, +0x45,0xfa,0xa9,0xf4,0x46,0xe9,0x58,0xe9,0x38,0xe9,0x2d,0xd2,0xad,0xd2,0x6d,0xd2, +0xe7,0xa4,0xcf,0x4b,0x5f,0x90,0xce,0x90,0xee,0x92,0xee,0x96,0x7e,0x29,0xdd,0x83, +0x4e,0x4a,0xa0,0xfd,0x27,0xb8,0x7a,0x9e,0xf4,0x7c,0x69,0x6b,0xe9,0x05,0xd2,0x0b, +0xa5,0xed,0xa5,0x17,0x49,0x2f,0x96,0x5e,0x22,0xbd,0x4c,0xda,0x45,0xda,0x4d,0xda, +0x43,0xda,0x4b,0xda,0x5b,0x9a,0x0d,0x0f,0xc2,0x40,0xb9,0x07,0xcb,0x3d,0x44,0xee, +0xa1,0x72,0x0f,0x93,0xfb,0x6a,0xb9,0xaf,0x91,0x7b,0x84,0xdc,0xd7,0xc9,0xfd,0xa8, +0xf4,0x1b,0xe9,0x73,0xd2,0x17,0xa4,0x33,0xa5,0xb3,0xa5,0x2f,0x4a,0x5f,0x92,0xce, +0x97,0xbe,0x2c,0x7d,0x55,0xba,0x48,0xba,0x44,0xba,0x4c,0xfa,0x86,0x74,0x85,0xf4, +0x4d,0xe9,0x5a,0xa5,0xeb,0x5d,0xb9,0xd7,0xcb,0xfd,0x9e,0xdc,0x1f,0xc8,0xbd,0x41, +0xee,0x0f,0xe5,0xfe,0x48,0xee,0x1c,0xb9,0x3f,0x96,0xfb,0x7b,0xe9,0x0f,0xd2,0x83, +0xd2,0x43,0xd2,0x9f,0x4d,0x9a,0x8b,0x06,0x9c,0x07,0xc1,0xe8,0xc3,0xd2,0xe9,0x50, +0xa9,0x58,0xc0,0x89,0x2f,0xe6,0x6a,0x75,0xa8,0x57,0x22,0xe0,0xb4,0x80,0x0e,0x70, +0x1e,0xcc,0x2c,0x19,0x70,0x5e,0x85,0x97,0xe1,0x15,0x58,0x08,0x8b,0x60,0x46,0x29, +0xfc,0x4a,0xb9,0xfa,0x0a,0x24,0x9c,0x1e,0x70,0x6a,0x02,0xa7,0x72,0xd2,0xa1,0x01, +0x5c,0x0c,0x9d,0x45,0x57,0xb8,0x06,0x9e,0x15,0x73,0xc5,0x3c,0xf1,0xb2,0x30,0x63, +0xb1,0x66,0xbc,0x68,0xa3,0xe3,0xbe,0x67,0xfc,0xc1,0xf8,0xf3,0xbb,0xf3,0x15,0xf1, +0x2a,0x2c,0x86,0x25,0xf0,0x1a,0xbc,0x0e,0xf7,0xf0,0xfb,0xf4,0x5e,0x98,0x08,0xf7, +0xc1,0x0c,0x98,0x09,0x4b,0x61,0x39,0xbc,0x0b,0x5b,0x60,0x3b,0x7c,0x29,0xbe,0x12, +0xa6,0x1f,0x19,0x60,0xda,0xaa,0x79,0x8f,0x66,0xda,0xa8,0x18,0x6a,0x9e,0x37,0xcd, +0x6f,0x14,0x71,0xad,0x79,0x9f,0x66,0xde,0xa5,0x89,0x9b,0xc4,0xcd,0x62,0x9c,0x7e, +0x8f,0xde,0x2e,0xcc,0x6f,0xc7,0x29,0xa6,0x0f,0x36,0xcf,0xb7,0xa6,0xcf,0x32,0xed, +0x9a,0xe7,0xd3,0x31,0x70,0x33,0xdc,0x0a,0xd5,0x43,0x3c,0x63,0x42,0x7b,0xe8,0x28, +0xba,0xc0,0x38,0xb8,0x0b,0x16,0xc2,0x62,0xb1,0x14,0x96,0xc1,0xeb,0xf0,0x06,0xac, +0x10,0x6b,0x61,0x17,0xec,0x85,0xaf,0xa1,0x28,0xcf,0xb0,0x67,0x40,0x39,0xa8,0x0f, +0x19,0xa2,0x01,0x34,0x87,0x16,0xd0,0x19,0xba,0x40,0x6f,0xe8,0x0f,0x03,0x20,0x5b, +0x0c,0xd4,0xf3,0xf0,0xfb,0xe2,0x03,0xc8,0x81,0xcd,0xb0,0x1d,0x3e,0x83,0x1d,0xf0, +0x39,0xec,0x84,0x5d,0xb0,0x07,0xbe,0x82,0xbd,0xb0,0x0f,0x0e,0xc2,0x21,0x38,0x0c, +0xbf,0x88,0xa2,0xd1,0x2e,0xc5,0x44,0x71,0xa8,0x0e,0x09,0xd0,0x1c,0x5a,0xc2,0x53, +0xf0,0x34,0xcc,0x84,0x59,0x62,0x09,0xbc,0x09,0xab,0x60,0x17,0xec,0x86,0x03,0xf0, +0x0d,0x7c,0x0b,0x87,0xc4,0x4f,0xc2,0xc9,0xc7,0xf3,0x12,0x9c,0x02,0xa7,0xc3,0x19, +0xa2,0x34,0xc4,0xc2,0xd9,0xe2,0x1c,0xa8,0x04,0x95,0xc5,0xb9,0x10,0x07,0x19,0x70, +0x11,0x74,0x84,0x4e,0xd0,0x05,0xae,0x84,0x6c,0xb8,0x19,0x6e,0x81,0xf1,0x70,0x3f, +0x3c,0x06,0x93,0x61,0x25,0xbc,0x29,0x56,0xc1,0xa7,0xb0,0x0d,0x82,0xfc,0x4e,0x88, +0x10,0x91,0x90,0x0e,0xb5,0x44,0x6d,0x51,0x47,0xd4,0x15,0xf5,0x20,0x03,0x1a,0x40, +0x53,0x68,0x06,0xe7,0x41,0x4b,0x71,0x3e,0xb4,0x82,0xd6,0xa2,0x0d,0x74,0x80,0x8b, +0xa0,0x2b,0x74,0x83,0xee,0xd0,0x13,0x06,0xc0,0x40,0x31,0x08,0x46,0xc2,0x28,0x31, +0x1a,0xc6,0xc0,0x58,0xb8,0x1d,0xc6,0xc3,0x04,0xb8,0x07,0xa6,0xc2,0xb3,0x30,0x13, +0x66,0x8b,0x97,0x60,0x01,0xbc,0x2a,0x16,0x0a,0xf3,0xbb,0x68,0x09,0x2c,0x85,0xd7, +0x61,0x05,0xac,0xd4,0x6f,0x25,0xf3,0x3b,0x69,0x8d,0x78,0x5b,0x6c,0x10,0x39,0xf0, +0x31,0x6c,0x86,0x4f,0x61,0x2b,0x6c,0x83,0x1d,0xb0,0x17,0xf6,0xc1,0x7e,0x38,0x2c, +0x7e,0x16,0x81,0xfc,0x94,0x2b,0x44,0x88,0x10,0xe4,0x87,0x22,0x50,0x14,0x4a,0x40, +0x65,0xa8,0x02,0x09,0x90,0x04,0xc9,0x90,0x0a,0x69,0x50,0x13,0xd2,0xa1,0x8e,0xa8, +0x07,0x19,0xd0,0x00,0x32,0xa1,0x09,0x34,0x85,0x16,0xd0,0x12,0xda,0x88,0x8e,0x70, +0x09,0x5c,0x26,0x7a,0xc2,0x00,0xc8,0x86,0x81,0x30,0x08,0x86,0xc0,0x55,0x62,0x14, +0x8c,0x86,0x31,0x62,0x2c,0xdc,0x01,0xe3,0xe1,0x2e,0xb8,0x07,0xa6,0xc2,0xb3,0x30, +0x13,0x66,0xc3,0x1c,0x98,0x0b,0x0b,0xe0,0x55,0xb1,0x50,0x2c,0x82,0x25,0xb0,0x14, +0xde,0x80,0x15,0xb0,0x12,0xde,0x14,0xab,0xe1,0x2d,0x58,0x23,0xd6,0x8a,0x2d,0xf0, +0x29,0x6c,0x85,0x6d,0xb0,0x03,0xf6,0xc2,0x41,0x71,0x08,0x7e,0x81,0x40,0x01,0x97, +0x20,0x44,0x40,0x08,0x0a,0x42,0x11,0x28,0x0a,0x25,0xa0,0x32,0x54,0x81,0x04,0x48, +0x82,0x64,0x48,0x85,0x74,0xa8,0x23,0xea,0x8a,0x7a,0xa2,0xbe,0xc8,0x10,0x0d,0xa0, +0x11,0x34,0xd1,0xef,0xe6,0x16,0xfa,0xdd,0xdc,0x52,0xb4,0xd3,0x6f,0xea,0x0e,0xe2, +0x12,0xb8,0x14,0x3a,0x43,0x57,0xe8,0x06,0xdd,0xa1,0x27,0x0c,0x80,0x81,0x62,0xb4, +0x18,0x23,0xc6,0xc2,0xad,0x70,0x27,0x4c,0x80,0xbb,0x61,0x22,0x4c,0x82,0x07,0xe1, +0x61,0xf1,0x28,0x3c,0x06,0x4f,0xc0,0x93,0x30,0x15,0x9e,0x85,0x17,0x60,0x81,0x7e, +0xb7,0x2f,0x86,0x25,0x62,0x29,0x2c,0x83,0xe5,0xb0,0x52,0xbf,0xf1,0xcd,0xef,0xfb, +0x35,0x62,0xad,0xd8,0x20,0x76,0xc0,0xde,0x02,0x66,0x40,0xd9,0x25,0x00,0x11,0x10, +0x29,0x42,0x50,0x10,0x0a,0x43,0x51,0x28,0x0e,0x95,0xa1,0x0a,0xa4,0x43,0x1d,0x51, +0x57,0xd4,0x83,0x0c,0x68,0x00,0x8d,0xa0,0xb1,0xde,0x27,0x34,0x87,0x96,0xd0,0xae, +0xa0,0xfb,0x8e,0xe1,0x22,0xb8,0x18,0x2e,0x81,0x4b,0xa1,0x0b,0x74,0x85,0x6e,0xd0, +0x1d,0x7a,0xc2,0x00,0x18,0x29,0x46,0x89,0xd1,0x30,0x06,0xc6,0xc2,0xed,0x70,0x27, +0x4c,0x80,0xbb,0x61,0x2a,0x3c,0x0b,0x73,0x60,0x2e,0x2c,0x80,0x57,0xc5,0x42,0xb1, +0x48,0x2c,0x16,0xe6,0x1d,0xc7,0xeb,0xb0,0x5c,0xac,0xd0,0xfb,0x8d,0x55,0x7a,0xbf, +0xf1,0x16,0xac,0xd1,0xfb,0x0e,0xf3,0xee,0x23,0x07,0x3e,0x81,0x2d,0xf0,0x29,0x6c, +0x85,0x6d,0xb0,0x03,0xf6,0xc2,0x7e,0xf8,0x1a,0x0e,0x08,0xa7,0x10,0x65,0x0a,0x41, +0x88,0x80,0x48,0x28,0x08,0x85,0xa1,0x28,0x14,0x87,0x5a,0x50,0x1b,0xea,0x40,0x5d, +0x61,0xde,0xa3,0x64,0x40,0x03,0x68,0x04,0x8d,0xa1,0xa9,0xde,0xb5,0x98,0xf7,0x2c, +0x2d,0xc5,0xf9,0xe2,0x42,0x68,0xaf,0xf7,0x30,0x86,0xce,0xd0,0x15,0xba,0x41,0x77, +0xe8,0x09,0x03,0xe0,0x1a,0xb8,0x01,0x46,0x89,0xd1,0x30,0x06,0xc6,0xc2,0x7d,0xf0, +0x20,0xcc,0x82,0x39,0xf0,0x0a,0x2c,0x14,0x4b,0x60,0xb9,0xde,0xdf,0xac,0xd2,0x7b, +0x9d,0x77,0x61,0x1d,0xbc,0x07,0x1f,0x88,0x8d,0x7a,0xd7,0xb3,0x03,0xf6,0xc2,0xd7, +0x70,0xc0,0x94,0x41,0x61,0xda,0x25,0x24,0x8a,0x24,0x48,0x86,0x14,0xa8,0x05,0x19, +0x90,0x05,0x8d,0x45,0x13,0x38,0x1f,0x5a,0x43,0x47,0x18,0x05,0xa3,0xe1,0x46,0x71, +0x13,0xdc,0x0a,0xb7,0xc3,0x13,0xf0,0x94,0x78,0x06,0x66,0xc2,0x2c,0x31,0x1b,0xe6, +0xc0,0x8b,0xf0,0x2a,0x2c,0x14,0x4b,0xe0,0x75,0x58,0x2e,0x56,0xc2,0xdb,0xb0,0x16, +0x3e,0x84,0x1c,0xd8,0x0c,0x4e,0x11,0x97,0xd3,0xe0,0x74,0x28,0x07,0xe7,0x42,0xaa, +0xa8,0x21,0xd2,0x45,0x3d,0xa8,0x0f,0x19,0xd0,0x04,0x9a,0x41,0x5f,0x18,0x08,0xd7, +0xc3,0x0d,0x62,0x24,0xdc,0x08,0x37,0xc1,0xcd,0x30,0x0e,0x6e,0x87,0x3b,0xe0,0x7e, +0x98,0x04,0xaf,0xc2,0x72,0xe1,0x14,0xa5,0xcd,0x41,0x55,0xa8,0x06,0x71,0x90,0x00, +0x89,0x22,0x09,0x6a,0x40,0x4d,0x91,0x0e,0xb5,0xa0,0x36,0xd4,0x81,0xba,0x50,0x0f, +0xea,0x8b,0x0c,0x68,0x06,0xad,0xa1,0x1d,0xb4,0x87,0x0e,0x70,0x11,0x74,0x84,0x8b, +0xe1,0x52,0xb8,0x0c,0xba,0x40,0x57,0xd1,0x0d,0x2e,0x87,0x1e,0xd0,0x13,0x7a,0x41, +0x3f,0xe8,0x0f,0xd9,0x30,0x10,0x86,0xc0,0x55,0x30,0x0a,0x46,0x8b,0x31,0x70,0x23, +0x8c,0x85,0x9b,0xe0,0x66,0xb8,0x1d,0xee,0x10,0x77,0x8a,0xf1,0x62,0x02,0x4c,0x82, +0x07,0xe1,0x61,0x78,0x44,0x4c,0x86,0x37,0x60,0x85,0x58,0x23,0xd6,0xc2,0x21,0x38, +0x2c,0x7e,0x82,0x5f,0xc0,0x29,0x46,0xbb,0x29,0x4e,0xbb,0x81,0x96,0xd0,0x1a,0xda, +0xc3,0x45,0xe2,0x62,0xb8,0x14,0xba,0xc0,0x38,0xb8,0x15,0xee,0x80,0x09,0x30,0x13, +0x66,0xc3,0x5c,0x98,0x0f,0x8b,0x60,0x89,0x58,0x06,0x6f,0xc0,0x4a,0xf8,0x00,0x36, +0x42,0xd1,0x12,0xb4,0x67,0x28,0x05,0xa7,0xc1,0xc5,0x70,0x29,0x74,0x86,0xde,0x30, +0x10,0x46,0xc2,0x78,0x98,0x0c,0xdf,0xc2,0x0f,0xf0,0x13,0x04,0x4a,0x52,0x4f,0x4e, +0xa1,0x8d,0xc2,0x0d,0x30,0x0a,0x1e,0x84,0xc9,0xb0,0x0b,0xbe,0x82,0x7d,0xb0,0x1f, +0x7e,0x00,0xe7,0x54,0xb2,0x06,0xc5,0xa1,0x24,0x94,0x12,0x65,0x21,0x11,0x92,0x20, +0x19,0x52,0x44,0x06,0xb4,0x81,0x0b,0xa0,0x2d,0x74,0x81,0xbe,0xd0,0x1f,0xb2,0x61, +0x10,0x0c,0x86,0x91,0x30,0x07,0x5e,0x84,0xb9,0xf0,0x92,0x98,0x07,0x0b,0x61,0x11, +0xbc,0x01,0xcb,0xc5,0x0a,0x58,0x09,0x6f,0xc2,0x7a,0xd8,0x20,0x72,0xc4,0xc7,0x62, +0x0b,0x7c,0x01,0x05,0x4e,0xa3,0x4b,0x84,0x22,0xa2,0x28,0x9c,0x0e,0xe5,0x20,0x13, +0x1a,0x8a,0x46,0x30,0x1c,0x46,0xc2,0x8d,0x30,0x16,0x6e,0x82,0x9b,0x61,0x2a,0x4c, +0x13,0xcf,0x8a,0x99,0xf0,0x2d,0x38,0xa7,0x3b,0x4e,0x19,0x28,0x07,0x15,0x20,0x16, +0x2a,0x42,0x25,0xa8,0x0c,0xe7,0x42,0x55,0x48,0x80,0x44,0x48,0x12,0xc9,0x50,0x13, +0xd2,0xa1,0x36,0x34,0x86,0x56,0xd0,0x1a,0xfa,0x41,0x36,0x0c,0x81,0x91,0x30,0x1d, +0x66,0xc2,0x9b,0xb0,0x16,0x3e,0x84,0x8f,0x84,0x73,0x06,0xcf,0xf6,0x70,0x2a,0x9c, +0x06,0xa7,0xc3,0x19,0x50,0x5a,0x94,0x83,0x0b,0xa1,0x9d,0x68,0x2f,0x3a,0x88,0x8b, +0xe0,0x32,0xe8,0x22,0xba,0x8a,0x6e,0xa2,0x3b,0x5c,0x0e,0x3d,0xa0,0x2f,0xf4,0x83, +0x41,0x30,0x18,0x46,0xc0,0x0d,0x62,0x24,0xdc,0x02,0x13,0x60,0x12,0x3c,0x23,0x66, +0xc2,0x42,0x58,0x0c,0x1f,0xc3,0x16,0xd8,0x0d,0x4e,0x69,0xee,0x4f,0xe6,0xbd,0xb9, +0x08,0x41,0x32,0xa4,0x88,0x54,0x91,0x06,0xb5,0xf4,0x0e,0xde,0x50,0x47,0xd4,0xd5, +0xfb,0xf7,0x4c,0x61,0xde,0xc1,0x37,0x82,0x2c,0x38,0x0f,0x5a,0x43,0x47,0xe8,0x03, +0x83,0x61,0x24,0x8c,0x82,0xd1,0x62,0x0c,0x4c,0x86,0x29,0xe2,0x71,0x78,0x0a,0x9e, +0x86,0x67,0x60,0x2a,0x4c,0x83,0x67,0xc5,0x74,0x78,0x1e,0x5e,0x80,0x19,0x30,0x13, +0x16,0xc0,0xcb,0xf0,0x19,0xec,0x10,0x9f,0x8b,0x9d,0xf0,0x05,0xec,0x82,0x2f,0x61, +0x8f,0xf8,0x4a,0xec,0x85,0xfd,0xf0,0x35,0x1c,0x00,0xe7,0x4c,0xea,0x0e,0x9c,0x0d, +0x55,0xa1,0x1a,0x24,0x43,0x0a,0xa4,0x42,0x1a,0xd4,0x80,0x0c,0x68,0x06,0x2d,0xa1, +0x15,0xb4,0x86,0x8e,0x70,0x31,0x0c,0x83,0xe1,0x70,0x1d,0x8c,0x84,0x5b,0x61,0x02, +0xbc,0x0c,0x0b,0x61,0x31,0xac,0x85,0x75,0xf0,0x1e,0x6c,0x81,0x4f,0xc5,0x56,0xd8, +0x09,0x5f,0xc0,0x97,0xb0,0x47,0x7c,0x05,0x07,0xe0,0x1b,0xf1,0x2d,0x7c,0x07,0xdf, +0x8b,0x1f,0xe0,0x20,0x1c,0x12,0xce,0x59,0xa4,0x1f,0xaa,0xc1,0x95,0xd0,0x07,0x86, +0xc1,0x70,0x71,0x35,0x3c,0x08,0x0f,0xc1,0x62,0x58,0x02,0xbf,0x9c,0xe5,0xce,0x01, +0x37,0xef,0xf5,0xcd,0x18,0xb8,0x79,0x7f,0x6f,0xc6,0x66,0xcd,0x7b,0x66,0x33,0x26, +0x6d,0xde,0x27,0x9b,0x31,0x4f,0xf3,0x9e,0xb8,0xa3,0xe8,0x24,0x2e,0x15,0xe6,0x5d, +0xf1,0x75,0x65,0xdd,0xb1,0x0f,0x33,0xae,0x6c,0xc6,0x86,0xcd,0x38,0xfb,0x22,0x61, +0xde,0xad,0x9a,0x71,0x66,0x33,0xc6,0x6b,0xc6,0xcd,0xcd,0x18,0xee,0xfa,0xb2,0xee, +0x58,0xed,0xa6,0xb2,0xee,0x18,0xab,0x19,0xef,0x36,0xef,0x5e,0xcd,0x38,0xa7,0x19, +0x2b,0x35,0xe3,0xd4,0x05,0xcb,0xd1,0x7f,0x40,0x7d,0xc8,0x80,0x0b,0xc5,0x40,0x71, +0x83,0x98,0x00,0x0f,0xc3,0x5a,0xc8,0x81,0x4f,0xc5,0x67,0xb0,0x0f,0x82,0xe5,0x5d, +0xa2,0x45,0x7e,0x28,0x01,0xa5,0xc4,0x69,0xe2,0x74,0x38,0x0b,0xce,0x16,0x15,0x45, +0x65,0x51,0x05,0xe2,0x20,0x5e,0x54,0x87,0x14,0x48,0x35,0xef,0x6e,0x21,0x5d,0xd4, +0x81,0xfa,0x90,0x05,0xcd,0xe0,0x7c,0xd1,0x05,0x46,0xc3,0x18,0xb8,0x11,0xc6,0xc2, +0x38,0x70,0xaa,0x39,0xce,0xb5,0x30,0x02,0xae,0x83,0xeb,0x61,0x3b,0xec,0x86,0xaf, +0x60,0x2f,0xec,0x87,0xaf,0xe1,0x00,0x38,0x71,0x8e,0x73,0x0e,0x54,0x12,0x71,0x22, +0x01,0x7a,0xc1,0x00,0x71,0x83,0x18,0x09,0xf7,0xc1,0x64,0x78,0x1a,0xa6,0xc2,0x0b, +0x30,0x13,0x5e,0x82,0xf9,0xb0,0x08,0x96,0xc0,0x72,0x58,0x09,0x6f,0xc3,0x5a,0xf8, +0x00,0x36,0xc2,0x27,0xb0,0x05,0x7e,0x81,0x50,0x82,0x4b,0x94,0x88,0x16,0xe5,0xe1, +0x5c,0xa8,0x02,0x71,0x10,0x0f,0xd5,0x21,0x11,0x52,0xa1,0x26,0xd4,0x82,0xda,0xa2, +0x8e,0x68,0x00,0xf7,0xe9,0xfd,0xa0,0x79,0x97,0xf8,0x10,0x3c,0x0c,0x8f,0xe8,0x3d, +0xe9,0x63,0x62,0x8a,0xde,0x23,0xfe,0x28,0x0e,0xeb,0x7d,0xe2,0x2f,0x22,0x94,0xc8, +0xf9,0x20,0x11,0xee,0x84,0xc9,0xb0,0x18,0xf6,0xc1,0x2f,0xe0,0xa4,0xe0,0x6e,0x89, +0x9e,0xcf,0x7d,0x74,0x32,0xd7,0x5e,0x9c,0x02,0xb7,0x3f,0x49,0x7e,0xe1,0x7b,0xf8, +0x01,0x7e,0x02,0xe7,0x29,0xee,0x61,0x4f,0x53,0x0f,0x45,0x51,0x28,0x0b,0xe5,0xe0, +0x5c,0xa8,0x02,0x55,0x21,0x03,0xfa,0x41,0x7f,0x31,0x40,0x0c,0x81,0xeb,0xe0,0x06, +0x31,0x12,0x1e,0x82,0x87,0xe1,0x11,0x78,0x14,0x1e,0x83,0xc9,0xf0,0x19,0xec,0x80, +0xbd,0xb0,0x0f,0xf6,0xc3,0xa9,0xcf,0x70,0x3e,0xa8,0x00,0x03,0x20,0x5b,0x0c,0x84, +0x9b,0x61,0x9c,0xb8,0x0d,0xee,0x84,0xf1,0x62,0x02,0xe4,0xc0,0x7e,0xf8,0x06,0xbe, +0x85,0xef,0xe0,0x7b,0xf1,0x03,0x1c,0x84,0x43,0xe2,0x47,0x08,0x4c,0xa5,0x8d,0x88, +0x08,0x08,0x41,0x94,0x88,0x86,0xfc,0x50,0x40,0x14,0x84,0x0a,0x10,0x0b,0x67,0xc3, +0x39,0x50,0x11,0x2a,0x89,0x6a,0x22,0x03,0x06,0xc3,0x48,0x18,0x05,0xa3,0x61,0x0e, +0xbc,0x08,0xaf,0xc1,0xeb,0xf0,0x06,0xac,0x85,0x0f,0x61,0x0b,0xec,0x87,0xaf,0xe1, +0x7b,0xf8,0x51,0xfc,0x04,0x3f,0xc3,0x2f,0xc2,0x99,0xe6,0x38,0x31,0x90,0x1f,0xce, +0x81,0x8a,0x10,0x07,0x09,0xd0,0x18,0x9a,0x40,0x1b,0xb8,0x00,0xda,0x42,0x17,0x18, +0x01,0x23,0x61,0x34,0x8c,0x11,0x37,0xc2,0x6c,0x98,0x23,0x5e,0x84,0xb9,0xf0,0x12, +0x2c,0x80,0x97,0xe1,0x15,0x78,0x15,0x16,0xc2,0x22,0x58,0x02,0xef,0x88,0xb5,0xf0, +0x21,0x6c,0x81,0xed,0xf0,0x99,0xd8,0x21,0x3e,0x87,0xbd,0xb0,0x0f,0x0e,0xc2,0x21, +0xf8,0x79,0x9a,0xfb,0xd2,0xb9,0x32,0x9c,0x0b,0xf1,0x50,0x1d,0x12,0x20,0x11,0x92, +0x20,0x19,0x52,0x20,0x15,0xd2,0x20,0x03,0x32,0xa1,0xa1,0x68,0x04,0x2d,0xe0,0x3c, +0xd1,0x52,0xb4,0x86,0x8e,0xd0,0x05,0x06,0x40,0xb6,0x18,0x08,0x43,0xe1,0x1a,0x71, +0xad,0x18,0x21,0xae,0x13,0xd7,0xc3,0x0c,0x98,0x29,0x66,0x89,0xd9,0xf0,0x22,0xcc, +0x85,0x97,0x60,0x1e,0xcc,0x87,0x05,0xb0,0x10,0x16,0xc1,0x62,0x58,0x22,0x96,0x8a, +0x65,0x62,0x13,0xe4,0xc0,0xc7,0x62,0x0b,0xec,0x82,0xdd,0xe2,0x4b,0xd8,0x03,0x5f, +0xc1,0x5e,0xf8,0x5a,0x1c,0x80,0x6f,0xe0,0x5b,0xf1,0x9d,0x08,0x4c,0xa7,0x5e,0x42, +0x0c,0x14,0x86,0x62,0x70,0x0a,0x94,0x83,0x8a,0x50,0x19,0xe2,0x21,0x01,0x2e,0x86, +0x4b,0xa0,0x33,0x74,0x81,0x2b,0xa0,0xb7,0xc8,0x86,0xc5,0xb0,0x04,0xb6,0xc2,0x36, +0xd8,0x0e,0x9f,0x89,0x1d,0xf0,0x39,0xec,0x14,0x5f,0xc0,0x2e,0xf8,0x52,0xec,0x11, +0xfb,0xe0,0x20,0x38,0xcf,0xf1,0xfb,0x74,0x03,0x65,0x07,0xcb,0x61,0x35,0xfc,0x08, +0x66,0x52,0x6e,0xbf,0x43,0x9c,0x0f,0x3e,0x34,0x13,0x73,0x7f,0x24,0xfd,0x50,0x02, +0x4e,0x85,0xb3,0x44,0x19,0x51,0x16,0x2a,0x43,0x15,0x48,0x83,0x9a,0x50,0x07,0xea, +0x89,0x0c,0x68,0x00,0x0d,0xa1,0x11,0x34,0x86,0x59,0xb0,0x1e,0xea,0xfe,0x44,0x3d, +0x80,0xf1,0x70,0x37,0xac,0x80,0x7d,0xf0,0xa3,0x99,0x20,0xfb,0x33,0xcf,0xe1,0x50, +0x0e,0xaa,0x43,0x32,0xa4,0x40,0x4b,0x68,0x05,0xd9,0x30,0x04,0x86,0xc2,0x61,0x28, +0xfa,0x0b,0xf7,0x44,0x28,0x0f,0xb5,0xa0,0xbe,0x68,0x00,0x17,0x43,0x0f,0xd1,0x13, +0x06,0x40,0xb6,0x18,0x08,0x8f,0xc0,0xa3,0xf0,0x18,0x4c,0x86,0x45,0xb0,0x0c,0x56, +0xc0,0x2a,0x78,0x07,0xd6,0xc1,0x06,0xf8,0x08,0x72,0xcc,0xc4,0x5c,0x27,0xe0,0x14, +0x80,0x42,0x50,0x11,0x2a,0x43,0x2d,0xa8,0x03,0x75,0xa1,0x3e,0xb4,0x84,0xd6,0x70, +0x29,0x8c,0x84,0x43,0x90,0x11,0x08,0x38,0x43,0xe0,0x27,0x31,0x32,0x18,0x70,0x1e, +0x86,0xc9,0xb0,0x16,0xb6,0x08,0xf3,0xb1,0x45,0x59,0x88,0x83,0x0c,0x68,0x20,0x32, +0xa1,0x19,0x34,0x17,0xad,0xe1,0x2a,0x18,0x0a,0xd7,0xc0,0x48,0x78,0x04,0x26,0xc3, +0x6b,0xb0,0x12,0xde,0x81,0x77,0xe1,0x7d,0xf3,0x01,0x47,0x64,0xc0,0x69,0x05,0xad, +0xe1,0x11,0x98,0x0c,0xd3,0x60,0x26,0xac,0x87,0x8d,0xf0,0xa3,0xf9,0xc0,0x2e,0x14, +0x70,0x2a,0x41,0x02,0x74,0x87,0x6c,0xb8,0x06,0x46,0xc0,0xad,0x70,0x3b,0xdc,0x0d, +0xf7,0xc2,0x44,0xb8,0x1f,0xa6,0xc0,0x13,0x30,0x0b,0xe6,0xc0,0x02,0x78,0x05,0x5e, +0x85,0x25,0x70,0xc0,0x7c,0xf0,0x11,0x15,0x70,0xd2,0xa2,0xc9,0x13,0xb4,0x83,0x2e, +0xd0,0x0b,0x46,0xc2,0x58,0xb8,0x19,0x66,0xc2,0x6c,0x78,0xd9,0x7c,0x00,0x92,0x2f, +0xe0,0x84,0x20,0x9f,0xc8,0x0f,0xa9,0x50,0x03,0x6a,0x42,0x1d,0x51,0x1f,0xda,0x41, +0x17,0x18,0x0a,0x23,0xe1,0x51,0xd8,0x02,0x5f,0xc3,0x37,0xf0,0xad,0xf9,0x20,0x30, +0x26,0xe0,0x94,0x82,0x72,0x90,0x0e,0x19,0xd0,0x11,0x46,0xc2,0x3c,0x58,0x04,0x8b, +0xcd,0x07,0x27,0xf9,0x5d,0x02,0x10,0x01,0x21,0x88,0x82,0x82,0x50,0x04,0x8a,0x42, +0x09,0x28,0x05,0xa7,0xc2,0xe9,0x90,0x0a,0x35,0xa1,0x16,0xd4,0x17,0x5d,0x60,0x04, +0x8c,0x84,0x87,0x61,0x09,0xac,0x80,0x37,0x61,0x3b,0x7c,0x06,0x3b,0xcc,0xb9,0x0a, +0x70,0x3c,0x64,0x40,0x3b,0xe8,0x02,0x83,0x60,0x24,0xdc,0x95,0xfb,0xe1,0x4b,0xc0, +0x69,0x0a,0x23,0x61,0x36,0x2c,0x81,0xaf,0xcd,0x07,0x8d,0x85,0x02,0x4e,0x2c,0x9c, +0x0d,0x95,0x20,0x01,0xd2,0x21,0x03,0x9a,0x41,0x73,0x68,0x09,0xe7,0x8b,0x56,0xa2, +0x35,0xf4,0x80,0xde,0xd0,0x0f,0x06,0x88,0x6c,0x18,0x0b,0x23,0x0b,0x53,0x2f,0x60, +0x3a,0x3c,0x07,0x33,0x61,0x16,0x2c,0x83,0xd7,0xe1,0x0d,0xb1,0x1c,0x56,0xc0,0x21, +0xf8,0xc5,0x7c,0x48,0x59,0x24,0xe0,0x9c,0x09,0x95,0x44,0x02,0x64,0x41,0x63,0x68, +0x0d,0xd9,0x30,0x0a,0x46,0xc3,0x58,0x98,0x09,0xaf,0xc3,0x16,0xf8,0xce,0x7c,0xc0, +0x53,0xd4,0x25,0x20,0x82,0x22,0x02,0x6a,0x40,0x4d,0x68,0x0c,0x3d,0x61,0x00,0x64, +0x8b,0x81,0x30,0x08,0x06,0xc3,0x10,0xb8,0x4a,0xdc,0x00,0xa3,0x60,0xb4,0x18,0x03, +0x33,0x60,0x26,0xcc,0x86,0x39,0xf0,0x12,0xcc,0x83,0xf9,0xb0,0x40,0x63,0xbc,0xcb, +0xc4,0x5a,0xd8,0x09,0xfb,0xe0,0xa0,0x49,0x5b,0x31,0xd2,0x03,0x11,0x50,0x51,0xe3, +0xbf,0x55,0xa1,0x9a,0x88,0x83,0x14,0x48,0x83,0xfa,0xd0,0x48,0x64,0x41,0x63,0x68, +0x22,0x5a,0xc3,0x20,0x18,0x2c,0x86,0x8a,0x91,0x30,0x0a,0x46,0x8b,0x31,0x30,0x1b, +0xe6,0xc0,0x5c,0x78,0x09,0x16,0xc1,0x62,0x58,0x02,0x4b,0xe1,0x75,0x78,0x13,0xde, +0x82,0xb7,0xc5,0x3b,0x62,0x2d,0x7c,0x08,0x1f,0x89,0x1c,0x61,0x3e,0x56,0x2d,0x06, +0x25,0xa0,0x2a,0x54,0x83,0x78,0xa8,0x0e,0x89,0x90,0x04,0xc9,0x90,0x22,0x52,0x45, +0x1a,0xd4,0x80,0x7a,0xa2,0x3e,0x64,0x40,0x03,0x31,0x12,0x6e,0x82,0x71,0xe2,0x56, +0xb8,0x03,0xc6,0xc3,0x23,0xf0,0x18,0x4c,0x85,0x99,0xf0,0x09,0x6c,0x16,0x5b,0x60, +0x2b,0x6c,0x83,0x5d,0xb0,0x0f,0x0e,0x9a,0x0f,0x6a,0x4b,0x50,0x0f,0x20,0x08,0x11, +0x10,0x82,0x82,0x50,0x04,0x8a,0x42,0x09,0xa8,0x0c,0x55,0x20,0x01,0x92,0x20,0x19, +0x52,0x21,0x1d,0x6a,0x43,0x1d,0xa8,0x2b,0xcc,0x38,0x7d,0x7d,0xc8,0x10,0x0d,0xa0, +0x11,0x34,0x81,0xa6,0x1a,0xc3,0x6f,0x09,0xad,0x45,0x07,0x71,0x29,0x74,0x85,0x6e, +0xd0,0x1d,0x7a,0x42,0x5f,0xc8,0x86,0x21,0x30,0x12,0x6e,0x81,0xdb,0xc4,0x9d,0x62, +0x02,0xcc,0x85,0x79,0x62,0x3e,0xbc,0x0c,0xaf,0xc0,0x12,0x58,0x26,0xde,0x10,0x2b, +0x60,0x15,0xbc,0x05,0x6b,0xe0,0x6d,0xf1,0x8e,0x58,0x2b,0xde,0x15,0xeb,0xc4,0x7a, +0xf1,0x29,0x6c,0x35,0x1f,0xb0,0x95,0xe4,0xba,0x41,0x2a,0xd4,0x80,0x9a,0x50,0x1f, +0x32,0xa0,0x01,0x64,0x42,0x23,0xc8,0x12,0x8d,0x45,0x13,0x68,0x0e,0xad,0xa1,0x23, +0x5c,0x26,0x3a,0x43,0x57,0x18,0x69,0xe6,0x30,0x94,0x74,0xe7,0x37,0xcc,0x86,0x39, +0x30,0x1f,0x16,0x88,0x97,0xad,0x39,0x0f,0x66,0xbe,0xc3,0x62,0x58,0x02,0x4b,0xc5, +0x32,0x78,0x0d,0x5e,0x87,0x37,0x60,0x85,0x58,0x0b,0x1f,0x9a,0xf8,0x4b,0x05,0x9c, +0x17,0x34,0x3f,0x62,0x16,0xcc,0x86,0xb9,0x30,0x5f,0xf3,0x25,0x5e,0x85,0x85,0xb0, +0x48,0x2c,0x86,0x25,0xb0,0x11,0x36,0x41,0x0e,0x7c,0x6c,0x3e,0xdc,0x3b,0x85,0xba, +0x0c,0x09,0x90,0x04,0xc9,0x50,0x0b,0x6a,0x43,0x1d,0xa8,0x2b,0xea,0x89,0xfa,0x90, +0x01,0x8d,0x44,0x6b,0xe8,0x08,0x23,0xe1,0x59,0x98,0x2e,0x9e,0x13,0xcf,0x8b,0x17, +0x60,0x06,0xcc,0x84,0xb9,0xf0,0x92,0x98,0x27,0xe6,0x8b,0x25,0xf0,0x26,0xac,0x85, +0x6d,0xe6,0xc3,0xf0,0x53,0x03,0xce,0x19,0x70,0x96,0x28,0x23,0xca,0x8a,0x72,0x50, +0x1e,0x2a,0xc0,0x39,0x50,0x51,0x54,0x82,0xaa,0x90,0x00,0xe9,0x90,0x01,0x8d,0xcd, +0x07,0x8a,0xa7,0xe1,0x0f,0xd5,0x20,0x1e,0xaa,0x43,0x0d,0xa8,0x29,0xd2,0xa1,0x16, +0x4c,0x86,0xcd,0xb0,0x05,0xbe,0x80,0x5f,0x20,0xea,0xf4,0x80,0x13,0x23,0x0a,0x42, +0x09,0x28,0x05,0xa7,0xc0,0x69,0x50,0xfd,0x74,0x77,0x9e,0x4a,0x2a,0xd4,0xd0,0x7c, +0x95,0xda,0x50,0x07,0xea,0x8a,0x7a,0xa2,0xbe,0xc8,0x10,0x0d,0x44,0xa6,0x68,0x28, +0x5a,0x43,0x47,0x98,0x0c,0xcf,0xc0,0xb3,0xb0,0x16,0xde,0x85,0xf5,0xf0,0x1e,0x6c, +0x80,0x8f,0x60,0x13,0xe4,0xc0,0x66,0xd8,0x22,0x3e,0x15,0xdb,0xc4,0x76,0x91,0xfb, +0x71,0x3d,0x04,0x20,0x3f,0x14,0x80,0x24,0x48,0x86,0x9a,0x90,0x2e,0x6a,0x89,0xda, +0x50,0x0f,0x9a,0x88,0xd6,0xa2,0x0d,0xb4,0x87,0x0e,0x70,0x11,0x74,0x84,0x4e,0x70, +0x09,0xdc,0x02,0xb7,0xc2,0x7d,0x70,0xbf,0x78,0x00,0x26,0xc1,0x23,0x62,0x26,0xfc, +0x00,0x5d,0x4a,0xbb,0x74,0x15,0xdd,0xe0,0x72,0xe8,0x21,0x7a,0x8a,0x5e,0x62,0x09, +0x6c,0x81,0x7d,0x70,0xd0,0x7c,0x60,0x7a,0x26,0xcf,0x3d,0x90,0x1f,0xe2,0xa1,0xba, +0x48,0x80,0x34,0xa8,0x09,0x75,0xa1,0x9e,0xa8,0x2f,0x32,0x44,0x6b,0xe8,0x08,0x83, +0x60,0x3c,0xdc,0x0d,0xcf,0xc0,0x34,0xf1,0x2c,0xcc,0x84,0x59,0x62,0x36,0xcc,0x81, +0x17,0xc5,0x5c,0x78,0xc9,0x2c,0x30,0x70,0x16,0xf5,0x04,0xf2,0x41,0x0c,0x14,0x80, +0x04,0x48,0x84,0x34,0xa8,0x25,0xea,0x40,0x5d,0xa8,0x0f,0x59,0xd0,0x58,0x34,0x11, +0xad,0xa1,0x23,0x74,0x81,0x1e,0xd0,0x0b,0xae,0x80,0x2b,0xe1,0x16,0xb8,0x15,0xee, +0x84,0x09,0x70,0x17,0xdc,0x03,0xf7,0xc2,0x44,0x71,0x9f,0xb8,0x5f,0x3c,0x20,0x26, +0xc3,0x34,0x98,0x09,0x1b,0xe1,0x43,0xf1,0x11,0x6c,0x82,0x2d,0xf0,0x85,0xd1,0x32, +0x3c,0x37,0xc1,0x01,0xf8,0x06,0xbe,0x85,0xef,0xcc,0x82,0x09,0x65,0xa9,0x33,0x10, +0x14,0x11,0x22,0x12,0x8a,0x42,0x71,0x48,0x86,0x14,0x48,0x85,0x34,0xa8,0x05,0xf5, +0xa0,0x3e,0x64,0x88,0x06,0x22,0x53,0xb4,0x86,0x8e,0x70,0xb1,0x98,0x29,0xcc,0xe2, +0x0c,0x93,0xcc,0x87,0xbc,0x67,0x07,0x9c,0xfe,0x30,0x12,0x1a,0x9e,0x43,0xbe,0xab, +0x73,0xed,0x73,0x3f,0x9c,0xe5,0x3a,0xa7,0x10,0xa7,0x68,0x00,0x8d,0xa1,0x09,0xb4, +0x83,0x2e,0x70,0xc8,0x2c,0x4c,0xd0,0x08,0x7f,0xf3,0xa1,0x6a,0x57,0xfa,0x11,0x28, +0x03,0xe7,0x42,0x15,0xa8,0x06,0x71,0x50,0x1d,0x12,0x20,0xdd,0x7c,0xd0,0x79,0x05, +0x75,0xe6,0x4a,0xe2,0x84,0xcb,0xa0,0x0b,0xf4,0x86,0x6c,0x58,0x04,0x4b,0xe0,0x4d, +0x58,0x0b,0x7b,0x60,0x1f,0x7c,0x63,0x3e,0xb0,0xef,0x43,0x3c,0x90,0x00,0x69,0x90, +0x01,0x0d,0xa1,0x35,0x74,0x84,0xee,0x30,0x0c,0xae,0x83,0xf1,0x66,0x7f,0x3f,0xf2, +0x0f,0x0d,0xe1,0x4a,0xe8,0x03,0x7d,0x21,0x1b,0xae,0x86,0x8c,0xfe,0x3c,0x9b,0xc1, +0x64,0x98,0x0f,0xaf,0xc0,0x7a,0xf3,0xa1,0xfe,0x00,0xee,0x3f,0xd0,0x4a,0xb4,0x16, +0x6d,0xe0,0x66,0x18,0x0f,0x77,0xc3,0x3d,0xf0,0x18,0x6c,0x81,0x4f,0x61,0x9b,0xd8, +0x2e,0xf6,0xc1,0x7e,0xf8,0x1a,0x0e,0xc0,0x37,0xf0,0x9d,0xf9,0x60,0x34,0x9b,0xdf, +0x41,0xb7,0xd3,0xef,0x41,0x99,0x3b,0x28,0x77,0xf8,0x1a,0xf6,0xcd,0x20,0x1c,0x7c, +0x0b,0x3f,0xc2,0x4f,0xf0,0xb3,0x59,0x10,0x60,0x26,0x7d,0xf0,0x2c,0xfa,0x10,0xd1, +0x1a,0x2e,0x80,0x76,0xe2,0x72,0xe8,0x05,0xd9,0xf0,0xe3,0x6c,0x77,0xa2,0xdd,0x95, +0x90,0x0d,0x23,0x60,0x24,0x8c,0x83,0x09,0x30,0x09,0x1e,0x81,0x47,0x61,0xdf,0x5b, +0xb4,0x6f,0x30,0x8b,0x61,0xc4,0x41,0x02,0x34,0x86,0x1e,0xef,0xd2,0x1f,0x40,0x2f, +0xe8,0x0d,0xfd,0x60,0x10,0x5c,0x0b,0xa3,0x61,0x2c,0xdc,0x06,0xcf,0xc2,0xf3,0x90, +0xb9,0x8e,0xfb,0x95,0xf9,0x80,0xf8,0xbd,0x80,0x73,0x21,0xb4,0x87,0x87,0xe1,0x51, +0x78,0x0c,0x1e,0x17,0x4f,0xc1,0xd3,0x30,0x0d,0x9e,0x83,0x17,0x60,0x01,0xbc,0x22, +0x16,0xc2,0x6b,0xf0,0x06,0x84,0xde,0x0f,0x38,0xd1,0x90,0x1f,0x0a,0x41,0x49,0x38, +0x05,0xce,0x84,0x32,0x90,0x0e,0xb5,0xa1,0x1e,0x64,0x40,0x23,0x68,0x2c,0x9a,0x43, +0x6b,0xb8,0x00,0x9e,0xfa,0x80,0x67,0x3d,0x58,0x02,0xcb,0xe0,0x23,0xc8,0x81,0x43, +0x70,0x18,0x4a,0x6e,0x20,0x5e,0x48,0x81,0x34,0x38,0x1f,0x5a,0x43,0x7f,0xc8,0x86, +0x71,0x70,0x2b,0x4c,0x85,0x67,0x61,0x19,0xbc,0x0e,0xab,0xe1,0x6d,0xf8,0xc5,0x7c, +0xf8,0xf9,0x11,0xc7,0x42,0x6d,0xe8,0x0b,0x57,0x89,0x1b,0xc5,0x43,0xf0,0x18,0x4c, +0x81,0x19,0xe6,0x03,0xca,0xcd,0xf4,0x5f,0x90,0x5f,0x14,0x80,0x32,0x70,0x0e,0x54, +0x31,0x1f,0x84,0x6e,0xa1,0x9f,0x83,0x7c,0x70,0x1a,0x94,0x86,0xf2,0x10,0x0b,0x67, +0x43,0x45,0xa8,0x02,0x09,0xd0,0x0f,0xc6,0x0b,0xf3,0x31,0x60,0x35,0x48,0x80,0x34, +0xa8,0x01,0x75,0x21,0x03,0x9a,0xc1,0xf9,0x62,0xc2,0x56,0xae,0x1b,0xbc,0x20,0x96, +0xc0,0x6e,0xf8,0x12,0xf6,0xc2,0x3e,0x38,0x08,0x6b,0xb7,0xf3,0x1c,0x0c,0xbb,0xc5, +0x97,0xb0,0x17,0xf6,0xc1,0x41,0x58,0xfb,0x19,0xed,0x13,0xbe,0x82,0xbd,0xb0,0x4f, +0xec,0x87,0x43,0xb0,0x64,0x07,0xcf,0xd7,0xb0,0x05,0xb6,0xc2,0x36,0xb1,0x1d,0x3e, +0x83,0x1d,0xe2,0x73,0xd8,0x03,0x5f,0xc1,0x5e,0xd8,0x07,0xdf,0xc0,0xb7,0xe2,0x67, +0xf1,0x8b,0xd8,0xf2,0x39,0xc7,0xc1,0x4e,0xd8,0x0d,0x7b,0xe0,0x2b,0xd8,0x07,0x3f, +0x9b,0x05,0x0a,0x76,0x72,0x8d,0x60,0x2d,0x7c,0x60,0x16,0x6a,0xf9,0x82,0x3e,0x00, +0x1a,0x41,0x73,0x68,0x21,0x5a,0x43,0x47,0xf3,0xe1,0xff,0x57,0xf4,0xb3,0x10,0x82, +0xb2,0x50,0x1e,0x2a,0xc0,0xd9,0xa2,0x92,0x38,0x17,0x92,0x20,0x05,0x6a,0x40,0xba, +0xa8,0x2d,0x32,0x45,0x13,0xd1,0x4c,0xb4,0x10,0x2d,0xa1,0x15,0xb4,0x81,0x0b,0xe0, +0x42,0xd1,0x41,0x74,0x14,0x9d,0xc4,0xa5,0xa2,0xb3,0xe8,0x0a,0xdd,0xe0,0x72,0xd1, +0x0b,0xae,0x84,0xbe,0x30,0x08,0x86,0xc0,0x30,0xb8,0x1a,0x46,0xc0,0xf5,0x62,0x24, +0xdc,0x02,0xb7,0xc1,0x43,0x30,0x05,0x9e,0x80,0xa7,0x60,0x1a,0x4c,0x87,0x57,0x60, +0xdf,0x8f,0x5c,0x57,0xf3,0x21,0xb2,0x13,0x74,0x36,0x3f,0x1d,0x74,0x9c,0x67,0x82, +0xce,0x59,0xf3,0x83,0x4e,0x39,0x78,0xfe,0xed,0xa0,0x33,0x13,0xb6,0xec,0x0e,0x3a, +0xfb,0xe0,0x52,0x33,0x01,0xf7,0x07,0xf6,0x1f,0x72,0x27,0xe2,0x36,0x2f,0x11,0xc1, +0x6f,0x95,0x08,0xe7,0xea,0x94,0x88,0xdc,0x09,0x2d,0x7b,0xc1,0x9b,0x47,0x9c,0xd7, +0xfc,0xe1,0xff,0xd5,0xbc,0xe1,0xdf,0x3a,0x5f,0xf8,0x44,0xe7,0x09,0x1f,0x6f,0x7e, +0xb0,0x7f,0xde,0x6f,0x5e,0xf3,0x7d,0xbd,0xf9,0xbd,0xfe,0x79,0xbd,0xde,0x3c,0x5e, +0x6f,0xde,0x6e,0x5e,0xf3,0x75,0xbd,0x79,0xba,0xde,0xfc,0x5c,0x6f,0x5e,0xae,0x37, +0x1f,0xd7,0x3f,0x0f,0xd7,0x9b,0x7f,0xeb,0xcd,0xbb,0xf5,0xe6,0xdb,0x7a,0xf3,0x6c, +0xbd,0xf9,0xb5,0x79,0xcd,0xab,0xf5,0xcf,0xa7,0xf5,0xe6,0xcd,0x7a,0xf3,0x63,0xbd, +0x79,0xaf,0xde,0x7c,0x57,0xff,0xfc,0xd6,0x93,0x9d,0xcf,0xea,0xcd,0x63,0xf5,0xe6, +0xa7,0xfa,0xe7,0xa5,0xfa,0xe7,0xa1,0xfe,0xd6,0xf9,0xa6,0xfe,0xf9,0xa3,0xde,0x7c, +0xd1,0x93,0x9d,0x17,0xea,0xcd,0x07,0xf5,0xcf,0xef,0xf4,0xe6,0x73,0x9e,0xec,0xbc, +0x4d,0x6f,0xbe,0xa6,0x7f,0x9e,0xa5,0x37,0xaf,0xf2,0x8f,0x9e,0x4f,0xe9,0xcd,0x8f, +0x3c,0xde,0xbc,0x47,0x6f,0xbe,0x63,0x5e,0xf3,0x18,0xbd,0x79,0x8b,0x27,0x3a,0x4f, +0xd1,0x9b,0x9f,0xe8,0x9f,0x5f,0xe8,0xcd,0x27,0xcc,0x6b,0xde,0xa0,0x37,0x5f,0xd0, +0x3f,0x0f,0xd0,0x9b,0xff,0xe7,0xcd,0xf7,0x3b,0xd1,0xf9,0x7d,0xde,0x3c,0x3d,0x6f, +0x7e,0x9e,0x7f,0x5e,0xde,0xc9,0xce,0xc3,0xf3,0xe6,0xdf,0xe5,0x35,0xef,0xce,0x3f, +0xcf,0xce,0x3f,0x6f,0xce,0x9b,0x17,0xe7,0xcd,0x7f,0xf3,0xe6,0xaf,0x79,0xf3,0xd6, +0xbc,0x79,0x6a,0xde,0xfc,0x34,0x6f,0x5e,0x9a,0x37,0x1f,0xcd,0x9b,0x87,0xe6,0xcd, +0x2f,0xfb,0xbb,0xcd,0x1f,0xfb,0xa3,0xe7,0x8b,0x79,0xf3,0xc3,0xbc,0xf9,0x60,0xfe, +0x79,0x60,0xde,0xfc,0x2f,0xff,0x3c,0xae,0x93,0x9d,0x9f,0x95,0xd7,0xbc,0xac,0xe3, +0xcd,0xa7,0xf2,0xe6,0x4f,0x79,0xf3,0xa4,0xbc,0x79,0x4b,0xde,0x7c,0x24,0x6f,0x3e, +0x91,0x37,0x5f,0xc8,0x9b,0xff,0xe3,0xcd,0xfb,0xf1,0xe6,0xed,0x78,0xf3,0x71,0x4e, +0x74,0x1e,0x8e,0x37,0xcf,0xc6,0x9b,0x5f,0xe3,0xcd,0xab,0xf9,0xad,0xf3,0x68,0xfe, +0xaa,0xf3,0x67,0xf2,0x9a,0x27,0xf3,0x77,0x9f,0x0f,0x73,0xb2,0xf3,0x60,0xfe,0xa8, +0xf9,0x2f,0xc7,0x9b,0xf7,0x72,0xa2,0xf3,0x5c,0x8e,0x37,0xbf,0xe5,0x7f,0x35,0xaf, +0x25,0xaf,0xf9,0x2c,0x79,0xcd,0x5f,0xf1,0xcf,0x5b,0xf9,0xb3,0xe7,0xab,0x78,0xf3, +0x54,0xbc,0xf9,0x29,0xde,0xbc,0x14,0x6f,0xde,0x89,0x37,0xdf,0x24,0xaf,0xf9,0x24, +0xde,0xfc,0x11,0x6f,0xde,0x88,0x37,0x4f,0xc4,0x9b,0x17,0xe2,0xcd,0xf3,0xf0,0xe6, +0x77,0xf8,0xe7,0x75,0xf8,0xe7,0x73,0x78,0xf3,0x34,0xbc,0xf9,0x19,0xc7,0x9b,0x87, +0xe1,0xcd,0xb7,0xf0,0xe6,0x59,0x78,0xf3,0x2b,0xbc,0x79,0x15,0xde,0x7c,0x8a,0xe3, +0xcd,0xa3,0xf0,0xcf,0x97,0xf8,0x6f,0xcd,0x8f,0xf8,0xbd,0xf3,0x1b,0xfe,0x5b,0xf3, +0x1a,0xfc,0xf3,0x16,0xbc,0xf9,0x0a,0xde,0x3c,0x85,0xbf,0xca,0xfc,0x04,0xff,0xbc, +0x84,0x93,0x9d,0x8f,0x70,0xb2,0xf3,0x10,0xc2,0xf3,0x0f,0x8e,0x3d,0xff,0x20,0xaf, +0x79,0x06,0xc7,0x9b,0x57,0xf0,0x7b,0xe7,0x13,0x1c,0x6f,0xde,0x40,0x5e,0xf3,0x05, +0x8e,0x37,0x4f,0x20,0xaf,0xf9,0x01,0xde,0xbc,0x00,0xff,0x7c,0x00,0x6f,0xdc,0xdf, +0x1b,0xdf,0xf7,0xc6,0xf5,0xbd,0x71,0x7c,0x6f,0x7c,0xde,0x1b,0x8f,0xf7,0xc6,0xdb, +0xfd,0xe3,0xec,0xde,0xf8,0xba,0x37,0x9e,0xee,0x8d,0x9b,0x1f,0x6f,0x5c,0xdc,0x1b, +0xdf,0x3e,0xd9,0x71,0xed,0x93,0x1d,0xa7,0xf6,0xc6,0xa7,0xbd,0x71,0x67,0x6f,0xbc, +0xf9,0x44,0xc7,0x95,0xbd,0xf1,0x60,0x6f,0x1c,0xd8,0x1b,0xff,0xf5,0xc6,0x73,0xfd, +0xe3,0xb7,0xfe,0xf1,0x57,0x6f,0xdc,0xd5,0x1b,0x47,0xf5,0xc6,0x4f,0xbd,0xf1,0x50, +0x6f,0x1c,0xd4,0x1b,0xcf,0xf4,0xc6,0x2f,0xfd,0xe3,0x8f,0xde,0xf8,0xe2,0x89,0x8e, +0x2b,0x7a,0xe3,0x85,0xde,0x38,0xa1,0x7f,0x3c,0xd0,0x3f,0xce,0xe7,0x8d,0xef,0x79, +0xe3,0x7a,0xde,0x38,0x9e,0x37,0x6e,0xe7,0x8d,0xcf,0xf9,0xc7,0xe1,0xbc,0x71,0x35, +0xff,0x78,0x9a,0x37,0x4e,0xe6,0x8d,0x8f,0xe5,0x35,0xce,0xe5,0x8d,0x63,0xe5,0x35, +0x6e,0xe5,0x8d,0x43,0xe5,0x39,0xfe,0xa4,0x71,0x27,0x6f,0x7c,0xc9,0x3f,0xae,0x74, +0xb2,0xe3,0x42,0xde,0x78,0x50,0x5e,0xe3,0x40,0xfe,0x71,0x1e,0x6f,0x7c,0xc7,0x1b, +0xd7,0xf1,0xc6,0x73,0xbc,0x71,0x9c,0x13,0x1d,0xbf,0x39,0xde,0xb8,0x8d,0x37,0x5e, +0x93,0xd7,0xf8,0xcc,0x5f,0x6d,0x3c,0xe6,0xdf,0x36,0x6e,0x72,0xbc,0xf1,0x0f,0x6f, +0x5c,0xc3,0x1b,0xcf,0xf0,0xc6,0x31,0xfc,0xe3,0x17,0xde,0xb8,0x85,0x7f,0x9c,0xc2, +0x1b,0x97,0xf0,0xc6,0x23,0xfc,0xe3,0x10,0xde,0xf8,0x83,0x37,0xee,0xe0,0x8d,0x37, +0xfc,0xd6,0x71,0x06,0x6f,0x7c,0xc1,0x1b,0x57,0x08,0x8f,0x27,0xb8,0xe3,0x09,0xbf, +0x7b,0x1c,0xc1,0xac,0x3d,0x0b,0xf9,0xc1,0xfb,0x0c,0xbb,0x10,0x14,0x76,0x5f,0x65, +0x98,0x25,0x16,0x1d,0x7e,0x9e,0x3b,0xe6,0x27,0x70,0x2c,0x54,0x84,0xaa,0xee,0xcf, +0x61,0xf3,0x53,0xd7,0x89,0x07,0xb3,0xa6,0x49,0x2d,0xa8,0xad,0x75,0x4d,0x3a,0x69, +0x3c,0xe2,0x5a,0xb8,0x01,0xc6,0xc2,0x4d,0xc0,0x4f,0x3f,0x67,0x0a,0x3c,0x0e,0x4f, +0x6b,0x9c,0xc2,0x3c,0xc2,0x3f,0x0f,0x2f,0xc0,0x4c,0x98,0x0d,0x2f,0x6a,0xec,0xe2, +0x25,0x58,0xa0,0xf1,0x8b,0x57,0x34,0x86,0xb1,0x41,0x63,0x18,0xdf,0x6b,0x0c,0x63, +0x01,0x59,0x7a,0x05,0x96,0xc1,0x5a,0x58,0xa7,0x31,0x89,0xcf,0x34,0x0e,0xb1,0x57, +0x6b,0x98,0x64,0x5b,0xe3,0x10,0x66,0xfc,0xe1,0x7a,0x8d,0x3b,0xdc,0x68,0xad,0x53, +0x32,0xce,0x1a,0x73,0x30,0xe3,0x0d,0xdf,0x69,0xbc,0x61,0x8c,0xc6,0x1b,0x12,0x35, +0xc6,0x70,0x2b,0xdc,0x01,0xe3,0xb5,0x0e,0xc9,0x22,0xad,0x41,0xb2,0x44,0xeb,0x90, +0xbc,0xa6,0x75,0x48,0x96,0x5b,0x6b,0x90,0x98,0x71,0x08,0x27,0x8a,0x7f,0x90,0x0f, +0x62,0xa0,0x00,0x14,0x84,0x42,0x50,0x38,0xca,0x5d,0x9b,0xa4,0x34,0x94,0xd1,0x3a, +0x24,0x66,0x0d,0x92,0x2b,0xa1,0x0f,0xf4,0xb3,0xd6,0x1f,0x31,0x6b,0x8e,0x7c,0x0c, +0x9f,0x68,0xdd,0x91,0xcf,0xb4,0xde,0xc8,0x17,0x5a,0x6f,0xe4,0x2b,0xad,0x33,0x62, +0xc6,0x2c,0x8a,0x58,0xeb,0x89,0x24,0x68,0x9c,0xe2,0x69,0x6b,0xed,0x90,0xdd,0x1a, +0xa3,0xf8,0xce,0x5a,0x27,0xe4,0xe7,0x68,0x77,0x7d,0x10,0x6f,0x5d,0x10,0x6f,0x3d, +0x10,0x6f,0x1d,0x90,0x04,0x8d,0x53,0x98,0x35,0x40,0x2e,0xd3,0x58,0x85,0x19,0x97, +0x78,0x09,0xd6,0xc3,0x56,0xad,0xef,0x11,0x61,0xad,0xe5,0xe1,0xad,0xe1,0xd1,0x40, +0x6b,0x76,0x78,0x6b,0x75,0xb4,0xd1,0x58,0x85,0x59,0x97,0xe3,0x72,0x6b,0xed,0x8d, +0xb1,0x1a,0xa3,0xb8,0x47,0x63,0x13,0xde,0x98,0x84,0xb7,0xb6,0xc6,0x52,0xad,0xa5, +0xb1,0xda,0x5a,0x3f,0xc3,0x5b,0x37,0x63,0xb3,0xd6,0xcb,0x30,0x6b,0x65,0x7c,0x0d, +0xdf,0xc0,0x8f,0xd6,0x3a,0x19,0x01,0x6b,0x6d,0x8c,0x22,0x1a,0xa3,0xa8,0xa2,0xb1, +0x89,0x54,0x8d,0x49,0x78,0x6b,0x5f,0x34,0xd0,0x9a,0x17,0x2d,0xac,0x75,0x2e,0xbc, +0xf5,0x2d,0xb2,0x35,0x4e,0x61,0xd6,0xb3,0x18,0xaa,0x35,0x2d,0xbc,0xb5,0x2c,0xc6, +0x6b,0xac,0xe2,0x59,0x8d,0x51,0xcc,0xb5,0xd6,0xab,0x58,0xaa,0xf5,0x29,0xbc,0x75, +0x29,0xd6,0x58,0x63,0x15,0x5b,0xb5,0x06,0xc5,0x7e,0x6b,0xfd,0x09,0x6f,0xdd,0x89, +0x90,0xc6,0x2d,0x4a,0x68,0xbc,0x22,0x49,0xe3,0x14,0xde,0xba,0x12,0xf5,0xad,0x35, +0x24,0x9a,0x68,0xed,0x08,0x6f,0xcd,0x08,0x6f,0xad,0x88,0xce,0x5a,0x23,0xa2,0xa7, +0xb5,0x1e,0xc4,0x58,0x8d,0x5b,0xdc,0xad,0xf1,0x0a,0x6f,0x9c,0xe2,0x09,0x8d,0x4f, +0xbc,0xa0,0x75,0x1e,0xbc,0xf5,0x1d,0x96,0x6b,0x5d,0x87,0x35,0xd6,0x5a,0x0e,0x66, +0x1d,0x87,0x03,0x70,0x10,0x0e,0x15,0x38,0xb2,0x96,0x83,0xb7,0x86,0x43,0x61,0x8d, +0x61,0x54,0xb1,0xd6,0x69,0x68,0xa0,0xf5,0x19,0x9a,0x6b,0x5d,0x86,0x8b,0x34,0x7e, +0xd1,0x4d,0xeb,0x2f,0x0c,0x83,0xe1,0x70,0x83,0xb5,0xf6,0xc2,0x9d,0x1a,0xc3,0x78, +0x56,0x63,0x17,0xde,0xda,0x0a,0xcb,0xb5,0x66,0xc2,0x5b,0x5a,0x2b,0xc1,0x1b,0xc3, +0xd8,0xaa,0xb5,0x11,0xf6,0xab,0x63,0x0b,0x6a,0x0c,0xa3,0xb8,0xd6,0x3c,0xa8,0xab, +0x35,0x0e,0x1a,0x6b,0x6d,0x83,0x96,0xd6,0x38,0x46,0x37,0xad,0x5b,0xe0,0xad,0x53, +0x30,0x56,0xe3,0x17,0x73,0xac,0x31,0x0b,0x6f,0x2d,0x82,0x75,0xd6,0xfa,0x03,0x3b, +0xb4,0xee,0x40,0xc0,0x5a,0x6b,0xc0,0xac,0x33,0x50,0x5f,0xe3,0x19,0x66,0x6d,0x81, +0x56,0x1a,0xcb,0xf0,0xc6,0x30,0x6e,0xb7,0xc6,0x2d,0xbc,0x75,0x03,0x5e,0xb4,0xc6, +0x2c,0xbc,0x35,0x02,0xd6,0x6a,0xcc,0xc2,0x5b,0x13,0xe0,0x0c,0xad,0x03,0x90,0xa6, +0x75,0x00,0x6a,0x6a,0x1d,0x80,0x5a,0x5a,0x0b,0xa0,0x99,0xbe,0xfd,0xf7,0xbe,0xf9, +0x1f,0xab,0x6f,0xfe,0xc7,0xe9,0x5b,0x7f,0xf3,0x9d,0xff,0x22,0x7d,0xe3,0xbf,0x02, +0xde,0xd6,0x58,0x47,0x9c,0xf5,0x5d,0xbf,0xf7,0x3d,0x7f,0x6d,0x7d,0xc7,0x5f,0x5f, +0xdf,0xe9,0x5f,0xac,0xef,0xf3,0xbb,0xea,0xbb,0xfb,0xab,0xac,0x6f,0xed,0xc7,0xea, +0x1b,0x7b,0xef,0xdb,0x7a,0xf3,0xed,0xfc,0xa3,0xd6,0x98,0x87,0x19,0xef,0x68,0xae, +0xf1,0x0c,0x6f,0x1c,0xa3,0x8b,0xc6,0x2f,0x26,0x68,0xdc,0x62,0xbe,0x35,0x56,0xb1, +0x52,0x63,0x14,0xc5,0x35,0x36,0x61,0xbe,0x6b,0xef,0xa2,0xf1,0x89,0x09,0x1a,0x9f, +0x30,0x63,0x13,0x4e,0x49,0x77,0x6c,0x62,0xa4,0xc6,0x24,0x1e,0xd2,0x98,0x84,0x19, +0x7f,0x28,0xac,0xef,0xd5,0xcb,0xe9,0xfb,0xf4,0x54,0x8d,0x43,0x5c,0xa0,0x71,0x88, +0xfe,0xff,0x57,0xd9,0xb9,0x40,0x47,0x59,0x98,0x69,0x78,0x26,0x4c,0x92,0x49,0xc2, +0x25,0x56,0x11,0xaf,0x88,0x82,0x02,0xa2,0x24,0x87,0x84,0x8b,0x5c,0xe3,0x0a,0xca, +0xd9,0x2e,0x27,0x41,0x2b,0x95,0x65,0x95,0xb8,0x8a,0x56,0x6a,0x0b,0xd5,0x54,0xad, +0x5a,0x8c,0xa0,0x45,0x50,0x2c,0xa7,0xab,0xed,0xd1,0xe2,0x82,0x6b,0xbd,0x50,0x45, +0xc2,0xa2,0xd6,0xae,0x0a,0x51,0xcb,0x6a,0xab,0x14,0x14,0xad,0xbb,0x5a,0x05,0xb4, +0xed,0x52,0x95,0xca,0x4d,0x91,0x9b,0xd9,0xf7,0x9b,0xff,0xf9,0x92,0x2f,0x63,0x50, +0x3b,0x39,0x6f,0x12,0x26,0x21,0x33,0xf9,0x33,0x13,0x7e,0xde,0xef,0x7d,0x9f,0x8f, +0x1e,0x7a,0x23,0xfd,0x73,0xef,0x9d,0xaf,0x0a,0x5d,0x73,0xeb,0x99,0xbf,0x26,0xbd, +0x15,0xfa,0xe5,0xd6,0x2d,0xdf,0x26,0xa5,0x8e,0x48,0xfa,0xe5,0x5d,0xe9,0x95,0xf7, +0x62,0x3e,0x71,0x33,0x73,0x89,0xa5,0x61,0x26,0x91,0xa2,0x23,0xde,0x9b,0x6e,0x78, +0x7f,0x3a,0xe1,0xde,0x05,0xb7,0x1e,0x78,0x8d,0x34,0x96,0x2e,0xf8,0x4c,0x66,0x15, +0x4d,0x74,0xbe,0xdf,0x61,0x56,0xd1,0x83,0x8e,0xb7,0x75,0xbb,0x7b,0x86,0x2e,0xf7, +0x79,0xa1,0xbf,0xed,0xbd,0xed,0x69,0xf4,0xb5,0xaf,0x0c,0x1d,0x6d,0xeb,0x67,0x2f, +0xa1,0x97,0x9d,0xa2,0x7b,0x5d,0x1d,0xba,0xd6,0x23,0x42,0xbf,0xda,0x7b,0xd5,0x75, +0xf4,0xa8,0x1b,0xe8,0x51,0xcf,0xa6,0x2f,0xfd,0x00,0x3d,0x69,0xef,0x47,0x3f,0x1a, +0x3a,0xd0,0x5b,0xe8,0x3e,0x6f,0x0d,0x7d,0x67,0xeb,0x3a,0xef,0x3f,0x3a,0xe9,0x36, +0x57,0xd3,0x69,0x1e,0xc1,0xec,0x64,0x21,0xb3,0x11,0xeb,0x27,0x6f,0xa0,0x9f,0xec, +0xbd,0xe4,0xbf,0x86,0x2e,0xb2,0x77,0x90,0x3f,0x0d,0x73,0x12,0xeb,0x10,0xef,0x63, +0x06,0x72,0x04,0xb3,0x8f,0xf1,0xcc,0x3c,0x26,0x87,0x39,0xc7,0x54,0xe6,0x1b,0x36, +0xdb,0x78,0x86,0xb9,0xc6,0x6a,0x66,0x1b,0x36,0xd7,0x58,0xcb,0x5c,0xc3,0x66,0x1a, +0x6f,0x33,0xd3,0xd8,0xca,0x4c,0xc3,0xe6,0x19,0x07,0x38,0x39,0x2a,0x93,0xba,0x4a, +0xdd,0xa4,0x72,0xa9,0x9f,0xd4,0x5f,0x3a,0x59,0x1a,0x20,0x9d,0x22,0x9d,0x2a,0x0d, +0x94,0x2a,0xa4,0x4a,0x69,0xb0,0x34,0x56,0x1a,0x27,0x4d,0x95,0xea,0xa5,0x4b,0xa4, +0x4b,0xa5,0x6f,0x49,0x97,0x49,0xd3,0xa5,0x99,0xcc,0x4b,0x1a,0xa4,0x6b,0xa5,0xeb, +0x99,0x9b,0x34,0x4a,0xf3,0xa5,0xdb,0x98,0xa1,0x2c,0xa1,0x6b,0x9c,0x62,0x8e,0xd2, +0x89,0x39,0x4a,0x96,0x59,0xca,0x61,0xcc,0x51,0x0e,0x67,0x86,0xd2,0x93,0xf9,0xc9, +0x89,0xcc,0x4f,0xfa,0x32,0x3f,0xe9,0xcf,0x0c,0xc5,0x67,0x27,0xc3,0x99,0x95,0xd4, +0x30,0x2b,0xf9,0x47,0xe6,0x24,0x75,0xcc,0x4a,0xe6,0x49,0x0b,0xa5,0xaf,0x9d,0xa0, +0x7f,0x97,0xa4,0xc3,0xa4,0x21,0x3a,0x51,0xbc,0x4e,0xba,0x53,0xfa,0xa9,0x54,0xd3, +0x47,0x9f,0x2b,0xdd,0x22,0x2d,0x92,0xde,0x97,0x1e,0xd1,0x89,0xe4,0x32,0x3b,0x99, +0xec,0x27,0xf5,0xd7,0xbf,0x9f,0x3a,0xa9,0xfc,0x19,0x27,0x96,0x95,0x52,0xbd,0xf4, +0x67,0xe6,0x2b,0x1f,0x31,0x5f,0xd9,0xc3,0x49,0x67,0xdf,0x30,0x53,0x99,0x11,0xfa, +0xc4,0x4b,0x98,0xa3,0x34,0x31,0x3f,0x69,0x66,0x6e,0xb2,0x9e,0x79,0xc9,0x26,0x4e, +0x58,0x1b,0xa5,0x9f,0xdb,0x89,0x6b,0x85,0x9e,0xb7,0x15,0xc9,0x09,0x6c,0x9a,0x39, +0x4a,0x96,0xd9,0xc9,0xc9,0x74,0x85,0x2b,0x99,0xa1,0x0c,0x61,0x86,0x32,0x8a,0x99, +0xc9,0x5d,0xcc,0x4c,0x6c,0x5e,0xb2,0x84,0x39,0x89,0xf7,0x7f,0x0b,0x99,0x8b,0x2c, +0x94,0x9a,0x99,0x89,0x1c,0x3b,0x48,0x0f,0x15,0xa9,0x4e,0xaa,0x97,0xae,0x97,0x6e, +0x90,0x56,0x48,0xcd,0xd2,0xcb,0xd2,0x7a,0xe9,0xea,0x2a,0x1d,0x3b,0xe9,0x1d,0x69, +0x93,0xd4,0x52,0x95,0xcc,0x52,0x9a,0x99,0xa5,0xd8,0x49,0xf4,0x42,0xe6,0x27,0x5d, +0x98,0x93,0xd4,0xd0,0xed,0xbd,0x92,0x7e,0xef,0x2c,0xe6,0x22,0xff,0xce,0x3c,0xc4, +0xba,0xbb,0x3b,0xec,0x84,0x9b,0x39,0x88,0xcd,0x3b,0xe6,0x49,0xcf,0x31,0xd7,0xf0, +0x7e,0xad,0xf7,0x6a,0xbd,0x4f,0x7b,0x22,0xdd,0xd9,0x7e,0x74,0x67,0x2b,0xa5,0x61, +0xcc,0x32,0x1a,0xe8,0xd0,0x5a,0x5f,0xf6,0xf7,0xf4,0x64,0x77,0x84,0x2e,0xac,0xf5, +0x5f,0x07,0xd2,0x7b,0xb5,0xce,0xeb,0x54,0xba,0xae,0x73,0x42,0xaf,0xf5,0x09,0xfa, +0xac,0x4f,0xd3,0x63,0xb5,0xb9,0xc6,0x3b,0xa1,0xaf,0x9a,0xa2,0x8f,0x5a,0x41,0x0f, +0xb5,0x8a,0xfe,0x69,0x4d,0xe8,0x9c,0xfe,0x53,0xe8,0x99,0xfe,0x4b,0xe8,0x8e,0x36, +0x85,0x9e,0xe8,0xe3,0xf4,0x43,0x7f,0x4d,0x2f,0xb4,0x39,0x74,0x41,0xdf,0xa2,0xeb, +0xf9,0xb7,0xd0,0xe3,0x2c,0x61,0x3e,0xd1,0x8b,0xb9,0x84,0xcd,0x24,0xa6,0x33,0x7b, +0xf0,0x0e,0xa6,0x77,0x2f,0xbd,0x6b,0x69,0x73,0x88,0x26,0xe6,0x0f,0xf6,0x1f,0x94, +0x99,0xcc,0x1c,0x0e,0x0d,0x3d,0x4a,0x9b,0x35,0xf4,0x67,0xd6,0x30,0x2c,0xcc,0x17, +0xce,0x60,0xae,0x50,0xc7,0x5c,0x61,0x34,0x73,0x85,0x9f,0x30,0x4f,0x38,0x40,0x4f, +0xb2,0x9c,0x9e,0x64,0xa5,0x54,0x27,0x4d,0x94,0xce,0x96,0xbe,0x21,0x9d,0x2b,0x4d, +0x92,0xa6,0x4a,0xf5,0xd2,0xbf,0x4a,0x17,0x4b,0xdf,0x92,0x2e,0x93,0xbe,0x4d,0x97, +0xd2,0xe6,0x11,0x2d,0x52,0xba,0x45,0x3f,0x73,0xa9,0x48,0x2a,0x93,0x3a,0x4b,0x5d, +0xa4,0xae,0x2d,0x49,0xc7,0xf2,0x28,0xe9,0x68,0x7a,0x96,0x23,0x98,0x5b,0x4c,0x61, +0x6e,0xf1,0x1c,0xf3,0x88,0x57,0x99,0x43,0x6c,0x92,0xde,0x95,0xfe,0x2c,0x6d,0x91, +0xf6,0x30,0x97,0xe8,0xc2,0x3c,0x62,0x24,0x73,0x88,0x3a,0xe6,0x0f,0xb6,0x68,0x2a, +0x2d,0x15,0x48,0xc5,0xd2,0xd0,0x74,0x32,0x8f,0x58,0x20,0x2d,0x94,0x96,0x48,0xeb, +0x43,0x6f,0x72,0x09,0x5d,0xc9,0xcd,0xcc,0x27,0x4e,0x65,0xfe,0x70,0x15,0xf3,0x87, +0xc5,0xcc,0x1d,0x52,0xf4,0x1c,0x9b,0x98,0x2f,0xa4,0x98,0x2b,0xcc,0x60,0x1e,0x50, +0xc3,0x1c,0x20,0x15,0x3c,0xfe,0xa1,0xc1,0xd7,0xff,0xa6,0xf4,0x20,0x5e,0xbe,0xf9, +0xf8,0xfb,0xa4,0xe3,0xf0,0xf0,0xc7,0xe0,0xdd,0x3f,0x2d,0xbd,0x5a,0x92,0xf4,0x05, +0x0b,0xe9,0x09,0x96,0xe3,0xdb,0x1f,0x49,0x2f,0xd0,0xfa,0x80,0x35,0x52,0x1d,0xfe, +0x7d,0x33,0xfd,0xbf,0x0f,0xf0,0xeb,0x4f,0xc3,0xaf,0x3f,0x4f,0xba,0x46,0xba,0x4b, +0x5a,0x8a,0x57,0xdf,0x88,0x47,0xbf,0x17,0x8f,0xbe,0x0f,0x5d,0xbf,0xfa,0xae,0x89, +0xf7,0x6e,0x3d,0xbd,0x65,0xf8,0xef,0x29,0x7c,0x75,0xeb,0xdc,0x4d,0xc4,0x53,0xdf, +0xd4,0xad,0xad,0x57,0x57,0x40,0x8f,0xee,0x2c,0xe9,0x6c,0xba,0x74,0x37,0xd0,0x8f, +0x5b,0x49,0x17,0xce,0x7a,0x70,0x4f,0x49,0x6b,0xf1,0xd8,0xb7,0xd1,0x7d,0xeb,0x44, +0xe7,0xcd,0xbb,0x6e,0x43,0xf0,0xd8,0xad,0xc3,0xd6,0x40,0x7f,0x6d,0x36,0x3d,0xb5, +0xd5,0xf4,0xd2,0xd6,0x86,0x2e,0xda,0x66,0x3c,0xf6,0x43,0xe9,0x9a,0x0d,0x0a,0xfd, +0x32,0xeb,0x96,0x0d,0xa3,0x57,0xd6,0x18,0x7c,0xf6,0x1f,0xe3,0xaf,0x37,0x85,0xae, +0xd8,0x7b,0x74,0xc4,0x52,0x74,0xc3,0x0a,0xf1,0xda,0x0f,0xc5,0x63,0x1f,0x84,0xb7, +0x3e,0x02,0x5f,0xdd,0xbb,0x5e,0x67,0xd1,0xf1,0xaa,0x0b,0xbd,0xae,0x4b,0xe8,0x71, +0xa5,0xe8,0x49,0xd5,0xd0,0x8f,0x1a,0x17,0x3a,0x51,0xe7,0x87,0x1e,0x54,0x23,0xbd, +0xa7,0x5f,0x87,0xae,0xd3,0xea,0xd0,0x6f,0xfa,0x0d,0x7d,0xa6,0x46,0xfa,0x4b,0x4f, +0xd2,0x5b,0xf2,0xbe,0xd2,0xb3,0xf4,0x94,0x52,0xf4,0x92,0x46,0x84,0x2e,0x92,0xf5, +0x90,0x4e,0xa7,0x7f,0x54,0x8f,0xef,0xfe,0x70,0xe8,0x1c,0x3d,0x4a,0xd7,0xe8,0x89, +0xd0,0x2f,0x6a,0xc6,0x8f,0x3f,0x96,0xde,0xd0,0x09,0xa1,0x2b,0x54,0x89,0x37,0x5f, +0x11,0x7a,0x40,0x23,0xf0,0xe9,0xcd,0xa3,0x77,0x6f,0xbe,0x3b,0x9e,0xfc,0x50,0xba, +0x3d,0xa3,0x42,0x9f,0xc7,0xfa,0x3a,0x63,0xe9,0xec,0x2c,0xc1,0x9b,0x7f,0x8d,0x6e, +0xce,0x1f,0x43,0x1f,0xc7,0x7b,0x37,0xc5,0x52,0x09,0x1e,0x7d,0x15,0x7d,0x1b,0xeb, +0xd9,0x8c,0x09,0x1d,0x9b,0x89,0x74,0x6b,0x26,0xe3,0xd9,0xcf,0x0f,0x3d,0x9a,0xbb, +0xcd,0xaf,0x3f,0x2a,0xf1,0xea,0x4b,0xe9,0xba,0x0c,0xa3,0xdf,0x62,0x7d,0x96,0x99, +0xf4,0x58,0xbc,0xbf,0xe2,0xbd,0x15,0xef,0xab,0xa4,0xf0,0xef,0xcb,0xe8,0xa7,0x78, +0x2f,0x65,0x4c,0xe8,0xa2,0xd4,0xe1,0xe5,0x5f,0x8a,0x87,0xbf,0x90,0xae,0xc9,0x9d, +0xa1,0x5f,0xe2,0xbd,0x92,0x4d,0xf4,0x45,0xac,0x2b,0x62,0x1e,0x7d,0xb3,0xf4,0xba, +0xf4,0xb6,0xb4,0x59,0x6a,0x39,0x2e,0xf1,0xeb,0x67,0xe2,0xd7,0x9b,0x47,0x5f,0x59, +0x9d,0x78,0xf2,0xe6,0xc3,0xd7,0xd0,0xb3,0xf8,0x2e,0xfe,0xbb,0x75,0x2a,0x3e,0xc6, +0x83,0xb7,0x3e,0xc5,0x50,0x7a,0x14,0x53,0xf0,0xe1,0xcd,0x83,0xaf,0xc1,0x53,0xf7, +0x0e,0xc4,0x8f,0xf1,0xd4,0xcd,0x4f,0x7f,0x37,0x74,0x1d,0xb6,0xe1,0xa1,0xa7,0x6e, +0x91,0x16,0x24,0xfe,0x78,0x1d,0x3e,0xb8,0x79,0xe0,0x29,0xbc,0xef,0x46,0x3c,0xef, +0x45,0x74,0x10,0x16,0x4b,0x4b,0xcc,0xff,0xb6,0x25,0x6e,0xaf,0xa4,0x53,0xfd,0xe9, +0x1c,0x4c,0x97,0xae,0xa4,0x6f,0x30,0x87,0xbe,0xc1,0x6d,0xf4,0x0d,0x1e,0xb5,0xc5, +0x93,0xaf,0x26,0x9d,0x83,0x71,0xd2,0x26,0xeb,0x1d,0x6c,0xd0,0xf7,0xb6,0x21,0xf1, +0xd1,0x27,0xe1,0x9f,0xbb,0x6f,0xbe,0x14,0xbf,0xdc,0x7d,0x72,0xf3,0xc8,0x8b,0xf1, +0xc6,0x0f,0xc7,0x13,0x1f,0x81,0x17,0xee,0x1e,0xb8,0xf9,0xdf,0xe6,0x7d,0xbf,0x85, +0xe7,0xdd,0x1d,0xaf,0xbb,0x16,0x8f,0x7b,0x1e,0xde,0xf6,0xf3,0x78,0xda,0xd6,0x03, +0xc8,0x2d,0x4a,0x7a,0x53,0xc7,0x91,0x1e,0xc0,0x77,0xe8,0x00,0x5c,0x45,0x07,0xe0, +0x66,0x7a,0x00,0xd6,0x01,0x48,0x91,0xed,0x3f,0x9a,0x4c,0xff,0x49,0x78,0xdd,0x95, +0x78,0xdd,0x35,0xf8,0xdc,0xcd,0x64,0xf2,0x2d,0x8f,0xdf,0xf2,0x6e,0xe2,0x37,0xbf, +0x40,0xae,0x3d,0x45,0x9e,0xdd,0x73,0xec,0x17,0x48,0xdf,0xfb,0x50,0x8f,0xfd,0xad, +0x89,0xff,0x5c,0x88,0xef,0xdc,0x27,0x78,0xcd,0xd5,0xc1,0x5f,0xfe,0x87,0xe0,0x29, +0xbb,0x97,0x3c,0x31,0xf8,0xc7,0x93,0x83,0x67,0xec,0x5e,0xb1,0x7b,0xc4,0x97,0xe3, +0x0d,0xff,0x20,0xf8,0xc1,0xb7,0xe2,0x03,0xdf,0x8f,0xff,0xbb,0xcd,0xfc,0xdf,0x6d, +0xfa,0x9e,0xa4,0x25,0xd2,0x0a,0xe9,0x59,0xe9,0x15,0x5b,0xbc,0xb7,0x5d,0xcf,0x0b, +0xa9,0x5c,0xaa,0x90,0x2a,0xa5,0xe9,0xd2,0x4c,0x69,0x99,0xf4,0x17,0xfb,0xd8,0x0e, +0x1d,0x07,0xa9,0x4e,0xaa,0x97,0x52,0x3b,0xf5,0xb3,0xfe,0x44,0x5f,0x57,0x4a,0xed, +0xd6,0x6d,0x4a,0x9b,0x24,0x5b,0x90,0x5a,0x2e,0xd5,0x49,0xf5,0xd2,0x42,0xa9,0xc9, +0x96,0xa6,0xee,0x49,0xa7,0xae,0x95,0xd6,0x4a,0xf5,0x7b,0xf5,0xb5,0xa5,0x6b,0xa4, +0x46,0x69,0xa1,0xd4,0x24,0x35,0x4b,0xeb,0x6d,0xa1,0xd8,0xbe,0x74,0xea,0x8e,0x7d, +0x49,0xfe,0x3d,0xb7,0xf8,0xf7,0xc1,0x82,0x54,0xcd,0xaf,0x12,0xbf,0xda,0xbc,0x6a, +0xf3,0xa7,0xcd,0xa8,0x4d,0xa7,0xba,0xea,0xbf,0x54,0x5d,0x13,0xf3,0x24,0x95,0x98, +0x11,0xd9,0x83,0x78,0xd4,0x47,0x27,0xff,0xc5,0x6b,0xf5,0xa8,0x6d,0x5d,0xf1,0x89, +0xd2,0xc9,0x79,0x1e,0x75,0x05,0xcc,0x6d,0xf3,0xa8,0x6b,0xc8,0xcb,0xd7,0x93,0x97, +0x9f,0x25,0xdd,0x84,0x47,0xbd,0x38,0x78,0xd4,0xf7,0x27,0xa7,0xb1,0x39,0x8f,0xfa, +0x11,0x3c,0xea,0xe5,0xd2,0x0a,0x69,0x65,0xf0,0xa8,0x9f,0x0c,0x1e,0xf5,0x6a,0x32, +0xf6,0x6f,0x90,0xb1,0x37,0x8f,0x5a,0xdf,0x5e,0xea,0xbf,0xc8,0xcc,0xaf,0x23,0x33, +0xbf,0x91,0xcc,0xfc,0x56,0x3c,0xea,0x96,0x82,0x84,0xb1,0x6d,0x79,0xf9,0xef,0x93, +0x93,0xff,0x61,0xf0,0xa8,0x6f,0x0e,0x1e,0xb5,0x67,0xe3,0xef,0x25,0x0f,0x6f,0x1e, +0xf5,0xec,0x8c,0xce,0xe7,0xc9,0xc3,0x5b,0x16,0x7e,0x1e,0x1e,0xf5,0xed,0x78,0xd4, +0xcf,0xe4,0x79,0xd4,0xcf,0xe1,0x51,0xaf,0x09,0x1e,0xb5,0x65,0xe5,0x77,0x49,0x85, +0x45,0xfa,0x3f,0x00,0x1e,0x75,0x69,0x9e,0x47,0xdd,0x0d,0x76,0xf6,0x31,0x64,0xe7, +0xa7,0xc2,0xc8,0x36,0x8f,0xfa,0xf2,0xc0,0xc9,0x7e,0x1d,0x26,0xb6,0x7b,0xd4,0x7f, +0x22,0x4b,0xbf,0x05,0x8f,0x7a,0x2b,0x99,0x7a,0xe3,0x60,0x77,0x09,0xdc,0xeb,0x0a, +0x58,0xd7,0xf7,0x07,0xc6,0xf5,0xfb,0xf0,0xac,0x2d,0x43,0xbf,0x27,0x78,0xd4,0xdd, +0x03,0xbf,0xda,0xb9,0xd5,0xce,0xab,0x36,0x4e,0xf5,0x68,0x72,0xf4,0x53,0xf0,0xa8, +0x2d,0x4b,0xff,0x98,0xf4,0x02,0xfc,0xe9,0x77,0xe1,0x4f,0x9f,0x96,0xe7,0x51,0xd7, +0xc0,0x95,0x76,0xa6,0x74,0x1d,0xfc,0xe8,0x0b,0xe1,0x46,0x3b,0x23,0x7a,0x0e,0x39, +0xfa,0x85,0xe4,0xe7,0x3d,0x3b,0xef,0x0c,0xe8,0x66,0x78,0xcf,0x2f,0x06,0xce,0xb3, +0x7b,0xd4,0x6f,0x93,0x9d,0x7f,0x8f,0xec,0xfc,0x4e,0x69,0x2f,0x1e,0xf5,0x01,0x3c, +0x6a,0x67,0x38,0x97,0x92,0xa3,0xef,0x47,0x7e,0xbe,0x8a,0xdc,0xbc,0x33,0x9a,0x6b, +0xe0,0x32,0x8f,0x0f,0x3c,0x66,0xcf,0xd1,0xcf,0x80,0xbd,0xdc,0x10,0x3c,0x6a,0x67, +0x2e,0x2f,0x20,0x4f,0xff,0x10,0x39,0xfa,0x95,0x81,0xab,0xdc,0x0c,0x43,0xd9,0xf9, +0xc9,0x2f,0x07,0x8f,0x7a,0x33,0x9c,0xe4,0x6d,0xc1,0xa3,0x76,0x3e,0x72,0x27,0xb2, +0xf5,0xe5,0x64,0xea,0x2b,0xc9,0xd2,0x3b,0xff,0x78,0x74,0xf0,0xa8,0xc7,0xc2,0x37, +0x76,0xb6,0xb1,0x33,0x8d,0xcf,0x27,0x5f,0x6f,0x0c,0xe3,0xab,0x83,0x47,0x3d,0x9f, +0x5c,0xfd,0x9d,0x21,0x4f,0xbf,0x98,0x0c,0xfd,0x2f,0xc9,0xce,0x3b,0x87,0xf8,0x39, +0xd8,0xc3,0x2f,0xe7,0x79,0xd4,0x3b,0xa4,0x4f,0xf3,0x3c,0x6a,0x67,0x0d,0x77,0x26, +0x67,0xdf,0x2f,0xe4,0xeb,0x6b,0x60,0x08,0x8f,0x87,0x1d,0x3c,0x89,0xac,0xfd,0x85, +0x30,0x82,0x67,0xe0,0x51,0xcf,0x0a,0x8c,0xe0,0xdb,0xc8,0xd9,0x3f,0x44,0xbe,0xde, +0x19,0xc0,0xbf,0x81,0xeb,0xfb,0x12,0x3c,0xdf,0x3f,0xe0,0x51,0x6f,0x86,0xdf,0xfb, +0x11,0x39,0xfb,0x34,0x39,0xfb,0x72,0xf2,0xf5,0x23,0xe1,0xf0,0x8e,0x85,0xbf,0xeb, +0xec,0xdd,0x5a,0xf2,0xf5,0x17,0x05,0x9e,0xee,0x1c,0x32,0xf6,0x2b,0x42,0xb6,0xde, +0x99,0xb9,0xaf,0x04,0x4e,0xee,0x46,0xd8,0xb8,0xbb,0xba,0xb4,0x31,0x71,0xab,0xe0, +0xe0,0x8e,0x21,0x67,0x6f,0xec,0xdb,0x29,0x21,0x6b,0x3f,0x3f,0xe4,0xeb,0x9d,0x6f, +0xbb,0x32,0x30,0x6d,0x3d,0x53,0xbf,0x16,0x7e,0xad,0x65,0xea,0x7b,0xc0,0xac,0xad, +0x3e,0x88,0x47,0x3d,0x8a,0xac,0xfd,0xe5,0x81,0x4d,0x7b,0x13,0x1e,0xf5,0x5c,0x72, +0xf7,0x3f,0x83,0x43,0xbb,0x06,0x8f,0xfa,0x65,0xe9,0xcd,0x6e,0x09,0x83,0xd6,0xf9, +0xb3,0xce,0x9d,0x1d,0x0e,0x6b,0x76,0x34,0x2c,0xd9,0xc9,0x64,0xf3,0xeb,0xc9,0xe2, +0x37,0x04,0x26,0xec,0x4d,0x70,0x60,0x9d,0x01,0xeb,0x8c,0xd7,0x35,0xc1,0xa3,0x1e, +0x4f,0xe6,0xde,0xf3,0xf6,0xe7,0x93,0xb1,0x5f,0x40,0xb6,0xfe,0xf1,0x90,0xa9,0x5f, +0x43,0x8e,0xbe,0x9c,0xfc,0xfc,0x3f,0xc3,0x5d,0xbd,0x9e,0xfc,0xfc,0x5d,0xe4,0xe7, +0x0f,0xe0,0x51,0x5b,0x66,0xbe,0x91,0xcc,0xfc,0x22,0x32,0xf2,0x9d,0xc9,0xc8,0x1f, +0x46,0x46,0xde,0xb8,0xa9,0x43,0xc8,0xc9,0x9f,0x43,0x4e,0x7e,0x26,0x9c,0xd4,0x95, +0x81,0x8f,0xfa,0x4c,0x60,0xa2,0xbe,0x08,0x07,0xf5,0xcd,0x3c,0x8f,0xda,0xd8,0xa7, +0x7b,0xa4,0x52,0xf8,0xa7,0x5d,0xe1,0x9e,0x5e,0x43,0x7e,0xfe,0x47,0x81,0x6b,0xfa, +0x4b,0x32,0xf3,0x3d,0x61,0x98,0x9e,0x04,0xbb,0x74,0x40,0x60,0x96,0x0e,0x83,0x53, +0x6a,0x1e,0xf5,0x38,0x32,0xf5,0x0d,0x64,0xe9,0x7f,0x0b,0x8b,0xb4,0xe5,0xc8,0x24, +0x4b,0x7f,0x44,0x60,0x90,0x9e,0x1b,0x3c,0xea,0x0b,0xf2,0x3c,0xea,0x8b,0x61,0x8a, +0x5e,0x11,0x58,0xa2,0xf3,0xe0,0x87,0x2e,0x93,0x9a,0x8f,0x4a,0x18,0xa1,0x55,0xc1, +0xa3,0x1e,0x1e,0x3c,0x6a,0xe7,0x7f,0x7e,0x5d,0x9a,0x0e,0xe7,0xf3,0x7a,0x38,0x9f, +0xf7,0xc2,0xf3,0x7c,0x30,0x70,0x3c,0x97,0x05,0x56,0xe7,0xff,0xc1,0xe7,0xfc,0x30, +0x78,0xd4,0xdb,0x61,0x71,0x0e,0x80,0xbd,0x39,0x18,0xe6,0xa6,0xf1,0x36,0x6f,0x21, +0xbf,0xff,0x02,0xfc,0xcc,0x0d,0x81,0x9f,0xb9,0x25,0x30,0x33,0x9d,0x95,0xb9,0x3b, +0x70,0x31,0x2d,0x9f,0xbf,0x07,0xce,0x65,0x77,0xf2,0xf9,0xe3,0xc8,0xe5,0x7f,0x33, +0xcf,0xa3,0xfe,0x21,0xf9,0xfb,0xa7,0x83,0x47,0xfd,0x2c,0xd9,0x7b,0xcb,0xdd,0xaf, +0x23,0x77,0x6f,0x99,0xfb,0x8d,0x64,0xee,0x3f,0x22,0x73,0x6f,0x79,0xfb,0xcf,0xa4, +0x52,0x98,0x95,0xee,0x51,0xf7,0xfd,0x0a,0x1e,0x75,0xb5,0x74,0x06,0x1e,0xf5,0x05, +0x78,0xd4,0x17,0x77,0xe0,0x51,0xcf,0x08,0x1e,0xf5,0x0f,0xa4,0xeb,0xa4,0x59,0x78, +0xd4,0xf3,0xa4,0x5b,0xa5,0xdb,0xc9,0xf8,0xaf,0x86,0x7d,0x99,0xc6,0xa3,0x2e,0xc2, +0xa3,0x2e,0x21,0xeb,0x7f,0x58,0xc8,0xfa,0x5b,0xc6,0xbf,0xf7,0x17,0x78,0xd4,0x9e, +0xf1,0xb7,0x2c,0xff,0x08,0xb2,0xfc,0x63,0xc9,0xf2,0x4f,0x90,0x6a,0xa5,0xa9,0x64, +0xf7,0x6f,0x95,0x0e,0x39,0xa1,0xcd,0xa3,0x1e,0xdc,0x5b,0xe7,0x7e,0xd2,0x1d,0x78, +0xd4,0x27,0xf5,0xd1,0x79,0x87,0x34,0x57,0xfa,0xb9,0xf4,0x57,0xe9,0xe1,0x93,0x12, +0x8f,0xba,0xa5,0xaf,0xd4,0x4f,0x8f,0x25,0x9d,0x50,0xde,0x29,0xb5,0x48,0x03,0x75, +0x62,0x79,0x01,0xf9,0xff,0xf7,0xc9,0xff,0x6f,0x27,0xff,0xdf,0x72,0x4a,0x5b,0xfe, +0xff,0x54,0x32,0xff,0x33,0xf1,0xa8,0x7f,0x4a,0xd6,0xff,0x51,0x32,0xfe,0xab,0xc8, +0xf6,0xff,0x9e,0x4c,0xff,0x3b,0xb0,0x2c,0xcf,0x1e,0xa8,0xc7,0xbc,0xb4,0x53,0x7a, +0x5d,0x27,0xaf,0xfb,0xf0,0xa8,0x33,0x64,0xfb,0x7b,0x91,0xed,0x3f,0x15,0x96,0x65, +0x25,0x19,0xff,0xa1,0x64,0xfa,0xc7,0x90,0xe9,0xbf,0x9b,0x4c,0xff,0x62,0x3c,0x6a, +0xe7,0x54,0x5a,0x7e,0xbf,0x82,0xdc,0xbe,0x65,0xf6,0xdf,0x93,0x8e,0x19,0xa4,0xe7, +0xbb,0x54,0x2b,0x4d,0x95,0xae,0x93,0x66,0x49,0x4d,0xd2,0x6a,0xe9,0x25,0x69,0x9d, +0x74,0x55,0x95,0x8e,0x9d,0xf4,0xb6,0xb4,0x51,0xfa,0x0c,0x8f,0xda,0xb2,0xfe,0x2d, +0xd2,0xfe,0xc5,0x49,0xbe,0xff,0xbf,0x7f,0x91,0xe4,0xf8,0xbb,0x91,0xdf,0xb7,0xcc, +0xfe,0x15,0x78,0xd4,0xce,0x9f,0xbc,0x07,0xd6,0xe4,0x47,0xb0,0x25,0x77,0x4b,0xc7, +0x87,0x5c,0xfe,0x6a,0xe9,0x77,0x81,0x03,0xe9,0xfc,0x47,0xe7,0x3e,0xf6,0x09,0x8c, +0xc7,0x01,0x78,0xd4,0x43,0xa5,0xd3,0xc8,0xda,0x5f,0x0d,0xd3,0x71,0x0d,0x2c,0xc7, +0xed,0x81,0xd9,0x78,0x22,0x7c,0xc6,0x33,0xe1,0x32,0x9e,0x43,0xce,0x7e,0x76,0xe0, +0x2f,0x3e,0x0e,0x73,0xf1,0x29,0x58,0x8b,0x6b,0x61,0x2b,0x3a,0x57,0xd1,0x72,0xf6, +0xfd,0xe0,0x25,0x56,0xc2,0x49,0xac,0x86,0x8f,0xe8,0x6c,0xc4,0xaf,0x07,0x8f,0x7a, +0x72,0x60,0x1c,0x2e,0x0f,0x1e,0xf5,0x63,0x64,0xec,0x9f,0x24,0x63,0xbf,0x3a,0xcf, +0xa3,0xfe,0x00,0x16,0xa1,0xf3,0x06,0x8b,0xc8,0xd0,0x1f,0x4e,0x76,0x7e,0x20,0xd9, +0xf8,0x6f,0x07,0x56,0xa0,0x33,0x02,0x9d,0x09,0x68,0x2c,0xc0,0xfb,0xc8,0xc8,0x5b, +0x3e,0xfe,0x3b,0xe4,0xe2,0x8b,0x42,0x1e,0xbe,0x27,0x59,0xf8,0xfe,0x64,0xe1,0x3d, +0x07,0x7f,0x3a,0xd9,0xf7,0x5a,0xe9,0x59,0x72,0xef,0x63,0xc8,0xbd,0x5b,0xe6,0x7d, +0x3f,0x1e,0xb5,0x71,0xfc,0x8e,0x84,0xe3,0x57,0x7b,0x10,0x8f,0xfa,0x02,0x3c,0xea, +0x0b,0xa5,0x8b,0xa4,0x4b,0xf0,0xa8,0xa7,0xe3,0x51,0x37,0x90,0x97,0x37,0x8f,0xba, +0xa0,0x45,0x3f,0x73,0xa9,0x34,0xcf,0xa3,0xee,0x06,0x03,0xd0,0x3c,0xea,0x5e,0xe4, +0xea,0x6b,0x02,0xff,0x6f,0x15,0x99,0xf9,0x75,0x64,0xe5,0x2d,0x27,0xbf,0x59,0xfa, +0x93,0xf4,0x17,0xe9,0x6f,0xd2,0x01,0xfb,0x9a,0x64,0xe6,0x87,0x93,0x95,0x9f,0x40, +0x46,0x7e,0x6f,0x9e,0x47,0x5d,0x25,0x8d,0x91,0x6e,0x93,0x6e,0x97,0x16,0xe1,0x51, +0xef,0xc7,0xa3,0x5e,0x14,0x98,0x7e,0xfb,0xa4,0xde,0x64,0xe4,0xbf,0x0f,0xab,0xef, +0x1e,0xb2,0xf1,0x96,0x87,0xbf,0x07,0x0e,0xdf,0x06,0xf2,0xef,0x7d,0xc9,0xbd,0x9b, +0x47,0x3d,0x84,0xac,0xba,0xe5,0xd4,0x3d,0x8b,0x3e,0x38,0xe4,0xcf,0xcf,0x25,0x6b, +0xbe,0x9c,0xac,0xb9,0xe5,0xcc,0x8f,0x2e,0x49,0x3c,0xea,0xd3,0xf0,0xa8,0x2d,0x5b, +0xbe,0x8e,0x5c,0x79,0x27,0x58,0x76,0xdd,0xc8,0x96,0xf7,0x20,0x53,0xee,0xdc,0xba, +0xf1,0xd2,0x79,0xd2,0x62,0xb2,0xe4,0xc6,0xa7,0xfb,0xa4,0x34,0xc9,0x93,0x8f,0x21, +0x4f,0x7e,0x05,0x39,0xf2,0x45,0xd2,0xf2,0xb2,0x24,0x4b,0xfe,0x9f,0x64,0xc8,0x5b, +0x3a,0x27,0x19,0xf2,0xbe,0xb0,0xe8,0x66,0x91,0x0d,0x7f,0x04,0x8f,0xda,0xf2,0xe1, +0x7d,0xc9,0x7d,0x1b,0x13,0x6e,0xb2,0xf4,0x52,0xe0,0xbf,0xa5,0xc9,0x7c,0x1b,0xe7, +0x6d,0x82,0x34,0x0d,0xd6,0xdb,0x8d,0x30,0xdb,0x9e,0x80,0xd5,0x66,0x9c,0xb6,0x67, +0xf1,0xa8,0xb7,0xc0,0x67,0x2b,0x20,0x07,0xee,0x4c,0xb6,0x6a,0x72,0xe0,0x57,0x04, +0xce,0xda,0x8d,0xb0,0xd4,0x8c,0xa3,0xf6,0x62,0xe0,0xa6,0x99,0x47,0xbd,0x51,0xda, +0x75,0x48,0x92,0x01,0x1f,0x08,0x0b,0xad,0x2a,0x78,0xd4,0xc6,0x3e,0x1b,0x85,0x47, +0xed,0x79,0xf0,0x05,0x64,0xc0,0x97,0x06,0xa6,0xd9,0xbb,0x70,0xcc,0x8c,0x61,0x96, +0x86,0x5d,0xd6,0x99,0x2c,0x78,0x3f,0x32,0xe0,0x55,0x64,0xbf,0x47,0x06,0x26,0xd9, +0x58,0x38,0x64,0x13,0x82,0x47,0x7d,0x11,0xac,0x31,0xe3,0x8c,0x0d,0x85,0xe3,0x75, +0x7a,0xe0,0x77,0x99,0x47,0x3d,0x25,0x78,0xd4,0x17,0xc2,0xe6,0x7a,0x32,0x78,0xd4, +0xab,0x02,0x87,0xeb,0x79,0x32,0xdf,0xc6,0xdb,0x5a,0x01,0x5f,0xeb,0xa9,0xc0,0xd5, +0x6a,0x26,0x03,0x6e,0x1c,0xad,0x41,0x70,0xb3,0x46,0x06,0x8f,0xda,0x39,0x59,0xc6, +0xc7,0xba,0x3c,0xf0,0xb1,0xdc,0xa3,0x5e,0x1e,0x58,0x58,0xee,0x51,0x1b,0xfb,0xea, +0x28,0xd8,0x56,0xc7,0x07,0xa6,0x95,0xb1,0xac,0xc6,0xf4,0x48,0x98,0x55,0xce,0xab, +0x1a,0x8e,0x47,0xbd,0x23,0x64,0xc8,0x0f,0x25,0x37,0x3e,0x18,0xfe,0xd4,0xc8,0xe0, +0x51,0x3b,0x57,0xea,0x4c,0x98,0x52,0x0f,0xc2,0x90,0x7a,0x03,0x76,0x94,0x73,0xa3, +0x9c,0x0f,0x55,0x24,0x65,0xe1,0x43,0x0d,0x82,0x0b,0x35,0x1c,0x0e,0xd4,0x99,0xc1, +0xa3,0x9e,0x04,0xfb,0x69,0x0a,0x99,0x72,0xe7,0x3d,0x19,0xe7,0xe9,0x3f,0xc8,0x95, +0x67,0xe1,0x31,0x0d,0x81,0xc3,0x34,0x4e,0xba,0x9c,0x2c,0xb9,0x73,0x96,0x9c,0xaf, +0xe4,0x5c,0x25,0xe3,0x29,0x15,0x91,0x2f,0xaf,0x0c,0xfc,0xa4,0x51,0x81,0x99,0x74, +0x16,0x9c,0xa4,0x69,0xe4,0xcc,0x6f,0x87,0x87,0x74,0x47,0x07,0x1e,0xb5,0x71,0x8f, +0x76,0xc0,0x33,0xfa,0x14,0x8f,0xfa,0x35,0xe9,0x8f,0xd2,0x26,0x69,0xfb,0x71,0x49, +0xa6,0xdc,0xf2,0xe4,0x0d,0xe4,0xc9,0x07,0x56,0xeb,0xfb,0xae,0x4e,0x32,0xe3,0xc3, +0xc8,0x88,0x1b,0x07,0x68,0x06,0xf9,0xf0,0x5d,0x78,0xd4,0x15,0xf0,0x7e,0xc6,0xc1, +0xf9,0xb9,0x90,0x9c,0xb8,0x65,0xc4,0xef,0xfe,0x6e,0x1b,0xab,0x67,0x2e,0x5c,0x9e, +0xc5,0xe4,0xbd,0xa3,0x47,0x6d,0x1c,0x9e,0xdd,0x73,0x93,0x9c,0x77,0x76,0x41,0x3a, +0xd5,0x93,0xcc,0xf6,0xa5,0x64,0xb4,0xa7,0x93,0xcd,0xbe,0x85,0x4c,0xf6,0x22,0x18, +0x39,0xe6,0x51,0xdf,0x27,0x7d,0xbc,0x5e,0x8f,0x15,0xb8,0x38,0x97,0xc1,0xc3,0xb9, +0x16,0x1e,0xce,0x4d,0xf0,0x70,0x96,0xc2,0xc3,0xd9,0x22,0x9d,0x0e,0x13,0xc7,0x3c, +0xea,0x9d,0xd2,0xa4,0x0d,0xe9,0xd4,0x35,0x1b,0x92,0x9c,0xf7,0xa2,0x90,0xef,0x7e, +0x80,0x4c,0xb7,0xe7,0xb9,0x9f,0x27,0xc3,0x5d,0x4a,0x76,0xfb,0x18,0x32,0xdb,0xa3, +0x43,0x56,0xbb,0x8e,0x7c,0xf6,0x9b,0x78,0xd4,0x96,0xc5,0xee,0x4e,0x06,0xbb,0x96, +0xec,0xf5,0x3c,0x32,0xd7,0xcf,0x93,0xb9,0x36,0x4e,0x4d,0xcb,0xff,0x26,0x9c,0x9a, +0xe1,0x70,0x6a,0x1a,0xf0,0xa8,0xe7,0xe0,0x51,0xdf,0x0a,0xa7,0xc6,0x18,0x35,0x45, +0xb0,0x67,0x8e,0x87,0x39,0x63,0xbc,0x99,0x53,0xe0,0xca,0x8c,0x82,0x27,0x53,0xbb, +0x39,0xc9,0x5f,0x7f,0x04,0x2f,0xc6,0x3c,0x6a,0xcb,0x43,0xaf,0x83,0xbb,0x72,0x46, +0xe0,0xad,0x18,0x67,0x65,0xaa,0xf4,0xd8,0x87,0xfa,0xfb,0x5b,0x93,0x7c,0xf4,0x71, +0x21,0x17,0xdd,0x97,0x2c,0xf4,0xd0,0x2f,0xf0,0xa8,0x6b,0x43,0xce,0xb9,0x23,0x8f, +0xda,0xb3,0xcc,0xd3,0xc9,0x2f,0x5f,0x1d,0x72,0xcb,0xf3,0xc8,0x2a,0xdf,0x47,0x46, +0xd9,0xf2,0xc9,0xdb,0xa5,0x01,0xdb,0xd2,0xa9,0x7f,0x93,0x1e,0x95,0x56,0x4b,0xeb, +0xa4,0x8f,0xa5,0xd2,0xed,0xfa,0xb7,0x49,0x1a,0x88,0x47,0x7d,0x99,0x34,0x43,0x7a, +0x04,0x8f,0xba,0x60,0x87,0xee,0xa3,0x34,0x5e,0x9a,0x28,0x4d,0x93,0xde,0xf8,0x24, +0x9d,0xfa,0x50,0xda,0x2f,0x5d,0xb9,0x3b,0x9d,0xfa,0x1f,0xe9,0x03,0xa9,0xec,0x53, +0x7d,0x1f,0xd2,0x64,0x69,0xae,0xb4,0x4c,0x5a,0x21,0x5d,0xb3,0x47,0x3f,0x1b,0xe9, +0x9c,0xbd,0x69,0x9d,0xf3,0xe8,0xe7,0x21,0x5d,0x2b,0xfd,0x48,0x7a,0x48,0x7a,0x42, +0x7a,0x4e,0xfa,0x83,0xf4,0x93,0x7d,0xe9,0xd4,0xef,0xe0,0xb3,0xbc,0xfd,0x40,0x41, +0xaa,0xfa,0x57,0x49,0xa6,0xfa,0x5e,0xb2,0xd4,0x96,0x9f,0xb6,0xec,0xb4,0x79,0xd4, +0x37,0xa4,0x12,0xfe,0xca,0x81,0x96,0x6e,0x52,0x79,0x2a,0x7d,0x78,0xf7,0xc3,0x3b, +0x77,0x4f,0xeb,0x55,0xa6,0x2c,0xd3,0xa9,0xa0,0x53,0x41,0x61,0x41,0xa6,0x48,0x2f, +0xe9,0xee,0xe9,0x02,0x5d,0xa3,0x77,0x32,0x65,0x85,0x7a,0x53,0x58,0x94,0x69,0xff, +0x92,0xd5,0x2b,0xde,0x2f,0xb2,0x77,0xb2,0xf6,0x3a,0x53,0x96,0x2d,0xf6,0x97,0xe2, +0xd2,0x4c,0x49,0x59,0x49,0x41,0x49,0x26,0x5b,0x52,0x92,0x2d,0x2d,0x2b,0x2d,0xc9, +0xea,0x8d,0xfe,0x90,0x95,0x0a,0x4b,0xec,0x4f,0x7a,0xd1,0xe7,0x65,0x8a,0xc3,0xdf, +0xc9,0x16,0x97,0xd8,0x67,0x67,0x8b,0xda,0xbf,0x24,0x97,0xdc,0x7b,0xd9,0xe4,0xbd, +0x32,0xbd,0x64,0xfd,0x03,0xf6,0x91,0x6c,0xee,0x4f,0x79,0x9f,0x9e,0x7c,0x7e,0x36, +0x7e,0x2e,0x9f,0xd1,0xfa,0xd9,0x6d,0x97,0x2c,0xd2,0xb7,0xed,0x1f,0xc8,0x7d,0xdd, +0xdc,0xb5,0x99,0xd6,0x6b,0x5a,0x95,0x0d,0x77,0xa9,0xf5,0x2b,0x65,0xb9,0x25,0xbd, +0x2d,0x6b,0x7f,0xc7,0x8b,0xda,0xee,0x5f,0x36,0xd3,0xfa,0x5e,0x36,0x5e,0xdd,0xe1, +0x77,0x5d,0xd4,0xfe,0x2e,0xe6,0x8e,0x7a,0xe7,0xdc,0x51,0x8f,0x37,0x9e,0xbc,0xd8, +0x4d,0x66,0x32,0xd9,0x74,0xb8,0xcd,0xe4,0xe3,0x99,0xdc,0x4f,0x29,0xf7,0x5d,0xb4, +0xde,0x2c,0x77,0x35,0x1b,0x6e,0xb0,0x83,0xfb,0x90,0xf5,0x23,0x1e,0xaf,0x8b,0xf7, +0x2d,0x93,0xdc,0x25,0xde,0x76,0x4e,0x17,0x15,0x67,0x3a,0x77,0xef,0x51,0xde,0xad, +0x6b,0x97,0x82,0xb2,0x4c,0x81,0xae,0x38,0xec,0x90,0xaf,0x1d,0x9a,0x2e,0x2c,0x2a, +0xec,0x94,0xc9,0xa9,0x2c,0x9b,0xc9,0x7f,0x2c,0xe9,0x7e,0xb7,0xbe,0x9f,0xe9,0x54, +0x96,0xbc,0xf5,0x87,0x5c,0xee,0xae,0xdb,0x1d,0xcf,0xb4,0xfe,0x00,0x38,0x18,0x19, +0xbb,0x74,0xce,0xf0,0xc1,0xdc,0xdb,0xf0,0x80,0xfc,0xfc,0x4b,0xf2,0x4a,0x8f,0xbf, +0xe4,0x30,0x64,0x5a,0x0f,0x62,0xee,0x4f,0xd9,0xdc,0xbd,0xe8,0xe0,0x60,0xe4,0x1d, +0xe3,0xa2,0x0e,0x8f,0x4f,0xdb,0xb1,0xe5,0xa2,0x87,0x72,0xa7,0xe2,0xdc,0xa5,0xa4, +0x24,0xa3,0x07,0x75,0xc6,0x6e,0xb7,0x20,0xf7,0xa2,0x27,0x9a,0x9e,0x29,0xba,0x32, +0xdd,0xfe,0x39,0x97,0xfb,0x7b,0x65,0xba,0x2e,0xd3,0x76,0x6c,0x73,0x77,0x3a,0xf7, +0xe0,0xcb,0x16,0xb6,0xfb,0xee,0x73,0xb7,0xd1,0x76,0xc9,0xe4,0x5e,0xeb,0xd1,0x9a, +0x7b,0x9d,0x7b,0xdf,0xaf,0xcc,0xdd,0x87,0x6c,0x69,0xa9,0x5d,0x53,0x6c,0xcf,0xb9, +0x62,0xbe,0xfd,0x6c,0xfb,0x1f,0x6e,0xfb,0x47,0x5e,0xbb,0x07,0xe1,0xe7,0x9e,0x85, +0x45,0xf1,0x81,0x93,0x7f,0xb0,0xda,0x1d,0x9f,0xcc,0xe7,0x3e,0x14,0x8f,0x52,0xdb, +0xcd,0x1d,0xec,0xf1,0x17,0x9e,0xaa,0x7c,0x91,0x6c,0xb6,0xfd,0xdd,0xf6,0x27,0x6d, +0xde,0x13,0xa5,0xdd,0xfd,0xcd,0xe4,0x1d,0xb9,0x6c,0x51,0xf2,0x1c,0x49,0xfb,0x0f, +0xdf,0x0f,0x7f,0xfe,0xa5,0xed,0xd1,0x53,0xd8,0x76,0xaf,0x92,0x4b,0xeb,0xaf,0xa2, +0xe2,0xe4,0x77,0x97,0xfd,0xea,0xfa,0xb2,0x4b,0x26,0xb9,0x14,0x66,0xc2,0xaf,0xce, +0x83,0x5e,0x0a,0xb9,0x0f,0x69,0xdd,0xcb,0xa2,0x54,0xdb,0x4e,0xdb,0x39,0xcc,0xcd, +0xbe,0xea,0x2e,0x59,0xdf,0x1d,0xeb,0x3b,0x62,0x7d,0x27,0x6c,0xfe,0x0e,0xd8,0xfc, +0xdd,0xaf,0xbe,0xd3,0xd5,0x77,0xb9,0xfa,0x0e,0x57,0xdf,0xd5,0xea,0xbb,0x59,0x7d, +0x27,0xab,0xef,0x62,0xf5,0x1d,0xac,0xbe,0x7b,0xd5,0x77,0xae,0x6e,0x08,0x3b,0x54, +0xbd,0x63,0x31,0x92,0xdd,0xa8,0xb5,0x61,0xe7,0xa9,0xef,0x3a,0xf5,0x79,0x95,0xef, +0x26,0x5d,0xd5,0xc1,0x2e,0xd2,0xb5,0x61,0xf7,0xa8,0xef,0x1a,0xfd,0x2c,0xaf,0x2f, +0x11,0x77,0x82,0x7e,0xd1,0x2e,0x50,0xdf,0xf9,0x19,0x77,0x7d,0xce,0x09,0x3b,0x3b, +0x57,0x85,0x1d,0x9d,0xb1,0x03,0xe1,0x3b,0x38,0xf7,0xe6,0xcd,0x94,0x46,0x86,0xf9, +0x51,0xfe,0x6e,0xcc,0xd8,0x6f,0xf0,0xdd,0x97,0xbe,0xeb,0x72,0x55,0x07,0xbb,0x28, +0xd7,0x86,0xdd,0x93,0x29,0x66,0x3f,0xa3,0xbf,0x64,0x57,0xa4,0xef,0x84,0xbc,0x91, +0xdd,0x8f,0xbe,0xd3,0x71,0x55,0xd8,0xdd,0xe8,0x3b,0x1b,0xe3,0xae,0x46,0xdf,0xcd, +0x98,0x62,0xf7,0xa2,0xef,0x58,0x1c,0xdd,0xc1,0x4e,0xc5,0x09,0x61,0x77,0xa2,0xef, +0x4c,0xf4,0x99,0x4e,0xdc,0x79,0xd8,0xd1,0xae,0x43,0xdf,0x71,0xe8,0xbb,0x0d,0x7d, +0xa7,0xa1,0xef,0x30,0xf4,0x5d,0x84,0xbe,0x83,0xf0,0x45,0xe6,0x34,0xbe,0x53,0xf0, +0xcb,0x76,0x09,0x7e,0x2f,0x6f,0x57,0xe0,0xc1,0x76,0x04,0x0e,0x60,0xf6,0x32,0x89, +0xd9,0x8b,0xef,0xee,0xf3,0x9d,0x7d,0xbe,0xab,0xcf,0x77,0xf4,0xcd,0x66,0xf6,0xe2, +0x3b,0xf7,0xee,0x66,0x06,0xe3,0x3b,0xeb,0x7c,0xb7,0xdc,0x20,0x66,0x21,0xbe,0x3b, +0xce,0x77,0xc5,0x3d,0xc6,0xac,0xc3,0x77,0xbc,0xf9,0x6e,0x37,0x67,0x01,0xf9,0x8e, +0xb6,0x5e,0x61,0xe7,0x9a,0xcd,0x2c,0x7a,0x84,0x59,0x84,0xcf,0x20,0xe2,0xee,0xb2, +0x26,0x66,0x0d,0x31,0x0f,0x3f,0x36,0x6f,0x77,0xd8,0x6c,0x66,0x0a,0xcb,0x98,0x1f, +0xd8,0x9c,0xa0,0x0f,0xf3,0x81,0xb8,0x53,0x6b,0x4b,0xd8,0x9d,0xb5,0x2b,0x6f,0x16, +0xd0,0xcc,0x1c,0x60,0x1f,0xb3,0x80,0xf5,0xf8,0xe3,0xbe,0x5b,0xc9,0x77,0x25,0xf9, +0x8e,0xa3,0x93,0xf1,0x7b,0x7d,0x27,0xd1,0x0c,0x3c,0x55,0xdf,0xe9,0xe3,0xbb,0x7b, +0x7c,0x57,0x8f,0xef,0xce,0xf1,0x9d,0x39,0xbe,0x2b,0xa7,0x77,0xde,0x4e,0x1c,0xdf, +0x85,0xf3,0x18,0x5e,0xa9,0xef,0xbc,0xf1,0xdd,0x36,0xbe,0xcb,0xe6,0x2c,0x7c,0xd2, +0x98,0xe3,0x6d,0x0e,0x3b,0x66,0xfa,0xe3,0x7d,0xfa,0x4e,0x18,0xf7,0x3d,0xaf,0x0b, +0x99,0xdc,0xa6,0xb0,0xbb,0xc5,0x77,0xb6,0xf8,0xae,0x16,0xdf,0xd1,0xf2,0x01,0x3b, +0x57,0xdc,0xef,0x7c,0x2f,0xec,0x38,0x31,0x2f,0xd3,0x77,0x92,0xe4,0xef,0x0e,0xf1, +0x5d,0x1b,0xbe,0x5b,0xc3,0x77,0x65,0x1c,0x6c,0xb7,0x43,0xfe,0x0e,0x07,0xdf,0xd1, +0xe0,0x3b,0x16,0x7c,0x27,0x82,0xef,0x34,0x48,0x85,0x4c,0xe5,0x99,0x21,0x4b,0xd9, +0x84,0x47,0xe5,0x3b,0x03,0xfa,0xe2,0x47,0xf9,0x2e,0x00,0x67,0xff,0x7b,0x66,0x72, +0x25,0x4c,0xff,0xdf,0xe6,0x79,0x52,0xa7,0xe4,0x31,0xf7,0x37,0xe2,0x2d,0xa5,0xf0, +0x95,0x9c,0x71,0x3f,0xfa,0x20,0x2c,0x7b,0x67,0xd8,0x1f,0x8c,0x5d,0x3f,0x18,0x0f, +0xc9,0x59,0xef,0x4d,0x78,0x44,0xcb,0x03,0x7b,0xbd,0x39,0xb0,0xd5,0x2b,0xf1,0x80, +0x1e,0xc6,0xdf,0x39,0x16,0x1f,0xe7,0x14,0xbc,0x9b,0x8e,0x58,0xe1,0xa3,0x03,0x13, +0xdc,0xfd,0x9a,0x57,0x02,0xe3,0x7b,0x53,0x60,0x78,0x3b,0xbb,0x3b,0x66,0x07,0x23, +0xa3,0x7b,0x22,0x9e,0xcc,0x7c,0xbc,0x98,0x8a,0xc0,0xc2,0x1e,0x93,0xc7,0xb8,0x36, +0xaf,0xe5,0xcb,0x18,0xd5,0xce,0xa6,0xee,0x88,0x3d,0x6d,0x1e,0xcb,0x4e,0x18,0xd1, +0xce,0x42,0x76,0x06,0xb2,0x33,0x8a,0xf3,0xd9,0xc4,0xf9,0x0c,0x62,0x67,0xfe,0x4e, +0xfb,0x7b,0x99,0xbe,0x7f,0x2f,0xdb,0xf6,0xab,0xb2,0x6b,0xf1,0x12,0x9c,0x39,0xeb, +0xac,0x56,0x67,0xb4,0x3a,0x43,0xf4,0xff,0x01, +}; +} // namespace ada::idna::table_blob +#endif +/* end file src/table_blob.inc */ + +#include +#include +#include +#include +#include + +namespace ada::idna { + +// table_blob.inc is packed little-endian (see scripts/pack_tables.py). After +// inflate the multi-byte sections must be converted to host endianness so +// big-endian platforms (s390x) can load uint16_t/uint32_t/uint64_t natively. +// CRC is checked on the raw little-endian payload before any conversion. +namespace detail { + +template +inline void bswap_inplace(T* data, size_t count) noexcept { + if constexpr (std::endian::native == std::endian::little) { + (void)data; + (void)count; + return; + } + for (size_t i = 0; i < count; ++i) { + if constexpr (sizeof(T) == 2) { +#if defined(__GNUC__) || defined(__clang__) + data[i] = + static_cast(__builtin_bswap16(static_cast(data[i]))); +#else + const auto v = static_cast(data[i]); + data[i] = static_cast(static_cast((v >> 8) | (v << 8))); +#endif + } else if constexpr (sizeof(T) == 4) { +#if defined(__GNUC__) || defined(__clang__) + data[i] = + static_cast(__builtin_bswap32(static_cast(data[i]))); +#else + auto v = static_cast(data[i]); + v = ((v & 0x000000FFu) << 24) | ((v & 0x0000FF00u) << 8) | + ((v & 0x00FF0000u) >> 8) | ((v & 0xFF000000u) >> 24); + data[i] = static_cast(v); +#endif + } else if constexpr (sizeof(T) == 8) { +#if defined(__GNUC__) || defined(__clang__) + data[i] = + static_cast(__builtin_bswap64(static_cast(data[i]))); +#else + auto v = static_cast(data[i]); + v = ((v & 0x00000000000000FFull) << 56) | + ((v & 0x000000000000FF00ull) << 40) | + ((v & 0x0000000000FF0000ull) << 24) | + ((v & 0x00000000FF000000ull) << 8) | + ((v & 0x000000FF00000000ull) >> 8) | + ((v & 0x0000FF0000000000ull) >> 24) | + ((v & 0x00FF000000000000ull) >> 40) | + ((v & 0xFF00000000000000ull) >> 56); + data[i] = static_cast(v); +#endif + } else { + static_assert(sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8); + } + } +} + +// Convert every multi-byte section of the inflated little-endian blob to host +// order. Single-byte sections are left unchanged. Safe no-op on little-endian. +inline void convert_table_blob_to_host_endian(uint8_t* buffer) noexcept { + if constexpr (std::endian::native == std::endian::little) { + (void)buffer; + return; + } + auto u16 = [&](size_t off, size_t count) { + bswap_inplace(reinterpret_cast(buffer + off), count); + }; + auto u32 = [&](size_t off, size_t count) { + bswap_inplace(reinterpret_cast(buffer + off), count); + }; + auto u64 = [&](size_t off, size_t count) { + bswap_inplace(reinterpret_cast(buffer + off), count); + }; + + u16(table_blob::off_idna_stage1, table_blob::count_idna_stage1); + u16(table_blob::off_idna_stage2, table_blob::count_idna_stage2); + u64(table_blob::off_idna_bool_blocks, table_blob::count_idna_bool_blocks); + u16(table_blob::off_decomposition_block, + table_blob::count_decomposition_block); + u32(table_blob::off_decomposition_data, table_blob::count_decomposition_data); + u16(table_blob::off_composition_block, table_blob::count_composition_block); + u32(table_blob::off_composition_data, table_blob::count_composition_data); + u32(table_blob::off_id_continue_flat, table_blob::count_id_continue_flat); + u32(table_blob::off_id_start_flat, table_blob::count_id_start_flat); + u32(table_blob::off_dir_start, table_blob::count_dir_start); + u32(table_blob::off_dir_final, table_blob::count_dir_final); + u32(table_blob::off_combining_flat, table_blob::count_combining_flat); +} + +} // namespace detail + +// --- Blob layout invariants -------------------------------------------------- +static_assert(table_blob::count_decomposition_index == 4352); +static_assert(table_blob::count_ccc_index == 4352); +static_assert(table_blob::count_composition_index == 4352); +static_assert(table_blob::count_decomposition_block == + table_blob::decomposition_block_rows * + table_blob::decomposition_block_cols); +static_assert(table_blob::count_ccc_block == + table_blob::ccc_block_rows * table_blob::ccc_block_cols); +static_assert(table_blob::count_composition_block == + table_blob::composition_block_rows * + table_blob::composition_block_cols); +static_assert(table_blob::count_dir_start == table_blob::dir_table_count && + table_blob::count_dir_final == table_blob::dir_table_count && + table_blob::count_dir_value == table_blob::dir_table_count); +static_assert(table_blob::count_id_continue_flat == + table_blob::id_continue_count * 2); +static_assert(table_blob::count_id_start_flat == + table_blob::id_start_count * 2); +static_assert(table_blob::count_combining_flat == + table_blob::combining_range_count * 2); +static_assert(table_blob::off_idna_stage1 % alignof(uint16_t) == 0); +static_assert(table_blob::off_idna_stage2 % alignof(uint16_t) == 0); +static_assert(table_blob::off_idna_bool_blocks % alignof(uint64_t) == 0); +static_assert(table_blob::off_decomposition_block % alignof(uint16_t) == 0); +static_assert(table_blob::off_decomposition_data % alignof(char32_t) == 0); +static_assert(table_blob::off_composition_block % alignof(uint16_t) == 0); +static_assert(table_blob::off_composition_data % alignof(char32_t) == 0); +static_assert(table_blob::off_id_continue_flat % alignof(uint32_t) == 0); +static_assert(table_blob::off_id_start_flat % alignof(uint32_t) == 0); +static_assert(table_blob::off_dir_start % alignof(uint32_t) == 0); +static_assert(table_blob::off_dir_final % alignof(uint32_t) == 0); +static_assert(table_blob::off_combining_flat % alignof(uint32_t) == 0); +static_assert(table_blob::compressed_size == sizeof(table_blob::compressed)); + +// Every section must lie entirely inside the uncompressed buffer. +#define ADA_IDNA_SECTION_IN_BOUNDS(off, count, width) \ + static_assert((off) + (count) * (width) <= table_blob::uncompressed_size, \ + #off " overflows uncompressed buffer") +ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_idna_stage1, + table_blob::count_idna_stage1, 2); +ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_idna_stage2, + table_blob::count_idna_stage2, 2); +ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_idna_bool_blocks, + table_blob::count_idna_bool_blocks, 8); +ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_idna_utf8_mappings, + table_blob::count_idna_utf8_mappings, 1); +ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_decomposition_index, + table_blob::count_decomposition_index, 1); +ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_decomposition_block, + table_blob::count_decomposition_block, 2); +ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_decomposition_data, + table_blob::count_decomposition_data, 4); +ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_ccc_index, + table_blob::count_ccc_index, 1); +ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_ccc_block, + table_blob::count_ccc_block, 1); +ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_composition_index, + table_blob::count_composition_index, 1); +ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_composition_block, + table_blob::count_composition_block, 2); +ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_composition_data, + table_blob::count_composition_data, 4); +ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_id_continue_flat, + table_blob::count_id_continue_flat, 4); +ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_id_start_flat, + table_blob::count_id_start_flat, 4); +ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_dir_start, + table_blob::count_dir_start, 4); +ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_dir_final, + table_blob::count_dir_final, 4); +ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_dir_value, + table_blob::count_dir_value, 1); +ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_combining_flat, + table_blob::count_combining_flat, 4); +#undef ADA_IDNA_SECTION_IN_BOUNDS + +// --- Mapping ----------------------------------------------------------------- +inline const uint16_t* idna_stage1 = nullptr; +inline const uint16_t* idna_stage2 = nullptr; +inline const uint64_t* idna_bool_blocks = nullptr; +inline const uint8_t* idna_utf8_mappings = nullptr; + +// --- Normalization (O(1) multi-stage) ---------------------------------------- +inline const uint8_t* decomposition_index = nullptr; +inline const uint16_t* decomposition_block_flat = nullptr; +inline const char32_t* decomposition_data = nullptr; +inline const uint8_t* ccc_index = nullptr; +inline const uint8_t* ccc_block_flat = nullptr; +inline const uint8_t* composition_index = nullptr; +inline const uint16_t* composition_block_flat = nullptr; +inline const char32_t* composition_data = nullptr; + +// --- Identifier -------------------------------------------------------------- +// Pointer-to-array alias. CF17 vs CF22 disagree on spacing inside (*)[2]. +// clang-format off +using range_pair_ptr = const uint32_t(*)[2]; +// clang-format on +inline range_pair_ptr id_continue = nullptr; +inline range_pair_ptr id_start = nullptr; + +// --- Validity (const SoA) ---------------------------------------------------- +inline const uint32_t* dir_start = nullptr; +inline const uint32_t* dir_final = nullptr; +inline const uint8_t* dir_value = nullptr; +inline range_pair_ptr combining_ranges = nullptr; + +inline constexpr size_t id_continue_count = table_blob::id_continue_count; +inline constexpr size_t id_start_count = table_blob::id_start_count; +inline constexpr size_t dir_table_count = table_blob::dir_table_count; +inline constexpr size_t combining_range_count = + table_blob::combining_range_count; +inline constexpr size_t idna_utf8_mappings_size = + table_blob::count_idna_utf8_mappings; +inline constexpr size_t decomposition_data_size = + table_blob::count_decomposition_data; +inline constexpr size_t composition_data_size = + table_blob::count_composition_data; + +inline constexpr size_t kDecompBlockCols = + table_blob::decomposition_block_cols; // 257 +inline constexpr size_t kCccBlockCols = table_blob::ccc_block_cols; // 256 +inline constexpr size_t kCompBlockCols = + table_blob::composition_block_cols; // 257 +inline constexpr size_t kDecompBlockRows = table_blob::decomposition_block_rows; +inline constexpr size_t kCccBlockRows = table_blob::ccc_block_rows; +inline constexpr size_t kCompBlockRows = table_blob::composition_block_rows; + +// Init state: 0=uninit, 1=in progress, 2=ready, 3=failed. +inline constexpr uint8_t kTablesUninit = 0; +inline constexpr uint8_t kTablesInProgress = 1; +inline constexpr uint8_t kTablesReady = 2; +inline constexpr uint8_t kTablesFailed = 3; + +inline std::atomic tables_init_state{kTablesUninit}; +// Process-lifetime allocation published only by the winning init thread. +// Never freed: shared read-only data for the process. Do not dlclose a DSO +// that owns this buffer while other code may still call into ada::idna. +inline uint8_t* tables_buffer = nullptr; + +// Cap spin-wait so a stuck peer cannot hang the process forever. +inline constexpr uint64_t kTablesSpinLimit = 1'000'000'000ull; + +// ISO HDLC / zlib CRC-32 of the uncompressed table payload. +[[nodiscard]] inline uint32_t crc32_ieee(const uint8_t* data, + size_t len) noexcept { + uint32_t c = 0xFFFFFFFFu; + for (size_t i = 0; i < len; ++i) { + c ^= data[i]; + for (int k = 0; k < 8; ++k) { + const uint32_t mask = 0u - (c & 1u); + c = (c >> 1) ^ (0xEDB88320u & mask); + } + } + return ~c; +} + +[[nodiscard]] inline bool tables_are_ready() noexcept { + return tables_init_state.load(std::memory_order_acquire) == kTablesReady; +} + +// Returns true only when all table pointers are safe to use. +[[nodiscard]] inline bool ensure_tables() noexcept { + uint8_t state = tables_init_state.load(std::memory_order_acquire); + if (state == kTablesReady) { + return true; + } + if (state == kTablesFailed) { + return false; + } + + uint8_t expected = kTablesUninit; + if (tables_init_state.compare_exchange_strong(expected, kTablesInProgress, + std::memory_order_acq_rel, + std::memory_order_acquire)) { + uint8_t* buffer = new (std::nothrow) uint8_t[table_blob::uncompressed_size]; + if (buffer == nullptr) { + tables_init_state.store(kTablesFailed, std::memory_order_release); + return false; + } + + const size_t n = deflate::inflate_raw(table_blob::compressed, + table_blob::compressed_size, buffer, + table_blob::uncompressed_size); + if (n != table_blob::uncompressed_size || + crc32_ieee(buffer, n) != table_blob::uncompressed_crc32) { + delete[] buffer; + tables_init_state.store(kTablesFailed, std::memory_order_release); + return false; + } + + // LE payload verified; convert multi-byte fields for big-endian hosts. + detail::convert_table_blob_to_host_endian(buffer); + + auto at = [&](size_t off) noexcept -> const uint8_t* { + return buffer + off; + }; + + // Publish all non-atomic pointers before READY. Waiters synchronize via + // acquire on tables_init_state and then observe these writes. + idna_stage1 = + reinterpret_cast(at(table_blob::off_idna_stage1)); + idna_stage2 = + reinterpret_cast(at(table_blob::off_idna_stage2)); + idna_bool_blocks = + reinterpret_cast(at(table_blob::off_idna_bool_blocks)); + idna_utf8_mappings = at(table_blob::off_idna_utf8_mappings); + + decomposition_index = at(table_blob::off_decomposition_index); + decomposition_block_flat = reinterpret_cast( + at(table_blob::off_decomposition_block)); + decomposition_data = reinterpret_cast( + at(table_blob::off_decomposition_data)); + ccc_index = at(table_blob::off_ccc_index); + ccc_block_flat = at(table_blob::off_ccc_block); + composition_index = at(table_blob::off_composition_index); + composition_block_flat = reinterpret_cast( + at(table_blob::off_composition_block)); + composition_data = + reinterpret_cast(at(table_blob::off_composition_data)); + + id_continue = + reinterpret_cast(at(table_blob::off_id_continue_flat)); + id_start = + reinterpret_cast(at(table_blob::off_id_start_flat)); + + dir_start = + reinterpret_cast(at(table_blob::off_dir_start)); + dir_final = + reinterpret_cast(at(table_blob::off_dir_final)); + dir_value = at(table_blob::off_dir_value); + combining_ranges = + reinterpret_cast(at(table_blob::off_combining_flat)); + + tables_buffer = buffer; + tables_init_state.store(kTablesReady, std::memory_order_release); + return true; + } + + // Another thread owns init (or finished between our loads). + for (uint64_t spins = 0; spins < kTablesSpinLimit; ++spins) { + state = tables_init_state.load(std::memory_order_acquire); + if (state == kTablesReady) { + return true; + } + if (state == kTablesFailed) { + return false; + } +#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || \ + defined(_M_IX86) +#if defined(__GNUC__) || defined(__clang__) + __builtin_ia32_pause(); +#endif +#elif defined(__aarch64__) || defined(_M_ARM64) +#if defined(__GNUC__) || defined(__clang__) + asm volatile("yield" ::: "memory"); +#endif +#endif + } + // Timed out waiting for a peer - treat as failure rather than hang. + return false; +} + +// O(1) multi-stage accessors. Block indices from the tables are uint8_t and +// theoretically can be out of range if the blob is corrupt; clamp to a valid +// empty/default row (index 0) instead of reading OOB. +inline const uint16_t* decomposition_block_row(uint8_t bi) noexcept { + if (bi >= kDecompBlockRows) { + bi = 0; + } + return decomposition_block_flat + static_cast(bi) * kDecompBlockCols; +} + +inline const uint8_t* ccc_block_row(uint8_t bi) noexcept { + if (bi >= kCccBlockRows) { + bi = 0; + } + return ccc_block_flat + static_cast(bi) * kCccBlockCols; +} + +inline const uint16_t* composition_block_row(uint8_t bi) noexcept { + if (bi >= kCompBlockRows) { + bi = 0; + } + return composition_block_flat + static_cast(bi) * kCompBlockCols; +} + +} // namespace ada::idna +/* end file src/table_store.hpp */ +/* begin file src/mapping_tables.cpp */ +// IDNA 17.0.0 +// Two-level compressed mapping table. +// All constants are derived from the table data; no hardcoded boundaries. +// Total binary size: 48659 bytes (47.5 KB) +// stage1: 6564 bytes (3282 uint16_t entries) +// stage2: 22912 bytes (179 mixed blocks x 64) +// bool_blocks: 1800 bytes (225 uint64_t words) +// utf8 maps: 17383 bytes + +// clang-format off +#ifndef ADA_IDNA_MAPPING_TABLE_H +#define ADA_IDNA_MAPPING_TABLE_H +#include + +namespace ada::idna { + +// Block size for two-level table (2^6 = 64 code points per block). +constexpr uint32_t IDNA_BLOCK_BITS = 6u; +constexpr uint32_t IDNA_BLOCK_SIZE = 64u; +constexpr uint32_t IDNA_BLOCK_MASK = 63u; + +// Sentinel values stored in stage2 / returned by lookup. +constexpr uint16_t IDNA_VALID = 0xFFFF; // code point is valid as-is +constexpr uint16_t IDNA_DISALLOWED = 0xFFFE; // code point is disallowed +constexpr uint16_t IDNA_IGNORED = 0x0000; // ignored (index into empty UTF-8 entry) + +// Bit 15 of a stage1 entry: set = boolean block, clear = mixed block. +constexpr uint16_t IDNA_BOOL_FLAG = 0x8000; + +// Two-level table covers code points [0, IDNA_LOW_RANGE_END). +// Derived from the highest non-disallowed code point below the high-ignored range, +// rounded up to the next 64-code-point block boundary. +constexpr uint32_t IDNA_LOW_RANGE_END = 0x00033480; + +// Variation selectors supplement: U+E0100..U+E01EF are all ignored. +// These are handled with a simple range check; everything else above +// IDNA_LOW_RANGE_END is disallowed. +constexpr uint32_t IDNA_HIGH_IGNORED_START = 0x000E0100; +constexpr uint32_t IDNA_HIGH_IGNORED_END = 0x000E01F0; // exclusive + +// idna_stage1[cp >> 6]: one entry per 64-code-point block. +// Bit 15 set -> lower 15 bits = index into idna_bool_blocks[]. +// Bit 15 clear -> value = base offset into idna_stage2[] for this block. + +} // namespace ada::idna +#endif // ADA_IDNA_MAPPING_TABLE_H +/* end file src/mapping_tables.cpp */ + +namespace ada::idna { + +// --- O(1) two-level table lookup --------------------------------------------- +// +// Returns one of: +// IDNA_VALID - keep code point in output unchanged +// IDNA_DISALLOWED - code point is not allowed (map() returns error) +// IDNA_IGNORED - code point is ignored (index 0 = empty UTF-8 entry) +// other - byte offset into idna_utf8_mappings[] (null-terminated) +// +// Assumes ensure_tables() has already been called by the public entry point. +static uint16_t idna_lookup(uint32_t cp) noexcept { + if (cp < IDNA_LOW_RANGE_END) { + uint16_t ref = idna_stage1[cp >> IDNA_BLOCK_BITS]; + if (ref & IDNA_BOOL_FLAG) { + uint32_t bit_idx = + static_cast(ref & ~IDNA_BOOL_FLAG) * IDNA_BLOCK_SIZE + + (cp & IDNA_BLOCK_MASK); + bool is_valid = (idna_bool_blocks[bit_idx >> 6] >> (bit_idx & 63u)) & 1u; + return is_valid ? IDNA_VALID : IDNA_DISALLOWED; + } + return idna_stage2[ref + (cp & IDNA_BLOCK_MASK)]; + } + + if (cp >= IDNA_HIGH_IGNORED_START && cp < IDNA_HIGH_IGNORED_END) { + return IDNA_IGNORED; + } + + return IDNA_DISALLOWED; +} + +// Advances *ptr past one well-formed UTF-8 code point from the mapping table. +static char32_t utf8_next(const uint8_t*& ptr) noexcept { + uint8_t b0 = *ptr++; + if (b0 < 0x80u) return static_cast(b0); + if (b0 < 0xE0u) { + uint32_t cp = (b0 & 0x1Fu) << 6; + cp |= (*ptr++ & 0x3Fu); + return static_cast(cp); + } + if (b0 < 0xF0u) { + uint32_t cp = (b0 & 0x0Fu) << 12; + cp |= ((*ptr++ & 0x3Fu) << 6); + cp |= (*ptr++ & 0x3Fu); + return static_cast(cp); + } + uint32_t cp = (b0 & 0x07u) << 18; + cp |= ((*ptr++ & 0x3Fu) << 12); + cp |= ((*ptr++ & 0x3Fu) << 6); + cp |= (*ptr++ & 0x3Fu); + return static_cast(cp); +} + +// Count UTF-8 code points in a null-terminated mapping string (trusted table). +static size_t utf8_count_codepoints(const uint8_t* ptr) noexcept { + size_t n = 0; + while (*ptr != 0) { + ++n; + if (*ptr < 0x80u) { + ++ptr; + } else if (*ptr < 0xE0u) { + ptr += 2; + } else if (*ptr < 0xF0u) { + ptr += 3; + } else { + ptr += 4; + } + } + return n; +} + +// --- ASCII fast path --------------------------------------------------------- +void ascii_map(char* input, size_t length) { + auto broadcast = [](uint8_t v) -> uint64_t { + return 0x101010101010101ull * v; + }; + uint64_t broadcast_80 = broadcast(0x80); + uint64_t broadcast_Ap = broadcast(128 - 'A'); + uint64_t broadcast_Zp = broadcast(128 - 'Z' - 1); + size_t i = 0; + + for (; i + 7 < length; i += 8) { + uint64_t word{}; + std::memcpy(&word, input + i, sizeof(word)); + word ^= + (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2; + std::memcpy(input + i, &word, sizeof(word)); + } + if (i < length) { + uint64_t word{}; + std::memcpy(&word, input + i, length - i); + word ^= + (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2; + std::memcpy(input + i, &word, length - i); + } +} + +// Two-pass map: first validate + exact size, then write once (no growth +// realloc). +bool map(std::u32string_view input, std::u32string& out) { + // [Map](https://www.unicode.org/reports/tr46/#ProcessingStepMap). + out.clear(); + if (!ensure_tables()) { + return false; + } + + // Pass 1: validate and compute exact output length. + size_t out_size = 0; + for (char32_t x : input) { + uint16_t status = idna_lookup(static_cast(x)); + if (status == IDNA_DISALLOWED) { + return false; + } + if (status == IDNA_VALID) { + ++out_size; + continue; + } + if (static_cast(status) >= idna_utf8_mappings_size) { + return false; + } + out_size += utf8_count_codepoints(idna_utf8_mappings + status); + } + + // Pass 2: write into a single allocation. + out.resize(out_size); + size_t w = 0; + for (char32_t x : input) { + uint16_t status = idna_lookup(static_cast(x)); + if (status == IDNA_VALID) { + out[w++] = x; + continue; + } + // IGNORED or mapped (status already validated in pass 1). + const uint8_t* ptr = idna_utf8_mappings + status; + while (*ptr != 0) { + out[w++] = utf8_next(ptr); + } + } + return true; +} + +std::u32string map(std::u32string_view input) { + std::u32string answer; + if (!map(input, answer)) { + return {}; + } + return answer; +} + +} // namespace ada::idna +/* end file src/mapping.cpp */ +/* begin file src/normalization.cpp */ +/* begin file include/ada/idna/normalization.h */ +#ifndef ADA_IDNA_NORMALIZATION_H +#define ADA_IDNA_NORMALIZATION_H + +#include +#include + +namespace ada::idna { + +// Returns true if `input` is already in Unicode Normalization Form C. +// Requires that internal tables have been loaded (call ensure via normalize +// or map first, or this returns false if tables are unavailable). +[[nodiscard]] bool is_already_nfc(std::u32string_view input) noexcept; + +// Normalize the characters according to IDNA (Unicode Normalization Form C). +// Returns false if the internal Unicode tables could not be loaded; in that +// case `input` is left unchanged. Skips work when the string is already NFC. +[[nodiscard]] bool normalize(std::u32string& input); + +} // namespace ada::idna +#endif +/* end file include/ada/idna/normalization.h */ +/* begin file src/normalization_tables.cpp */ +// Normalization table helpers. +// Array payloads live in the DEFLATE blob (table_store.hpp). +// clang-format off +#ifndef ADA_IDNA_NORMALIZATION_TABLES_H +#define ADA_IDNA_NORMALIZATION_TABLES_H + +namespace ada::idna { + +// Accessors and multi-stage tables are provided by table_store.hpp after +// ensure_tables(). Lookup code matches the classic O(1) uni-algo layout. + +} // namespace ada::idna +#endif // ADA_IDNA_NORMALIZATION_TABLES_H +/* end file src/normalization_tables.cpp */ + +#include + +namespace ada::idna { + +// See +// https://github.com/uni-algo/uni-algo/blob/c612968c5ed3ace39bde4c894c24286c5f2c7fe2/include/uni_algo/impl/impl_norm.h#L467 +constexpr char32_t hangul_sbase = 0xAC00; +constexpr char32_t hangul_tbase = 0x11A7; +constexpr char32_t hangul_vbase = 0x1161; +constexpr char32_t hangul_lbase = 0x1100; +constexpr char32_t hangul_lcount = 19; +constexpr char32_t hangul_vcount = 21; +constexpr char32_t hangul_tcount = 28; +constexpr char32_t hangul_ncount = hangul_vcount * hangul_tcount; +constexpr char32_t hangul_scount = + hangul_lcount * hangul_vcount * hangul_tcount; + +// Canonical decomposition length (0 if none / compatibility-only / Hangul +// syllable). Length 1 means a singleton mapping (character is not NFC form). +// Length >= 2 means a primary composite that is already the NFC form of its +// decomposition (e.g. U+00E9 LATIN SMALL LETTER E WITH ACUTE). +static size_t canonical_decomp_length(char32_t current_character) noexcept { + if (current_character >= hangul_sbase && + current_character < hangul_sbase + hangul_scount) { + // Hangul precomposed syllables are NFC. + return 0; + } + if (current_character >= 0x110000) { + return 0; + } + const uint8_t di = decomposition_index[current_character >> 8]; + const uint16_t* const decomposition = + decomposition_block_row(di) + (current_character % 256); + size_t decomposition_length = + (decomposition[1] >> 2) - (decomposition[0] >> 2); + if ((decomposition_length > 0) && (decomposition[0] & 1)) { + decomposition_length = 0; // compatibility-only: ignored for NFC + } + return decomposition_length; +} + +std::pair compute_decomposition_length( + const std::u32string_view input) noexcept { + bool decomposition_needed{false}; + size_t additional_elements{0}; + for (char32_t current_character : input) { + size_t decomposition_length{0}; + + if (current_character >= hangul_sbase && + current_character < hangul_sbase + hangul_scount) { + // Full NFD-style Hangul decomp for the decompose() step. + decomposition_length = 2; + if ((current_character - hangul_sbase) % hangul_tcount) { + decomposition_length = 3; + } + } else if (current_character < 0x110000) { + const uint8_t di = decomposition_index[current_character >> 8]; + const uint16_t* const decomposition = + decomposition_block_row(di) + (current_character % 256); + decomposition_length = (decomposition[1] >> 2) - (decomposition[0] >> 2); + if ((decomposition_length > 0) && (decomposition[0] & 1)) { + decomposition_length = 0; + } + } + if (decomposition_length != 0) { + decomposition_needed = true; + additional_elements += decomposition_length - 1; + } + } + return {decomposition_needed, additional_elements}; +} + +void decompose(std::u32string& input, size_t additional_elements) { + input.resize(input.size() + additional_elements); + for (size_t descending_idx = input.size(), + input_count = descending_idx - additional_elements; + input_count--;) { + if (input[input_count] >= hangul_sbase && + input[input_count] < hangul_sbase + hangul_scount) { + // Hangul decomposition. + char32_t s_index = input[input_count] - hangul_sbase; + if (s_index % hangul_tcount != 0) { + input[--descending_idx] = hangul_tbase + s_index % hangul_tcount; + } + input[--descending_idx] = + hangul_vbase + (s_index % hangul_ncount) / hangul_tcount; + input[--descending_idx] = hangul_lbase + s_index / hangul_ncount; + } else if (input[input_count] < 0x110000) { + const uint16_t* decomposition = + decomposition_block_row( + decomposition_index[input[input_count] >> 8]) + + (input[input_count] % 256); + uint16_t decomposition_length = + (decomposition[1] >> 2) - (decomposition[0] >> 2); + if (decomposition_length > 0 && (decomposition[0] & 1)) { + decomposition_length = 0; + } + if (decomposition_length > 0) { + const size_t base = static_cast(decomposition[0] >> 2); + if (base + decomposition_length > decomposition_data_size) { + input[--descending_idx] = input[input_count]; + } else { + while (decomposition_length-- > 0) { + input[--descending_idx] = + decomposition_data[base + decomposition_length]; + } + } + } else { + input[--descending_idx] = input[input_count]; + } + } else { + input[--descending_idx] = input[input_count]; + } + } +} + +uint8_t get_ccc(char32_t c) noexcept { + if (c >= 0x110000) { + return 0; + } + return ccc_block_row(ccc_index[c >> 8])[c % 256]; +} + +void sort_marks(std::u32string& input) { + for (size_t idx = 1; idx < input.size(); idx++) { + uint8_t ccc = get_ccc(input[idx]); + if (ccc == 0) { + continue; + } + auto current_character = input[idx]; + size_t back_idx = idx; + while (back_idx != 0 && get_ccc(input[back_idx - 1]) > ccc) { + input[back_idx] = input[back_idx - 1]; + back_idx--; + } + input[back_idx] = current_character; + } +} + +void decompose_nfc(std::u32string& input) { + /** + * Decompose the domain_name string to Unicode Normalization Form C. + * @see https://www.unicode.org/reports/tr46/#ProcessingStepDecompose + */ + auto [decomposition_needed, additional_elements] = + compute_decomposition_length(input); + if (decomposition_needed) { + decompose(input, additional_elements); + } + sort_marks(input); +} + +// Returns true if a composition step would change the string. +static bool would_compose(std::u32string_view input) noexcept { + for (size_t input_count = 0; input_count < input.size();) { + const char32_t current = input[input_count]; + if (current >= hangul_lbase && current < hangul_lbase + hangul_lcount) { + if (input_count + 1 < input.size() && + input[input_count + 1] >= hangul_vbase && + input[input_count + 1] < hangul_vbase + hangul_vcount) { + return true; + } + ++input_count; + continue; + } + if (current >= hangul_sbase && current < hangul_sbase + hangul_scount) { + if ((current - hangul_sbase) % hangul_tcount && + input_count + 1 < input.size() && + input[input_count + 1] > hangul_tbase && + input[input_count + 1] < hangul_tbase + hangul_tcount) { + return true; + } + ++input_count; + continue; + } + if (current < 0x110000) { + const uint16_t* composition = + composition_block_row(composition_index[current >> 8]) + + (current % 256); + int32_t previous_ccc = -1; + size_t j = input_count; + for (; j + 1 < input.size(); ++j) { + uint8_t ccc = get_ccc(input[j + 1]); + if (composition[1] != composition[0] && previous_ccc < ccc) { + int left = composition[0]; + int right = composition[1]; + if (left < 0 || right < left || + static_cast(right) > composition_data_size) { + break; + } + while (left + 2 < right) { + int middle = left + (((right - left) >> 1) & ~1); + if (composition_data[static_cast(middle)] <= input[j + 1]) { + left = middle; + } + if (composition_data[static_cast(middle)] >= input[j + 1]) { + right = middle; + } + } + if (static_cast(left + 1) < composition_data_size && + composition_data[static_cast(left)] == input[j + 1]) { + return true; + } + } + if (ccc == 0) { + break; + } + previous_ccc = ccc; + } + input_count = j + 1; + continue; + } + ++input_count; + } + return false; +} + +bool is_already_nfc(std::u32string_view input) noexcept { + if (input.empty()) { + return true; + } + if (!tables_are_ready() && !ensure_tables()) { + return false; + } + // 1) Singleton decompositions are never NFC (e.g. U+212B ANGSTROM SIGN). + // Multi-code-point decomps are primary composites that are NFC as-is. + for (char32_t c : input) { + if (canonical_decomp_length(c) == 1) { + return false; + } + } + // 2) Combining marks already in canonical order. + uint8_t prev_ccc = 0; + for (char32_t c : input) { + uint8_t ccc = get_ccc(c); + if (ccc != 0 && prev_ccc > ccc) { + return false; + } + prev_ccc = ccc; + } + // 3) No pairwise composition would apply (including Hangul L+V / LV+T). + return !would_compose(input); +} + +void compose(std::u32string& input) { + /** + * Compose the domain_name string to Unicode Normalization Form C. + * @see https://www.unicode.org/reports/tr46/#ProcessingStepCompose + */ + size_t input_count{0}; + size_t composition_count{0}; + for (; input_count < input.size(); input_count++, composition_count++) { + input[composition_count] = input[input_count]; + if (input[input_count] >= hangul_lbase && + input[input_count] < hangul_lbase + hangul_lcount) { + if (input_count + 1 < input.size() && + input[input_count + 1] >= hangul_vbase && + input[input_count + 1] < hangul_vbase + hangul_vcount) { + input[composition_count] = + hangul_sbase + + ((input[input_count] - hangul_lbase) * hangul_vcount + + input[input_count + 1] - hangul_vbase) * + hangul_tcount; + input_count++; + if (input_count + 1 < input.size() && + input[input_count + 1] > hangul_tbase && + input[input_count + 1] < hangul_tbase + hangul_tcount) { + input[composition_count] += input[++input_count] - hangul_tbase; + } + } + } else if (input[input_count] >= hangul_sbase && + input[input_count] < hangul_sbase + hangul_scount) { + if ((input[input_count] - hangul_sbase) % hangul_tcount && + input_count + 1 < input.size() && + input[input_count + 1] > hangul_tbase && + input[input_count + 1] < hangul_tbase + hangul_tcount) { + input[composition_count] += input[++input_count] - hangul_tbase; + } + } else if (input[input_count] < 0x110000) { + const uint16_t* composition = + composition_block_row(composition_index[input[input_count] >> 8]) + + (input[input_count] % 256); + size_t initial_composition_count = composition_count; + for (int32_t previous_ccc = -1; input_count + 1 < input.size(); + input_count++) { + uint8_t ccc = get_ccc(input[input_count + 1]); + + if (composition[1] != composition[0] && previous_ccc < ccc) { + int left = composition[0]; + int right = composition[1]; + if (left < 0 || right < left || + static_cast(right) > composition_data_size) { + break; + } + while (left + 2 < right) { + int middle = left + (((right - left) >> 1) & ~1); + if (composition_data[static_cast(middle)] <= + input[input_count + 1]) { + left = middle; + } + if (composition_data[static_cast(middle)] >= + input[input_count + 1]) { + right = middle; + } + } + if (static_cast(left + 1) < composition_data_size && + composition_data[static_cast(left)] == + input[input_count + 1]) { + char32_t composed = composition_data[static_cast(left + 1)]; + input[initial_composition_count] = composed; + composition = + composition_block_row(composition_index[composed >> 8]) + + (composed % 256); + continue; + } + } + + if (ccc == 0) { + break; + } + previous_ccc = ccc; + input[++composition_count] = input[input_count + 1]; + } + } + } + + if (composition_count < input_count) { + input.resize(composition_count); + } +} + +bool normalize(std::u32string& input) { + /** + * Normalize the characters according to IDNA (Unicode Normalization Form C). + * @see https://www.unicode.org/reports/tr46/#ProcessingStepNormalize + */ + if (!ensure_tables() || decomposition_index == nullptr || + composition_index == nullptr) { + return false; + } + if (is_already_nfc(input)) { + return true; + } + decompose_nfc(input); + compose(input); + return true; +} + +} // namespace ada::idna +/* end file src/normalization.cpp */ +/* begin file src/punycode.cpp */ +/* begin file include/ada/idna/punycode.h */ +#ifndef ADA_IDNA_PUNYCODE_H +#define ADA_IDNA_PUNYCODE_H + +#include +#include + +namespace ada::idna { + +bool punycode_to_utf32(std::string_view input, std::u32string& out); +bool verify_punycode(std::string_view input); +bool utf32_to_punycode(std::u32string_view input, std::string& out); + +} // namespace ada::idna + +#endif // ADA_IDNA_PUNYCODE_H +/* end file include/ada/idna/punycode.h */ + +#include + +namespace ada::idna { + +constexpr int32_t base = 36; +constexpr int32_t tmin = 1; +constexpr int32_t tmax = 26; +constexpr int32_t skew = 38; +constexpr int32_t damp = 700; +constexpr int32_t initial_bias = 72; +constexpr uint32_t initial_n = 128; + +static constexpr int32_t char_to_digit_value(char value) { + if (value >= 'a' && value <= 'z') return value - 'a'; + if (value >= '0' && value <= '9') return value - '0' + 26; + return -1; +} + +static constexpr char digit_to_char(int32_t digit) { + return digit < 26 ? char(digit + 97) : char(digit + 22); +} + +static constexpr int32_t adapt(int32_t d, int32_t n, bool firsttime) { + if (firsttime) { + d = d / damp; + } else { + d = d / 2; + } + d += d / n; + int32_t k = 0; + while (d > ((base - tmin) * tmax) / 2) { + d /= base - tmin; + k += base; + } + return k + (((base - tmin + 1) * d) / (d + skew)); +} + +bool punycode_to_utf32(std::string_view input, std::u32string &out) { + int32_t written_out{0}; + out.reserve(out.size() + input.size()); + uint32_t n = initial_n; + int32_t i = 0; + int32_t bias = initial_bias; + // grab ascii content + size_t end_of_ascii = input.find_last_of('-'); + if (end_of_ascii != std::string_view::npos) { + for (uint8_t c : input.substr(0, end_of_ascii)) { + if (c >= 0x80) { + return false; + } + out.push_back(c); + written_out++; + } + input.remove_prefix(end_of_ascii + 1); + } + while (!input.empty()) { + int32_t oldi = i; + int32_t w = 1; + for (int32_t k = base;; k += base) { + if (input.empty()) { + return false; + } + uint8_t code_point = input.front(); + input.remove_prefix(1); + int32_t digit = char_to_digit_value(code_point); + if (digit < 0) { + return false; + } + if (digit > (0x7fffffff - i) / w) { + return false; + } + i = i + digit * w; + int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias; + if (digit < t) { + break; + } + if (w > 0x7fffffff / (base - t)) { + return false; + } + w = w * (base - t); + } + bias = adapt(i - oldi, written_out + 1, oldi == 0); + if (i / (written_out + 1) > int32_t(0x7fffffff - n)) { + return false; + } + n = n + i / (written_out + 1); + i = i % (written_out + 1); + if (n < 0x80) { + return false; + } + out.insert(out.begin() + i, n); + written_out++; + ++i; + } + // See https://github.com/whatwg/url/issues/803 + // Reject labels whose decoded form begins with "xn--" (double-encoded ACE). + if (out.size() >= 4 && out[0] == U'x' && out[1] == U'n' && out[2] == U'-' && + out[3] == U'-') { + return false; + } + return true; +} + +bool verify_punycode(std::string_view input) { + // Track only the first 4 decoded code points to check for the "xn--" prefix. + // This avoids heap allocation while still detecting double-encoded ACE + // labels. + uint32_t first4[4]{}; + size_t written_out{0}; + uint32_t n = initial_n; + int32_t i = 0; + int32_t bias = initial_bias; + // grab ascii content + size_t end_of_ascii = input.find_last_of('-'); + if (end_of_ascii != std::string_view::npos) { + for (uint8_t c : input.substr(0, end_of_ascii)) { + if (c >= 0x80) { + return false; + } + if (written_out < 4) { + first4[written_out] = c; + } + written_out++; + } + input.remove_prefix(end_of_ascii + 1); + } + while (!input.empty()) { + int32_t oldi = i; + int32_t w = 1; + for (int32_t k = base;; k += base) { + if (input.empty()) { + return false; + } + uint8_t code_point = input.front(); + input.remove_prefix(1); + int32_t digit = char_to_digit_value(code_point); + if (digit < 0) { + return false; + } + if (digit > (0x7fffffff - i) / w) { + return false; + } + i = i + digit * w; + int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias; + if (digit < t) { + break; + } + if (w > 0x7fffffff / (base - t)) { + return false; + } + w = w * (base - t); + } + bias = adapt(i - oldi, int32_t(written_out + 1), oldi == 0); + if (i / (written_out + 1) > 0x7fffffff - n) { + return false; + } + n = n + i / int32_t(written_out + 1); + i = i % int32_t(written_out + 1); + if (n < 0x80) { + return false; + } + // Simulate insert at position i, maintaining only the first 4 slots. + size_t insert_pos = size_t(i); + if (insert_pos < 4) { + for (size_t j = 3; j > insert_pos; j--) { + first4[j] = first4[j - 1]; + } + first4[insert_pos] = n; + } + written_out++; + ++i; + } + // See https://github.com/whatwg/url/issues/803 + // Reject labels whose decoded form begins with "xn--" (double-encoded ACE). + if (written_out >= 4 && first4[0] == U'x' && first4[1] == U'n' && + first4[2] == U'-' && first4[3] == U'-') { + return false; + } + return true; +} + +bool utf32_to_punycode(std::u32string_view input, std::string &out) { + out.reserve(input.size() + out.size()); + uint32_t n = initial_n; + int32_t d = 0; + int32_t bias = initial_bias; + size_t h = 0; + // first push the ascii content + for (uint32_t c : input) { + if (c < 0x80) { + ++h; + out.push_back(char(c)); + } + if (c > 0x10ffff || (c >= 0xd800 && c < 0xe000)) { + return false; + } + } + size_t b = h; + if (b > 0) { + out.push_back('-'); + } + while (h < input.size()) { + uint32_t m = 0x10FFFF; + for (auto code_point : input) { + if (code_point >= n && code_point < m) m = code_point; + } + + if ((m - n) > (0x7fffffff - d) / (h + 1)) { + return false; + } + d = d + int32_t((m - n) * (h + 1)); + n = m; + for (auto c : input) { + if (c < n) { + if (d == 0x7fffffff) { + return false; + } + ++d; + } + if (c == n) { + int32_t q = d; + for (int32_t k = base;; k += base) { + int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias; + + if (q < t) { + break; + } + out.push_back(digit_to_char(t + ((q - t) % (base - t)))); + q = (q - t) / (base - t); + } + out.push_back(digit_to_char(q)); + bias = adapt(d, int32_t(h + 1), h == b); + d = 0; + ++h; + } + } + ++d; + ++n; + } + return true; +} + +} // namespace ada::idna +/* end file src/punycode.cpp */ +/* begin file src/validity.cpp */ + +#include +#include +#include + +namespace ada::idna { + +enum direction : uint8_t { + NONE, + BN, + CS, + ES, + ON, + EN, + L, + R, + NSM, + AL, + AN, + ET, + WS, + RLO, + LRO, + PDF, + RLE, + RLI, + FSI, + PDI, + LRI, + B, + S, + LRE +}; + +// Bidi direction ranges live in the compressed blob as const SoA arrays +// (dir_start / dir_final / dir_value). See table_store.hpp layout asserts. + +// CheckJoiners and CheckBidi are true for URL specification. + +// Assumes ensure_tables() has already been called by is_label_valid(). +inline static direction find_direction(uint32_t code_point) noexcept { + // Binary search on dir_final (sorted upper bounds). + size_t lo = 0, hi = dir_table_count; + while (lo < hi) { + size_t mid = lo + (hi - lo) / 2; + if (dir_final[mid] < code_point) { + lo = mid + 1; + } else { + hi = mid; + } + } + if (lo == dir_table_count) { + return direction::NONE; + } + return code_point >= dir_start[lo] ? static_cast(dir_value[lo]) + : direction::NONE; +} + +inline static size_t find_last_not_of_nsm( + const std::u32string_view label) noexcept { + for (int i = static_cast(label.size() - 1); i >= 0; i--) + if (find_direction(label[i]) != direction::NSM) return i; + + return std::u32string_view::npos; +} + +// An RTL label is a label that contains at least one character of type R, AL, +// or AN. https://www.rfc-editor.org/rfc/rfc5893#section-2 +inline static bool is_rtl_label(const std::u32string_view label) noexcept { + const size_t mask = + (1u << direction::R) | (1u << direction::AL) | (1u << direction::AN); + + size_t directions = 0; + for (size_t i = 0; i < label.size(); i++) { + directions |= 1u << find_direction(label[i]); + } + return (directions & mask) != 0; +} + +bool is_label_valid(const std::u32string_view label) { + if (label.empty()) { + return true; + } + if (!ensure_tables() || combining_ranges == nullptr || dir_start == nullptr || + dir_final == nullptr || dir_value == nullptr) { + return false; + } + + /////////////// + // We have a normalization step which ensures that we are in NFC. + // If we receive punycode, we normalize and check that the normalized + // version matches the original. + // -------------------------------------- + // The label must be in Unicode Normalization Form NFC. + + // Current URL standard indicatest that CheckHyphens is set to false. + // --------------------------------------- + // If CheckHyphens, the label must not contain a U+002D HYPHEN-MINUS character + // in both the third and fourth positions. If CheckHyphens, the label must + // neither begin nor end with a U+002D HYPHEN-MINUS character. + + // This is not necessary because we segment the + // labels by '.'. + // --------------------------------------- + // The label must not contain a U+002E ( . ) FULL STOP. + // if (label.find('.') != std::string_view::npos) return false; + + // The label must not begin with a combining mark. + // Range membership via lower_bound on range end. + const std::span comb_span{combining_ranges, + combining_range_count}; + const auto comb_it = std::ranges::lower_bound( + comb_span, label.front(), {}, [](const auto& range) { return range[1]; }); + if (comb_it != comb_span.end() && label.front() >= (*comb_it)[0]) { + return false; + } + // We verify this next step as part of the mapping: + // --------------------------------------------- + // Each code point in the label must only have certain status values + // according to Section 5, IDNA Mapping Table: + // - For Transitional Processing, each value must be valid. + // - For Nontransitional Processing, each value must be either valid or + // deviation. + + // If CheckJoiners, the label must satisfy the ContextJ rules from Appendix + // A, in The Unicode Code Points and Internationalized Domain Names for + // Applications (IDNA) [IDNA2008]. + constexpr static uint32_t virama[] = { + 0x094D, 0x09CD, 0x0A4D, 0x0ACD, 0x0B4D, 0x0BCD, 0x0C4D, 0x0CCD, + 0x0D3B, 0x0D3C, 0x0D4D, 0x0DCA, 0x0E3A, 0x0EBA, 0x0F84, 0x1039, + 0x103A, 0x1714, 0x1734, 0x17D2, 0x1A60, 0x1B44, 0x1BAA, 0x1BAB, + 0x1BF2, 0x1BF3, 0x2D7F, 0xA806, 0xA82C, 0xA8C4, 0xA953, 0xA9C0, + 0xAAF6, 0xABED, 0x10A3F, 0x11046, 0x1107F, 0x110B9, 0x11133, 0x11134, + 0x111C0, 0x11235, 0x112EA, 0x1134D, 0x11442, 0x114C2, 0x115BF, 0x1163F, + 0x116B6, 0x1172B, 0x11839, 0x1193D, 0x1193E, 0x119E0, 0x11A34, 0x11A47, + 0x11A99, 0x11C3F, 0x11D44, 0x11D45, 0x11D97}; + constexpr static uint32_t R[] = { + 0x622, 0x623, 0x624, 0x625, 0x627, 0x629, 0x62f, 0x630, 0x631, + 0x632, 0x648, 0x671, 0x672, 0x673, 0x675, 0x676, 0x677, 0x688, + 0x689, 0x68a, 0x68b, 0x68c, 0x68d, 0x68e, 0x68f, 0x690, 0x691, + 0x692, 0x693, 0x694, 0x695, 0x696, 0x697, 0x698, 0x699, 0x6c0, + 0x6c3, 0x6c4, 0x6c5, 0x6c6, 0x6c7, 0x6c8, 0x6c9, 0x6ca, 0x6cb, + 0x6cd, 0x6cf, 0x6d2, 0x6d3, 0x6d5, 0x6ee, 0x6ef, 0x710, 0x715, + 0x716, 0x717, 0x718, 0x719, 0x71e, 0x728, 0x72a, 0x72c, 0x72f, + 0x74d, 0x759, 0x75a, 0x75b, 0x854, 0x8aa, 0x8ab, 0x8ac}; + constexpr static uint32_t L[] = {0xa872}; + constexpr static uint32_t D[] = { + 0x620, 0x626, 0x628, 0x62a, 0x62b, 0x62c, 0x62d, 0x62e, 0x633, + 0x634, 0x635, 0x636, 0x637, 0x638, 0x639, 0x63a, 0x63b, 0x63c, + 0x63d, 0x63e, 0x63f, 0x641, 0x642, 0x643, 0x644, 0x645, 0x646, + 0x647, 0x649, 0x64a, 0x66e, 0x66f, 0x678, 0x679, 0x67a, 0x67b, + 0x67c, 0x67d, 0x67e, 0x67f, 0x680, 0x681, 0x682, 0x683, 0x684, + 0x685, 0x686, 0x687, 0x69a, 0x69b, 0x69c, 0x69d, 0x69e, 0x69f, + 0x6a0, 0x6a1, 0x6a2, 0x6a3, 0x6a4, 0x6a5, 0x6a6, 0x6a7, 0x6a8, + 0x6a9, 0x6aa, 0x6ab, 0x6ac, 0x6ad, 0x6ae, 0x6af, 0x6b0, 0x6b1, + 0x6b2, 0x6b3, 0x6b4, 0x6b5, 0x6b6, 0x6b7, 0x6b8, 0x6b9, 0x6ba, + 0x6bb, 0x6bc, 0x6bd, 0x6be, 0x6bf, 0x6c1, 0x6c2, 0x6cc, 0x6ce, + 0x6d0, 0x6d1, 0x6fa, 0x6fb, 0x6fc, 0x6ff, 0x712, 0x713, 0x714, + 0x71a, 0x71b, 0x71c, 0x71d, 0x71f, 0x720, 0x721, 0x722, 0x723, + 0x724, 0x725, 0x726, 0x727, 0x729, 0x72b, 0x72d, 0x72e, 0x74e, + 0x74f, 0x750, 0x751, 0x752, 0x753, 0x754, 0x755, 0x756, 0x757, + 0x758, 0x75c, 0x75d, 0x75e, 0x75f, 0x760, 0x761, 0x762, 0x763, + 0x764, 0x765, 0x766, 0x850, 0x851, 0x852, 0x853, 0x855, 0x8a0, + 0x8a2, 0x8a3, 0x8a4, 0x8a5, 0x8a6, 0x8a7, 0x8a8, 0x8a9, 0x1807, + 0x1820, 0x1821, 0x1822, 0x1823, 0x1824, 0x1825, 0x1826, 0x1827, 0x1828, + 0x1829, 0x182a, 0x182b, 0x182c, 0x182d, 0x182e, 0x182f, 0x1830, 0x1831, + 0x1832, 0x1833, 0x1834, 0x1835, 0x1836, 0x1837, 0x1838, 0x1839, 0x183a, + 0x183b, 0x183c, 0x183d, 0x183e, 0x183f, 0x1840, 0x1841, 0x1842, 0x1843, + 0x1844, 0x1845, 0x1846, 0x1847, 0x1848, 0x1849, 0x184a, 0x184b, 0x184c, + 0x184d, 0x184e, 0x184f, 0x1850, 0x1851, 0x1852, 0x1853, 0x1854, 0x1855, + 0x1856, 0x1857, 0x1858, 0x1859, 0x185a, 0x185b, 0x185c, 0x185d, 0x185e, + 0x185f, 0x1860, 0x1861, 0x1862, 0x1863, 0x1864, 0x1865, 0x1866, 0x1867, + 0x1868, 0x1869, 0x186a, 0x186b, 0x186c, 0x186d, 0x186e, 0x186f, 0x1870, + 0x1871, 0x1872, 0x1873, 0x1874, 0x1875, 0x1876, 0x1877, 0x1887, 0x1888, + 0x1889, 0x188a, 0x188b, 0x188c, 0x188d, 0x188e, 0x188f, 0x1890, 0x1891, + 0x1892, 0x1893, 0x1894, 0x1895, 0x1896, 0x1897, 0x1898, 0x1899, 0x189a, + 0x189b, 0x189c, 0x189d, 0x189e, 0x189f, 0x18a0, 0x18a1, 0x18a2, 0x18a3, + 0x18a4, 0x18a5, 0x18a6, 0x18a7, 0x18a8, 0x18aa, 0xa840, 0xa841, 0xa842, + 0xa843, 0xa844, 0xa845, 0xa846, 0xa847, 0xa848, 0xa849, 0xa84a, 0xa84b, + 0xa84c, 0xa84d, 0xa84e, 0xa84f, 0xa850, 0xa851, 0xa852, 0xa853, 0xa854, + 0xa855, 0xa856, 0xa857, 0xa858, 0xa859, 0xa85a, 0xa85b, 0xa85c, 0xa85d, + 0xa85e, 0xa85f, 0xa860, 0xa861, 0xa862, 0xa863, 0xa864, 0xa865, 0xa866, + 0xa867, 0xa868, 0xa869, 0xa86a, 0xa86b, 0xa86c, 0xa86d, 0xa86e, 0xa86f, + 0xa870, 0xa871}; + + for (size_t i = 0; i < label.size(); i++) { + uint32_t c = label[i]; + if (c == 0x200c) { + if (i > 0) { + if (std::ranges::binary_search(virama, label[i - 1])) { + return true; + } + } + if ((i == 0) || (i + 1 >= label.size())) { + return false; + } + // we go backward looking for L or D + auto is_l_or_d = [](uint32_t code) { + return std::ranges::binary_search(L, code) || + std::ranges::binary_search(D, code); + }; + auto is_r_or_d = [](uint32_t code) { + return std::ranges::binary_search(R, code) || + std::ranges::binary_search(D, code); + }; + std::u32string_view before = label.substr(0, i); + std::u32string_view after = label.substr(i + 1); + return (std::find_if(before.begin(), before.end(), is_l_or_d) != + before.end()) && + (std::find_if(after.begin(), after.end(), is_r_or_d) != + after.end()); + } else if (c == 0x200d) { + if (i > 0) { + if (std::ranges::binary_search(virama, label[i - 1])) { + return true; + } + } + return false; + } + } + + // If CheckBidi, and if the domain name is a Bidi domain name, then the label + // must satisfy all six of the numbered conditions in [IDNA2008] RFC 5893, + // Section 2. + + // The following rule, consisting of six conditions, applies to labels + // in Bidi domain names. The requirements that this rule satisfies are + // described in Section 3. All of the conditions must be satisfied for + // the rule to be satisfied. + // + // 1. The first character must be a character with Bidi property L, R, + // or AL. If it has the R or AL property, it is an RTL label; if it + // has the L property, it is an LTR label. + // + // 2. In an RTL label, only characters with the Bidi properties R, AL, + // AN, EN, ES, CS, ET, ON, BN, or NSM are allowed. + // + // 3. In an RTL label, the end of the label must be a character with + // Bidi property R, AL, EN, or AN, followed by zero or more + // characters with Bidi property NSM. + // + // 4. In an RTL label, if an EN is present, no AN may be present, and + // vice versa. + // + // 5. In an LTR label, only characters with the Bidi properties L, EN, + // ES, CS, ET, ON, BN, or NSM are allowed. + // + // 6. In an LTR label, the end of the label must be a character with + // Bidi property L or EN, followed by zero or more characters with + // Bidi property NSM. + + size_t last_non_nsm_char = find_last_not_of_nsm(label); + if (last_non_nsm_char == std::u32string_view::npos) { + return false; + } + + // A "Bidi domain name" is a domain name that contains at least one RTL label. + // The following rule, consisting of six conditions, applies to labels in Bidi + // domain names. + if (is_rtl_label(label)) { + // The first character must be a character with Bidi property L, R, + // or AL. If it has the R or AL property, it is an RTL label; if it + // has the L property, it is an LTR label. + + if (find_direction(label[0]) == direction::L) { + // Eval as LTR + + // In an LTR label, only characters with the Bidi properties L, EN, + // ES, CS, ET, ON, BN, or NSM are allowed. + for (size_t i = 0; i <= last_non_nsm_char; i++) { + const direction d = find_direction(label[i]); + if (!(d == direction::L || d == direction::EN || d == direction::ES || + d == direction::CS || d == direction::ET || d == direction::ON || + d == direction::BN || d == direction::NSM)) { + return false; + } + } + + const direction last_dir = find_direction(label[last_non_nsm_char]); + if (!(last_dir == direction::L || last_dir == direction::EN)) { + return false; + } + + return true; + + } else { + // Eval as RTL + + // The first character must be R or AL; a leading AN (or any other + // direction) does not start a valid RTL label. + const direction first_dir = find_direction(label[0]); + if (first_dir != direction::R && first_dir != direction::AL) { + return false; + } + + bool has_an = false; + bool has_en = false; + for (size_t i = 0; i <= last_non_nsm_char; i++) { + const direction d = find_direction(label[i]); + + // In an RTL label, if an EN is present, no AN may be present, and vice + // versa. + if ((d == direction::EN && ((has_en = true) && has_an)) || + (d == direction::AN && ((has_an = true) && has_en))) { + return false; + } + + if (!(d == direction::R || d == direction::AL || d == direction::AN || + d == direction::EN || d == direction::ES || d == direction::CS || + d == direction::ET || d == direction::ON || d == direction::BN || + d == direction::NSM)) { + return false; + } + + if (i == last_non_nsm_char && + !(d == direction::R || d == direction::AL || d == direction::AN || + d == direction::EN)) { + return false; + } + } + + return true; + } + } + + return true; +} + +} // namespace ada::idna +/* end file src/validity.cpp */ +/* begin file src/to_ascii.cpp */ +/* begin file include/ada/idna/to_ascii.h */ +#ifndef ADA_IDNA_TO_ASCII_H +#define ADA_IDNA_TO_ASCII_H + +#include +#include + +/* begin file include/ada/idna/limits.h */ +#ifndef ADA_IDNA_LIMITS_H +#define ADA_IDNA_LIMITS_H + +#include + +namespace ada::idna { + +// Maximum accepted UTF-8 domain length for to_ascii / to_unicode. +// Bounds heap growth under untrusted input (DoS resistance). DNS wire limits +// are smaller; this allows long Unicode labels used in URL tests/fixtures. +inline constexpr size_t max_domain_input_bytes = 16384; + +} // namespace ada::idna + +#endif // ADA_IDNA_LIMITS_H +/* end file include/ada/idna/limits.h */ + +namespace ada::idna { + +// Converts a domain (e.g., www.google.com) possibly containing international +// characters to an ascii domain (with punycode). It will not do percent +// decoding: percent decoding should be done prior to calling this function. We +// do not remove tabs and spaces, they should have been removed prior to calling +// this function. We also do not trim control characters. We also assume that +// the input is not empty. We return "" on error. Inputs longer than +// max_domain_input_bytes are rejected. +// +// This function may accept or even produce invalid domains (WHATWG carve-outs). +std::string to_ascii(std::string_view ut8_string); + +// Same as to_ascii, but writes into `out` and returns false on error without +// relying on empty-string ambiguity. +[[nodiscard]] bool to_ascii(std::string_view ut8_string, std::string& out); + +// Returns true if the string contains a forbidden code point according to the +// WHATGL URL specification: +// https://url.spec.whatwg.org/#forbidden-domain-code-point +bool contains_forbidden_domain_code_point(std::string_view ascii_string); + +bool constexpr is_ascii(std::u32string_view view); +bool constexpr is_ascii(std::string_view view); + +} // namespace ada::idna + +#endif // ADA_IDNA_TO_ASCII_H +/* end file include/ada/idna/to_ascii.h */ + +#include +#include +#include +#include + +/* begin file include/ada/idna/validity.h */ +#ifndef ADA_IDNA_VALIDITY_H +#define ADA_IDNA_VALIDITY_H + +#include +#include + +namespace ada::idna { + +/** + * @see https://www.unicode.org/reports/tr46/#Validity_Criteria + */ +bool is_label_valid(std::u32string_view label); + +} // namespace ada::idna + +#endif // ADA_IDNA_VALIDITY_H +/* end file include/ada/idna/validity.h */ + +#ifdef ADA_USE_SIMDUTF +#include "simdutf.h" +#endif + +namespace ada::idna { + +bool constexpr is_ascii(std::u32string_view view) { + for (uint32_t c : view) { + if (c >= 0x80) { + return false; + } + } + return true; +} + +bool constexpr is_ascii(std::string_view view) { + for (uint8_t c : view) { + if (c >= 0x80) { + return false; + } + } + return true; +} + +constexpr static uint8_t is_forbidden_domain_code_point_table[] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 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, 1, 1, 1, 1, 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, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + +static_assert(sizeof(is_forbidden_domain_code_point_table) == 256); + +inline bool is_forbidden_domain_code_point(const char c) noexcept { + return is_forbidden_domain_code_point_table[uint8_t(c)]; +} + +bool contains_forbidden_domain_code_point(std::string_view view) { + return std::ranges::any_of(view, is_forbidden_domain_code_point); +} + +// Per the WHATWG URL "domain to ASCII" algorithm, when beStrict is false and +// the input domain is an ASCII string, the result is the input lowercased, +// regardless of the outcome of Unicode ToASCII. +// +// See https://url.spec.whatwg.org/#concept-domain-to-ascii +static void from_ascii_to_ascii(std::string_view ut8_string, std::string& out) { + out.assign(ut8_string); + ascii_map(out.data(), out.size()); +} + +// Append ASCII code units from a UTF-32 label (all values < 0x80). +static void append_ascii_label(std::string& out, std::u32string_view label) { + const size_t old = out.size(); + out.resize(old + label.size()); + char* dest = out.data() + old; + for (char32_t c : label) { + *dest++ = static_cast(c); + } +} + +// True if label begins with "xn--" (already lowercased by mapping). +static bool is_ace_prefix(std::u32string_view label) noexcept { + return label.size() >= 4 && label[0] == U'x' && label[1] == U'n' && + label[2] == U'-' && label[3] == U'-'; +} + +[[nodiscard]] bool to_ascii(std::string_view ut8_string, std::string& out) { + out.clear(); + if (ut8_string.size() > max_domain_input_bytes) { + return false; + } + if (is_ascii(ut8_string)) { + from_ascii_to_ascii(ut8_string, out); + return true; + } + +#ifdef ADA_USE_SIMDUTF + size_t utf32_length = + simdutf::utf32_length_from_utf8(ut8_string.data(), ut8_string.size()); + if (utf32_length == 0 && !ut8_string.empty()) { + return false; + } + std::u32string working(utf32_length, U'\0'); + size_t actual_utf32_length = simdutf::convert_utf8_to_utf32( + ut8_string.data(), ut8_string.size(), working.data()); +#else + size_t utf32_length = + ada::idna::utf32_length_from_utf8(ut8_string.data(), ut8_string.size()); + if (utf32_length == 0 && !ut8_string.empty()) { + return false; + } + std::u32string working(utf32_length, U'\0'); + size_t actual_utf32_length = ada::idna::utf8_to_utf32( + ut8_string.data(), ut8_string.size(), working.data()); +#endif + if (actual_utf32_length == 0 || actual_utf32_length != utf32_length) { + return false; + } + working.resize(actual_utf32_length); + + // Map into a second buffer with exact sizing (no growth reallocs). + std::u32string mapped; + if (!ada::idna::map(working, mapped)) { + return false; + } + // Drop UTF-32 input; reuse `working` as scratch for ACE validation below. + working.clear(); + + // Skip NFC when already normalized (ASCII is a fast subset of this check). + if (!is_ascii(mapped) && !is_already_nfc(mapped)) { + if (!normalize(mapped)) { + return false; + } + } + + // Estimate ASCII output size (punycode may expand non-ASCII labels). + out.reserve(mapped.size() + 8); + + // Walk labels with a single pointer scan (no repeated string::find). + const char32_t* p = mapped.data(); + const char32_t* const end = p + mapped.size(); + std::u32string post_map; + + while (p < end) { + const char32_t* label_begin = p; + while (p < end && *p != U'.') { + ++p; + } + const size_t label_size = static_cast(p - label_begin); + std::u32string_view label_view(label_begin, label_size); + const bool is_last_label = (p == end); + if (p < end) { + ++p; // skip dot + } + + if (label_size == 0) { + // empty label + } else if (is_ace_prefix(label_view)) { + for (char32_t c : label_view) { + if (c >= 0x80) { + out.clear(); + return false; + } + } + append_ascii_label(out, label_view); + std::string_view puny_segment_ascii( + out.data() + (out.size() - label_size) + 4, label_size - 4); + working.clear(); + if (!ada::idna::punycode_to_utf32(puny_segment_ascii, working)) { + out.clear(); + return false; + } + if (is_ascii(working)) { + out.clear(); + return false; + } + if (!ada::idna::map(working, post_map) || working != post_map) { + out.clear(); + return false; + } + // Mapping must be stable; NFC must not change the mapped form either. + if (!is_ascii(post_map) && !is_already_nfc(post_map)) { + if (!normalize(post_map) || post_map != working) { + out.clear(); + return false; + } + } + if (post_map.empty() || !is_label_valid(post_map)) { + out.clear(); + return false; + } + } else if (is_ascii(label_view)) { + append_ascii_label(out, label_view); + } else { + if (!is_label_valid(label_view)) { + out.clear(); + return false; + } + out.append("xn--"); + if (!ada::idna::utf32_to_punycode(label_view, out)) { + out.clear(); + return false; + } + } + if (!is_last_label) { + out.push_back('.'); + } + } + return true; +} + +std::string to_ascii(std::string_view ut8_string) { + std::string out; + if (!to_ascii(ut8_string, out)) { + return {}; + } + return out; +} +} // namespace ada::idna +/* end file src/to_ascii.cpp */ +/* begin file src/to_unicode.cpp */ +/* begin file include/ada/idna/to_unicode.h */ +#ifndef ADA_IDNA_TO_UNICODE_H +#define ADA_IDNA_TO_UNICODE_H + +#include +#include + + +namespace ada::idna { + +// UTS #46 ToUnicode. Never fails per the standard: on step failure the original +// label is kept. Inputs longer than max_domain_input_bytes are returned +// unchanged as a safety measure under untrusted input. +std::string to_unicode(std::string_view input); + +// Writes into `out`. Returns false only if the input exceeds +// max_domain_input_bytes (out is left empty). Otherwise always returns true +// (ToUnicode does not fail). +[[nodiscard]] bool to_unicode(std::string_view input, std::string& out); + +} // namespace ada::idna + +#endif // ADA_IDNA_TO_UNICODE_H +/* end file include/ada/idna/to_unicode.h */ + +#include +#include + +/* begin file include/idna.h */ +#ifndef ADA_IDNA_H +#define ADA_IDNA_H + +/* begin file include/ada/idna/identifier.h */ +#ifndef ADA_IDNA_IDENTIFIER_H +#define ADA_IDNA_IDENTIFIER_H + +#include +#include + +namespace ada::idna { + +// Verify if it is valid name code point given a Unicode code point and a +// boolean first: If first is true return the result of checking if code point +// is contained in the IdentifierStart set of code points. Otherwise return the +// result of checking if code point is contained in the IdentifierPart set of +// code points. Returns false if the input is empty or the code point is not +// valid. There is minimal Unicode error handling: the input should be valid +// UTF-8. https://urlpattern.spec.whatwg.org/#is-a-valid-name-code-point +bool valid_name_code_point(char32_t code_point, bool first); + +} // namespace ada::idna + +#endif +/* end file include/ada/idna/identifier.h */ + +#endif +/* end file include/idna.h */ + +#ifdef ADA_USE_SIMDUTF +#include "simdutf.h" +#endif + +namespace ada::idna { + +[[nodiscard]] bool to_unicode(std::string_view input, std::string& output) { + output.clear(); + if (input.size() > max_domain_input_bytes) { + return false; + } + output.reserve(input.size()); + + size_t label_start = 0; + std::u32string tmp_buffer; + std::u32string post_map; + while (label_start < input.size()) { + size_t loc_dot = input.find('.', label_start); + bool is_last_label = (loc_dot == std::string_view::npos); + size_t label_size = + is_last_label ? input.size() - label_start : loc_dot - label_start; + auto label_view = std::string_view(input.data() + label_start, label_size); + + if (label_view.starts_with("xn--") && ada::idna::is_ascii(label_view)) { + label_view.remove_prefix(4); + tmp_buffer.clear(); + if (ada::idna::punycode_to_utf32(label_view, tmp_buffer)) { + // Per UTS #46, the decoded label must be re-validated. Reject decodings + // that are pure ASCII (xn-- encoding of an ASCII-only label), or whose + // mapping/normalization is not stable, or that fail label validity. + bool accept_decoded = true; + if (ada::idna::is_ascii(tmp_buffer)) { + accept_decoded = false; + } else { + post_map.clear(); + if (!ada::idna::map(tmp_buffer, post_map) || post_map != tmp_buffer) { + accept_decoded = false; + } else if (!ada::idna::normalize(post_map) || + post_map != tmp_buffer || post_map.empty() || + !ada::idna::is_label_valid(post_map)) { + accept_decoded = false; + } + } + + if (accept_decoded) { +#ifdef ADA_USE_SIMDUTF + auto utf8_size = simdutf::utf8_length_from_utf32(tmp_buffer.data(), + tmp_buffer.size()); + size_t old_size = output.size(); + output.resize(old_size + utf8_size); + size_t written = simdutf::convert_utf32_to_utf8( + tmp_buffer.data(), tmp_buffer.size(), output.data() + old_size); + if (written != utf8_size) { + output.resize(old_size); + output.append( + std::string_view(input.data() + label_start, label_size)); + } +#else + auto utf8_size = ada::idna::utf8_length_from_utf32(tmp_buffer.data(), + tmp_buffer.size()); + size_t old_size = output.size(); + output.resize(old_size + utf8_size); + size_t written = ada::idna::utf32_to_utf8( + tmp_buffer.data(), tmp_buffer.size(), output.data() + old_size); + if (written != utf8_size) { + output.resize(old_size); + output.append( + std::string_view(input.data() + label_start, label_size)); + } +#endif + } else { + // ToUnicode never fails. If any step fails, return the original + // input sequence for the label. + output.append( + std::string_view(input.data() + label_start, label_size)); + } + } else { + output.append(std::string_view(input.data() + label_start, label_size)); + } + } else { + output.append(label_view); + } + + if (!is_last_label) { + output.push_back('.'); + } + + label_start += label_size + 1; + } + + return true; +} + +std::string to_unicode(std::string_view input) { + std::string output; + if (!to_unicode(input, output)) { + // Over-limit input: return original (ToUnicode never fails in the sense of + // producing no answer for valid-length inputs). + return std::string(input); + } + return output; +} +} // namespace ada::idna +/* end file src/to_unicode.cpp */ +/* begin file src/identifier.cpp */ + +#include +#include +#include +#include + +/* begin file src/id_tables.cpp */ +// IDNA 17.0.0 +// Identifier range tables are stored in the compressed blob (table_store.hpp). + +// clang-format off +#ifndef ADA_IDNA_IDENTIFIER_TABLES_H +#define ADA_IDNA_IDENTIFIER_TABLES_H +#include + +namespace ada::idna { + +// id_continue / id_start pointers and counts are provided by table_store.hpp. + +} // namespace ada::idna +#endif // ADA_IDNA_IDENTIFIER_TABLES_H +/* end file src/id_tables.cpp */ + +namespace ada::idna { +constexpr bool is_ascii_letter(char32_t c) noexcept { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); +} + +constexpr bool is_ascii_letter_or_digit(char32_t c) noexcept { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9'); +} + +bool valid_name_code_point(char32_t code_point, bool first) { + // https://tc39.es/ecma262/#prod-IdentifierStart + + // Fast paths (no table needed) + if (first && (code_point == U'$' || code_point == U'_' || + is_ascii_letter(code_point))) { + return true; + } + if (!first && (code_point == U'$' || is_ascii_letter_or_digit(code_point))) { + return true; + } + + // Minimal error handling for invalid code point + if (code_point > 0x10FFFF) { + return false; + } + if (code_point >= 0xD800 && code_point <= 0xDFFF) { + return false; + } + + if (!ensure_tables() || id_start == nullptr || id_continue == nullptr) { + return false; + } + + // Slow path: binary search through the appropriate Unicode range table. + // Each entry is a [low, high] inclusive range. + const std::span ranges = + first ? std::span{ada::idna::id_start, + ada::idna::id_start_count} + : std::span{ada::idna::id_continue, + ada::idna::id_continue_count}; + + const auto iter = std::ranges::lower_bound( + ranges, code_point, {}, + [](const auto& range) { return range[1]; }); // project to range-high + + return iter != ranges.end() && code_point >= (*iter)[0]; +} +} // namespace ada::idna +/* end file src/identifier.cpp */ +/* end file src/idna.cpp */ +/* end file src/ada_idna.cpp */ +ADA_POP_DISABLE_WARNINGS + +#include +#include +#include +#if ADA_SSSE3 +#include +#elif ADA_NEON +#include +#elif ADA_SSE2 +#include +#elif ADA_LSX +#include +#elif ADA_RVV +#include +#endif + +#include + +namespace ada::unicode { + +constexpr bool is_tabs_or_newline(char c) noexcept { + return c == '\r' || c == '\n' || c == '\t'; +} + +constexpr uint64_t broadcast(uint8_t v) noexcept { + return 0x101010101010101ull * v; +} + +constexpr bool to_lower_ascii(char* input, size_t length) noexcept { + uint64_t broadcast_80 = broadcast(0x80); + uint64_t broadcast_Ap = broadcast(128 - 'A'); + uint64_t broadcast_Zp = broadcast(128 - 'Z' - 1); + uint64_t non_ascii = 0; + size_t i = 0; + + for (; i + 7 < length; i += 8) { + uint64_t word{}; + memcpy(&word, input + i, sizeof(word)); + non_ascii |= (word & broadcast_80); + word ^= + (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2; + memcpy(input + i, &word, sizeof(word)); + } + if (i < length) { + uint64_t word{}; + memcpy(&word, input + i, length - i); + non_ascii |= (word & broadcast_80); + word ^= + (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2; + memcpy(input + i, &word, length - i); + } + return non_ascii == 0; +} +#if ADA_SSSE3 +ada_really_inline bool has_tabs_or_newline( + std::string_view user_input) noexcept { + // first check for short strings in which case we do it naively. + if (user_input.size() < 16) { // slow path + return std::ranges::any_of(user_input, is_tabs_or_newline); + } + // fast path for long strings (expected to be common) + // Using SSSE3's _mm_shuffle_epi8 for table lookup (same approach as NEON) + size_t i = 0; + // Lookup table where positions 9, 10, 13 contain their own values + // Everything else is set to 1 so it won't match + const __m128i rnt = + _mm_setr_epi8(1, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 13, 0, 0); + __m128i running = _mm_setzero_si128(); + for (; i + 15 < user_input.size(); i += 16) { + __m128i word = _mm_loadu_si128((const __m128i*)(user_input.data() + i)); + // Shuffle the lookup table using input bytes as indices + __m128i shuffled = _mm_shuffle_epi8(rnt, word); + // Compare: if shuffled value matches input, we found \t, \n, or \r + __m128i matches = _mm_cmpeq_epi8(shuffled, word); + running = _mm_or_si128(running, matches); + } + if (i < user_input.size()) { + __m128i word = _mm_loadu_si128( + (const __m128i*)(user_input.data() + user_input.length() - 16)); + __m128i shuffled = _mm_shuffle_epi8(rnt, word); + __m128i matches = _mm_cmpeq_epi8(shuffled, word); + running = _mm_or_si128(running, matches); + } + return _mm_movemask_epi8(running) != 0; +} +#elif ADA_NEON +ada_really_inline bool has_tabs_or_newline( + std::string_view user_input) noexcept { + // first check for short strings in which case we do it naively. + if (user_input.size() < 16) { // slow path + return std::ranges::any_of(user_input, is_tabs_or_newline); + } + // fast path for long strings (expected to be common) + size_t i = 0; + /** + * The fastest way to check for `\t` (==9), '\n'(== 10) and `\r` (==13) relies + * on table lookup instruction. We notice that these are all unique numbers + * between 0..15. Let's prepare a special register, where we put '\t' in the + * 9th position, '\n' - 10th and '\r' - 13th. Then we shuffle this register by + * input register. If the input had `\t` in position X then this shuffled + * register will also have '\t' in that position. Comparing input with this + * shuffled register will mark us all interesting characters in the input. + * + * credit for algorithmic idea: @aqrit, credit for description: + * @DenisYaroshevskiy + */ + static uint8_t rnt_array[16] = {1, 0, 0, 0, 0, 0, 0, 0, + 0, 9, 10, 0, 0, 13, 0, 0}; + const uint8x16_t rnt = vld1q_u8(rnt_array); + // m['0xd', '0xa', '0x9'] + uint8x16_t running{0}; + for (; i + 15 < user_input.size(); i += 16) { + uint8x16_t word = vld1q_u8((const uint8_t*)user_input.data() + i); + + running = vorrq_u8(running, vceqq_u8(vqtbl1q_u8(rnt, word), word)); + } + if (i < user_input.size()) { + uint8x16_t word = + vld1q_u8((const uint8_t*)user_input.data() + user_input.length() - 16); + running = vorrq_u8(running, vceqq_u8(vqtbl1q_u8(rnt, word), word)); + } + return vmaxvq_u32(vreinterpretq_u32_u8(running)) != 0; +} +#elif ADA_SSE2 +ada_really_inline bool has_tabs_or_newline( + std::string_view user_input) noexcept { + // first check for short strings in which case we do it naively. + if (user_input.size() < 16) { // slow path + return std::ranges::any_of(user_input, is_tabs_or_newline); + } + // fast path for long strings (expected to be common) + size_t i = 0; + const __m128i mask1 = _mm_set1_epi8('\r'); + const __m128i mask2 = _mm_set1_epi8('\n'); + const __m128i mask3 = _mm_set1_epi8('\t'); + // If we supported SSSE3, we could use the algorithm that we use for NEON. + __m128i running{0}; + for (; i + 15 < user_input.size(); i += 16) { + __m128i word = _mm_loadu_si128((const __m128i*)(user_input.data() + i)); + running = _mm_or_si128( + _mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1), + _mm_cmpeq_epi8(word, mask2))), + _mm_cmpeq_epi8(word, mask3)); + } + if (i < user_input.size()) { + __m128i word = _mm_loadu_si128( + (const __m128i*)(user_input.data() + user_input.length() - 16)); + running = _mm_or_si128( + _mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1), + _mm_cmpeq_epi8(word, mask2))), + _mm_cmpeq_epi8(word, mask3)); + } + return _mm_movemask_epi8(running) != 0; +} +#elif ADA_LSX +ada_really_inline bool has_tabs_or_newline( + std::string_view user_input) noexcept { + // first check for short strings in which case we do it naively. + if (user_input.size() < 16) { // slow path + return std::ranges::any_of(user_input, is_tabs_or_newline); + } + // fast path for long strings (expected to be common) + size_t i = 0; + const __m128i mask1 = __lsx_vrepli_b('\r'); + const __m128i mask2 = __lsx_vrepli_b('\n'); + const __m128i mask3 = __lsx_vrepli_b('\t'); + // If we supported SSSE3, we could use the algorithm that we use for NEON. + __m128i running{0}; + for (; i + 15 < user_input.size(); i += 16) { + __m128i word = __lsx_vld((const __m128i*)(user_input.data() + i), 0); + running = __lsx_vor_v( + __lsx_vor_v(running, __lsx_vor_v(__lsx_vseq_b(word, mask1), + __lsx_vseq_b(word, mask2))), + __lsx_vseq_b(word, mask3)); + } + if (i < user_input.size()) { + __m128i word = __lsx_vld( + (const __m128i*)(user_input.data() + user_input.length() - 16), 0); + running = __lsx_vor_v( + __lsx_vor_v(running, __lsx_vor_v(__lsx_vseq_b(word, mask1), + __lsx_vseq_b(word, mask2))), + __lsx_vseq_b(word, mask3)); + } + if (__lsx_bz_v(running)) return false; + return true; +} +#elif ADA_RVV +ada_really_inline bool has_tabs_or_newline( + std::string_view user_input) noexcept { + uint8_t* src = (uint8_t*)user_input.data(); + for (size_t vl, n = user_input.size(); n > 0; n -= vl, src += vl) { + vl = __riscv_vsetvl_e8m1(n); + vuint8m1_t v = __riscv_vle8_v_u8m1(src, vl); + vbool8_t m1 = __riscv_vmseq(v, '\r', vl); + vbool8_t m2 = __riscv_vmseq(v, '\n', vl); + vbool8_t m3 = __riscv_vmseq(v, '\t', vl); + vbool8_t m = __riscv_vmor(__riscv_vmor(m1, m2, vl), m3, vl); + long idx = __riscv_vfirst(m, vl); + if (idx >= 0) return true; + } + return false; +} +#else +ada_really_inline bool has_tabs_or_newline( + std::string_view user_input) noexcept { + auto has_zero_byte = [](uint64_t v) { + return ((v - 0x0101010101010101) & ~(v) & 0x8080808080808080); + }; + size_t i = 0; + uint64_t mask1 = broadcast('\r'); + uint64_t mask2 = broadcast('\n'); + uint64_t mask3 = broadcast('\t'); + uint64_t running{0}; + for (; i + 7 < user_input.size(); i += 8) { + uint64_t word{}; + memcpy(&word, user_input.data() + i, sizeof(word)); + uint64_t xor1 = word ^ mask1; + uint64_t xor2 = word ^ mask2; + uint64_t xor3 = word ^ mask3; + running |= has_zero_byte(xor1) | has_zero_byte(xor2) | has_zero_byte(xor3); + } + if (i < user_input.size()) { + uint64_t word{}; + memcpy(&word, user_input.data() + i, user_input.size() - i); + uint64_t xor1 = word ^ mask1; + uint64_t xor2 = word ^ mask2; + uint64_t xor3 = word ^ mask3; + running |= has_zero_byte(xor1) | has_zero_byte(xor2) | has_zero_byte(xor3); + } + return running; +} +#endif + +// A forbidden host code point is U+0000 NULL, U+0009 TAB, U+000A LF, U+000D CR, +// U+0020 SPACE, U+0023 (#), U+002F (/), U+003A (:), U+003C (<), U+003E (>), +// U+003F (?), U+0040 (@), U+005B ([), U+005C (\), U+005D (]), U+005E (^), or +// U+007C (|). +constexpr static std::array is_forbidden_host_code_point_table = + []() consteval { + std::array result{}; + for (uint8_t c : {'\0', '\x09', '\x0a', '\x0d', ' ', '#', '/', ':', '<', + '>', '?', '@', '[', '\\', ']', '^', '|'}) { + result[c] = true; + } + return result; + }(); + +ada_really_inline constexpr bool is_forbidden_host_code_point( + const char c) noexcept { + return is_forbidden_host_code_point_table[uint8_t(c)]; +} + +constexpr static std::array is_forbidden_domain_code_point_table = + []() consteval { + std::array result{}; + for (uint8_t c : {'\0', '\x09', '\x0a', '\x0d', ' ', '#', '/', ':', '<', + '>', '?', '@', '[', '\\', ']', '^', '|', '%'}) { + result[c] = true; + } + for (uint8_t c = 0; c <= 32; c++) { + result[c] = true; + } + for (size_t c = 127; c < 256; c++) { + result[c] = true; + } + return result; + }(); + +static_assert(sizeof(is_forbidden_domain_code_point_table) == 256); + +ada_really_inline constexpr bool is_forbidden_domain_code_point( + const char c) noexcept { + return is_forbidden_domain_code_point_table[uint8_t(c)]; +} + +ada_really_inline constexpr bool contains_forbidden_domain_code_point( + const char* input, size_t length) noexcept { + size_t i = 0; + uint8_t accumulator{}; + for (; i + 4 <= length; i += 4) { + accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i])]; + accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 1])]; + accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 2])]; + accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 3])]; + } + for (; i < length; i++) { + accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i])]; + } + return accumulator; +} + +constexpr static std::array + is_forbidden_domain_code_point_table_or_upper = []() consteval { + std::array result{}; + for (uint8_t c : {'\0', '\x09', '\x0a', '\x0d', ' ', '#', '/', ':', '<', + '>', '?', '@', '[', '\\', ']', '^', '|', '%'}) { + result[c] = 1; + } + for (uint8_t c = 'A'; c <= 'Z'; c++) { + result[c] = 2; + } + for (uint8_t c = 0; c <= 32; c++) { + result[c] = 1; + } + for (size_t c = 127; c < 256; c++) { + result[c] = 1; + } + return result; + }(); + +ada_really_inline constexpr uint8_t +contains_forbidden_domain_code_point_or_upper(const char* input, + size_t length) noexcept { + size_t i = 0; + uint8_t accumulator{}; + for (; i + 4 <= length; i += 4) { + accumulator |= + is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])]; + accumulator |= + is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 1])]; + accumulator |= + is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 2])]; + accumulator |= + is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 3])]; + } + for (; i < length; i++) { + accumulator |= + is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])]; + } + return accumulator; +} + +// std::isalnum(c) || c == '+' || c == '-' || c == '.') is true for +constexpr static std::array is_alnum_plus_table = []() consteval { + std::array result{}; + for (size_t c = 0; c < 256; c++) { + result[c] = (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || c == '+' || c == '-' || c == '.'; + } + return result; +}(); + +ada_really_inline constexpr bool is_alnum_plus(const char c) noexcept { + return is_alnum_plus_table[uint8_t(c)]; + // A table is almost surely much faster than the + // following under most compilers: return + // return (std::isalnum(c) || c == '+' || c == '-' || c == '.'); +} + +ada_really_inline constexpr bool is_ascii_hex_digit(const char c) noexcept { + return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || + (c >= 'a' && c <= 'f'); +} + +ada_really_inline constexpr bool is_ascii_digit(const char c) noexcept { + // An ASCII digit is a code point in the range U+0030 (0) to U+0039 (9), + // inclusive. + return (c >= '0' && c <= '9'); +} + +ada_really_inline constexpr bool is_ascii(const char32_t c) noexcept { + // If code point is between U+0000 and U+007F inclusive, then return true. + return c <= 0x7F; +} + +ada_really_inline constexpr bool is_c0_control_or_space(const char c) noexcept { + return (unsigned char)c <= ' '; +} + +ada_really_inline constexpr bool is_ascii_tab_or_newline( + const char c) noexcept { + return c == '\t' || c == '\n' || c == '\r'; +} + +constexpr std::string_view table_is_double_dot_path_segment[] = { + "..", "%2e.", ".%2e", "%2e%2e"}; + +ada_really_inline constexpr bool is_double_dot_path_segment( + std::string_view input) noexcept { + // This will catch most cases: + // The length must be 2,4 or 6. + // We divide by two and require + // that the result be between 1 and 3 inclusively. + uint64_t half_length = uint64_t(input.size()) / 2; + if (half_length - 1 > 2) { + return false; + } + // We have a string of length 2, 4 or 6. + // We now check the first character: + if ((input[0] != '.') && (input[0] != '%')) { + return false; + } + // We are unlikely the get beyond this point. + int hash_value = (input.size() + (unsigned)(input[0])) & 3; + const std::string_view target = table_is_double_dot_path_segment[hash_value]; + if (target.size() != input.size()) { + return false; + } + // We almost never get here. + // Optimizing the rest is relatively unimportant. + auto prefix_equal_unsafe = [](std::string_view a, std::string_view b) { + uint16_t A, B; + memcpy(&A, a.data(), sizeof(A)); + memcpy(&B, b.data(), sizeof(B)); + return A == B; + }; + if (!prefix_equal_unsafe(input, target)) { + return false; + } + for (size_t i = 2; i < input.size(); i++) { + char c = input[i]; + if ((uint8_t((c | 0x20) - 0x61) <= 25 ? (c | 0x20) : c) != target[i]) { + return false; + } + } + return true; + // The above code might be a bit better than the code below. Compilers + // are not stupid and may use the fact that these strings have length 2,4 and + // 6 and other tricks. + // return input == ".." || + // input == ".%2e" || input == ".%2E" || + // input == "%2e." || input == "%2E." || + // input == "%2e%2e" || input == "%2E%2E" || input == "%2E%2e" || input == + // "%2e%2E"; +} + +ada_really_inline constexpr bool is_single_dot_path_segment( + std::string_view input) noexcept { + return input == "." || input == "%2e" || input == "%2E"; +} + +ada_really_inline constexpr bool is_lowercase_hex(const char c) noexcept { + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'); +} + +constexpr static char hex_to_binary_table[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, + 12, 13, 14, 15, 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, 10, 11, 12, 13, 14, 15}; +unsigned constexpr convert_hex_to_binary(const char c) noexcept { + return hex_to_binary_table[c - '0']; +} + +std::string percent_decode(const std::string_view input, size_t first_percent) { + // next line is for safety only, we expect users to avoid calling + // percent_decode when first_percent is outside the range. + if (first_percent == std::string_view::npos) { + return std::string(input); + } + std::string dest; + dest.reserve(input.length()); + dest.append(input.substr(0, first_percent)); + const char* pointer = input.data() + first_percent; + const char* end = input.data() + input.size(); + // Optimization opportunity: if the following code gets + // called often, it can be optimized quite a bit. + while (pointer < end) { + const char ch = pointer[0]; + size_t remaining = end - pointer - 1; + if (ch != '%' || remaining < 2 || + ( // ch == '%' && // It is unnecessary to check that ch == '%'. + (!is_ascii_hex_digit(pointer[1]) || + !is_ascii_hex_digit(pointer[2])))) { + dest += ch; + pointer++; + } else { + unsigned a = convert_hex_to_binary(pointer[1]); + unsigned b = convert_hex_to_binary(pointer[2]); + char c = static_cast(a * 16 + b); + dest += c; + pointer += 3; + } + } + return dest; +} + +// 0..15 for hex digits, 0xFF otherwise - validate and decode with two loads. +constexpr static std::array unhex_table = []() consteval { + std::array t{}; + for (size_t i = 0; i < 256; ++i) { + t[i] = 0xFF; + } + for (uint8_t i = 0; i < 10; ++i) { + t[static_cast('0') + i] = i; + } + for (uint8_t i = 0; i < 6; ++i) { + t[static_cast('A') + i] = static_cast(10 + i); + t[static_cast('a') + i] = static_cast(10 + i); + } + return t; +}(); + +std::string form_urlencoded_decode(const std::string_view input) { + const size_t len = input.size(); + if (len == 0) [[unlikely]] { + return {}; + } + + // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage) + const char* const src = input.data(); + const char* const end = src + len; + const char* p = src; + + // Advance over the untransformed prefix. + while (p < end && *p != '+' && *p != '%') { + ++p; + } + if (p == end) { + return std::string(input); + } + + // Output is always at most as long as the input: write into a single + // pre-sized buffer, then shrink to the final length. + std::string out(len, '\0'); + char* d = out.data(); + char* const d0 = d; + + const size_t prefix = static_cast(p - src); + std::memcpy(d, src, prefix); + d += prefix; + + while (p < end) { + const char c = *p; + if (c == '+') { + *d++ = ' '; + ++p; + } else if (c == '%') { + // Decode runs of valid %XX tightly (common for nested URL query values). + while (p + 2 < end && *p == '%') { + const uint8_t hi = unhex_table[static_cast(p[1])]; + const uint8_t lo = unhex_table[static_cast(p[2])]; + if ((hi | lo) >= 16) { + break; + } + *d++ = static_cast((hi << 4) | lo); + p += 3; + } + if (p < end && *p == '%') { + // Invalid escape: copy '%' literally and continue. + *d++ = *p++; + } + } else { + // Copy a plain run until the next '+' or '%'. + const char* start = p; + ++p; + while (p < end && *p != '+' && *p != '%') { + ++p; + } + const size_t n = static_cast(p - start); + std::memcpy(d, start, n); + d += n; + } + } + + out.resize(static_cast(d - d0)); + return out; +} + +std::string percent_encode(const std::string_view input, + const uint8_t character_set[]) { + auto pointer = std::ranges::find_if(input, [character_set](const char c) { + return character_sets::bit_at(character_set, c); + }); + // Optimization: Don't iterate if percent encode is not required + if (pointer == input.end()) { + return std::string(input); + } + + std::string result; + result.reserve(input.length()); // in the worst case, percent encoding might + // produce 3 characters. + result.append(input.substr(0, std::distance(input.begin(), pointer))); + + for (; pointer != input.end(); pointer++) { + if (character_sets::bit_at(character_set, *pointer)) { + result.append(character_sets::hex + uint8_t(*pointer) * 4, 3); + } else { + result += *pointer; + } + } + + return result; +} + +template +bool percent_encode(const std::string_view input, const uint8_t character_set[], + std::string& out) { + ada_log("percent_encode ", input, " to output string while ", + append ? "appending" : "overwriting"); + auto pointer = std::ranges::find_if(input, [character_set](const char c) { + return character_sets::bit_at(character_set, c); + }); + ada_log("percent_encode done checking, moved to ", + std::distance(input.begin(), pointer)); + + // Optimization: Don't iterate if percent encode is not required + if (pointer == input.end()) { + ada_log("percent_encode encoding not needed."); + return false; + } + if constexpr (!append) { + out.clear(); + } + ada_log("percent_encode appending ", std::distance(input.begin(), pointer), + " bytes"); + // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage) + out.append(input.data(), std::distance(input.begin(), pointer)); + ada_log("percent_encode processing ", std::distance(pointer, input.end()), + " bytes"); + for (; pointer != input.end(); pointer++) { + if (character_sets::bit_at(character_set, *pointer)) { + out.append(character_sets::hex + uint8_t(*pointer) * 4, 3); + } else { + out += *pointer; + } + } + return true; +} + +bool to_ascii(std::optional& out, const std::string_view plain, + size_t first_percent) { + std::string percent_decoded_buffer; + std::string_view input = plain; + if (first_percent != std::string_view::npos) { + percent_decoded_buffer = unicode::percent_decode(plain, first_percent); + input = percent_decoded_buffer; + } + // input is a non-empty UTF-8 string, must be percent decoded + std::string idna_ascii = ada::idna::to_ascii(input); + if (idna_ascii.empty() || contains_forbidden_domain_code_point( + idna_ascii.data(), idna_ascii.size())) { + return false; + } + out = std::move(idna_ascii); + return true; +} + +std::string percent_encode(const std::string_view input, + const uint8_t character_set[], size_t index) { + std::string out; + // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage) + out.append(input.data(), index); + auto pointer = input.begin() + index; + for (; pointer != input.end(); pointer++) { + if (character_sets::bit_at(character_set, *pointer)) { + out.append(character_sets::hex + uint8_t(*pointer) * 4, 3); + } else { + out += *pointer; + } + } + return out; +} + +} // namespace ada::unicode +/* end file src/unicode.cpp */ +/* begin file src/serializers.cpp */ + +#include +#include +#include +#include + +namespace ada::serializers { +namespace { + +// Digit pair LUT for fast decimal write: index 0..99 -> two chars. +constexpr std::array make_digit_pairs() noexcept { + std::array t{}; + for (size_t i = 0; i < 100; ++i) { + t[i * 2] = static_cast('0' + i / 10); + t[i * 2 + 1] = static_cast('0' + i % 10); + } + return t; +} + +constexpr auto digit_pairs = make_digit_pairs(); + +ada_really_inline char* write_u8(char* p, uint8_t v) noexcept { + if (v < 10) { + *p++ = static_cast('0' + v); + } else if (v < 100) { + std::memcpy(p, &digit_pairs[static_cast(v) * 2], 2); + p += 2; + } else { + *p++ = static_cast('0' + v / 100); + std::memcpy(p, &digit_pairs[static_cast(v % 100) * 2], 2); + p += 2; + } + return p; +} + +ada_really_inline char* write_hex_u16(char* p, uint16_t v) noexcept { + static constexpr char kHex[] = "0123456789abcdef"; + if (v >= 0x1000) { + *p++ = kHex[(v >> 12) & 0xf]; + *p++ = kHex[(v >> 8) & 0xf]; + *p++ = kHex[(v >> 4) & 0xf]; + *p++ = kHex[v & 0xf]; + } else if (v >= 0x100) { + *p++ = kHex[(v >> 8) & 0xf]; + *p++ = kHex[(v >> 4) & 0xf]; + *p++ = kHex[v & 0xf]; + } else if (v >= 0x10) { + *p++ = kHex[(v >> 4) & 0xf]; + *p++ = kHex[v & 0xf]; + } else { + *p++ = kHex[v & 0xf]; + } + return p; +} + +} // namespace + +void find_longest_sequence_of_ipv6_pieces( + const std::array& address, size_t& compress, + size_t& compress_length) noexcept { + compress = 0; + compress_length = 0; + size_t i = 0; + while (i < 8) { + if (address[i] != 0) { + ++i; + continue; + } + size_t next = i + 1; + while (next < 8 && address[next] == 0) { + ++next; + } + const size_t count = next - i; + if (count > compress_length) { + compress_length = count; + compress = i; + } + i = next; + } +} + +std::string ipv6(const std::array& address) { + size_t compress = 0; + size_t compress_length = 0; + find_longest_sequence_of_ipv6_pieces(address, compress, compress_length); + + // Skip compression when the longest zero run is a single piece. + if (compress_length <= 1) { + compress = compress_length = 8; + } + + // Max: '[' + 8*4 hex + 7 ':' + ']' = 41 + std::string output(4 * 8 + 7 + 2, '\0'); + char* point = output.data(); + *point++ = '['; + size_t piece_index = 0; + while (true) { + if (piece_index == compress) { + *point++ = ':'; + // If we skip a value initially, we need to write '::'. + if (piece_index == 0) { + *point++ = ':'; + } + piece_index += compress_length; + if (piece_index == 8) { + break; + } + } + point = write_hex_u16(point, address[piece_index]); + ++piece_index; + if (piece_index == 8) { + break; + } + *point++ = ':'; + } + *point++ = ']'; + output.resize(static_cast(point - output.data())); + return output; +} + +std::string ipv4(const uint64_t address) { + std::string output(15, '\0'); + char* point = output.data(); + point = write_u8(point, static_cast(address >> 24)); + *point++ = '.'; + point = write_u8(point, static_cast(address >> 16)); + *point++ = '.'; + point = write_u8(point, static_cast(address >> 8)); + *point++ = '.'; + point = write_u8(point, static_cast(address)); + output.resize(static_cast(point - output.data())); + return output; +} + +} // namespace ada::serializers +/* end file src/serializers.cpp */ +/* begin file src/implementation.cpp */ + +#include +#include +#include +#include + + +namespace ada { + +static std::atomic max_input_length_{ + std::numeric_limits::max()}; + +void set_max_input_length(uint32_t length) { + max_input_length_.store(length, std::memory_order_relaxed); +} + +uint32_t get_max_input_length() { + return max_input_length_.load(std::memory_order_relaxed); +} + +namespace { + +// @private +// Fast-path validator for can_parse. +// +// Validates absolute special (non-file) URLs without constructing any +// url_aggregator object and without running the state machine. +// Performs a single forward scan over the input bytes. +// +// Returns: +// true -- URL is structurally valid +// false -- URL is definitely invalid +// nullopt -- edge case; fall through to the full parser +// (credentials, IDNA, IPv4/6, tabs/newlines, relative URLs, ...) +std::optional try_can_parse_absolute_fast( + std::string_view input) noexcept { + const uint8_t* b = reinterpret_cast(input.data()); + size_t len = input.size(); + + // -- Inline C0 whitespace trim (no allocation) -------------------------- + // Note: \t (0x09), \n (0x0a), \r (0x0d) are all <= 0x20, so any + // leading/trailing tabs or newlines are correctly stripped here, matching + // the WHATWG spec's "remove leading/trailing C0 control and space" step. + while (len > 0 && b[0] <= 0x20) { + b++; + len--; + } + while (len > 0 && b[len - 1] <= 0x20) { + len--; + } + if (len == 0) return false; + + // -- Scheme detection ----------------------------------------------------- + // Fast path for HTTP and HTTPS (covers ~90%+ of real-world URLs). + // Avoids the general scheme loop, buffer copy, and perfect hash lookup. + // We know HTTP and HTTPS are special non-file schemes, so no further + // scheme_type checks are needed on the fast path -- only `pos` matters. + size_t pos; + + if (len >= 7 && (b[0] | 0x20) == 'h' && (b[1] | 0x20) == 't' && + (b[2] | 0x20) == 't' && (b[3] | 0x20) == 'p') { + if (b[4] == ':' && b[5] == '/' && b[6] == '/') { + pos = 7; + goto skip_extra_slashes; + } + if (len >= 8 && (b[4] | 0x20) == 's' && b[5] == ':' && b[6] == '/' && + b[7] == '/') { + pos = 8; + goto skip_extra_slashes; + } + // Fall through: could be "httpe://", tabs in scheme, etc. + } + + { + // General scheme detection for ws, wss, ftp, and edge cases. + if (!checkers::is_alpha(static_cast(b[0]))) return false; + + // Scan for ':' within the first 7 bytes. All special schemes are <= 5 + // chars ("https"), so any URL whose first ':' is beyond byte 6 is either + // non-special or relative -- both require the full parser. + size_t colon_pos = 0; + for (size_t i = 1;; ++i) { + if (i >= 7 || i >= len) return std::nullopt; + const char c = static_cast(b[i]); + if (c == ':') { + colon_pos = i; + break; + } + // Tabs/newlines in the scheme require the full parser to strip them. + if (c == '\t' || c == '\n' || c == '\r') return std::nullopt; + if (!unicode::is_alnum_plus(c)) return false; + } + + // Lowercase scheme bytes inline and classify via the existing perfect + // hash. + char scheme_buf[6]; + scheme_buf[0] = static_cast(b[0] | 0x20); + for (size_t i = 1; i < colon_pos; ++i) + scheme_buf[i] = static_cast(b[i] | 0x20); + + const ada::scheme::type scheme_type = + ada::scheme::get_scheme_type({scheme_buf, colon_pos}); + + // Only handle special, non-file schemes. + if (scheme_type == ada::scheme::NOT_SPECIAL) return std::nullopt; + if (scheme_type == ada::scheme::FILE) return std::nullopt; + + // Per WHATWG, special URLs don't require "//": "http:example.com" is valid + // (SPECIAL_AUTHORITY_IGNORE_SLASHES just skips leading slashes and + // proceeds to AUTHORITY). Defer to the inline fallback for any input + // without "://". + pos = colon_pos + 1; + if (pos + 2 > len || b[pos] != '/' || b[pos + 1] != '/') { + return std::nullopt; + } + pos += 2; + } + +skip_extra_slashes: + // SPECIAL_AUTHORITY_IGNORE_SLASHES: the full parser skips any additional + // leading '/' or '\' after the initial "//". Mirror that here so we don't + // mis-identify the host as empty when there are extra slashes. + while (pos < len && (b[pos] == '/' || b[pos] == '\\')) { + ++pos; + } + + // Early IPv6 bail-out: if the authority starts with '[', it's an IPv6 + // literal which requires the full parser. Checking here avoids scanning + // the entire bracketed address only to bail out afterward. + if (pos < len && b[pos] == '[') return std::nullopt; + + // -- Merged authority + host scan ------------------------------------------ + // A single forward pass over the authority bytes that simultaneously: + // - finds the authority end and port colon + // - validates host characters (forbidden domain code points) + // - tracks IPv4 indicators (all-decimal-dots, last non-dot char) + // - detects xn-- prefixes (IDNA punycode) + // - detects tabs/newlines (which require the full parser to strip) + // This replaces 4 separate scans over the host bytes. + const size_t auth_start = pos; + size_t auth_end = pos; + size_t port_colon = SIZE_MAX; + bool all_dec_dots = true; + uint8_t last_non_dot = 0; + + for (; auth_end < len; ++auth_end) { + const uint8_t c = b[auth_end]; + + // Non-ASCII -> needs IDNA processing -> full parser. + if (c >= 0x80) return std::nullopt; + + // Authority delimiters. + if (c == '/' || c == '?' || c == '#' || c == '\\') break; + + // Port separator. + if (c == ':') { + if (port_colon == SIZE_MAX) port_colon = auth_end; + continue; + } + + // Credentials or percent-encoding -> full parser. + if (c == '@' || c == '%') return std::nullopt; + + // Tabs/newlines anywhere in the authority require the full parser to + // strip them before validation. Without this, a tab in the port (e.g. + // "http://host:8\t0/") would be mis-rejected by port validation. + if (c == '\t' || c == '\n' || c == '\r') return std::nullopt; + + // Skip remaining host-specific checks for port bytes. Port digits are + // validated separately below, and no forbidden-domain-code-point check + // is needed on port characters. + if (port_colon != SIZE_MAX) continue; + + // -- Host byte validation (inlined) ------------------------------------ + // Forbidden domain code points that are not already caught above: + // C0 controls and space (0x00-0x20), DEL (0x7F), <, >, [, ], ^, |. + // At this stage, the input may still be userinfo or be normalized later + // (e.g., percent-encoded), so we do not reject here and defer to the + // parser. Characters already caught: >= 0x80 (non-ASCII), '/' '?' '#' '\\' + // (delimiters), ':' (port), '@' '%' (bail), '\t' '\n' '\r' (bail). + if (c <= 0x20 || c == 0x7F || c == '<' || c == '>' || c == '[' || + c == ']' || c == '^' || c == '|') { + return std::nullopt; + } + + // Track whether host is all decimal digits and dots (potential IPv4). + if (c != '.' && (c < '0' || c > '9')) all_dec_dots = false; + + // Track last non-dot character for the IPv4 hex/octal heuristic. + if (c != '.') last_non_dot = c; + + // Detect xn-- prefix inline (IDNA punycode -> needs full parser). + // Checking at every position mirrors the original behavior: any + // occurrence of "xn--" in the host (not just at label boundaries) + // triggers a bail-out to the full IDNA validator. + if ((c | 0x20) == 'x' && auth_end + 4 <= len && + (b[auth_end + 1] | 0x20) == 'n' && b[auth_end + 2] == '-' && + b[auth_end + 3] == '-') { + return std::nullopt; + } + } + + const size_t host_end = (port_colon != SIZE_MAX) ? port_colon : auth_end; + + // Empty host is invalid for special URLs. + if (auth_start == host_end) return false; + + // -- IPv4 handling --------------------------------------------------------- + const char* host_ptr = reinterpret_cast(b + auth_start); + const size_t host_len = host_end - auth_start; + + if (all_dec_dots) { + // Host is all decimal digits and dots -> try the fast IPv4 parser. + if (checkers::try_parse_ipv4_fast({host_ptr, host_len}) != + checkers::ipv4_fast_fail) { + // Valid decimal IPv4 host. Do NOT return true yet: the port still + // needs to be validated below before we can declare the URL valid. + goto validate_port; + } + // Fast IPv4 parsing failed (e.g. host is ".", "..", "1.2.3.500"). + // Such hosts may still be valid domain names; defer to the full parser. + return std::nullopt; + } + + // Last-significant-character heuristic for non-decimal IPv4 (hex/octal): + // if the last non-dot char is a digit, 'a'-'f', or 'x' the host might be + // an IPv4 address that the fast path can't validate -- fall through. + // last_non_dot was tracked during the authority scan above. + { + const uint8_t lc = last_non_dot | 0x20; + if ((last_non_dot >= '0' && last_non_dot <= '9') || + (lc >= 'a' && lc <= 'f') || lc == 'x') { + return std::nullopt; + } + } + + // -- Port validation ------------------------------------------------------- +validate_port: + if (port_colon != SIZE_MAX) { + const uint8_t* pp = b + port_colon + 1; + size_t pl = auth_end - port_colon - 1; + if (pl > 0) { + // Strip leading zeros: "0000001" == 1, "0000000000000" == 0, both valid. + // Only the significant digits count toward the 5-digit maximum. + while (pl > 0 && *pp == '0') { + ++pp; + --pl; + } + if (pl > 5) return false; // significant digits > 99999 + uint32_t pv = 0; + for (size_t i = 0; i < pl; ++i) { + if (pp[i] < '0' || pp[i] > '9') return false; + pv = pv * 10 + (pp[i] - '0'); + } + if (pv > 65535) return false; + } + } + + // Path, query, and fragment are structurally always valid for can_parse -- + // the parser would encode whatever is there. + return true; +} + +} // namespace + +template +ada_warn_unused tl::expected parse( + std::string_view input, const result_type* base_url) { + result_type u = ada::parser::parse_url_impl(input, base_url); + if (!u.is_valid) { + return tl::unexpected(errors::type_error); + } + return u; +} + +template ada::result parse(std::string_view input, + const url* base_url = nullptr); +template ada::result parse( + std::string_view input, const url_aggregator* base_url = nullptr); + +std::string href_from_file(std::string_view input) { + // Match ada::parse / setters: refuse inputs that already exceed the limit. + // Path percent-encoding can still expand the result, so we also check the + // final href below. + const uint32_t max_length = ada::get_max_input_length(); + if (input.size() > max_length) { + return {}; + } + + // This is going to be much faster than constructing a URL. + std::string tmp_buffer; + std::string_view internal_input; + if (unicode::has_tabs_or_newline(input)) { + tmp_buffer = input; + helpers::remove_ascii_tab_or_newline(tmp_buffer); + internal_input = tmp_buffer; + } else { + internal_input = input; + } + std::string path; + if (internal_input.empty()) { + path = "/"; + } else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) { + helpers::parse_prepared_path(internal_input.substr(1), + ada::scheme::type::FILE, path); + } else { + helpers::parse_prepared_path(internal_input, ada::scheme::type::FILE, path); + } + std::string result = "file://" + path; + if (result.size() > max_length) { + return {}; + } + return result; +} + +bool can_parse(std::string_view input, const std::string_view* base_input) { + // Must match parse().has_value(), including post-normalization max length. + // Percent-encoding expands a byte by at most 3x, but IDNA expands more: a + // 3-byte UTF-8 label such as U+337F becomes the 17-byte "xn--6oqv20b1zgzxr", + // so a dotted host sustains 4.5x. When the input (plus base, if any) fits in + // max_length/5, the normalized href cannot exceed max_length, so + // validation-only parsing (store_values=false) is safe. + + // Hot path first: absolute special URLs, no base. Avoid loading max_length + // until we need it (common absolute-fast true/false cases). + if (base_input == nullptr) { + if (const auto r = try_can_parse_absolute_fast(input)) { + if (!*r) { + return false; + } + // size <= max/5 => normalized href cannot exceed max (4.5x expansion). + // Check this first: default max is ~4GB so almost all URLs return true. + const uint32_t max_length = ada::get_max_input_length(); + if (input.size() <= static_cast(max_length) / 5) { + return true; + } + if (input.size() > max_length) { + return false; + } + return ada::parser::parse_url_impl(input, + nullptr) + .is_valid; + } + } + + const uint32_t max_length = ada::get_max_input_length(); + if (input.size() > max_length) { + return false; + } + if (base_input != nullptr && base_input->size() > max_length) { + return false; + } + + // Relative resolution combines base + input; bound the sum so 4.5x expansion + // of either side cannot push the final href past max_length. + const size_t combined = + input.size() + (base_input == nullptr ? 0 : base_input->size()); + const bool size_safe = combined <= static_cast(max_length) / 5; + + if (size_safe) { + // Validation-only: no buffer build, host still fully checked. + ada::url_aggregator base_agg; + ada::url_aggregator* base_ptr = nullptr; + if (base_input != nullptr) { + base_agg = ada::parser::parse_url_impl( + *base_input, nullptr); + if (!base_agg.is_valid) { + return false; + } + base_ptr = &base_agg; + } + return ada::parser::parse_url_impl(input, + base_ptr) + .is_valid; + } + + // Near the limit: full parse so post-normalization length matches parse(). + if (base_input == nullptr) { + return ada::parser::parse_url_impl(input, + nullptr) + .is_valid; + } + ada::url_aggregator base_agg = + ada::parser::parse_url_impl(*base_input, + nullptr); + if (!base_agg.is_valid) { + return false; + } + return ada::parser::parse_url_impl(input, + &base_agg) + .is_valid; +} + +ada_warn_unused std::string_view to_string(ada::encoding_type type) { + switch (type) { + case ada::encoding_type::UTF8: + return "UTF-8"; + case ada::encoding_type::UTF_16LE: + return "UTF-16LE"; + case ada::encoding_type::UTF_16BE: + return "UTF-16BE"; + default: + unreachable(); + } +} + +} // namespace ada +/* end file src/implementation.cpp */ +/* begin file src/helpers.cpp */ +#include +#include +#include + + +#if ADA_SSSE3 +#include +#endif + +namespace ada::helpers { + +template +void encode_json(std::string_view view, out_iter out) { + // trivial implementation. could be faster. + const char* hexvalues = + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"; + for (uint8_t c : view) { + if (c == '\\') { + *out++ = '\\'; + *out++ = '\\'; + } else if (c == '"') { + *out++ = '\\'; + *out++ = '"'; + } else if (c <= 0x1f) { + *out++ = '\\'; + *out++ = 'u'; + *out++ = '0'; + *out++ = '0'; + *out++ = hexvalues[2 * c]; + *out++ = hexvalues[2 * c + 1]; + } else { + *out++ = c; + } + } +} + +ada_unused std::string get_state(ada::state s) { + switch (s) { + case ada::state::AUTHORITY: + return "Authority"; + case ada::state::SCHEME_START: + return "Scheme Start"; + case ada::state::SCHEME: + return "Scheme"; + case ada::state::HOST: + return "Host"; + case ada::state::NO_SCHEME: + return "No Scheme"; + case ada::state::FRAGMENT: + return "Fragment"; + case ada::state::RELATIVE_SCHEME: + return "Relative Scheme"; + case ada::state::RELATIVE_SLASH: + return "Relative Slash"; + case ada::state::FILE: + return "File"; + case ada::state::FILE_HOST: + return "File Host"; + case ada::state::FILE_SLASH: + return "File Slash"; + case ada::state::PATH_OR_AUTHORITY: + return "Path or Authority"; + case ada::state::SPECIAL_AUTHORITY_IGNORE_SLASHES: + return "Special Authority Ignore Slashes"; + case ada::state::SPECIAL_AUTHORITY_SLASHES: + return "Special Authority Slashes"; + case ada::state::SPECIAL_RELATIVE_OR_AUTHORITY: + return "Special Relative or Authority"; + case ada::state::QUERY: + return "Query"; + case ada::state::PATH: + return "Path"; + case ada::state::PATH_START: + return "Path Start"; + case ada::state::OPAQUE_PATH: + return "Opaque Path"; + case ada::state::PORT: + return "Port"; + default: + return "unknown state"; + } +} + +ada_really_inline std::optional prune_hash( + std::string_view& input) noexcept { + // compiles down to 20--30 instructions including a class to memchr (C + // function). this function should be quite fast. + size_t location_of_first = input.find('#'); + if (location_of_first == std::string_view::npos) { + return std::nullopt; + } + std::string_view hash = input; + hash.remove_prefix(location_of_first + 1); + input.remove_suffix(input.size() - location_of_first); + return hash; +} + +ada_really_inline bool shorten_path(std::string& path, ada::scheme::type type) { + // Let path be url's path. + // If url's scheme is "file", path's size is 1, and path[0] is a normalized + // Windows drive letter, then return. + if (type == ada::scheme::type::FILE && + path.find('/', 1) == std::string_view::npos && !path.empty()) { + if (checkers::is_normalized_windows_drive_letter( + helpers::substring(path, 1))) { + return false; + } + } + + // Remove path's last item, if any. + size_t last_delimiter = path.rfind('/'); + if (last_delimiter != std::string::npos) { + path.erase(last_delimiter); + return true; + } + + return false; +} + +ada_really_inline bool shorten_path(std::string_view& path, + ada::scheme::type type) { + // Let path be url's path. + // If url's scheme is "file", path's size is 1, and path[0] is a normalized + // Windows drive letter, then return. + if (type == ada::scheme::type::FILE && + path.find('/', 1) == std::string_view::npos && !path.empty()) { + if (checkers::is_normalized_windows_drive_letter( + helpers::substring(path, 1))) { + return false; + } + } + + // Remove path's last item, if any. + if (!path.empty()) { + size_t slash_loc = path.rfind('/'); + if (slash_loc != std::string_view::npos) { + path.remove_suffix(path.size() - slash_loc); + return true; + } + } + + return false; +} + +ada_really_inline void remove_ascii_tab_or_newline(std::string& input) { + // if this ever becomes a performance issue, we could use an approach similar + // to has_tabs_or_newline + std::erase_if(input, ada::unicode::is_ascii_tab_or_newline); +} + +ada_really_inline constexpr std::string_view substring(std::string_view input, + size_t pos) { + ADA_ASSERT_TRUE(pos <= input.size()); + // The following is safer but unneeded if we have the above line: + // return pos > input.size() ? std::string_view() : input.substr(pos); + return input.substr(pos); +} + +ada_really_inline void resize(std::string_view& input, size_t pos) noexcept { + ADA_ASSERT_TRUE(pos <= input.size()); + input.remove_suffix(input.size() - pos); +} + +// computes the number of trailing zeroes +// this is a private inline function only defined in this source file. +ada_really_inline int trailing_zeroes(uint32_t input_num) noexcept { +#ifdef ADA_REGULAR_VISUAL_STUDIO + unsigned long ret; + // Search the mask data from least significant bit (LSB) + // to the most significant bit (MSB) for a set bit (1). + _BitScanForward(&ret, input_num); + return (int)ret; +#else // ADA_REGULAR_VISUAL_STUDIO + return __builtin_ctzl(input_num); +#endif // ADA_REGULAR_VISUAL_STUDIO +} + +// starting at index location, this finds the next location of a character +// :, /, \\, ? or [. If none is found, view.size() is returned. +// For use within get_host_delimiter_location. +#if ADA_SSSE3 +ada_really_inline size_t find_next_host_delimiter_special( + std::string_view view, size_t location) noexcept { + // first check for short strings in which case we do it naively. + if (view.size() - location < 16) { // slow path + for (size_t i = location; i < view.size(); i++) { + if (view[i] == ':' || view[i] == '/' || view[i] == '\\' || + view[i] == '?' || view[i] == '[') { + return i; + } + } + return size_t(view.size()); + } + // fast path for long strings (expected to be common) + // Using SSSE3's _mm_shuffle_epi8 for table lookup (same approach as NEON) + size_t i = location; + const __m128i low_mask = + _mm_setr_epi8(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x04, 0x04, 0x00, 0x00, 0x03); + const __m128i high_mask = + _mm_setr_epi8(0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + const __m128i fmask = _mm_set1_epi8(0xf); + const __m128i zero = _mm_setzero_si128(); + for (; i + 15 < view.size(); i += 16) { + __m128i word = _mm_loadu_si128((const __m128i*)(view.data() + i)); + __m128i lowpart = _mm_shuffle_epi8(low_mask, _mm_and_si128(word, fmask)); + __m128i highpart = _mm_shuffle_epi8( + high_mask, _mm_and_si128(_mm_srli_epi16(word, 4), fmask)); + __m128i classify = _mm_and_si128(lowpart, highpart); + __m128i is_zero = _mm_cmpeq_epi8(classify, zero); + // _mm_movemask_epi8 returns a 16-bit mask in bits 0-15, with bits 16-31 + // zero. After NOT (~), bits 16-31 become 1. We must mask to 16 bits to + // avoid false positives. + int mask = ~_mm_movemask_epi8(is_zero) & 0xFFFF; + if (mask != 0) { + return i + trailing_zeroes(static_cast(mask)); + } + } + if (i < view.size()) { + __m128i word = + _mm_loadu_si128((const __m128i*)(view.data() + view.length() - 16)); + __m128i lowpart = _mm_shuffle_epi8(low_mask, _mm_and_si128(word, fmask)); + __m128i highpart = _mm_shuffle_epi8( + high_mask, _mm_and_si128(_mm_srli_epi16(word, 4), fmask)); + __m128i classify = _mm_and_si128(lowpart, highpart); + __m128i is_zero = _mm_cmpeq_epi8(classify, zero); + // _mm_movemask_epi8 returns a 16-bit mask in bits 0-15, with bits 16-31 + // zero. After NOT (~), bits 16-31 become 1. We must mask to 16 bits to + // avoid false positives. + int mask = ~_mm_movemask_epi8(is_zero) & 0xFFFF; + if (mask != 0) { + return view.length() - 16 + trailing_zeroes(static_cast(mask)); + } + } + return size_t(view.size()); +} +#elif ADA_NEON +// The ada_make_uint8x16_t macro is necessary because Visual Studio does not +// support direct initialization of uint8x16_t. See +// https://developercommunity.visualstudio.com/t/error-C2078:-too-many-initializers-whe/402911?q=backend+neon +#ifndef ada_make_uint8x16_t +#define ada_make_uint8x16_t(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, \ + x13, x14, x15, x16) \ + ([=]() { \ + static uint8_t array[16] = {x1, x2, x3, x4, x5, x6, x7, x8, \ + x9, x10, x11, x12, x13, x14, x15, x16}; \ + return vld1q_u8(array); \ + }()) +#endif + +ada_really_inline size_t find_next_host_delimiter_special( + std::string_view view, size_t location) noexcept { + // first check for short strings in which case we do it naively. + if (view.size() - location < 16) { // slow path + for (size_t i = location; i < view.size(); i++) { + if (view[i] == ':' || view[i] == '/' || view[i] == '\\' || + view[i] == '?' || view[i] == '[') { + return i; + } + } + return size_t(view.size()); + } + auto to_bitmask = [](uint8x16_t input) -> uint16_t { + uint8x16_t bit_mask = + ada_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x01, + 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80); + uint8x16_t minput = vandq_u8(input, bit_mask); + uint8x16_t tmp = vpaddq_u8(minput, minput); + tmp = vpaddq_u8(tmp, tmp); + tmp = vpaddq_u8(tmp, tmp); + return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0); + }; + + // fast path for long strings (expected to be common) + size_t i = location; + uint8x16_t low_mask = + ada_make_uint8x16_t(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x03); + uint8x16_t high_mask = + ada_make_uint8x16_t(0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + uint8x16_t fmask = vmovq_n_u8(0xf); + uint8x16_t zero{0}; + for (; i + 15 < view.size(); i += 16) { + uint8x16_t word = vld1q_u8((const uint8_t*)view.data() + i); + uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask)); + uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4)); + uint8x16_t classify = vandq_u8(lowpart, highpart); + if (vmaxvq_u32(vreinterpretq_u32_u8(classify)) != 0) { + uint8x16_t is_zero = vceqq_u8(classify, zero); + uint16_t is_non_zero = static_cast(~to_bitmask(is_zero)); + return i + trailing_zeroes(is_non_zero); + } + } + + if (i < view.size()) { + uint8x16_t word = + vld1q_u8((const uint8_t*)view.data() + view.length() - 16); + uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask)); + uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4)); + uint8x16_t classify = vandq_u8(lowpart, highpart); + if (vmaxvq_u32(vreinterpretq_u32_u8(classify)) != 0) { + uint8x16_t is_zero = vceqq_u8(classify, zero); + uint16_t is_non_zero = static_cast(~to_bitmask(is_zero)); + return view.length() - 16 + trailing_zeroes(is_non_zero); + } + } + return size_t(view.size()); +} +#elif ADA_SSE2 +ada_really_inline size_t find_next_host_delimiter_special( + std::string_view view, size_t location) noexcept { + // first check for short strings in which case we do it naively. + if (view.size() - location < 16) { // slow path + for (size_t i = location; i < view.size(); i++) { + if (view[i] == ':' || view[i] == '/' || view[i] == '\\' || + view[i] == '?' || view[i] == '[') { + return i; + } + } + return size_t(view.size()); + } + // fast path for long strings (expected to be common) + size_t i = location; + const __m128i mask1 = _mm_set1_epi8(':'); + const __m128i mask2 = _mm_set1_epi8('/'); + const __m128i mask3 = _mm_set1_epi8('\\'); + const __m128i mask4 = _mm_set1_epi8('?'); + const __m128i mask5 = _mm_set1_epi8('['); + + for (; i + 15 < view.size(); i += 16) { + __m128i word = _mm_loadu_si128((const __m128i*)(view.data() + i)); + __m128i m1 = _mm_cmpeq_epi8(word, mask1); + __m128i m2 = _mm_cmpeq_epi8(word, mask2); + __m128i m3 = _mm_cmpeq_epi8(word, mask3); + __m128i m4 = _mm_cmpeq_epi8(word, mask4); + __m128i m5 = _mm_cmpeq_epi8(word, mask5); + __m128i m = _mm_or_si128( + _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5); + int mask = _mm_movemask_epi8(m); + if (mask != 0) { + return i + trailing_zeroes(mask); + } + } + if (i < view.size()) { + __m128i word = + _mm_loadu_si128((const __m128i*)(view.data() + view.length() - 16)); + __m128i m1 = _mm_cmpeq_epi8(word, mask1); + __m128i m2 = _mm_cmpeq_epi8(word, mask2); + __m128i m3 = _mm_cmpeq_epi8(word, mask3); + __m128i m4 = _mm_cmpeq_epi8(word, mask4); + __m128i m5 = _mm_cmpeq_epi8(word, mask5); + __m128i m = _mm_or_si128( + _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5); + int mask = _mm_movemask_epi8(m); + if (mask != 0) { + return view.length() - 16 + trailing_zeroes(mask); + } + } + return size_t(view.length()); +} +#elif ADA_LSX +ada_really_inline size_t find_next_host_delimiter_special( + std::string_view view, size_t location) noexcept { + // first check for short strings in which case we do it naively. + if (view.size() - location < 16) { // slow path + for (size_t i = location; i < view.size(); i++) { + if (view[i] == ':' || view[i] == '/' || view[i] == '\\' || + view[i] == '?' || view[i] == '[') { + return i; + } + } + return size_t(view.size()); + } + // fast path for long strings (expected to be common) + size_t i = location; + const __m128i mask1 = __lsx_vrepli_b(':'); + const __m128i mask2 = __lsx_vrepli_b('/'); + const __m128i mask3 = __lsx_vrepli_b('\\'); + const __m128i mask4 = __lsx_vrepli_b('?'); + const __m128i mask5 = __lsx_vrepli_b('['); + + for (; i + 15 < view.size(); i += 16) { + __m128i word = __lsx_vld((const __m128i*)(view.data() + i), 0); + __m128i m1 = __lsx_vseq_b(word, mask1); + __m128i m2 = __lsx_vseq_b(word, mask2); + __m128i m3 = __lsx_vseq_b(word, mask3); + __m128i m4 = __lsx_vseq_b(word, mask4); + __m128i m5 = __lsx_vseq_b(word, mask5); + __m128i m = + __lsx_vor_v(__lsx_vor_v(__lsx_vor_v(m1, m2), __lsx_vor_v(m3, m4)), m5); + int mask = __lsx_vpickve2gr_hu(__lsx_vmsknz_b(m), 0); + if (mask != 0) { + return i + trailing_zeroes(mask); + } + } + if (i < view.size()) { + __m128i word = + __lsx_vld((const __m128i*)(view.data() + view.length() - 16), 0); + __m128i m1 = __lsx_vseq_b(word, mask1); + __m128i m2 = __lsx_vseq_b(word, mask2); + __m128i m3 = __lsx_vseq_b(word, mask3); + __m128i m4 = __lsx_vseq_b(word, mask4); + __m128i m5 = __lsx_vseq_b(word, mask5); + __m128i m = + __lsx_vor_v(__lsx_vor_v(__lsx_vor_v(m1, m2), __lsx_vor_v(m3, m4)), m5); + int mask = __lsx_vpickve2gr_hu(__lsx_vmsknz_b(m), 0); + if (mask != 0) { + return view.length() - 16 + trailing_zeroes(mask); + } + } + return size_t(view.length()); +} +#elif ADA_RVV +ada_really_inline size_t find_next_host_delimiter_special( + std::string_view view, size_t location) noexcept { + // The LUT approach was a bit slower on the SpacemiT X60, but I could see it + // being faster on future hardware. +#if 0 + // LUT generated using: s=":/\\?["; list(zip([((ord(c)>>2)&0xF)for c in s],s)) + static const uint8_t tbl[16] = { + 0xF, 0, 0, 0, 0, 0, '[', '\\', 0, 0, 0, '/', 0, 0, ':', '?' + }; + vuint8m1_t vtbl = __riscv_vle8_v_u8m1(tbl, 16); +#endif + uint8_t* src = (uint8_t*)view.data() + location; + for (size_t vl, n = view.size() - location; n > 0; + n -= vl, src += vl, location += vl) { + vl = __riscv_vsetvl_e8m1(n); + vuint8m1_t v = __riscv_vle8_v_u8m1(src, vl); +#if 0 + vuint8m1_t vidx = __riscv_vand(__riscv_vsrl(v, 2, vl), 0xF, vl); + vuint8m1_t vlut = __riscv_vrgather(vtbl, vidx, vl); + vbool8_t m = __riscv_vmseq(v, vlut, vl); +#else + vbool8_t m1 = __riscv_vmseq(v, ':', vl); + vbool8_t m2 = __riscv_vmseq(v, '/', vl); + vbool8_t m3 = __riscv_vmseq(v, '?', vl); + vbool8_t m4 = __riscv_vmseq(v, '[', vl); + vbool8_t m5 = __riscv_vmseq(v, '\\', vl); + vbool8_t m = __riscv_vmor( + __riscv_vmor(__riscv_vmor(m1, m2, vl), __riscv_vmor(m3, m4, vl), vl), + m5, vl); +#endif + long idx = __riscv_vfirst(m, vl); + if (idx >= 0) return location + idx; + } + return size_t(view.size()); +} +#else +// : / [ \\ ? +static constexpr std::array special_host_delimiters = + []() consteval { + std::array result{}; + for (int i : {':', '/', '[', '\\', '?'}) { + result[i] = 1; + } + return result; + }(); +// credit: @the-moisrex recommended a table-based approach +ada_really_inline size_t find_next_host_delimiter_special( + std::string_view view, size_t location) noexcept { + auto const str = view.substr(location); + for (auto pos = str.begin(); pos != str.end(); ++pos) { + if (special_host_delimiters[(uint8_t)*pos]) { + return pos - str.begin() + location; + } + } + return size_t(view.size()); +} +#endif + +// starting at index location, this finds the next location of a character +// :, /, ? or [. If none is found, view.size() is returned. +// For use within get_host_delimiter_location. +#if ADA_SSSE3 +ada_really_inline size_t find_next_host_delimiter(std::string_view view, + size_t location) noexcept { + // first check for short strings in which case we do it naively. + if (view.size() - location < 16) { // slow path + for (size_t i = location; i < view.size(); i++) { + if (view[i] == ':' || view[i] == '/' || view[i] == '?' || + view[i] == '[') { + return i; + } + } + return size_t(view.size()); + } + // fast path for long strings (expected to be common) + size_t i = location; + // Lookup tables for bit classification: + // ':' (0x3A): low[0xA]=0x01, high[0x3]=0x01 -> match + // '/' (0x2F): low[0xF]=0x02, high[0x2]=0x02 -> match + // '?' (0x3F): low[0xF]=0x01, high[0x3]=0x01 -> match + // '[' (0x5B): low[0xB]=0x04, high[0x5]=0x04 -> match + const __m128i low_mask = + _mm_setr_epi8(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x04, 0x00, 0x00, 0x00, 0x03); + const __m128i high_mask = + _mm_setr_epi8(0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + const __m128i fmask = _mm_set1_epi8(0xf); + const __m128i zero = _mm_setzero_si128(); + + for (; i + 15 < view.size(); i += 16) { + __m128i word = _mm_loadu_si128((const __m128i*)(view.data() + i)); + __m128i lowpart = _mm_shuffle_epi8(low_mask, _mm_and_si128(word, fmask)); + __m128i highpart = _mm_shuffle_epi8( + high_mask, _mm_and_si128(_mm_srli_epi16(word, 4), fmask)); + __m128i classify = _mm_and_si128(lowpart, highpart); + __m128i is_zero = _mm_cmpeq_epi8(classify, zero); + // _mm_movemask_epi8 returns a 16-bit mask in bits 0-15, with bits 16-31 + // zero. After NOT (~), bits 16-31 become 1. We must mask to 16 bits to + // avoid false positives. + int mask = ~_mm_movemask_epi8(is_zero) & 0xFFFF; + if (mask != 0) { + return i + trailing_zeroes(static_cast(mask)); + } + } + + if (i < view.size()) { + __m128i word = + _mm_loadu_si128((const __m128i*)(view.data() + view.length() - 16)); + __m128i lowpart = _mm_shuffle_epi8(low_mask, _mm_and_si128(word, fmask)); + __m128i highpart = _mm_shuffle_epi8( + high_mask, _mm_and_si128(_mm_srli_epi16(word, 4), fmask)); + __m128i classify = _mm_and_si128(lowpart, highpart); + __m128i is_zero = _mm_cmpeq_epi8(classify, zero); + // _mm_movemask_epi8 returns a 16-bit mask in bits 0-15, with bits 16-31 + // zero. After NOT (~), bits 16-31 become 1. We must mask to 16 bits to + // avoid false positives. + int mask = ~_mm_movemask_epi8(is_zero) & 0xFFFF; + if (mask != 0) { + return view.length() - 16 + trailing_zeroes(static_cast(mask)); + } + } + return size_t(view.size()); +} +#elif ADA_NEON +ada_really_inline size_t find_next_host_delimiter(std::string_view view, + size_t location) noexcept { + // first check for short strings in which case we do it naively. + if (view.size() - location < 16) { // slow path + for (size_t i = location; i < view.size(); i++) { + if (view[i] == ':' || view[i] == '/' || view[i] == '?' || + view[i] == '[') { + return i; + } + } + return size_t(view.size()); + } + auto to_bitmask = [](uint8x16_t input) -> uint16_t { + uint8x16_t bit_mask = + ada_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x01, + 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80); + uint8x16_t minput = vandq_u8(input, bit_mask); + uint8x16_t tmp = vpaddq_u8(minput, minput); + tmp = vpaddq_u8(tmp, tmp); + tmp = vpaddq_u8(tmp, tmp); + return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0); + }; + + // fast path for long strings (expected to be common) + size_t i = location; + uint8x16_t low_mask = + ada_make_uint8x16_t(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x03); + uint8x16_t high_mask = + ada_make_uint8x16_t(0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + uint8x16_t fmask = vmovq_n_u8(0xf); + uint8x16_t zero{0}; + for (; i + 15 < view.size(); i += 16) { + uint8x16_t word = vld1q_u8((const uint8_t*)view.data() + i); + uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask)); + uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4)); + uint8x16_t classify = vandq_u8(lowpart, highpart); + if (vmaxvq_u32(vreinterpretq_u32_u8(classify)) != 0) { + uint8x16_t is_zero = vceqq_u8(classify, zero); + uint16_t is_non_zero = static_cast(~to_bitmask(is_zero)); + return i + trailing_zeroes(is_non_zero); + } + } + + if (i < view.size()) { + uint8x16_t word = + vld1q_u8((const uint8_t*)view.data() + view.length() - 16); + uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask)); + uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4)); + uint8x16_t classify = vandq_u8(lowpart, highpart); + if (vmaxvq_u32(vreinterpretq_u32_u8(classify)) != 0) { + uint8x16_t is_zero = vceqq_u8(classify, zero); + uint16_t is_non_zero = static_cast(~to_bitmask(is_zero)); + return view.length() - 16 + trailing_zeroes(is_non_zero); + } + } + return size_t(view.size()); +} +#elif ADA_SSE2 +ada_really_inline size_t find_next_host_delimiter(std::string_view view, + size_t location) noexcept { + // first check for short strings in which case we do it naively. + if (view.size() - location < 16) { // slow path + for (size_t i = location; i < view.size(); i++) { + if (view[i] == ':' || view[i] == '/' || view[i] == '?' || + view[i] == '[') { + return i; + } + } + return size_t(view.size()); + } + // fast path for long strings (expected to be common) + size_t i = location; + const __m128i mask1 = _mm_set1_epi8(':'); + const __m128i mask2 = _mm_set1_epi8('/'); + const __m128i mask4 = _mm_set1_epi8('?'); + const __m128i mask5 = _mm_set1_epi8('['); + + for (; i + 15 < view.size(); i += 16) { + __m128i word = _mm_loadu_si128((const __m128i*)(view.data() + i)); + __m128i m1 = _mm_cmpeq_epi8(word, mask1); + __m128i m2 = _mm_cmpeq_epi8(word, mask2); + __m128i m4 = _mm_cmpeq_epi8(word, mask4); + __m128i m5 = _mm_cmpeq_epi8(word, mask5); + __m128i m = _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m4, m5)); + int mask = _mm_movemask_epi8(m); + if (mask != 0) { + return i + trailing_zeroes(mask); + } + } + if (i < view.size()) { + __m128i word = + _mm_loadu_si128((const __m128i*)(view.data() + view.length() - 16)); + __m128i m1 = _mm_cmpeq_epi8(word, mask1); + __m128i m2 = _mm_cmpeq_epi8(word, mask2); + __m128i m4 = _mm_cmpeq_epi8(word, mask4); + __m128i m5 = _mm_cmpeq_epi8(word, mask5); + __m128i m = _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m4, m5)); + int mask = _mm_movemask_epi8(m); + if (mask != 0) { + return view.length() - 16 + trailing_zeroes(mask); + } + } + return size_t(view.length()); +} +#elif ADA_LSX +ada_really_inline size_t find_next_host_delimiter(std::string_view view, + size_t location) noexcept { + // first check for short strings in which case we do it naively. + if (view.size() - location < 16) { // slow path + for (size_t i = location; i < view.size(); i++) { + if (view[i] == ':' || view[i] == '/' || view[i] == '?' || + view[i] == '[') { + return i; + } + } + return size_t(view.size()); + } + // fast path for long strings (expected to be common) + size_t i = location; + const __m128i mask1 = __lsx_vrepli_b(':'); + const __m128i mask2 = __lsx_vrepli_b('/'); + const __m128i mask4 = __lsx_vrepli_b('?'); + const __m128i mask5 = __lsx_vrepli_b('['); + + for (; i + 15 < view.size(); i += 16) { + __m128i word = __lsx_vld((const __m128i*)(view.data() + i), 0); + __m128i m1 = __lsx_vseq_b(word, mask1); + __m128i m2 = __lsx_vseq_b(word, mask2); + __m128i m4 = __lsx_vseq_b(word, mask4); + __m128i m5 = __lsx_vseq_b(word, mask5); + __m128i m = __lsx_vor_v(__lsx_vor_v(m1, m2), __lsx_vor_v(m4, m5)); + int mask = __lsx_vpickve2gr_hu(__lsx_vmsknz_b(m), 0); + if (mask != 0) { + return i + trailing_zeroes(mask); + } + } + if (i < view.size()) { + __m128i word = + __lsx_vld((const __m128i*)(view.data() + view.length() - 16), 0); + __m128i m1 = __lsx_vseq_b(word, mask1); + __m128i m2 = __lsx_vseq_b(word, mask2); + __m128i m4 = __lsx_vseq_b(word, mask4); + __m128i m5 = __lsx_vseq_b(word, mask5); + __m128i m = __lsx_vor_v(__lsx_vor_v(m1, m2), __lsx_vor_v(m4, m5)); + int mask = __lsx_vpickve2gr_hu(__lsx_vmsknz_b(m), 0); + if (mask != 0) { + return view.length() - 16 + trailing_zeroes(mask); + } + } + return size_t(view.length()); +} +#elif ADA_RVV +ada_really_inline size_t find_next_host_delimiter(std::string_view view, + size_t location) noexcept { + uint8_t* src = (uint8_t*)view.data() + location; + for (size_t vl, n = view.size() - location; n > 0; + n -= vl, src += vl, location += vl) { + vl = __riscv_vsetvl_e8m1(n); + vuint8m1_t v = __riscv_vle8_v_u8m1(src, vl); + vbool8_t m1 = __riscv_vmseq(v, ':', vl); + vbool8_t m2 = __riscv_vmseq(v, '/', vl); + vbool8_t m3 = __riscv_vmseq(v, '?', vl); + vbool8_t m4 = __riscv_vmseq(v, '[', vl); + vbool8_t m = + __riscv_vmor(__riscv_vmor(m1, m2, vl), __riscv_vmor(m3, m4, vl), vl); + long idx = __riscv_vfirst(m, vl); + if (idx >= 0) return location + idx; + } + return size_t(view.size()); +} +#else +// : / [ ? +static constexpr std::array host_delimiters = []() consteval { + std::array result{}; + for (int i : {':', '/', '?', '['}) { + result[i] = 1; + } + return result; +}(); +// credit: @the-moisrex recommended a table-based approach +ada_really_inline size_t find_next_host_delimiter(std::string_view view, + size_t location) noexcept { + auto const str = view.substr(location); + for (auto pos = str.begin(); pos != str.end(); ++pos) { + if (host_delimiters[(uint8_t)*pos]) { + return pos - str.begin() + location; + } + } + return size_t(view.size()); +} +#endif + +ada_really_inline std::pair get_host_delimiter_location( + const bool is_special, std::string_view& view) noexcept { + /** + * The spec at https://url.spec.whatwg.org/#hostname-state expects us to + * compute a variable called insideBrackets but this variable is only used + * once, to check whether a ':' character was found outside brackets. Exact + * text: "Otherwise, if c is U+003A (:) and insideBrackets is false, then:". + * It is conceptually simpler and arguably more efficient to just return a + * Boolean indicating whether ':' was found outside brackets. + */ + const size_t view_size = view.size(); + size_t location = 0; + bool found_colon = false; + /** + * Performance analysis: + * + * We are basically seeking the end of the hostname which can be indicated + * by the end of the view, or by one of the characters ':', '/', '?', '\\' + * (where '\\' is only applicable for special URLs). However, these must + * appear outside a bracket range. E.g., if you have [something?]fd: then the + * '?' does not count. + * + * So we can skip ahead to the next delimiter, as long as we include '[' in + * the set of delimiters, and that we handle it first. + * + * So the trick is to have a fast function that locates the next delimiter. + * Unless we find '[', then it only needs to be called once! Ideally, such a + * function would be provided by the C++ standard library, but it seems that + * find_first_of is not very fast, so we are forced to roll our own. + * + * We do not break into two loops for speed, but for clarity. + */ + if (is_special) { + // We move to the next delimiter. + location = find_next_host_delimiter_special(view, location); + // Unless we find '[' then we are going only going to have to call + // find_next_host_delimiter_special once. + for (; location < view_size; + location = find_next_host_delimiter_special(view, location)) { + if (view[location] == '[') { + location = view.find(']', location); + if (location == std::string_view::npos) { + // performance: view.find might get translated to a memchr, which + // has no notion of std::string_view::npos, so the code does not + // reflect the assembly. + location = view_size; + break; + } + } else { + found_colon = view[location] == ':'; + break; + } + } + } else { + // We move to the next delimiter. + location = find_next_host_delimiter(view, location); + // Unless we find '[' then we are going only going to have to call + // find_next_host_delimiter_special once. + for (; location < view_size; + location = find_next_host_delimiter(view, location)) { + if (view[location] == '[') { + location = view.find(']', location); + if (location == std::string_view::npos) { + // performance: view.find might get translated to a memchr, which + // has no notion of std::string_view::npos, so the code does not + // reflect the assembly. + location = view_size; + break; + } + } else { + found_colon = view[location] == ':'; + break; + } + } + } + // performance: remove_suffix may translate into a single instruction. + view.remove_suffix(view_size - location); + return {location, found_colon}; +} + +void trim_c0_whitespace(std::string_view& input) noexcept { + while (!input.empty() && + ada::unicode::is_c0_control_or_space(input.front())) { + input.remove_prefix(1); + } + while (!input.empty() && ada::unicode::is_c0_control_or_space(input.back())) { + input.remove_suffix(1); + } +} + +ada_really_inline void parse_prepared_path(std::string_view input, + ada::scheme::type type, + std::string& path) { + ada_log("parse_prepared_path ", input); + uint8_t accumulator = checkers::path_signature(input); + // Let us first detect a trivial case. + // If it is special, we check that we have no dot, no %, no \ and no + // character needing percent encoding. Otherwise, we check that we have no %, + // no dot, and no character needing percent encoding. + constexpr uint8_t need_encoding = 1; + constexpr uint8_t backslash_char = 2; + constexpr uint8_t dot_char = 4; + constexpr uint8_t percent_char = 8; + bool special = type != ada::scheme::NOT_SPECIAL; + bool may_need_slow_file_handling = (type == ada::scheme::type::FILE && + checkers::is_windows_drive_letter(input)); + bool trivial_path = + (special ? (accumulator == 0) + : ((accumulator & (need_encoding | dot_char | percent_char)) == + 0)) && + (!may_need_slow_file_handling); + if (accumulator == dot_char && !may_need_slow_file_handling) { + // '4' means that we have at least one dot, but nothing that requires + // percent encoding or decoding. The only part that is not trivial is + // that we may have single dots and double dots path segments. + // If we have such segments, then we either have a path that begins + // with '.' (easy to check), or we have the sequence './'. + // Note: input cannot be empty, it must at least contain one character ('.') + // Note: we know that '\' is not present. + if (input[0] != '.') { + size_t slashdot = 0; + bool dot_is_file = true; + for (;;) { + slashdot = input.find("/.", slashdot); + if (slashdot == std::string_view::npos) { // common case + break; + } else { // uncommon + // only three cases matter: /./, /.. or a final / + slashdot += 2; + dot_is_file &= !(slashdot == input.size() || input[slashdot] == '.' || + input[slashdot] == '/'); + } + } + trivial_path = dot_is_file; + } + } + if (trivial_path) { + ada_log("parse_path trivial"); + path += '/'; + path += input; + return; + } + // We are going to need to look a bit at the path, but let us see if we can + // ignore percent encoding *and* backslashes *and* percent characters. + // Except for the trivial case, this is likely to capture 99% of paths out + // there. + bool fast_path = + (special && + (accumulator & (need_encoding | backslash_char | percent_char)) == 0) && + (type != ada::scheme::type::FILE); + if (fast_path) { + ada_log("parse_prepared_path fast"); + // Here we don't need to worry about \ or percent encoding. + // We also do not have a file protocol. We might have dots, however, + // but dots must as appear as '.', and they cannot be encoded because + // the symbol '%' is not present. + size_t previous_location = 0; // We start at 0. + do { + size_t new_location = input.find('/', previous_location); + // std::string_view path_view = input; + // We process the last segment separately: + if (new_location == std::string_view::npos) { + std::string_view path_view = input.substr(previous_location); + if (path_view == "..") { // The path ends with .. + // e.g., if you receive ".." with an empty path, you go to "/". + if (path.empty()) { + path = '/'; + return; + } + // Fast case where we have nothing to do: + if (path.back() == '/') { + return; + } + // If you have the path "/joe/myfriend", + // then you delete 'myfriend'. + path.resize(path.rfind('/') + 1); + return; + } + path += '/'; + if (path_view != ".") { + path.append(path_view); + } + return; + } else { + // This is a non-final segment. + std::string_view path_view = + input.substr(previous_location, new_location - previous_location); + previous_location = new_location + 1; + if (path_view == "..") { + size_t last_delimiter = path.rfind('/'); + if (last_delimiter != std::string::npos) { + path.erase(last_delimiter); + } + } else if (path_view != ".") { + path += '/'; + path.append(path_view); + } + } + } while (true); + } else { + ada_log("parse_path slow"); + // we have reached the general case + bool needs_percent_encoding = (accumulator & 1); + std::string path_buffer_tmp; + do { + size_t location = (special && (accumulator & 2)) + ? input.find_first_of("/\\") + : input.find('/'); + std::string_view path_view = input; + if (location != std::string_view::npos) { + path_view.remove_suffix(path_view.size() - location); + input.remove_prefix(location + 1); + } + // path_buffer is either path_view or it might point at a percent encoded + // temporary file. + std::string_view path_buffer = + (needs_percent_encoding && + ada::unicode::percent_encode( + path_view, character_sets::PATH_PERCENT_ENCODE, path_buffer_tmp)) + ? path_buffer_tmp + : path_view; + if (unicode::is_double_dot_path_segment(path_buffer)) { + helpers::shorten_path(path, type); + if (location == std::string_view::npos) { + path += '/'; + } + } else if (unicode::is_single_dot_path_segment(path_buffer) && + (location == std::string_view::npos)) { + path += '/'; + } + // Otherwise, if path_buffer is not a single-dot path segment, then: + else if (!unicode::is_single_dot_path_segment(path_buffer)) { + // If url's scheme is "file", url's path is empty, and path_buffer is a + // Windows drive letter, then replace the second code point in + // path_buffer with U+003A (:). + if (type == ada::scheme::type::FILE && path.empty() && + checkers::is_windows_drive_letter(path_buffer)) { + path += '/'; + path += path_buffer[0]; + path += ':'; + path_buffer.remove_prefix(2); + path.append(path_buffer); + } else { + // Append path_buffer to url's path. + path += '/'; + path.append(path_buffer); + } + } + if (location == std::string_view::npos) { + return; + } + } while (true); + } +} + +bool overlaps(std::string_view input1, const std::string& input2) noexcept { + ada_log("helpers::overlaps check if string_view '", input1, "' [", + input1.size(), " bytes] is part of string '", input2, "' [", + input2.size(), " bytes]"); + return !input1.empty() && !input2.empty() && input1.data() >= input2.data() && + input1.data() < input2.data() + input2.size(); +} + +template +ada_really_inline void strip_trailing_spaces_from_opaque_path(url_type& url) { + ada_log("helpers::strip_trailing_spaces_from_opaque_path"); + if (!url.has_opaque_path) return; + if (url.has_hash()) return; + if (url.has_search()) return; + + auto path = std::string(url.get_pathname()); + while (!path.empty() && path.back() == ' ') { + path.resize(path.size() - 1); + } + url.update_base_pathname(path); +} + +// @ / \\ ? +static constexpr std::array authority_delimiter_special = + []() consteval { + std::array result{}; + for (uint8_t i : {'@', '/', '\\', '?'}) { + result[i] = 1; + } + return result; + }(); +// credit: @the-moisrex recommended a table-based approach +ada_really_inline size_t +find_authority_delimiter_special(std::string_view view) noexcept { + // performance note: we might be able to gain further performance + // with SIMD intrinsics. + for (auto pos = view.begin(); pos != view.end(); ++pos) { + if (authority_delimiter_special[(uint8_t)*pos]) { + return pos - view.begin(); + } + } + return size_t(view.size()); +} + +// @ / ? +static constexpr std::array authority_delimiter = []() consteval { + std::array result{}; + for (uint8_t i : {'@', '/', '?'}) { + result[i] = 1; + } + return result; +}(); +// credit: @the-moisrex recommended a table-based approach +ada_really_inline size_t +find_authority_delimiter(std::string_view view) noexcept { + // performance note: we might be able to gain further performance + // with SIMD instrinsics. + for (auto pos = view.begin(); pos != view.end(); ++pos) { + if (authority_delimiter[(uint8_t)*pos]) { + return pos - view.begin(); + } + } + return size_t(view.size()); +} + +} // namespace ada::helpers + +namespace ada { +ada_warn_unused std::string to_string(ada::state state) { + return ada::helpers::get_state(state); +} +#undef ada_make_uint8x16_t +} // namespace ada +/* end file src/helpers.cpp */ +/* begin file src/url.cpp */ +/* begin file include/ada/url_ip-inl.h */ +/** + * @file url_ip-inl.h + * @brief Shared IPv4/IPv6 parsing helpers used by url and url_aggregator. + * + * Not part of the public API. Defined inline so the single-TU amalgamation + * (ada.cpp) can include them from multiple translation-unit sources once. + */ +#ifndef ADA_URL_IP_INL_H +#define ADA_URL_IP_INL_H + + +#include +#include + +#if defined(ADA_AVX512) +#include +#endif + +namespace ada::detail { + +// 256-entry: 0xff = not hex, else nibble value. +inline constexpr std::array make_hex_nibble_table() noexcept { + std::array t{}; + for (size_t i = 0; i < 256; ++i) { + t[i] = 0xff; + } + for (size_t d = 0; d < 10; ++d) { + t[size_t{'0'} + d] = static_cast(d); + } + for (size_t d = 0; d < 6; ++d) { + t[size_t{'a'} + d] = static_cast(10 + d); + t[size_t{'A'} + d] = static_cast(10 + d); + } + return t; +} + +inline constexpr auto hex_nibble = make_hex_nibble_table(); + +inline bool parse_ipv4_number(const char*& p, const char* end, uint64_t& value, + bool& is_pure_decimal) noexcept { + is_pure_decimal = false; + if (p >= end) [[unlikely]] { + return false; + } + if (end - p >= 2 && p[0] == '0' && ((p[1] | 0x20) == 'x')) { + p += 2; + if (p == end || *p == '.') { + value = 0; + return true; + } + uint64_t v = 0; + int digits = 0; + while (p < end && *p != '.') { + const uint8_t nib = hex_nibble[static_cast(*p)]; + if (nib == 0xff) [[unlikely]] { + return false; + } + if (v > (0xFFFFFFFFULL >> 4)) [[unlikely]] { + return false; + } + v = (v << 4) | nib; + ++p; + ++digits; + } + if (digits == 0) [[unlikely]] { + return false; + } + value = v; + return true; + } + if (end - p >= 2 && p[0] == '0' && p[1] >= '0' && p[1] <= '9') { + ++p; + uint64_t v = 0; + while (p < end && *p != '.') { + const char c = *p; + if (c < '0' || c > '7') [[unlikely]] { + return false; + } + if (v > (0xFFFFFFFFULL >> 3)) [[unlikely]] { + return false; + } + v = (v << 3) | static_cast(c - '0'); + ++p; + } + value = v; + return true; + } + if (*p < '0' || *p > '9') [[unlikely]] { + return false; + } + is_pure_decimal = true; + uint64_t v = static_cast(*p - '0'); + ++p; + while (p < end && *p != '.') { + const char c = *p; + if (c < '0' || c > '9') [[unlikely]] { + return false; + } + if (v > 429496729ULL) [[unlikely]] { + return false; + } + v = v * 10u + static_cast(c - '0'); + if (v > 0xFFFFFFFFULL) [[unlikely]] { + return false; + } + ++p; + } + value = v; + return true; +} + +// Parse up to 4 hex digits. Returns digit count (0 if none). +inline int parse_hex_piece(const char*& pointer, const char* end, + uint16_t& value) noexcept { + if (pointer == end) { + return 0; + } + const uint8_t n0 = hex_nibble[static_cast(*pointer)]; + if (n0 == 0xff) { + return 0; + } + uint32_t v = n0; + ++pointer; + int length = 1; + if (pointer != end) { + const uint8_t n1 = hex_nibble[static_cast(*pointer)]; + if (n1 != 0xff) { + v = (v << 4) | n1; + ++pointer; + ++length; + if (pointer != end) { + const uint8_t n2 = hex_nibble[static_cast(*pointer)]; + if (n2 != 0xff) { + v = (v << 4) | n2; + ++pointer; + ++length; + if (pointer != end) { + const uint8_t n3 = hex_nibble[static_cast(*pointer)]; + if (n3 != 0xff) { + v = (v << 4) | n3; + ++pointer; + ++length; + } + } + } + } + } + } + value = static_cast(v); + return length; +} + +#if defined(ADA_AVX512) +// Classify an IPv6 host (no brackets) with one masked 512-bit load. +// Returns false if the colon/dot shape is impossible (e.g. two "::", >8 +// colons, full form without 7 colons). Used as a cheap prefilter before the +// full WHATWG piece parser. +ada_really_inline bool ipv6_structure_plausible(const char* data, + size_t len) noexcept { + if (len < 2 || len > 45) { + return false; + } + const __mmask64 live = static_cast<__mmask64>((1ULL << len) - 1ULL); + const __m512i input = + _mm512_maskz_loadu_epi8(live, reinterpret_cast(data)); + const __mmask64 is_colon = + _mm512_mask_cmpeq_epi8_mask(live, input, _mm512_set1_epi8(':')); + const __mmask64 is_dot = + _mm512_mask_cmpeq_epi8_mask(live, input, _mm512_set1_epi8('.')); + const int colons = + static_cast(_mm_popcnt_u64(static_cast(is_colon))); + if (colons > 8) { + return false; + } + const uint64_t doubles = + static_cast(is_colon) & (static_cast(is_colon) << 1); + if (doubles != 0 && (doubles & (doubles - 1)) != 0) { + return false; // more than one "::" (or ":::...") + } + const bool has_double = doubles != 0; + const bool has_dot = is_dot != 0; + if (!has_double && !has_dot && colons != 7) { + return false; + } + return true; +} +#endif // ADA_AVX512 + +} // namespace ada::detail + +#endif // ADA_URL_IP_INL_H +/* end file include/ada/url_ip-inl.h */ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ada { + +bool url::parse_opaque_host(std::string_view input) { + ada_log("parse_opaque_host ", input, " [", input.size(), " bytes]"); + if (std::ranges::any_of(input, ada::unicode::is_forbidden_host_code_point)) { + return is_valid = false; + } + + // Return the result of running UTF-8 percent-encode on input using the C0 + // control percent-encode set. + host = ada::unicode::percent_encode( + input, ada::character_sets::C0_CONTROL_PERCENT_ENCODE); + return true; +} + +bool url::parse_ipv4(std::string_view input) { + ada_log("parse_ipv4 ", input, " [", input.size(), " bytes]"); + if (input.empty()) { + return is_valid = false; + } + std::string_view original_input = input; + if (original_input.back() == '.') { + original_input.remove_suffix(1); + } + if (input.back() == '.') { + input.remove_suffix(1); + if (input.empty()) { + return is_valid = false; + } + } + + const uint64_t fast = checkers::try_parse_ipv4_fast(input); + if (fast < checkers::ipv4_fast_fail) [[likely]] { + host = original_input; + host_type = IPV4; + return true; + } + + const char* p = input.data(); + const char* end = p + input.size(); + uint64_t ipv4 = 0; + int digit_count = 0; + int pure_decimal_count = 0; + + for (; digit_count < 4 && p < end; ++digit_count) { + uint64_t segment = 0; + bool pure = false; + if (!detail::parse_ipv4_number(p, end, segment, pure)) { + return is_valid = false; + } + if (pure) { + ++pure_decimal_count; + } + if (p >= end) { + const unsigned shift = static_cast(32 - digit_count * 8); + if (segment >= (uint64_t{1} << shift)) { + return is_valid = false; + } + ipv4 = (ipv4 << shift) | segment; + host = (pure_decimal_count == 4) ? std::string(original_input) + : ada::serializers::ipv4(ipv4); + host_type = IPV4; + return true; + } + if (segment > 255 || *p != '.') { + return is_valid = false; + } + ipv4 = (ipv4 << 8) | segment; + ++p; + } + if (digit_count != 4 || p != end) { + return is_valid = false; + } + host = (pure_decimal_count == 4) ? std::string(original_input) + : ada::serializers::ipv4(ipv4); + host_type = IPV4; + return true; +} + +bool url::parse_ipv6(std::string_view input) { + ada_log("parse_ipv6 ", input, " [", input.size(), " bytes]"); + if (input.empty() || input.size() > 45) [[unlikely]] { + return is_valid = false; + } +#if defined(ADA_AVX512) + // One masked load classifies colon/dot shape; rejects impossible inputs + // before the piece parser (free on AVX-512BW+VL builds). + if (!detail::ipv6_structure_plausible(input.data(), input.size())) + [[unlikely]] { + return is_valid = false; + } +#endif + + std::array address{}; + const char* pointer = input.data(); + const char* const end = pointer + input.size(); + int piece_index = 0; + int compress = -1; + + if (*pointer == ':') { + if (input.size() == 1 || pointer[1] != ':') [[unlikely]] { + return is_valid = false; + } + pointer += 2; + compress = ++piece_index; + } + + while (pointer != end) { + if (piece_index == 8) [[unlikely]] { + return is_valid = false; + } + if (*pointer == ':') { + if (compress != -1) [[unlikely]] { + return is_valid = false; + } + ++pointer; + compress = ++piece_index; + continue; + } + + uint16_t value = 0; + const int length = detail::parse_hex_piece(pointer, end, value); + + if (pointer != end && *pointer == '.') { + if (length == 0) [[unlikely]] { + return is_valid = false; + } + pointer -= length; + if (piece_index > 6) [[unlikely]] { + return is_valid = false; + } + + int numbers_seen = 0; + while (pointer != end) { + int ipv4_piece = -1; + if (numbers_seen > 0) { + if (*pointer == '.' && numbers_seen < 4) { + ++pointer; + } else { + return is_valid = false; + } + } + if (pointer == end || *pointer < '0' || *pointer > '9') [[unlikely]] { + return is_valid = false; + } + ipv4_piece = *pointer - '0'; + ++pointer; + if (pointer != end && *pointer >= '0' && *pointer <= '9') { + if (ipv4_piece == 0) [[unlikely]] { + return is_valid = false; + } + ipv4_piece = ipv4_piece * 10 + (*pointer - '0'); + ++pointer; + if (pointer != end && *pointer >= '0' && *pointer <= '9') { + ipv4_piece = ipv4_piece * 10 + (*pointer - '0'); + ++pointer; + if (ipv4_piece > 255) [[unlikely]] { + return is_valid = false; + } + } + } + address[static_cast(piece_index)] = static_cast( + address[static_cast(piece_index)] * 0x100 + + static_cast(ipv4_piece)); + ++numbers_seen; + if (numbers_seen == 2 || numbers_seen == 4) { + ++piece_index; + } + } + if (numbers_seen != 4) [[unlikely]] { + return is_valid = false; + } + break; + } + + if (length == 0) [[unlikely]] { + return is_valid = false; + } + + if (pointer != end && *pointer == ':') { + ++pointer; + if (pointer == end) [[unlikely]] { + return is_valid = false; + } + } else if (pointer != end) [[unlikely]] { + return is_valid = false; + } + + address[static_cast(piece_index)] = value; + ++piece_index; + } + + if (compress != -1) { + const int right = piece_index - compress; + if (right > 0) { + const size_t dest = static_cast(8 - right); + const size_t src = static_cast(compress); + if (dest != src) { + for (size_t i = static_cast(right); i-- > 0;) { + address[dest + i] = address[src + i]; + address[src + i] = 0; + } + } + } + } else if (piece_index != 8) [[unlikely]] { + return is_valid = false; + } + + host = ada::serializers::ipv6(address); + ada_log("parse_ipv6 ", *host); + host_type = IPV6; + return true; +} + +template +ada_really_inline bool url::parse_scheme(const std::string_view input) { + auto parsed_type = ada::scheme::get_scheme_type(input); + bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL); + /** + * In the common case, we will immediately recognize a special scheme (e.g., + *http, https), in which case, we can go really fast. + **/ + if (is_input_special) { // fast path!!! + if constexpr (has_state_override) { + // If url's scheme is not a special scheme and buffer is a special scheme, + // then return. + if (is_special() != is_input_special) { + return false; + } + + // If url includes credentials or has a non-null port, and buffer is + // "file", then return. + if ((has_credentials() || port.has_value()) && + parsed_type == ada::scheme::type::FILE) { + return false; + } + + // If url's scheme is "file" and its host is an empty host, then return. + // An empty host is the empty string. + if (type == ada::scheme::type::FILE && host.has_value() && + host->empty()) { + return false; + } + } + + type = parsed_type; + + if constexpr (has_state_override) { + // This is uncommon. + uint16_t urls_scheme_port = get_special_port(); + + if (urls_scheme_port) { + // If url's port is url's scheme's default port, then set url's port to + // null. + if (port.has_value() && *port == urls_scheme_port) { + port = std::nullopt; + } + } + } + } else { // slow path + std::string _buffer(input); + // Next function is only valid if the input is ASCII and returns false + // otherwise, but it seems that we always have ascii content so we do not + // need to check the return value. + // bool is_ascii = + unicode::to_lower_ascii(_buffer.data(), _buffer.size()); + + if constexpr (has_state_override) { + // The state-override validation errors below ("return" in the WHATWG URL + // parser) leave the URL unchanged. The setter contract is + // "true on success, false if the scheme is invalid" -- the fast path + // above already returns false here, so the slow path must agree. + + // If url's scheme is a special scheme and buffer is not a special scheme, + // then return. If url's scheme is not a special scheme and buffer is a + // special scheme, then return. + if (is_special() != ada::scheme::is_special(_buffer)) { + return false; + } + + // If url includes credentials or has a non-null port, and buffer is + // "file", then return. + if ((has_credentials() || port.has_value()) && _buffer == "file") { + return false; + } + + // If url's scheme is "file" and its host is an empty host, then return. + // An empty host is the empty string. + if (type == ada::scheme::type::FILE && host.has_value() && + host->empty()) { + return false; + } + } + + set_scheme(std::move(_buffer)); + + if constexpr (has_state_override) { + // This is uncommon. + uint16_t urls_scheme_port = get_special_port(); + + if (urls_scheme_port) { + // If url's port is url's scheme's default port, then set url's port to + // null. + if (port.has_value() && *port == urls_scheme_port) { + port = std::nullopt; + } + } + } + } + + return true; +} + +ada_really_inline bool url::parse_host(std::string_view input) { + ada_log("parse_host ", input, " [", input.size(), " bytes]"); + if (input.empty()) { + return is_valid = false; + } // technically unnecessary. + // If input starts with U+005B ([), then: + if (input[0] == '[') { + // If input does not end with U+005D (]), validation error, return failure. + if (input.back() != ']') { + return is_valid = false; + } + ada_log("parse_host ipv6"); + + // Return the result of IPv6 parsing input with its leading U+005B ([) and + // trailing U+005D (]) removed. + input.remove_prefix(1); + input.remove_suffix(1); + return parse_ipv6(input); + } + + // If isNotSpecial is true, then return the result of opaque-host parsing + // input. + if (!is_special()) { + return parse_opaque_host(input); + } + + // Fast path: try to parse as pure decimal IPv4(a.b.c.d) first. + const uint64_t fast_result = checkers::try_parse_ipv4_fast(input); + if (fast_result < checkers::ipv4_fast_fail) { + // Fast path succeeded - input is pure decimal IPv4 + if (!input.empty() && input.back() == '.') { + host = input.substr(0, input.size() - 1); + } else { + host = input; + } + host_type = IPV4; + is_valid = true; + ada_log("parse_host fast path decimal ipv4"); + return true; + } + // Let domain be the result of running UTF-8 decode without BOM on the + // percent-decoding of input. Let asciiDomain be the result of running domain + // to ASCII with domain and false. The most common case is an ASCII input, in + // which case we do not need to call the expensive 'to_ascii' if a few + // conditions are met: no '%' and no 'xn-' subsequence. + std::string buffer = std::string(input); + // This next function checks that the result is ascii, but we are going to + // to check anyhow with is_forbidden. + // bool is_ascii = + unicode::to_lower_ascii(buffer.data(), buffer.size()); + bool is_forbidden = unicode::contains_forbidden_domain_code_point( + buffer.data(), buffer.size()); + static constexpr std::string_view xn_dash{"xn-", 3}; + if (is_forbidden == 0 && buffer.find(xn_dash) == std::string_view::npos) { + // fast path + host = std::move(buffer); + + // Check for other IPv4 formats (hex, octal, etc.) + if (checkers::is_ipv4(host.value())) { + ada_log("parse_host fast path ipv4"); + return parse_ipv4(host.value()); + } + ada_log("parse_host fast path ", *host); + is_valid = true; + return true; + } + ada_log("parse_host calling to_ascii"); + is_valid = ada::unicode::to_ascii(host, input, input.find('%')); + if (!is_valid || !host.has_value()) { + ada_log("parse_host to_ascii returns false"); + return is_valid = false; + } + ada_log("parse_host to_ascii succeeded ", *host, " [", host->size(), + " bytes]"); + + if (std::any_of(host->begin(), host->end(), + ada::unicode::is_forbidden_domain_code_point)) { + host = std::nullopt; + return is_valid = false; + } + + // If asciiDomain ends in a number, then return the result of IPv4 parsing + // asciiDomain. + if (checkers::is_ipv4(*host)) { + ada_log("parse_host got ipv4 ", *host); + return parse_ipv4(*host); + } + + return true; +} + +ada_really_inline void url::parse_path(std::string_view input) { + ada_log("parse_path ", input); + std::string tmp_buffer; + std::string_view internal_input; + if (unicode::has_tabs_or_newline(input)) { + tmp_buffer = input; + // Optimization opportunity: Instead of copying and then pruning, we could + // just directly build the string from user_input. + helpers::remove_ascii_tab_or_newline(tmp_buffer); + internal_input = tmp_buffer; + } else { + internal_input = input; + } + + // If url is special, then: + if (is_special()) { + if (internal_input.empty()) { + path = "/"; + } else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) { + helpers::parse_prepared_path(internal_input.substr(1), type, path); + } else { + helpers::parse_prepared_path(internal_input, type, path); + } + } else if (!internal_input.empty()) { + if (internal_input[0] == '/') { + helpers::parse_prepared_path(internal_input.substr(1), type, path); + } else { + helpers::parse_prepared_path(internal_input, type, path); + } + } else { + if (!host.has_value()) { + path = "/"; + } + } +} + +[[nodiscard]] std::string url::to_string() const { + if (!is_valid) { + return "null"; + } + std::string answer; + auto back = std::back_insert_iterator(answer); + answer.append("{\n"); + answer.append("\t\"protocol\":\""); + helpers::encode_json(get_protocol(), back); + answer.append("\",\n"); + if (has_credentials()) { + answer.append("\t\"username\":\""); + helpers::encode_json(username, back); + answer.append("\",\n"); + answer.append("\t\"password\":\""); + helpers::encode_json(password, back); + answer.append("\",\n"); + } + if (host.has_value()) { + answer.append("\t\"host\":\""); + helpers::encode_json(host.value(), back); + answer.append("\",\n"); + } + if (port.has_value()) { + answer.append("\t\"port\":\""); + answer.append(std::to_string(port.value())); + answer.append("\",\n"); + } + answer.append("\t\"path\":\""); + helpers::encode_json(path, back); + answer.append("\",\n"); + answer.append("\t\"opaque path\":"); + answer.append((has_opaque_path ? "true" : "false")); + if (has_search()) { + answer.append(",\n"); + answer.append("\t\"query\":\""); + // NOLINTNEXTLINE(bugprone-unchecked-optional-access) + helpers::encode_json(query.value(), back); + answer.append("\""); + } + if (hash.has_value()) { + answer.append(",\n"); + answer.append("\t\"hash\":\""); + helpers::encode_json(hash.value(), back); + answer.append("\""); + } + answer.append("\n}"); + return answer; +} + +[[nodiscard]] bool url::has_valid_domain() const noexcept { + if (!host.has_value()) { + return false; + } + return checkers::verify_dns_length(*host); +} + +[[nodiscard]] std::string url::get_origin() const { + if (is_special()) { + // Return a new opaque origin. + if (type == scheme::FILE) { + return "null"; + } + return ada::helpers::concat(get_protocol(), "//", get_host()); + } + + if (non_special_scheme == "blob") { + if (!path.empty()) { + auto result = ada::parse(path); + if (result && + (result->type == scheme::HTTP || result->type == scheme::HTTPS)) { + // If pathURL's scheme is not "http" and not "https", then return a + // new opaque origin. + return ada::helpers::concat(result->get_protocol(), "//", + result->get_host()); + } + } + } + + // Return a new opaque origin. + return "null"; +} + +[[nodiscard]] std::string url::get_protocol() const { + if (is_special()) { + return helpers::concat(ada::scheme::details::is_special_list[type], ":"); + } + // We only move the 'scheme' if it is non-special. + return helpers::concat(non_special_scheme, ":"); +} + +[[nodiscard]] std::string url::get_host() const { + // If url's host is null, then return the empty string. + // If url's port is null, return url's host, serialized. + // Return url's host, serialized, followed by U+003A (:) and url's port, + // serialized. + if (!host.has_value()) { + return ""; + } + if (port.has_value()) { + return host.value() + ":" + get_port(); + } + return host.value(); +} + +[[nodiscard]] std::string url::get_hostname() const { + return host.value_or(""); +} + +[[nodiscard]] std::string url::get_search() const { + // If this's URL's query is either null or the empty string, then return the + // empty string. Return U+003F (?), followed by this's URL's query. + return (!query.has_value() || (query->empty())) ? "" : "?" + query.value(); +} + +[[nodiscard]] const std::string& url::get_username() const noexcept { + return username; +} + +[[nodiscard]] const std::string& url::get_password() const noexcept { + return password; +} + +[[nodiscard]] std::string url::get_port() const { + return port.has_value() ? std::to_string(port.value()) : ""; +} + +[[nodiscard]] std::string url::get_hash() const { + // If this's URL's fragment is either null or the empty string, then return + // the empty string. Return U+0023 (#), followed by this's URL's fragment. + return (!hash.has_value() || (hash->empty())) ? "" : "#" + hash.value(); +} + +template +bool url::set_host_or_hostname(const std::string_view input) { + if (has_opaque_path) { + return false; + } + + url saved_url(*this); + + size_t host_end_pos = input.find('#'); + std::string _host(input.data(), host_end_pos != std::string_view::npos + ? host_end_pos + : input.size()); + helpers::remove_ascii_tab_or_newline(_host); + std::string_view new_host(_host); + + auto check_url_size = [&]() -> bool { + if (get_href_size() > ada::get_max_input_length()) { + *this = std::move(saved_url); + return false; + } + return true; + }; + + // If url's scheme is "file", then set state to file host state, instead of + // host state. + if (type != ada::scheme::type::FILE) { + std::string_view host_view(_host.data(), _host.length()); + auto [location, found_colon] = + helpers::get_host_delimiter_location(is_special(), host_view); + + // Otherwise, if c is U+003A (:) and insideBrackets is false, then: + // Note: the 'found_colon' value is true if and only if a colon was + // encountered while not inside brackets. + if (found_colon) { + // If buffer is the empty string, host-missing validation error, return + // failure. + std::string_view buffer = host_view.substr(0, location); + if (buffer.empty()) { + return false; + } + + // If state override is given and state override is hostname state, then + // return failure. + if constexpr (override_hostname) { + return false; + } + + // Let host be the result of host parsing buffer with url is not special. + bool succeeded = parse_host(buffer); + if (!succeeded) { + *this = std::move(saved_url); + return false; + } + + // Set url's host to host, buffer to the empty string, and state to port + // state. + std::string_view port_buffer = new_host.substr(location + 1); + if (!port_buffer.empty()) { + set_port(port_buffer); + } + return check_url_size(); + } + // Otherwise, if one of the following is true: + // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) + // - url is special and c is U+005C (\) + else { + // If url is special and host_view is the empty string, host-missing + // validation error, return failure. + if (host_view.empty() && is_special()) { + return false; + } + + // Otherwise, if state override is given, host_view is the empty string, + // and either url includes credentials or url's port is non-null, then + // return failure. + if (host_view.empty() && (has_credentials() || port.has_value())) { + return false; + } + + // Let host be the result of host parsing host_view with url is not + // special. + if (host_view.empty() && !is_special()) { + host = ""; + return check_url_size(); + } + + bool succeeded = parse_host(host_view); + if (!succeeded) { + *this = std::move(saved_url); + return false; + } + return check_url_size(); + } + } + + size_t location = new_host.find_first_of("/\\?"); + if (location != std::string_view::npos) { + new_host.remove_suffix(new_host.length() - location); + } + + if (new_host.empty()) { + // Set url's host to the empty string. + host = ""; + } else { + // Let host be the result of host parsing buffer with url is not special. + if (!parse_host(new_host)) { + *this = std::move(saved_url); + return false; + } + + // If host is "localhost", then set host to the empty string. + if (host == "localhost") { + host = ""; + } + } + return check_url_size(); +} + +bool url::set_host(const std::string_view input) { + return set_host_or_hostname(input); +} + +bool url::set_hostname(const std::string_view input) { + return set_host_or_hostname(input); +} + +bool url::set_username(const std::string_view input) { + if (cannot_have_credentials_or_port()) { + return false; + } + auto previous_username = std::move(username); + username = ada::unicode::percent_encode( + input, character_sets::USERINFO_PERCENT_ENCODE); + if (get_href_size() > ada::get_max_input_length()) { + username = std::move(previous_username); + return false; + } + return true; +} + +bool url::set_password(const std::string_view input) { + if (cannot_have_credentials_or_port()) { + return false; + } + auto previous_password = std::move(password); + password = ada::unicode::percent_encode( + input, character_sets::USERINFO_PERCENT_ENCODE); + if (get_href_size() > ada::get_max_input_length()) { + password = std::move(previous_password); + return false; + } + return true; +} + +bool url::set_port(const std::string_view input) { + if (cannot_have_credentials_or_port()) { + return false; + } + + if (input.empty()) { + port = std::nullopt; + return true; + } + + std::string trimmed(input); + helpers::remove_ascii_tab_or_newline(trimmed); + + if (trimmed.empty()) { + return true; + } + + // Input should not start with a non-digit character. + if (!ada::unicode::is_ascii_digit(trimmed.front())) { + return false; + } + + // Find the first non-digit character to determine the length of digits + auto first_non_digit = + std::ranges::find_if_not(trimmed, ada::unicode::is_ascii_digit); + std::string_view digits_to_parse = + std::string_view(trimmed.data(), first_non_digit - trimmed.begin()); + + // Revert changes if parse_port fails. + std::optional previous_port = port; + parse_port(digits_to_parse); + if (is_valid) { + if (get_href_size() > ada::get_max_input_length()) { + port = std::move(previous_port); + return false; + } + return true; + } + port = std::move(previous_port); + is_valid = true; + return false; +} + +void url::set_hash(const std::string_view input) { + if (input.empty()) { + hash = std::nullopt; + helpers::strip_trailing_spaces_from_opaque_path(*this); + return; + } + + std::string new_value; + new_value = input[0] == '#' ? input.substr(1) : input; + helpers::remove_ascii_tab_or_newline(new_value); + auto previous_hash = std::move(hash); + hash = unicode::percent_encode(new_value, + ada::character_sets::FRAGMENT_PERCENT_ENCODE); + if (get_href_size() > ada::get_max_input_length()) { + hash = std::move(previous_hash); + } +} + +void url::set_search(const std::string_view input) { + if (input.empty()) { + query = std::nullopt; + helpers::strip_trailing_spaces_from_opaque_path(*this); + return; + } + + std::string new_value; + new_value = input[0] == '?' ? input.substr(1) : input; + helpers::remove_ascii_tab_or_newline(new_value); + + auto query_percent_encode_set = + is_special() ? ada::character_sets::SPECIAL_QUERY_PERCENT_ENCODE + : ada::character_sets::QUERY_PERCENT_ENCODE; + + auto previous_query = std::move(query); + query = ada::unicode::percent_encode(new_value, query_percent_encode_set); + if (get_href_size() > ada::get_max_input_length()) { + query = std::move(previous_query); + } +} + +bool url::set_pathname(const std::string_view input) { + if (has_opaque_path) { + return false; + } + auto previous_path = std::move(path); + path.clear(); + parse_path(input); + if (get_href_size() > ada::get_max_input_length()) { + path = std::move(previous_path); + return false; + } + return true; +} + +bool url::set_protocol(const std::string_view input) { + std::string view(input); + helpers::remove_ascii_tab_or_newline(view); + if (view.empty()) { + return true; + } + + // Schemes should start with alpha values. + if (!checkers::is_alpha(view[0])) { + return false; + } + + view.append(":"); + + std::string::iterator pointer = + std::ranges::find_if_not(view, unicode::is_alnum_plus); + + if (pointer != view.end() && *pointer == ':') { + url saved_url(*this); + bool result = parse_scheme( + std::string_view(view.data(), pointer - view.begin())); + if (result && get_href_size() > ada::get_max_input_length()) { + *this = std::move(saved_url); + return false; + } + return result; + } + return false; +} + +bool url::set_href(const std::string_view input) { + ada::result out = ada::parse(input); + + if (out) { + // The parser enforces get_max_input_length() on both the input and the + // normalized result. This is a defense-in-depth check. + if (out->get_href_size() > ada::get_max_input_length()) { + return false; + } + *this = *out; + } + + return out.has_value(); +} + +} // namespace ada +/* end file src/url.cpp */ +/* begin file src/parser.cpp */ + +#include +#include +#include +#include + + +namespace ada::parser { + +// 0 = host byte, 1 = host delimiter (/ ? #), 2 = reject +namespace { + +constexpr std::array k_host_class = []() consteval { + std::array t{}; + for (size_t i = 0; i < 256; ++i) { + t[i] = 2; + } + for (size_t i = 0x21; i <= 0x7E; ++i) { + t[i] = 0; + } + for (uint8_t c : + {'#', '/', ':', '<', '>', '?', '@', '[', '\\', ']', '^', '|', '%'}) { + t[c] = 2; + } + t[static_cast('/')] = 1; + t[static_cast('?')] = 1; + t[static_cast('#')] = 1; + return t; +}(); + +// 0 = ok, 1 = ?/#, 2 = reject. Path rejects '%' so "%2e" falls through. +constexpr std::array k_rest = []() consteval { + std::array t{}; + for (size_t i = 0; i < 256; ++i) { + t[i] = 2; + } + for (uint8_t c = 0x21; c <= 0x7E; ++c) { + t[c] = 0; + } + for (uint8_t c : {static_cast('"'), static_cast('<'), + static_cast('>'), static_cast('`'), + static_cast('{'), static_cast('}'), + static_cast('^'), static_cast('\\'), + static_cast('%'), static_cast('\'')}) { + t[c] = 2; + } + t[static_cast('?')] = 1; + t[static_cast('#')] = 1; + return t; +}(); + +} // namespace + +// Fast path for already-normalized absolute http(s) URLs. noinline keeps +// the fallthrough path small (IPv4 microbenches). +template +ada_never_inline bool try_parse_simple_absolute(std::string_view input, + result_type& out) { + constexpr bool is_ada_url = std::is_same_v; + constexpr bool is_aggregator = + std::is_same_v; + static_assert(is_ada_url || is_aggregator); + + const size_t len = input.size(); + if (len < 8) [[unlikely]] { + return false; + } + const auto* b = reinterpret_cast(input.data()); + + size_t pos; + ada::scheme::type scheme_type; + uint32_t protocol_end; + if (b[0] == 'h' && b[1] == 't' && b[2] == 't' && b[3] == 'p') { + if (b[4] == ':' && b[5] == '/' && b[6] == '/') { + pos = 7; + scheme_type = ada::scheme::type::HTTP; + protocol_end = 5; + } else if (len >= 8 && b[4] == 's' && b[5] == ':' && b[6] == '/' && + b[7] == '/') { + pos = 8; + scheme_type = ada::scheme::type::HTTPS; + protocol_end = 6; + } else { + return false; + } + } else { + return false; + } + if (pos < len && (b[pos] == '/' || b[pos] == '\\')) [[unlikely]] { + return false; + } + + // Digit-led hosts are IPv4/numeric; skip before scanning. + if (pos < len && b[pos] >= '0' && b[pos] <= '9') { + return false; + } + + const size_t host_start = pos; + bool has_upper = false; + size_t i = pos; + for (; i < len; ++i) { + const uint8_t c = b[i]; + const uint8_t cls = k_host_class[c]; + if (cls == 1) { + break; + } + if (cls == 2) [[unlikely]] { + return false; + } + if (c >= 'A' && c <= 'Z') { + has_upper = true; + } + } + const size_t host_end = i; + if (host_start == host_end) [[unlikely]] { + return false; + } + const size_t host_len = host_end - host_start; + if (host_len > 253) [[unlikely]] { + return false; + } + { + std::string_view hv(input.data() + host_start, host_len); + char host_buf[256]; + if (has_upper) [[unlikely]] { + std::memcpy(host_buf, input.data() + host_start, host_len); + unicode::to_lower_ascii(host_buf, host_len); + hv = std::string_view(host_buf, host_len); + } + if (checkers::is_ipv4(hv)) [[unlikely]] { + return false; + } + static constexpr std::string_view xn{"xn-", 3}; + if (hv.find(xn) != std::string_view::npos) [[unlikely]] { + return false; + } + } + + size_t path_start = host_end; + size_t path_end = host_end; + size_t query_start = std::string_view::npos; + size_t hash_start = std::string_view::npos; + bool has_path = false; + bool path_has_dot = false; + + if (i < len && b[i] == '/') { + has_path = true; + path_start = i; + ++i; + for (; i < len; ++i) { + const uint8_t c = b[i]; + const uint8_t cls = k_rest[c]; + if (cls == 0) { + path_has_dot |= (c == '.'); + continue; + } + if (cls == 1) { + path_end = i; + if (c == '?') { + query_start = i; + ++i; + goto scan_query; + } + hash_start = i; + ++i; + goto scan_hash; + } + return false; + } + path_end = i; + } else if (i < len && b[i] == '?') { + query_start = i; + ++i; + goto scan_query; + } else if (i < len && b[i] == '#') { + hash_start = i; + ++i; + goto scan_hash; + } + goto after_rest; + +scan_query: + for (; i < len; ++i) { + const uint8_t c = b[i]; + if (c == '#') { + hash_start = i; + ++i; + goto scan_hash; + } + if (c == '?' || c == '%') { + continue; + } + if (k_rest[c] == 2) [[unlikely]] { + return false; + } + } + goto after_rest; + +scan_hash: + for (; i < len; ++i) { + const uint8_t c = b[i]; + if (c == '?' || c == '#' || c == '%') { + continue; + } + if (k_rest[c] == 2) [[unlikely]] { + return false; + } + } + +after_rest: + if (path_has_dot) [[unlikely]] { + const std::string_view path_body(input.data() + path_start, + path_end - path_start); + if (path_body.size() >= 2 && path_body[1] == '.') { + if (path_body.size() == 2 || path_body[2] == '/' || + (path_body.size() >= 3 && path_body[2] == '.' && + (path_body.size() == 3 || path_body[3] == '/'))) { + return false; + } + } + static constexpr std::string_view slash_dot{"/.", 2}; + size_t p = 1; + while ((p = path_body.find(slash_dot, p)) != std::string_view::npos) { + const size_t after = p + 2; + if (after == path_body.size() || path_body[after] == '/' || + (after + 1 <= path_body.size() && path_body[after] == '.' && + (after + 1 == path_body.size() || path_body[after + 1] == '/'))) { + return false; + } + p = after; + } + } + + const bool need_slash = !has_path; + out.type = scheme_type; + out.is_valid = true; + out.has_opaque_path = false; + out.host_type = DEFAULT; + + if constexpr (is_aggregator) { + if (!need_slash) { + out.buffer.resize(len); + // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage) + std::memcpy(out.buffer.data(), input.data(), len); + if (has_upper) { + unicode::to_lower_ascii(out.buffer.data() + host_start, + host_end - host_start); + } + out.components.protocol_end = protocol_end; + out.components.username_end = protocol_end + 2; + out.components.host_start = protocol_end + 2; + out.components.host_end = static_cast(host_end); + out.components.port = url_components::omitted; + out.components.pathname_start = static_cast(path_start); + out.components.search_start = (query_start != std::string_view::npos) + ? static_cast(query_start) + : url_components::omitted; + out.components.hash_start = (hash_start != std::string_view::npos) + ? static_cast(hash_start) + : url_components::omitted; + } else { + out.buffer.resize(len + 1); + // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage) + std::memcpy(out.buffer.data(), input.data(), host_end); + out.buffer[host_end] = '/'; + if (host_end < len) { + std::memcpy(out.buffer.data() + host_end + 1, input.data() + host_end, + len - host_end); + } + if (has_upper) { + unicode::to_lower_ascii(out.buffer.data() + host_start, + host_end - host_start); + } + out.components.protocol_end = protocol_end; + out.components.username_end = protocol_end + 2; + out.components.host_start = protocol_end + 2; + out.components.host_end = static_cast(host_end); + out.components.port = url_components::omitted; + out.components.pathname_start = static_cast(host_end); + out.components.search_start = (query_start != std::string_view::npos) + ? static_cast(query_start + 1) + : url_components::omitted; + out.components.hash_start = (hash_start != std::string_view::npos) + ? static_cast(hash_start + 1) + : url_components::omitted; + } + } else { + std::string host_str(input.substr(host_start, host_end - host_start)); + if (has_upper) { + unicode::to_lower_ascii(host_str.data(), host_str.size()); + } + out.host = std::move(host_str); + if (need_slash) { + out.path = "/"; + } else { + out.path.assign(input.data() + path_start, path_end - path_start); + } + if (query_start != std::string_view::npos) { + const size_t q_end = + (hash_start != std::string_view::npos) ? hash_start : len; + out.query.emplace(input.data() + query_start + 1, + q_end - query_start - 1); + } + if (hash_start != std::string_view::npos) { + out.hash.emplace(input.data() + hash_start + 1, len - hash_start - 1); + } + } + return true; +} + +template +result_type parse_url_impl(std::string_view user_input, + const result_type* base_url) { + // We can specialize the implementation per type. + // Important: result_type_is_ada_url is evaluated at *compile time*. This + // means that doing if constexpr(result_type_is_ada_url) { something } else { + // something else } is free (at runtime). This means that ada::url_aggregator + // and ada::url **do not have to support the exact same API**. + constexpr bool result_type_is_ada_url = std::is_same_v; + constexpr bool result_type_is_ada_url_aggregator = + std::is_same_v; + static_assert(result_type_is_ada_url || + result_type_is_ada_url_aggregator); // We don't support + // anything else for now. + + ada_log("ada::parser::parse_url('", user_input, "' [", user_input.size(), + " bytes],", (base_url != nullptr ? base_url->to_string() : "null"), + ")"); + + state state = state::SCHEME_START; + result_type url{}; + + const uint32_t max_input_length = ada::get_max_input_length(); + + // We refuse to parse URL strings that exceed the maximum input length. + // By default, this is 4GB but can be configured via + // ada::set_max_input_length(). + if (user_input.size() > max_input_length) [[unlikely]] { + url.is_valid = false; + } + // Going forward, user_input.size() is in [0, + // std::numeric_limits::max). If we are provided with an invalid + // base, or the optional_url was invalid, we must return. + if (base_url != nullptr) { + url.is_valid &= base_url->is_valid; + } + if (!url.is_valid) { + return url; + } + + // Simple absolute http(s) fast path (before tabs/newline scan). + // Skip digit-led hosts (IPv4) with a cheap peek. + if constexpr (store_values) { + if (base_url == nullptr) { + const auto* p = reinterpret_cast(user_input.data()); + const size_t n = user_input.size(); + const bool digit_led_host = (n >= 8 && p[4] == ':' && p[5] == '/' && + p[6] == '/' && p[7] >= '0' && p[7] <= '9') || + (n >= 9 && p[5] == ':' && p[6] == '/' && + p[7] == '/' && p[8] >= '0' && p[8] <= '9'); + if (!digit_led_host && try_parse_simple_absolute(user_input, url)) { + if constexpr (result_type_is_ada_url_aggregator) { + if (url.buffer.size() > max_input_length) [[unlikely]] { + url.is_valid = false; + } + } else { + if (url.get_href_size() > max_input_length) [[unlikely]] { + url.is_valid = false; + } + } + return url; + } + } + } + + std::string tmp_buffer; + std::string_view url_data; + if (unicode::has_tabs_or_newline(user_input)) [[unlikely]] { + tmp_buffer = user_input; + // Optimization opportunity: Instead of copying and then pruning, we could + // just directly build the string from user_input. + helpers::remove_ascii_tab_or_newline(tmp_buffer); + url_data = tmp_buffer; + } else [[likely]] { + url_data = user_input; + } + + // Leading and trailing control characters are uncommon and easy to deal with + // (no performance concern). + helpers::trim_c0_whitespace(url_data); + + if constexpr (result_type_is_ada_url_aggregator && store_values) { + // Most of the time, we just need user_input.size(). + // In some instances, we may need a bit more. + /////////////////////////// + // This is *very* important. This line should *not* be removed + // hastily. There are principled reasons why reserve is important + // for performance. If you have a benchmark with small inputs, + // it may not matter, but in other instances, it could. + //// + // This rounds up to the next power of two. + // We know that user_input.size() is in [0, + // std::numeric_limits::max). + uint32_t reserve_capacity = + (0xFFFFFFFF >> + helpers::leading_zeroes(uint32_t(1 | user_input.size()))) + + 1; + url.reserve(reserve_capacity); + } + + // Optimization opportunity. Most websites do not have fragment. + std::optional fragment = helpers::prune_hash(url_data); + // We add it last so that an implementation like ada::url_aggregator + // can append it last to its internal buffer, thus improving performance. + + // Here url_data no longer has its fragment. + // We are going to access the data from url_data (it is immutable). + // At any given time, we are pointing at byte 'input_position' in url_data. + // The input_position variable should range from 0 to input_size. + // It is illegal to access url_data at input_size. + size_t input_position = 0; + const size_t input_size = url_data.size(); + // Keep running the following state machine by switching on state. + // If after a run pointer points to the EOF code point, go to the next step. + // Otherwise, increase pointer by 1 and continue with the state machine. + // We never decrement input_position. + while (input_position <= input_size) { + ada_log("In parsing at ", input_position, " out of ", input_size, + " in state ", ada::to_string(state)); + switch (state) { + case state::SCHEME_START: { + ada_log("SCHEME_START ", helpers::substring(url_data, input_position)); + // If c is an ASCII alpha, append c, lowercased, to buffer, and set + // state to scheme state. + if ((input_position != input_size) && + checkers::is_alpha(url_data[input_position])) { + state = state::SCHEME; + input_position++; + } else { + // Otherwise, if state override is not given, set state to no scheme + // state and decrease pointer by 1. + state = state::NO_SCHEME; + } + break; + } + case state::SCHEME: { + ada_log("SCHEME ", helpers::substring(url_data, input_position)); + // If c is an ASCII alphanumeric, U+002B (+), U+002D (-), or U+002E (.), + // append c, lowercased, to buffer. + while ((input_position != input_size) && + (unicode::is_alnum_plus(url_data[input_position]))) { + input_position++; + } + // Otherwise, if c is U+003A (:), then: + if ((input_position != input_size) && + (url_data[input_position] == ':')) { + ada_log("SCHEME the scheme should be ", + url_data.substr(0, input_position)); + if constexpr (result_type_is_ada_url) { + if (!url.parse_scheme(url_data.substr(0, input_position))) { + return url; + } + } else { + // we pass the colon along instead of painfully adding it back. + if (!url.parse_scheme_with_colon( + url_data.substr(0, input_position + 1))) { + return url; + } + } + ada_log("SCHEME the scheme is ", url.get_protocol()); + + // If url's scheme is "file", then: + // NOLINTNEXTLINE(bugprone-branch-clone) + if (url.type == scheme::type::FILE) { + // Set state to file state. + state = state::FILE; + } + // Otherwise, if url is special, base is non-null, and base's scheme + // is url's scheme: Note: Doing base_url->scheme is unsafe if base_url + // != nullptr is false. + else if (url.is_special() && base_url != nullptr && + base_url->type == url.type) { + // Set state to special relative or authority state. + state = state::SPECIAL_RELATIVE_OR_AUTHORITY; + } + // Otherwise, if url is special, set state to special authority + // slashes state. + else if (url.is_special()) { + state = state::SPECIAL_AUTHORITY_SLASHES; + } + // Otherwise, if remaining starts with an U+002F (/), set state to + // path or authority state and increase pointer by 1. + else if (input_position + 1 < input_size && + url_data[input_position + 1] == '/') { + state = state::PATH_OR_AUTHORITY; + input_position++; + } + // Otherwise, set url's path to the empty string and set state to + // opaque path state. + else { + state = state::OPAQUE_PATH; + } + } + // Otherwise, if state override is not given, set buffer to the empty + // string, state to no scheme state, and start over (from the first code + // point in input). + else { + state = state::NO_SCHEME; + input_position = 0; + break; + } + input_position++; + break; + } + case state::NO_SCHEME: { + ada_log("NO_SCHEME ", helpers::substring(url_data, input_position)); + // The fragment was pruned from url_data before the state machine ran, + // so 'c is U+0023 (#)' holds exactly when a fragment was found and + // nothing else remains in front of it. + const bool c_is_hash = + fragment.has_value() && input_position == input_size; + // If base is null, or base has an opaque path and c is not U+0023 (#), + // validation error, return failure. + if (base_url == nullptr || (base_url->has_opaque_path && !c_is_hash)) { + ada_log("NO_SCHEME validation error"); + url.is_valid = false; + return url; + } + // Otherwise, if base has an opaque path and c is U+0023 (#), + // set url's scheme to base's scheme, url's path to base's path, url's + // query to base's query, and set state to fragment state. + else if (base_url->has_opaque_path && c_is_hash) { + ada_log("NO_SCHEME opaque base with fragment"); + url.copy_scheme(*base_url); + url.has_opaque_path = base_url->has_opaque_path; + + if constexpr (result_type_is_ada_url) { + url.path = base_url->path; + url.query = base_url->query; + } else { + url.update_base_pathname(base_url->get_pathname()); + if (base_url->has_search()) { + // get_search() returns "" for an empty query string (URL ends + // with '?'). update_base_search("") would incorrectly clear the + // query, so pass "?" to preserve the empty query distinction. + auto s = base_url->get_search(); + url.update_base_search(s.empty() ? std::string_view("?") : s); + } + } + url.update_unencoded_base_hash(*fragment); + return url; + } + // Otherwise, if base's scheme is not "file", set state to relative + // state and decrease pointer by 1. + // NOLINTNEXTLINE(bugprone-branch-clone) + else if (base_url->type != scheme::type::FILE) { + ada_log("NO_SCHEME non-file relative path"); + state = state::RELATIVE_SCHEME; + } + // Otherwise, set state to file state and decrease pointer by 1. + else { + ada_log("NO_SCHEME file base type"); + state = state::FILE; + } + break; + } + case state::AUTHORITY: { + ada_log("AUTHORITY ", helpers::substring(url_data, input_position)); + // most URLs have no @. Having no @ tells us that we don't have to worry + // about AUTHORITY. Of course, we could have @ and still not have to + // worry about AUTHORITY. + // TODO: Instead of just collecting a bool, collect the location of the + // '@' and do something useful with it. + // TODO: We could do various processing early on, using a single pass + // over the string to collect information about it, e.g., telling us + // whether there is a @ and if so, where (or how many). + + // Check if url data contains an @. + if (url_data.find('@', input_position) == std::string_view::npos) { + state = state::HOST; + break; + } + bool at_sign_seen{false}; + bool password_token_seen{false}; + /** + * We expect something of the sort... + * https://user:pass@example.com:1234/foo/bar?baz#quux + * --------^ + */ + do { + std::string_view view = url_data.substr(input_position); + // The delimiters are @, /, ? \\. + size_t location = + url.is_special() ? helpers::find_authority_delimiter_special(view) + : helpers::find_authority_delimiter(view); + std::string_view authority_view = view.substr(0, location); + size_t end_of_authority = input_position + authority_view.size(); + // If c is U+0040 (@), then: + if ((end_of_authority != input_size) && + (url_data[end_of_authority] == '@')) { + // If atSignSeen is true, then prepend "%40" to buffer. + if (at_sign_seen) { + if (password_token_seen) { + if constexpr (result_type_is_ada_url) { + url.password += "%40"; + } else { + url.append_base_password("%40"); + } + } else { + if constexpr (result_type_is_ada_url) { + url.username += "%40"; + } else { + url.append_base_username("%40"); + } + } + } + + at_sign_seen = true; + + if (!password_token_seen) { + size_t password_token_location = authority_view.find(':'); + password_token_seen = + password_token_location != std::string_view::npos; + + if constexpr (store_values) { + if (!password_token_seen) { + if constexpr (result_type_is_ada_url) { + url.username += unicode::percent_encode( + authority_view, + character_sets::USERINFO_PERCENT_ENCODE); + } else { + url.append_base_username(unicode::percent_encode( + authority_view, + character_sets::USERINFO_PERCENT_ENCODE)); + } + } else { + if constexpr (result_type_is_ada_url) { + url.username += unicode::percent_encode( + authority_view.substr(0, password_token_location), + character_sets::USERINFO_PERCENT_ENCODE); + url.password += unicode::percent_encode( + authority_view.substr(password_token_location + 1), + character_sets::USERINFO_PERCENT_ENCODE); + } else { + url.append_base_username(unicode::percent_encode( + authority_view.substr(0, password_token_location), + character_sets::USERINFO_PERCENT_ENCODE)); + url.append_base_password(unicode::percent_encode( + authority_view.substr(password_token_location + 1), + character_sets::USERINFO_PERCENT_ENCODE)); + } + } + } + } else if constexpr (store_values) { + if constexpr (result_type_is_ada_url) { + url.password += unicode::percent_encode( + authority_view, character_sets::USERINFO_PERCENT_ENCODE); + } else { + url.append_base_password(unicode::percent_encode( + authority_view, character_sets::USERINFO_PERCENT_ENCODE)); + } + } + } + // Otherwise, if one of the following is true: + // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) + // - url is special and c is U+005C (\) + else if (end_of_authority == input_size || + url_data[end_of_authority] == '/' || + url_data[end_of_authority] == '?' || + (url.is_special() && url_data[end_of_authority] == '\\')) { + // If atSignSeen is true and authority_view is the empty string, + // validation error, return failure. + if (at_sign_seen && authority_view.empty()) { + url.is_valid = false; + return url; + } + state = state::HOST; + break; + } + if (end_of_authority == input_size) { + if constexpr (store_values) { + if (fragment.has_value()) { + url.update_unencoded_base_hash(*fragment); + } + } + return url; + } + input_position = end_of_authority + 1; + } while (true); + + break; + } + case state::SPECIAL_RELATIVE_OR_AUTHORITY: { + ada_log("SPECIAL_RELATIVE_OR_AUTHORITY ", + helpers::substring(url_data, input_position)); + + // If c is U+002F (/) and remaining starts with U+002F (/), + // then set state to special authority ignore slashes state and increase + // pointer by 1. + if (url_data.substr(input_position, 2) == "//") { + state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES; + input_position += 2; + } else { + // Otherwise, validation error, set state to relative state and + // decrease pointer by 1. + state = state::RELATIVE_SCHEME; + } + + break; + } + case state::PATH_OR_AUTHORITY: { + ada_log("PATH_OR_AUTHORITY ", + helpers::substring(url_data, input_position)); + + // If c is U+002F (/), then set state to authority state. + if ((input_position != input_size) && + (url_data[input_position] == '/')) { + state = state::AUTHORITY; + input_position++; + } else { + // Otherwise, set state to path state, and decrease pointer by 1. + state = state::PATH; + } + + break; + } + case state::RELATIVE_SCHEME: { + ada_log("RELATIVE_SCHEME ", + helpers::substring(url_data, input_position)); + + // Set url's scheme to base's scheme. + url.copy_scheme(*base_url); + + // If c is U+002F (/), then set state to relative slash state. + if ((input_position != input_size) && + // NOLINTNEXTLINE(bugprone-branch-clone) + (url_data[input_position] == '/')) { + ada_log( + "RELATIVE_SCHEME if c is U+002F (/), then set state to relative " + "slash state"); + state = state::RELATIVE_SLASH; + } else if (url.is_special() && (input_position != input_size) && + (url_data[input_position] == '\\')) { + // Otherwise, if url is special and c is U+005C (\), validation error, + // set state to relative slash state. + ada_log( + "RELATIVE_SCHEME if url is special and c is U+005C, validation " + "error, set state to relative slash state"); + state = state::RELATIVE_SLASH; + } else { + ada_log("RELATIVE_SCHEME otherwise"); + // Set url's username to base's username, url's password to base's + // password, url's host to base's host, url's port to base's port, + // url's path to a clone of base's path, and url's query to base's + // query. + if constexpr (result_type_is_ada_url) { + url.username = base_url->username; + url.password = base_url->password; + url.host = base_url->host; + url.port = base_url->port; + // cloning the base path includes cloning the has_opaque_path flag + url.has_opaque_path = base_url->has_opaque_path; + url.path = base_url->path; + url.query = base_url->query; + } else { + url.update_base_authority(base_url->get_href(), + base_url->get_components()); + url.update_host_to_base_host(base_url->get_hostname()); + url.update_base_port(base_url->retrieve_base_port()); + // cloning the base path includes cloning the has_opaque_path flag + url.has_opaque_path = base_url->has_opaque_path; + url.update_base_pathname(base_url->get_pathname()); + if (base_url->has_search()) { + // get_search() returns "" for an empty query string (URL ends + // with '?'). update_base_search("") would incorrectly clear the + // query, so pass "?" to preserve the empty query distinction. + auto s = base_url->get_search(); + url.update_base_search(s.empty() ? std::string_view("?") : s); + } + } + + url.has_opaque_path = base_url->has_opaque_path; + + // If c is U+003F (?), then set url's query to the empty string, and + // state to query state. + if ((input_position != input_size) && + (url_data[input_position] == '?')) { + state = state::QUERY; + } + // Otherwise, if c is not the EOF code point: + else if (input_position != input_size) { + // Set url's query to null. + url.clear_search(); + if constexpr (result_type_is_ada_url) { + // Shorten url's path. + helpers::shorten_path(url.path, url.type); + } else { + std::string_view path = url.get_pathname(); + if (helpers::shorten_path(path, url.type)) { + url.update_base_pathname(std::move(std::string(path))); + } + } + // Set state to path state and decrease pointer by 1. + state = state::PATH; + break; + } + } + input_position++; + break; + } + case state::RELATIVE_SLASH: { + ada_log("RELATIVE_SLASH ", + helpers::substring(url_data, input_position)); + + // If url is special and c is U+002F (/) or U+005C (\), then: + // NOLINTNEXTLINE(bugprone-branch-clone) + if (url.is_special() && (input_position != input_size) && + (url_data[input_position] == '/' || + url_data[input_position] == '\\')) { + // Set state to special authority ignore slashes state. + state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES; + } + // Otherwise, if c is U+002F (/), then set state to authority state. + else if ((input_position != input_size) && + (url_data[input_position] == '/')) { + state = state::AUTHORITY; + } + // Otherwise, set + // - url's username to base's username, + // - url's password to base's password, + // - url's host to base's host, + // - url's port to base's port, + // - state to path state, and then, decrease pointer by 1. + else { + if constexpr (result_type_is_ada_url) { + url.username = base_url->username; + url.password = base_url->password; + url.host = base_url->host; + url.port = base_url->port; + } else { + url.update_base_authority(base_url->get_href(), + base_url->get_components()); + url.update_host_to_base_host(base_url->get_hostname()); + url.update_base_port(base_url->retrieve_base_port()); + } + state = state::PATH; + break; + } + + input_position++; + break; + } + case state::SPECIAL_AUTHORITY_SLASHES: { + ada_log("SPECIAL_AUTHORITY_SLASHES ", + helpers::substring(url_data, input_position)); + + // If c is U+002F (/) and remaining starts with U+002F (/), + // then set state to special authority ignore slashes state and increase + // pointer by 1. + if (url_data.substr(input_position, 2) == "//") { + input_position += 2; + } + + [[fallthrough]]; + } + case state::SPECIAL_AUTHORITY_IGNORE_SLASHES: { + ada_log("SPECIAL_AUTHORITY_IGNORE_SLASHES ", + helpers::substring(url_data, input_position)); + + // If c is neither U+002F (/) nor U+005C (\), then set state to + // authority state and decrease pointer by 1. + while ((input_position != input_size) && + ((url_data[input_position] == '/') || + (url_data[input_position] == '\\'))) { + input_position++; + } + state = state::AUTHORITY; + + break; + } + case state::QUERY: { + ada_log("QUERY ", helpers::substring(url_data, input_position)); + if constexpr (store_values) { + // Let queryPercentEncodeSet be the special-query percent-encode set + // if url is special; otherwise the query percent-encode set. + const uint8_t* query_percent_encode_set = + url.is_special() ? character_sets::SPECIAL_QUERY_PERCENT_ENCODE + : character_sets::QUERY_PERCENT_ENCODE; + + // Percent-encode after encoding, with encoding, buffer, and + // queryPercentEncodeSet, and append the result to url's query. + url.update_base_search(url_data.substr(input_position), + query_percent_encode_set); + ada_log("QUERY update_base_search completed "); + if (fragment.has_value()) { + url.update_unencoded_base_hash(*fragment); + } + } + return url; + } + case state::HOST: { + ada_log("HOST ", helpers::substring(url_data, input_position)); + + std::string_view host_view = url_data.substr(input_position); + auto [location, found_colon] = + helpers::get_host_delimiter_location(url.is_special(), host_view); + input_position = (location != std::string_view::npos) + ? input_position + location + : input_size; + // Otherwise, if c is U+003A (:) and insideBrackets is false, then: + // Note: the 'found_colon' value is true if and only if a colon was + // encountered while not inside brackets. + if (found_colon) { + // If buffer is the empty string, validation error, return failure. + // Let host be the result of host parsing buffer with url is not + // special. + ada_log("HOST parsing ", host_view); + if (!url.parse_host(host_view)) { + return url; + } + ada_log("HOST parsing results in ", url.get_hostname()); + // Set url's host to host, buffer to the empty string, and state to + // port state. + state = state::PORT; + input_position++; + } + // Otherwise, if one of the following is true: + // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) + // - url is special and c is U+005C (\) + // The get_host_delimiter_location function either brings us to + // the colon outside of the bracket, or to one of those characters. + else { + // If url is special and host_view is the empty string, validation + // error, return failure. + if (host_view.empty() && url.is_special()) { + url.is_valid = false; + return url; + } + ada_log("HOST parsing ", host_view, " href=", url.get_href()); + // Let host be the result of host parsing host_view with url is not + // special. + if (host_view.empty()) { + url.update_base_hostname(""); + } else if (!url.parse_host(host_view)) { + return url; + } + ada_log("HOST parsing results in ", url.get_hostname(), + " href=", url.get_href()); + + // Set url's host to host, and state to path start state. + state = state::PATH_START; + } + + break; + } + case state::OPAQUE_PATH: { + ada_log("OPAQUE_PATH ", helpers::substring(url_data, input_position)); + // Opaque path, query, and fragment are structurally always valid: + // the parser would just percent-encode whatever is there. When we + // are not storing values (can_parse), we can return immediately. + // We must set has_opaque_path = true before returning so that when + // this URL is used as an internal base inside can_parse, NO_SCHEME + // correctly rejects relative inputs against an opaque-path base + // (e.g. can_parse("", &"W:") must return false). + if constexpr (!store_values) { + url.has_opaque_path = true; + return url; + } + std::string_view view = url_data.substr(input_position); + // If c is U+003F (?), then set url's query to the empty string and + // state to query state. + size_t location = view.find('?'); + if (location != std::string_view::npos) { + view.remove_suffix(view.size() - location); + state = state::QUERY; + input_position += location + 1; + } else { + input_position = input_size + 1; + } + url.has_opaque_path = true; + + // This is a really unlikely scenario in real world. We should not seek + // to optimize it. + if (view.ends_with(' ')) { + std::string modified_view = + std::string(view.substr(0, view.size() - 1)) + "%20"; + url.update_base_pathname(unicode::percent_encode( + modified_view, character_sets::C0_CONTROL_PERCENT_ENCODE)); + } else { + url.update_base_pathname(unicode::percent_encode( + view, character_sets::C0_CONTROL_PERCENT_ENCODE)); + } + break; + } + case state::PORT: { + ada_log("PORT ", helpers::substring(url_data, input_position)); + std::string_view port_view = url_data.substr(input_position); + input_position += url.parse_port(port_view, true); + if (!url.is_valid) { + return url; + } + state = state::PATH_START; + [[fallthrough]]; + } + case state::PATH_START: { + ada_log("PATH_START ", helpers::substring(url_data, input_position)); + // Path, query, and fragment are structurally always valid: the + // parser would just percent-encode whatever is there. When we are + // not storing values (can_parse), we can return immediately since + // no subsequent state can invalidate the URL. + if constexpr (!store_values) { + return url; + } + + // If url is special, then: + if (url.is_special()) { + // Set state to path state. + state = state::PATH; + + // Optimization: Avoiding going into PATH state improves the + // performance of urls ending with /. + if (input_position == input_size) { + if constexpr (store_values) { + url.update_base_pathname("/"); + if (fragment.has_value()) { + url.update_unencoded_base_hash(*fragment); + } + } + return url; + } + // If c is neither U+002F (/) nor U+005C (\), then decrease pointer + // by 1. We know that (input_position == input_size) is impossible + // here, because of the previous if-check. + if ((url_data[input_position] != '/') && + (url_data[input_position] != '\\')) { + break; + } + } + // Otherwise, if state override is not given and c is U+003F (?), + // set url's query to the empty string and state to query state. + else if ((input_position != input_size) && + (url_data[input_position] == '?')) { + state = state::QUERY; + } + // Otherwise, if c is not the EOF code point: + else if (input_position != input_size) { + // Set state to path state. + state = state::PATH; + + // If c is not U+002F (/), then decrease pointer by 1. + if (url_data[input_position] != '/') { + break; + } + } + + input_position++; + break; + } + case state::PATH: { + ada_log("PATH ", helpers::substring(url_data, input_position)); + // Path, query, and fragment are structurally always valid: the + // parser would just percent-encode whatever is there. When we are + // not storing values (can_parse), we can return immediately since + // no subsequent state can invalidate the URL. + if constexpr (!store_values) { + return url; + } + std::string_view view = url_data.substr(input_position); + + // Most time, we do not need percent encoding. + // Furthermore, we can immediately locate the '?'. + size_t locofquestionmark = view.find('?'); + if (locofquestionmark != std::string_view::npos) { + state = state::QUERY; + view.remove_suffix(view.size() - locofquestionmark); + input_position += locofquestionmark + 1; + } else { + input_position = input_size + 1; + } + if constexpr (store_values) { + if constexpr (result_type_is_ada_url) { + helpers::parse_prepared_path(view, url.type, url.path); + } else { + url.consume_prepared_path(view); + ADA_ASSERT_TRUE(url.validate()); + } + } + break; + } + case state::FILE_SLASH: { + ada_log("FILE_SLASH ", helpers::substring(url_data, input_position)); + + // If c is U+002F (/) or U+005C (\), then: + if ((input_position != input_size) && + (url_data[input_position] == '/' || + url_data[input_position] == '\\')) { + ada_log("FILE_SLASH c is U+002F or U+005C"); + // Set state to file host state. + state = state::FILE_HOST; + input_position++; + } else { + ada_log("FILE_SLASH otherwise"); + // If base is non-null and base's scheme is "file", then: + // Note: it is unsafe to do base_url->scheme unless you know that + // base_url_has_value() is true. + if (base_url != nullptr && base_url->type == scheme::type::FILE) { + // Set url's host to base's host. + if constexpr (result_type_is_ada_url) { + url.host = base_url->host; + } else { + url.update_host_to_base_host(base_url->get_host()); + } + // If the code point substring from pointer to the end of input does + // not start with a Windows drive letter and base's path[0] is a + // normalized Windows drive letter, then append base's path[0] to + // url's path. + if (!base_url->get_pathname().empty()) { + if (!checkers::is_windows_drive_letter( + url_data.substr(input_position))) { + std::string_view first_base_url_path = + base_url->get_pathname().substr(1); + size_t loc = first_base_url_path.find('/'); + if (loc != std::string_view::npos) { + helpers::resize(first_base_url_path, loc); + } + if (checkers::is_normalized_windows_drive_letter( + first_base_url_path)) { + if constexpr (result_type_is_ada_url) { + url.path += '/'; + url.path += first_base_url_path; + } else { + url.append_base_pathname( + helpers::concat("/", first_base_url_path)); + } + } + } + } + } + + // Set state to path state, and decrease pointer by 1. + state = state::PATH; + } + + break; + } + case state::FILE_HOST: { + ada_log("FILE_HOST ", helpers::substring(url_data, input_position)); + std::string_view view = url_data.substr(input_position); + + size_t location = view.find_first_of("/\\?"); + std::string_view file_host_buffer = view.substr( + 0, (location != std::string_view::npos) ? location : view.size()); + + if (checkers::is_windows_drive_letter(file_host_buffer)) { + state = state::PATH; + } else if (file_host_buffer.empty()) { + // Set url's host to the empty string. + if constexpr (result_type_is_ada_url) { + url.host = ""; + } else { + url.update_base_hostname(""); + } + // Set state to path start state. + state = state::PATH_START; + } else { + size_t consumed_bytes = file_host_buffer.size(); + input_position += consumed_bytes; + // Let host be the result of host parsing buffer with url is not + // special. + if (!url.parse_host(file_host_buffer)) { + return url; + } + + if constexpr (result_type_is_ada_url) { + // If host is "localhost", then set host to the empty string. + if (url.host.has_value() && url.host.value() == "localhost") { + url.host = ""; + } + } else { + if (url.get_hostname() == "localhost") { + url.update_base_hostname(""); + } + } + + // Set buffer to the empty string and state to path start state. + state = state::PATH_START; + } + + break; + } + case state::FILE: { + ada_log("FILE ", helpers::substring(url_data, input_position)); + std::string_view file_view = url_data.substr(input_position); + + url.set_protocol_as_file(); + if constexpr (result_type_is_ada_url) { + // Set url's host to the empty string. + url.host = ""; + } else { + url.update_base_hostname(""); + } + // If c is U+002F (/) or U+005C (\), then: + if (input_position != input_size && + (url_data[input_position] == '/' || + url_data[input_position] == '\\')) { + ada_log("FILE c is U+002F or U+005C"); + // Set state to file slash state. + state = state::FILE_SLASH; + } + // Otherwise, if base is non-null and base's scheme is "file": + else if (base_url != nullptr && base_url->type == scheme::type::FILE) { + // Set url's host to base's host, url's path to a clone of base's + // path, and url's query to base's query. + ada_log("FILE base non-null"); + if constexpr (result_type_is_ada_url) { + url.host = base_url->host; + url.path = base_url->path; + url.query = base_url->query; + } else { + url.update_host_to_base_host(base_url->get_hostname()); + url.update_base_pathname(base_url->get_pathname()); + if (base_url->has_search()) { + // get_search() returns "" for an empty query string (URL ends + // with '?'). update_base_search("") would incorrectly clear the + // query, so pass "?" to preserve the empty query distinction. + auto s = base_url->get_search(); + url.update_base_search(s.empty() ? std::string_view("?") : s); + } + } + url.has_opaque_path = base_url->has_opaque_path; + + // If c is U+003F (?), then set url's query to the empty string and + // state to query state. + if (input_position != input_size && url_data[input_position] == '?') { + state = state::QUERY; + } + // Otherwise, if c is not the EOF code point: + else if (input_position != input_size) { + // Set url's query to null. + url.clear_search(); + // If the code point substring from pointer to the end of input does + // not start with a Windows drive letter, then shorten url's path. + if (!checkers::is_windows_drive_letter(file_view)) { + if constexpr (result_type_is_ada_url) { + helpers::shorten_path(url.path, url.type); + } else { + std::string_view path = url.get_pathname(); + if (helpers::shorten_path(path, url.type)) { + url.update_base_pathname(std::move(std::string(path))); + } + } + } + // Otherwise: + else { + // Set url's path to an empty list. + url.clear_pathname(); + url.has_opaque_path = true; + } + + // Set state to path state and decrease pointer by 1. + state = state::PATH; + break; + } + } + // Otherwise, set state to path state, and decrease pointer by 1. + else { + ada_log("FILE go to path"); + state = state::PATH; + break; + } + + input_position++; + break; + } + default: + unreachable(); + } + } + if constexpr (store_values) { + if (fragment.has_value()) { + url.update_unencoded_base_hash(*fragment); + } + } + // Check the resulting (normalized) URL size against the maximum input length. + // Normalization (percent-encoding, IDNA, etc.) can expand the URL beyond the + // original input size. + if constexpr (store_values) { + if (url.is_valid) { + if constexpr (result_type_is_ada_url_aggregator) { + if (url.buffer.size() > max_input_length) { + url.is_valid = false; + } + } else { + if (url.get_href_size() > max_input_length) { + url.is_valid = false; + } + } + } + } + return url; +} + +template url parse_url_impl(std::string_view user_input, + const url* base_url = nullptr); +template url_aggregator parse_url_impl( + std::string_view user_input, const url_aggregator* base_url = nullptr); +template url_aggregator parse_url_impl( + std::string_view user_input, const url_aggregator* base_url = nullptr); + +template +result_type parse_url(std::string_view user_input, + const result_type* base_url) { + return parse_url_impl(user_input, base_url); +} + +template url parse_url(std::string_view user_input, + const url* base_url = nullptr); +template url_aggregator parse_url( + std::string_view user_input, const url_aggregator* base_url = nullptr); +} // namespace ada::parser +/* end file src/parser.cpp */ +/* begin file src/url_components.cpp */ + +#include +#include + +namespace ada { + +[[nodiscard]] std::string url_components::to_string() const { + std::string answer; + auto back = std::back_insert_iterator(answer); + answer.append("{\n"); + + answer.append("\t\"protocol_end\":\""); + helpers::encode_json(std::to_string(protocol_end), back); + answer.append("\",\n"); + + answer.append("\t\"username_end\":\""); + helpers::encode_json(std::to_string(username_end), back); + answer.append("\",\n"); + + answer.append("\t\"host_start\":\""); + helpers::encode_json(std::to_string(host_start), back); + answer.append("\",\n"); + + answer.append("\t\"host_end\":\""); + helpers::encode_json(std::to_string(host_end), back); + answer.append("\",\n"); + + answer.append("\t\"port\":\""); + helpers::encode_json(std::to_string(port), back); + answer.append("\",\n"); + + answer.append("\t\"pathname_start\":\""); + helpers::encode_json(std::to_string(pathname_start), back); + answer.append("\",\n"); + + answer.append("\t\"search_start\":\""); + helpers::encode_json(std::to_string(search_start), back); + answer.append("\",\n"); + + answer.append("\t\"hash_start\":\""); + helpers::encode_json(std::to_string(hash_start), back); + answer.append("\",\n"); + + answer.append("\n}"); + return answer; +} + +} // namespace ada +/* end file src/url_components.cpp */ +/* begin file src/url_aggregator.cpp */ + +#include +#include +#include +#include +#include +#include +#include + +namespace { + +ada_really_inline void apply_shifted_non_scheme_offsets( + ada::url_components& components, uint32_t new_difference) { + components.username_end += new_difference; + components.host_start += new_difference; + components.host_end += new_difference; + components.pathname_start += new_difference; + if (components.search_start != ada::url_components::omitted) { + components.search_start += new_difference; + } + if (components.hash_start != ada::url_components::omitted) { + components.hash_start += new_difference; + } +} + +} // namespace + +namespace ada { +template +[[nodiscard]] ada_really_inline bool url_aggregator::parse_scheme_with_colon( + const std::string_view input_with_colon) { + ada_log("url_aggregator::parse_scheme_with_colon ", input_with_colon); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input_with_colon, buffer)); + std::string_view input{input_with_colon}; + input.remove_suffix(1); + auto parsed_type = ada::scheme::get_scheme_type(input); + const bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL); + /** + * In the common case, we will immediately recognize a special scheme (e.g., + *http, https), in which case, we can go really fast. + **/ + if (is_input_special) { // fast path!!! + if constexpr (has_state_override) { + // If url's scheme is not a special scheme and buffer is a special scheme, + // then return. + if (is_special() != is_input_special) { + return false; + } + + // If url includes credentials or has a non-null port, and buffer is + // "file", then return. + if ((has_credentials() || components.port != url_components::omitted) && + parsed_type == ada::scheme::type::FILE) { + return false; + } + + // If url's scheme is "file" and its host is an empty host, then return. + // An empty host is the empty string. + if (type == ada::scheme::type::FILE && + components.host_start == components.host_end) { + return false; + } + } + + type = parsed_type; + set_scheme_from_view_with_colon(input_with_colon); + + if constexpr (has_state_override) { + // This is uncommon. + uint16_t urls_scheme_port = get_special_port(); + + if (urls_scheme_port) { + // If url's port is url's scheme's default port, then set url's port to + // null. + if (components.port == urls_scheme_port) { + clear_port(); + } + } + } + } else { // slow path + std::string _buffer(input); + // Next function is only valid if the input is ASCII and returns false + // otherwise, but it seems that we always have ascii content so we do not + // need to check the return value. + unicode::to_lower_ascii(_buffer.data(), _buffer.size()); + + if constexpr (has_state_override) { + // The state-override validation errors below ("return" in the WHATWG URL + // parser) leave the URL unchanged. The setter contract is + // "true on success, false if the scheme is invalid" -- the fast path + // above already returns false here, so the slow path must agree. + + // If url's scheme is a special scheme and buffer is not a special scheme, + // then return. If url's scheme is not a special scheme and buffer is a + // special scheme, then return. + if (is_special() != ada::scheme::is_special(_buffer)) { + return false; + } + + // If url includes credentials or has a non-null port, and buffer is + // "file", then return. + if ((has_credentials() || components.port != url_components::omitted) && + _buffer == "file") { + return false; + } + + // If url's scheme is "file" and its host is an empty host, then return. + // An empty host is the empty string. + if (type == ada::scheme::type::FILE && + components.host_start == components.host_end) { + return false; + } + } + + set_scheme(_buffer); + + if constexpr (has_state_override) { + // This is uncommon. + uint16_t urls_scheme_port = get_special_port(); + + if (urls_scheme_port) { + // If url's port is url's scheme's default port, then set url's port to + // null. + if (components.port == urls_scheme_port) { + clear_port(); + } + } + } + } + ADA_ASSERT_TRUE(validate()); + return true; +} + +inline void url_aggregator::copy_scheme(const url_aggregator& u) { + ada_log("url_aggregator::copy_scheme ", u.buffer); + ADA_ASSERT_TRUE(validate()); + // next line could overflow but unsigned arithmetic has well-defined + // overflows. + uint32_t new_difference = u.components.protocol_end - components.protocol_end; + + type = u.type; + buffer.erase(0, components.protocol_end); + buffer.insert(0, u.get_protocol()); + components.protocol_end = u.components.protocol_end; + + // No need to update the components + if (new_difference == 0) { + return; + } + + apply_shifted_non_scheme_offsets(components, new_difference); + ADA_ASSERT_TRUE(validate()); +} + +inline void url_aggregator::set_scheme_from_view_with_colon( + std::string_view new_scheme_with_colon) { + ada_log("url_aggregator::set_scheme_from_view_with_colon ", + new_scheme_with_colon); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!new_scheme_with_colon.empty() && + new_scheme_with_colon.back() == ':'); + // next line could overflow but unsigned arithmetic has well-defined + // overflows. + uint32_t new_difference = + uint32_t(new_scheme_with_colon.size()) - components.protocol_end; + + if (buffer.empty()) { + buffer.append(new_scheme_with_colon); + } else { + buffer.erase(0, components.protocol_end); + buffer.insert(0, new_scheme_with_colon); + } + components.protocol_end += new_difference; + + apply_shifted_non_scheme_offsets(components, new_difference); + ADA_ASSERT_TRUE(validate()); +} + +inline void url_aggregator::set_scheme(std::string_view new_scheme) { + ada_log("url_aggregator::set_scheme ", new_scheme); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(new_scheme.empty() || new_scheme.back() != ':'); + // next line could overflow but unsigned arithmetic has well-defined + // overflows. + uint32_t new_difference = + uint32_t(new_scheme.size()) - components.protocol_end + 1; + + type = ada::scheme::get_scheme_type(new_scheme); + if (buffer.empty()) { + buffer.append(helpers::concat(new_scheme, ":")); + } else { + buffer.erase(0, components.protocol_end); + buffer.insert(0, helpers::concat(new_scheme, ":")); + } + components.protocol_end = uint32_t(new_scheme.size() + 1); + + apply_shifted_non_scheme_offsets(components, new_difference); + ADA_ASSERT_TRUE(validate()); +} + +bool url_aggregator::set_protocol(const std::string_view input) { + ada_log("url_aggregator::set_protocol ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + std::string view(input); + helpers::remove_ascii_tab_or_newline(view); + if (view.empty()) { + return true; + } + + // Schemes should start with alpha values. + if (!checkers::is_alpha(view[0])) { + return false; + } + + view.append(":"); + + std::string::iterator pointer = + std::ranges::find_if_not(view, unicode::is_alnum_plus); + + if (pointer != view.end() && *pointer == ':') { + url_aggregator saved_url(*this); + bool result = parse_scheme_with_colon( + view.substr(0, pointer - view.begin() + 1)); + if (result && buffer.size() > ada::get_max_input_length()) { + *this = std::move(saved_url); + return false; + } + return result; + } + return false; +} + +bool url_aggregator::set_username(const std::string_view input) { + ada_log("url_aggregator::set_username '", input, "' "); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (cannot_have_credentials_or_port()) { + return false; + } + url_aggregator saved_url(*this); + size_t idx = ada::unicode::percent_encode_index( + input, character_sets::USERINFO_PERCENT_ENCODE); + if (idx == input.size()) { + update_base_username(input); + } else { + // We only create a temporary string if we have to! + update_base_username(ada::unicode::percent_encode( + input, character_sets::USERINFO_PERCENT_ENCODE, idx)); + } + if (buffer.size() > ada::get_max_input_length()) { + *this = std::move(saved_url); + return false; + } + ADA_ASSERT_TRUE(validate()); + return true; +} + +bool url_aggregator::set_password(const std::string_view input) { + ada_log("url_aggregator::set_password '", input, "'"); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (cannot_have_credentials_or_port()) { + return false; + } + url_aggregator saved_url(*this); + size_t idx = ada::unicode::percent_encode_index( + input, character_sets::USERINFO_PERCENT_ENCODE); + if (idx == input.size()) { + update_base_password(input); + } else { + // We only create a temporary string if we have to! + update_base_password(ada::unicode::percent_encode( + input, character_sets::USERINFO_PERCENT_ENCODE, idx)); + } + if (buffer.size() > ada::get_max_input_length()) { + *this = std::move(saved_url); + return false; + } + ADA_ASSERT_TRUE(validate()); + return true; +} + +bool url_aggregator::set_port(const std::string_view input) { + ada_log("url_aggregator::set_port ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (cannot_have_credentials_or_port()) { + return false; + } + + if (input.empty()) { + clear_port(); + return true; + } + + std::string trimmed(input); + helpers::remove_ascii_tab_or_newline(trimmed); + + if (trimmed.empty()) { + return true; + } + + // Input should not start with a non-digit character. + if (!ada::unicode::is_ascii_digit(trimmed.front())) { + return false; + } + + // Find the first non-digit character to determine the length of digits + auto first_non_digit = + std::ranges::find_if_not(trimmed, ada::unicode::is_ascii_digit); + std::string_view digits_to_parse = + std::string_view(trimmed.data(), first_non_digit - trimmed.begin()); + + // Revert changes if parse_port fails. + url_aggregator saved_url(*this); + parse_port(digits_to_parse); + if (is_valid) { + if (buffer.size() > ada::get_max_input_length()) { + *this = std::move(saved_url); + return false; + } + return true; + } + *this = std::move(saved_url); + is_valid = true; + ADA_ASSERT_TRUE(validate()); + return false; +} + +bool url_aggregator::set_pathname(const std::string_view input) { + ada_log("url_aggregator::set_pathname ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (has_opaque_path) { + return false; + } + url_aggregator saved_url(*this); + clear_pathname(); + parse_path(input); + if (get_pathname().starts_with("//") && !has_authority() && !has_dash_dot()) { + buffer.insert(components.pathname_start, "/."); + components.pathname_start += 2; + if (components.search_start != url_components::omitted) { + components.search_start += 2; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += 2; + } + } + if (buffer.size() > ada::get_max_input_length()) { + *this = std::move(saved_url); + return false; + } + ADA_ASSERT_TRUE(validate()); + return true; +} + +ada_really_inline void url_aggregator::parse_path(std::string_view input) { + ada_log("url_aggregator::parse_path ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + std::string tmp_buffer; + std::string_view internal_input; + if (unicode::has_tabs_or_newline(input)) { + tmp_buffer = input; + // Optimization opportunity: Instead of copying and then pruning, we could + // just directly build the string from user_input. + helpers::remove_ascii_tab_or_newline(tmp_buffer); + internal_input = tmp_buffer; + } else { + internal_input = input; + } + + // If url is special, then: + if (is_special()) { + if (internal_input.empty()) { + update_base_pathname("/"); + } else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) { + consume_prepared_path(internal_input.substr(1)); + } else { + consume_prepared_path(internal_input); + } + } else if (!internal_input.empty()) { + if (internal_input[0] == '/') { + consume_prepared_path(internal_input.substr(1)); + } else { + consume_prepared_path(internal_input); + } + } else { + // Non-special URLs with an empty host can have their paths erased + // Path-only URLs cannot have their paths erased + if (components.host_start == components.host_end && !has_authority()) { + update_base_pathname("/"); + } + } + ADA_ASSERT_TRUE(validate()); +} + +void url_aggregator::set_search(const std::string_view input) { + ada_log("url_aggregator::set_search ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (input.empty()) { + clear_search(); + helpers::strip_trailing_spaces_from_opaque_path(*this); + return; + } + + std::string new_value; + new_value = input[0] == '?' ? input.substr(1) : input; + helpers::remove_ascii_tab_or_newline(new_value); + + auto query_percent_encode_set = + is_special() ? ada::character_sets::SPECIAL_QUERY_PERCENT_ENCODE + : ada::character_sets::QUERY_PERCENT_ENCODE; + + url_aggregator saved_url(*this); + update_base_search(new_value, query_percent_encode_set); + if (buffer.size() > ada::get_max_input_length()) { + *this = std::move(saved_url); + return; + } + ADA_ASSERT_TRUE(validate()); +} + +void url_aggregator::set_hash(const std::string_view input) { + ada_log("url_aggregator::set_hash ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (input.empty()) { + if (components.hash_start != url_components::omitted) { + buffer.resize(components.hash_start); + components.hash_start = url_components::omitted; + } + helpers::strip_trailing_spaces_from_opaque_path(*this); + return; + } + + std::string new_value; + new_value = input[0] == '#' ? input.substr(1) : input; + helpers::remove_ascii_tab_or_newline(new_value); + url_aggregator saved_url(*this); + update_unencoded_base_hash(new_value); + if (buffer.size() > ada::get_max_input_length()) { + *this = std::move(saved_url); + return; + } + ADA_ASSERT_TRUE(validate()); +} + +bool url_aggregator::set_href(const std::string_view input) { + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + ada_log("url_aggregator::set_href ", input, " [", input.size(), " bytes]"); + ada::result out = ada::parse(input); + ada_log("url_aggregator::set_href, success :", out.has_value()); + + if (out) { + // The parser enforces get_max_input_length() on both the input and the + // normalized result. This is a defense-in-depth check. + if (out->buffer.size() > ada::get_max_input_length()) { + return false; + } + ada_log("url_aggregator::set_href, parsed ", out->to_string()); + // TODO: Figure out why the following line puts test to never finish. + *this = *out; + } + + return out.has_value(); +} + +ada_really_inline bool url_aggregator::parse_host(std::string_view input) { + ada_log("url_aggregator:parse_host \"", input, "\" [", input.size(), + " bytes]"); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (input.empty()) { + return is_valid = false; + } // technically unnecessary. + // If input starts with U+005B ([), then: + if (input[0] == '[') { + // If input does not end with U+005D (]), validation error, return failure. + if (input.back() != ']') { + return is_valid = false; + } + ada_log("parse_host ipv6"); + + // Return the result of IPv6 parsing input with its leading U+005B ([) and + // trailing U+005D (]) removed. + input.remove_prefix(1); + input.remove_suffix(1); + return parse_ipv6(input); + } + + // If isNotSpecial is true, then return the result of opaque-host parsing + // input. + if (!is_special()) { + return parse_opaque_host(input); + } + // Let domain be the result of running UTF-8 decode without BOM on the + // percent-decoding of input. Let asciiDomain be the result of running domain + // to ASCII with domain and false. The most common case is an ASCII input, in + // which case we do not need to call the expensive 'to_ascii' if a few + // conditions are met: no '%' and no 'xn-' subsequence. + + // Often, the input does not contain any forbidden code points, and no upper + // case ASCII letter, then we can just copy it to the buffer. We want to + // optimize for such a common case. + + // Fast path: try to parse as pure decimal IPv4(a.b.c.d) first. + const uint64_t fast_result = checkers::try_parse_ipv4_fast(input); + if (fast_result < checkers::ipv4_fast_fail) { + // Fast path succeeded - input is pure decimal IPv4 + if (!input.empty() && input.back() == '.') { + update_base_hostname(input.substr(0, input.size() - 1)); + } else { + update_base_hostname(input); + } + host_type = IPV4; + is_valid = true; + ada_log("parse_host fast path decimal ipv4"); + ADA_ASSERT_TRUE(validate()); + return true; + } + uint8_t is_forbidden_or_upper = + unicode::contains_forbidden_domain_code_point_or_upper(input.data(), + input.size()); + // Minor optimization opportunity: + // contains_forbidden_domain_code_point_or_upper could be extend to check for + // the presence of characters that cannot appear in the ipv4 address and we + // could also check whether x and n and - are present, and so we could skip + // some of the checks below. However, the gains are likely to be small, and + // the code would be more complex. + static constexpr std::string_view xn_dash{"xn-", 3}; + if (is_forbidden_or_upper == 0 && + input.find(xn_dash) == std::string_view::npos) { + // fast path + update_base_hostname(input); + + // Check for other IPv4 formats (hex, octal, etc.) + if (checkers::is_ipv4(get_hostname())) { + ada_log("parse_host fast path ipv4"); + return parse_ipv4(get_hostname(), true); + } + ada_log("parse_host fast path ", get_hostname()); + is_valid = true; + return true; + } + // We have encountered at least one forbidden code point or the input contains + // 'xn-' (case insensitive), so we need to call 'to_ascii' to perform the full + // conversion. + + ada_log("parse_host calling to_ascii"); + std::optional host = std::string(get_hostname()); + is_valid = ada::unicode::to_ascii(host, input, input.find('%')); + if (!is_valid) { + ada_log("parse_host to_ascii returns false"); + return is_valid = false; + } + ada_log("parse_host to_ascii succeeded ", *host, " [", host->size(), + " bytes]"); + + if (std::ranges::any_of(host.value(), + ada::unicode::is_forbidden_domain_code_point)) { + return is_valid = false; + } + + // If asciiDomain ends in a number, then return the result of IPv4 parsing + // asciiDomain. + if (checkers::is_ipv4(host.value())) { + ada_log("parse_host got ipv4 ", *host); + return parse_ipv4(host.value(), false); + } + + update_base_hostname(host.value()); + ADA_ASSERT_TRUE(validate()); + return true; +} + +template +bool url_aggregator::set_host_or_hostname(const std::string_view input) { + ada_log("url_aggregator::set_host_or_hostname ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (has_opaque_path) { + return false; + } + + url_aggregator saved_url(*this); + + size_t host_end_pos = input.find('#'); + std::string _host(input.data(), host_end_pos != std::string_view::npos + ? host_end_pos + : input.size()); + helpers::remove_ascii_tab_or_newline(_host); + std::string_view new_host(_host); + + auto check_url_size = [&]() -> bool { + if (buffer.size() > ada::get_max_input_length()) { + *this = std::move(saved_url); + return false; + } + return true; + }; + + // If url's scheme is "file", then set state to file host state, instead of + // host state. + if (type != ada::scheme::type::FILE) { + std::string_view host_view(_host.data(), _host.length()); + auto [location, found_colon] = + helpers::get_host_delimiter_location(is_special(), host_view); + + // Otherwise, if c is U+003A (:) and insideBrackets is false, then: + // Note: the 'found_colon' value is true if and only if a colon was + // encountered while not inside brackets. + if (found_colon) { + // If buffer is the empty string, host-missing validation error, return + // failure. + std::string_view host_buffer = host_view.substr(0, location); + if (host_buffer.empty()) { + return false; + } + + // If state override is given and state override is hostname state, then + // return failure. + if constexpr (override_hostname) { + return false; + } + + // Let host be the result of host parsing buffer with url is not special. + bool succeeded = parse_host(host_buffer); + if (!succeeded) { + *this = std::move(saved_url); + return false; + } else if (has_dash_dot()) { + // The url now has a non-null host, so the "/." that guarded a + // leading "//" path is no longer needed. Drop it before the port is + // inserted at host_end, otherwise it stays wedged in the path. + delete_dash_dot(); + } + + // Set url's host to host, buffer to the empty string, and state to port + // state. + std::string_view port_buffer = new_host.substr(location + 1); + if (!port_buffer.empty()) { + set_port(port_buffer); + } + return check_url_size(); + } + // Otherwise, if one of the following is true: + // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) + // - url is special and c is U+005C (\) + else { + // If url is special and host_view is the empty string, host-missing + // validation error, return failure. + if (host_view.empty() && is_special()) { + return false; + } + + // Otherwise, if state override is given, host_view is the empty string, + // and either url includes credentials or url's port is non-null, then + // return failure. + if (host_view.empty() && (has_credentials() || has_port())) { + return false; + } + + // Let host be the result of host parsing host_view with url is not + // special. + if (host_view.empty() && !is_special()) { + if (has_hostname()) { + clear_hostname(); // easy! + } else if (has_dash_dot()) { + add_authority_slashes_if_needed(); + delete_dash_dot(); + } else { + // The url has no authority yet (e.g. "foo:/bar"); setting an empty + // host must still give it an (empty) authority, matching ada::url. + add_authority_slashes_if_needed(); + } + return check_url_size(); + } + + bool succeeded = parse_host(host_view); + if (!succeeded) { + *this = std::move(saved_url); + return false; + } else if (has_dash_dot()) { + // Should remove dash_dot from pathname + delete_dash_dot(); + } + return check_url_size(); + } + } + + size_t location = new_host.find_first_of("/\\?"); + if (location != std::string_view::npos) { + new_host.remove_suffix(new_host.length() - location); + } + + if (new_host.empty()) { + // Set url's host to the empty string. + clear_hostname(); + } else { + // Let host be the result of host parsing buffer with url is not special. + if (!parse_host(new_host)) { + *this = std::move(saved_url); + return false; + } + + // If host is "localhost", then set host to the empty string. + if (helpers::substring(buffer, components.host_start, + components.host_end) == "localhost") { + clear_hostname(); + } + } + ADA_ASSERT_TRUE(validate()); + return check_url_size(); +} + +bool url_aggregator::set_host(const std::string_view input) { + ada_log("url_aggregator::set_host '", input, "'"); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + return set_host_or_hostname(input); +} + +bool url_aggregator::set_hostname(const std::string_view input) { + ada_log("url_aggregator::set_hostname '", input, "'"); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + return set_host_or_hostname(input); +} + +[[nodiscard]] std::string url_aggregator::get_origin() const { + ada_log("url_aggregator::get_origin"); + if (is_special()) { + // Return a new opaque origin. + if (type == scheme::FILE) { + return "null"; + } + + return helpers::concat(get_protocol(), "//", get_host()); + } + + if (get_protocol() == "blob:") { + std::string_view path = get_pathname(); + if (!path.empty()) { + auto out = ada::parse(path); + if (out && (out->type == scheme::HTTP || out->type == scheme::HTTPS)) { + // If pathURL's scheme is not "http" and not "https", then return a + // new opaque origin. + return helpers::concat(out->get_protocol(), "//", out->get_host()); + } + } + } + + // Return a new opaque origin. + return "null"; +} + +[[nodiscard]] std::string_view url_aggregator::get_username() const + ada_lifetime_bound { + ada_log("url_aggregator::get_username"); + if (has_non_empty_username()) { + return helpers::substring(buffer, components.protocol_end + 2, + components.username_end); + } + return ""; +} + +[[nodiscard]] std::string_view url_aggregator::get_password() const + ada_lifetime_bound { + ada_log("url_aggregator::get_password"); + if (has_non_empty_password()) { + return helpers::substring(buffer, components.username_end + 1, + components.host_start); + } + return ""; +} + +[[nodiscard]] std::string_view url_aggregator::get_port() const + ada_lifetime_bound { + ada_log("url_aggregator::get_port"); + if (components.port == url_components::omitted) { + return ""; + } + return helpers::substring(buffer, components.host_end + 1, + components.pathname_start); +} + +[[nodiscard]] std::string_view url_aggregator::get_hash() const + ada_lifetime_bound { + ada_log("url_aggregator::get_hash"); + // If this's URL's fragment is either null or the empty string, then return + // the empty string. Return U+0023 (#), followed by this's URL's fragment. + if (components.hash_start == url_components::omitted) { + return ""; + } + if (buffer.size() - components.hash_start <= 1) { + return ""; + } + return helpers::substring(buffer, components.hash_start); +} + +[[nodiscard]] std::string_view url_aggregator::get_host() const + ada_lifetime_bound { + ada_log("url_aggregator::get_host"); + // Technically, we should check if there is a hostname, but + // the code below works even if there isn't. + // if(!has_hostname()) { return ""; } + size_t start = components.host_start; + if (components.host_end > components.host_start && + buffer[components.host_start] == '@') { + start++; + } + // if we have an empty host, then the space between components.host_end and + // components.pathname_start may be occupied by /. + if (start == components.host_end) { + return {}; + } + return helpers::substring(buffer, start, components.pathname_start); +} + +[[nodiscard]] std::string_view url_aggregator::get_hostname() const + ada_lifetime_bound { + ada_log("url_aggregator::get_hostname"); + // Technically, we should check if there is a hostname, but + // the code below works even if there isn't. + // if(!has_hostname()) { return ""; } + size_t start = components.host_start; + // So host_start is not where the host begins. + if (components.host_end > components.host_start && + buffer[components.host_start] == '@') { + start++; + } + return helpers::substring(buffer, start, components.host_end); +} + +[[nodiscard]] std::string_view url_aggregator::get_search() const + ada_lifetime_bound { + ada_log("url_aggregator::get_search"); + // If this's URL's query is either null or the empty string, then return the + // empty string. Return U+003F (?), followed by this's URL's query. + if (components.search_start == url_components::omitted) { + return ""; + } + auto ending_index = uint32_t(buffer.size()); + if (components.hash_start != url_components::omitted) { + ending_index = components.hash_start; + } + if (ending_index - components.search_start <= 1) { + return ""; + } + return helpers::substring(buffer, components.search_start, ending_index); +} + +[[nodiscard]] std::string_view url_aggregator::get_protocol() const + ada_lifetime_bound { + ada_log("url_aggregator::get_protocol"); + return helpers::substring(buffer, 0, components.protocol_end); +} + +[[nodiscard]] std::string ada::url_aggregator::to_string() const { + ada_log("url_aggregator::to_string buffer:", buffer, " [", buffer.size(), + " bytes]"); + if (!is_valid) { + return "null"; + } + + std::string answer; + auto back = std::back_insert_iterator(answer); + answer.append("{\n"); + + answer.append("\t\"buffer\":\""); + helpers::encode_json(buffer, back); + answer.append("\",\n"); + + answer.append("\t\"protocol\":\""); + helpers::encode_json(get_protocol(), back); + answer.append("\",\n"); + + if (has_credentials()) { + answer.append("\t\"username\":\""); + helpers::encode_json(get_username(), back); + answer.append("\",\n"); + answer.append("\t\"password\":\""); + helpers::encode_json(get_password(), back); + answer.append("\",\n"); + } + + answer.append("\t\"host\":\""); + helpers::encode_json(get_host(), back); + answer.append("\",\n"); + + answer.append("\t\"path\":\""); + helpers::encode_json(get_pathname(), back); + answer.append("\",\n"); + answer.append("\t\"opaque path\":"); + answer.append((has_opaque_path ? "true" : "false")); + answer.append(",\n"); + + if (components.search_start != url_components::omitted) { + answer.append("\t\"query\":\""); + helpers::encode_json(get_search(), back); + answer.append("\",\n"); + } + if (components.hash_start != url_components::omitted) { + answer.append("\t\"fragment\":\""); + helpers::encode_json(get_hash(), back); + answer.append("\",\n"); + } + + auto convert_offset_to_string = [](uint32_t offset) -> std::string { + if (offset == url_components::omitted) { + return "null"; + } else { + return std::to_string(offset); + } + }; + + answer.append("\t\"protocol_end\":"); + answer.append(convert_offset_to_string(components.protocol_end)); + answer.append(",\n"); + + answer.append("\t\"username_end\":"); + answer.append(convert_offset_to_string(components.username_end)); + answer.append(",\n"); + + answer.append("\t\"host_start\":"); + answer.append(convert_offset_to_string(components.host_start)); + answer.append(",\n"); + + answer.append("\t\"host_end\":"); + answer.append(convert_offset_to_string(components.host_end)); + answer.append(",\n"); + + answer.append("\t\"port\":"); + answer.append(convert_offset_to_string(components.port)); + answer.append(",\n"); + + answer.append("\t\"pathname_start\":"); + answer.append(convert_offset_to_string(components.pathname_start)); + answer.append(",\n"); + + answer.append("\t\"search_start\":"); + answer.append(convert_offset_to_string(components.search_start)); + answer.append(",\n"); + + answer.append("\t\"hash_start\":"); + answer.append(convert_offset_to_string(components.hash_start)); + answer.append("\n}"); + + return answer; +} + +[[nodiscard]] bool url_aggregator::has_valid_domain() const noexcept { + if (components.host_start == components.host_end) { + return false; + } + // Avoid allocation: construct a string_view directly into the buffer. + size_t start = components.host_start; + if (components.host_end > components.host_start && + buffer[components.host_start] == '@') { + start++; + } + return checkers::verify_dns_length( + std::string_view(buffer.data() + start, components.host_end - start)); +} + +bool url_aggregator::parse_ipv4(std::string_view input, bool in_place) { + ada_log("parse_ipv4 ", input, " [", input.size(), + " bytes], overlaps with buffer: ", + helpers::overlaps(input, buffer) ? "yes" : "no"); + ADA_ASSERT_TRUE(validate()); + if (input.empty()) { + return is_valid = false; + } + const bool trailing_dot = (input.back() == '.'); + if (trailing_dot) { + input.remove_suffix(1); + if (input.empty()) { + return is_valid = false; + } + } + + const uint64_t fast = checkers::try_parse_ipv4_fast(input); + if (fast < checkers::ipv4_fast_fail) [[likely]] { + // Pure decimal: keep the buffer when it already holds the address. + // Otherwise write the (trailing-dot-stripped) input. + if (!(in_place && !trailing_dot)) { + update_base_hostname(input); + } + host_type = IPV4; + ADA_ASSERT_TRUE(validate()); + return true; + } + + const char* p = input.data(); + const char* end = p + input.size(); + uint64_t ipv4 = 0; + int digit_count = 0; + int pure_decimal_count = 0; + + for (; digit_count < 4 && p < end; ++digit_count) { + uint64_t segment = 0; + bool pure = false; + if (!detail::parse_ipv4_number(p, end, segment, pure)) { + return is_valid = false; + } + if (pure) { + ++pure_decimal_count; + } + if (p >= end) { + const unsigned shift = static_cast(32 - digit_count * 8); + if (segment >= (uint64_t{1} << shift)) { + return is_valid = false; + } + ipv4 = (ipv4 << shift) | segment; + goto ipv4_done; + } + if (segment > 255 || *p != '.') { + return is_valid = false; + } + ipv4 = (ipv4 << 8) | segment; + ++p; + } + if (digit_count != 4 || p != end) { + return is_valid = false; + } +ipv4_done: + ada_log("url_aggregator::parse_ipv4 completed ", get_href(), + " host: ", get_host()); + if (in_place && pure_decimal_count == 4 && !trailing_dot) { + ada_log( + "url_aggregator::parse_ipv4 completed and was already correct in the " + "buffer"); + } else { + update_base_hostname(ada::serializers::ipv4(ipv4)); + } + host_type = IPV4; + ADA_ASSERT_TRUE(validate()); + return true; +} + +bool url_aggregator::parse_ipv6(std::string_view input) { + ada_log("parse_ipv6 ", input, " [", input.size(), " bytes]"); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (input.empty() || input.size() > 45) [[unlikely]] { + return is_valid = false; + } +#if defined(ADA_AVX512) + if (!detail::ipv6_structure_plausible(input.data(), input.size())) + [[unlikely]] { + return is_valid = false; + } +#endif + + std::array address{}; + const char* pointer = input.data(); + const char* const end = pointer + input.size(); + int piece_index = 0; + int compress = -1; + + if (*pointer == ':') { + if (input.size() == 1 || pointer[1] != ':') [[unlikely]] { + return is_valid = false; + } + pointer += 2; + compress = ++piece_index; + } + + while (pointer != end) { + if (piece_index == 8) [[unlikely]] { + return is_valid = false; + } + if (*pointer == ':') { + if (compress != -1) [[unlikely]] { + return is_valid = false; + } + ++pointer; + compress = ++piece_index; + continue; + } + + uint16_t value = 0; + const int length = detail::parse_hex_piece(pointer, end, value); + + if (pointer != end && *pointer == '.') { + if (length == 0) [[unlikely]] { + return is_valid = false; + } + pointer -= length; + if (piece_index > 6) [[unlikely]] { + return is_valid = false; + } + + int numbers_seen = 0; + while (pointer != end) { + int ipv4_piece = -1; + if (numbers_seen > 0) { + if (*pointer == '.' && numbers_seen < 4) { + ++pointer; + } else { + return is_valid = false; + } + } + if (pointer == end || *pointer < '0' || *pointer > '9') [[unlikely]] { + return is_valid = false; + } + ipv4_piece = *pointer - '0'; + ++pointer; + if (pointer != end && *pointer >= '0' && *pointer <= '9') { + if (ipv4_piece == 0) [[unlikely]] { + return is_valid = false; + } + ipv4_piece = ipv4_piece * 10 + (*pointer - '0'); + ++pointer; + if (pointer != end && *pointer >= '0' && *pointer <= '9') { + ipv4_piece = ipv4_piece * 10 + (*pointer - '0'); + ++pointer; + if (ipv4_piece > 255) [[unlikely]] { + return is_valid = false; + } + } + } + address[static_cast(piece_index)] = static_cast( + address[static_cast(piece_index)] * 0x100 + + static_cast(ipv4_piece)); + ++numbers_seen; + if (numbers_seen == 2 || numbers_seen == 4) { + ++piece_index; + } + } + if (numbers_seen != 4) [[unlikely]] { + return is_valid = false; + } + break; + } + + if (length == 0) [[unlikely]] { + return is_valid = false; + } + + if (pointer != end && *pointer == ':') { + ++pointer; + if (pointer == end) [[unlikely]] { + return is_valid = false; + } + } else if (pointer != end) [[unlikely]] { + return is_valid = false; + } + + address[static_cast(piece_index)] = value; + ++piece_index; + } + + if (compress != -1) { + const int right = piece_index - compress; + if (right > 0) { + const size_t dest = static_cast(8 - right); + const size_t src = static_cast(compress); + if (dest != src) { + for (size_t i = static_cast(right); i-- > 0;) { + address[dest + i] = address[src + i]; + address[src + i] = 0; + } + } + } + } else if (piece_index != 8) [[unlikely]] { + return is_valid = false; + } + + // Serialize once; skip rewrite when hostname is already canonical. + const std::string serialized = ada::serializers::ipv6(address); + const std::string_view current = get_hostname(); + if (current.size() == serialized.size() && + std::memcmp(current.data(), serialized.data(), serialized.size()) == 0) { + ada_log("parse_ipv6 in-place canonical match"); + } else { + update_base_hostname(serialized); + } + ada_log("parse_ipv6 ", get_hostname()); + ADA_ASSERT_TRUE(validate()); + host_type = IPV6; + return true; +} + +bool url_aggregator::parse_opaque_host(std::string_view input) { + ada_log("parse_opaque_host ", input, " [", input.size(), " bytes]"); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (std::ranges::any_of(input, ada::unicode::is_forbidden_host_code_point)) { + return is_valid = false; + } + + // Return the result of running UTF-8 percent-encode on input using the C0 + // control percent-encode set. + size_t idx = ada::unicode::percent_encode_index( + input, character_sets::C0_CONTROL_PERCENT_ENCODE); + if (idx == input.size()) { + update_base_hostname(input); + } else { + // We only create a temporary string if we need to. + update_base_hostname(ada::unicode::percent_encode( + input, character_sets::C0_CONTROL_PERCENT_ENCODE, idx)); + } + ADA_ASSERT_TRUE(validate()); + return true; +} + +[[nodiscard]] std::string url_aggregator::to_diagram() const { + if (!is_valid) { + return "invalid"; + } + std::string answer; + answer.append(buffer); + answer.append(" ["); + answer.append(std::to_string(buffer.size())); + answer.append(" bytes]"); + answer.append("\n"); + // first line + std::string line1; + line1.resize(buffer.size(), ' '); + if (components.hash_start != url_components::omitted) { + line1[components.hash_start] = '|'; + } + if (components.search_start != url_components::omitted) { + line1[components.search_start] = '|'; + } + if (components.pathname_start != buffer.size()) { + line1[components.pathname_start] = '|'; + } + if (components.host_end != buffer.size()) { + line1[components.host_end] = '|'; + } + if (components.host_start != buffer.size()) { + line1[components.host_start] = '|'; + } + if (components.username_end != buffer.size()) { + line1[components.username_end] = '|'; + } + if (components.protocol_end != buffer.size()) { + line1[components.protocol_end] = '|'; + } + answer.append(line1); + answer.append("\n"); + + std::string line2 = line1; + if (components.hash_start != url_components::omitted) { + line2[components.hash_start] = '`'; + line1[components.hash_start] = ' '; + + for (size_t i = components.hash_start + 1; i < line2.size(); i++) { + line2[i] = '-'; + } + line2.append(" hash_start"); + answer.append(line2); + answer.append("\n"); + } + + std::string line3 = line1; + if (components.search_start != url_components::omitted) { + line3[components.search_start] = '`'; + line1[components.search_start] = ' '; + + for (size_t i = components.search_start + 1; i < line3.size(); i++) { + line3[i] = '-'; + } + line3.append(" search_start "); + line3.append(std::to_string(components.search_start)); + answer.append(line3); + answer.append("\n"); + } + + std::string line4 = line1; + if (components.pathname_start != buffer.size()) { + line4[components.pathname_start] = '`'; + line1[components.pathname_start] = ' '; + for (size_t i = components.pathname_start + 1; i < line4.size(); i++) { + line4[i] = '-'; + } + line4.append(" pathname_start "); + line4.append(std::to_string(components.pathname_start)); + answer.append(line4); + answer.append("\n"); + } + + std::string line5 = line1; + if (components.host_end != buffer.size()) { + line5[components.host_end] = '`'; + line1[components.host_end] = ' '; + + for (size_t i = components.host_end + 1; i < line5.size(); i++) { + line5[i] = '-'; + } + line5.append(" host_end "); + line5.append(std::to_string(components.host_end)); + answer.append(line5); + answer.append("\n"); + } + + std::string line6 = line1; + if (components.host_start != buffer.size()) { + line6[components.host_start] = '`'; + line1[components.host_start] = ' '; + + for (size_t i = components.host_start + 1; i < line6.size(); i++) { + line6[i] = '-'; + } + line6.append(" host_start "); + line6.append(std::to_string(components.host_start)); + answer.append(line6); + answer.append("\n"); + } + + std::string line7 = line1; + if (components.username_end != buffer.size()) { + line7[components.username_end] = '`'; + line1[components.username_end] = ' '; + + for (size_t i = components.username_end + 1; i < line7.size(); i++) { + line7[i] = '-'; + } + line7.append(" username_end "); + line7.append(std::to_string(components.username_end)); + answer.append(line7); + answer.append("\n"); + } + + std::string line8 = line1; + if (components.protocol_end != buffer.size()) { + line8[components.protocol_end] = '`'; + line1[components.protocol_end] = ' '; + + for (size_t i = components.protocol_end + 1; i < line8.size(); i++) { + line8[i] = '-'; + } + line8.append(" protocol_end "); + line8.append(std::to_string(components.protocol_end)); + answer.append(line8); + answer.append("\n"); + } + + if (components.hash_start == url_components::omitted) { + answer.append("note: hash omitted\n"); + } + if (components.search_start == url_components::omitted) { + answer.append("note: search omitted\n"); + } + if (components.protocol_end > buffer.size()) { + answer.append("warning: protocol_end overflows\n"); + } + if (components.username_end > buffer.size()) { + answer.append("warning: username_end overflows\n"); + } + if (components.host_start > buffer.size()) { + answer.append("warning: host_start overflows\n"); + } + if (components.host_end > buffer.size()) { + answer.append("warning: host_end overflows\n"); + } + if (components.pathname_start > buffer.size()) { + answer.append("warning: pathname_start overflows\n"); + } + return answer; +} + +void url_aggregator::delete_dash_dot() { + ada_log("url_aggregator::delete_dash_dot"); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(has_dash_dot()); + buffer.erase(components.host_end, 2); + components.pathname_start -= 2; + if (components.search_start != url_components::omitted) { + components.search_start -= 2; + } + if (components.hash_start != url_components::omitted) { + components.hash_start -= 2; + } + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!has_dash_dot()); +} + +inline void url_aggregator::consume_prepared_path(std::string_view input) { + ada_log("url_aggregator::consume_prepared_path ", input); + /*** + * This is largely duplicated code from helpers::parse_prepared_path, which is + * unfortunate. This particular function is nearly identical, except that it + * is a method on url_aggregator. The idea is that the trivial path (which is + * very common) merely appends to the buffer. This is the same trivial path as + * with helpers::parse_prepared_path, except that we have the additional check + * for is_at_path(). Otherwise, we grab a copy of the current path and we + * modify it, and then insert it back into the buffer. + */ + uint8_t accumulator = checkers::path_signature(input); + // Let us first detect a trivial case. + // If it is special, we check that we have no dot, no %, no \ and no + // character needing percent encoding. Otherwise, we check that we have no %, + // no dot, and no character needing percent encoding. + constexpr uint8_t need_encoding = 1; + constexpr uint8_t backslash_char = 2; + constexpr uint8_t dot_char = 4; + constexpr uint8_t percent_char = 8; + bool special = type != ada::scheme::NOT_SPECIAL; + bool may_need_slow_file_handling = (type == ada::scheme::type::FILE && + checkers::is_windows_drive_letter(input)); + bool trivial_path = + (special ? (accumulator == 0) + : ((accumulator & (need_encoding | dot_char | percent_char)) == + 0)) && + (!may_need_slow_file_handling); + if (accumulator == dot_char && !may_need_slow_file_handling) { + // '4' means that we have at least one dot, but nothing that requires + // percent encoding or decoding. The only part that is not trivial is + // that we may have single dots and double dots path segments. + // If we have such segments, then we either have a path that begins + // with '.' (easy to check), or we have the sequence './'. + // Note: input cannot be empty, it must at least contain one character ('.') + // Note: we know that '\' is not present. + if (input[0] != '.') { + size_t slashdot = 0; + bool dot_is_file = true; + for (;;) { + slashdot = input.find("/.", slashdot); + if (slashdot == std::string_view::npos) { // common case + break; + } else { // uncommon + // only three cases matter: /./, /.. or a final / + slashdot += 2; + dot_is_file &= !(slashdot == input.size() || input[slashdot] == '.' || + input[slashdot] == '/'); + } + } + trivial_path = dot_is_file; + } + } + if (trivial_path && is_at_path()) { + ada_log("parse_path trivial"); + buffer += '/'; + buffer += input; + return; + } + std::string path = std::string(get_pathname()); + // We are going to need to look a bit at the path, but let us see if we can + // ignore percent encoding *and* backslashes *and* percent characters. + // Except for the trivial case, this is likely to capture 99% of paths out + // there. + bool fast_path = + (special && + (accumulator & (need_encoding | backslash_char | percent_char)) == 0) && + (type != ada::scheme::type::FILE); + if (fast_path) { + ada_log("parse_prepared_path fast"); + // Here we don't need to worry about \ or percent encoding. + // We also do not have a file protocol. We might have dots, however, + // but dots must as appear as '.', and they cannot be encoded because + // the symbol '%' is not present. + size_t previous_location = 0; // We start at 0. + do { + size_t new_location = input.find('/', previous_location); + // std::string_view path_view = input; + // We process the last segment separately: + if (new_location == std::string_view::npos) { + std::string_view path_view = input.substr(previous_location); + if (path_view == "..") { // The path ends with .. + // e.g., if you receive ".." with an empty path, you go to "/". + if (path.empty()) { + path = '/'; + update_base_pathname(path); + return; + } + // Fast case where we have nothing to do: + if (path.back() == '/') { + update_base_pathname(path); + return; + } + // If you have the path "/joe/myfriend", + // then you delete 'myfriend'. + path.resize(path.rfind('/') + 1); + update_base_pathname(path); + return; + } + path += '/'; + if (path_view != ".") { + path.append(path_view); + } + update_base_pathname(path); + return; + } else { + // This is a non-final segment. + std::string_view path_view = + input.substr(previous_location, new_location - previous_location); + previous_location = new_location + 1; + if (path_view == "..") { + size_t last_delimiter = path.rfind('/'); + if (last_delimiter != std::string::npos) { + path.erase(last_delimiter); + } + } else if (path_view != ".") { + path += '/'; + path.append(path_view); + } + } + } while (true); + } else { + ada_log("parse_path slow"); + // we have reached the general case + bool needs_percent_encoding = (accumulator & 1); + std::string path_buffer_tmp; + do { + size_t location = (special && (accumulator & 2)) + ? input.find_first_of("/\\") + : input.find('/'); + std::string_view path_view = input; + if (location != std::string_view::npos) { + path_view.remove_suffix(path_view.size() - location); + input.remove_prefix(location + 1); + } + // path_buffer is either path_view or it might point at a percent encoded + // temporary string. + std::string_view path_buffer = + (needs_percent_encoding && + ada::unicode::percent_encode( + path_view, character_sets::PATH_PERCENT_ENCODE, path_buffer_tmp)) + ? path_buffer_tmp + : path_view; + if (unicode::is_double_dot_path_segment(path_buffer)) { + helpers::shorten_path(path, type); + if (location == std::string_view::npos) { + path += '/'; + } + } else if (unicode::is_single_dot_path_segment(path_buffer) && + (location == std::string_view::npos)) { + path += '/'; + } + // Otherwise, if path_buffer is not a single-dot path segment, then: + else if (!unicode::is_single_dot_path_segment(path_buffer)) { + // If url's scheme is "file", url's path is empty, and path_buffer is a + // Windows drive letter, then replace the second code point in + // path_buffer with U+003A (:). + if (type == ada::scheme::type::FILE && path.empty() && + checkers::is_windows_drive_letter(path_buffer)) { + path += '/'; + path += path_buffer[0]; + path += ':'; + path_buffer.remove_prefix(2); + path.append(path_buffer); + } else { + // Append path_buffer to url's path. + path += '/'; + path.append(path_buffer); + } + } + if (location == std::string_view::npos) { + update_base_pathname(path); + return; + } + } while (true); + } +} +} // namespace ada +/* end file src/url_aggregator.cpp */ + +#if ADA_INCLUDE_URL_PATTERN +/* begin file src/url_pattern.cpp */ +#if ADA_INCLUDE_URL_PATTERN + + +#include +#include +#include + +namespace ada { + +tl::expected url_pattern_init::process( + const url_pattern_init& init, url_pattern_init::process_type type, + std::optional protocol, + std::optional username, + std::optional password, + std::optional hostname, + std::optional port, + std::optional pathname, + std::optional search, + std::optional hash) { + // Let result be the result of creating a new URLPatternInit. + auto result = url_pattern_init{}; + + // If protocol is not null, set result["protocol"] to protocol. + if (protocol.has_value()) result.protocol = *protocol; + + // If username is not null, set result["username"] to username. + if (username.has_value()) result.username = *username; + + // If password is not null, set result["password"] to password. + if (password.has_value()) result.password = *password; + + // If hostname is not null, set result["hostname"] to hostname. + if (hostname.has_value()) result.hostname = *hostname; + + // If port is not null, set result["port"] to port. + if (port.has_value()) result.port = *port; + + // If pathname is not null, set result["pathname"] to pathname. + if (pathname.has_value()) result.pathname = *pathname; + + // If search is not null, set result["search"] to search. + if (search.has_value()) result.search = *search; + + // If hash is not null, set result["hash"] to hash. + if (hash.has_value()) result.hash = *hash; + + // Let baseURL be null. + std::optional base_url{}; + + // If init["baseURL"] exists: + if (init.base_url.has_value()) { + // Set baseURL to the result of parsing init["baseURL"]. + auto parsing_result = ada::parse(*init.base_url); + // If baseURL is failure, then throw a TypeError. + if (!parsing_result) { + return tl::unexpected(errors::type_error); + } + base_url = std::move(*parsing_result); + + // If init["protocol"] does not exist, then set result["protocol"] to the + // result of processing a base URL string given baseURL's scheme and type. + if (!init.protocol.has_value()) { + ADA_ASSERT_TRUE(base_url.has_value()); + std::string_view base_url_protocol = base_url->get_protocol(); + if (base_url_protocol.ends_with(":")) base_url_protocol.remove_suffix(1); + result.protocol = + url_pattern_helpers::process_base_url_string(base_url_protocol, type); + } + + // If type is not "pattern" and init contains none of "protocol", + // "hostname", "port" and "username", then set result["username"] to the + // result of processing a base URL string given baseURL's username and type. + if (type != process_type::pattern && !init.protocol && !init.hostname && + !init.port && !init.username) { + result.username = url_pattern_helpers::process_base_url_string( + base_url->get_username(), type); + } + + // TODO: Optimization opportunity: Merge this with the previous check. + // If type is not "pattern" and init contains none of "protocol", + // "hostname", "port", "username" and "password", then set + // result["password"] to the result of processing a base URL string given + // baseURL's password and type. + if (type != process_type::pattern && !init.protocol && !init.hostname && + !init.port && !init.username && !init.password) { + result.password = url_pattern_helpers::process_base_url_string( + base_url->get_password(), type); + } + + // If init contains neither "protocol" nor "hostname", then: + if (!init.protocol && !init.hostname) { + // Let baseHost be baseURL's host. + // If baseHost is null, then set baseHost to the empty string. + auto base_host = base_url->get_hostname(); + // Set result["hostname"] to the result of processing a base URL string + // given baseHost and type. + result.hostname = + url_pattern_helpers::process_base_url_string(base_host, type); + } + + // If init contains none of "protocol", "hostname", and "port", then: + if (!init.protocol && !init.hostname && !init.port) { + // If baseURL's port is null, then set result["port"] to the empty string. + // Otherwise, set result["port"] to baseURL's port, serialized. + result.port = base_url->get_port(); + } + + // If init contains none of "protocol", "hostname", "port", and "pathname", + // then set result["pathname"] to the result of processing a base URL string + // given the result of URL path serializing baseURL and type. + if (!init.protocol && !init.hostname && !init.port && !init.pathname) { + result.pathname = url_pattern_helpers::process_base_url_string( + base_url->get_pathname(), type); + } + + // If init contains none of "protocol", "hostname", "port", "pathname", and + // "search", then: + if (!init.protocol && !init.hostname && !init.port && !init.pathname && + !init.search) { + // Let baseQuery be baseURL's query. get_search() carries the leading "?" + // delimiter, but the spec inherits the query itself, so drop it. + std::string_view base_query = base_url->get_search(); + if (base_query.starts_with("?")) base_query.remove_prefix(1); + // Set result["search"] to the result of processing a base URL string + // given baseQuery and type. + result.search = + url_pattern_helpers::process_base_url_string(base_query, type); + } + + // If init contains none of "protocol", "hostname", "port", "pathname", + // "search", and "hash", then: + if (!init.protocol && !init.hostname && !init.port && !init.pathname && + !init.search && !init.hash) { + // Let baseFragment be baseURL's fragment. get_hash() carries the leading + // "#" delimiter, but the spec inherits the fragment itself, so drop it. + std::string_view base_fragment = base_url->get_hash(); + if (base_fragment.starts_with("#")) base_fragment.remove_prefix(1); + // Set result["hash"] to the result of processing a base URL string given + // baseFragment and type. + result.hash = + url_pattern_helpers::process_base_url_string(base_fragment, type); + } + } + + // If init["protocol"] exists, then set result["protocol"] to the result of + // process protocol for init given init["protocol"] and type. + if (init.protocol) { + auto process_result = process_protocol(*init.protocol, type); + if (!process_result) { + return tl::unexpected(process_result.error()); + } + result.protocol = std::move(*process_result); + } + + // If init["username"] exists, then set result["username"] to the result of + // process username for init given init["username"] and type. + if (init.username.has_value()) { + auto process_result = process_username(*init.username, type); + if (!process_result) { + return tl::unexpected(process_result.error()); + } + result.username = std::move(*process_result); + } + + // If init["password"] exists, then set result["password"] to the result of + // process password for init given init["password"] and type. + if (init.password.has_value()) { + auto process_result = process_password(*init.password, type); + if (!process_result) { + return tl::unexpected(process_result.error()); + } + result.password = std::move(*process_result); + } + + // If init["hostname"] exists, then set result["hostname"] to the result of + // process hostname for init given init["hostname"] and type. + if (init.hostname.has_value()) { + auto process_result = process_hostname(*init.hostname, type); + if (!process_result) { + return tl::unexpected(process_result.error()); + } + result.hostname = std::move(*process_result); + } + + // If init["port"] exists, then set result["port"] to the result of process + // port for init given init["port"], result["protocol"], and type. + if (init.port) { + auto process_result = + process_port(*init.port, result.protocol.value_or("fake"), type); + if (!process_result) { + return tl::unexpected(process_result.error()); + } + result.port = std::move(*process_result); + } + + // If init["pathname"] exists: + if (init.pathname.has_value()) { + // Set result["pathname"] to init["pathname"]. + result.pathname = init.pathname; + + // If the following are all true: + // - baseURL is not null; + // - baseURL has an opaque path; and + // - the result of running is an absolute pathname given result["pathname"] + // and type is false, + if (base_url && !base_url->has_opaque_path && + !url_pattern_helpers::is_absolute_pathname(*result.pathname, type)) { + // Let baseURLPath be the result of running process a base URL string + // given the result of URL path serializing baseURL and type. + // TODO: Optimization opportunity: Avoid returning a string if no slash + // exist. + std::string base_url_path = url_pattern_helpers::process_base_url_string( + base_url->get_pathname(), type); + + // Let slash index be the index of the last U+002F (/) code point found in + // baseURLPath, interpreted as a sequence of code points, or null if there + // are no instances of the code point. + auto slash_index = base_url_path.find_last_of('/'); + + // If slash index is not null: + if (slash_index != std::string::npos) { + // Let new pathname be the code point substring from 0 to slash index + + // 1 within baseURLPath. + base_url_path.resize(slash_index + 1); + // Append result["pathname"] to the end of new pathname. + ADA_ASSERT_TRUE(result.pathname.has_value()); + base_url_path.append(std::move(*result.pathname)); + // Set result["pathname"] to new pathname. + result.pathname = std::move(base_url_path); + } + } + + // Set result["pathname"] to the result of process pathname for init given + // result["pathname"], result["protocol"], and type. + auto pathname_processing_result = + process_pathname(*result.pathname, result.protocol.value_or(""), type); + if (!pathname_processing_result) { + return tl::unexpected(pathname_processing_result.error()); + } + result.pathname = std::move(*pathname_processing_result); + } + + // If init["search"] exists then set result["search"] to the result of process + // search for init given init["search"] and type. + if (init.search) { + auto process_result = process_search(*init.search, type); + if (!process_result) { + return tl::unexpected(process_result.error()); + } + result.search = std::move(*process_result); + } + + // If init["hash"] exists then set result["hash"] to the result of process + // hash for init given init["hash"] and type. + if (init.hash) { + auto process_result = process_hash(*init.hash, type); + if (!process_result) { + return tl::unexpected(process_result.error()); + } + result.hash = std::move(*process_result); + } + // Return result. + return result; +} + +tl::expected url_pattern_init::process_protocol( + std::string_view value, process_type type) { + ada_log("process_protocol=", value, " [", type, "]"); + // Let strippedValue be the given value with a single trailing U+003A (:) + // removed, if any. + if (value.ends_with(":")) { + value.remove_suffix(1); + } + // If type is "pattern" then return strippedValue. + if (type == process_type::pattern) { + return std::string(value); + } + // Return the result of running canonicalize a protocol given strippedValue. + return url_pattern_helpers::canonicalize_protocol(value); +} + +tl::expected url_pattern_init::process_username( + std::string_view value, process_type type) { + // If type is "pattern" then return value. + if (type == process_type::pattern) { + return std::string(value); + } + // Return the result of running canonicalize a username given value. + return url_pattern_helpers::canonicalize_username(value); +} + +tl::expected url_pattern_init::process_password( + std::string_view value, process_type type) { + // If type is "pattern" then return value. + if (type == process_type::pattern) { + return std::string(value); + } + // Return the result of running canonicalize a password given value. + return url_pattern_helpers::canonicalize_password(value); +} + +tl::expected url_pattern_init::process_hostname( + std::string_view value, process_type type) { + ada_log("process_hostname value=", value, " type=", type); + // If type is "pattern" then return value. + if (type == process_type::pattern) { + return std::string(value); + } + // Return the result of running canonicalize a hostname given value. + return url_pattern_helpers::canonicalize_hostname(value); +} + +tl::expected url_pattern_init::process_port( + std::string_view port, std::string_view protocol, process_type type) { + // If type is "pattern" then return portValue. + if (type == process_type::pattern) { + return std::string(port); + } + // Return the result of running canonicalize a port given portValue and + // protocolValue. + return url_pattern_helpers::canonicalize_port_with_protocol(port, protocol); +} + +tl::expected url_pattern_init::process_pathname( + std::string_view value, std::string_view protocol, process_type type) { + // If type is "pattern" then return pathnameValue. + if (type == process_type::pattern) { + return std::string(value); + } + + // If protocolValue is a special scheme or the empty string, then return the + // result of running canonicalize a pathname given pathnameValue. + if (protocol.empty() || scheme::is_special(protocol)) { + return url_pattern_helpers::canonicalize_pathname(value); + } + + // Return the result of running canonicalize an opaque pathname given + // pathnameValue. + return url_pattern_helpers::canonicalize_opaque_pathname(value); +} + +tl::expected url_pattern_init::process_search( + std::string_view value, process_type type) { + // Let strippedValue be the given value with a single leading U+003F (?) + // removed, if any. + if (value.starts_with("?")) { + value.remove_prefix(1); + } + // We cannot assert that the value is no longer starting with a single + // question mark because technically it can start. The question is whether or + // not we should remove the first question mark. Ref: + // https://github.com/ada-url/ada/pull/992 The spec is not clear on this. + + // If type is "pattern" then return strippedValue. + if (type == process_type::pattern) { + return std::string(value); + } + // Return the result of running canonicalize a search given strippedValue. + return url_pattern_helpers::canonicalize_search(value); +} + +tl::expected url_pattern_init::process_hash( + std::string_view value, process_type type) { + // Let strippedValue be the given value with a single leading U+0023 (#) + // removed, if any. + if (value.starts_with("#")) { + value.remove_prefix(1); + } + ADA_ASSERT_TRUE(!value.starts_with("#")); + // If type is "pattern" then return strippedValue. + if (type == process_type::pattern) { + return std::string(value); + } + // Return the result of running canonicalize a hash given strippedValue. + return url_pattern_helpers::canonicalize_hash(value); +} + +} // namespace ada + +#endif // ADA_INCLUDE_URL_PATTERN +/* end file src/url_pattern.cpp */ +/* begin file src/url_pattern_helpers.cpp */ +#if ADA_INCLUDE_URL_PATTERN + +#include +#include +#include +#include +#include +#include + + +namespace ada::url_pattern_helpers { + +std::tuple> +generate_regular_expression_and_name_list( + const std::vector& part_list, + url_pattern_compile_component_options options) { + // Let result be "^" + std::string result = "^"; + // Reserve capacity to reduce reallocations + result.reserve(part_list.size() * 16); + + // Let name list be a new list + std::vector name_list{}; + name_list.reserve(part_list.size()); + + // Pre-generate segment wildcard regexp if needed (avoids repeated generation) + std::string segment_wildcard_regexp; + + // For each part of part list: + for (const url_pattern_part& part : part_list) { + // If part's type is "fixed-text": + if (part.type == url_pattern_part_type::FIXED_TEXT) { + // If part's modifier is "none" + if (part.modifier == url_pattern_part_modifier::none) { + result.append(escape_regexp_string(part.value)); + } else { + // (?:) + result.append("(?:"); + result.append(escape_regexp_string(part.value)); + result.push_back(')'); + result.append(convert_modifier_to_string(part.modifier)); + } + continue; + } + + // Assert: part's name is not the empty string + ADA_ASSERT_TRUE(!part.name.empty()); + name_list.push_back(part.name); + + // Use string_view to avoid copies where possible + std::string_view regexp_value = part.value; + + if (part.type == url_pattern_part_type::SEGMENT_WILDCARD) { + // Lazy generate segment wildcard regexp + if (segment_wildcard_regexp.empty()) { + segment_wildcard_regexp = generate_segment_wildcard_regexp(options); + } + regexp_value = segment_wildcard_regexp; + } else if (part.type == url_pattern_part_type::FULL_WILDCARD) { + regexp_value = ".*"; + } + + // If part's prefix is the empty string and part's suffix is the empty + // string + if (part.prefix.empty() && part.suffix.empty()) { + // If part's modifier is "none" or "optional" + if (part.modifier == url_pattern_part_modifier::none || + part.modifier == url_pattern_part_modifier::optional) { + // () + result.push_back('('); + result.append(regexp_value); + result.push_back(')'); + result.append(convert_modifier_to_string(part.modifier)); + } else { + // ((?:)) + result.append("((?:"); + result.append(regexp_value); + result.push_back(')'); + result.append(convert_modifier_to_string(part.modifier)); + result.push_back(')'); + } + continue; + } + + // If part's modifier is "none" or "optional" + if (part.modifier == url_pattern_part_modifier::none || + part.modifier == url_pattern_part_modifier::optional) { + // (?:()) + result.append("(?:"); + result.append(escape_regexp_string(part.prefix)); + result.push_back('('); + result.append(regexp_value); + result.push_back(')'); + result.append(escape_regexp_string(part.suffix)); + result.push_back(')'); + result.append(convert_modifier_to_string(part.modifier)); + continue; + } + + // Assert: part's modifier is "zero-or-more" or "one-or-more" + ADA_ASSERT_TRUE(part.modifier == url_pattern_part_modifier::zero_or_more || + part.modifier == url_pattern_part_modifier::one_or_more); + + // Assert: part's prefix is not the empty string or part's suffix is not the + // empty string + ADA_ASSERT_TRUE(!part.prefix.empty() || !part.suffix.empty()); + + // (?:((?:)(?:(?:))*))? + // Append "(?:" to the end of result. + result.append("(?:"); + // Append the result of running escape a regexp string given part's prefix + // to the end of result. + result.append(escape_regexp_string(part.prefix)); + // Append "((?:" to the end of result. + result.append("((?:"); + // Append regexp value to the end of result. + result.append(regexp_value); + // Append ")(?:" to the end of result. + result.append(")(?:"); + // Append the result of running escape a regexp string given part's suffix + // to the end of result. + result.append(escape_regexp_string(part.suffix)); + // Append the result of running escape a regexp string given part's prefix + // to the end of result. + result.append(escape_regexp_string(part.prefix)); + // Append "(?:" to the end of result. + result.append("(?:"); + // Append regexp value to the end of result. + result.append(regexp_value); + // Append "))*)" to the end of result. + result.append("))*)"); + // Append the result of running escape a regexp string given part's suffix + // to the end of result. + result.append(escape_regexp_string(part.suffix)); + // Append ")" to the end of result. + result.append(")"); + + // If part's modifier is "zero-or-more" then append "?" to the end of result + if (part.modifier == url_pattern_part_modifier::zero_or_more) { + result += "?"; + } + } + + // Append "$" to the end of result + result += "$"; + + // Return (result, name list) + return {std::move(result), std::move(name_list)}; +} + +bool is_ipv6_address(std::string_view input) noexcept { + // If input's code point length is less than 2, then return false. + if (input.size() < 2) return false; + + // Let input code points be input interpreted as a list of code points. + // If input code points[0] is U+005B ([), then return true. + if (input.front() == '[') return true; + // If input code points[0] is U+007B ({) and input code points[1] is U+005B + // ([), then return true. + if (input.starts_with("{[")) return true; + // If input code points[0] is U+005C (\) and input code points[1] is U+005B + // ([), then return true. + return input.starts_with("\\["); +} + +std::string_view convert_modifier_to_string( + url_pattern_part_modifier modifier) { + switch (modifier) { + // If modifier is "zero-or-more", then return "*". + case url_pattern_part_modifier::zero_or_more: + return "*"; + // If modifier is "optional", then return "?". + case url_pattern_part_modifier::optional: + return "?"; + // If modifier is "one-or-more", then return "+". + case url_pattern_part_modifier::one_or_more: + return "+"; + // Return the empty string. + default: + return ""; + } +} + +std::string generate_segment_wildcard_regexp( + url_pattern_compile_component_options options) { + // Let result be "[^". + std::string result = "[^"; + // Append the result of running escape a regexp string given options's + // delimiter code point to the end of result. + result.append(escape_regexp_string(options.get_delimiter())); + // Append "]+?" to the end of result. + result.append("]+?"); + // Return result. + ada_log("generate_segment_wildcard_regexp result: ", result); + return result; +} + +namespace { +// Unified lookup table for URL pattern character classification +// Bit flags for different character types +constexpr uint8_t CHAR_SCHEME = 1; // valid in scheme (a-z, A-Z, 0-9, +, -, .) +constexpr uint8_t CHAR_UPPER = 2; // uppercase letter (needs lowercasing) +constexpr uint8_t CHAR_SIMPLE_HOSTNAME = 4; // simple hostname (a-z, 0-9, -, .) +constexpr uint8_t CHAR_SIMPLE_PATHNAME = + 8; // simple pathname (a-z, A-Z, 0-9, /, -, _, ~) + +constexpr std::array char_class_table = []() consteval { + std::array table{}; + for (int c = 'a'; c <= 'z'; c++) + table[c] = CHAR_SCHEME | CHAR_SIMPLE_HOSTNAME | CHAR_SIMPLE_PATHNAME; + for (int c = 'A'; c <= 'Z'; c++) + table[c] = CHAR_SCHEME | CHAR_UPPER | CHAR_SIMPLE_PATHNAME; + for (int c = '0'; c <= '9'; c++) + table[c] = CHAR_SCHEME | CHAR_SIMPLE_HOSTNAME | CHAR_SIMPLE_PATHNAME; + table['+'] = CHAR_SCHEME; + table['-'] = CHAR_SCHEME | CHAR_SIMPLE_HOSTNAME | CHAR_SIMPLE_PATHNAME; + table['.'] = + CHAR_SCHEME | CHAR_SIMPLE_HOSTNAME; // not pathname (needs normalization) + table['/'] = CHAR_SIMPLE_PATHNAME; + table['_'] = CHAR_SIMPLE_PATHNAME; + table['~'] = CHAR_SIMPLE_PATHNAME; + return table; +}(); +} // namespace + +tl::expected canonicalize_protocol( + std::string_view input) { + ada_log("canonicalize_protocol called with input=", input); + if (input.empty()) [[unlikely]] { + return ""; + } + + if (input.ends_with(":")) { + input.remove_suffix(1); + } + + // Fast path: special schemes are already canonical + if (scheme::is_special(input)) { + return std::string(input); + } + + // Fast path: validate scheme chars and check for uppercase + // First char must be alpha (not +, -, ., or digit) + uint8_t first_flags = char_class_table[static_cast(input[0])]; + if (!(first_flags & CHAR_SCHEME) || input[0] == '+' || input[0] == '-' || + input[0] == '.' || unicode::is_ascii_digit(input[0])) { + return tl::unexpected(errors::type_error); + } + + uint8_t needs_lowercase = first_flags & CHAR_UPPER; + for (size_t i = 1; i < input.size(); i++) { + uint8_t flags = char_class_table[static_cast(input[i])]; + if (!(flags & CHAR_SCHEME)) { + return tl::unexpected(errors::type_error); + } + needs_lowercase |= flags & CHAR_UPPER; + } + + if (needs_lowercase == 0) { + return std::string(input); + } + + std::string result(input); + unicode::to_lower_ascii(result.data(), result.size()); + return result; +} + +tl::expected canonicalize_username( + std::string_view input) { + // If value is the empty string, return value. + if (input.empty()) [[unlikely]] { + return ""; + } + // Percent-encode the input using the userinfo percent-encode set. + size_t idx = ada::unicode::percent_encode_index( + input, character_sets::USERINFO_PERCENT_ENCODE); + if (idx == input.size()) { + // No encoding needed, return input as-is + return std::string(input); + } + // Percent-encode from the first character that needs encoding + return ada::unicode::percent_encode( + input, character_sets::USERINFO_PERCENT_ENCODE, idx); +} + +tl::expected canonicalize_password( + std::string_view input) { + // If value is the empty string, return value. + if (input.empty()) [[unlikely]] { + return ""; + } + // Percent-encode the input using the userinfo percent-encode set. + size_t idx = ada::unicode::percent_encode_index( + input, character_sets::USERINFO_PERCENT_ENCODE); + if (idx == input.size()) { + // No encoding needed, return input as-is + return std::string(input); + } + // Percent-encode from the first character that needs encoding + return ada::unicode::percent_encode( + input, character_sets::USERINFO_PERCENT_ENCODE, idx); +} + +tl::expected canonicalize_hostname( + std::string_view input) { + ada_log("canonicalize_hostname input=", input); + if (input.empty()) [[unlikely]] { + return ""; + } + + // Fast path: simple hostnames (lowercase ASCII, digits, -, .) need no IDNA. + // The simple character set also covers IPv4-shaped hosts, which the slow + // path rewrites ("0" -> "0.0.0.0", "0x7f.1" -> "127.0.0.1"). Exclude those + // so the fast path can't return a non-canonical hostname. + // + // Pure-ASCII "xn--" labels are intentionally left on the fast path: with + // beStrict=false, domain-to-ASCII returns the lowercased ASCII input even + // when Unicode ToASCII would fail (e.g. invalid ACE "xn--a"). See + // https://url.spec.whatwg.org/#concept-domain-to-ascii + bool needs_processing = false; + for (char c : input) { + needs_processing |= + !(char_class_table[static_cast(c)] & CHAR_SIMPLE_HOSTNAME); + } + if (!needs_processing && !checkers::is_ipv4(input)) { + return std::string(input); + } + + // Let dummyURL be a new URL record. + // Let parseResult be the result of running the basic URL parser given value + // with dummyURL as url and hostname state as state override. + + // IMPORTANT: The protocol needs to be a special protocol, otherwise the + // hostname will not be converted using IDNA. + auto url = ada::parse("https://dummy.test", nullptr); + ADA_ASSERT_TRUE(url); + // if (!isValidHostnameInput(hostname)) return kj::none; + if (!url->set_hostname(input)) { + // If parseResult is failure, then throw a TypeError. + return tl::unexpected(errors::type_error); + } + // Return dummyURL's host, serialized, or empty string if it is null. + return std::string(url->get_hostname()); +} + +tl::expected canonicalize_ipv6_hostname( + std::string_view input) { + ada_log("canonicalize_ipv6_hostname input=", input); + // TODO: Optimization opportunity: Use lookup table to speed up checking + if (std::ranges::any_of(input, [](char c) { + return c != '[' && c != ']' && c != ':' && + !unicode::is_ascii_hex_digit(c); + })) { + return tl::unexpected(errors::type_error); + } + // Append the result of running ASCII lowercase given code point to the end of + // result. + auto hostname = std::string(input); + unicode::to_lower_ascii(hostname.data(), hostname.size()); + return hostname; +} + +tl::expected canonicalize_port( + std::string_view port_value) { + // If portValue is the empty string, return portValue. + if (port_value.empty()) [[unlikely]] { + return ""; + } + + // Remove ASCII tab or newline characters + std::string trimmed(port_value); + helpers::remove_ascii_tab_or_newline(trimmed); + + if (trimmed.empty()) { + return ""; + } + + // Input should start with a digit character + if (!unicode::is_ascii_digit(trimmed.front())) { + return tl::unexpected(errors::type_error); + } + + // Find the first non-digit character + auto first_non_digit = + std::ranges::find_if_not(trimmed, unicode::is_ascii_digit); + std::string_view digits_to_parse = + std::string_view(trimmed.data(), first_non_digit - trimmed.begin()); + + // Here we have a range of ASCII digit characters identified by + // digits_to_parse. It is non-empty. The port state of the URL parser reads + // it as an integer, so leading zeros are part of the number: "0080" is 80 + // and "065535" is 65535, not a six-digit overflow. Only the significant + // digits count toward the 5-digit maximum, matching the fast path in + // implementation.cpp. + size_t first_significant = digits_to_parse.find_first_not_of('0'); + if (first_significant == std::string_view::npos) { + // The value is all zeros, i.e. port 0. + return "0"; + } + digits_to_parse.remove_prefix(first_significant); + // We want to determine whether it is a valid port number (0-65535). + // Clearly, if the length is greater than 5, it is invalid. + // If the length is 5, we need to compare lexicographically to "65535". + // Otherwise it is valid. + if (digits_to_parse.size() == 5) { + if (digits_to_parse > "65535") { + return tl::unexpected(errors::type_error); + } + } else if (digits_to_parse.size() > 5) { + return tl::unexpected(errors::type_error); + } + // It is valid! Most times, we do not need to parse it into an integer. + return std::string(digits_to_parse); +} + +tl::expected canonicalize_port_with_protocol( + std::string_view port_value, std::string_view protocol) { + // If portValue is the empty string, return portValue. + if (port_value.empty()) [[unlikely]] { + return ""; + } + + // Handle empty or trailing colon in protocol + if (protocol.empty()) { + protocol = "fake"; + } else if (protocol.ends_with(":")) { + protocol.remove_suffix(1); + } + + // Remove ASCII tab or newline characters + std::string trimmed(port_value); + helpers::remove_ascii_tab_or_newline(trimmed); + + if (trimmed.empty()) { + return ""; + } + + // Input should start with a digit character + if (!unicode::is_ascii_digit(trimmed.front())) { + return tl::unexpected(errors::type_error); + } + + // Find the first non-digit character + auto first_non_digit = + std::ranges::find_if_not(trimmed, unicode::is_ascii_digit); + std::string_view digits_to_parse = + std::string_view(trimmed.data(), first_non_digit - trimmed.begin()); + + // Parse the port number + uint16_t parsed_port{}; + // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage) + auto result = std::from_chars(digits_to_parse.data(), + digits_to_parse.data() + digits_to_parse.size(), + parsed_port); + + if (result.ec == std::errc::result_out_of_range) { + return tl::unexpected(errors::type_error); + } + + if (result.ec == std::errc()) { + // Check if this is the default port for the scheme + uint16_t default_port = scheme::get_special_port(protocol); + + // If it's the default port for a special scheme, return empty string + if (default_port != 0 && default_port == parsed_port) { + return ""; + } + + // Successfully parsed, return as string + return std::to_string(parsed_port); + } + + return tl::unexpected(errors::type_error); +} + +tl::expected canonicalize_pathname( + std::string_view input) { + if (input.empty()) [[unlikely]] { + return ""; + } + + // Fast path: simple pathnames (no . which needs normalization) can be + // returned as-is + bool needs_processing = false; + for (char c : input) { + needs_processing |= + !(char_class_table[static_cast(c)] & CHAR_SIMPLE_PATHNAME); + } + if (!needs_processing) { + return std::string(input); + } + + // Let leading slash be true if the first code point in value is U+002F (/) + // and otherwise false. + const bool leading_slash = input.starts_with("/"); + // Let modified value be "/-" if leading slash is false and otherwise the + // empty string. + const auto modified_value = + (leading_slash ? std::string() : std::string("/-")) + std::string(input); + // The spec runs the basic URL parser with the path in state override, where + // '?' and '#' are ordinary path code points (percent-encoded) and leading or + // trailing C0 control or space is kept. Building a full URL string and + // parsing it (no state override) instead let '?' and '#' start the + // query/fragment, so the pathname was silently truncated at the first literal + // '?' or '#'. set_pathname runs the parser in path state override, matching + // how canonicalize_hostname uses set_hostname. + auto url = ada::parse("fake://fake-url", nullptr); + ADA_ASSERT_TRUE(url); + if (!url->set_pathname(modified_value)) { + // If parseResult is failure, then throw a TypeError. + return tl::unexpected(errors::type_error); + } + const auto pathname = url->get_pathname(); + // If leading slash is false, then set result to the code point substring + // from 2 to the end of the string within result. + if (!leading_slash) { + // pathname should start with "/-" but path traversal (e.g. "../../") + // can reduce it to just "/" which is shorter than 2 characters. + if (pathname.size() < 2) { + return tl::unexpected(errors::type_error); + } + return std::string(pathname.substr(2)); + } + return std::string(pathname); +} + +tl::expected canonicalize_opaque_pathname( + std::string_view input) { + // If value is the empty string, return value. + if (input.empty()) [[unlikely]] { + return ""; + } + // Let dummyURL be a new URL record. + // Set dummyURL's path to the empty string. + // Let parseResult be the result of running URL parsing given value with + // dummyURL as url and opaque path state as state override. + if (auto url = + ada::parse("fake:" + std::string(input), nullptr)) { + // Return the result of URL path serializing dummyURL. + return std::string(url->get_pathname()); + } + // If parseResult is failure, then throw a TypeError. + return tl::unexpected(errors::type_error); +} + +tl::expected canonicalize_search(std::string_view input) { + // If value is the empty string, return value. + if (input.empty()) [[unlikely]] { + return ""; + } + // A leading '?' is a valid query code point here: it is the caller (process a + // search) that removes a single delimiter, not this step, which mirrors the + // basic URL parser's query state. + std::string new_value(input); + // Remove ASCII tab or newline characters + helpers::remove_ascii_tab_or_newline(new_value); + + if (new_value.empty()) { + return ""; + } + + // Percent-encode using QUERY_PERCENT_ENCODE (for non-special URLs) + // Note: "fake://dummy.test" is not a special URL, so we use + // QUERY_PERCENT_ENCODE + size_t idx = ada::unicode::percent_encode_index( + new_value, character_sets::QUERY_PERCENT_ENCODE); + if (idx == new_value.size()) { + // No encoding needed + return new_value; + } + // Percent-encode from the first character that needs encoding + return ada::unicode::percent_encode( + new_value, character_sets::QUERY_PERCENT_ENCODE, idx); +} + +tl::expected canonicalize_hash(std::string_view input) { + // If value is the empty string, return value. + if (input.empty()) [[unlikely]] { + return ""; + } + // A leading '#' is a valid fragment code point here: it is the caller + // (process a hash) that removes a single delimiter, not this step, which + // mirrors the basic URL parser's fragment state. + std::string new_value(input); + // Remove ASCII tab or newline characters + helpers::remove_ascii_tab_or_newline(new_value); + + if (new_value.empty()) { + return ""; + } + + // Percent-encode using FRAGMENT_PERCENT_ENCODE + size_t idx = ada::unicode::percent_encode_index( + new_value, character_sets::FRAGMENT_PERCENT_ENCODE); + if (idx == new_value.size()) { + // No encoding needed + return new_value; + } + // Percent-encode from the first character that needs encoding + return ada::unicode::percent_encode( + new_value, character_sets::FRAGMENT_PERCENT_ENCODE, idx); +} + +tl::expected, errors> tokenize(std::string_view input, + token_policy policy) { + ada_log("tokenize input: ", input); + // Let tokenizer be a new tokenizer. + // Set tokenizer's input to input. + // Set tokenizer's policy to policy. + auto tokenizer = Tokenizer(input, policy); + // While tokenizer's index is less than tokenizer's input's code point length: + while (tokenizer.index < tokenizer.input.size()) { + // Run seek and get the next code point given tokenizer and tokenizer's + // index. + tokenizer.seek_and_get_next_code_point(tokenizer.index); + + // Malformed UTF-8 must not stall tokenization: report an invalid-char + // token (lenient) or fail fast (strict), while always making progress. + if (tokenizer.had_invalid_code_point()) { + if (auto error = tokenizer.process_tokenizing_error(tokenizer.next_index, + tokenizer.index)) { + return tl::unexpected(*error); + } + continue; + } + + // If tokenizer's code point is U+002A (*): + if (tokenizer.code_point == '*') { + // Run add a token with default position and length given tokenizer and + // "asterisk". + tokenizer.add_token_with_defaults(token_type::ASTERISK); + ada_log("add ASTERISK token"); + // Continue. + continue; + } + + // If tokenizer's code point is U+002B (+) or U+003F (?): + if (tokenizer.code_point == '+' || tokenizer.code_point == '?') { + // Run add a token with default position and length given tokenizer and + // "other-modifier". + tokenizer.add_token_with_defaults(token_type::OTHER_MODIFIER); + // Continue. + continue; + } + + // If tokenizer's code point is U+005C (\): + if (tokenizer.code_point == '\\') { + // If tokenizer's index is equal to tokenizer's input's code point length + // - 1: + if (tokenizer.index == tokenizer.input.size() - 1) { + // Run process a tokenizing error given tokenizer, tokenizer's next + // index, and tokenizer's index. + if (auto error = tokenizer.process_tokenizing_error( + tokenizer.next_index, tokenizer.index)) { + ada_log("process_tokenizing_error failed"); + return tl::unexpected(*error); + } + continue; + } + + // Let escaped index be tokenizer's next index. + auto escaped_index = tokenizer.next_index; + // Run get the next code point given tokenizer. + tokenizer.get_next_code_point(); + if (tokenizer.had_invalid_code_point()) { + if (auto error = tokenizer.process_tokenizing_error( + tokenizer.next_index, escaped_index)) { + return tl::unexpected(*error); + } + continue; + } + // Run add a token with default length given tokenizer, "escaped-char", + // tokenizer's next index, and escaped index. + tokenizer.add_token_with_default_length( + token_type::ESCAPED_CHAR, tokenizer.next_index, escaped_index); + ada_log("add ESCAPED_CHAR token on next_index ", tokenizer.next_index, + " with escaped index ", escaped_index); + // Continue. + continue; + } + + // If tokenizer's code point is U+007B ({): + if (tokenizer.code_point == '{') { + // Run add a token with default position and length given tokenizer and + // "open". + tokenizer.add_token_with_defaults(token_type::OPEN); + ada_log("add OPEN token"); + continue; + } + + // If tokenizer's code point is U+007D (}): + if (tokenizer.code_point == '}') { + // Run add a token with default position and length given tokenizer and + // "close". + tokenizer.add_token_with_defaults(token_type::CLOSE); + ada_log("add CLOSE token"); + continue; + } + + // If tokenizer's code point is U+003A (:): + if (tokenizer.code_point == ':') { + // Let name position be tokenizer's next index. + auto name_position = tokenizer.next_index; + // Let name start be name position. + auto name_start = name_position; + bool invalid_name = false; + // While name position is less than tokenizer's input's code point length: + while (name_position < tokenizer.input.size()) { + // Run seek and get the next code point given tokenizer and name + // position. + tokenizer.seek_and_get_next_code_point(name_position); + if (tokenizer.had_invalid_code_point()) { + if (auto error = tokenizer.process_tokenizing_error( + tokenizer.next_index, name_position)) { + return tl::unexpected(*error); + } + invalid_name = true; + break; + } + // Let first code point be true if name position equals name start and + // false otherwise. + bool first_code_point = name_position == name_start; + // Let valid code point be the result of running is a valid name code + // point given tokenizer's code point and first code point. + auto valid_code_point = + idna::valid_name_code_point(tokenizer.code_point, first_code_point); + ada_log("tokenizer.code_point=", uint32_t(tokenizer.code_point), + " first_code_point=", first_code_point, + " valid_code_point=", valid_code_point); + // If valid code point is false break. + if (!valid_code_point) break; + // Set name position to tokenizer's next index. + name_position = tokenizer.next_index; + } + + if (invalid_name) { + continue; + } + + // If name position is less than or equal to name start: + if (name_position <= name_start) { + // Run process a tokenizing error given tokenizer, name start, and + // tokenizer's index. + if (auto error = tokenizer.process_tokenizing_error(name_start, + tokenizer.index)) { + ada_log("process_tokenizing_error failed"); + return tl::unexpected(*error); + } + // Continue + continue; + } + + // Run add a token with default length given tokenizer, "name", name + // position, and name start. + tokenizer.add_token_with_default_length(token_type::NAME, name_position, + name_start); + continue; + } + + // If tokenizer's code point is U+0028 ((): + if (tokenizer.code_point == '(') { + // Let depth be 1. + size_t depth = 1; + // Let regexp position be tokenizer's next index. + auto regexp_position = tokenizer.next_index; + // Let regexp start be regexp position. + auto regexp_start = regexp_position; + // Let error be false. + bool error = false; + + // While regexp position is less than tokenizer's input's code point + // length: + while (regexp_position < tokenizer.input.size()) { + // Run seek and get the next code point given tokenizer and regexp + // position. + tokenizer.seek_and_get_next_code_point(regexp_position); + if (tokenizer.had_invalid_code_point()) { + if (auto process_error = tokenizer.process_tokenizing_error( + tokenizer.next_index, regexp_position)) { + return tl::unexpected(*process_error); + } + error = true; + break; + } + + // TODO: Optimization opportunity: The next 2 if statements can be + // merged. If the result of running is ASCII given tokenizer's code + // point is false: + if (!unicode::is_ascii(tokenizer.code_point)) { + // Run process a tokenizing error given tokenizer, regexp start, and + // tokenizer's index. + if (auto process_error = tokenizer.process_tokenizing_error( + regexp_start, tokenizer.index)) { + return tl::unexpected(*process_error); + } + // Set error to true. + error = true; + break; + } + + // If regexp position equals regexp start and tokenizer's code point is + // U+003F (?): + if (regexp_position == regexp_start && tokenizer.code_point == '?') { + // Run process a tokenizing error given tokenizer, regexp start, and + // tokenizer's index. + if (auto process_error = tokenizer.process_tokenizing_error( + regexp_start, tokenizer.index)) { + return tl::unexpected(*process_error); + } + // Set error to true; + error = true; + break; + } + + // If tokenizer's code point is U+005C (\): + if (tokenizer.code_point == '\\') { + // If regexp position equals tokenizer's input's code point length - 1 + if (regexp_position == tokenizer.input.size() - 1) { + // Run process a tokenizing error given tokenizer, regexp start, and + // tokenizer's index. + if (auto process_error = tokenizer.process_tokenizing_error( + regexp_start, tokenizer.index)) { + return tl::unexpected(*process_error); + } + // Set error to true. + error = true; + break; + } + // Run get the next code point given tokenizer. + auto escaped_index = tokenizer.next_index; + tokenizer.get_next_code_point(); + if (tokenizer.had_invalid_code_point()) { + if (auto process_error = tokenizer.process_tokenizing_error( + tokenizer.next_index, escaped_index)) { + return tl::unexpected(*process_error); + } + error = true; + break; + } + // If the result of running is ASCII given tokenizer's code point is + // false: + if (!unicode::is_ascii(tokenizer.code_point)) { + // Run process a tokenizing error given tokenizer, regexp start, and + // tokenizer's index. + if (auto process_error = tokenizer.process_tokenizing_error( + regexp_start, tokenizer.index); + process_error.has_value()) { + return tl::unexpected(*process_error); + } + // Set error to true. + error = true; + break; + } + // Set regexp position to tokenizer's next index. + regexp_position = tokenizer.next_index; + continue; + } + + // If tokenizer's code point is U+0029 ()): + if (tokenizer.code_point == ')') { + // Decrement depth by 1. + depth--; + // If depth is 0: + if (depth == 0) { + // Set regexp position to tokenizer's next index. + regexp_position = tokenizer.next_index; + // Break. + break; + } + } else if (tokenizer.code_point == '(') { + // Otherwise if tokenizer's code point is U+0028 ((): + // Increment depth by 1. + depth++; + // If regexp position equals tokenizer's input's code point length - + // 1: + if (regexp_position == tokenizer.input.size() - 1) { + // Run process a tokenizing error given tokenizer, regexp start, and + // tokenizer's index. + if (auto process_error = tokenizer.process_tokenizing_error( + regexp_start, tokenizer.index)) { + return tl::unexpected(*process_error); + } + // Set error to true. + error = true; + break; + } + // Let temporary position be tokenizer's next index. + auto temporary_position = tokenizer.next_index; + // Run get the next code point given tokenizer. + tokenizer.get_next_code_point(); + if (tokenizer.had_invalid_code_point()) { + if (auto process_error = tokenizer.process_tokenizing_error( + tokenizer.next_index, temporary_position)) { + return tl::unexpected(*process_error); + } + error = true; + break; + } + // If tokenizer's code point is not U+003F (?): + if (tokenizer.code_point != '?') { + // Run process a tokenizing error given tokenizer, regexp start, and + // tokenizer's index. + if (auto process_error = tokenizer.process_tokenizing_error( + regexp_start, tokenizer.index)) { + return tl::unexpected(*process_error); + } + // Set error to true. + error = true; + break; + } + // Set tokenizer's next index to temporary position. + tokenizer.next_index = temporary_position; + } + // Set regexp position to tokenizer's next index. + regexp_position = tokenizer.next_index; + } + + // If error is true continue. + if (error) continue; + // If depth is not zero: + if (depth != 0) { + // Run process a tokenizing error given tokenizer, regexp start, and + // tokenizer's index. + if (auto process_error = tokenizer.process_tokenizing_error( + regexp_start, tokenizer.index)) { + return tl::unexpected(*process_error); + } + continue; + } + // Let regexp length be regexp position - regexp start - 1. + auto regexp_length = regexp_position - regexp_start - 1; + // If regexp length is zero: + if (regexp_length == 0) { + // Run process a tokenizing error given tokenizer, regexp start, and + // tokenizer's index. + if (auto process_error = tokenizer.process_tokenizing_error( + regexp_start, tokenizer.index)) { + ada_log("process_tokenizing_error failed"); + return tl::unexpected(*process_error); + } + continue; + } + // Run add a token given tokenizer, "regexp", regexp position, regexp + // start, and regexp length. + tokenizer.add_token(token_type::REGEXP, regexp_position, regexp_start, + regexp_length); + continue; + } + // Run add a token with default position and length given tokenizer and + // "char". + tokenizer.add_token_with_defaults(token_type::CHAR); + } + // Run add a token with default length given tokenizer, "end", tokenizer's + // index, and tokenizer's index. + tokenizer.add_token_with_default_length(token_type::END, tokenizer.index, + tokenizer.index); + + ada_log("tokenizer.token_list size is: ", tokenizer.token_list.size()); + // Return tokenizer's token list. + return tokenizer.token_list; +} + +namespace { +constexpr std::array escape_pattern_table = []() consteval { + std::array out{}; + for (auto& c : {'+', '*', '?', ':', '{', '}', '(', ')', '\\'}) { + out[c] = 1; + } + return out; +}(); + +constexpr bool should_escape_pattern_char(char c) { + return escape_pattern_table[static_cast(c)]; +} +} // namespace + +std::string escape_pattern_string(std::string_view input) { + ada_log("escape_pattern_string called with input=", input); + if (input.empty()) [[unlikely]] { + return ""; + } + // Assert: input is an ASCII string. + ADA_ASSERT_TRUE(ada::idna::is_ascii(input)); + // Let result be the empty string. + std::string result{}; + // Reserve extra space for potential escapes + result.reserve(input.size() * 2); + + // While index is less than input's length: + for (const char c : input) { + if (should_escape_pattern_char(c)) { + // Append U+005C (\) to the end of result. + result.push_back('\\'); + } + // Append c to the end of result. + result.push_back(c); + } + // Return result. + return result; +} + +namespace { +constexpr std::array escape_regexp_table = []() consteval { + std::array out{}; + for (auto& c : {'.', '+', '*', '?', '^', '$', '{', '}', '(', ')', '[', ']', + '|', '/', '\\'}) { + out[c] = 1; + } + return out; +}(); + +constexpr bool should_escape_regexp_char(char c) { + return escape_regexp_table[(uint8_t)c]; +} +} // namespace + +std::string escape_regexp_string(std::string_view input) { + // Assert: input is an ASCII string. + ADA_ASSERT_TRUE(idna::is_ascii(input)); + // Let result be the empty string. + std::string result{}; + // Reserve extra space for potential escapes (worst case: all chars escaped) + result.reserve(input.size() * 2); + for (const char c : input) { + if (should_escape_regexp_char(c)) { + // Avoid temporary string allocation - directly append characters + result.push_back('\\'); + result.push_back(c); + } else { + result.push_back(c); + } + } + return result; +} + +std::string process_base_url_string(std::string_view input, + url_pattern_init::process_type type) { + // If type is not "pattern" return input. + if (type != url_pattern_init::process_type::pattern) { + return std::string(input); + } + // Return the result of escaping a pattern string given input. + return escape_pattern_string(input); +} + +constexpr bool is_absolute_pathname( + std::string_view input, url_pattern_init::process_type type) noexcept { + // If input is the empty string, then return false. + if (input.empty()) [[unlikely]] { + return false; + } + // If input[0] is U+002F (/), then return true. + if (input.starts_with("/")) return true; + // If type is "url", then return false. + if (type == url_pattern_init::process_type::url) return false; + // If input's code point length is less than 2, then return false. + if (input.size() < 2) return false; + // If input[0] is U+005C (\) and input[1] is U+002F (/), then return true. + // If input[0] is U+007B ({) and input[1] is U+002F (/), then return true. + // Return false. + return input[1] == '/' && (input[0] == '\\' || input[0] == '{'); +} + +std::string generate_pattern_string( + std::vector& part_list, + url_pattern_compile_component_options& options) { + // Let result be the empty string. + std::string result{}; + // Let index list be the result of getting the indices for part list. + // For each index of index list: + for (size_t index = 0; index < part_list.size(); index++) { + // Let part be part list[index]. + // Use reference to avoid copy + const auto& part = part_list[index]; + // Let previous part be part list[index - 1] if index is greater than 0, + // otherwise let it be null. + // Use pointer to avoid copy + const url_pattern_part* previous_part = + index == 0 ? nullptr : &part_list[index - 1]; + // Let next part be part list[index + 1] if index is less than index list's + // size - 1, otherwise let it be null. + const url_pattern_part* next_part = + index < part_list.size() - 1 ? &part_list[index + 1] : nullptr; + // If part's type is "fixed-text" then: + if (part.type == url_pattern_part_type::FIXED_TEXT) { + // If part's modifier is "none" then: + if (part.modifier == url_pattern_part_modifier::none) { + // Append the result of running escape a pattern string given part's + // value to the end of result. + result.append(escape_pattern_string(part.value)); + continue; + } + // Append "{" to the end of result. + result += "{"; + // Append the result of running escape a pattern string given part's value + // to the end of result. + result.append(escape_pattern_string(part.value)); + // Append "}" to the end of result. + result += "}"; + // Append the result of running convert a modifier to a string given + // part's modifier to the end of result. + result.append(convert_modifier_to_string(part.modifier)); + continue; + } + // Let custom name be true if part's name[0] is not an ASCII digit; + // otherwise false. + bool custom_name = !unicode::is_ascii_digit(part.name[0]); + // Let needs grouping be true if at least one of the following are true, + // otherwise let it be false: + // - part's suffix is not the empty string. + // - part's prefix is not the empty string and is not options's prefix code + // point. + bool needs_grouping = + !part.suffix.empty() || + (!part.prefix.empty() && (options.get_prefix().empty() || + part.prefix[0] != options.get_prefix()[0])); + + // If all of the following are true: + // - needs grouping is false; and + // - custom name is true; and + // - part's type is "segment-wildcard"; and + // - part's modifier is "none"; and + // - next part is not null; and + // - next part's prefix is the empty string; and + // - next part's suffix is the empty string + if (!needs_grouping && custom_name && + part.type == url_pattern_part_type::SEGMENT_WILDCARD && + part.modifier == url_pattern_part_modifier::none && next_part && + next_part->prefix.empty() && next_part->suffix.empty()) { + // If next part's type is "fixed-text": + if (next_part->type == url_pattern_part_type::FIXED_TEXT) { + // Set needs grouping to true if the result of running is a valid name + // code point given next part's value's first code point and the boolean + // false is true. + if (idna::valid_name_code_point(next_part->value[0], false)) { + needs_grouping = true; + } + } else { + // Set needs grouping to true if next part's name[0] is an ASCII digit. + needs_grouping = !next_part->name.empty() && + unicode::is_ascii_digit(next_part->name[0]); + } + } + + // If all of the following are true: + // - needs grouping is false; and + // - part's prefix is the empty string; and + // - previous part is not null; and + // - previous part's type is "fixed-text"; and + // - previous part's value's last code point is options's prefix code point. + // then set needs grouping to true. + if (!needs_grouping && part.prefix.empty() && previous_part && + previous_part->type == url_pattern_part_type::FIXED_TEXT && + !previous_part->value.empty() && !options.get_prefix().empty() && + previous_part->value.back() == options.get_prefix()[0]) { + needs_grouping = true; + } + + // Assert: part's name is not the empty string or null. + ADA_ASSERT_TRUE(!part.name.empty()); + + // If needs grouping is true, then append "{" to the end of result. + if (needs_grouping) { + result.append("{"); + } + + // Append the result of running escape a pattern string given part's prefix + // to the end of result. + result.append(escape_pattern_string(part.prefix)); + + // If custom name is true: + if (custom_name) { + // Append ":" to the end of result. + result.append(":"); + // Append part's name to the end of result. + result.append(part.name); + } + + // If part's type is "regexp" then: + if (part.type == url_pattern_part_type::REGEXP) { + // Append "(" to the end of result. + result.append("("); + // Append part's value to the end of result. + result.append(part.value); + // Append ")" to the end of result. + result.append(")"); + } else if (part.type == url_pattern_part_type::SEGMENT_WILDCARD && + !custom_name) { + // Otherwise if part's type is "segment-wildcard" and custom name is + // false: Append "(" to the end of result. + result.append("("); + // Append the result of running generate a segment wildcard regexp given + // options to the end of result. + result.append(generate_segment_wildcard_regexp(options)); + // Append ")" to the end of result. + result.append(")"); + } else if (part.type == url_pattern_part_type::FULL_WILDCARD) { + // Otherwise if part's type is "full-wildcard": + // If custom name is false and one of the following is true: + // - previous part is null; or + // - previous part's type is "fixed-text"; or + // - previous part's modifier is not "none"; or + // - needs grouping is true; or + // - part's prefix is not the empty string + // - then append "*" to the end of result. + if (!custom_name && + (!previous_part || + previous_part->type == url_pattern_part_type::FIXED_TEXT || + previous_part->modifier != url_pattern_part_modifier::none || + needs_grouping || !part.prefix.empty())) { + result.append("*"); + } else { + // Append "(" to the end of result. + // Append full wildcard regexp value to the end of result. + // Append ")" to the end of result. + result.append("(.*)"); + } + } + + // If all of the following are true: + // - part's type is "segment-wildcard"; and + // - custom name is true; and + // - part's suffix is not the empty string; and + // - The result of running is a valid name code point given part's suffix's + // first code point and the boolean false is true then append U+005C (\) to + // the end of result. + if (part.type == url_pattern_part_type::SEGMENT_WILDCARD && custom_name && + !part.suffix.empty() && + idna::valid_name_code_point(part.suffix[0], false)) { + result.append("\\"); + } + + // Append the result of running escape a pattern string given part's suffix + // to the end of result. + result.append(escape_pattern_string(part.suffix)); + // If needs grouping is true, then append "}" to the end of result. + if (needs_grouping) result.append("}"); + // Append the result of running convert a modifier to a string given part's + // modifier to the end of result. + result.append(convert_modifier_to_string(part.modifier)); + } + // Return result. + return result; +} +} // namespace ada::url_pattern_helpers + +#endif // ADA_INCLUDE_URL_PATTERN +/* end file src/url_pattern_helpers.cpp */ +/* begin file src/url_pattern_regex.cpp */ +#if ADA_INCLUDE_URL_PATTERN + + +namespace ada::url_pattern_regex { + +#ifdef ADA_USE_UNSAFE_STD_REGEX_PROVIDER +std::optional std_regex_provider::create_instance( + std::string_view pattern, bool ignore_case) { + // Let flags be an empty string. + // If options's ignore case is true then set flags to "vi". + // Otherwise set flags to "v" + auto flags = ignore_case + ? std::regex::icase | std::regex_constants::ECMAScript + : std::regex_constants::ECMAScript; + try { + return std::regex(pattern.data(), pattern.size(), flags); + } catch (const std::regex_error& e) { + (void)e; + ada_log("std_regex_provider::create_instance failed:", e.what()); + return std::nullopt; + } +} + +std::optional>> +std_regex_provider::regex_search(std::string_view input, + const std::regex& pattern) { + // Use iterator-based regex_search to avoid string allocation + std::match_results match_result; + try { + if (!std::regex_search(input.begin(), input.end(), match_result, pattern, + std::regex_constants::match_any)) { + return std::nullopt; + } + } catch (const std::regex_error& e) { + (void)e; + ada_log("std_regex_provider::regex_search failed:", e.what()); + return std::nullopt; + } + std::vector> matches; + // An empty input can still match with capture groups (e.g. "(x*)" or an + // optional ":a?" against ""), so the group values must be extracted here + // just like for a non-empty input. A successful regex_search always leaves + // the full match at index 0, so match_result is never empty at this point. + if (match_result.empty()) { + return matches; + } + matches.reserve(match_result.size()); + for (size_t i = 1; i < match_result.size(); ++i) { + if (auto entry = match_result[i]; entry.matched) { + matches.emplace_back(entry.str()); + } else { + // A capture group that did not participate in the match is undefined, + // not absent. Emitting nullopt keeps the result aligned by position with + // the component's group name list; dropping it shifts every later group + // onto the wrong name. + matches.emplace_back(std::nullopt); + } + } + return matches; +} + +bool std_regex_provider::regex_match(std::string_view input, + const std::regex& pattern) { + try { + return std::regex_match(input.begin(), input.end(), pattern); + } catch (const std::regex_error& e) { + (void)e; + ada_log("std_regex_provider::regex_match failed:", e.what()); + return false; + } +} + +#endif // ADA_USE_UNSAFE_STD_REGEX_PROVIDER + +} // namespace ada::url_pattern_regex + +#endif // ADA_INCLUDE_URL_PATTERN +/* end file src/url_pattern_regex.cpp */ +#endif // ADA_INCLUDE_URL_PATTERN + +/* begin file src/ada_c.cpp */ +// NOLINTBEGIN(bugprone-exception-escape, +// bugprone-suspicious-stringview-data-usage) + +ada::result& get_instance(void* result) noexcept { + return *(ada::result*)result; +} + +extern "C" { +typedef void* ada_url; +typedef void* ada_url_search_params; +typedef void* ada_strings; +typedef void* ada_url_search_params_keys_iter; +typedef void* ada_url_search_params_values_iter; +typedef void* ada_url_search_params_entries_iter; + +struct ada_string { + const char* data; + size_t length; +}; + +struct ada_owned_string { + const char* data; + size_t length; +}; + +struct ada_string_pair { + ada_string key; + ada_string value; +}; + +ada_string ada_string_create(const char* data, size_t length) { + ada_string out{}; + out.data = data; + out.length = length; + return out; +} + +struct ada_url_components { + /* + * By using 32-bit integers, we implicitly assume that the URL string + * cannot exceed 4 GB. + * + * https://user:pass@example.com:1234/foo/bar?baz#quux + * | | | | ^^^^| | | + * | | | | | | | `----- hash_start + * | | | | | | `--------- search_start + * | | | | | `----------------- pathname_start + * | | | | `--------------------- port + * | | | `----------------------- host_end + * | | `---------------------------------- host_start + * | `--------------------------------------- username_end + * `--------------------------------------------- protocol_end + */ + uint32_t protocol_end; + /** + * Username end is not `omitted` by default (-1) to make username and password + * getters less costly to implement. + */ + uint32_t username_end; + uint32_t host_start; + uint32_t host_end; + uint32_t port; + uint32_t pathname_start; + uint32_t search_start; + uint32_t hash_start; +}; + +ada_url ada_parse(const char* input, size_t length) noexcept { + return new ada::result( + ada::parse(std::string_view(input, length))); +} + +ada_url ada_parse_with_base(const char* input, size_t input_length, + const char* base, size_t base_length) noexcept { + auto base_out = + ada::parse(std::string_view(base, base_length)); + + if (!base_out) { + return new ada::result(base_out); + } + + return new ada::result(ada::parse( + std::string_view(input, input_length), &base_out.value())); +} + +bool ada_can_parse(const char* input, size_t length) noexcept { + return ada::can_parse(std::string_view(input, length)); +} + +bool ada_can_parse_with_base(const char* input, size_t input_length, + const char* base, size_t base_length) noexcept { + std::string_view base_view(base, base_length); + return ada::can_parse(std::string_view(input, input_length), &base_view); +} + +void ada_free(ada_url result) noexcept { + auto* r = (ada::result*)result; + delete r; +} + +ada_url ada_copy(ada_url input) noexcept { + ada::result& r = get_instance(input); + return new ada::result(r); +} + +bool ada_is_valid(ada_url result) noexcept { + ada::result& r = get_instance(result); + return r.has_value(); +} + +// caller must free the result with ada_free_owned_string +ada_owned_string ada_get_origin(ada_url result) noexcept { + ada::result& r = get_instance(result); + ada_owned_string owned{}; + if (!r) { + owned.data = nullptr; + owned.length = 0; + return owned; + } + std::string out = r->get_origin(); + owned.length = out.size(); + owned.data = new char[owned.length]; + memcpy((void*)owned.data, out.data(), owned.length); + return owned; +} + +void ada_free_owned_string(ada_owned_string owned) noexcept { + delete[] owned.data; +} + +ada_string ada_get_href(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view out = r->get_href(); + return ada_string_create(out.data(), out.length()); +} + +ada_string ada_get_username(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view out = r->get_username(); + return ada_string_create(out.data(), out.length()); +} + +ada_string ada_get_password(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view out = r->get_password(); + return ada_string_create(out.data(), out.length()); +} + +ada_string ada_get_port(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view out = r->get_port(); + return ada_string_create(out.data(), out.length()); +} + +ada_string ada_get_hash(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view out = r->get_hash(); + return ada_string_create(out.data(), out.length()); +} + +ada_string ada_get_host(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view out = r->get_host(); + return ada_string_create(out.data(), out.length()); +} + +ada_string ada_get_hostname(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view out = r->get_hostname(); + return ada_string_create(out.data(), out.length()); +} + +ada_string ada_get_pathname(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view out = r->get_pathname(); + return ada_string_create(out.data(), out.length()); +} + +ada_string ada_get_search(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view out = r->get_search(); + return ada_string_create(out.data(), out.length()); +} + +ada_string ada_get_protocol(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view out = r->get_protocol(); + return ada_string_create(out.data(), out.length()); +} + +uint8_t ada_get_host_type(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return 0; + } + return r->host_type; +} + +uint8_t ada_get_scheme_type(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return 0; + } + return r->type; +} + +bool ada_set_href(ada_url result, const char* input, size_t length) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->set_href(std::string_view(input, length)); +} + +bool ada_set_host(ada_url result, const char* input, size_t length) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->set_host(std::string_view(input, length)); +} + +bool ada_set_hostname(ada_url result, const char* input, + size_t length) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->set_hostname(std::string_view(input, length)); +} + +bool ada_set_protocol(ada_url result, const char* input, + size_t length) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->set_protocol(std::string_view(input, length)); +} + +bool ada_set_username(ada_url result, const char* input, + size_t length) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->set_username(std::string_view(input, length)); +} + +bool ada_set_password(ada_url result, const char* input, + size_t length) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->set_password(std::string_view(input, length)); +} + +bool ada_set_port(ada_url result, const char* input, size_t length) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->set_port(std::string_view(input, length)); +} + +bool ada_set_pathname(ada_url result, const char* input, + size_t length) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->set_pathname(std::string_view(input, length)); +} + +/** + * Update the search/query of the URL. + * + * If a URL has `?` as the search value, passing empty string to this function + * does not remove the attribute. If you need to remove it, please use + * `ada_clear_search` method. + */ +void ada_set_search(ada_url result, const char* input, size_t length) noexcept { + ada::result& r = get_instance(result); + if (r) { + r->set_search(std::string_view(input, length)); + } +} + +/** + * Update the hash/fragment of the URL. + * + * If a URL has `#` as the hash value, passing empty string to this function + * does not remove the attribute. If you need to remove it, please use + * `ada_clear_hash` method. + */ +void ada_set_hash(ada_url result, const char* input, size_t length) noexcept { + ada::result& r = get_instance(result); + if (r) { + r->set_hash(std::string_view(input, length)); + } +} + +void ada_clear_port(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (r) { + r->clear_port(); + } +} + +/** + * Removes the hash of the URL. + * + * Despite `ada_set_hash` method, this function allows the complete + * removal of the hash attribute, even if it has a value of `#`. + */ +void ada_clear_hash(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (r) { + r->clear_hash(); + } +} + +/** + * Removes the search of the URL. + * + * Despite `ada_set_search` method, this function allows the complete + * removal of the search attribute, even if it has a value of `?`. + */ +void ada_clear_search(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (r) { + r->clear_search(); + } +} + +bool ada_has_credentials(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->has_credentials(); +} + +bool ada_has_empty_hostname(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->has_empty_hostname(); +} + +bool ada_has_hostname(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->has_hostname(); +} + +bool ada_has_non_empty_username(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->has_non_empty_username(); +} + +bool ada_has_non_empty_password(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->has_non_empty_password(); +} + +bool ada_has_port(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->has_port(); +} + +bool ada_has_password(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->has_password(); +} + +bool ada_has_hash(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->has_hash(); +} + +bool ada_has_search(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->has_search(); +} + +// returns a pointer to the internal url_aggregator::url_components +const ada_url_components* ada_get_components(ada_url result) noexcept { + static_assert(sizeof(ada_url_components) == sizeof(ada::url_components)); + ada::result& r = get_instance(result); + if (!r) { + return nullptr; + } + return reinterpret_cast(&r->get_components()); +} + +ada_owned_string ada_idna_to_unicode(const char* input, size_t length) { + std::string out = ada::idna::to_unicode(std::string_view(input, length)); + ada_owned_string owned{}; + owned.length = out.length(); + owned.data = new char[owned.length]; + memcpy((void*)owned.data, out.data(), owned.length); + return owned; +} + +ada_owned_string ada_idna_to_ascii(const char* input, size_t length) { + std::string out = ada::idna::to_ascii(std::string_view(input, length)); + ada_owned_string owned{}; + owned.length = out.size(); + owned.data = new char[owned.length]; + memcpy((void*)owned.data, out.data(), owned.length); + return owned; +} + +ada_url_search_params ada_parse_search_params(const char* input, + size_t length) { + return new ada::result( + ada::url_search_params(std::string_view(input, length))); +} + +void ada_free_search_params(ada_url_search_params result) { + auto* r = (ada::result*)result; + delete r; +} + +ada_owned_string ada_search_params_to_string(ada_url_search_params result) { + ada::result& r = + *(ada::result*)result; + if (!r) return ada_owned_string{nullptr, 0}; + std::string out = r->to_string(); + ada_owned_string owned{}; + owned.length = out.size(); + owned.data = new char[owned.length]; + memcpy((void*)owned.data, out.data(), owned.length); + return owned; +} + +size_t ada_search_params_size(ada_url_search_params result) { + ada::result& r = + *(ada::result*)result; + if (!r) { + return 0; + } + return r->size(); +} + +void ada_search_params_sort(ada_url_search_params result) { + ada::result& r = + *(ada::result*)result; + if (r) { + r->sort(); + } +} + +void ada_search_params_reset(ada_url_search_params result, const char* input, + size_t length) { + ada::result& r = + *(ada::result*)result; + if (r) { + r->reset(std::string_view(input, length)); + } +} + +void ada_search_params_append(ada_url_search_params result, const char* key, + size_t key_length, const char* value, + size_t value_length) { + ada::result& r = + *(ada::result*)result; + if (r) { + r->append(std::string_view(key, key_length), + std::string_view(value, value_length)); + } +} + +void ada_search_params_set(ada_url_search_params result, const char* key, + size_t key_length, const char* value, + size_t value_length) { + ada::result& r = + *(ada::result*)result; + if (r) { + r->set(std::string_view(key, key_length), + std::string_view(value, value_length)); + } +} + +void ada_search_params_remove(ada_url_search_params result, const char* key, + size_t key_length) { + ada::result& r = + *(ada::result*)result; + if (r) { + r->remove(std::string_view(key, key_length)); + } +} + +void ada_search_params_remove_value(ada_url_search_params result, + const char* key, size_t key_length, + const char* value, size_t value_length) { + ada::result& r = + *(ada::result*)result; + if (r) { + r->remove(std::string_view(key, key_length), + std::string_view(value, value_length)); + } +} + +bool ada_search_params_has(ada_url_search_params result, const char* key, + size_t key_length) { + ada::result& r = + *(ada::result*)result; + if (!r) { + return false; + } + return r->has(std::string_view(key, key_length)); +} + +bool ada_search_params_has_value(ada_url_search_params result, const char* key, + size_t key_length, const char* value, + size_t value_length) { + ada::result& r = + *(ada::result*)result; + if (!r) { + return false; + } + return r->has(std::string_view(key, key_length), + std::string_view(value, value_length)); +} + +ada_string ada_search_params_get(ada_url_search_params result, const char* key, + size_t key_length) { + ada::result& r = + *(ada::result*)result; + if (!r) { + return ada_string_create(nullptr, 0); + } + auto found = r->get(std::string_view(key, key_length)); + if (!found.has_value()) { + return ada_string_create(nullptr, 0); + } + return ada_string_create(found->data(), found->length()); +} + +ada_strings ada_search_params_get_all(ada_url_search_params result, + const char* key, size_t key_length) { + ada::result& r = + *(ada::result*)result; + if (!r) { + return new ada::result>( + std::vector()); + } + return new ada::result>( + r->get_all(std::string_view(key, key_length))); +} + +ada_url_search_params_keys_iter ada_search_params_get_keys( + ada_url_search_params result) { + ada::result& r = + *(ada::result*)result; + if (!r) { + return new ada::result( + ada::url_search_params_keys_iter()); + } + return new ada::result(r->get_keys()); +} + +ada_url_search_params_values_iter ada_search_params_get_values( + ada_url_search_params result) { + ada::result& r = + *(ada::result*)result; + if (!r) { + return new ada::result( + ada::url_search_params_values_iter()); + } + return new ada::result(r->get_values()); +} + +ada_url_search_params_entries_iter ada_search_params_get_entries( + ada_url_search_params result) { + ada::result& r = + *(ada::result*)result; + if (!r) { + return new ada::result( + ada::url_search_params_entries_iter()); + } + return new ada::result(r->get_entries()); +} + +void ada_free_strings(ada_strings result) { + auto* r = (ada::result>*)result; + delete r; +} + +size_t ada_strings_size(ada_strings result) { + auto* r = (ada::result>*)result; + if (!r) { + return 0; + } + return (*r)->size(); +} + +ada_string ada_strings_get(ada_strings result, size_t index) { + auto* r = (ada::result>*)result; + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view view = (*r)->at(index); + return ada_string_create(view.data(), view.length()); +} + +void ada_free_search_params_keys_iter(ada_url_search_params_keys_iter result) { + auto* r = (ada::result*)result; + delete r; +} + +ada_string ada_search_params_keys_iter_next( + ada_url_search_params_keys_iter result) { + auto* r = (ada::result*)result; + if (!r) { + return ada_string_create(nullptr, 0); + } + auto next = (*r)->next(); + if (!next.has_value()) { + return ada_string_create(nullptr, 0); + } + return ada_string_create(next->data(), next->length()); +} + +bool ada_search_params_keys_iter_has_next( + ada_url_search_params_keys_iter result) { + auto* r = (ada::result*)result; + if (!r) { + return false; + } + return (*r)->has_next(); +} + +void ada_free_search_params_values_iter( + ada_url_search_params_values_iter result) { + auto* r = (ada::result*)result; + delete r; +} + +ada_string ada_search_params_values_iter_next( + ada_url_search_params_values_iter result) { + auto* r = (ada::result*)result; + if (!r) { + return ada_string_create(nullptr, 0); + } + auto next = (*r)->next(); + if (!next.has_value()) { + return ada_string_create(nullptr, 0); + } + return ada_string_create(next->data(), next->length()); +} + +bool ada_search_params_values_iter_has_next( + ada_url_search_params_values_iter result) { + auto* r = (ada::result*)result; + if (!r) { + return false; + } + return (*r)->has_next(); +} + +void ada_free_search_params_entries_iter( + ada_url_search_params_entries_iter result) { + auto* r = (ada::result*)result; + delete r; +} + +ada_string_pair ada_search_params_entries_iter_next( + ada_url_search_params_entries_iter result) { + auto* r = (ada::result*)result; + if (!r) return {ada_string_create(nullptr, 0), ada_string_create(nullptr, 0)}; + auto next = (*r)->next(); + if (!next.has_value()) { + return {ada_string_create(nullptr, 0), ada_string_create(nullptr, 0)}; + } + return ada_string_pair{ + ada_string_create(next->first.data(), next->first.length()), + ada_string_create(next->second.data(), next->second.length())}; +} + +bool ada_search_params_entries_iter_has_next( + ada_url_search_params_entries_iter result) { + auto* r = (ada::result*)result; + if (!r) { + return false; + } + return (*r)->has_next(); +} + +void ada_set_max_input_length(uint32_t length) noexcept { + ada::set_max_input_length(length); +} + +uint32_t ada_get_max_input_length() noexcept { + return ada::get_max_input_length(); +} + +typedef struct { + int major; + int minor; + int revision; +} ada_version_components; + +const char* ada_get_version() { return ADA_VERSION; } + +ada_version_components ada_get_version_components() { + return ada_version_components{ + .major = ada::ADA_VERSION_MAJOR, + .minor = ada::ADA_VERSION_MINOR, + .revision = ada::ADA_VERSION_REVISION, + }; +} + +} // extern "C" +// NOLINTEND(bugprone-exception-escape, +// bugprone-suspicious-stringview-data-usage) +/* end file src/ada_c.cpp */ +/* end file src/ada.cpp */ diff --git a/NativeScript/ada/ada.h b/NativeScript/ada/ada.h new file mode 100644 index 00000000..dc96fe83 --- /dev/null +++ b/NativeScript/ada/ada.h @@ -0,0 +1,11654 @@ +/* auto-generated on 2026-07-27 16:10:09 -0400. Do not edit! */ +/* begin file include/ada.h */ +/** + * @file ada.h + * @brief Main header for the Ada URL parser library. + * + * This is the primary entry point for the Ada URL parser library. Including + * this single header provides access to the complete Ada API, including: + * + * - URL parsing via `ada::parse()` function + * - Two URL representations: `ada::url` and `ada::url_aggregator` + * - URL search parameters via `ada::url_search_params` + * - URL pattern matching via `ada::url_pattern` (URLPattern API) + * - IDNA (Internationalized Domain Names) support + * + * @example + * ```cpp + * + * // Parse a URL + * auto url = ada::parse("https://example.com/path?query=1"); + * if (url) { + * std::cout << url->get_hostname(); // "example.com" + * } + * ``` + * + * @see https://url.spec.whatwg.org/ - WHATWG URL Standard + * @see https://github.com/ada-url/ada - Ada URL Parser GitHub Repository + */ +#ifndef ADA_H +#define ADA_H + +/* begin file include/ada/ada_idna.h */ +/* auto-generated on 2026-07-12 20:34:08 -0400. Do not edit! */ +/* begin file include/idna.h */ +#ifndef ADA_IDNA_H +#define ADA_IDNA_H + +/* begin file include/ada/idna/unicode_transcoding.h */ +#ifndef ADA_IDNA_UNICODE_TRANSCODING_H +#define ADA_IDNA_UNICODE_TRANSCODING_H + +#include +#include + +namespace ada::idna { + +size_t utf8_to_utf32(const char* buf, size_t len, char32_t* utf32_output); + +size_t utf8_length_from_utf32(const char32_t* buf, size_t len); + +size_t utf32_length_from_utf8(const char* buf, size_t len); + +size_t utf32_to_utf8(const char32_t* buf, size_t len, char* utf8_output); + +} // namespace ada::idna + +#endif // ADA_IDNA_UNICODE_TRANSCODING_H +/* end file include/ada/idna/unicode_transcoding.h */ +/* begin file include/ada/idna/mapping.h */ +#ifndef ADA_IDNA_MAPPING_H +#define ADA_IDNA_MAPPING_H + +#include +#include + +namespace ada::idna { + +// If the input is ascii, then the mapping is just -> lower case. +void ascii_map(char* input, size_t length); +// Map the characters according to IDNA, returning the empty string on error. +std::u32string map(std::u32string_view input); +// Map into an existing buffer (cleared on entry). Returns false if any code +// point is disallowed. Reusing the buffer avoids repeated heap allocations +// when called in a loop over multiple labels. +bool map(std::u32string_view input, std::u32string& out); + +} // namespace ada::idna + +#endif +/* end file include/ada/idna/mapping.h */ +/* begin file include/ada/idna/normalization.h */ +#ifndef ADA_IDNA_NORMALIZATION_H +#define ADA_IDNA_NORMALIZATION_H + +#include +#include + +namespace ada::idna { + +// Returns true if `input` is already in Unicode Normalization Form C. +// Requires that internal tables have been loaded (call ensure via normalize +// or map first, or this returns false if tables are unavailable). +[[nodiscard]] bool is_already_nfc(std::u32string_view input) noexcept; + +// Normalize the characters according to IDNA (Unicode Normalization Form C). +// Returns false if the internal Unicode tables could not be loaded; in that +// case `input` is left unchanged. Skips work when the string is already NFC. +[[nodiscard]] bool normalize(std::u32string& input); + +} // namespace ada::idna +#endif +/* end file include/ada/idna/normalization.h */ +/* begin file include/ada/idna/punycode.h */ +#ifndef ADA_IDNA_PUNYCODE_H +#define ADA_IDNA_PUNYCODE_H + +#include +#include + +namespace ada::idna { + +bool punycode_to_utf32(std::string_view input, std::u32string& out); +bool verify_punycode(std::string_view input); +bool utf32_to_punycode(std::u32string_view input, std::string& out); + +} // namespace ada::idna + +#endif // ADA_IDNA_PUNYCODE_H +/* end file include/ada/idna/punycode.h */ +/* begin file include/ada/idna/validity.h */ +#ifndef ADA_IDNA_VALIDITY_H +#define ADA_IDNA_VALIDITY_H + +#include +#include + +namespace ada::idna { + +/** + * @see https://www.unicode.org/reports/tr46/#Validity_Criteria + */ +bool is_label_valid(std::u32string_view label); + +} // namespace ada::idna + +#endif // ADA_IDNA_VALIDITY_H +/* end file include/ada/idna/validity.h */ +/* begin file include/ada/idna/to_ascii.h */ +#ifndef ADA_IDNA_TO_ASCII_H +#define ADA_IDNA_TO_ASCII_H + +#include +#include + +/* begin file include/ada/idna/limits.h */ +#ifndef ADA_IDNA_LIMITS_H +#define ADA_IDNA_LIMITS_H + +#include + +namespace ada::idna { + +// Maximum accepted UTF-8 domain length for to_ascii / to_unicode. +// Bounds heap growth under untrusted input (DoS resistance). DNS wire limits +// are smaller; this allows long Unicode labels used in URL tests/fixtures. +inline constexpr size_t max_domain_input_bytes = 16384; + +} // namespace ada::idna + +#endif // ADA_IDNA_LIMITS_H +/* end file include/ada/idna/limits.h */ + +namespace ada::idna { + +// Converts a domain (e.g., www.google.com) possibly containing international +// characters to an ascii domain (with punycode). It will not do percent +// decoding: percent decoding should be done prior to calling this function. We +// do not remove tabs and spaces, they should have been removed prior to calling +// this function. We also do not trim control characters. We also assume that +// the input is not empty. We return "" on error. Inputs longer than +// max_domain_input_bytes are rejected. +// +// This function may accept or even produce invalid domains (WHATWG carve-outs). +std::string to_ascii(std::string_view ut8_string); + +// Same as to_ascii, but writes into `out` and returns false on error without +// relying on empty-string ambiguity. +[[nodiscard]] bool to_ascii(std::string_view ut8_string, std::string& out); + +// Returns true if the string contains a forbidden code point according to the +// WHATGL URL specification: +// https://url.spec.whatwg.org/#forbidden-domain-code-point +bool contains_forbidden_domain_code_point(std::string_view ascii_string); + +bool constexpr is_ascii(std::u32string_view view); +bool constexpr is_ascii(std::string_view view); + +} // namespace ada::idna + +#endif // ADA_IDNA_TO_ASCII_H +/* end file include/ada/idna/to_ascii.h */ +/* begin file include/ada/idna/to_unicode.h */ +#ifndef ADA_IDNA_TO_UNICODE_H +#define ADA_IDNA_TO_UNICODE_H + +#include +#include + +namespace ada::idna { + +// UTS #46 ToUnicode. Never fails per the standard: on step failure the original +// label is kept. Inputs longer than max_domain_input_bytes are returned +// unchanged as a safety measure under untrusted input. +std::string to_unicode(std::string_view input); + +// Writes into `out`. Returns false only if the input exceeds +// max_domain_input_bytes (out is left empty). Otherwise always returns true +// (ToUnicode does not fail). +[[nodiscard]] bool to_unicode(std::string_view input, std::string& out); + +} // namespace ada::idna + +#endif // ADA_IDNA_TO_UNICODE_H +/* end file include/ada/idna/to_unicode.h */ +/* begin file include/ada/idna/identifier.h */ +#ifndef ADA_IDNA_IDENTIFIER_H +#define ADA_IDNA_IDENTIFIER_H + +#include +#include + +namespace ada::idna { + +// Verify if it is valid name code point given a Unicode code point and a +// boolean first: If first is true return the result of checking if code point +// is contained in the IdentifierStart set of code points. Otherwise return the +// result of checking if code point is contained in the IdentifierPart set of +// code points. Returns false if the input is empty or the code point is not +// valid. There is minimal Unicode error handling: the input should be valid +// UTF-8. https://urlpattern.spec.whatwg.org/#is-a-valid-name-code-point +bool valid_name_code_point(char32_t code_point, bool first); + +} // namespace ada::idna + +#endif +/* end file include/ada/idna/identifier.h */ + +#endif +/* end file include/idna.h */ +/* end file include/ada/ada_idna.h */ +/* begin file include/ada/character_sets.h */ +/** + * @file character_sets.h + * @brief Declaration of the character sets used by unicode functions. + * @author Node.js + * @see https://github.com/nodejs/node/blob/main/src/node_url_tables.cc + */ +#ifndef ADA_CHARACTER_SETS_H +#define ADA_CHARACTER_SETS_H + +/* begin file include/ada/common_defs.h */ +/** + * @file common_defs.h + * @brief Cross-platform compiler macros and common definitions. + * + * This header provides compiler-specific macros for optimization hints, + * platform detection, SIMD support detection, and development/debug utilities. + * It ensures consistent behavior across different compilers (GCC, Clang, MSVC). + */ +#ifndef ADA_COMMON_DEFS_H +#define ADA_COMMON_DEFS_H + +// https://en.cppreference.com/w/cpp/feature_test#Library_features +// detect C++20 features +#include + +#ifdef _MSC_VER +#define ADA_VISUAL_STUDIO 1 +/** + * We want to differentiate carefully between + * clang under visual studio and regular visual + * studio. + */ +#ifdef __clang__ +// clang under visual studio +#define ADA_CLANG_VISUAL_STUDIO 1 +#else +// just regular visual studio (best guess) +#define ADA_REGULAR_VISUAL_STUDIO 1 +#endif // __clang__ +#endif // _MSC_VER + +#if defined(__GNUC__) +// Marks a block with a name so that MCA analysis can see it. +#define ADA_BEGIN_DEBUG_BLOCK(name) __asm volatile("# LLVM-MCA-BEGIN " #name); +#define ADA_END_DEBUG_BLOCK(name) __asm volatile("# LLVM-MCA-END " #name); +#define ADA_DEBUG_BLOCK(name, block) \ + BEGIN_DEBUG_BLOCK(name); \ + block; \ + END_DEBUG_BLOCK(name); +#else +#define ADA_BEGIN_DEBUG_BLOCK(name) +#define ADA_END_DEBUG_BLOCK(name) +#define ADA_DEBUG_BLOCK(name, block) +#endif + +// Align to N-byte boundary +#define ADA_ROUNDUP_N(a, n) (((a) + ((n) - 1)) & ~((n) - 1)) +#define ADA_ROUNDDOWN_N(a, n) ((a) & ~((n) - 1)) + +#define ADA_ISALIGNED_N(ptr, n) (((uintptr_t)(ptr) & ((n) - 1)) == 0) + +#if defined(ADA_REGULAR_VISUAL_STUDIO) + +#define ada_really_inline __forceinline +#define ada_never_inline __declspec(noinline) + +#define ada_unused +#define ada_warn_unused + +#define ADA_PUSH_DISABLE_WARNINGS __pragma(warning(push)) +#define ADA_PUSH_DISABLE_ALL_WARNINGS __pragma(warning(push, 0)) +#define ADA_DISABLE_VS_WARNING(WARNING_NUMBER) \ + __pragma(warning(disable : WARNING_NUMBER)) +// Get rid of Intellisense-only warnings (Code Analysis) +// Though __has_include is C++17, it is supported in Visual Studio 2017 or +// better (_MSC_VER>=1910). +#ifdef __has_include +#if __has_include() +#include +#define ADA_DISABLE_UNDESIRED_WARNINGS \ + ADA_DISABLE_VS_WARNING(ALL_CPPCORECHECK_WARNINGS) +#endif +#endif + +#ifndef ADA_DISABLE_UNDESIRED_WARNINGS +#define ADA_DISABLE_UNDESIRED_WARNINGS +#endif + +#define ADA_DISABLE_DEPRECATED_WARNING ADA_DISABLE_VS_WARNING(4996) +#define ADA_DISABLE_STRICT_OVERFLOW_WARNING +#define ADA_POP_DISABLE_WARNINGS __pragma(warning(pop)) + +#else // ADA_REGULAR_VISUAL_STUDIO + +#define ada_really_inline inline __attribute__((always_inline)) +#define ada_never_inline inline __attribute__((noinline)) + +#define ada_unused __attribute__((unused)) +#define ada_warn_unused __attribute__((warn_unused_result)) + +#define ADA_PUSH_DISABLE_WARNINGS _Pragma("GCC diagnostic push") +// gcc doesn't seem to disable all warnings with all and extra, add warnings +// here as necessary +#define ADA_PUSH_DISABLE_ALL_WARNINGS \ + ADA_PUSH_DISABLE_WARNINGS \ + ADA_DISABLE_GCC_WARNING("-Weffc++") \ + ADA_DISABLE_GCC_WARNING("-Wall") \ + ADA_DISABLE_GCC_WARNING("-Wconversion") \ + ADA_DISABLE_GCC_WARNING("-Wextra") \ + ADA_DISABLE_GCC_WARNING("-Wattributes") \ + ADA_DISABLE_GCC_WARNING("-Wimplicit-fallthrough") \ + ADA_DISABLE_GCC_WARNING("-Wnon-virtual-dtor") \ + ADA_DISABLE_GCC_WARNING("-Wreturn-type") \ + ADA_DISABLE_GCC_WARNING("-Wshadow") \ + ADA_DISABLE_GCC_WARNING("-Wunused-parameter") \ + ADA_DISABLE_GCC_WARNING("-Wunused-variable") \ + ADA_DISABLE_GCC_WARNING("-Wsign-compare") +#define ADA_PRAGMA(P) _Pragma(#P) +#define ADA_DISABLE_GCC_WARNING(WARNING) \ + ADA_PRAGMA(GCC diagnostic ignored WARNING) +#if defined(ADA_CLANG_VISUAL_STUDIO) +#define ADA_DISABLE_UNDESIRED_WARNINGS \ + ADA_DISABLE_GCC_WARNING("-Wmicrosoft-include") +#else +#define ADA_DISABLE_UNDESIRED_WARNINGS +#endif +#define ADA_DISABLE_DEPRECATED_WARNING \ + ADA_DISABLE_GCC_WARNING("-Wdeprecated-declarations") +#define ADA_DISABLE_STRICT_OVERFLOW_WARNING \ + ADA_DISABLE_GCC_WARNING("-Wstrict-overflow") +#define ADA_POP_DISABLE_WARNINGS _Pragma("GCC diagnostic pop") + +#endif // MSC_VER + +#if defined(ADA_VISUAL_STUDIO) +/** + * It does not matter here whether you are using + * the regular visual studio or clang under visual + * studio. + */ +#if ADA_USING_LIBRARY +#define ADA_DLLIMPORTEXPORT __declspec(dllimport) +#else +#define ADA_DLLIMPORTEXPORT __declspec(dllexport) +#endif +#else +#define ADA_DLLIMPORTEXPORT +#endif + +/// If EXPR is an error, returns it. +#define ADA_TRY(EXPR) \ + { \ + auto _err = (EXPR); \ + if (_err) { \ + return _err; \ + } \ + } + +// __has_cpp_attribute is part of C++20 +#if !defined(__has_cpp_attribute) +#define __has_cpp_attribute(x) 0 +#endif + +#if __has_cpp_attribute(gnu::noinline) +#define ADA_ATTRIBUTE_NOINLINE [[gnu::noinline]] +#else +#define ADA_ATTRIBUTE_NOINLINE +#endif + +namespace ada { +[[noreturn]] inline void unreachable() { +#ifdef __GNUC__ + __builtin_unreachable(); +#elif defined(_MSC_VER) + __assume(false); +#else +#endif +} +} // namespace ada + +// Unless the programmer has already set ADA_DEVELOPMENT_CHECKS, +// we want to set it under debug builds. We detect a debug build +// under Visual Studio when the _DEBUG macro is set. Under the other +// compilers, we use the fact that they define __OPTIMIZE__ whenever +// they allow optimizations. +// It is possible that this could miss some cases where ADA_DEVELOPMENT_CHECKS +// is helpful, but the programmer can set the macro ADA_DEVELOPMENT_CHECKS. +// It could also wrongly set ADA_DEVELOPMENT_CHECKS (e.g., if the programmer +// sets _DEBUG in a release build under Visual Studio, or if some compiler fails +// to set the __OPTIMIZE__ macro). +#if !defined(ADA_DEVELOPMENT_CHECKS) && !defined(NDEBUG) +#ifdef _MSC_VER +// Visual Studio seems to set _DEBUG for debug builds. +#ifdef _DEBUG +#define ADA_DEVELOPMENT_CHECKS 1 +#endif // _DEBUG +#else // _MSC_VER +// All other compilers appear to set __OPTIMIZE__ to a positive integer +// when the compiler is optimizing. +#ifndef __OPTIMIZE__ +#define ADA_DEVELOPMENT_CHECKS 1 +#endif // __OPTIMIZE__ +#endif // _MSC_VER +#endif // ADA_DEVELOPMENT_CHECKS + +#define ADA_STR(x) #x + +#if ADA_DEVELOPMENT_CHECKS +#define ADA_REQUIRE(EXPR) \ + { \ + if (!(EXPR) { abort(); }) } + +#define ADA_FAIL(MESSAGE) \ + do { \ + std::cerr << "FAIL: " << (MESSAGE) << std::endl; \ + abort(); \ + } while (0); +#define ADA_ASSERT_EQUAL(LHS, RHS, MESSAGE) \ + do { \ + if (LHS != RHS) { \ + std::cerr << "Mismatch: '" << LHS << "' - '" << RHS << "'" << std::endl; \ + ADA_FAIL(MESSAGE); \ + } \ + } while (0); +#define ADA_ASSERT_TRUE(COND) \ + do { \ + if (!(COND)) { \ + std::cerr << "Assert at line " << __LINE__ << " of file " << __FILE__ \ + << std::endl; \ + ADA_FAIL(ADA_STR(COND)); \ + } \ + } while (0); +#else +#define ADA_FAIL(MESSAGE) +#define ADA_ASSERT_EQUAL(LHS, RHS, MESSAGE) +#define ADA_ASSERT_TRUE(COND) +#endif + +#ifdef ADA_VISUAL_STUDIO +#define ADA_ASSUME(COND) __assume(COND) +#else +#define ADA_ASSUME(COND) \ + do { \ + if (!(COND)) { \ + __builtin_unreachable(); \ + } \ + } while (0) +#endif + +#if defined(__SSSE3__) +#define ADA_SSSE3 1 +#endif + +#if defined(__SSE2__) || defined(__x86_64__) || defined(__x86_64) || \ + (defined(_M_AMD64) || defined(_M_X64) || \ + (defined(_M_IX86_FP) && _M_IX86_FP == 2)) +#define ADA_SSE2 1 +#endif + +// AVX-512 byte/word ops + 128/256-bit vectors of AVX-512 instructions. +// Used for optional high-performance IP address parsing kernels. +#if defined(__AVX512BW__) && defined(__AVX512VL__) +#define ADA_AVX512 1 +#endif + +#if defined(__aarch64__) || defined(_M_ARM64) +#define ADA_NEON 1 +#endif + +#if defined(__loongarch_sx) +#define ADA_LSX 1 +#endif + +#if defined(__riscv_v) && __riscv_v_intrinsic >= 11000 +// Support RVV intrinsics v0.11 and above +#define ADA_RVV 1 +#endif + +#ifndef __has_cpp_attribute +#define ada_lifetime_bound +#elif __has_cpp_attribute(msvc::lifetimebound) +#define ada_lifetime_bound [[msvc::lifetimebound]] +#elif __has_cpp_attribute(clang::lifetimebound) +#define ada_lifetime_bound [[clang::lifetimebound]] +#elif __has_cpp_attribute(lifetimebound) +#define ada_lifetime_bound [[lifetimebound]] +#else +#define ada_lifetime_bound +#endif + +#ifdef __cpp_lib_format +#if __cpp_lib_format >= 202110L +#include +#define ADA_HAS_FORMAT 1 +#endif +#endif + +#ifndef ADA_INCLUDE_URL_PATTERN +#define ADA_INCLUDE_URL_PATTERN 1 +#endif // ADA_INCLUDE_URL_PATTERN + +#endif // ADA_COMMON_DEFS_H +/* end file include/ada/common_defs.h */ +#include + +/** + * These functions are not part of our public API and may + * change at any time. + * @private + * @namespace ada::character_sets + * @brief Includes the definitions for unicode character sets. + */ +namespace ada::character_sets { +ada_really_inline constexpr bool bit_at(const uint8_t a[], uint8_t i); +} // namespace ada::character_sets + +#endif // ADA_CHARACTER_SETS_H +/* end file include/ada/character_sets.h */ +/* begin file include/ada/character_sets-inl.h */ +/** + * @file character_sets-inl.h + * @brief Definitions of the character sets used by unicode functions. + * @author Node.js + * @see https://github.com/nodejs/node/blob/main/src/node_url_tables.cc + */ +#ifndef ADA_CHARACTER_SETS_INL_H +#define ADA_CHARACTER_SETS_INL_H + + +/** + * These functions are not part of our public API and may + * change at any time. + * @private + */ +namespace ada::character_sets { + +constexpr char hex[1024] = + "%00\0%01\0%02\0%03\0%04\0%05\0%06\0%07\0" + "%08\0%09\0%0A\0%0B\0%0C\0%0D\0%0E\0%0F\0" + "%10\0%11\0%12\0%13\0%14\0%15\0%16\0%17\0" + "%18\0%19\0%1A\0%1B\0%1C\0%1D\0%1E\0%1F\0" + "%20\0%21\0%22\0%23\0%24\0%25\0%26\0%27\0" + "%28\0%29\0%2A\0%2B\0%2C\0%2D\0%2E\0%2F\0" + "%30\0%31\0%32\0%33\0%34\0%35\0%36\0%37\0" + "%38\0%39\0%3A\0%3B\0%3C\0%3D\0%3E\0%3F\0" + "%40\0%41\0%42\0%43\0%44\0%45\0%46\0%47\0" + "%48\0%49\0%4A\0%4B\0%4C\0%4D\0%4E\0%4F\0" + "%50\0%51\0%52\0%53\0%54\0%55\0%56\0%57\0" + "%58\0%59\0%5A\0%5B\0%5C\0%5D\0%5E\0%5F\0" + "%60\0%61\0%62\0%63\0%64\0%65\0%66\0%67\0" + "%68\0%69\0%6A\0%6B\0%6C\0%6D\0%6E\0%6F\0" + "%70\0%71\0%72\0%73\0%74\0%75\0%76\0%77\0" + "%78\0%79\0%7A\0%7B\0%7C\0%7D\0%7E\0%7F\0" + "%80\0%81\0%82\0%83\0%84\0%85\0%86\0%87\0" + "%88\0%89\0%8A\0%8B\0%8C\0%8D\0%8E\0%8F\0" + "%90\0%91\0%92\0%93\0%94\0%95\0%96\0%97\0" + "%98\0%99\0%9A\0%9B\0%9C\0%9D\0%9E\0%9F\0" + "%A0\0%A1\0%A2\0%A3\0%A4\0%A5\0%A6\0%A7\0" + "%A8\0%A9\0%AA\0%AB\0%AC\0%AD\0%AE\0%AF\0" + "%B0\0%B1\0%B2\0%B3\0%B4\0%B5\0%B6\0%B7\0" + "%B8\0%B9\0%BA\0%BB\0%BC\0%BD\0%BE\0%BF\0" + "%C0\0%C1\0%C2\0%C3\0%C4\0%C5\0%C6\0%C7\0" + "%C8\0%C9\0%CA\0%CB\0%CC\0%CD\0%CE\0%CF\0" + "%D0\0%D1\0%D2\0%D3\0%D4\0%D5\0%D6\0%D7\0" + "%D8\0%D9\0%DA\0%DB\0%DC\0%DD\0%DE\0%DF\0" + "%E0\0%E1\0%E2\0%E3\0%E4\0%E5\0%E6\0%E7\0" + "%E8\0%E9\0%EA\0%EB\0%EC\0%ED\0%EE\0%EF\0" + "%F0\0%F1\0%F2\0%F3\0%F4\0%F5\0%F6\0%F7\0" + "%F8\0%F9\0%FA\0%FB\0%FC\0%FD\0%FE\0%FF"; + +constexpr uint8_t C0_CONTROL_PERCENT_ENCODE[32] = { + // 00 01 02 03 04 05 06 07 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 08 09 0A 0B 0C 0D 0E 0F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 10 11 12 13 14 15 16 17 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 18 19 1A 1B 1C 1D 1E 1F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 20 21 22 23 24 25 26 27 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 28 29 2A 2B 2C 2D 2E 2F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 30 31 32 33 34 35 36 37 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 38 39 3A 3B 3C 3D 3E 3F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 40 41 42 43 44 45 46 47 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 48 49 4A 4B 4C 4D 4E 4F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 50 51 52 53 54 55 56 57 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 58 59 5A 5B 5C 5D 5E 5F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 60 61 62 63 64 65 66 67 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 68 69 6A 6B 6C 6D 6E 6F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 70 71 72 73 74 75 76 77 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 78 79 7A 7B 7C 7D 7E 7F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80, + // 80 81 82 83 84 85 86 87 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 88 89 8A 8B 8C 8D 8E 8F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 90 91 92 93 94 95 96 97 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 98 99 9A 9B 9C 9D 9E 9F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A0 A1 A2 A3 A4 A5 A6 A7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A8 A9 AA AB AC AD AE AF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B0 B1 B2 B3 B4 B5 B6 B7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B8 B9 BA BB BC BD BE BF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C0 C1 C2 C3 C4 C5 C6 C7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C8 C9 CA CB CC CD CE CF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D0 D1 D2 D3 D4 D5 D6 D7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D8 D9 DA DB DC DD DE DF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E0 E1 E2 E3 E4 E5 E6 E7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E8 E9 EA EB EC ED EE EF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F0 F1 F2 F3 F4 F5 F6 F7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F8 F9 FA FB FC FD FE FF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80}; + +constexpr uint8_t SPECIAL_QUERY_PERCENT_ENCODE[32] = { + // 00 01 02 03 04 05 06 07 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 08 09 0A 0B 0C 0D 0E 0F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 10 11 12 13 14 15 16 17 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 18 19 1A 1B 1C 1D 1E 1F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 20 21 22 23 24 25 26 27 + 0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x80, + // 28 29 2A 2B 2C 2D 2E 2F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 30 31 32 33 34 35 36 37 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 38 39 3A 3B 3C 3D 3E 3F + 0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00, + // 40 41 42 43 44 45 46 47 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 48 49 4A 4B 4C 4D 4E 4F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 50 51 52 53 54 55 56 57 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 58 59 5A 5B 5C 5D 5E 5F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 60 61 62 63 64 65 66 67 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 68 69 6A 6B 6C 6D 6E 6F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 70 71 72 73 74 75 76 77 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 78 79 7A 7B 7C 7D 7E 7F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80, + // 80 81 82 83 84 85 86 87 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 88 89 8A 8B 8C 8D 8E 8F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 90 91 92 93 94 95 96 97 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 98 99 9A 9B 9C 9D 9E 9F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A0 A1 A2 A3 A4 A5 A6 A7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A8 A9 AA AB AC AD AE AF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B0 B1 B2 B3 B4 B5 B6 B7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B8 B9 BA BB BC BD BE BF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C0 C1 C2 C3 C4 C5 C6 C7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C8 C9 CA CB CC CD CE CF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D0 D1 D2 D3 D4 D5 D6 D7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D8 D9 DA DB DC DD DE DF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E0 E1 E2 E3 E4 E5 E6 E7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E8 E9 EA EB EC ED EE EF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F0 F1 F2 F3 F4 F5 F6 F7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F8 F9 FA FB FC FD FE FF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80}; + +constexpr uint8_t QUERY_PERCENT_ENCODE[32] = { + // 00 01 02 03 04 05 06 07 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 08 09 0A 0B 0C 0D 0E 0F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 10 11 12 13 14 15 16 17 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 18 19 1A 1B 1C 1D 1E 1F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 20 21 22 23 24 25 26 27 + 0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00, + // 28 29 2A 2B 2C 2D 2E 2F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 30 31 32 33 34 35 36 37 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 38 39 3A 3B 3C 3D 3E 3F + 0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00, + // 40 41 42 43 44 45 46 47 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 48 49 4A 4B 4C 4D 4E 4F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 50 51 52 53 54 55 56 57 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 58 59 5A 5B 5C 5D 5E 5F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 60 61 62 63 64 65 66 67 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 68 69 6A 6B 6C 6D 6E 6F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 70 71 72 73 74 75 76 77 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 78 79 7A 7B 7C 7D 7E 7F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80, + // 80 81 82 83 84 85 86 87 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 88 89 8A 8B 8C 8D 8E 8F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 90 91 92 93 94 95 96 97 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 98 99 9A 9B 9C 9D 9E 9F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A0 A1 A2 A3 A4 A5 A6 A7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A8 A9 AA AB AC AD AE AF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B0 B1 B2 B3 B4 B5 B6 B7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B8 B9 BA BB BC BD BE BF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C0 C1 C2 C3 C4 C5 C6 C7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C8 C9 CA CB CC CD CE CF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D0 D1 D2 D3 D4 D5 D6 D7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D8 D9 DA DB DC DD DE DF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E0 E1 E2 E3 E4 E5 E6 E7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E8 E9 EA EB EC ED EE EF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F0 F1 F2 F3 F4 F5 F6 F7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F8 F9 FA FB FC FD FE FF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80}; + +constexpr uint8_t FRAGMENT_PERCENT_ENCODE[32] = { + // 00 01 02 03 04 05 06 07 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 08 09 0A 0B 0C 0D 0E 0F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 10 11 12 13 14 15 16 17 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 18 19 1A 1B 1C 1D 1E 1F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 20 21 22 23 24 25 26 27 + 0x01 | 0x00 | 0x04 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 28 29 2A 2B 2C 2D 2E 2F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 30 31 32 33 34 35 36 37 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 38 39 3A 3B 3C 3D 3E 3F + 0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00, + // 40 41 42 43 44 45 46 47 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 48 49 4A 4B 4C 4D 4E 4F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 50 51 52 53 54 55 56 57 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 58 59 5A 5B 5C 5D 5E 5F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 60 61 62 63 64 65 66 67 + 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 68 69 6A 6B 6C 6D 6E 6F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 70 71 72 73 74 75 76 77 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 78 79 7A 7B 7C 7D 7E 7F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80, + // 80 81 82 83 84 85 86 87 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 88 89 8A 8B 8C 8D 8E 8F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 90 91 92 93 94 95 96 97 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 98 99 9A 9B 9C 9D 9E 9F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A0 A1 A2 A3 A4 A5 A6 A7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A8 A9 AA AB AC AD AE AF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B0 B1 B2 B3 B4 B5 B6 B7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B8 B9 BA BB BC BD BE BF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C0 C1 C2 C3 C4 C5 C6 C7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C8 C9 CA CB CC CD CE CF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D0 D1 D2 D3 D4 D5 D6 D7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D8 D9 DA DB DC DD DE DF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E0 E1 E2 E3 E4 E5 E6 E7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E8 E9 EA EB EC ED EE EF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F0 F1 F2 F3 F4 F5 F6 F7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F8 F9 FA FB FC FD FE FF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80}; + +constexpr uint8_t USERINFO_PERCENT_ENCODE[32] = { + // 00 01 02 03 04 05 06 07 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 08 09 0A 0B 0C 0D 0E 0F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 10 11 12 13 14 15 16 17 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 18 19 1A 1B 1C 1D 1E 1F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 20 21 22 23 24 25 26 27 + 0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00, + // 28 29 2A 2B 2C 2D 2E 2F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80, + // 30 31 32 33 34 35 36 37 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 38 39 3A 3B 3C 3D 3E 3F + 0x00 | 0x00 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 40 41 42 43 44 45 46 47 + 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 48 49 4A 4B 4C 4D 4E 4F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 50 51 52 53 54 55 56 57 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 58 59 5A 5B 5C 5D 5E 5F + 0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x00, + // 60 61 62 63 64 65 66 67 + 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 68 69 6A 6B 6C 6D 6E 6F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 70 71 72 73 74 75 76 77 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 78 79 7A 7B 7C 7D 7E 7F + 0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x00 | 0x80, + // 80 81 82 83 84 85 86 87 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 88 89 8A 8B 8C 8D 8E 8F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 90 91 92 93 94 95 96 97 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 98 99 9A 9B 9C 9D 9E 9F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A0 A1 A2 A3 A4 A5 A6 A7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A8 A9 AA AB AC AD AE AF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B0 B1 B2 B3 B4 B5 B6 B7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B8 B9 BA BB BC BD BE BF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C0 C1 C2 C3 C4 C5 C6 C7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C8 C9 CA CB CC CD CE CF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D0 D1 D2 D3 D4 D5 D6 D7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D8 D9 DA DB DC DD DE DF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E0 E1 E2 E3 E4 E5 E6 E7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E8 E9 EA EB EC ED EE EF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F0 F1 F2 F3 F4 F5 F6 F7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F8 F9 FA FB FC FD FE FF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80}; + +constexpr uint8_t PATH_PERCENT_ENCODE[32] = { + // 00 01 02 03 04 05 06 07 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 08 09 0A 0B 0C 0D 0E 0F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 10 11 12 13 14 15 16 17 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 18 19 1A 1B 1C 1D 1E 1F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 20 21 22 23 24 25 26 27 + 0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00, + // 28 29 2A 2B 2C 2D 2E 2F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 30 31 32 33 34 35 36 37 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 38 39 3A 3B 3C 3D 3E 3F + 0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x80, + // 40 41 42 43 44 45 46 47 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 48 49 4A 4B 4C 4D 4E 4F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 50 51 52 53 54 55 56 57 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 58 59 5A 5B 5C 5D 5E 5F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x40 | 0x00, + // 60 61 62 63 64 65 66 67 + 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 68 69 6A 6B 6C 6D 6E 6F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 70 71 72 73 74 75 76 77 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 78 79 7A 7B 7C 7D 7E 7F + 0x00 | 0x00 | 0x00 | 0x08 | 0x00 | 0x20 | 0x00 | 0x80, + // 80 81 82 83 84 85 86 87 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 88 89 8A 8B 8C 8D 8E 8F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 90 91 92 93 94 95 96 97 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 98 99 9A 9B 9C 9D 9E 9F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A0 A1 A2 A3 A4 A5 A6 A7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A8 A9 AA AB AC AD AE AF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B0 B1 B2 B3 B4 B5 B6 B7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B8 B9 BA BB BC BD BE BF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C0 C1 C2 C3 C4 C5 C6 C7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C8 C9 CA CB CC CD CE CF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D0 D1 D2 D3 D4 D5 D6 D7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D8 D9 DA DB DC DD DE DF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E0 E1 E2 E3 E4 E5 E6 E7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E8 E9 EA EB EC ED EE EF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F0 F1 F2 F3 F4 F5 F6 F7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F8 F9 FA FB FC FD FE FF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80}; + +constexpr uint8_t WWW_FORM_URLENCODED_PERCENT_ENCODE[32] = { + // 00 01 02 03 04 05 06 07 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 08 09 0A 0B 0C 0D 0E 0F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 10 11 12 13 14 15 16 17 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 18 19 1A 1B 1C 1D 1E 1F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 20 21 22 23 24 25 26 27 + 0x00 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 28 29 2A 2B 2C 2D 2E 2F + 0x01 | 0x02 | 0x00 | 0x08 | 0x10 | 0x00 | 0x00 | 0x80, + // 30 31 32 33 34 35 36 37 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 38 39 3A 3B 3C 3D 3E 3F + 0x00 | 0x00 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 40 41 42 43 44 45 46 47 + 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 48 49 4A 4B 4C 4D 4E 4F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 50 51 52 53 54 55 56 57 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 58 59 5A 5B 5C 5D 5E 5F + 0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x00, + // 60 61 62 63 64 65 66 67 + 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 68 69 6A 6B 6C 6D 6E 6F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 70 71 72 73 74 75 76 77 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 78 79 7A 7B 7C 7D 7E 7F + 0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 80 81 82 83 84 85 86 87 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 88 89 8A 8B 8C 8D 8E 8F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 90 91 92 93 94 95 96 97 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 98 99 9A 9B 9C 9D 9E 9F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A0 A1 A2 A3 A4 A5 A6 A7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A8 A9 AA AB AC AD AE AF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B0 B1 B2 B3 B4 B5 B6 B7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B8 B9 BA BB BC BD BE BF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C0 C1 C2 C3 C4 C5 C6 C7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C8 C9 CA CB CC CD CE CF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D0 D1 D2 D3 D4 D5 D6 D7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D8 D9 DA DB DC DD DE DF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E0 E1 E2 E3 E4 E5 E6 E7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E8 E9 EA EB EC ED EE EF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F0 F1 F2 F3 F4 F5 F6 F7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F8 F9 FA FB FC FD FE FF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80}; + +ada_really_inline constexpr bool bit_at(const uint8_t a[], const uint8_t i) { + return !!(a[i >> 3] & (1 << (i & 7))); +} + +} // namespace ada::character_sets + +#endif // ADA_CHARACTER_SETS_INL_H +/* end file include/ada/character_sets-inl.h */ +/* begin file include/ada/checkers-inl.h */ +/** + * @file checkers-inl.h + * @brief Definitions for URL specific checkers used within Ada. + */ +#ifndef ADA_CHECKERS_INL_H +#define ADA_CHECKERS_INL_H + +#include +#include +#include +#include +/* begin file include/ada/checkers.h */ +/** + * @file checkers.h + * @brief Declarations for URL specific checkers used within Ada. + */ +#ifndef ADA_CHECKERS_H +#define ADA_CHECKERS_H + + +#include +#include + +/** + * These functions are not part of our public API and may + * change at any time. + * @private + * @namespace ada::checkers + * @brief Includes the definitions for validation functions + */ +namespace ada::checkers { + +/** + * @private + * Assuming that x is an ASCII letter, this function returns the lower case + * equivalent. + * @details More likely to be inlined by the compiler and constexpr. + */ +constexpr char to_lower(char x) noexcept; + +/** + * @private + * Returns true if the character is an ASCII letter. Equivalent to std::isalpha + * but more likely to be inlined by the compiler. + * + * @attention std::isalpha is not constexpr generally. + */ +constexpr bool is_alpha(char x) noexcept; + +/** + * @private + * Check whether a string starts with 0x or 0X. The function is only + * safe if input.size() >=2. + * + * @see has_hex_prefix + */ +constexpr bool has_hex_prefix_unsafe(std::string_view input); +/** + * @private + * Check whether a string starts with 0x or 0X. + */ +constexpr bool has_hex_prefix(std::string_view input); + +/** + * @private + * Check whether x is an ASCII digit. More likely to be inlined than + * std::isdigit. + */ +constexpr bool is_digit(char x) noexcept; + +/** + * @private + * @details A string starts with a Windows drive letter if all of the following + * are true: + * + * - its length is greater than or equal to 2 + * - its first two code points are a Windows drive letter + * - its length is 2 or its third code point is U+002F (/), U+005C (\), U+003F + * (?), or U+0023 (#). + * + * https://url.spec.whatwg.org/#start-with-a-windows-drive-letter + */ +inline constexpr bool is_windows_drive_letter(std::string_view input) noexcept; + +/** + * @private + * @details A normalized Windows drive letter is a Windows drive letter of which + * the second code point is U+003A (:). + */ +inline constexpr bool is_normalized_windows_drive_letter( + std::string_view input) noexcept; + +/** + * @private + * Returns true if an input is an ipv4 address. It is assumed that the string + * does not contain uppercase ASCII characters (the input should have been + * lowered cased before calling this function) and is not empty. + */ +ada_really_inline constexpr bool is_ipv4(std::string_view view) noexcept; + +/** + * @private + * Returns a bitset. If the first bit is set, then at least one character needs + * percent encoding. If the second bit is set, a \\ is found. If the third bit + * is set then we have a dot. If the fourth bit is set, then we have a percent + * character. + */ +ada_really_inline constexpr uint8_t path_signature( + std::string_view input) noexcept; + +/** + * @private + * Returns true if the length of the domain name and its labels are according to + * the specifications. The length of the domain must be 255 octets (253 + * characters not including the last 2 which are the empty label reserved at the + * end). When the empty label is included (a dot at the end), the domain name + * can have 254 characters. The length of a label must be at least 1 and at most + * 63 characters. + * @see section 3.1. of https://www.rfc-editor.org/rfc/rfc1034 + * @see https://www.unicode.org/reports/tr46/#ToASCII + */ +ada_really_inline constexpr bool verify_dns_length( + std::string_view input) noexcept; + +/** + * @private + * Fast-path parser for pure decimal IPv4 addresses (e.g., "192.168.1.1"). + * Returns the packed 32-bit IPv4 address on success, or a value > 0xFFFFFFFF + * to indicate failure (caller should fall back to general parser). + * This is optimized for the common case where the input is a well-formed + * decimal IPv4 address with exactly 4 octets. + */ +ada_really_inline uint64_t try_parse_ipv4_fast(std::string_view input) noexcept; + +/** + * Sentinel value indicating try_parse_ipv4_fast() did not succeed. + * Any value > 0xFFFFFFFF indicates the fast path should not be used. + */ +constexpr uint64_t ipv4_fast_fail = uint64_t(1) << 32; + +} // namespace ada::checkers + +#endif // ADA_CHECKERS_H +/* end file include/ada/checkers.h */ + +#if defined(ADA_AVX512) +#include +#endif + +namespace ada::checkers { + +constexpr bool has_hex_prefix_unsafe(std::string_view input) { + // This is actually efficient code, see has_hex_prefix for the assembly. + constexpr bool is_little_endian = std::endian::native == std::endian::little; + constexpr uint16_t word0x = 0x7830; + uint16_t two_first_bytes = + static_cast(input[0]) | + static_cast((static_cast(input[1]) << 8)); + if constexpr (is_little_endian) { + two_first_bytes |= 0x2000; + } else { + two_first_bytes |= 0x020; + } + return two_first_bytes == word0x; +} + +constexpr bool has_hex_prefix(std::string_view input) { + return input.size() >= 2 && has_hex_prefix_unsafe(input); +} + +constexpr bool is_digit(char x) noexcept { return (x >= '0') & (x <= '9'); } + +constexpr char to_lower(char x) noexcept { return (x | 0x20); } + +constexpr bool is_alpha(char x) noexcept { + return (to_lower(x) >= 'a') && (to_lower(x) <= 'z'); +} + +constexpr bool is_windows_drive_letter(std::string_view input) noexcept { + return input.size() >= 2 && + (is_alpha(input[0]) && ((input[1] == ':') || (input[1] == '|'))) && + ((input.size() == 2) || (input[2] == '/' || input[2] == '\\' || + input[2] == '?' || input[2] == '#')); +} + +constexpr bool is_normalized_windows_drive_letter( + std::string_view input) noexcept { + return input.size() == 2 && (is_alpha(input[0]) && (input[1] == ':')); +} + +namespace detail { + +// Unrolled pure-decimal IPv4. The common portable path for 7-16 byte hosts. +ada_really_inline uint64_t +parse_ipv4_decimal_scalar(const char* p, const char* pend) noexcept { + uint32_t ipv4 = 0; + for (int i = 0; i < 4; ++i) { + if (p == pend) [[unlikely]] { + return ipv4_fast_fail; + } + uint32_t val; + char c = *p; + if (c >= '0' && c <= '9') [[likely]] { + val = static_cast(c - '0'); + ++p; + } else { + return ipv4_fast_fail; + } + if (p < pend) { + c = *p; + if (c >= '0' && c <= '9') { + if (val == 0) [[unlikely]] { + return ipv4_fast_fail; + } + val = val * 10u + static_cast(c - '0'); + ++p; + if (p < pend) { + c = *p; + if (c >= '0' && c <= '9') { + val = val * 10u + static_cast(c - '0'); + ++p; + if (val > 255u) [[unlikely]] { + return ipv4_fast_fail; + } + } + } + } + } + ipv4 = (ipv4 << 8) | val; + if (i < 3) { + if (p == pend || *p != '.') [[unlikely]] { + return ipv4_fast_fail; + } + ++p; + } + } + if (p != pend) { + if (p == pend - 1 && *p == '.') { + return ipv4; + } + return ipv4_fast_fail; + } + return ipv4; +} + +#if defined(ADA_AVX512) +// After SIMD validation: fewer rejection branches on convert. +ada_really_inline uint64_t +parse_ipv4_decimal_trusted(const char* p, const char* pend) noexcept { + uint32_t ipv4 = 0; + for (int i = 0; i < 4; ++i) { + uint32_t val = static_cast(*p - '0'); + ++p; + if (p < pend && static_cast(*p - '0') <= 9) { + if (val == 0) [[unlikely]] { + return ipv4_fast_fail; + } + val = val * 10u + static_cast(*p - '0'); + ++p; + if (p < pend && static_cast(*p - '0') <= 9) { + val = val * 10u + static_cast(*p - '0'); + ++p; + if (val > 255u) [[unlikely]] { + return ipv4_fast_fail; + } + } + } + ipv4 = (ipv4 << 8) | val; + if (i < 3) { + ++p; // trusted '.' + } + } + return ipv4; // trailing-dot already accounted for by caller via pend +} + +// AVX-512 pure-decimal IPv4 (Lemire/Mula-style masked load + parallel checks). +// No over-read of the source string. Wins when the binary is built with +// -mavx512bw -mavx512vl (or -march that enables them). +ada_really_inline uint64_t try_parse_ipv4_avx512(const char* data, + size_t len) noexcept { + const __mmask16 live = static_cast<__mmask16>((1u << len) - 1u); + const __m128i input = + _mm_maskz_loadu_epi8(live, reinterpret_cast(data)); + const __mmask16 is_dot = + _mm_mask_cmpeq_epi8_mask(live, input, _mm_set1_epi8('.')); + const __m128i shifted = _mm_sub_epi8(input, _mm_set1_epi8('0')); + const __mmask16 is_digit = + _mm_mask_cmplt_epu8_mask(live, shifted, _mm_set1_epi8(10)); + if ((is_digit | is_dot) != live) { + return ipv4_fast_fail; + } + const unsigned dot_count = + static_cast(_mm_popcnt_u32(static_cast(is_dot))); + size_t effective_len = len; + if (dot_count == 3) { + // ok + } else if (dot_count == 4 && data[len - 1] == '.') { + effective_len = len - 1; // strip trailing dot for convert + } else { + return ipv4_fast_fail; + } + // Convert from a tiny stack copy so trusted peeks stay in-bounds. + alignas(16) char buf[16]{}; + std::memcpy(buf, data, effective_len); + return parse_ipv4_decimal_trusted(buf, buf + effective_len); +} +#endif // ADA_AVX512 + +} // namespace detail + +/** + * Fast pure-decimal IPv4 parse. Returns packed address or ipv4_fast_fail. + * Accepts an optional single trailing dot. + * + * On AVX-512BW+VL targets, uses a masked-load SIMD kernel (no source + * over-read) inspired by Lemire/Mula. Otherwise uses an unrolled scalar path + * (typically faster than SSE2/NEON pre-validation for these 7-16 byte hosts). + */ +ada_really_inline uint64_t +try_parse_ipv4_fast(std::string_view input) noexcept { + const size_t len = input.size(); + // Shortest pure decimal: "0.0.0.0" (7). Longest + trailing dot: 16. + if (len < 7 || len > 16) [[unlikely]] { + return ipv4_fast_fail; + } + const char* data = input.data(); + +#if defined(ADA_AVX512) + return detail::try_parse_ipv4_avx512(data, len); +#else + return detail::parse_ipv4_decimal_scalar(data, data + len); +#endif +} + +} // namespace ada::checkers + +#endif // ADA_CHECKERS_INL_H +/* end file include/ada/checkers-inl.h */ +/* begin file include/ada/log.h */ +/** + * @file log.h + * @brief Includes the definitions for logging. + * @private Excluded from docs through the doxygen file. + */ +#ifndef ADA_LOG_H +#define ADA_LOG_H + +// To enable logging, set ADA_LOGGING to 1: +#ifndef ADA_LOGGING +#define ADA_LOGGING 0 +#endif + +#if ADA_LOGGING +#include +#endif // ADA_LOGGING + +namespace ada { + +/** + * Log a message. If you want to have no overhead when logging is disabled, use + * the ada_log macro. + * @private + */ +template +constexpr ada_really_inline void log([[maybe_unused]] Args... args) { +#if ADA_LOGGING + ((std::cout << "ADA_LOG: ") << ... << args) << std::endl; +#endif // ADA_LOGGING +} +} // namespace ada + +#if ADA_LOGGING +#ifndef ada_log +#define ada_log(...) \ + do { \ + ada::log(__VA_ARGS__); \ + } while (0) +#endif // ada_log +#else +#define ada_log(...) +#endif // ADA_LOGGING + +#endif // ADA_LOG_H +/* end file include/ada/log.h */ +/* begin file include/ada/encoding_type.h */ +/** + * @file encoding_type.h + * @brief Character encoding type definitions. + * + * Defines the encoding types supported for URL processing. + * + * @see https://encoding.spec.whatwg.org/ + */ +#ifndef ADA_ENCODING_TYPE_H +#define ADA_ENCODING_TYPE_H + +#include + +namespace ada { + +/** + * @brief Character encoding types for URL processing. + * + * Specifies the character encoding used for percent-decoding and other + * string operations. UTF-8 is the most commonly used encoding for URLs. + * + * @see https://encoding.spec.whatwg.org/#encodings + */ +enum class encoding_type { + UTF8, /**< UTF-8 encoding (default for URLs) */ + UTF_16LE, /**< UTF-16 Little Endian encoding */ + UTF_16BE, /**< UTF-16 Big Endian encoding */ +}; + +/** + * Converts an encoding_type to its string representation. + * @param type The encoding type to convert. + * @return A string view of the encoding name. + */ +ada_warn_unused std::string_view to_string(encoding_type type); + +} // namespace ada + +#endif // ADA_ENCODING_TYPE_H +/* end file include/ada/encoding_type.h */ +/* begin file include/ada/helpers.h */ +/** + * @file helpers.h + * @brief Definitions for helper functions used within Ada. + */ +#ifndef ADA_HELPERS_H +#define ADA_HELPERS_H + +/* begin file include/ada/url_base.h */ +/** + * @file url_base.h + * @brief Base class and common definitions for URL types. + * + * This file defines the `url_base` abstract base class from which both + * `ada::url` and `ada::url_aggregator` inherit. It also defines common + * enumerations like `url_host_type`. + */ +#ifndef ADA_URL_BASE_H +#define ADA_URL_BASE_H + +/* begin file include/ada/scheme.h */ +/** + * @file scheme.h + * @brief URL scheme type definitions and utilities. + * + * This header defines the URL scheme types (http, https, etc.) and provides + * functions to identify special schemes and their default ports according + * to the WHATWG URL Standard. + * + * @see https://url.spec.whatwg.org/#special-scheme + */ +#ifndef ADA_SCHEME_H +#define ADA_SCHEME_H + + +#include + +/** + * @namespace ada::scheme + * @brief URL scheme utilities and constants. + * + * Provides functions for working with URL schemes, including identification + * of special schemes and retrieval of default port numbers. + */ +namespace ada::scheme { + +/** + * @brief Enumeration of URL scheme types. + * + * Special schemes have specific parsing rules and default ports. + * Using an enum allows efficient scheme comparisons without string operations. + * + * Default ports: + * - HTTP: 80 + * - HTTPS: 443 + * - WS: 80 + * - WSS: 443 + * - FTP: 21 + * - FILE: (none) + */ +enum type : uint8_t { + HTTP = 0, /**< http:// scheme (port 80) */ + NOT_SPECIAL = 1, /**< Non-special scheme (no default port) */ + HTTPS = 2, /**< https:// scheme (port 443) */ + WS = 3, /**< ws:// WebSocket scheme (port 80) */ + FTP = 4, /**< ftp:// scheme (port 21) */ + WSS = 5, /**< wss:// secure WebSocket scheme (port 443) */ + FILE = 6 /**< file:// scheme (no default port) */ +}; + +/** + * Checks if a scheme string is a special scheme. + * @param scheme The scheme string to check (e.g., "http", "https"). + * @return `true` if the scheme is special, `false` otherwise. + * @see https://url.spec.whatwg.org/#special-scheme + */ +ada_really_inline constexpr bool is_special(std::string_view scheme); + +/** + * Returns the default port for a special scheme string. + * @param scheme The scheme string (e.g., "http", "https"). + * @return The default port number, or 0 if not a special scheme. + * @see https://url.spec.whatwg.org/#special-scheme + */ +constexpr uint16_t get_special_port(std::string_view scheme) noexcept; + +/** + * Returns the default port for a scheme type. + * @param type The scheme type enum value. + * @return The default port number, or 0 if not applicable. + * @see https://url.spec.whatwg.org/#special-scheme + */ +constexpr uint16_t get_special_port(ada::scheme::type type) noexcept; + +/** + * Converts a scheme string to its type enum. + * @param scheme The scheme string to convert. + * @return The corresponding scheme type, or NOT_SPECIAL if not recognized. + */ +constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept; + +} // namespace ada::scheme + +#endif // ADA_SCHEME_H +/* end file include/ada/scheme.h */ + +#include +#include + +namespace ada { + +/** + * @brief Enum representing the type of host in a URL. + * + * Used to distinguish between regular domain names, IPv4 addresses, + * and IPv6 addresses for proper parsing and serialization. + */ +enum url_host_type : uint8_t { + /** Regular domain name (e.g., "www.example.com") */ + DEFAULT = 0, + /** IPv4 address (e.g., "127.0.0.1") */ + IPV4 = 1, + /** IPv6 address (e.g., "[::1]" or "[2001:db8::1]") */ + IPV6 = 2, +}; + +/** + * @brief Abstract base class for URL representations. + * + * The `url_base` class provides the common interface and state shared by + * both `ada::url` and `ada::url_aggregator`. It contains basic URL attributes + * like validity status and scheme type, but delegates component storage and + * access to derived classes. + * + * @note This is an abstract class and cannot be instantiated directly. + * Use `ada::url` or `ada::url_aggregator` instead. + * + * @see url + * @see url_aggregator + */ +struct url_base { + virtual ~url_base() = default; + + /** + * Indicates whether the URL was successfully parsed. + * Set to `false` if parsing failed (e.g., invalid URL syntax). + */ + bool is_valid{true}; + + /** + * Indicates whether the URL has an opaque path (non-hierarchical). + * Opaque paths occur in non-special URLs like `mailto:` or `javascript:`. + */ + bool has_opaque_path{false}; + + /** + * The type of the URL's host (domain, IPv4, or IPv6). + */ + url_host_type host_type = url_host_type::DEFAULT; + + /** + * @private + * Internal representation of the URL's scheme type. + */ + ada::scheme::type type{ada::scheme::type::NOT_SPECIAL}; + + /** + * Checks if the URL has a special scheme (http, https, ws, wss, ftp, file). + * Special schemes have specific parsing rules and default ports. + * @return `true` if the scheme is special, `false` otherwise. + */ + [[nodiscard]] ada_really_inline constexpr bool is_special() const noexcept; + + /** + * Returns the URL's origin (scheme + host + port for special URLs). + * @return A newly allocated string containing the serialized origin. + * @see https://url.spec.whatwg.org/#concept-url-origin + */ + [[nodiscard]] virtual std::string get_origin() const = 0; + + /** + * Validates whether the hostname is a valid domain according to RFC 1034. + * Checks that the domain and its labels have valid lengths. + * @return `true` if the domain is valid, `false` otherwise. + */ + [[nodiscard]] virtual bool has_valid_domain() const noexcept = 0; + + /** + * @private + * Returns the default port for special schemes (e.g., 443 for https). + * Returns 0 for file:// URLs or non-special schemes. + */ + [[nodiscard]] inline uint16_t get_special_port() const noexcept; + + /** + * @private + * Returns the default port for the URL's scheme, or 0 if none. + */ + [[nodiscard]] ada_really_inline uint16_t scheme_default_port() const noexcept; + + /** + * @private + * Parses a port number from the input string. + * @param view The string containing the port to parse. + * @param check_trailing_content Whether to validate no trailing characters. + * @return Number of bytes consumed on success, 0 on failure. + */ + virtual size_t parse_port(std::string_view view, + bool check_trailing_content) = 0; + + /** @private */ + virtual ada_really_inline size_t parse_port(std::string_view view) { + return this->parse_port(view, false); + } + + /** + * Returns a JSON string representation of this URL for debugging. + * @return A JSON-formatted string with URL information. + */ + [[nodiscard]] virtual std::string to_string() const = 0; + + /** @private */ + virtual inline void clear_pathname() = 0; + + /** @private */ + virtual inline void clear_search() = 0; + + /** @private */ + [[nodiscard]] virtual inline bool has_hash() const noexcept = 0; + + /** @private */ + [[nodiscard]] virtual inline bool has_search() const noexcept = 0; + +}; // url_base + +} // namespace ada + +#endif +/* end file include/ada/url_base.h */ + +#include +#include +#include + +#if ADA_DEVELOPMENT_CHECKS +#include +#endif // ADA_DEVELOPMENT_CHECKS + +/** + * These functions are not part of our public API and may + * change at any time. + * + * @private + * @namespace ada::helpers + * @brief Includes the definitions for helper functions + */ +namespace ada::helpers { + +/** + * @private + */ +template +void encode_json(std::string_view view, out_iter out); + +/** + * @private + * This function is used to prune a fragment from a url, and returning the + * removed string if input has fragment. + * + * @details prune_hash seeks the first '#' and returns everything after it + * as a string_view, and modifies (in place) the input so that it points at + * everything before the '#'. If no '#' is found, the input is left unchanged + * and std::nullopt is returned. + * + * @attention The function is non-allocating and it does not throw. + * @returns Note that the returned string_view might be empty! + */ +ada_really_inline std::optional prune_hash( + std::string_view& input) noexcept; + +/** + * @private + * Defined by the URL specification, shorten a URLs paths. + * @see https://url.spec.whatwg.org/#shorten-a-urls-path + * @returns Returns true if path is shortened. + */ +ada_really_inline bool shorten_path(std::string& path, ada::scheme::type type); + +/** + * @private + * Defined by the URL specification, shorten a URLs paths. + * @see https://url.spec.whatwg.org/#shorten-a-urls-path + * @returns Returns true if path is shortened. + */ +ada_really_inline bool shorten_path(std::string_view& path, + ada::scheme::type type); + +/** + * @private + * + * Parse the path from the provided input and append to the existing + * (possibly empty) path. The input cannot contain tabs and spaces: it + * is the user's responsibility to check. + * + * The input is expected to be UTF-8. + * + * @see https://url.spec.whatwg.org/ + */ +ada_really_inline void parse_prepared_path(std::string_view input, + ada::scheme::type type, + std::string& path); + +/** + * @private + * Remove and mutate all ASCII tab or newline characters from an input. + */ +ada_really_inline void remove_ascii_tab_or_newline(std::string& input); + +/** + * @private + * Return the substring from input going from index pos to the end. + */ +ada_really_inline constexpr std::string_view substring(std::string_view input, + size_t pos); + +/** + * @private + * Returns true if the string_view points within the string. + */ +bool overlaps(std::string_view input1, const std::string& input2) noexcept; + +/** + * @private + * Return the substring from input going from index pos1 to the pos2 (non + * included). The length of the substring is pos2 - pos1. + */ +ada_really_inline constexpr std::string_view substring(std::string_view input, + size_t pos1, + size_t pos2) { +#if ADA_DEVELOPMENT_CHECKS + if (pos2 < pos1) { + std::cerr << "Negative-length substring: [" << pos1 << " to " << pos2 << ")" + << std::endl; + abort(); + } +#endif + return input.substr(pos1, pos2 - pos1); +} + +/** + * @private + * Modify the string_view so that it has the new size pos, assuming that pos <= + * input.size(). This function cannot throw. + */ +ada_really_inline void resize(std::string_view& input, size_t pos) noexcept; + +/** + * @private + * Returns a host's delimiter location depending on the state of the instance, + * and whether a colon was found outside brackets. Used by the host parser. + */ +ada_really_inline std::pair get_host_delimiter_location( + bool is_special, std::string_view& view) noexcept; + +/** + * @private + * Removes leading and trailing C0 control and whitespace characters from + * string. + */ +void trim_c0_whitespace(std::string_view& input) noexcept; + +/** + * @private + * @see + * https://url.spec.whatwg.org/#potentially-strip-trailing-spaces-from-an-opaque-path + */ +template +ada_really_inline void strip_trailing_spaces_from_opaque_path(url_type& url); + +/** + * @private + * Finds the delimiter of a view in authority state. + */ +ada_really_inline size_t +find_authority_delimiter_special(std::string_view view) noexcept; + +/** + * @private + * Finds the delimiter of a view in authority state. + */ +ada_really_inline size_t +find_authority_delimiter(std::string_view view) noexcept; + +/** + * @private + */ +template +inline void inner_concat(std::string& buffer, T t) { + buffer.append(t); +} + +/** + * @private + */ +template +inline void inner_concat(std::string& buffer, T t, Args... args) { + buffer.append(t); + return inner_concat(buffer, args...); +} + +/** + * @private + * Concatenate the arguments and return a string. + * @returns a string + */ +template +std::string concat(Args... args) { + std::string answer; + inner_concat(answer, args...); + return answer; +} + +/** + * @private + * @return Number of leading zeroes. + */ +inline int leading_zeroes(uint32_t input_num) noexcept { +#if ADA_REGULAR_VISUAL_STUDIO + unsigned long leading_zero(0); + unsigned long in(input_num); + return _BitScanReverse(&leading_zero, in) ? int(31 - leading_zero) : 32; +#else + return __builtin_clz(input_num); +#endif // ADA_REGULAR_VISUAL_STUDIO +} + +/** + * @private + * Counts the number of decimal digits necessary to represent x. + * faster than std::to_string(x).size(). + * @return digit count + */ +inline int fast_digit_count(uint32_t x) noexcept { + auto int_log2 = [](uint32_t z) -> int { + return 31 - ada::helpers::leading_zeroes(z | 1); + }; + // Compiles to very few instructions. Note that the + // table is static and thus effectively a constant. + // We leave it inside the function because it is meaningless + // outside of it (this comes at no performance cost). + const static uint64_t table[] = { + 4294967296, 8589934582, 8589934582, 8589934582, 12884901788, + 12884901788, 12884901788, 17179868184, 17179868184, 17179868184, + 21474826480, 21474826480, 21474826480, 21474826480, 25769703776, + 25769703776, 25769703776, 30063771072, 30063771072, 30063771072, + 34349738368, 34349738368, 34349738368, 34349738368, 38554705664, + 38554705664, 38554705664, 41949672960, 41949672960, 41949672960, + 42949672960, 42949672960}; + return int((x + table[int_log2(x)]) >> 32); +} +} // namespace ada::helpers + +#endif // ADA_HELPERS_H +/* end file include/ada/helpers.h */ +/* begin file include/ada/parser.h */ +/** + * @file parser.h + * @brief Low-level URL parsing functions. + * + * This header provides the internal URL parsing implementation. Most users + * should use `ada::parse()` from implementation.h instead of these functions + * directly. + * + * @see implementation.h for the recommended public API + */ +#ifndef ADA_PARSER_H +#define ADA_PARSER_H + +#include +#include + +/* begin file include/ada/expected.h */ +/** + * @file expected.h + * @brief Definitions for std::expected + * @private Excluded from docs through the doxygen file. + */ +/// +// expected - An implementation of std::expected with extensions +// Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama) +// +// Documentation available at http://tl.tartanllama.xyz/ +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to the +// public domain worldwide. This software is distributed without any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. If not, see +// . +/// + +#ifndef TL_EXPECTED_HPP +#define TL_EXPECTED_HPP + +#define TL_EXPECTED_VERSION_MAJOR 1 +#define TL_EXPECTED_VERSION_MINOR 1 +#define TL_EXPECTED_VERSION_PATCH 0 + +#include +#include +#include +#include + +#if defined(__EXCEPTIONS) || defined(_CPPUNWIND) +#define TL_EXPECTED_EXCEPTIONS_ENABLED +#endif + +#if (defined(_MSC_VER) && _MSC_VER == 1900) +#define TL_EXPECTED_MSVC2015 +#define TL_EXPECTED_MSVC2015_CONSTEXPR +#else +#define TL_EXPECTED_MSVC2015_CONSTEXPR constexpr +#endif + +#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ + !defined(__clang__)) +#define TL_EXPECTED_GCC49 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \ + !defined(__clang__)) +#define TL_EXPECTED_GCC54 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \ + !defined(__clang__)) +#define TL_EXPECTED_GCC55 +#endif + +#if !defined(TL_ASSERT) +// can't have assert in constexpr in C++11 and GCC 4.9 has a compiler bug +#if (__cplusplus > 201103L) && !defined(TL_EXPECTED_GCC49) +#include +#define TL_ASSERT(x) assert(x) +#else +#define TL_ASSERT(x) +#endif +#endif + +#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ + !defined(__clang__)) +// GCC < 5 doesn't support overloading on const&& for member functions + +#define TL_EXPECTED_NO_CONSTRR +// GCC < 5 doesn't support some standard C++11 type traits +#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ + std::has_trivial_copy_constructor +#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ + std::has_trivial_copy_assign + +// This one will be different for GCC 5.7 if it's ever supported +#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \ + std::is_trivially_destructible + +// GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks +// std::vector for non-copyable types +#elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__)) +#ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX +#define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX +namespace tl { +namespace detail { +template +struct is_trivially_copy_constructible + : std::is_trivially_copy_constructible {}; +#ifdef _GLIBCXX_VECTOR +template +struct is_trivially_copy_constructible> : std::false_type {}; +#endif +} // namespace detail +} // namespace tl +#endif + +#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ + tl::detail::is_trivially_copy_constructible +#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ + std::is_trivially_copy_assignable +#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \ + std::is_trivially_destructible +#else +#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ + std::is_trivially_copy_constructible +#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ + std::is_trivially_copy_assignable +#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \ + std::is_trivially_destructible +#endif + +#if __cplusplus > 201103L +#define TL_EXPECTED_CXX14 +#endif + +#ifdef TL_EXPECTED_GCC49 +#define TL_EXPECTED_GCC49_CONSTEXPR +#else +#define TL_EXPECTED_GCC49_CONSTEXPR constexpr +#endif + +#if (__cplusplus == 201103L || defined(TL_EXPECTED_MSVC2015) || \ + defined(TL_EXPECTED_GCC49)) +#define TL_EXPECTED_11_CONSTEXPR +#else +#define TL_EXPECTED_11_CONSTEXPR constexpr +#endif + +namespace tl { +template +class expected; + +#ifndef TL_MONOSTATE_INPLACE_MUTEX +#define TL_MONOSTATE_INPLACE_MUTEX +class monostate {}; + +struct in_place_t { + explicit in_place_t() = default; +}; +static constexpr in_place_t in_place{}; +#endif + +template +class unexpected { + public: + static_assert(!std::is_same::value, "E must not be void"); + + unexpected() = delete; + constexpr explicit unexpected(const E& e) : m_val(e) {} + + constexpr explicit unexpected(E&& e) : m_val(std::move(e)) {} + + template ::value>::type* = nullptr> + constexpr explicit unexpected(Args&&... args) + : m_val(std::forward(args)...) {} + template < + class U, class... Args, + typename std::enable_if&, Args&&...>::value>::type* = nullptr> + constexpr explicit unexpected(std::initializer_list l, Args&&... args) + : m_val(l, std::forward(args)...) {} + + constexpr const E& value() const& { return m_val; } + TL_EXPECTED_11_CONSTEXPR E& value() & { return m_val; } + TL_EXPECTED_11_CONSTEXPR E&& value() && { return std::move(m_val); } + constexpr const E&& value() const&& { return std::move(m_val); } + + private: + E m_val; +}; + +#ifdef __cpp_deduction_guides +template +unexpected(E) -> unexpected; +#endif + +template +constexpr bool operator==(const unexpected& lhs, const unexpected& rhs) { + return lhs.value() == rhs.value(); +} +template +constexpr bool operator!=(const unexpected& lhs, const unexpected& rhs) { + return lhs.value() != rhs.value(); +} +template +constexpr bool operator<(const unexpected& lhs, const unexpected& rhs) { + return lhs.value() < rhs.value(); +} +template +constexpr bool operator<=(const unexpected& lhs, const unexpected& rhs) { + return lhs.value() <= rhs.value(); +} +template +constexpr bool operator>(const unexpected& lhs, const unexpected& rhs) { + return lhs.value() > rhs.value(); +} +template +constexpr bool operator>=(const unexpected& lhs, const unexpected& rhs) { + return lhs.value() >= rhs.value(); +} + +template +unexpected::type> make_unexpected(E&& e) { + return unexpected::type>(std::forward(e)); +} + +struct unexpect_t { + unexpect_t() = default; +}; +static constexpr unexpect_t unexpect{}; + +namespace detail { +template +[[noreturn]] TL_EXPECTED_11_CONSTEXPR void throw_exception(E&& e) { +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + throw std::forward(e); +#else + (void)e; +#ifdef _MSC_VER + __assume(0); +#else + __builtin_unreachable(); +#endif +#endif +} + +#ifndef TL_TRAITS_MUTEX +#define TL_TRAITS_MUTEX +// C++14-style aliases for brevity +template +using remove_const_t = typename std::remove_const::type; +template +using remove_reference_t = typename std::remove_reference::type; +template +using decay_t = typename std::decay::type; +template +using enable_if_t = typename std::enable_if::type; +template +using conditional_t = typename std::conditional::type; + +// std::conjunction from C++17 +template +struct conjunction : std::true_type {}; +template +struct conjunction : B {}; +template +struct conjunction + : std::conditional, B>::type {}; + +#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L +#define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND +#endif + +// In C++11 mode, there's an issue in libc++'s std::mem_fn +// which results in a hard-error when using it in a noexcept expression +// in some cases. This is a check to workaround the common failing case. +#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND +template +struct is_pointer_to_non_const_member_func : std::false_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; + +template +struct is_const_or_const_ref : std::false_type {}; +template +struct is_const_or_const_ref : std::true_type {}; +template +struct is_const_or_const_ref : std::true_type {}; +#endif + +// std::invoke from C++17 +// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround +template < + typename Fn, typename... Args, +#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND + typename = enable_if_t::value && + is_const_or_const_ref::value)>, +#endif + typename = enable_if_t>::value>, int = 0> +constexpr auto invoke(Fn&& f, Args&&... args) noexcept( + noexcept(std::mem_fn(f)(std::forward(args)...))) + -> decltype(std::mem_fn(f)(std::forward(args)...)) { + return std::mem_fn(f)(std::forward(args)...); +} + +template >::value>> +constexpr auto invoke(Fn&& f, Args&&... args) noexcept( + noexcept(std::forward(f)(std::forward(args)...))) + -> decltype(std::forward(f)(std::forward(args)...)) { + return std::forward(f)(std::forward(args)...); +} + +// std::invoke_result from C++17 +template +struct invoke_result_impl; + +template +struct invoke_result_impl< + F, + decltype(detail::invoke(std::declval(), std::declval()...), void()), + Us...> { + using type = + decltype(detail::invoke(std::declval(), std::declval()...)); +}; + +template +using invoke_result = invoke_result_impl; + +template +using invoke_result_t = typename invoke_result::type; + +#if defined(_MSC_VER) && _MSC_VER <= 1900 +// TODO make a version which works with MSVC 2015 +template +struct is_swappable : std::true_type {}; + +template +struct is_nothrow_swappable : std::true_type {}; +#else +// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept +namespace swap_adl_tests { +// if swap ADL finds this then it would call std::swap otherwise (same +// signature) +struct tag {}; + +template +tag swap(T&, T&); +template +tag swap(T (&a)[N], T (&b)[N]); + +// helper functions to test if an unqualified swap is possible, and if it +// becomes std::swap +template +std::false_type can_swap(...) noexcept(false); +template (), std::declval()))> +std::true_type can_swap(int) noexcept(noexcept(swap(std::declval(), + std::declval()))); + +template +std::false_type uses_std(...); +template +std::is_same(), std::declval())), tag> +uses_std(int); + +template +struct is_std_swap_noexcept + : std::integral_constant::value && + std::is_nothrow_move_assignable::value> {}; + +template +struct is_std_swap_noexcept : is_std_swap_noexcept {}; + +template +struct is_adl_swap_noexcept + : std::integral_constant(0))> {}; +} // namespace swap_adl_tests + +template +struct is_swappable + : std::integral_constant< + bool, + decltype(detail::swap_adl_tests::can_swap(0))::value && + (!decltype(detail::swap_adl_tests::uses_std(0))::value || + (std::is_move_assignable::value && + std::is_move_constructible::value))> {}; + +template +struct is_swappable + : std::integral_constant< + bool, + decltype(detail::swap_adl_tests::can_swap(0))::value && + (!decltype(detail::swap_adl_tests::uses_std( + 0))::value || + is_swappable::value)> {}; + +template +struct is_nothrow_swappable + : std::integral_constant< + bool, + is_swappable::value && + ((decltype(detail::swap_adl_tests::uses_std(0))::value && + detail::swap_adl_tests::is_std_swap_noexcept::value) || + (!decltype(detail::swap_adl_tests::uses_std(0))::value && + detail::swap_adl_tests::is_adl_swap_noexcept::value))> {}; +#endif +#endif + +// Trait for checking if a type is a tl::expected +template +struct is_expected_impl : std::false_type {}; +template +struct is_expected_impl> : std::true_type {}; +template +using is_expected = is_expected_impl>; + +template +using expected_enable_forward_value = detail::enable_if_t< + std::is_constructible::value && + !std::is_same, in_place_t>::value && + !std::is_same, detail::decay_t>::value && + !std::is_same, detail::decay_t>::value>; + +template +using expected_enable_from_other = detail::enable_if_t< + std::is_constructible::value && + std::is_constructible::value && + !std::is_constructible&>::value && + !std::is_constructible&&>::value && + !std::is_constructible&>::value && + !std::is_constructible&&>::value && + !std::is_convertible&, T>::value && + !std::is_convertible&&, T>::value && + !std::is_convertible&, T>::value && + !std::is_convertible&&, T>::value>; + +template +using is_void_or = conditional_t::value, std::true_type, U>; + +template +using is_copy_constructible_or_void = + is_void_or>; + +template +using is_move_constructible_or_void = + is_void_or>; + +template +using is_copy_assignable_or_void = is_void_or>; + +template +using is_move_assignable_or_void = is_void_or>; + +} // namespace detail + +namespace detail { +struct no_init_t {}; +static constexpr no_init_t no_init{}; + +// Implements the storage of the values, and ensures that the destructor is +// trivial if it can be. +// +// This specialization is for where neither `T` or `E` is trivially +// destructible, so the destructors must be called on destruction of the +// `expected` +template ::value, + bool = std::is_trivially_destructible::value> +struct expected_storage_base { + constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} + + template ::value>* = + nullptr> + constexpr expected_storage_base(in_place_t, Args&&... args) + : m_val(std::forward(args)...), m_has_val(true) {} + + template &, Args&&...>::value>* = nullptr> + constexpr expected_storage_base(in_place_t, std::initializer_list il, + Args&&... args) + : m_val(il, std::forward(args)...), m_has_val(true) {} + template ::value>* = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args&&... args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args&&...>::value>* = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args&&... args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + ~expected_storage_base() { + if (m_has_val) { + m_val.~T(); + } else { + m_unexpect.~unexpected(); + } + } + union { + T m_val; + unexpected m_unexpect; + char m_no_init; + }; + bool m_has_val; +}; + +// This specialization is for when both `T` and `E` are trivially-destructible, +// so the destructor of the `expected` can be trivial. +template +struct expected_storage_base { + constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} + + template ::value>* = + nullptr> + constexpr expected_storage_base(in_place_t, Args&&... args) + : m_val(std::forward(args)...), m_has_val(true) {} + + template &, Args&&...>::value>* = nullptr> + constexpr expected_storage_base(in_place_t, std::initializer_list il, + Args&&... args) + : m_val(il, std::forward(args)...), m_has_val(true) {} + template ::value>* = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args&&... args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args&&...>::value>* = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args&&... args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + ~expected_storage_base() = default; + union { + T m_val; + unexpected m_unexpect; + char m_no_init; + }; + bool m_has_val; +}; + +// T is trivial, E is not. +template +struct expected_storage_base { + constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t) + : m_no_init(), m_has_val(false) {} + + template ::value>* = + nullptr> + constexpr expected_storage_base(in_place_t, Args&&... args) + : m_val(std::forward(args)...), m_has_val(true) {} + + template &, Args&&...>::value>* = nullptr> + constexpr expected_storage_base(in_place_t, std::initializer_list il, + Args&&... args) + : m_val(il, std::forward(args)...), m_has_val(true) {} + template ::value>* = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args&&... args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args&&...>::value>* = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args&&... args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + ~expected_storage_base() { + if (!m_has_val) { + m_unexpect.~unexpected(); + } + } + + union { + T m_val; + unexpected m_unexpect; + char m_no_init; + }; + bool m_has_val; +}; + +// E is trivial, T is not. +template +struct expected_storage_base { + constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} + + template ::value>* = + nullptr> + constexpr expected_storage_base(in_place_t, Args&&... args) + : m_val(std::forward(args)...), m_has_val(true) {} + + template &, Args&&...>::value>* = nullptr> + constexpr expected_storage_base(in_place_t, std::initializer_list il, + Args&&... args) + : m_val(il, std::forward(args)...), m_has_val(true) {} + template ::value>* = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args&&... args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args&&...>::value>* = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args&&... args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + ~expected_storage_base() { + if (m_has_val) { + m_val.~T(); + } + } + union { + T m_val; + unexpected m_unexpect; + char m_no_init; + }; + bool m_has_val; +}; + +// `T` is `void`, `E` is trivially-destructible +template +struct expected_storage_base { +#if __GNUC__ <= 5 +// no constexpr for GCC 4/5 bug +#else + TL_EXPECTED_MSVC2015_CONSTEXPR +#endif + expected_storage_base() : m_has_val(true) {} + + constexpr expected_storage_base(no_init_t) : m_val(), m_has_val(false) {} + + constexpr expected_storage_base(in_place_t) : m_has_val(true) {} + + template ::value>* = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args&&... args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args&&...>::value>* = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args&&... args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + ~expected_storage_base() = default; + struct dummy {}; + union { + unexpected m_unexpect; + dummy m_val; + }; + bool m_has_val; +}; + +// `T` is `void`, `E` is not trivially-destructible +template +struct expected_storage_base { + constexpr expected_storage_base() : m_dummy(), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_dummy(), m_has_val(false) {} + + constexpr expected_storage_base(in_place_t) : m_dummy(), m_has_val(true) {} + + template ::value>* = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args&&... args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args&&...>::value>* = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args&&... args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + ~expected_storage_base() { + if (!m_has_val) { + m_unexpect.~unexpected(); + } + } + + union { + unexpected m_unexpect; + char m_dummy; + }; + bool m_has_val; +}; + +// This base class provides some handy member functions which can be used in +// further derived classes +template +struct expected_operations_base : expected_storage_base { + using expected_storage_base::expected_storage_base; + + template + void construct(Args&&... args) noexcept { + new (std::addressof(this->m_val)) T(std::forward(args)...); + this->m_has_val = true; + } + + template + // NOLINTNEXTLINE(bugprone-exception-escape) + void construct_with(Rhs&& rhs) noexcept { + new (std::addressof(this->m_val)) T(std::forward(rhs).get()); + this->m_has_val = true; + } + + template + void construct_error(Args&&... args) noexcept { + new (std::addressof(this->m_unexpect)) + unexpected(std::forward(args)...); + this->m_has_val = false; + } + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + + // These assign overloads ensure that the most efficient assignment + // implementation is used while maintaining the strong exception guarantee. + // The problematic case is where rhs has a value, but *this does not. + // + // This overload handles the case where we can just copy-construct `T` + // directly into place without throwing. + template ::value>* = + nullptr> + void assign(const expected_operations_base& rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected(); + construct(rhs.get()); + } else { + assign_common(rhs); + } + } + + // This overload handles the case where we can attempt to create a copy of + // `T`, then no-throw move it into place if the copy was successful. + template ::value && + std::is_nothrow_move_constructible::value>* = + nullptr> + void assign(const expected_operations_base& rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + T tmp = rhs.get(); + geterr().~unexpected(); + construct(std::move(tmp)); + } else { + assign_common(rhs); + } + } + + // This overload is the worst-case, where we have to move-construct the + // unexpected value into temporary storage, then try to copy the T into place. + // If the construction succeeds, then everything is fine, but if it throws, + // then we move the old unexpected value back into place before rethrowing the + // exception. + template ::value && + !std::is_nothrow_move_constructible::value>* = nullptr> + void assign(const expected_operations_base& rhs) { + if (!this->m_has_val && rhs.m_has_val) { + auto tmp = std::move(geterr()); + geterr().~unexpected(); + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + construct(rhs.get()); + } catch (...) { + geterr() = std::move(tmp); + throw; + } +#else + construct(rhs.get()); +#endif + } else { + assign_common(rhs); + } + } + + // These overloads do the same as above, but for rvalues + template ::value>* = + nullptr> + void assign(expected_operations_base&& rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected(); + construct(std::move(rhs).get()); + } else { + assign_common(std::move(rhs)); + } + } + + template ::value>* = nullptr> + void assign(expected_operations_base&& rhs) { + if (!this->m_has_val && rhs.m_has_val) { + auto tmp = std::move(geterr()); + geterr().~unexpected(); +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + construct(std::move(rhs).get()); + } catch (...) { + geterr() = std::move(tmp); + throw; + } +#else + construct(std::move(rhs).get()); +#endif + } else { + assign_common(std::move(rhs)); + } + } + +#else + + // If exceptions are disabled then we can just copy-construct + void assign(const expected_operations_base& rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected(); + construct(rhs.get()); + } else { + assign_common(rhs); + } + } + + void assign(expected_operations_base&& rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected(); + construct(std::move(rhs).get()); + } else { + assign_common(std::move(rhs)); + } + } + +#endif + + // The common part of move/copy assigning + template + void assign_common(Rhs&& rhs) { + if (this->m_has_val) { + if (rhs.m_has_val) { + get() = std::forward(rhs).get(); + } else { + destroy_val(); + construct_error(std::forward(rhs).geterr()); + } + } else { + if (!rhs.m_has_val) { + geterr() = std::forward(rhs).geterr(); + } + } + } + + bool has_value() const { return this->m_has_val; } + + TL_EXPECTED_11_CONSTEXPR T& get() & { return this->m_val; } + constexpr const T& get() const& { return this->m_val; } + TL_EXPECTED_11_CONSTEXPR T&& get() && { return std::move(this->m_val); } +#ifndef TL_EXPECTED_NO_CONSTRR + constexpr const T&& get() const&& { return std::move(this->m_val); } +#endif + + TL_EXPECTED_11_CONSTEXPR unexpected& geterr() & { + return this->m_unexpect; + } + constexpr const unexpected& geterr() const& { return this->m_unexpect; } + TL_EXPECTED_11_CONSTEXPR unexpected&& geterr() && { + return std::move(this->m_unexpect); + } +#ifndef TL_EXPECTED_NO_CONSTRR + constexpr const unexpected&& geterr() const&& { + return std::move(this->m_unexpect); + } +#endif + + TL_EXPECTED_11_CONSTEXPR void destroy_val() { get().~T(); } +}; + +// This base class provides some handy member functions which can be used in +// further derived classes +template +struct expected_operations_base : expected_storage_base { + using expected_storage_base::expected_storage_base; + + template + void construct() noexcept { + this->m_has_val = true; + } + + // This function doesn't use its argument, but needs it so that code in + // levels above this can work independently of whether T is void + template + void construct_with(Rhs&&) noexcept { + this->m_has_val = true; + } + + template + void construct_error(Args&&... args) noexcept { + new (std::addressof(this->m_unexpect)) + unexpected(std::forward(args)...); + this->m_has_val = false; + } + + template + void assign(Rhs&& rhs) noexcept { + if (!this->m_has_val) { + if (rhs.m_has_val) { + geterr().~unexpected(); + construct(); + } else { + geterr() = std::forward(rhs).geterr(); + } + } else { + if (!rhs.m_has_val) { + construct_error(std::forward(rhs).geterr()); + } + } + } + + bool has_value() const { return this->m_has_val; } + + TL_EXPECTED_11_CONSTEXPR unexpected& geterr() & { + return this->m_unexpect; + } + constexpr const unexpected& geterr() const& { return this->m_unexpect; } + TL_EXPECTED_11_CONSTEXPR unexpected&& geterr() && { + return std::move(this->m_unexpect); + } +#ifndef TL_EXPECTED_NO_CONSTRR + constexpr const unexpected&& geterr() const&& { + return std::move(this->m_unexpect); + } +#endif + + TL_EXPECTED_11_CONSTEXPR void destroy_val() { + // no-op + } +}; + +// This class manages conditionally having a trivial copy constructor +// This specialization is for when T and E are trivially copy constructible +template ::value && + TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value> +struct expected_copy_base : expected_operations_base { + using expected_operations_base::expected_operations_base; +}; + +// This specialization is for when T or E are not trivially copy constructible +template +struct expected_copy_base : expected_operations_base { + using expected_operations_base::expected_operations_base; + + expected_copy_base() = default; + expected_copy_base(const expected_copy_base& rhs) + : expected_operations_base(no_init) { + if (rhs.has_value()) { + this->construct_with(rhs); + } else { + this->construct_error(rhs.geterr()); + } + } + + expected_copy_base(expected_copy_base&& rhs) = default; + expected_copy_base& operator=(const expected_copy_base& rhs) = default; + expected_copy_base& operator=(expected_copy_base&& rhs) = default; +}; + +// This class manages conditionally having a trivial move constructor +// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it +// doesn't implement an analogue to std::is_trivially_move_constructible. We +// have to make do with a non-trivial move constructor even if T is trivially +// move constructible +#ifndef TL_EXPECTED_GCC49 +template >::value && + std::is_trivially_move_constructible::value> +struct expected_move_base : expected_copy_base { + using expected_copy_base::expected_copy_base; +}; +#else +template +struct expected_move_base; +#endif +template +struct expected_move_base : expected_copy_base { + using expected_copy_base::expected_copy_base; + + expected_move_base() = default; + expected_move_base(const expected_move_base& rhs) = default; + + expected_move_base(expected_move_base&& rhs) noexcept( + std::is_nothrow_move_constructible::value) + : expected_copy_base(no_init) { + if (rhs.has_value()) { + this->construct_with(std::move(rhs)); + } else { + this->construct_error(std::move(rhs.geterr())); + } + } + expected_move_base& operator=(const expected_move_base& rhs) = default; + expected_move_base& operator=(expected_move_base&& rhs) = default; +}; + +// This class manages conditionally having a trivial copy assignment operator +template < + class T, class E, + bool = + is_void_or< + T, conjunction>::value && + TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(E)::value && + TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value && + TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(E)::value> +struct expected_copy_assign_base : expected_move_base { + using expected_move_base::expected_move_base; +}; + +template +struct expected_copy_assign_base : expected_move_base { + using expected_move_base::expected_move_base; + + expected_copy_assign_base() = default; + expected_copy_assign_base(const expected_copy_assign_base& rhs) = default; + + expected_copy_assign_base(expected_copy_assign_base&& rhs) = default; + expected_copy_assign_base& operator=(const expected_copy_assign_base& rhs) { + this->assign(rhs); + return *this; + } + expected_copy_assign_base& operator=(expected_copy_assign_base&& rhs) = + default; +}; + +// This class manages conditionally having a trivial move assignment operator +// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it +// doesn't implement an analogue to std::is_trivially_move_assignable. We have +// to make do with a non-trivial move assignment operator even if T is trivially +// move assignable +#ifndef TL_EXPECTED_GCC49 +template < + class T, class E, + bool = is_void_or< + T, conjunction, + std::is_trivially_move_constructible, + std::is_trivially_move_assignable>>::value && + std::is_trivially_destructible::value && + std::is_trivially_move_constructible::value && + std::is_trivially_move_assignable::value> +struct expected_move_assign_base : expected_copy_assign_base { + using expected_copy_assign_base::expected_copy_assign_base; +}; +#else +template +struct expected_move_assign_base; +#endif + +template +struct expected_move_assign_base + : expected_copy_assign_base { + using expected_copy_assign_base::expected_copy_assign_base; + + expected_move_assign_base() = default; + expected_move_assign_base(const expected_move_assign_base& rhs) = default; + + expected_move_assign_base(expected_move_assign_base&& rhs) = default; + + expected_move_assign_base& operator=(const expected_move_assign_base& rhs) = + default; + + expected_move_assign_base& + operator=(expected_move_assign_base&& rhs) noexcept( + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_assignable::value) { + this->assign(std::move(rhs)); + return *this; + } +}; + +// expected_delete_ctor_base will conditionally delete copy and move +// constructors depending on whether T is copy/move constructible +template ::value && + std::is_copy_constructible::value), + bool EnableMove = (is_move_constructible_or_void::value && + std::is_move_constructible::value)> +struct expected_delete_ctor_base { + expected_delete_ctor_base() = default; + expected_delete_ctor_base(const expected_delete_ctor_base&) = default; + expected_delete_ctor_base(expected_delete_ctor_base&&) noexcept = default; + expected_delete_ctor_base& operator=(const expected_delete_ctor_base&) = + default; + expected_delete_ctor_base& operator=(expected_delete_ctor_base&&) noexcept = + default; +}; + +template +struct expected_delete_ctor_base { + expected_delete_ctor_base() = default; + expected_delete_ctor_base(const expected_delete_ctor_base&) = default; + expected_delete_ctor_base(expected_delete_ctor_base&&) noexcept = delete; + expected_delete_ctor_base& operator=(const expected_delete_ctor_base&) = + default; + expected_delete_ctor_base& operator=(expected_delete_ctor_base&&) noexcept = + default; +}; + +template +struct expected_delete_ctor_base { + expected_delete_ctor_base() = default; + expected_delete_ctor_base(const expected_delete_ctor_base&) = delete; + expected_delete_ctor_base(expected_delete_ctor_base&&) noexcept = default; + expected_delete_ctor_base& operator=(const expected_delete_ctor_base&) = + default; + expected_delete_ctor_base& operator=(expected_delete_ctor_base&&) noexcept = + default; +}; + +template +struct expected_delete_ctor_base { + expected_delete_ctor_base() = default; + expected_delete_ctor_base(const expected_delete_ctor_base&) = delete; + expected_delete_ctor_base(expected_delete_ctor_base&&) noexcept = delete; + expected_delete_ctor_base& operator=(const expected_delete_ctor_base&) = + default; + expected_delete_ctor_base& operator=(expected_delete_ctor_base&&) noexcept = + default; +}; + +// expected_delete_assign_base will conditionally delete copy and move +// constructors depending on whether T and E are copy/move constructible + +// assignable +template ::value && + std::is_copy_constructible::value && + is_copy_assignable_or_void::value && + std::is_copy_assignable::value), + bool EnableMove = (is_move_constructible_or_void::value && + std::is_move_constructible::value && + is_move_assignable_or_void::value && + std::is_move_assignable::value)> +struct expected_delete_assign_base { + expected_delete_assign_base() = default; + expected_delete_assign_base(const expected_delete_assign_base&) = default; + expected_delete_assign_base(expected_delete_assign_base&&) noexcept = default; + expected_delete_assign_base& operator=(const expected_delete_assign_base&) = + default; + expected_delete_assign_base& operator=( + expected_delete_assign_base&&) noexcept = default; +}; + +template +struct expected_delete_assign_base { + expected_delete_assign_base() = default; + expected_delete_assign_base(const expected_delete_assign_base&) = default; + expected_delete_assign_base(expected_delete_assign_base&&) noexcept = default; + expected_delete_assign_base& operator=(const expected_delete_assign_base&) = + default; + expected_delete_assign_base& operator=( + expected_delete_assign_base&&) noexcept = delete; +}; + +template +struct expected_delete_assign_base { + expected_delete_assign_base() = default; + expected_delete_assign_base(const expected_delete_assign_base&) = default; + expected_delete_assign_base(expected_delete_assign_base&&) noexcept = default; + expected_delete_assign_base& operator=(const expected_delete_assign_base&) = + delete; + expected_delete_assign_base& operator=( + expected_delete_assign_base&&) noexcept = default; +}; + +template +struct expected_delete_assign_base { + expected_delete_assign_base() = default; + expected_delete_assign_base(const expected_delete_assign_base&) = default; + expected_delete_assign_base(expected_delete_assign_base&&) noexcept = default; + expected_delete_assign_base& operator=(const expected_delete_assign_base&) = + delete; + expected_delete_assign_base& operator=( + expected_delete_assign_base&&) noexcept = delete; +}; + +// This is needed to be able to construct the expected_default_ctor_base which +// follows, while still conditionally deleting the default constructor. +struct default_constructor_tag { + explicit constexpr default_constructor_tag() = default; +}; + +// expected_default_ctor_base will ensure that expected has a deleted default +// consturctor if T is not default constructible. +// This specialization is for when T is default constructible +template ::value || std::is_void::value> +struct expected_default_ctor_base { + constexpr expected_default_ctor_base() noexcept = default; + constexpr expected_default_ctor_base( + expected_default_ctor_base const&) noexcept = default; + constexpr expected_default_ctor_base(expected_default_ctor_base&&) noexcept = + default; + expected_default_ctor_base& operator=( + expected_default_ctor_base const&) noexcept = default; + expected_default_ctor_base& operator=(expected_default_ctor_base&&) noexcept = + default; + + constexpr explicit expected_default_ctor_base(default_constructor_tag) {} +}; + +// This specialization is for when T is not default constructible +template +struct expected_default_ctor_base { + constexpr expected_default_ctor_base() noexcept = delete; + constexpr expected_default_ctor_base( + expected_default_ctor_base const&) noexcept = default; + constexpr expected_default_ctor_base(expected_default_ctor_base&&) noexcept = + default; + expected_default_ctor_base& operator=( + expected_default_ctor_base const&) noexcept = default; + expected_default_ctor_base& operator=(expected_default_ctor_base&&) noexcept = + default; + + constexpr explicit expected_default_ctor_base(default_constructor_tag) {} +}; +} // namespace detail + +template +class bad_expected_access : public std::exception { + public: + explicit bad_expected_access(E e) : m_val(std::move(e)) {} + + virtual const char* what() const noexcept override { + return "Bad expected access"; + } + + const E& error() const& { return m_val; } + E& error() & { return m_val; } + const E&& error() const&& { return std::move(m_val); } + E&& error() && { return std::move(m_val); } + + private: + E m_val; +}; + +/// An `expected` object is an object that contains the storage for +/// another object and manages the lifetime of this contained object `T`. +/// Alternatively it could contain the storage for another unexpected object +/// `E`. The contained object may not be initialized after the expected object +/// has been initialized, and may not be destroyed before the expected object +/// has been destroyed. The initialization state of the contained object is +/// tracked by the expected object. +template +class expected : private detail::expected_move_assign_base, + private detail::expected_delete_ctor_base, + private detail::expected_delete_assign_base, + private detail::expected_default_ctor_base { + static_assert(!std::is_reference::value, "T must not be a reference"); + static_assert(!std::is_same::type>::value, + "T must not be in_place_t"); + static_assert(!std::is_same::type>::value, + "T must not be unexpect_t"); + static_assert( + !std::is_same>::type>::value, + "T must not be unexpected"); + static_assert(!std::is_reference::value, "E must not be a reference"); + + T* valptr() { return std::addressof(this->m_val); } + const T* valptr() const { return std::addressof(this->m_val); } + unexpected* errptr() { return std::addressof(this->m_unexpect); } + const unexpected* errptr() const { + return std::addressof(this->m_unexpect); + } + + template ::value>* = nullptr> + TL_EXPECTED_11_CONSTEXPR U& val() { + return this->m_val; + } + TL_EXPECTED_11_CONSTEXPR unexpected& err() { return this->m_unexpect; } + + template ::value>* = nullptr> + constexpr const U& val() const { + return this->m_val; + } + constexpr const unexpected& err() const { return this->m_unexpect; } + + using impl_base = detail::expected_move_assign_base; + using ctor_base = detail::expected_default_ctor_base; + + public: + typedef T value_type; + typedef E error_type; + typedef unexpected unexpected_type; + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template + TL_EXPECTED_11_CONSTEXPR auto and_then(F&& f) & { + return and_then_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR auto and_then(F&& f) && { + return and_then_impl(std::move(*this), std::forward(f)); + } + template + constexpr auto and_then(F&& f) const& { + return and_then_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + constexpr auto and_then(F&& f) const&& { + return and_then_impl(std::move(*this), std::forward(f)); + } +#endif + +#else + template + TL_EXPECTED_11_CONSTEXPR auto and_then(F&& f) & -> decltype(and_then_impl( + std::declval(), std::forward(f))) { + return and_then_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR auto and_then(F&& f) && -> decltype(and_then_impl( + std::declval(), std::forward(f))) { + return and_then_impl(std::move(*this), std::forward(f)); + } + template + constexpr auto and_then(F&& f) const& -> decltype(and_then_impl( + std::declval(), std::forward(f))) { + return and_then_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + constexpr auto and_then(F&& f) const&& -> decltype(and_then_impl( + std::declval(), std::forward(f))) { + return and_then_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template + TL_EXPECTED_11_CONSTEXPR auto map(F&& f) & { + return expected_map_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR auto map(F&& f) && { + return expected_map_impl(std::move(*this), std::forward(f)); + } + template + constexpr auto map(F&& f) const& { + return expected_map_impl(*this, std::forward(f)); + } + template + constexpr auto map(F&& f) const&& { + return expected_map_impl(std::move(*this), std::forward(f)); + } +#else + template + TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl( + std::declval(), std::declval())) map(F&& f) & { + return expected_map_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval(), + std::declval())) + map(F&& f) && { + return expected_map_impl(std::move(*this), std::forward(f)); + } + template + constexpr decltype(expected_map_impl(std::declval(), + std::declval())) + map(F&& f) const& { + return expected_map_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + constexpr decltype(expected_map_impl(std::declval(), + std::declval())) map(F&& f) + const&& { + return expected_map_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template + TL_EXPECTED_11_CONSTEXPR auto transform(F&& f) & { + return expected_map_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR auto transform(F&& f) && { + return expected_map_impl(std::move(*this), std::forward(f)); + } + template + constexpr auto transform(F&& f) const& { + return expected_map_impl(*this, std::forward(f)); + } + template + constexpr auto transform(F&& f) const&& { + return expected_map_impl(std::move(*this), std::forward(f)); + } +#else + template + TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl( + std::declval(), std::declval())) transform(F&& f) & { + return expected_map_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval(), + std::declval())) + transform(F&& f) && { + return expected_map_impl(std::move(*this), std::forward(f)); + } + template + constexpr decltype(expected_map_impl(std::declval(), + std::declval())) + transform(F&& f) const& { + return expected_map_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + constexpr decltype(expected_map_impl(std::declval(), + std::declval())) transform(F&& f) + const&& { + return expected_map_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template + TL_EXPECTED_11_CONSTEXPR auto map_error(F&& f) & { + return map_error_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR auto map_error(F&& f) && { + return map_error_impl(std::move(*this), std::forward(f)); + } + template + constexpr auto map_error(F&& f) const& { + return map_error_impl(*this, std::forward(f)); + } + template + constexpr auto map_error(F&& f) const&& { + return map_error_impl(std::move(*this), std::forward(f)); + } +#else + template + TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl( + std::declval(), std::declval())) map_error(F&& f) & { + return map_error_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval(), + std::declval())) + map_error(F&& f) && { + return map_error_impl(std::move(*this), std::forward(f)); + } + template + constexpr decltype(map_error_impl(std::declval(), + std::declval())) + map_error(F&& f) const& { + return map_error_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + constexpr decltype(map_error_impl(std::declval(), + std::declval())) map_error(F&& f) + const&& { + return map_error_impl(std::move(*this), std::forward(f)); + } +#endif +#endif +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template + TL_EXPECTED_11_CONSTEXPR auto transform_error(F&& f) & { + return map_error_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR auto transform_error(F&& f) && { + return map_error_impl(std::move(*this), std::forward(f)); + } + template + constexpr auto transform_error(F&& f) const& { + return map_error_impl(*this, std::forward(f)); + } + template + constexpr auto transform_error(F&& f) const&& { + return map_error_impl(std::move(*this), std::forward(f)); + } +#else + template + TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl( + std::declval(), + std::declval())) transform_error(F&& f) & { + return map_error_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval(), + std::declval())) + transform_error(F&& f) && { + return map_error_impl(std::move(*this), std::forward(f)); + } + template + constexpr decltype(map_error_impl(std::declval(), + std::declval())) + transform_error(F&& f) const& { + return map_error_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + constexpr decltype(map_error_impl(std::declval(), + std::declval())) transform_error(F&& f) + const&& { + return map_error_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + template + expected TL_EXPECTED_11_CONSTEXPR or_else(F&& f) & { + return or_else_impl(*this, std::forward(f)); + } + + template + expected TL_EXPECTED_11_CONSTEXPR or_else(F&& f) && { + return or_else_impl(std::move(*this), std::forward(f)); + } + + template + expected constexpr or_else(F&& f) const& { + return or_else_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + expected constexpr or_else(F&& f) const&& { + return or_else_impl(std::move(*this), std::forward(f)); + } +#endif + constexpr expected() = default; + constexpr expected(const expected& rhs) = default; + constexpr expected(expected&& rhs) = default; + expected& operator=(const expected& rhs) = default; + expected& operator=(expected&& rhs) = default; + + template ::value>* = + nullptr> + constexpr expected(in_place_t, Args&&... args) + : impl_base(in_place, std::forward(args)...), + ctor_base(detail::default_constructor_tag{}) {} + + template &, Args&&...>::value>* = nullptr> + constexpr expected(in_place_t, std::initializer_list il, Args&&... args) + : impl_base(in_place, il, std::forward(args)...), + ctor_base(detail::default_constructor_tag{}) {} + + template < + class G = E, + detail::enable_if_t::value>* = nullptr, + detail::enable_if_t::value>* = nullptr> + explicit constexpr expected(const unexpected& e) + : impl_base(unexpect, e.value()), + ctor_base(detail::default_constructor_tag{}) {} + + template < + class G = E, + detail::enable_if_t::value>* = nullptr, + detail::enable_if_t::value>* = nullptr> + constexpr expected(unexpected const& e) + : impl_base(unexpect, e.value()), + ctor_base(detail::default_constructor_tag{}) {} + + template < + class G = E, + detail::enable_if_t::value>* = nullptr, + detail::enable_if_t::value>* = nullptr> + explicit constexpr expected(unexpected&& e) noexcept( + std::is_nothrow_constructible::value) + : impl_base(unexpect, std::move(e.value())), + ctor_base(detail::default_constructor_tag{}) {} + + template < + class G = E, + detail::enable_if_t::value>* = nullptr, + detail::enable_if_t::value>* = nullptr> + constexpr expected(unexpected&& e) noexcept( + std::is_nothrow_constructible::value) + : impl_base(unexpect, std::move(e.value())), + ctor_base(detail::default_constructor_tag{}) {} + + template ::value>* = + nullptr> + constexpr explicit expected(unexpect_t, Args&&... args) + : impl_base(unexpect, std::forward(args)...), + ctor_base(detail::default_constructor_tag{}) {} + + template &, Args&&...>::value>* = nullptr> + constexpr explicit expected(unexpect_t, std::initializer_list il, + Args&&... args) + : impl_base(unexpect, il, std::forward(args)...), + ctor_base(detail::default_constructor_tag{}) {} + + template ::value && + std::is_convertible::value)>* = + nullptr, + detail::expected_enable_from_other* = nullptr> + explicit TL_EXPECTED_11_CONSTEXPR expected(const expected& rhs) + : ctor_base(detail::default_constructor_tag{}) { + if (rhs.has_value()) { + this->construct(*rhs); + } else { + this->construct_error(rhs.error()); + } + } + + template < + class U, class G, + detail::enable_if_t<(std::is_convertible::value && + std::is_convertible::value)>* = nullptr, + detail::expected_enable_from_other* = + nullptr> + TL_EXPECTED_11_CONSTEXPR expected(const expected& rhs) + : ctor_base(detail::default_constructor_tag{}) { + if (rhs.has_value()) { + this->construct(*rhs); + } else { + this->construct_error(rhs.error()); + } + } + + template < + class U, class G, + detail::enable_if_t::value && + std::is_convertible::value)>* = nullptr, + detail::expected_enable_from_other* = nullptr> + explicit TL_EXPECTED_11_CONSTEXPR expected(expected&& rhs) + : ctor_base(detail::default_constructor_tag{}) { + if (rhs.has_value()) { + this->construct(std::move(*rhs)); + } else { + this->construct_error(std::move(rhs.error())); + } + } + + template < + class U, class G, + detail::enable_if_t<(std::is_convertible::value && + std::is_convertible::value)>* = nullptr, + detail::expected_enable_from_other* = nullptr> + TL_EXPECTED_11_CONSTEXPR expected(expected&& rhs) + : ctor_base(detail::default_constructor_tag{}) { + if (rhs.has_value()) { + this->construct(std::move(*rhs)); + } else { + this->construct_error(std::move(rhs.error())); + } + } + + template ::value>* = nullptr, + detail::expected_enable_forward_value* = nullptr> + explicit TL_EXPECTED_MSVC2015_CONSTEXPR expected(U&& v) + : expected(in_place, std::forward(v)) {} + + template ::value>* = nullptr, + detail::expected_enable_forward_value* = nullptr> + TL_EXPECTED_MSVC2015_CONSTEXPR expected(U&& v) + : expected(in_place, std::forward(v)) {} + + template < + class U = T, class G = T, + detail::enable_if_t::value>* = + nullptr, + detail::enable_if_t::value>* = nullptr, + detail::enable_if_t< + (!std::is_same, detail::decay_t>::value && + !detail::conjunction, + std::is_same>>::value && + std::is_constructible::value && + std::is_assignable::value && + std::is_nothrow_move_constructible::value)>* = nullptr> + expected& operator=(U&& v) { + if (has_value()) { + val() = std::forward(v); + } else { + err().~unexpected(); + ::new (valptr()) T(std::forward(v)); + this->m_has_val = true; + } + + return *this; + } + + template < + class U = T, class G = T, + detail::enable_if_t::value>* = + nullptr, + detail::enable_if_t::value>* = nullptr, + detail::enable_if_t< + (!std::is_same, detail::decay_t>::value && + !detail::conjunction, + std::is_same>>::value && + std::is_constructible::value && + std::is_assignable::value && + std::is_nothrow_move_constructible::value)>* = nullptr> + expected& operator=(U&& v) { + if (has_value()) { + val() = std::forward(v); + } else { + auto tmp = std::move(err()); + err().~unexpected(); + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (valptr()) T(std::forward(v)); + this->m_has_val = true; + } catch (...) { + err() = std::move(tmp); + throw; + } +#else + ::new (valptr()) T(std::forward(v)); + this->m_has_val = true; +#endif + } + + return *this; + } + + template ::value && + std::is_assignable::value>* = nullptr> + expected& operator=(const unexpected& rhs) { + if (!has_value()) { + err() = rhs; + } else { + this->destroy_val(); + ::new (errptr()) unexpected(rhs); + this->m_has_val = false; + } + + return *this; + } + + template ::value && + std::is_move_assignable::value>* = nullptr> + expected& operator=(unexpected&& rhs) noexcept { + if (!has_value()) { + err() = std::move(rhs); + } else { + this->destroy_val(); + ::new (errptr()) unexpected(std::move(rhs)); + this->m_has_val = false; + } + + return *this; + } + + template ::value>* = nullptr> + void emplace(Args&&... args) { + if (has_value()) { + val().~T(); + } else { + err().~unexpected(); + this->m_has_val = true; + } + ::new (valptr()) T(std::forward(args)...); + } + + template ::value>* = nullptr> + void emplace(Args&&... args) { + if (has_value()) { + val().~T(); + ::new (valptr()) T(std::forward(args)...); + } else { + auto tmp = std::move(err()); + err().~unexpected(); + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (valptr()) T(std::forward(args)...); + this->m_has_val = true; + } catch (...) { + err() = std::move(tmp); + throw; + } +#else + ::new (valptr()) T(std::forward(args)...); + this->m_has_val = true; +#endif + } + } + + template &, Args&&...>::value>* = nullptr> + void emplace(std::initializer_list il, Args&&... args) { + if (has_value()) { + T t(il, std::forward(args)...); + val() = std::move(t); + } else { + err().~unexpected(); + ::new (valptr()) T(il, std::forward(args)...); + this->m_has_val = true; + } + } + + template &, Args&&...>::value>* = nullptr> + void emplace(std::initializer_list il, Args&&... args) { + if (has_value()) { + T t(il, std::forward(args)...); + val() = std::move(t); + } else { + auto tmp = std::move(err()); + err().~unexpected(); + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (valptr()) T(il, std::forward(args)...); + this->m_has_val = true; + } catch (...) { + err() = std::move(tmp); + throw; + } +#else + ::new (valptr()) T(il, std::forward(args)...); + this->m_has_val = true; +#endif + } + } + + private: + using t_is_void = std::true_type; + using t_is_not_void = std::false_type; + using t_is_nothrow_move_constructible = std::true_type; + using move_constructing_t_can_throw = std::false_type; + using e_is_nothrow_move_constructible = std::true_type; + using move_constructing_e_can_throw = std::false_type; + + void swap_where_both_have_value(expected& /*rhs*/, t_is_void) noexcept { + // swapping void is a no-op + } + + void swap_where_both_have_value(expected& rhs, t_is_not_void) { + using std::swap; + swap(val(), rhs.val()); + } + + void swap_where_only_one_has_value(expected& rhs, t_is_void) noexcept( + std::is_nothrow_move_constructible::value) { + ::new (errptr()) unexpected_type(std::move(rhs.err())); + rhs.err().~unexpected_type(); + std::swap(this->m_has_val, rhs.m_has_val); + } + + void swap_where_only_one_has_value(expected& rhs, t_is_not_void) { + swap_where_only_one_has_value_and_t_is_not_void( + rhs, typename std::is_nothrow_move_constructible::type{}, + typename std::is_nothrow_move_constructible::type{}); + } + + void swap_where_only_one_has_value_and_t_is_not_void( + expected& rhs, t_is_nothrow_move_constructible, + e_is_nothrow_move_constructible) noexcept { + auto temp = std::move(val()); + val().~T(); + ::new (errptr()) unexpected_type(std::move(rhs.err())); + rhs.err().~unexpected_type(); + ::new (rhs.valptr()) T(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); + } + + void swap_where_only_one_has_value_and_t_is_not_void( + expected& rhs, t_is_nothrow_move_constructible, + move_constructing_e_can_throw) { + auto temp = std::move(val()); + val().~T(); +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (errptr()) unexpected_type(std::move(rhs.err())); + rhs.err().~unexpected_type(); + ::new (rhs.valptr()) T(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); + } catch (...) { + val() = std::move(temp); + throw; + } +#else + ::new (errptr()) unexpected_type(std::move(rhs.err())); + rhs.err().~unexpected_type(); + ::new (rhs.valptr()) T(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); +#endif + } + + void swap_where_only_one_has_value_and_t_is_not_void( + expected& rhs, move_constructing_t_can_throw, + e_is_nothrow_move_constructible) { + auto temp = std::move(rhs.err()); + rhs.err().~unexpected_type(); +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (rhs.valptr()) T(std::move(val())); + val().~T(); + ::new (errptr()) unexpected_type(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); + } catch (...) { + rhs.err() = std::move(temp); + throw; + } +#else + ::new (rhs.valptr()) T(std::move(val())); + val().~T(); + ::new (errptr()) unexpected_type(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); +#endif + } + + public: + template + detail::enable_if_t::value && + detail::is_swappable::value && + (std::is_nothrow_move_constructible::value || + std::is_nothrow_move_constructible::value)> + swap(expected& rhs) noexcept(std::is_nothrow_move_constructible::value && + detail::is_nothrow_swappable::value && + std::is_nothrow_move_constructible::value && + detail::is_nothrow_swappable::value) { + if (has_value() && rhs.has_value()) { + swap_where_both_have_value(rhs, typename std::is_void::type{}); + } else if (!has_value() && rhs.has_value()) { + rhs.swap(*this); + } else if (has_value()) { + swap_where_only_one_has_value(rhs, typename std::is_void::type{}); + } else { + using std::swap; + swap(err(), rhs.err()); + } + } + + constexpr const T* operator->() const { + TL_ASSERT(has_value()); + return valptr(); + } + TL_EXPECTED_11_CONSTEXPR T* operator->() { + TL_ASSERT(has_value()); + return valptr(); + } + + template ::value>* = nullptr> + constexpr const U& operator*() const& { + TL_ASSERT(has_value()); + return val(); + } + template ::value>* = nullptr> + TL_EXPECTED_11_CONSTEXPR U& operator*() & { + TL_ASSERT(has_value()); + return val(); + } + template ::value>* = nullptr> + constexpr const U&& operator*() const&& { + TL_ASSERT(has_value()); + return std::move(val()); + } + template ::value>* = nullptr> + TL_EXPECTED_11_CONSTEXPR U&& operator*() && { + TL_ASSERT(has_value()); + return std::move(val()); + } + + constexpr bool has_value() const noexcept { return this->m_has_val; } + constexpr explicit operator bool() const noexcept { return this->m_has_val; } + + template ::value>* = nullptr> + TL_EXPECTED_11_CONSTEXPR const U& value() const& { + if (!has_value()) + detail::throw_exception(bad_expected_access(err().value())); + return val(); + } + template ::value>* = nullptr> + TL_EXPECTED_11_CONSTEXPR U& value() & { + if (!has_value()) + detail::throw_exception(bad_expected_access(err().value())); + return val(); + } + template ::value>* = nullptr> + TL_EXPECTED_11_CONSTEXPR const U&& value() const&& { + if (!has_value()) + detail::throw_exception(bad_expected_access(std::move(err()).value())); + return std::move(val()); + } + template ::value>* = nullptr> + TL_EXPECTED_11_CONSTEXPR U&& value() && { + if (!has_value()) + detail::throw_exception(bad_expected_access(std::move(err()).value())); + return std::move(val()); + } + + constexpr const E& error() const& { + TL_ASSERT(!has_value()); + return err().value(); + } + TL_EXPECTED_11_CONSTEXPR E& error() & { + TL_ASSERT(!has_value()); + return err().value(); + } + constexpr const E&& error() const&& { + TL_ASSERT(!has_value()); + return std::move(err().value()); + } + TL_EXPECTED_11_CONSTEXPR E&& error() && { + TL_ASSERT(!has_value()); + return std::move(err().value()); + } + + template + constexpr T value_or(U&& v) const& { + static_assert(std::is_copy_constructible::value && + std::is_convertible::value, + "T must be copy-constructible and convertible to from U&&"); + return bool(*this) ? **this : static_cast(std::forward(v)); + } + template + TL_EXPECTED_11_CONSTEXPR T value_or(U&& v) && { + static_assert(std::is_move_constructible::value && + std::is_convertible::value, + "T must be move-constructible and convertible to from U&&"); + return bool(*this) ? std::move(**this) : static_cast(std::forward(v)); + } +}; + +namespace detail { +template +using exp_t = typename detail::decay_t::value_type; +template +using err_t = typename detail::decay_t::error_type; +template +using ret_t = expected>; + +#ifdef TL_EXPECTED_CXX14 +template >::value>* = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + *std::declval()))> +constexpr auto and_then_impl(Exp&& exp, F&& f) { + static_assert(detail::is_expected::value, "F must return an expected"); + + return exp.has_value() + ? detail::invoke(std::forward(f), *std::forward(exp)) + : Ret(unexpect, std::forward(exp).error()); +} + +template >::value>* = nullptr, + class Ret = decltype(detail::invoke(std::declval()))> +constexpr auto and_then_impl(Exp&& exp, F&& f) { + static_assert(detail::is_expected::value, "F must return an expected"); + + return exp.has_value() ? detail::invoke(std::forward(f)) + : Ret(unexpect, std::forward(exp).error()); +} +#else +template +struct TC; +template (), + *std::declval())), + detail::enable_if_t>::value>* = nullptr> +auto and_then_impl(Exp&& exp, F&& f) -> Ret { + static_assert(detail::is_expected::value, "F must return an expected"); + + return exp.has_value() + ? detail::invoke(std::forward(f), *std::forward(exp)) + : Ret(unexpect, std::forward(exp).error()); +} + +template ())), + detail::enable_if_t>::value>* = nullptr> +constexpr auto and_then_impl(Exp&& exp, F&& f) -> Ret { + static_assert(detail::is_expected::value, "F must return an expected"); + + return exp.has_value() ? detail::invoke(std::forward(f)) + : Ret(unexpect, std::forward(exp).error()); +} +#endif + +#ifdef TL_EXPECTED_CXX14 +template >::value>* = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + *std::declval())), + detail::enable_if_t::value>* = nullptr> +constexpr auto expected_map_impl(Exp&& exp, F&& f) { + using result = ret_t>; + return exp.has_value() ? result(detail::invoke(std::forward(f), + *std::forward(exp))) + : result(unexpect, std::forward(exp).error()); +} + +template >::value>* = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + *std::declval())), + detail::enable_if_t::value>* = nullptr> +auto expected_map_impl(Exp&& exp, F&& f) { + using result = expected>; + if (exp.has_value()) { + detail::invoke(std::forward(f), *std::forward(exp)); + return result(); + } + + return result(unexpect, std::forward(exp).error()); +} + +template >::value>* = nullptr, + class Ret = decltype(detail::invoke(std::declval())), + detail::enable_if_t::value>* = nullptr> +constexpr auto expected_map_impl(Exp&& exp, F&& f) { + using result = ret_t>; + return exp.has_value() ? result(detail::invoke(std::forward(f))) + : result(unexpect, std::forward(exp).error()); +} + +template >::value>* = nullptr, + class Ret = decltype(detail::invoke(std::declval())), + detail::enable_if_t::value>* = nullptr> +auto expected_map_impl(Exp&& exp, F&& f) { + using result = expected>; + if (exp.has_value()) { + detail::invoke(std::forward(f)); + return result(); + } + + return result(unexpect, std::forward(exp).error()); +} +#else +template >::value>* = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + *std::declval())), + detail::enable_if_t::value>* = nullptr> + +constexpr auto expected_map_impl(Exp&& exp, F&& f) + -> ret_t> { + using result = ret_t>; + + return exp.has_value() ? result(detail::invoke(std::forward(f), + *std::forward(exp))) + : result(unexpect, std::forward(exp).error()); +} + +template >::value>* = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + *std::declval())), + detail::enable_if_t::value>* = nullptr> + +auto expected_map_impl(Exp&& exp, F&& f) -> expected> { + if (exp.has_value()) { + detail::invoke(std::forward(f), *std::forward(exp)); + return {}; + } + + return unexpected>(std::forward(exp).error()); +} + +template >::value>* = nullptr, + class Ret = decltype(detail::invoke(std::declval())), + detail::enable_if_t::value>* = nullptr> + +constexpr auto expected_map_impl(Exp&& exp, F&& f) + -> ret_t> { + using result = ret_t>; + + return exp.has_value() ? result(detail::invoke(std::forward(f))) + : result(unexpect, std::forward(exp).error()); +} + +template >::value>* = nullptr, + class Ret = decltype(detail::invoke(std::declval())), + detail::enable_if_t::value>* = nullptr> + +auto expected_map_impl(Exp&& exp, F&& f) -> expected> { + if (exp.has_value()) { + detail::invoke(std::forward(f)); + return {}; + } + + return unexpected>(std::forward(exp).error()); +} +#endif + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) +template >::value>* = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value>* = nullptr> +constexpr auto map_error_impl(Exp&& exp, F&& f) { + using result = expected, detail::decay_t>; + return exp.has_value() + ? result(*std::forward(exp)) + : result(unexpect, detail::invoke(std::forward(f), + std::forward(exp).error())); +} +template >::value>* = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value>* = nullptr> +auto map_error_impl(Exp&& exp, F&& f) { + using result = expected, monostate>; + if (exp.has_value()) { + return result(*std::forward(exp)); + } + + detail::invoke(std::forward(f), std::forward(exp).error()); + return result(unexpect, monostate{}); +} +template >::value>* = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value>* = nullptr> +constexpr auto map_error_impl(Exp&& exp, F&& f) { + using result = expected, detail::decay_t>; + return exp.has_value() + ? result() + : result(unexpect, detail::invoke(std::forward(f), + std::forward(exp).error())); +} +template >::value>* = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value>* = nullptr> +auto map_error_impl(Exp&& exp, F&& f) { + using result = expected, monostate>; + if (exp.has_value()) { + return result(); + } + + detail::invoke(std::forward(f), std::forward(exp).error()); + return result(unexpect, monostate{}); +} +#else +template >::value>* = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value>* = nullptr> +constexpr auto map_error_impl(Exp&& exp, F&& f) + -> expected, detail::decay_t> { + using result = expected, detail::decay_t>; + + return exp.has_value() + ? result(*std::forward(exp)) + : result(unexpect, detail::invoke(std::forward(f), + std::forward(exp).error())); +} + +template >::value>* = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value>* = nullptr> +auto map_error_impl(Exp&& exp, F&& f) -> expected, monostate> { + using result = expected, monostate>; + if (exp.has_value()) { + return result(*std::forward(exp)); + } + + detail::invoke(std::forward(f), std::forward(exp).error()); + return result(unexpect, monostate{}); +} + +template >::value>* = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value>* = nullptr> +constexpr auto map_error_impl(Exp&& exp, F&& f) + -> expected, detail::decay_t> { + using result = expected, detail::decay_t>; + + return exp.has_value() + ? result() + : result(unexpect, detail::invoke(std::forward(f), + std::forward(exp).error())); +} + +template >::value>* = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value>* = nullptr> +auto map_error_impl(Exp&& exp, F&& f) -> expected, monostate> { + using result = expected, monostate>; + if (exp.has_value()) { + return result(); + } + + detail::invoke(std::forward(f), std::forward(exp).error()); + return result(unexpect, monostate{}); +} +#endif + +#ifdef TL_EXPECTED_CXX14 +template (), + std::declval().error())), + detail::enable_if_t::value>* = nullptr> +constexpr auto or_else_impl(Exp&& exp, F&& f) { + static_assert(detail::is_expected::value, "F must return an expected"); + return exp.has_value() ? std::forward(exp) + : detail::invoke(std::forward(f), + std::forward(exp).error()); +} + +template (), + std::declval().error())), + detail::enable_if_t::value>* = nullptr> +detail::decay_t or_else_impl(Exp&& exp, F&& f) { + return exp.has_value() ? std::forward(exp) + : (detail::invoke(std::forward(f), + std::forward(exp).error()), + std::forward(exp)); +} +#else +template (), + std::declval().error())), + detail::enable_if_t::value>* = nullptr> +auto or_else_impl(Exp&& exp, F&& f) -> Ret { + static_assert(detail::is_expected::value, "F must return an expected"); + return exp.has_value() ? std::forward(exp) + : detail::invoke(std::forward(f), + std::forward(exp).error()); +} + +template (), + std::declval().error())), + detail::enable_if_t::value>* = nullptr> +detail::decay_t or_else_impl(Exp&& exp, F&& f) { + return exp.has_value() ? std::forward(exp) + : (detail::invoke(std::forward(f), + std::forward(exp).error()), + std::forward(exp)); +} +#endif +} // namespace detail + +template +constexpr bool operator==(const expected& lhs, + const expected& rhs) { + return (lhs.has_value() != rhs.has_value()) + ? false + : (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs); +} +template +constexpr bool operator!=(const expected& lhs, + const expected& rhs) { + return (lhs.has_value() != rhs.has_value()) + ? true + : (!lhs.has_value() ? lhs.error() != rhs.error() : *lhs != *rhs); +} +template +constexpr bool operator==(const expected& lhs, + const expected& rhs) { + return (lhs.has_value() != rhs.has_value()) + ? false + : (!lhs.has_value() ? lhs.error() == rhs.error() : true); +} +template +constexpr bool operator!=(const expected& lhs, + const expected& rhs) { + return (lhs.has_value() != rhs.has_value()) + ? true + : (!lhs.has_value() ? lhs.error() == rhs.error() : false); +} + +template +constexpr bool operator==(const expected& x, const U& v) { + return x.has_value() ? *x == v : false; +} +template +constexpr bool operator==(const U& v, const expected& x) { + return x.has_value() ? *x == v : false; +} +template +constexpr bool operator!=(const expected& x, const U& v) { + return x.has_value() ? *x != v : true; +} +template +constexpr bool operator!=(const U& v, const expected& x) { + return x.has_value() ? *x != v : true; +} + +template +constexpr bool operator==(const expected& x, const unexpected& e) { + return x.has_value() ? false : x.error() == e.value(); +} +template +constexpr bool operator==(const unexpected& e, const expected& x) { + return x.has_value() ? false : x.error() == e.value(); +} +template +constexpr bool operator!=(const expected& x, const unexpected& e) { + return x.has_value() ? true : x.error() != e.value(); +} +template +constexpr bool operator!=(const unexpected& e, const expected& x) { + return x.has_value() ? true : x.error() != e.value(); +} + +template ::value || + std::is_move_constructible::value) && + detail::is_swappable::value && + std::is_move_constructible::value && + detail::is_swappable::value>* = nullptr> +void swap(expected& lhs, + expected& rhs) noexcept(noexcept(lhs.swap(rhs))) { + lhs.swap(rhs); +} +} // namespace tl + +#endif +/* end file include/ada/expected.h */ + +/* begin file include/ada/url_pattern_regex.h */ +/** + * @file url_search_params.h + * @brief Declaration for the URL Search Params + */ +#ifndef ADA_URL_PATTERN_REGEX_H +#define ADA_URL_PATTERN_REGEX_H + +#include +#include + +#ifdef ADA_USE_UNSAFE_STD_REGEX_PROVIDER +#include +#endif // ADA_USE_UNSAFE_STD_REGEX_PROVIDER + +#if ADA_INCLUDE_URL_PATTERN +namespace ada::url_pattern_regex { + +template +concept regex_concept = requires(T t, std::string_view pattern, + bool ignore_case, std::string_view input) { + // Ensure the class has a type alias 'regex_type' + typename T::regex_type; + + // Function to create a regex instance + { + T::create_instance(pattern, ignore_case) + } -> std::same_as>; + + // Function to perform regex search + { + T::regex_search(input, std::declval()) + } -> std::same_as>>>; + + // Function to match regex pattern + { + T::regex_match(input, std::declval()) + } -> std::same_as; + + // Copy constructor + { T(std::declval()) } -> std::same_as; + + // Move constructor + { T(std::declval()) } -> std::same_as; +}; + +#ifdef ADA_USE_UNSAFE_STD_REGEX_PROVIDER +class std_regex_provider final { + public: + std_regex_provider() = default; + using regex_type = std::regex; + static std::optional create_instance(std::string_view pattern, + bool ignore_case); + static std::optional>> regex_search( + std::string_view input, const regex_type& pattern); + static bool regex_match(std::string_view input, const regex_type& pattern); +}; +#endif // ADA_USE_UNSAFE_STD_REGEX_PROVIDER + +} // namespace ada::url_pattern_regex +#endif // ADA_INCLUDE_URL_PATTERN +#endif // ADA_URL_PATTERN_REGEX_H +/* end file include/ada/url_pattern_regex.h */ +/* begin file include/ada/url_pattern_init.h */ +/** + * @file url_pattern_init.h + * @brief Declaration for the url_pattern_init implementation. + */ +#ifndef ADA_URL_PATTERN_INIT_H +#define ADA_URL_PATTERN_INIT_H + +/* begin file include/ada/errors.h */ +/** + * @file errors.h + * @brief Error type definitions for URL parsing. + * + * Defines the error codes that can be returned when URL parsing fails. + */ +#ifndef ADA_ERRORS_H +#define ADA_ERRORS_H + +#include +namespace ada { +/** + * @brief Error codes for URL parsing operations. + * + * Used with `tl::expected` to indicate why a URL parsing operation failed. + */ +enum class errors : uint8_t { + type_error /**< A type error occurred (e.g., invalid URL syntax). */ +}; +} // namespace ada +#endif // ADA_ERRORS_H +/* end file include/ada/errors.h */ + +#include +#include +#include +#include + +#if ADA_TESTING +#include +#endif // ADA_TESTING + +#if ADA_INCLUDE_URL_PATTERN +namespace ada { + +// Important: C++20 allows us to use concept rather than `using` or `typedef +// and allows functions with second argument, which is optional (using either +// std::nullopt or a parameter with default value) +template +concept url_pattern_encoding_callback = requires(F f, std::string_view sv) { + { f(sv) } -> std::same_as>; +}; + +// A structure providing matching patterns for individual components +// of a URL. When a URLPattern is created, or when a URLPattern is +// used to match or test against a URL, the input can be given as +// either a string or a URLPatternInit struct. If a string is given, +// it will be parsed to create a URLPatternInit. The URLPatternInit +// API is defined as part of the URLPattern specification. +// All provided strings must be valid UTF-8. +struct url_pattern_init { + enum class process_type : uint8_t { + url, + pattern, + }; + + friend std::ostream& operator<<(std::ostream& os, process_type type) { + switch (type) { + case process_type::url: + return os << "url"; + case process_type::pattern: + return os << "pattern"; + default: + return os << "unknown"; + } + } + + // All strings must be valid UTF-8. + // @see https://urlpattern.spec.whatwg.org/#process-a-urlpatterninit + static tl::expected process( + const url_pattern_init& init, process_type type, + std::optional protocol = std::nullopt, + std::optional username = std::nullopt, + std::optional password = std::nullopt, + std::optional hostname = std::nullopt, + std::optional port = std::nullopt, + std::optional pathname = std::nullopt, + std::optional search = std::nullopt, + std::optional hash = std::nullopt); + + // @see https://urlpattern.spec.whatwg.org/#process-protocol-for-init + static tl::expected process_protocol( + std::string_view value, process_type type); + + // @see https://urlpattern.spec.whatwg.org/#process-username-for-init + static tl::expected process_username( + std::string_view value, process_type type); + + // @see https://urlpattern.spec.whatwg.org/#process-password-for-init + static tl::expected process_password( + std::string_view value, process_type type); + + // @see https://urlpattern.spec.whatwg.org/#process-hostname-for-init + static tl::expected process_hostname( + std::string_view value, process_type type); + + // @see https://urlpattern.spec.whatwg.org/#process-port-for-init + static tl::expected process_port( + std::string_view port, std::string_view protocol, process_type type); + + // @see https://urlpattern.spec.whatwg.org/#process-pathname-for-init + static tl::expected process_pathname( + std::string_view value, std::string_view protocol, process_type type); + + // @see https://urlpattern.spec.whatwg.org/#process-search-for-init + static tl::expected process_search( + std::string_view value, process_type type); + + // @see https://urlpattern.spec.whatwg.org/#process-hash-for-init + static tl::expected process_hash(std::string_view value, + process_type type); + +#if ADA_TESTING + friend void PrintTo(const url_pattern_init& init, std::ostream* os) { + *os << "protocol: '" << init.protocol.value_or("undefined") << "', "; + *os << "username: '" << init.username.value_or("undefined") << "', "; + *os << "password: '" << init.password.value_or("undefined") << "', "; + *os << "hostname: '" << init.hostname.value_or("undefined") << "', "; + *os << "port: '" << init.port.value_or("undefined") << "', "; + *os << "pathname: '" << init.pathname.value_or("undefined") << "', "; + *os << "search: '" << init.search.value_or("undefined") << "', "; + *os << "hash: '" << init.hash.value_or("undefined") << "', "; + *os << "base_url: '" << init.base_url.value_or("undefined") << "', "; + } +#endif // ADA_TESTING + + bool operator==(const url_pattern_init&) const; + // If present, must be valid UTF-8. + std::optional protocol{}; + // If present, must be valid UTF-8. + std::optional username{}; + // If present, must be valid UTF-8. + std::optional password{}; + // If present, must be valid UTF-8. + std::optional hostname{}; + // If present, must be valid UTF-8. + std::optional port{}; + // If present, must be valid UTF-8. + std::optional pathname{}; + // If present, must be valid UTF-8. + std::optional search{}; + // If present, must be valid UTF-8. + std::optional hash{}; + // If present, must be valid UTF-8. + std::optional base_url{}; +}; +} // namespace ada +#endif // ADA_INCLUDE_URL_PATTERN +#endif // ADA_URL_PATTERN_INIT_H +/* end file include/ada/url_pattern_init.h */ + +/** @private Forward declarations */ +namespace ada { +struct url_aggregator; +struct url; +#if ADA_INCLUDE_URL_PATTERN +template +class url_pattern; +struct url_pattern_options; +#endif // ADA_INCLUDE_URL_PATTERN +enum class errors : uint8_t; +} // namespace ada + +/** + * @namespace ada::parser + * @brief Internal URL parsing implementation. + * + * Contains the core URL parsing algorithm as specified by the WHATWG URL + * Standard. These functions are used internally by `ada::parse()`. + */ +namespace ada::parser { +/** + * Parses a URL string into a URL object. + * + * @tparam result_type The type of URL object to create (url or url_aggregator). + * + * @param user_input The URL string to parse (must be valid UTF-8). + * @param base_url Optional base URL for resolving relative URLs. + * + * @return The parsed URL object. Check `is_valid` to determine if parsing + * succeeded. + * + * @see https://url.spec.whatwg.org/#concept-basic-url-parser + */ +template +result_type parse_url(std::string_view user_input, + const result_type* base_url = nullptr); + +extern template url_aggregator parse_url( + std::string_view user_input, const url_aggregator* base_url); +extern template url parse_url(std::string_view user_input, + const url* base_url); + +template +result_type parse_url_impl(std::string_view user_input, + const result_type* base_url = nullptr); + +extern template url_aggregator parse_url_impl( + std::string_view user_input, const url_aggregator* base_url); +extern template url_aggregator parse_url_impl( + std::string_view user_input, const url_aggregator* base_url); +extern template url parse_url_impl(std::string_view user_input, + const url* base_url); + +/** @private */ +template +bool try_parse_simple_absolute(std::string_view input, result_type& out); + +#if ADA_INCLUDE_URL_PATTERN +template +tl::expected, errors> parse_url_pattern_impl( + std::variant&& input, + const std::string_view* base_url, const url_pattern_options* options); +#endif // ADA_INCLUDE_URL_PATTERN + +} // namespace ada::parser + +#endif // ADA_PARSER_H +/* end file include/ada/parser.h */ +/* begin file include/ada/parser-inl.h */ +/** + * @file parser-inl.h + */ +#ifndef ADA_PARSER_INL_H +#define ADA_PARSER_INL_H + +/* begin file include/ada/url_pattern.h */ +/** + * @file url_pattern.h + * @brief URLPattern API implementation. + * + * This header provides the URLPattern API as specified by the WHATWG URL + * Pattern Standard. URLPattern allows matching URLs against patterns with + * wildcards and named groups, similar to how regular expressions match strings. + * + * @see https://urlpattern.spec.whatwg.org/ + * @see https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API + */ +#ifndef ADA_URL_PATTERN_H +#define ADA_URL_PATTERN_H + +/* begin file include/ada/implementation.h */ +/** + * @file implementation.h + * @brief User-facing functions for URL parsing and manipulation. + * + * This header provides the primary public API for parsing URLs in Ada. + * It includes the main `ada::parse()` function which is the recommended + * entry point for most users. + * + * @see https://url.spec.whatwg.org/#api + */ +#ifndef ADA_IMPLEMENTATION_H +#define ADA_IMPLEMENTATION_H + +#include +#include +#include + +/* begin file include/ada/url.h */ +/** + * @file url.h + * @brief Declaration for the `ada::url` class. + * + * This file contains the `ada::url` struct which represents a parsed URL + * using separate `std::string` instances for each component. This + * representation is more flexible but uses more memory than `url_aggregator`. + * + * @see url_aggregator.h for a more memory-efficient alternative + */ +#ifndef ADA_URL_H +#define ADA_URL_H + +#include +#include +#include +#include +#include + +/* begin file include/ada/url_components.h */ +/** + * @file url_components.h + * @brief URL component offset representation for url_aggregator. + * + * This file defines the `url_components` struct which stores byte offsets + * into a URL string buffer. It is used internally by `url_aggregator` to + * efficiently locate URL components without storing separate strings. + */ +#ifndef ADA_URL_COMPONENTS_H +#define ADA_URL_COMPONENTS_H + +namespace ada { + +/** + * @brief Stores byte offsets for URL components within a buffer. + * + * The `url_components` struct uses 32-bit offsets to track the boundaries + * of each URL component within a single string buffer. This enables efficient + * component extraction without additional memory allocations. + * + * Component layout in a URL: + * ``` + * https://user:pass@example.com:1234/foo/bar?baz#quux + * | | | | ^^^^| | | + * | | | | | | | `----- hash_start + * | | | | | | `--------- search_start + * | | | | | `----------------- pathname_start + * | | | | `--------------------- port + * | | | `----------------------- host_end + * | | `---------------------------------- host_start + * | `--------------------------------------- username_end + * `--------------------------------------------- protocol_end + * ``` + * + * @note The 32-bit offsets limit URLs to 4GB in length. + * @note A value of `omitted` (UINT32_MAX) indicates the component is not + * present. + */ +struct url_components { + /** Sentinel value indicating a component is not present. */ + constexpr static uint32_t omitted = uint32_t(-1); + + url_components() = default; + url_components(const url_components& u) = default; + url_components(url_components&& u) noexcept = default; + url_components& operator=(url_components&& u) noexcept = default; + url_components& operator=(const url_components& u) = default; + ~url_components() = default; + + /** Offset of the end of the protocol/scheme (position of ':'). */ + uint32_t protocol_end{0}; + + /** + * Offset of the end of the username. + * Initialized to 0 (not `omitted`) to simplify username/password getters. + */ + uint32_t username_end{0}; + + /** Offset of the start of the host. */ + uint32_t host_start{0}; + + /** Offset of the end of the host. */ + uint32_t host_end{0}; + + /** Port number, or `omitted` if no port is specified. */ + uint32_t port{omitted}; + + /** Offset of the start of the pathname. */ + uint32_t pathname_start{0}; + + /** Offset of the '?' starting the query, or `omitted` if no query. */ + uint32_t search_start{omitted}; + + /** Offset of the '#' starting the fragment, or `omitted` if no fragment. */ + uint32_t hash_start{omitted}; + + /** + * Validates that offsets are in ascending order and consistent. + * Useful for debugging to detect internal corruption. + * @return `true` if offsets are consistent, `false` otherwise. + */ + [[nodiscard]] constexpr bool check_offset_consistency() const noexcept; + + /** + * Returns a JSON string representation of the offsets for debugging. + * @return A JSON-formatted string with all offset values. + */ + [[nodiscard]] std::string to_string() const; + +}; // struct url_components +} // namespace ada +#endif +/* end file include/ada/url_components.h */ + +namespace ada { + +struct url_aggregator; + +// namespace parser { +// template +// result_type parse_url(std::string_view user_input, +// const result_type* base_url = nullptr); +// template +// result_type parse_url_impl(std::string_view user_input, +// const result_type* base_url = nullptr); +// } + +/** + * @brief Represents a parsed URL with individual string components. + * + * The `url` struct stores each URL component (scheme, username, password, + * host, port, path, query, fragment) as a separate `std::string`. This + * provides flexibility but incurs more memory allocations compared to + * `url_aggregator`. + * + * **When to use `ada::url`:** + * - When you need to frequently modify individual URL components + * - When you want independent ownership of component strings + * + * **When to use `ada::url_aggregator` instead:** + * - For read-mostly operations on parsed URLs + * - When memory efficiency is important + * - When you only need string_view access to components + * + * @note This type is returned when parsing with `ada::parse()`. + * By default, `ada::parse()` returns `ada::url_aggregator`. + * + * @see url_aggregator For a more memory-efficient URL representation + * @see https://url.spec.whatwg.org/#url-representation + */ +struct url : url_base { + url() = default; + url(const url& u) = default; + url(url&& u) noexcept = default; + url& operator=(url&& u) noexcept = default; + url& operator=(const url& u) = default; + ~url() override = default; + + // Fields are ordered so that the most frequently accessed components + // tend to occupy earlier cache lines and remain close together in memory. + // + // Note: The exact object layout (including cache-line boundaries, byte + // offsets, and member sizes) is implementation- and platform-dependent. + // This ordering expresses an intent for better cache locality but does not + // guarantee any specific in-memory layout. + + /** + * @private + * A URL's host is null or a host. It is initially null. + */ + std::optional host{}; + + /** + * @private + * A URL's path is either an ASCII string or a list of zero or more ASCII + * strings, usually identifying a location. + */ + std::string path{}; + + /** + * @private + * A URL's query is either null or an ASCII string. It is initially null. + */ + std::optional query{}; + + /** + * @private + * A URL's fragment is either null or an ASCII string that can be used for + * further processing on the resource the URL's other components identify. It + * is initially null. + */ + std::optional hash{}; + + /** + * @private + * A URL's port is either null or a 16-bit unsigned integer that identifies a + * networking port. It is initially null. + */ + std::optional port{}; + + /** + * @private + * A URL's username is an ASCII string identifying a username. It is initially + * the empty string. + */ + std::string username{}; + + /** + * @private + * A URL's password is an ASCII string identifying a password. It is initially + * the empty string. + */ + std::string password{}; + + /** + * Checks if the URL has an empty hostname (host is set but empty string). + * @return `true` if host exists but is empty, `false` otherwise. + */ + [[nodiscard]] inline bool has_empty_hostname() const noexcept; + + /** + * Checks if the URL has a non-default port explicitly specified. + * @return `true` if a port is present, `false` otherwise. + */ + [[nodiscard]] inline bool has_port() const noexcept; + + /** + * Checks if the URL has a hostname (including empty hostnames). + * @return `true` if host is present, `false` otherwise. + */ + [[nodiscard]] inline bool has_hostname() const noexcept; + + /** + * Validates whether the hostname is a valid domain according to RFC 1034. + * Checks that the domain and its labels have valid lengths (max 255 octets + * total, max 63 octets per label). + * @return `true` if the domain is valid, `false` otherwise. + */ + [[nodiscard]] bool has_valid_domain() const noexcept override; + + /** + * Returns a JSON string representation of this URL for debugging. + * @return A JSON-formatted string with all URL components. + */ + [[nodiscard]] std::string to_string() const override; + + /** + * Returns the full serialized URL (the href). + * @return The complete URL string (allocates a new string). + * @see https://url.spec.whatwg.org/#dom-url-href + */ + [[nodiscard]] ada_really_inline std::string get_href() const; + + /** + * Returns the byte length of the serialized URL without allocating a string. + * @return Size of the href in bytes. + */ + [[nodiscard]] size_t get_href_size() const noexcept; + + /** + * Returns the URL's origin as a string (scheme + host + port for special + * URLs). + * @return A newly allocated string containing the serialized origin. + * @see https://url.spec.whatwg.org/#concept-url-origin + */ + [[nodiscard]] std::string get_origin() const override; + + /** + * Returns the URL's scheme followed by a colon (e.g., "https:"). + * @return A newly allocated string with the protocol. + * @see https://url.spec.whatwg.org/#dom-url-protocol + */ + [[nodiscard]] std::string get_protocol() const; + + /** + * Returns the URL's host and port (e.g., "example.com:8080"). + * If no port is set, returns just the host. Returns empty string if no host. + * @return A newly allocated string with host:port. + * @see https://url.spec.whatwg.org/#dom-url-host + */ + [[nodiscard]] std::string get_host() const; + + /** + * Returns the URL's hostname (without port). + * Returns empty string if no host is set. + * @return A newly allocated string with the hostname. + * @see https://url.spec.whatwg.org/#dom-url-hostname + */ + [[nodiscard]] std::string get_hostname() const; + + /** + * Returns the URL's path component. + * @return A string_view pointing to the path. + * @see https://url.spec.whatwg.org/#dom-url-pathname + */ + [[nodiscard]] constexpr std::string_view get_pathname() const noexcept; + + /** + * Returns the byte length of the pathname without creating a string. + * @return Size of the pathname in bytes. + * @see https://url.spec.whatwg.org/#dom-url-pathname + */ + [[nodiscard]] ada_really_inline size_t get_pathname_length() const noexcept; + + /** + * Returns the URL's query string prefixed with '?' (e.g., "?foo=bar"). + * Returns empty string if no query is set. + * @return A newly allocated string with the search/query. + * @see https://url.spec.whatwg.org/#dom-url-search + */ + [[nodiscard]] std::string get_search() const; + + /** + * Returns the URL's username component. + * @return A constant reference to the username string. + * @see https://url.spec.whatwg.org/#dom-url-username + */ + [[nodiscard]] const std::string& get_username() const noexcept; + + /** + * Sets the URL's username, percent-encoding special characters. + * @param input The new username value. + * @return `true` on success, `false` if the URL cannot have credentials. + * @see https://url.spec.whatwg.org/#dom-url-username + */ + bool set_username(std::string_view input); + + /** + * Sets the URL's password, percent-encoding special characters. + * @param input The new password value. + * @return `true` on success, `false` if the URL cannot have credentials. + * @see https://url.spec.whatwg.org/#dom-url-password + */ + bool set_password(std::string_view input); + + /** + * Sets the URL's port from a string (e.g., "8080"). + * @param input The port string. Empty string removes the port. + * @return `true` on success, `false` if the URL cannot have a port. + * @see https://url.spec.whatwg.org/#dom-url-port + */ + bool set_port(std::string_view input); + + /** + * Sets the URL's fragment/hash (the part after '#'). + * @param input The new hash value (with or without leading '#'). + * @see https://url.spec.whatwg.org/#dom-url-hash + */ + void set_hash(std::string_view input); + + /** + * Sets the URL's query string (the part after '?'). + * @param input The new query value (with or without leading '?'). + * @see https://url.spec.whatwg.org/#dom-url-search + */ + void set_search(std::string_view input); + + /** + * Sets the URL's pathname. + * @param input The new path value. + * @return `true` on success, `false` if the URL has an opaque path. + * @see https://url.spec.whatwg.org/#dom-url-pathname + */ + bool set_pathname(std::string_view input); + + /** + * Sets the URL's host (hostname and optionally port). + * @param input The new host value (e.g., "example.com:8080"). + * @return `true` on success, `false` if parsing fails. + * @see https://url.spec.whatwg.org/#dom-url-host + */ + bool set_host(std::string_view input); + + /** + * Sets the URL's hostname (without port). + * @param input The new hostname value. + * @return `true` on success, `false` if parsing fails. + * @see https://url.spec.whatwg.org/#dom-url-hostname + */ + bool set_hostname(std::string_view input); + + /** + * Sets the URL's protocol/scheme. + * @param input The new protocol (with or without trailing ':'). + * @return `true` on success, `false` if the scheme is invalid. + * @see https://url.spec.whatwg.org/#dom-url-protocol + */ + bool set_protocol(std::string_view input); + + /** + * Replaces the entire URL by parsing a new href string. + * @param input The new URL string to parse. + * @return `true` on success, `false` if parsing fails. + * @see https://url.spec.whatwg.org/#dom-url-href + */ + bool set_href(std::string_view input); + + /** + * Returns the URL's password component. + * @return A constant reference to the password string. + * @see https://url.spec.whatwg.org/#dom-url-password + */ + [[nodiscard]] const std::string& get_password() const noexcept; + + /** + * Returns the URL's port as a string (e.g., "8080"). + * Returns empty string if no port is set. + * @return A newly allocated string with the port. + * @see https://url.spec.whatwg.org/#dom-url-port + */ + [[nodiscard]] std::string get_port() const; + + /** + * Returns the URL's fragment prefixed with '#' (e.g., "#section"). + * Returns empty string if no fragment is set. + * @return A newly allocated string with the hash. + * @see https://url.spec.whatwg.org/#dom-url-hash + */ + [[nodiscard]] std::string get_hash() const; + + /** + * Checks if the URL has credentials (non-empty username or password). + * @return `true` if username or password is non-empty, `false` otherwise. + */ + [[nodiscard]] ada_really_inline bool has_credentials() const noexcept; + + /** + * Returns the URL component offsets for efficient serialization. + * + * The components represent byte offsets into the serialized URL: + * ``` + * https://user:pass@example.com:1234/foo/bar?baz#quux + * | | | | ^^^^| | | + * | | | | | | | `----- hash_start + * | | | | | | `--------- search_start + * | | | | | `----------------- pathname_start + * | | | | `--------------------- port + * | | | `----------------------- host_end + * | | `---------------------------------- host_start + * | `--------------------------------------- username_end + * `--------------------------------------------- protocol_end + * ``` + * @return A newly constructed url_components struct. + * @see https://github.com/servo/rust-url + */ + [[nodiscard]] ada_really_inline ada::url_components get_components() const; + + /** + * Checks if the URL has a fragment/hash component. + * @return `true` if hash is present, `false` otherwise. + */ + [[nodiscard]] constexpr bool has_hash() const noexcept override; + + /** + * Checks if the URL has a query/search component. + * @return `true` if query is present, `false` otherwise. + */ + [[nodiscard]] constexpr bool has_search() const noexcept override; + + private: + friend ada::url ada::parser::parse_url(std::string_view, + const ada::url*); + friend ada::url_aggregator ada::parser::parse_url( + std::string_view, const ada::url_aggregator*); + friend void ada::helpers::strip_trailing_spaces_from_opaque_path( + ada::url& url); + + friend ada::url ada::parser::parse_url_impl(std::string_view, + const ada::url*); + friend ada::url_aggregator ada::parser::parse_url_impl< + ada::url_aggregator, true>(std::string_view, const ada::url_aggregator*); + friend ada::url_aggregator ada::parser::parse_url_impl< + ada::url_aggregator, false>(std::string_view, const ada::url_aggregator*); + template + friend bool ada::parser::try_parse_simple_absolute(std::string_view, + result_type&); + + inline void update_unencoded_base_hash(std::string_view input); + inline void update_base_hostname(std::string_view input); + inline void update_base_search(std::string_view input, + const uint8_t query_percent_encode_set[]); + inline void update_base_search(std::optional&& input); + inline void update_base_pathname(std::string_view input); + inline void update_base_username(std::string_view input); + inline void update_base_password(std::string_view input); + inline void update_base_port(std::optional input); + + /** + * Sets the host or hostname according to override condition. + * Return true on success. + * @see https://url.spec.whatwg.org/#hostname-state + */ + template + bool set_host_or_hostname(std::string_view input); + + /** + * Return true on success. + * @see https://url.spec.whatwg.org/#concept-ipv4-parser + */ + [[nodiscard]] bool parse_ipv4(std::string_view input); + + /** + * Return true on success. + * @see https://url.spec.whatwg.org/#concept-ipv6-parser + */ + [[nodiscard]] bool parse_ipv6(std::string_view input); + + /** + * Return true on success. + * @see https://url.spec.whatwg.org/#concept-opaque-host-parser + */ + [[nodiscard]] bool parse_opaque_host(std::string_view input); + + /** + * A URL's scheme is an ASCII string that identifies the type of URL and can + * be used to dispatch a URL for further processing after parsing. It is + * initially the empty string. We only set non_special_scheme when the scheme + * is non-special, otherwise we avoid constructing string. + * + * Special schemes are stored in ada::scheme::details::is_special_list so we + * typically do not need to store them in each url instance. + */ + std::string non_special_scheme{}; + + /** + * A URL cannot have a username/password/port if its host is null or the empty + * string, or its scheme is "file". + */ + [[nodiscard]] inline bool cannot_have_credentials_or_port() const; + + ada_really_inline size_t parse_port( + std::string_view view, bool check_trailing_content) noexcept override; + + ada_really_inline size_t parse_port(std::string_view view) noexcept override { + return this->parse_port(view, false); + } + + /** + * Parse the host from the provided input. We assume that + * the input does not contain spaces or tabs. Control + * characters and spaces are not trimmed (they should have + * been removed if needed). + * Return true on success. + * @see https://url.spec.whatwg.org/#host-parsing + */ + [[nodiscard]] ada_really_inline bool parse_host(std::string_view input); + + template + [[nodiscard]] ada_really_inline bool parse_scheme(std::string_view input); + + constexpr void clear_pathname() override; + constexpr void clear_search() override; + constexpr void set_protocol_as_file(); + + /** + * Parse the path from the provided input. + * Return true on success. Control characters not + * trimmed from the ends (they should have + * been removed if needed). + * + * The input is expected to be UTF-8. + * + * @see https://url.spec.whatwg.org/ + */ + ada_really_inline void parse_path(std::string_view input); + + /** + * Set the scheme for this URL. The provided scheme should be a valid + * scheme string, be lower-cased, not contain spaces or tabs. It should + * have no spurious trailing or leading content. + */ + inline void set_scheme(std::string&& new_scheme) noexcept; + + /** + * Take the scheme from another URL. The scheme string is moved from the + * provided url. + */ + constexpr void copy_scheme(ada::url&& u); + + /** + * Take the scheme from another URL. The scheme string is copied from the + * provided url. + */ + constexpr void copy_scheme(const ada::url& u); + +}; // struct url + +inline std::ostream& operator<<(std::ostream& out, const ada::url& u); +} // namespace ada + +#endif // ADA_URL_H +/* end file include/ada/url.h */ + +namespace ada { + +/** + * Result type for URL parsing operations. + * + * Uses `tl::expected` to represent either a successfully parsed URL or an + * error. This allows for exception-free error handling. + * + * @tparam result_type The URL type to return (default: `ada::url_aggregator`) + * + * @example + * ```cpp + * ada::result result = ada::parse("https://example.com"); + * if (result) { + * // Success: use result.value() or *result + * } else { + * // Error: handle result.error() + * } + * ``` + */ +template +using result = tl::expected; + +/** + * Parses a URL string according to the WHATWG URL Standard. + * + * This is the main entry point for URL parsing in Ada. The function takes + * a string input and optionally a base URL for resolving relative URLs. + * + * @tparam result_type The URL type to return. Can be either `ada::url` or + * `ada::url_aggregator` (default). The `url_aggregator` type is more + * memory-efficient as it stores components as offsets into a single + * buffer. + * + * @param input The URL string to parse. Must be valid ASCII or UTF-8 encoded. + * Leading and trailing whitespace is automatically trimmed. + * @param base_url Optional pointer to a base URL for resolving relative URLs. + * If nullptr (default), only absolute URLs can be parsed successfully. + * + * @return A `result` containing either the parsed URL on success, + * or an error code on failure. Use the boolean conversion or + * `has_value()` to check for success. + * + * @note The parser is fully compliant with the WHATWG URL Standard. + * + * Parsing fails if the input or the resulting normalized URL exceeds + * `get_max_input_length()` bytes (default ~4 GB, configurable via + * `set_max_input_length()`). This accounts for percent-encoding expansion: + * a short input that normalizes into a long URL is still rejected. + * + * @example + * ```cpp + * // Parse an absolute URL + * auto url = ada::parse("https://user:pass@example.com:8080/path?query#hash"); + * if (url) { + * std::cout << url->get_hostname(); // "example.com" + * std::cout << url->get_pathname(); // "/path" + * } + * + * // Parse a relative URL with a base + * auto base = ada::parse("https://example.com/dir/"); + * if (base) { + * auto relative = ada::parse("../other/page", &*base); + * if (relative) { + * std::cout << relative->get_href(); // + * "https://example.com/other/page" + * } + * } + * ``` + * + * @see https://url.spec.whatwg.org/#url-parsing + */ +template +ada_warn_unused ada::result parse( + std::string_view input, const result_type* base_url = nullptr); + +extern template ada::result parse(std::string_view input, + const url* base_url); +extern template ada::result parse( + std::string_view input, const url_aggregator* base_url); + +/** + * Checks whether a URL string can be successfully parsed. + * + * Equivalent to `parse(input, base).has_value()` for every input, including + * when `set_max_input_length` rejects a normalized href that exceeds the limit. + * + * @param input The URL string to validate. Must be valid ASCII or UTF-8. + * @param base_input Optional base URL string for relative inputs. + * @return `true` if parsing would succeed, `false` otherwise. + * @see https://url.spec.whatwg.org/#dom-url-canparse + */ +bool can_parse(std::string_view input, + const std::string_view* base_input = nullptr); + +#if ADA_INCLUDE_URL_PATTERN +/** + * Parses a URL pattern according to the URLPattern specification. + * + * URL patterns provide a syntax for matching URLs against patterns, similar + * to how regular expressions match strings. This is useful for routing and + * URL-based dispatching. + * + * @tparam regex_provider The regex implementation to use for pattern matching. + * + * @param input Either a URL pattern string (valid UTF-8) or a URLPatternInit + * struct specifying individual component patterns. + * @param base_url Optional pointer to a base URL string (valid UTF-8) for + * resolving relative patterns. + * @param options Optional pointer to configuration options (e.g., ignore_case). + * + * @return A `tl::expected` containing either the parsed url_pattern on success, + * or an error code on failure. + * + * @see https://urlpattern.spec.whatwg.org + */ +template +ada_warn_unused tl::expected, errors> +parse_url_pattern(std::variant&& input, + const std::string_view* base_url = nullptr, + const url_pattern_options* options = nullptr); +#endif // ADA_INCLUDE_URL_PATTERN + +/** + * Converts a file system path to a file:// URL. + * + * Creates a properly formatted file URL from a local file system path. + * Handles platform-specific path separators and percent-encoding. + * + * Respects `get_max_input_length()`: if the input path or the resulting + * `file://` href would exceed the limit, returns an empty string. + * + * @param path The file system path to convert. Must be valid ASCII or UTF-8. + * + * @return A file:// URL string representing the given path, or empty on + * length-limit rejection. + */ +std::string href_from_file(std::string_view path); + +/** + * Sets the maximum allowed length for URLs. + * + * Both the raw input and the resulting normalized URL (the href) are checked + * against this limit. Parsing or setter calls that would produce a URL + * exceeding this length are rejected. The same limit also applies to + * `href_from_file` and to query strings passed to `url_search_params` + * construction / `reset`. The value must fit in a uint32_t. + * The default is std::numeric_limits::max() (approximately 4 GB). + * + * @param length The new maximum URL length in bytes. + */ +void set_max_input_length(uint32_t length); + +/** + * Returns the current maximum allowed length for URLs. + * + * @return The current maximum URL length in bytes. + */ +uint32_t get_max_input_length(); + +} // namespace ada + +#endif // ADA_IMPLEMENTATION_H +/* end file include/ada/implementation.h */ + +#include +#include +#include +#include +#include +#include + +#if ADA_TESTING +#include +#endif // ADA_TESTING + +#if ADA_INCLUDE_URL_PATTERN +namespace ada { + +enum class url_pattern_part_type : uint8_t { + // The part represents a simple fixed text string. + FIXED_TEXT, + // The part represents a matching group with a custom regular expression. + REGEXP, + // The part represents a matching group that matches code points up to the + // next separator code point. This is typically used for a named group like + // ":foo" that does not have a custom regular expression. + SEGMENT_WILDCARD, + // The part represents a matching group that greedily matches all code points. + // This is typically used for the "*" wildcard matching group. + FULL_WILDCARD, +}; + +// Pattern type for fast-path matching optimization. +// This allows skipping expensive regex evaluation for common simple patterns. +enum class url_pattern_component_type : uint8_t { + // Pattern is "^$" - only matches empty string + EMPTY, + // Pattern is "^$" - exact string match (no regex needed) + EXACT_MATCH, + // Pattern is "^(.*)$" - matches anything (full wildcard) + FULL_WILDCARD, + // Pattern requires actual regex evaluation + REGEXP, +}; + +enum class url_pattern_part_modifier : uint8_t { + // The part does not have a modifier. + none, + // The part has an optional modifier indicated by the U+003F (?) code point. + optional, + // The part has a "zero or more" modifier indicated by the U+002A (*) code + // point. + zero_or_more, + // The part has a "one or more" modifier indicated by the U+002B (+) code + // point. + one_or_more, +}; + +// @see https://urlpattern.spec.whatwg.org/#part +class url_pattern_part { + public: + url_pattern_part(url_pattern_part_type _type, std::string&& _value, + url_pattern_part_modifier _modifier) + : type(_type), value(std::move(_value)), modifier(_modifier) {} + + url_pattern_part(url_pattern_part_type _type, std::string&& _value, + url_pattern_part_modifier _modifier, std::string&& _name, + std::string&& _prefix, std::string&& _suffix) + : type(_type), + value(std::move(_value)), + modifier(_modifier), + name(std::move(_name)), + prefix(std::move(_prefix)), + suffix(std::move(_suffix)) {} + // A part has an associated type, a string, which must be set upon creation. + url_pattern_part_type type; + // A part has an associated value, a string, which must be set upon creation. + std::string value; + // A part has an associated modifier a string, which must be set upon + // creation. + url_pattern_part_modifier modifier; + // A part has an associated name, a string, initially the empty string. + std::string name{}; + // A part has an associated prefix, a string, initially the empty string. + std::string prefix{}; + // A part has an associated suffix, a string, initially the empty string. + std::string suffix{}; + + inline bool is_regexp() const noexcept; +}; + +// @see https://urlpattern.spec.whatwg.org/#options-header +struct url_pattern_compile_component_options { + url_pattern_compile_component_options() = default; + explicit url_pattern_compile_component_options( + std::optional new_delimiter = std::nullopt, + std::optional new_prefix = std::nullopt) noexcept + : delimiter(new_delimiter), prefix(new_prefix) {} + + inline std::string_view get_delimiter() const ada_warn_unused; + inline std::string_view get_prefix() const ada_warn_unused; + + // @see https://urlpattern.spec.whatwg.org/#options-ignore-case + bool ignore_case = false; + + static url_pattern_compile_component_options DEFAULT; + static url_pattern_compile_component_options HOSTNAME; + static url_pattern_compile_component_options PATHNAME; + + private: + // @see https://urlpattern.spec.whatwg.org/#options-delimiter-code-point + std::optional delimiter{}; + // @see https://urlpattern.spec.whatwg.org/#options-prefix-code-point + std::optional prefix{}; +}; + +// The default options is an options struct with delimiter code point set to +// the empty string and prefix code point set to the empty string. +inline url_pattern_compile_component_options + url_pattern_compile_component_options::DEFAULT(std::nullopt, std::nullopt); + +// The hostname options is an options struct with delimiter code point set +// "." and prefix code point set to the empty string. +inline url_pattern_compile_component_options + url_pattern_compile_component_options::HOSTNAME('.', std::nullopt); + +// The pathname options is an options struct with delimiter code point set +// "/" and prefix code point set to "/". +inline url_pattern_compile_component_options + url_pattern_compile_component_options::PATHNAME('/', '/'); + +// A struct providing the URLPattern matching results for a single +// URL component. The URLPatternComponentResult is only ever used +// as a member attribute of a URLPatternResult struct. The +// URLPatternComponentResult API is defined as part of the URLPattern +// specification. +struct url_pattern_component_result { + std::string input; + std::unordered_map> groups; + + bool operator==(const url_pattern_component_result&) const; + +#if ADA_TESTING + friend void PrintTo(const url_pattern_component_result& result, + std::ostream* os) { + *os << "input: '" << result.input << "', group: "; + for (const auto& group : result.groups) { + *os << "(" << group.first << ", " << group.second.value_or("undefined") + << ") "; + } + } +#endif // ADA_TESTING +}; + +template +class url_pattern_component { + public: + url_pattern_component() = default; + + // This function explicitly takes a std::string because it is moved. + // To avoid unnecessary copy, move each value while calling the constructor. + url_pattern_component(std::string&& new_pattern, + typename regex_provider::regex_type&& new_regexp, + std::vector&& new_group_name_list, + bool new_has_regexp_groups, + url_pattern_component_type new_type, + std::string&& new_exact_match_value = {}) + : regexp(std::move(new_regexp)), + pattern(std::move(new_pattern)), + group_name_list(std::move(new_group_name_list)), + exact_match_value(std::move(new_exact_match_value)), + has_regexp_groups(new_has_regexp_groups), + type(new_type) {} + + // @see https://urlpattern.spec.whatwg.org/#compile-a-component + template + static tl::expected compile( + std::string_view input, F& encoding_callback, + url_pattern_compile_component_options& options); + + // @see https://urlpattern.spec.whatwg.org/#create-a-component-match-result + url_pattern_component_result create_component_match_result( + std::string&& input, + std::vector>&& exec_result); + + // Fast path test that returns true/false without constructing result groups. + // Uses cached pattern type to skip regex evaluation for simple patterns. + bool fast_test(std::string_view input) const noexcept; + + // Fast path match that returns capture groups without regex for simple + // patterns. Returns nullopt if pattern doesn't match, otherwise returns + // capture groups. + std::optional>> fast_match( + std::string_view input) const; + +#if ADA_TESTING + friend void PrintTo(const url_pattern_component& component, + std::ostream* os) { + *os << "pattern: '" << component.pattern + << "', has_regexp_groups: " << component.has_regexp_groups + << "group_name_list: "; + for (const auto& name : component.group_name_list) { + *os << name << ", "; + } + } +#endif // ADA_TESTING + + typename regex_provider::regex_type regexp{}; + std::string pattern{}; + std::vector group_name_list{}; + // For EXACT_MATCH type: the literal string to compare against + std::string exact_match_value{}; + bool has_regexp_groups = false; + // Cached pattern type for fast-path optimization + url_pattern_component_type type = url_pattern_component_type::REGEXP; +}; + +// A URLPattern input can be either a string or a URLPatternInit object. +// If it is a string, it must be a valid UTF-8 string. +using url_pattern_input = std::variant; + +// A struct providing the URLPattern matching results for all +// components of a URL. The URLPatternResult API is defined as +// part of the URLPattern specification. +struct url_pattern_result { + std::vector inputs; + url_pattern_component_result protocol; + url_pattern_component_result username; + url_pattern_component_result password; + url_pattern_component_result hostname; + url_pattern_component_result port; + url_pattern_component_result pathname; + url_pattern_component_result search; + url_pattern_component_result hash; +}; + +struct url_pattern_options { + bool ignore_case = false; + +#if ADA_TESTING + friend void PrintTo(const url_pattern_options& options, std::ostream* os) { + *os << "ignore_case: '" << options.ignore_case; + } +#endif // ADA_TESTING +}; + +/** + * @brief URL pattern matching class implementing the URLPattern API. + * + * URLPattern provides a way to match URLs against patterns with wildcards + * and named capture groups. It's useful for routing, URL-based dispatching, + * and URL validation. + * + * Pattern syntax supports: + * - Literal text matching + * - Named groups: `:name` (matches up to the next separator) + * - Wildcards: `*` (matches everything) + * - Custom regex: `(pattern)` + * - Optional segments: `:name?` + * - Repeated segments: `:name+`, `:name*` + * + * @tparam regex_provider The regex implementation to use for pattern matching. + * Must satisfy the url_pattern_regex::regex_concept. + * + * @note All string inputs must be valid UTF-8. + * + * @see https://urlpattern.spec.whatwg.org/ + */ +template +class url_pattern { + public: + url_pattern() = default; + + /** + * If non-null, base_url must pointer at a valid UTF-8 string. + * @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-exec + */ + result> exec( + const url_pattern_input& input, + const std::string_view* base_url = nullptr); + + /** + * If non-null, base_url must pointer at a valid UTF-8 string. + * @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-test + */ + result test(const url_pattern_input& input, + const std::string_view* base_url = nullptr); + + /** + * @see https://urlpattern.spec.whatwg.org/#url-pattern-match + * This function expects a valid UTF-8 string if input is a string. + */ + result> match( + const url_pattern_input& input, + const std::string_view* base_url_string = nullptr); + + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-protocol + [[nodiscard]] std::string_view get_protocol() const ada_lifetime_bound; + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-username + [[nodiscard]] std::string_view get_username() const ada_lifetime_bound; + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-password + [[nodiscard]] std::string_view get_password() const ada_lifetime_bound; + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-hostname + [[nodiscard]] std::string_view get_hostname() const ada_lifetime_bound; + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-port + [[nodiscard]] std::string_view get_port() const ada_lifetime_bound; + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-pathname + [[nodiscard]] std::string_view get_pathname() const ada_lifetime_bound; + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-search + [[nodiscard]] std::string_view get_search() const ada_lifetime_bound; + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-hash + [[nodiscard]] std::string_view get_hash() const ada_lifetime_bound; + + // If ignoreCase is true, the JavaScript regular expression created for each + // pattern must use the `vi` flag. Otherwise, they must use the `v` flag. + [[nodiscard]] bool ignore_case() const; + + // @see https://urlpattern.spec.whatwg.org/#url-pattern-has-regexp-groups + [[nodiscard]] bool has_regexp_groups() const; + + // Helper to test all components at once. Returns true if all match. + [[nodiscard]] bool test_components( + std::string_view protocol, std::string_view username, + std::string_view password, std::string_view hostname, + std::string_view port, std::string_view pathname, std::string_view search, + std::string_view hash) const; + +#if ADA_TESTING + friend void PrintTo(const url_pattern& c, std::ostream* os) { + *os << "protocol_component: '" << c.get_protocol() << ", "; + *os << "username_component: '" << c.get_username() << ", "; + *os << "password_component: '" << c.get_password() << ", "; + *os << "hostname_component: '" << c.get_hostname() << ", "; + *os << "port_component: '" << c.get_port() << ", "; + *os << "pathname_component: '" << c.get_pathname() << ", "; + *os << "search_component: '" << c.get_search() << ", "; + *os << "hash_component: '" << c.get_hash(); + } +#endif // ADA_TESTING + + template + friend tl::expected, errors> parser::parse_url_pattern_impl( + std::variant&& input, + const std::string_view* base_url, const url_pattern_options* options); + + /** + * @private + * We can not make this private due to a LLVM bug. + * Ref: https://github.com/ada-url/ada/pull/859 + */ + url_pattern_component protocol_component{}; + /** + * @private + * We can not make this private due to a LLVM bug. + * Ref: https://github.com/ada-url/ada/pull/859 + */ + url_pattern_component username_component{}; + /** + * @private + * We can not make this private due to a LLVM bug. + * Ref: https://github.com/ada-url/ada/pull/859 + */ + url_pattern_component password_component{}; + /** + * @private + * We can not make this private due to a LLVM bug. + * Ref: https://github.com/ada-url/ada/pull/859 + */ + url_pattern_component hostname_component{}; + /** + * @private + * We can not make this private due to a LLVM bug. + * Ref: https://github.com/ada-url/ada/pull/859 + */ + url_pattern_component port_component{}; + /** + * @private + * We can not make this private due to a LLVM bug. + * Ref: https://github.com/ada-url/ada/pull/859 + */ + url_pattern_component pathname_component{}; + /** + * @private + * We can not make this private due to a LLVM bug. + * Ref: https://github.com/ada-url/ada/pull/859 + */ + url_pattern_component search_component{}; + /** + * @private + * We can not make this private due to a LLVM bug. + * Ref: https://github.com/ada-url/ada/pull/859 + */ + url_pattern_component hash_component{}; + /** + * @private + * We can not make this private due to a LLVM bug. + * Ref: https://github.com/ada-url/ada/pull/859 + */ + bool ignore_case_ = false; +}; +} // namespace ada +#endif // ADA_INCLUDE_URL_PATTERN +#endif +/* end file include/ada/url_pattern.h */ +/* begin file include/ada/url_pattern_helpers.h */ +/** + * @file url_pattern_helpers.h + * @brief Declaration for the URLPattern helpers. + */ +#ifndef ADA_URL_PATTERN_HELPERS_H +#define ADA_URL_PATTERN_HELPERS_H + + +#include +#include +#include + +#if ADA_INCLUDE_URL_PATTERN +namespace ada { +enum class errors : uint8_t; +} + +namespace ada::url_pattern_helpers { + +// @see https://urlpattern.spec.whatwg.org/#token +enum class token_type : uint8_t { + INVALID_CHAR, // 0 + OPEN, // 1 + CLOSE, // 2 + REGEXP, // 3 + NAME, // 4 + CHAR, // 5 + ESCAPED_CHAR, // 6 + OTHER_MODIFIER, // 7 + ASTERISK, // 8 + END, // 9 +}; + +#ifdef ADA_TESTING +std::string to_string(token_type type); +#endif // ADA_TESTING + +// @see https://urlpattern.spec.whatwg.org/#tokenize-policy +enum class token_policy { + strict, + lenient, +}; + +// @see https://urlpattern.spec.whatwg.org/#tokens +class token { + public: + token(token_type _type, size_t _index, std::string_view _value) + : type(_type), index(_index), value(_value) {} + + // A token has an associated type, a string, initially "invalid-char". + token_type type = token_type::INVALID_CHAR; + + // A token has an associated index, a number, initially 0. It is the position + // of the first code point in the pattern string represented by the token. + size_t index = 0; + + // A token has an associated value, a string, initially the empty string. It + // contains the code points from the pattern string represented by the token. + std::string_view value{}; +}; + +// @see https://urlpattern.spec.whatwg.org/#pattern-parser +template +class url_pattern_parser { + public: + url_pattern_parser(F& encoding_callback_, + std::string_view segment_wildcard_regexp_) + : encoding_callback(encoding_callback_), + segment_wildcard_regexp(segment_wildcard_regexp_) {} + + bool can_continue() const { return index < tokens.size(); } + + // @see https://urlpattern.spec.whatwg.org/#try-to-consume-a-token + token* try_consume_token(token_type type); + // @see https://urlpattern.spec.whatwg.org/#try-to-consume-a-modifier-token + token* try_consume_modifier_token(); + // @see + // https://urlpattern.spec.whatwg.org/#try-to-consume-a-regexp-or-wildcard-token + token* try_consume_regexp_or_wildcard_token(const token* name_token); + // @see https://urlpattern.spec.whatwg.org/#consume-text + std::string consume_text(); + // @see https://urlpattern.spec.whatwg.org/#consume-a-required-token + bool consume_required_token(token_type type); + // @see + // https://urlpattern.spec.whatwg.org/#maybe-add-a-part-from-the-pending-fixed-value + std::optional maybe_add_part_from_the_pending_fixed_value() + ada_warn_unused; + // @see https://urlpattern.spec.whatwg.org/#add-a-part + std::optional add_part(std::string_view prefix, token* name_token, + token* regexp_or_wildcard_token, + std::string_view suyffix, + token* modifier_token) ada_warn_unused; + + std::vector tokens{}; + F& encoding_callback; + std::string segment_wildcard_regexp; + std::vector parts{}; + std::string pending_fixed_value{}; + size_t index = 0; + size_t next_numeric_name = 0; +}; + +// @see https://urlpattern.spec.whatwg.org/#tokenizer +class Tokenizer { + public: + explicit Tokenizer(std::string_view new_input, token_policy new_policy) + : input(new_input), policy(new_policy) {} + + // @see https://urlpattern.spec.whatwg.org/#get-the-next-code-point + constexpr void get_next_code_point(); + + // True when the most recent decoded unit was malformed UTF-8. + bool had_invalid_code_point() const { return invalid_code_point; } + + // @see https://urlpattern.spec.whatwg.org/#seek-and-get-the-next-code-point + constexpr void seek_and_get_next_code_point(size_t index); + + // @see https://urlpattern.spec.whatwg.org/#add-a-token + + void add_token(token_type type, size_t next_position, size_t value_position, + size_t value_length); + + // @see https://urlpattern.spec.whatwg.org/#add-a-token-with-default-length + void add_token_with_default_length(token_type type, size_t next_position, + size_t value_position); + + // @see + // https://urlpattern.spec.whatwg.org/#add-a-token-with-default-position-and-length + void add_token_with_defaults(token_type type); + + // @see https://urlpattern.spec.whatwg.org/#process-a-tokenizing-error + std::optional process_tokenizing_error( + size_t next_position, size_t value_position) ada_warn_unused; + + friend tl::expected, errors> tokenize( + std::string_view input, token_policy policy); + + private: + // has an associated input, a pattern string, initially the empty string. + std::string_view input; + // has an associated policy, a tokenize policy, initially "strict". + token_policy policy; + // has an associated token list, a token list, initially an empty list. + std::vector token_list{}; + // has an associated index, a number, initially 0. + size_t index = 0; + // has an associated next index, a number, initially 0. + size_t next_index = 0; + // has an associated code point, a Unicode code point, initially null. + char32_t code_point{}; + // Tracks whether the last decoded code point was malformed UTF-8. + bool invalid_code_point = false; +}; + +// @see https://urlpattern.spec.whatwg.org/#constructor-string-parser +template +struct constructor_string_parser { + explicit constructor_string_parser(std::string_view new_input, + std::vector&& new_token_list) + : input(new_input), token_list(std::move(new_token_list)) {} + // @see https://urlpattern.spec.whatwg.org/#parse-a-constructor-string + static tl::expected parse(std::string_view input); + + // @see https://urlpattern.spec.whatwg.org/#constructor-string-parser-state + enum class State { + INIT, + PROTOCOL, + AUTHORITY, + USERNAME, + PASSWORD, + HOSTNAME, + PORT, + PATHNAME, + SEARCH, + HASH, + DONE, + }; + + // @see + // https://urlpattern.spec.whatwg.org/#compute-protocol-matches-a-special-scheme-flag + std::optional compute_protocol_matches_special_scheme_flag(); + + private: + // @see https://urlpattern.spec.whatwg.org/#rewind + constexpr void rewind(); + + // @see https://urlpattern.spec.whatwg.org/#is-a-hash-prefix + constexpr bool is_hash_prefix(); + + // @see https://urlpattern.spec.whatwg.org/#is-a-search-prefix + constexpr bool is_search_prefix(); + + // @see https://urlpattern.spec.whatwg.org/#change-state + void change_state(State state, size_t skip); + + // @see https://urlpattern.spec.whatwg.org/#is-a-group-open + constexpr bool is_group_open() const; + + // @see https://urlpattern.spec.whatwg.org/#is-a-group-close + constexpr bool is_group_close() const; + + // @see https://urlpattern.spec.whatwg.org/#is-a-protocol-suffix + constexpr bool is_protocol_suffix() const; + + // @see https://urlpattern.spec.whatwg.org/#next-is-authority-slashes + constexpr bool next_is_authority_slashes() const; + + // @see https://urlpattern.spec.whatwg.org/#is-an-identity-terminator + constexpr bool is_an_identity_terminator() const; + + // @see https://urlpattern.spec.whatwg.org/#is-a-pathname-start + constexpr bool is_pathname_start() const; + + // @see https://urlpattern.spec.whatwg.org/#is-a-password-prefix + constexpr bool is_password_prefix() const; + + // @see https://urlpattern.spec.whatwg.org/#is-an-ipv6-open + constexpr bool is_an_ipv6_open() const; + + // @see https://urlpattern.spec.whatwg.org/#is-an-ipv6-close + constexpr bool is_an_ipv6_close() const; + + // @see https://urlpattern.spec.whatwg.org/#is-a-port-prefix + constexpr bool is_port_prefix() const; + + // @see https://urlpattern.spec.whatwg.org/#is-a-non-special-pattern-char + constexpr bool is_non_special_pattern_char(size_t index, + uint32_t value) const; + + // @see https://urlpattern.spec.whatwg.org/#get-a-safe-token + constexpr const token* get_safe_token(size_t index) const; + + // @see https://urlpattern.spec.whatwg.org/#make-a-component-string + std::string make_component_string(); + // has an associated input, a string, which must be set upon creation. + std::string_view input; + // has an associated token list, a token list, which must be set upon + // creation. + std::vector token_list; + // has an associated result, a URLPatternInit, initially set to a new + // URLPatternInit. + url_pattern_init result{}; + // has an associated component start, a number, initially set to 0. + size_t component_start = 0; + // has an associated token index, a number, initially set to 0. + size_t token_index = 0; + // has an associated token increment, a number, initially set to 1. + size_t token_increment = 1; + // has an associated group depth, a number, initially set to 0. + size_t group_depth = 0; + // has an associated hostname IPv6 bracket depth, a number, initially set to + // 0. + size_t hostname_ipv6_bracket_depth = 0; + // has an associated protocol matches a special scheme flag, a boolean, + // initially set to false. + bool protocol_matches_a_special_scheme_flag = false; + // has an associated state, a string, initially set to "init". + State state = State::INIT; +}; + +// @see https://urlpattern.spec.whatwg.org/#canonicalize-a-protocol +tl::expected canonicalize_protocol(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-username +tl::expected canonicalize_username(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-password +tl::expected canonicalize_password(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-password +tl::expected canonicalize_hostname(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-an-ipv6-hostname +tl::expected canonicalize_ipv6_hostname( + std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-port +tl::expected canonicalize_port(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-port +tl::expected canonicalize_port_with_protocol( + std::string_view input, std::string_view protocol); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-pathname +tl::expected canonicalize_pathname(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-an-opaque-pathname +tl::expected canonicalize_opaque_pathname( + std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-search +tl::expected canonicalize_search(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-hash +tl::expected canonicalize_hash(std::string_view input); + +// @see https://urlpattern.spec.whatwg.org/#tokenize +tl::expected, errors> tokenize(std::string_view input, + token_policy policy); + +// @see https://urlpattern.spec.whatwg.org/#process-a-base-url-string +std::string process_base_url_string(std::string_view input, + url_pattern_init::process_type type); + +// @see https://urlpattern.spec.whatwg.org/#escape-a-pattern-string +std::string escape_pattern_string(std::string_view input); + +// @see https://urlpattern.spec.whatwg.org/#escape-a-regexp-string +std::string escape_regexp_string(std::string_view input); + +// @see https://urlpattern.spec.whatwg.org/#is-an-absolute-pathname +constexpr bool is_absolute_pathname( + std::string_view input, url_pattern_init::process_type type) noexcept; + +// @see https://urlpattern.spec.whatwg.org/#parse-a-pattern-string +template +tl::expected, errors> parse_pattern_string( + std::string_view input, url_pattern_compile_component_options& options, + F& encoding_callback); + +// @see https://urlpattern.spec.whatwg.org/#generate-a-pattern-string +std::string generate_pattern_string( + std::vector& part_list, + url_pattern_compile_component_options& options); + +// @see +// https://urlpattern.spec.whatwg.org/#generate-a-regular-expression-and-name-list +std::tuple> +generate_regular_expression_and_name_list( + const std::vector& part_list, + url_pattern_compile_component_options options); + +// @see https://urlpattern.spec.whatwg.org/#hostname-pattern-is-an-ipv6-address +bool is_ipv6_address(std::string_view input) noexcept; + +// @see +// https://urlpattern.spec.whatwg.org/#protocol-component-matches-a-special-scheme +template +bool protocol_component_matches_special_scheme( + ada::url_pattern_component& input); + +// @see https://urlpattern.spec.whatwg.org/#convert-a-modifier-to-a-string +std::string_view convert_modifier_to_string(url_pattern_part_modifier modifier); + +// @see https://urlpattern.spec.whatwg.org/#generate-a-segment-wildcard-regexp +std::string generate_segment_wildcard_regexp( + url_pattern_compile_component_options options); + +} // namespace ada::url_pattern_helpers +#endif // ADA_INCLUDE_URL_PATTERN +#endif +/* end file include/ada/url_pattern_helpers.h */ + +#include +#include +#include + +namespace ada::parser { +#if ADA_INCLUDE_URL_PATTERN +template +tl::expected, errors> parse_url_pattern_impl( + std::variant&& input, + const std::string_view* base_url, const url_pattern_options* options) { + // Let init be null. + url_pattern_init init; + + // If input is a scalar value string then: + if (std::holds_alternative(input)) { + // Set init to the result of running parse a constructor string given input. + auto parse_result = + url_pattern_helpers::constructor_string_parser::parse( + std::get(input)); + if (!parse_result) { + ada_log("constructor_string_parser::parse failed"); + return tl::unexpected(parse_result.error()); + } + init = std::move(*parse_result); + // If baseURL is null and init["protocol"] does not exist, then throw a + // TypeError. + if (!base_url && !init.protocol) { + ada_log("base url is null and protocol is not set"); + return tl::unexpected(errors::type_error); + } + + // If baseURL is not null, set init["baseURL"] to baseURL. + if (base_url) { + init.base_url = std::string(*base_url); + } + } else { + // Assert: input is a URLPatternInit. + ADA_ASSERT_TRUE(std::holds_alternative(input)); + // If baseURL is not null, then throw a TypeError. + if (base_url) { + ada_log("base url is not null"); + return tl::unexpected(errors::type_error); + } + // Optimization: Avoid copy by moving the input value. + // Set init to input. + init = std::move(std::get(input)); + } + + // Let processedInit be the result of process a URLPatternInit given init, + // "pattern", null, null, null, null, null, null, null, and null. + auto processed_init = + url_pattern_init::process(init, url_pattern_init::process_type::pattern); + if (!processed_init) { + ada_log("url_pattern_init::process failed for init and 'pattern'"); + return tl::unexpected(processed_init.error()); + } + + // For each componentName of "protocol", "username", "password", "hostname", + // "port", "pathname", "search", "hash" If processedInit[componentName] does + // not exist, then set processedInit[componentName] to "*". + ADA_ASSERT_TRUE(processed_init.has_value()); + if (!processed_init->protocol) processed_init->protocol = "*"; + if (!processed_init->username) processed_init->username = "*"; + if (!processed_init->password) processed_init->password = "*"; + if (!processed_init->hostname) processed_init->hostname = "*"; + if (!processed_init->port) processed_init->port = "*"; + if (!processed_init->pathname) processed_init->pathname = "*"; + if (!processed_init->search) processed_init->search = "*"; + if (!processed_init->hash) processed_init->hash = "*"; + + ada_log("-- processed_init->protocol: ", processed_init->protocol.value()); + ada_log("-- processed_init->username: ", processed_init->username.value()); + ada_log("-- processed_init->password: ", processed_init->password.value()); + ada_log("-- processed_init->hostname: ", processed_init->hostname.value()); + ada_log("-- processed_init->port: ", processed_init->port.value()); + ada_log("-- processed_init->pathname: ", processed_init->pathname.value()); + ada_log("-- processed_init->search: ", processed_init->search.value()); + ada_log("-- processed_init->hash: ", processed_init->hash.value()); + + // If processedInit["protocol"] is a special scheme and processedInit["port"] + // is a string which represents its corresponding default port in radix-10 + // using ASCII digits then set processedInit["port"] to the empty string. + // TODO: Optimization opportunity. + if (scheme::is_special(*processed_init->protocol)) { + std::string_view port = processed_init->port.value(); + if (std::to_string(scheme::get_special_port(*processed_init->protocol)) == + port) { + processed_init->port->clear(); + } + } + + // Let urlPattern be a new URL pattern. + url_pattern url_pattern_{}; + + // Set urlPattern's protocol component to the result of compiling a component + // given processedInit["protocol"], canonicalize a protocol, and default + // options. + auto protocol_component = url_pattern_component::compile( + processed_init->protocol.value(), + url_pattern_helpers::canonicalize_protocol, + url_pattern_compile_component_options::DEFAULT); + if (!protocol_component) { + ada_log("url_pattern_component::compile failed for protocol ", + processed_init->protocol.value()); + return tl::unexpected(protocol_component.error()); + } + url_pattern_.protocol_component = std::move(*protocol_component); + + // Set urlPattern's username component to the result of compiling a component + // given processedInit["username"], canonicalize a username, and default + // options. + auto username_component = url_pattern_component::compile( + processed_init->username.value(), + url_pattern_helpers::canonicalize_username, + url_pattern_compile_component_options::DEFAULT); + if (!username_component) { + ada_log("url_pattern_component::compile failed for username ", + processed_init->username.value()); + return tl::unexpected(username_component.error()); + } + url_pattern_.username_component = std::move(*username_component); + + // Set urlPattern's password component to the result of compiling a component + // given processedInit["password"], canonicalize a password, and default + // options. + auto password_component = url_pattern_component::compile( + processed_init->password.value(), + url_pattern_helpers::canonicalize_password, + url_pattern_compile_component_options::DEFAULT); + if (!password_component) { + ada_log("url_pattern_component::compile failed for password ", + processed_init->password.value()); + return tl::unexpected(password_component.error()); + } + url_pattern_.password_component = std::move(*password_component); + + // TODO: Optimization opportunity. The following if statement can be + // simplified. + // If the result running hostname pattern is an IPv6 address given + // processedInit["hostname"] is true, then set urlPattern's hostname component + // to the result of compiling a component given processedInit["hostname"], + // canonicalize an IPv6 hostname, and hostname options. + if (url_pattern_helpers::is_ipv6_address(processed_init->hostname.value())) { + ada_log("processed_init->hostname is ipv6 address"); + // then set urlPattern's hostname component to the result of compiling a + // component given processedInit["hostname"], canonicalize an IPv6 hostname, + // and hostname options. + auto hostname_component = url_pattern_component::compile( + processed_init->hostname.value(), + url_pattern_helpers::canonicalize_ipv6_hostname, + url_pattern_compile_component_options::DEFAULT); + if (!hostname_component) { + ada_log("url_pattern_component::compile failed for ipv6 hostname ", + processed_init->hostname.value()); + return tl::unexpected(hostname_component.error()); + } + url_pattern_.hostname_component = std::move(*hostname_component); + } else { + // Otherwise, set urlPattern's hostname component to the result of compiling + // a component given processedInit["hostname"], canonicalize a hostname, and + // hostname options. + auto hostname_component = url_pattern_component::compile( + processed_init->hostname.value(), + url_pattern_helpers::canonicalize_hostname, + url_pattern_compile_component_options::HOSTNAME); + if (!hostname_component) { + ada_log("url_pattern_component::compile failed for hostname ", + processed_init->hostname.value()); + return tl::unexpected(hostname_component.error()); + } + url_pattern_.hostname_component = std::move(*hostname_component); + } + + // Set urlPattern's port component to the result of compiling a component + // given processedInit["port"], canonicalize a port, and default options. + auto port_component = url_pattern_component::compile( + processed_init->port.value(), url_pattern_helpers::canonicalize_port, + url_pattern_compile_component_options::DEFAULT); + if (!port_component) { + ada_log("url_pattern_component::compile failed for port ", + processed_init->port.value()); + return tl::unexpected(port_component.error()); + } + url_pattern_.port_component = std::move(*port_component); + + // Let compileOptions be a copy of the default options with the ignore case + // property set to options["ignoreCase"]. + auto compile_options = url_pattern_compile_component_options::DEFAULT; + if (options) { + compile_options.ignore_case = options->ignore_case; + } + + // TODO: Optimization opportunity: Simplify this if statement. + // If the result of running protocol component matches a special scheme given + // urlPattern's protocol component is true, then: + if (url_pattern_helpers::protocol_component_matches_special_scheme< + regex_provider>(url_pattern_.protocol_component)) { + // Let pathCompileOptions be copy of the pathname options with the ignore + // case property set to options["ignoreCase"]. + auto path_compile_options = url_pattern_compile_component_options::PATHNAME; + if (options) { + path_compile_options.ignore_case = options->ignore_case; + } + + // Set urlPattern's pathname component to the result of compiling a + // component given processedInit["pathname"], canonicalize a pathname, and + // pathCompileOptions. + auto pathname_component = url_pattern_component::compile( + processed_init->pathname.value(), + url_pattern_helpers::canonicalize_pathname, path_compile_options); + if (!pathname_component) { + ada_log("url_pattern_component::compile failed for pathname ", + processed_init->pathname.value()); + return tl::unexpected(pathname_component.error()); + } + url_pattern_.pathname_component = std::move(*pathname_component); + } else { + // Otherwise set urlPattern's pathname component to the result of compiling + // a component given processedInit["pathname"], canonicalize an opaque + // pathname, and compileOptions. + auto pathname_component = url_pattern_component::compile( + processed_init->pathname.value(), + url_pattern_helpers::canonicalize_opaque_pathname, compile_options); + if (!pathname_component) { + ada_log("url_pattern_component::compile failed for opaque pathname ", + processed_init->pathname.value()); + return tl::unexpected(pathname_component.error()); + } + url_pattern_.pathname_component = std::move(*pathname_component); + } + + // Set urlPattern's search component to the result of compiling a component + // given processedInit["search"], canonicalize a search, and compileOptions. + auto search_component = url_pattern_component::compile( + processed_init->search.value(), url_pattern_helpers::canonicalize_search, + compile_options); + if (!search_component) { + ada_log("url_pattern_component::compile failed for search ", + processed_init->search.value()); + return tl::unexpected(search_component.error()); + } + url_pattern_.search_component = std::move(*search_component); + + // Set urlPattern's hash component to the result of compiling a component + // given processedInit["hash"], canonicalize a hash, and compileOptions. + auto hash_component = url_pattern_component::compile( + processed_init->hash.value(), url_pattern_helpers::canonicalize_hash, + compile_options); + if (!hash_component) { + ada_log("url_pattern_component::compile failed for hash ", + processed_init->hash.value()); + return tl::unexpected(hash_component.error()); + } + url_pattern_.hash_component = std::move(*hash_component); + + // Return urlPattern. + return url_pattern_; +} +#endif // ADA_INCLUDE_URL_PATTERN + +} // namespace ada::parser + +#endif // ADA_PARSER_INL_H +/* end file include/ada/parser-inl.h */ +/* begin file include/ada/scheme-inl.h */ +/** + * @file scheme-inl.h + * @brief Definitions for the URL scheme. + */ +#ifndef ADA_SCHEME_INL_H +#define ADA_SCHEME_INL_H + + +namespace ada::scheme { + +/** + * @namespace ada::scheme::details + * @brief Includes the definitions for scheme specific entities + */ +namespace details { +// for use with is_special and get_special_port +// Spaces, if present, are removed from URL. +constexpr std::string_view is_special_list[] = {"http", " ", "https", "ws", + "ftp", "wss", "file", " "}; +// for use with get_special_port +constexpr uint16_t special_ports[] = {80, 0, 443, 80, 21, 443, 0, 0}; + +// @private +// convert a string_view to a 64-bit integer key for fast comparison +constexpr uint64_t make_key(std::string_view sv) { + uint64_t val = 0; + for (size_t i = 0; i < sv.size(); i++) + val |= (uint64_t)(uint8_t)sv[i] << (i * 8); + return val; +} +// precomputed keys for the special schemes, indexed by a hash of the input +// string +constexpr uint64_t scheme_keys[] = { + make_key("http"), // 0: HTTP + 0, // 1: sentinel + make_key("https"), // 2: HTTPS + make_key("ws"), // 3: WS + make_key("ftp"), // 4: FTP + make_key("wss"), // 5: WSS + make_key("file"), // 6: FILE + 0, // 7: sentinel +}; + +// @private +// branchless load of up to 5 characters into a uint64_t, padding with zeros if +// n < 5 +inline uint64_t branchless_load5(const char* p, size_t n) { + uint64_t input = (uint8_t)p[0]; + input |= ((uint64_t)(uint8_t)p[n > 1] << 8) & (0 - (uint64_t)(n > 1)); + input |= ((uint64_t)(uint8_t)p[(n > 2) * 2] << 16) & (0 - (uint64_t)(n > 2)); + input |= ((uint64_t)(uint8_t)p[(n > 3) * 3] << 24) & (0 - (uint64_t)(n > 3)); + input |= ((uint64_t)(uint8_t)p[(n > 4) * 4] << 32) & (0 - (uint64_t)(n > 4)); + return input; +} +} // namespace details + +/**** + * @private + * In is_special, get_scheme_type, and get_special_port, we + * use a standard hashing technique to find the index of the scheme in + * the is_special_list. The hashing technique is based on the size of + * the scheme and the first character of the scheme. It ensures that we + * do at most one string comparison per call. If the protocol is + * predictible (e.g., it is always "http"), we can get a better average + * performance by using a simpler approach where we loop and compare + * scheme with all possible protocols starting with the most likely + * protocol. Doing multiple comparisons may have a poor worst case + * performance, however. In this instance, we choose a potentially + * slightly lower best-case performance for a better worst-case + * performance. We can revisit this choice at any time. + * + * Reference: + * Schmidt, Douglas C. "Gperf: A perfect hash function generator." + * More C++ gems 17 (2000). + * + * Reference: https://en.wikipedia.org/wiki/Perfect_hash_function + * + * Reference: https://github.com/ada-url/ada/issues/617 + ****/ + +ada_really_inline constexpr bool is_special(std::string_view scheme) { + if (scheme.empty()) { + return false; + } + int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7; + const std::string_view target = details::is_special_list[hash_value]; + return (target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1)); +} +constexpr uint16_t get_special_port(std::string_view scheme) noexcept { + if (scheme.empty()) { + return 0; + } + int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7; + const std::string_view target = details::is_special_list[hash_value]; + if (scheme.size() == target.size() && + details::branchless_load5(scheme.data(), scheme.size()) == + details::scheme_keys[hash_value]) { + return details::special_ports[hash_value]; + } else { + return 0; + } +} +constexpr uint16_t get_special_port(ada::scheme::type type) noexcept { + return details::special_ports[int(type)]; +} +constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept { + if (scheme.empty()) { + return ada::scheme::NOT_SPECIAL; + } + int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7; + const std::string_view target = details::is_special_list[hash_value]; + if (scheme.size() == target.size() && + details::branchless_load5(scheme.data(), scheme.size()) == + details::scheme_keys[hash_value]) { + return ada::scheme::type(hash_value); + } else { + return ada::scheme::NOT_SPECIAL; + } +} + +} // namespace ada::scheme + +#endif // ADA_SCHEME_INL_H +/* end file include/ada/scheme-inl.h */ +/* begin file include/ada/serializers.h */ +/** + * @file serializers.h + * @brief IP address serialization utilities. + * + * This header provides functions for converting IP addresses to their + * string representations according to the WHATWG URL Standard. + */ +#ifndef ADA_SERIALIZERS_H +#define ADA_SERIALIZERS_H + + +#include +#include + +/** + * @namespace ada::serializers + * @brief IP address serialization functions. + * + * Contains utilities for serializing IPv4 and IPv6 addresses to strings. + */ +namespace ada::serializers { + +/** + * Finds the longest consecutive sequence of zero pieces in an IPv6 address. + * Used for :: compression in IPv6 serialization. + * + * @param address The 8 16-bit pieces of the IPv6 address. + * @param[out] compress Index of the start of the longest zero sequence. + * @param[out] compress_length Length of the longest zero sequence. + */ +void find_longest_sequence_of_ipv6_pieces( + const std::array& address, size_t& compress, + size_t& compress_length) noexcept; + +/** + * Serializes an IPv6 address to its string representation. + * + * @param address The 8 16-bit pieces of the IPv6 address. + * @return The serialized IPv6 string (e.g., "2001:db8::1"). + * @see https://url.spec.whatwg.org/#concept-ipv6-serializer + */ +std::string ipv6(const std::array& address); + +/** + * Serializes an IPv4 address to its dotted-decimal string representation. + * + * @param address The 32-bit IPv4 address as an integer. + * @return The serialized IPv4 string (e.g., "192.168.1.1"). + * @see https://url.spec.whatwg.org/#concept-ipv4-serializer + */ +std::string ipv4(uint64_t address); + +} // namespace ada::serializers + +#endif // ADA_SERIALIZERS_H +/* end file include/ada/serializers.h */ +/* begin file include/ada/state.h */ +/** + * @file state.h + * @brief URL parser state machine states. + * + * Defines the states used by the URL parsing state machine as specified + * in the WHATWG URL Standard. + * + * @see https://url.spec.whatwg.org/#url-parsing + */ +#ifndef ADA_STATE_H +#define ADA_STATE_H + + +#include + +namespace ada { + +/** + * @brief States in the URL parsing state machine. + * + * The URL parser processes input through a sequence of states, each handling + * a specific part of the URL syntax. + * + * @see https://url.spec.whatwg.org/#url-parsing + */ +enum class state { + /** + * @see https://url.spec.whatwg.org/#authority-state + */ + AUTHORITY, + + /** + * @see https://url.spec.whatwg.org/#scheme-start-state + */ + SCHEME_START, + + /** + * @see https://url.spec.whatwg.org/#scheme-state + */ + SCHEME, + + /** + * @see https://url.spec.whatwg.org/#host-state + */ + HOST, + + /** + * @see https://url.spec.whatwg.org/#no-scheme-state + */ + NO_SCHEME, + + /** + * @see https://url.spec.whatwg.org/#fragment-state + */ + FRAGMENT, + + /** + * @see https://url.spec.whatwg.org/#relative-state + */ + RELATIVE_SCHEME, + + /** + * @see https://url.spec.whatwg.org/#relative-slash-state + */ + RELATIVE_SLASH, + + /** + * @see https://url.spec.whatwg.org/#file-state + */ + FILE, + + /** + * @see https://url.spec.whatwg.org/#file-host-state + */ + FILE_HOST, + + /** + * @see https://url.spec.whatwg.org/#file-slash-state + */ + FILE_SLASH, + + /** + * @see https://url.spec.whatwg.org/#path-or-authority-state + */ + PATH_OR_AUTHORITY, + + /** + * @see https://url.spec.whatwg.org/#special-authority-ignore-slashes-state + */ + SPECIAL_AUTHORITY_IGNORE_SLASHES, + + /** + * @see https://url.spec.whatwg.org/#special-authority-slashes-state + */ + SPECIAL_AUTHORITY_SLASHES, + + /** + * @see https://url.spec.whatwg.org/#special-relative-or-authority-state + */ + SPECIAL_RELATIVE_OR_AUTHORITY, + + /** + * @see https://url.spec.whatwg.org/#query-state + */ + QUERY, + + /** + * @see https://url.spec.whatwg.org/#path-state + */ + PATH, + + /** + * @see https://url.spec.whatwg.org/#path-start-state + */ + PATH_START, + + /** + * @see https://url.spec.whatwg.org/#cannot-be-a-base-url-path-state + */ + OPAQUE_PATH, + + /** + * @see https://url.spec.whatwg.org/#port-state + */ + PORT, +}; + +/** + * Converts a parser state to its string name for debugging. + * @param s The state to convert. + * @return A string representation of the state. + */ +ada_warn_unused std::string to_string(ada::state s); + +} // namespace ada + +#endif // ADA_STATE_H +/* end file include/ada/state.h */ +/* begin file include/ada/unicode.h */ +/** + * @file unicode.h + * @brief Definitions for all unicode specific functions. + */ +#ifndef ADA_UNICODE_H +#define ADA_UNICODE_H + + +#include +#include +#include + +/** + * Unicode operations. These functions are not part of our public API and may + * change at any time. + * + * @private + * @namespace ada::unicode + * @brief Includes the definitions for unicode operations + */ +namespace ada::unicode { + +/** + * @private + * We receive a UTF-8 string representing a domain name. + * If the string is percent encoded, we apply percent decoding. + * + * Given a domain, we need to identify its labels. + * They are separated by label-separators: + * + * U+002E (.) FULL STOP + * U+FF0E FULLWIDTH FULL STOP + * U+3002 IDEOGRAPHIC FULL STOP + * U+FF61 HALFWIDTH IDEOGRAPHIC FULL STOP + * + * They are all mapped to U+002E. + * + * We process each label into a string that should not exceed 63 octets. + * If the string is already punycode (starts with "xn--"), then we must + * scan it to look for unallowed code points. + * Otherwise, if the string is not pure ASCII, we need to transcode it + * to punycode by following RFC 3454 which requires us to + * - Map characters (see section 3), + * - Normalize (see section 4), + * - Reject forbidden characters, + * - Check for right-to-left characters and if so, check all requirements (see + * section 6), + * - Optionally reject based on unassigned code points (section 7). + * + * The Unicode standard provides a table of code points with a mapping, a list + * of forbidden code points and so forth. This table is subject to change and + * will vary based on the implementation. For Unicode 15, the table is at + * https://www.unicode.org/Public/idna/15.0.0/IdnaMappingTable.txt + * If you use ICU, they parse this table and map it to code using a Python + * script. + * + * The resulting strings should not exceed 255 octets according to RFC 1035 + * section 2.3.4. ICU checks for label size and domain size, but these errors + * are ignored. + * + * @see https://url.spec.whatwg.org/#concept-domain-to-ascii + * + */ +bool to_ascii(std::optional& out, std::string_view plain, + size_t first_percent); + +/** + * @private + * Checks if the input has tab or newline characters. + * + * @attention The has_tabs_or_newline function is a bottleneck and it is simple + * enough that compilers like GCC can 'autovectorize it'. + */ +ada_really_inline bool has_tabs_or_newline( + std::string_view user_input) noexcept; + +/** + * @private + * Checks if the input is a forbidden host code point. + * @see https://url.spec.whatwg.org/#forbidden-host-code-point + */ +ada_really_inline constexpr bool is_forbidden_host_code_point(char c) noexcept; + +/** + * @private + * Checks if the input contains a forbidden domain code point. + * @see https://url.spec.whatwg.org/#forbidden-domain-code-point + */ +ada_really_inline constexpr bool contains_forbidden_domain_code_point( + const char* input, size_t length) noexcept; + +/** + * @private + * Checks if the input contains a forbidden domain code point in which case + * the first bit is set to 1. If the input contains an upper case ASCII letter, + * then the second bit is set to 1. + * @see https://url.spec.whatwg.org/#forbidden-domain-code-point + */ +ada_really_inline constexpr uint8_t +contains_forbidden_domain_code_point_or_upper(const char* input, + size_t length) noexcept; + +/** + * @private + * Checks if the input is a forbidden domain code point. + * @see https://url.spec.whatwg.org/#forbidden-domain-code-point + */ +ada_really_inline constexpr bool is_forbidden_domain_code_point( + char c) noexcept; + +/** + * @private + * Checks if the input is alphanumeric, '+', '-' or '.' + */ +ada_really_inline constexpr bool is_alnum_plus(char c) noexcept; + +/** + * @private + * @details An ASCII hex digit is an ASCII upper hex digit or ASCII lower hex + * digit. An ASCII upper hex digit is an ASCII digit or a code point in the + * range U+0041 (A) to U+0046 (F), inclusive. An ASCII lower hex digit is an + * ASCII digit or a code point in the range U+0061 (a) to U+0066 (f), inclusive. + */ +ada_really_inline constexpr bool is_ascii_hex_digit(char c) noexcept; + +/** + * @private + * An ASCII digit is a code point in the range U+0030 (0) to U+0039 (9), + * inclusive. + */ +ada_really_inline constexpr bool is_ascii_digit(char c) noexcept; + +/** + * @private + * @details If a char is between U+0000 and U+007F inclusive, then it's an ASCII + * character. + */ +ada_really_inline constexpr bool is_ascii(char32_t c) noexcept; + +/** + * @private + * Checks if the input is a C0 control or space character. + * + * @details A C0 control or space is a C0 control or U+0020 SPACE. + * A C0 control is a code point in the range U+0000 NULL to U+001F INFORMATION + * SEPARATOR ONE, inclusive. + */ +ada_really_inline constexpr bool is_c0_control_or_space(char c) noexcept; + +/** + * @private + * Checks if the input is a ASCII tab or newline character. + * + * @details An ASCII tab or newline is U+0009 TAB, U+000A LF, or U+000D CR. + */ +ada_really_inline constexpr bool is_ascii_tab_or_newline(char c) noexcept; + +/** + * @private + * @details A double-dot path segment must be ".." or an ASCII case-insensitive + * match for ".%2e", "%2e.", or "%2e%2e". + */ +ada_really_inline constexpr bool is_double_dot_path_segment( + std::string_view input) noexcept; + +/** + * @private + * @details A single-dot path segment must be "." or an ASCII case-insensitive + * match for "%2e". + */ +ada_really_inline constexpr bool is_single_dot_path_segment( + std::string_view input) noexcept; + +/** + * @private + * @details ipv4 character might contain 0-9 or a-f character ranges. + */ +ada_really_inline constexpr bool is_lowercase_hex(char c) noexcept; + +/** + * @private + * @details Convert hex to binary. Caller is responsible to ensure that + * the parameter is an hexadecimal digit (0-9, A-F, a-f). + */ +ada_really_inline unsigned constexpr convert_hex_to_binary(char c) noexcept; + +/** + * @private + * first_percent should be = input.find('%') + * + * @todo It would be faster as noexcept maybe, but it could be unsafe since. + * @author Node.js + * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L245 + * @see https://encoding.spec.whatwg.org/#utf-8-decode-without-bom + */ +std::string percent_decode(std::string_view input, size_t first_percent); + +/** + * Decode an application/x-www-form-urlencoded component: map '+' to space, + * then percent-decode. Single allocation; no intermediate string. + * + * @param input A form-urlencoded component (key or value). + * @return The decoded string. + * @see https://url.spec.whatwg.org/#concept-urlencoded-parser + */ +std::string form_urlencoded_decode(std::string_view input); + +/** + * @private + * Returns a percent-encoding string whether percent encoding was needed or not. + * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L226 + */ +std::string percent_encode(std::string_view input, + const uint8_t character_set[]); +/** + * @private + * Returns a percent-encoded string version of input, while starting the percent + * encoding at the provided index. + * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L226 + */ +std::string percent_encode(std::string_view input, + const uint8_t character_set[], size_t index); +/** + * @private + * Returns true if percent encoding was needed, in which case, we store + * the percent-encoded content in 'out'. If the boolean 'append' is set to + * true, the content is appended to 'out'. + * If percent encoding is not needed, out is left unchanged. + * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L226 + */ +template +bool percent_encode(std::string_view input, const uint8_t character_set[], + std::string& out); +/** + * @private + * Returns the index at which percent encoding should start, or (equivalently), + * the length of the prefix that does not require percent encoding. + */ +ada_really_inline size_t percent_encode_index(std::string_view input, + const uint8_t character_set[]); +/** + * @private + * Lowers the string in-place, assuming that the content is ASCII. + * Return true if the content was ASCII. + */ +constexpr bool to_lower_ascii(char* input, size_t length) noexcept; +} // namespace ada::unicode + +#endif // ADA_UNICODE_H +/* end file include/ada/unicode.h */ +/* begin file include/ada/url_base-inl.h */ +/** + * @file url_base-inl.h + * @brief Inline functions for url base + */ +#ifndef ADA_URL_BASE_INL_H +#define ADA_URL_BASE_INL_H + + +#include +#if ADA_REGULAR_VISUAL_STUDIO +#include +#endif // ADA_REGULAR_VISUAL_STUDIO + +namespace ada { + +[[nodiscard]] ada_really_inline constexpr bool url_base::is_special() + const noexcept { + return type != ada::scheme::NOT_SPECIAL; +} + +[[nodiscard]] inline uint16_t url_base::get_special_port() const noexcept { + return ada::scheme::get_special_port(type); +} + +[[nodiscard]] ada_really_inline uint16_t +url_base::scheme_default_port() const noexcept { + return scheme::get_special_port(type); +} + +} // namespace ada + +#endif // ADA_URL_BASE_INL_H +/* end file include/ada/url_base-inl.h */ +/* begin file include/ada/url-inl.h */ +/** + * @file url-inl.h + * @brief Definitions for the URL + */ +#ifndef ADA_URL_INL_H +#define ADA_URL_INL_H + + +#include +#include +#include +#include +#if ADA_REGULAR_VISUAL_STUDIO +#include +#endif // ADA_REGULAR_VISUAL_STUDIO + +namespace ada { +[[nodiscard]] ada_really_inline bool url::has_credentials() const noexcept { + return !username.empty() || !password.empty(); +} +[[nodiscard]] ada_really_inline bool url::has_port() const noexcept { + return port.has_value(); +} +[[nodiscard]] inline bool url::cannot_have_credentials_or_port() const { + return !host.has_value() || host->empty() || type == ada::scheme::type::FILE; +} +[[nodiscard]] inline bool url::has_empty_hostname() const noexcept { + if (!host.has_value()) { + return false; + } + return host->empty(); +} +[[nodiscard]] inline bool url::has_hostname() const noexcept { + return host.has_value(); +} +inline std::ostream& operator<<(std::ostream& out, const ada::url& u) { + return out << u.to_string(); +} + +[[nodiscard]] size_t url::get_pathname_length() const noexcept { + return path.size(); +} + +[[nodiscard]] constexpr std::string_view url::get_pathname() const noexcept { + return path; +} + +[[nodiscard]] ada_really_inline ada::url_components url::get_components() + const { + url_components out{}; + + // protocol ends with ':'. for example: "https:" + out.protocol_end = uint32_t(get_protocol().size()); + + // Trailing index is always the next character of the current one. + // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores) + size_t running_index = out.protocol_end; + + if (host.has_value()) { + // 2 characters for "//" and 1 character for starting index + out.host_start = out.protocol_end + 2; + + if (has_credentials()) { + out.username_end = uint32_t(out.host_start + username.size()); + + out.host_start += uint32_t(username.size()); + + if (!password.empty()) { + out.host_start += uint32_t(password.size() + 1); + } + + out.host_end = uint32_t(out.host_start + host->size()); + } else { + out.username_end = out.host_start; + + // Host does not start with "@" if it does not include credentials. + out.host_end = uint32_t(out.host_start + host->size()) - 1; + } + + running_index = out.host_end + 1; + } else { + // Update host start and end date to the same index, since it does not + // exist. + out.host_start = out.protocol_end; + out.host_end = out.host_start; + + if (!has_opaque_path && path.starts_with("//")) { + // If url's host is null, url does not have an opaque path, url's path's + // size is greater than 1, and url's path[0] is the empty string, then + // append U+002F (/) followed by U+002E (.) to output. + running_index = out.protocol_end + 2; + } else { + running_index = out.protocol_end; + } + } + + if (port.has_value()) { + out.port = *port; + running_index += helpers::fast_digit_count(*port) + 1; // Port omits ':' + } + + out.pathname_start = uint32_t(running_index); + + running_index += path.size(); + + if (query.has_value()) { + out.search_start = uint32_t(running_index); + running_index += get_search().size(); + if (get_search().empty()) { + running_index++; + } + } + + if (hash.has_value()) { + out.hash_start = uint32_t(running_index); + } + + return out; +} + +inline void url::update_base_hostname(std::string_view input) { host = input; } + +inline void url::update_unencoded_base_hash(std::string_view input) { + // We do the percent encoding + hash = unicode::percent_encode(input, + ada::character_sets::FRAGMENT_PERCENT_ENCODE); +} + +inline void url::update_base_search(std::string_view input, + const uint8_t query_percent_encode_set[]) { + query = ada::unicode::percent_encode(input, query_percent_encode_set); +} + +inline void url::update_base_search(std::optional&& input) { + query = std::move(input); +} + +inline void url::update_base_pathname(const std::string_view input) { + path = input; +} + +inline void url::update_base_username(const std::string_view input) { + username = input; +} + +inline void url::update_base_password(const std::string_view input) { + password = input; +} + +inline void url::update_base_port(std::optional input) { + port = input; +} + +constexpr void url::clear_pathname() { path.clear(); } + +constexpr void url::clear_search() { query = std::nullopt; } + +[[nodiscard]] constexpr bool url::has_hash() const noexcept { + return hash.has_value(); +} + +[[nodiscard]] constexpr bool url::has_search() const noexcept { + return query.has_value(); +} + +constexpr void url::set_protocol_as_file() { type = ada::scheme::type::FILE; } + +inline void url::set_scheme(std::string&& new_scheme) noexcept { + type = ada::scheme::get_scheme_type(new_scheme); + // We only move the 'scheme' if it is non-special. + if (!is_special()) { + non_special_scheme = std::move(new_scheme); + } +} + +constexpr void url::copy_scheme(ada::url&& u) { + non_special_scheme = u.non_special_scheme; + type = u.type; +} + +constexpr void url::copy_scheme(const ada::url& u) { + non_special_scheme = u.non_special_scheme; + type = u.type; +} + +[[nodiscard]] ada_really_inline std::string url::get_href() const { + if (is_special() && host.has_value() && username.empty() && + password.empty() && !port.has_value()) [[likely]] { + const std::string_view scheme = ada::scheme::details::is_special_list[type]; + const size_t host_size = host->size(); + const size_t path_size = path.size(); + const size_t query_size = query.has_value() ? query->size() : 0; + const size_t hash_size = hash.has_value() ? hash->size() : 0; + const size_t total = scheme.size() + 3 + host_size + path_size + + (query.has_value() ? query_size + 1 : 0) + + (hash.has_value() ? hash_size + 1 : 0); + std::string output(total, '\0'); + char* p = output.data(); + std::memcpy(p, scheme.data(), scheme.size()); + p += scheme.size(); + p[0] = ':'; + p[1] = '/'; + p[2] = '/'; + p += 3; + // NOLINTNEXTLINE(bugprone-not-null-terminated-result) + std::memcpy(p, host->data(), host_size); + p += host_size; + std::memcpy(p, path.data(), path_size); + p += path_size; + if (query.has_value()) { + *p++ = '?'; + // NOLINTNEXTLINE(bugprone-not-null-terminated-result) + std::memcpy(p, query->data(), query_size); + p += query_size; + } + if (hash.has_value()) { + *p++ = '#'; + // NOLINTNEXTLINE(bugprone-not-null-terminated-result) + std::memcpy(p, hash->data(), hash_size); + } + return output; + } + + std::string output; + output.reserve(get_href_size()); + + if (is_special()) { + output.append(ada::scheme::details::is_special_list[type]); + output += ':'; + } else { + output.append(non_special_scheme); + output += ':'; + } + + if (host.has_value()) { + output += '/'; + output += '/'; + if (has_credentials()) { + output.append(username); + if (!password.empty()) { + output += ':'; + output.append(password); + } + output += '@'; + } + output.append(*host); + if (port.has_value()) { + output += ':'; + char port_buf[5]; + auto [ptr, ec] = std::to_chars(port_buf, port_buf + 5, *port); + (void)ec; + output.append(port_buf, static_cast(ptr - port_buf)); + } + } else if (!has_opaque_path && path.starts_with("//")) { + // If url's host is null, url does not have an opaque path, url's path's + // size is greater than 1, and url's path[0] is the empty string, then + // append U+002F (/) followed by U+002E (.) to output. + output += '/'; + output += '.'; + } + output.append(path); + if (query.has_value()) { + output += '?'; + output.append(*query); + } + if (hash.has_value()) { + output += '#'; + output.append(*hash); + } + return output; +} + +[[nodiscard]] inline size_t url::get_href_size() const noexcept { + size_t size = 0; + if (is_special()) { + size += ada::scheme::details::is_special_list[type].size() + 1; + } else { + size += non_special_scheme.size() + 1; + } + if (host.has_value()) { + size += host->size(); + size += 2; + if (has_credentials()) { + size += username.size(); + if (!password.empty()) { + size += 1 + password.size(); + } + size += 1; + } + if (port.has_value()) { + size += 1; + uint16_t p = *port; + size += (p >= 10000) ? 5 + : (p >= 1000) ? 4 + : (p >= 100) ? 3 + : (p >= 10) ? 2 + : 1; + } + } else if (!has_opaque_path && path.starts_with("//")) { + size += 2; + } + size += path.size(); + if (query.has_value()) { + size += 1 + query->size(); + } + if (hash.has_value()) { + size += 1 + hash->size(); + } + return size; +} + +ada_really_inline size_t url::parse_port(std::string_view view, + bool check_trailing_content) noexcept { + ada_log("parse_port('", view, "') ", view.size()); + if (!view.empty() && view[0] == '-') { + ada_log("parse_port: view[0] == '0' && view.size() > 1"); + is_valid = false; + return 0; + } + uint16_t parsed_port{}; + auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port); + if (r.ec == std::errc::result_out_of_range) { + ada_log("parse_port: r.ec == std::errc::result_out_of_range"); + is_valid = false; + return 0; + } + ada_log("parse_port: ", parsed_port); + const auto consumed = size_t(r.ptr - view.data()); + ada_log("parse_port: consumed ", consumed); + if (check_trailing_content) { + is_valid &= + (consumed == view.size() || view[consumed] == '/' || + view[consumed] == '?' || (is_special() && view[consumed] == '\\')); + } + ada_log("parse_port: is_valid = ", is_valid); + if (is_valid) { + // scheme_default_port can return 0, and we should allow 0 as a base port. + auto default_port = scheme_default_port(); + bool is_port_valid = (default_port == 0 && parsed_port == 0) || + (default_port != parsed_port); + port = (r.ec == std::errc() && is_port_valid) ? std::optional(parsed_port) + : std::nullopt; + } + return consumed; +} + +} // namespace ada + +#endif // ADA_URL_H +/* end file include/ada/url-inl.h */ +/* begin file include/ada/url_components-inl.h */ +/** + * @file url_components.h + * @brief Declaration for the URL Components + */ +#ifndef ADA_URL_COMPONENTS_INL_H +#define ADA_URL_COMPONENTS_INL_H + + +namespace ada { + +[[nodiscard]] constexpr bool url_components::check_offset_consistency() + const noexcept { + /** + * https://user:pass@example.com:1234/foo/bar?baz#quux + * | | | | ^^^^| | | + * | | | | | | | `----- hash_start + * | | | | | | `--------- search_start + * | | | | | `----------------- pathname_start + * | | | | `--------------------- port + * | | | `----------------------- host_end + * | | `---------------------------------- host_start + * | `--------------------------------------- username_end + * `--------------------------------------------- protocol_end + */ + // These conditions can be made more strict. + if (protocol_end == url_components::omitted) { + return false; + } + uint32_t index = protocol_end; + + if (username_end == url_components::omitted) { + return false; + } + if (username_end < index) { + return false; + } + index = username_end; + + if (host_start == url_components::omitted) { + return false; + } + if (host_start < index) { + return false; + } + index = host_start; + + if (port != url_components::omitted) { + if (port > 0xffff) { + return false; + } + uint32_t port_length = helpers::fast_digit_count(port) + 1; + if (index + port_length < index) { + return false; + } + index += port_length; + } + + if (pathname_start == url_components::omitted) { + return false; + } + if (pathname_start < index) { + return false; + } + index = pathname_start; + + if (search_start != url_components::omitted) { + if (search_start < index) { + return false; + } + index = search_start; + } + + if (hash_start != url_components::omitted) { + if (hash_start < index) { + return false; + } + } + + return true; +} + +} // namespace ada +#endif +/* end file include/ada/url_components-inl.h */ +/* begin file include/ada/url_aggregator.h */ +/** + * @file url_aggregator.h + * @brief Declaration for the `ada::url_aggregator` class. + * + * This file contains the `ada::url_aggregator` struct which represents a parsed + * URL using a single buffer with component offsets. This is the default and + * most memory-efficient URL representation in Ada. + * + * @see url.h for an alternative representation using separate strings + */ +#ifndef ADA_URL_AGGREGATOR_H +#define ADA_URL_AGGREGATOR_H + +#include +#include +#include +#include + + +namespace ada { + +namespace parser {} + +/** + * @brief Memory-efficient URL representation using a single buffer. + * + * The `url_aggregator` stores the entire normalized URL in a single string + * buffer and tracks component boundaries using offsets. This design minimizes + * memory allocations and is ideal for read-mostly access patterns. + * + * Getter methods return `std::string_view` pointing into the internal buffer. + * These views are lightweight (no allocation) but become invalid if the + * url_aggregator is modified or destroyed. + * + * @warning Views returned by getters (e.g., `get_pathname()`) are invalidated + * when any setter is called. Do not use a getter's result as input to a + * setter on the same object without copying first. + * + * @note This is the default URL type returned by `ada::parse()`. + * + * @see url For an alternative using separate std::string instances + */ +struct url_aggregator : url_base { + url_aggregator() = default; + url_aggregator(const url_aggregator& u) = default; + url_aggregator(url_aggregator&& u) noexcept = default; + url_aggregator& operator=(url_aggregator&& u) noexcept = default; + url_aggregator& operator=(const url_aggregator& u) = default; + ~url_aggregator() override = default; + + /** + * The setter functions follow the steps defined in the URL Standard. + * + * The url_aggregator has a single buffer that contains the entire normalized + * URL. The various components are represented as offsets into that buffer. + * When you call get_pathname(), for example, you get a std::string_view that + * points into that buffer. If the url_aggregator is modified, the buffer may + * be reallocated, and the std::string_view you obtained earlier may become + * invalid. In particular, this implies that you cannot modify the URL using + * a setter function with a std::string_view that points into the + * url_aggregator E.g., the following is incorrect: + * url->set_hostname(url->get_pathname()). + * You must first copy the pathname to a separate string. + * std::string pathname(url->get_pathname()); + * url->set_hostname(pathname); + * + * The caller is responsible for ensuring that the url_aggregator is not + * modified while any std::string_view obtained from it is in use. + */ + bool set_href(std::string_view input); + bool set_host(std::string_view input); + bool set_hostname(std::string_view input); + bool set_protocol(std::string_view input); + bool set_username(std::string_view input); + bool set_password(std::string_view input); + bool set_port(std::string_view input); + bool set_pathname(std::string_view input); + void set_search(std::string_view input); + void set_hash(std::string_view input); + + /** + * Validates whether the hostname is a valid domain according to RFC 1034. + * @return `true` if the domain is valid, `false` otherwise. + */ + [[nodiscard]] bool has_valid_domain() const noexcept override; + + /** + * Returns the URL's origin (scheme + host + port for special URLs). + * @return A newly allocated string containing the serialized origin. + * @see https://url.spec.whatwg.org/#concept-url-origin + */ + [[nodiscard]] std::string get_origin() const override; + + /** + * Returns the full serialized URL (the href) as a string_view. + * Does not allocate memory. The returned view becomes invalid if this + * url_aggregator is modified or destroyed. + * @return A string_view into the internal buffer. + * @see https://url.spec.whatwg.org/#dom-url-href + */ + [[nodiscard]] constexpr std::string_view get_href() const noexcept + ada_lifetime_bound; + + /** + * Returns the byte length of the serialized URL without allocating a string. + * @return Size of the href in bytes. + */ + [[nodiscard]] constexpr size_t get_href_size() const noexcept; + + /** + * Returns the URL's username component. + * Does not allocate memory. The returned view becomes invalid if this + * url_aggregator is modified or destroyed. + * @return A string_view of the username. + * @see https://url.spec.whatwg.org/#dom-url-username + */ + [[nodiscard]] std::string_view get_username() const ada_lifetime_bound; + + /** + * Returns the URL's password component. + * Does not allocate memory. The returned view becomes invalid if this + * url_aggregator is modified or destroyed. + * @return A string_view of the password. + * @see https://url.spec.whatwg.org/#dom-url-password + */ + [[nodiscard]] std::string_view get_password() const ada_lifetime_bound; + + /** + * Returns the URL's port as a string (e.g., "8080"). + * Does not allocate memory. Returns empty view if no port is set. + * The returned view becomes invalid if this url_aggregator is modified. + * @return A string_view of the port. + * @see https://url.spec.whatwg.org/#dom-url-port + */ + [[nodiscard]] std::string_view get_port() const ada_lifetime_bound; + + /** + * Returns the URL's fragment prefixed with '#' (e.g., "#section"). + * Does not allocate memory. Returns empty view if no fragment is set. + * The returned view becomes invalid if this url_aggregator is modified. + * @return A string_view of the hash. + * @see https://url.spec.whatwg.org/#dom-url-hash + */ + [[nodiscard]] std::string_view get_hash() const ada_lifetime_bound; + + /** + * Returns the URL's host and port (e.g., "example.com:8080"). + * Does not allocate memory. Returns empty view if no host is set. + * The returned view becomes invalid if this url_aggregator is modified. + * @return A string_view of host:port. + * @see https://url.spec.whatwg.org/#dom-url-host + */ + [[nodiscard]] std::string_view get_host() const ada_lifetime_bound; + + /** + * Returns the URL's hostname (without port). + * Does not allocate memory. Returns empty view if no host is set. + * The returned view becomes invalid if this url_aggregator is modified. + * @return A string_view of the hostname. + * @see https://url.spec.whatwg.org/#dom-url-hostname + */ + [[nodiscard]] std::string_view get_hostname() const ada_lifetime_bound; + + /** + * Returns the URL's path component. + * Does not allocate memory. The returned view becomes invalid if this + * url_aggregator is modified or destroyed. + * @return A string_view of the pathname. + * @see https://url.spec.whatwg.org/#dom-url-pathname + */ + [[nodiscard]] constexpr std::string_view get_pathname() const + ada_lifetime_bound; + + /** + * Returns the byte length of the pathname without creating a string. + * @return Size of the pathname in bytes. + * @see https://url.spec.whatwg.org/#dom-url-pathname + */ + [[nodiscard]] ada_really_inline uint32_t get_pathname_length() const noexcept; + + /** + * Returns the URL's query string prefixed with '?' (e.g., "?foo=bar"). + * Does not allocate memory. Returns empty view if no query is set. + * The returned view becomes invalid if this url_aggregator is modified. + * @return A string_view of the search/query. + * @see https://url.spec.whatwg.org/#dom-url-search + */ + [[nodiscard]] std::string_view get_search() const ada_lifetime_bound; + + /** + * Returns the URL's scheme followed by a colon (e.g., "https:"). + * Does not allocate memory. The returned view becomes invalid if this + * url_aggregator is modified or destroyed. + * @return A string_view of the protocol. + * @see https://url.spec.whatwg.org/#dom-url-protocol + */ + [[nodiscard]] std::string_view get_protocol() const ada_lifetime_bound; + + /** + * Checks if the URL has credentials (non-empty username or password). + * @return `true` if username or password is non-empty, `false` otherwise. + */ + [[nodiscard]] ada_really_inline constexpr bool has_credentials() + const noexcept; + + /** + * Returns the URL component offsets for efficient serialization. + * + * The components represent byte offsets into the serialized URL: + * ``` + * https://user:pass@example.com:1234/foo/bar?baz#quux + * | | | | ^^^^| | | + * | | | | | | | `----- hash_start + * | | | | | | `--------- search_start + * | | | | | `----------------- pathname_start + * | | | | `--------------------- port + * | | | `----------------------- host_end + * | | `---------------------------------- host_start + * | `--------------------------------------- username_end + * `--------------------------------------------- protocol_end + * ``` + * @return A constant reference to the url_components struct. + * @see https://github.com/servo/rust-url + */ + [[nodiscard]] ada_really_inline const url_components& get_components() + const noexcept; + + /** + * Returns a JSON string representation of this URL for debugging. + * @return A JSON-formatted string with all URL components. + */ + [[nodiscard]] std::string to_string() const override; + + /** + * Returns a visual diagram showing component boundaries in the URL. + * Useful for debugging and understanding URL structure. + * @return A multi-line string diagram. + */ + [[nodiscard]] std::string to_diagram() const; + + /** + * Validates internal consistency of component offsets (for debugging). + * @return `true` if offsets are consistent, `false` if corrupted. + */ + [[nodiscard]] constexpr bool validate() const noexcept; + + /** + * Checks if the URL has an empty hostname (host is set but empty string). + * @return `true` if host exists but is empty, `false` otherwise. + */ + [[nodiscard]] constexpr bool has_empty_hostname() const noexcept; + + /** + * Checks if the URL has a hostname (including empty hostnames). + * @return `true` if host is present, `false` otherwise. + */ + [[nodiscard]] constexpr bool has_hostname() const noexcept; + + /** + * Checks if the URL has a non-empty username. + * @return `true` if username is non-empty, `false` otherwise. + */ + [[nodiscard]] constexpr bool has_non_empty_username() const noexcept; + + /** + * Checks if the URL has a non-empty password. + * @return `true` if password is non-empty, `false` otherwise. + */ + [[nodiscard]] constexpr bool has_non_empty_password() const noexcept; + + /** + * Checks if the URL has a non-default port explicitly specified. + * @return `true` if a port is present, `false` otherwise. + */ + [[nodiscard]] constexpr bool has_port() const noexcept; + + /** + * Checks if the URL has a password component (may be empty). + * @return `true` if password is present, `false` otherwise. + */ + [[nodiscard]] constexpr bool has_password() const noexcept; + + /** + * Checks if the URL has a fragment/hash component. + * @return `true` if hash is present, `false` otherwise. + */ + [[nodiscard]] constexpr bool has_hash() const noexcept override; + + /** + * Checks if the URL has a query/search component. + * @return `true` if query is present, `false` otherwise. + */ + [[nodiscard]] constexpr bool has_search() const noexcept override; + + /** + * Removes the port from the URL. + */ + inline void clear_port(); + + /** + * Removes the hash/fragment from the URL. + */ + inline void clear_hash(); + + /** + * Removes the query/search string from the URL. + */ + inline void clear_search() override; + + private: + // helper methods + friend void helpers::strip_trailing_spaces_from_opaque_path( + url_aggregator& url); + // parse_url methods + friend url_aggregator parser::parse_url( + std::string_view, const url_aggregator*); + + friend url_aggregator parser::parse_url_impl( + std::string_view, const url_aggregator*); + friend url_aggregator parser::parse_url_impl( + std::string_view, const url_aggregator*); + template + friend bool parser::try_parse_simple_absolute(std::string_view, result_type&); + +#if ADA_INCLUDE_URL_PATTERN + // url_pattern methods + template + friend tl::expected, errors> + parse_url_pattern_impl( + std::variant&& input, + const std::string_view* base_url, const url_pattern_options* options); +#endif // ADA_INCLUDE_URL_PATTERN + + // components is declared before buffer so that the offset fields land + // close to url_base in memory, improving cache locality for getter calls. + // Note: exact cache-line placement is implementation- and platform-dependent. + url_components components{}; + std::string buffer{}; + + /** + * Returns true if neither the search, nor the hash nor the pathname + * have been set. + * @return true if the buffer is ready to receive the path. + */ + [[nodiscard]] ada_really_inline bool is_at_path() const noexcept; + + inline void add_authority_slashes_if_needed(); + + /** + * To optimize performance, you may indicate how much memory to allocate + * within this instance. + */ + constexpr void reserve(uint32_t capacity); + + ada_really_inline size_t parse_port(std::string_view view, + bool check_trailing_content) override; + + ada_really_inline size_t parse_port(std::string_view view) override { + return this->parse_port(view, false); + } + + /** + * Return true on success. The 'in_place' parameter indicates whether the + * the string_view input is pointing in the buffer. When in_place is false, + * we must nearly always update the buffer. + * @see https://url.spec.whatwg.org/#concept-ipv4-parser + */ + [[nodiscard]] bool parse_ipv4(std::string_view input, bool in_place); + + /** + * Return true on success. + * @see https://url.spec.whatwg.org/#concept-ipv6-parser + */ + [[nodiscard]] bool parse_ipv6(std::string_view input); + + /** + * Return true on success. + * @see https://url.spec.whatwg.org/#concept-opaque-host-parser + */ + [[nodiscard]] bool parse_opaque_host(std::string_view input); + + ada_really_inline void parse_path(std::string_view input); + + /** + * A URL cannot have a username/password/port if its host is null or the empty + * string, or its scheme is "file". + */ + [[nodiscard]] constexpr bool cannot_have_credentials_or_port() const; + + template + bool set_host_or_hostname(std::string_view input); + + ada_really_inline bool parse_host(std::string_view input); + + inline void update_base_authority(std::string_view base_buffer, + const url_components& base); + inline void update_unencoded_base_hash(std::string_view input); + inline void update_base_hostname(std::string_view input); + inline void update_base_search(std::string_view input); + inline void update_base_search(std::string_view input, + const uint8_t* query_percent_encode_set); + inline void update_base_pathname(std::string_view input); + inline void update_base_username(std::string_view input); + inline void append_base_username(std::string_view input); + inline void update_base_password(std::string_view input); + inline void append_base_password(std::string_view input); + inline void update_base_port(uint32_t input); + inline void append_base_pathname(std::string_view input); + [[nodiscard]] inline uint32_t retrieve_base_port() const; + constexpr void clear_hostname(); + constexpr void clear_password(); + constexpr void clear_pathname() override; + [[nodiscard]] constexpr bool has_dash_dot() const noexcept; + void delete_dash_dot(); + inline void consume_prepared_path(std::string_view input); + template + [[nodiscard]] ada_really_inline bool parse_scheme_with_colon( + std::string_view input); + ada_really_inline uint32_t replace_and_resize(uint32_t start, uint32_t end, + std::string_view input); + [[nodiscard]] constexpr bool has_authority() const noexcept; + constexpr void set_protocol_as_file(); + inline void set_scheme(std::string_view new_scheme); + /** + * Fast function to set the scheme from a view with a colon in the + * buffer, does not change type. + */ + inline void set_scheme_from_view_with_colon( + std::string_view new_scheme_with_colon); + inline void copy_scheme(const url_aggregator& u); + + inline void update_host_to_base_host(const std::string_view input); + +}; // url_aggregator + +inline std::ostream& operator<<(std::ostream& out, const url& u); +} // namespace ada + +#endif +/* end file include/ada/url_aggregator.h */ +/* begin file include/ada/url_aggregator-inl.h */ +/** + * @file url_aggregator-inl.h + * @brief Inline functions for url aggregator + */ +#ifndef ADA_URL_AGGREGATOR_INL_H +#define ADA_URL_AGGREGATOR_INL_H + +/* begin file include/ada/unicode-inl.h */ +/** + * @file unicode-inl.h + * @brief Definitions for unicode operations. + */ +#ifndef ADA_UNICODE_INL_H +#define ADA_UNICODE_INL_H + +/** + * Unicode operations. These functions are not part of our public API and may + * change at any time. + * + * private + * @namespace ada::unicode + * @brief Includes the declarations for unicode operations + */ +namespace ada::unicode { +ada_really_inline size_t percent_encode_index(const std::string_view input, + const uint8_t character_set[]) { + const char* data = input.data(); + const size_t size = input.size(); + + // Process 8 bytes at a time using unrolled loop + size_t i = 0; + for (; i + 8 <= size; i += 8) { + unsigned char chunk[8]; + std::memcpy(&chunk, data + i, + 8); // entices compiler to unconditionally process 8 characters + + // Check 8 characters at once + for (size_t j = 0; j < 8; j++) { + if (character_sets::bit_at(character_set, chunk[j])) { + return i + j; + } + } + } + + // Handle remaining bytes + for (; i < size; i++) { + if (character_sets::bit_at(character_set, data[i])) { + return i; + } + } + + return size; +} +} // namespace ada::unicode + +#endif // ADA_UNICODE_INL_H +/* end file include/ada/unicode-inl.h */ + +#include +#include +#include + +namespace ada { + +inline void url_aggregator::update_base_authority( + std::string_view base_buffer, const ada::url_components& base) { + std::string_view input = base_buffer.substr( + base.protocol_end, base.host_start - base.protocol_end); + ada_log("url_aggregator::update_base_authority ", input); + + bool input_starts_with_dash = input.starts_with("//"); + uint32_t diff = components.host_start - components.protocol_end; + + buffer.erase(components.protocol_end, + components.host_start - components.protocol_end); + components.username_end = components.protocol_end; + + if (input_starts_with_dash) { + input.remove_prefix(2); + diff += 2; // add "//" + buffer.insert(components.protocol_end, "//"); + components.username_end += 2; + } + + size_t password_delimiter = input.find(':'); + + // Check if input contains both username and password by checking the + // delimiter: ":" A typical input that contains authority would be "user:pass" + if (password_delimiter != std::string_view::npos) { + // Insert both username and password + std::string_view username = input.substr(0, password_delimiter); + std::string_view password = input.substr(password_delimiter + 1); + + buffer.insert(components.protocol_end + diff, username); + diff += uint32_t(username.size()); + buffer.insert(components.protocol_end + diff, ":"); + components.username_end = components.protocol_end + diff; + buffer.insert(components.protocol_end + diff + 1, password); + diff += uint32_t(password.size()) + 1; + } else if (!input.empty()) { + // Insert only username + buffer.insert(components.protocol_end + diff, input); + components.username_end = + components.protocol_end + diff + uint32_t(input.size()); + diff += uint32_t(input.size()); + } + + components.host_start += diff; + + if (buffer.size() > base.host_start && buffer[base.host_start] != '@') { + buffer.insert(components.host_start, "@"); + diff++; + } + components.host_end += diff; + components.pathname_start += diff; + if (components.search_start != url_components::omitted) { + components.search_start += diff; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += diff; + } +} + +inline void url_aggregator::update_unencoded_base_hash(std::string_view input) { + ada_log("url_aggregator::update_unencoded_base_hash ", input, " [", + input.size(), " bytes], buffer is '", buffer, "' [", buffer.size(), + " bytes] components.hash_start = ", components.hash_start); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (components.hash_start != url_components::omitted) { + buffer.resize(components.hash_start); + } + components.hash_start = uint32_t(buffer.size()); + buffer += "#"; + bool encoding_required = unicode::percent_encode( + input, ada::character_sets::FRAGMENT_PERCENT_ENCODE, buffer); + // When encoding_required is false, then buffer is left unchanged, and percent + // encoding was not deemed required. + if (!encoding_required) { + buffer.append(input); + } + ada_log("url_aggregator::update_unencoded_base_hash final buffer is '", + buffer, "' [", buffer.size(), " bytes]"); + ADA_ASSERT_TRUE(validate()); +} + +ada_really_inline uint32_t url_aggregator::replace_and_resize( + uint32_t start, uint32_t end, std::string_view input) { + uint32_t current_length = end - start; + uint32_t input_size = uint32_t(input.size()); + uint32_t new_difference = input_size - current_length; + + if (current_length == 0) { + buffer.insert(start, input); + } else if (input_size == current_length) { + buffer.replace(start, input_size, input); + } else if (input_size < current_length) { + buffer.erase(start, current_length - input_size); + buffer.replace(start, input_size, input); + } else { + buffer.replace(start, current_length, input.substr(0, current_length)); + buffer.insert(start + current_length, input.substr(current_length)); + } + + return new_difference; +} + +inline void url_aggregator::update_base_hostname(const std::string_view input) { + ada_log("url_aggregator::update_base_hostname ", input, " [", input.size(), + " bytes], buffer is '", buffer, "' [", buffer.size(), " bytes]"); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + + // This next line is required for when parsing a URL like `foo://` + add_authority_slashes_if_needed(); + + bool has_credentials = components.protocol_end + 2 < components.host_start; + uint32_t new_difference = + replace_and_resize(components.host_start, components.host_end, input); + + if (has_credentials) { + buffer.insert(components.host_start, "@"); + new_difference++; + } + components.host_end += new_difference; + components.pathname_start += new_difference; + if (components.search_start != url_components::omitted) { + components.search_start += new_difference; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += new_difference; + } + ADA_ASSERT_TRUE(validate()); +} + +[[nodiscard]] ada_really_inline uint32_t +url_aggregator::get_pathname_length() const noexcept { + ada_log("url_aggregator::get_pathname_length"); + uint32_t ending_index = uint32_t(buffer.size()); + if (components.search_start != url_components::omitted) { + ending_index = components.search_start; + } else if (components.hash_start != url_components::omitted) { + ending_index = components.hash_start; + } + return ending_index - components.pathname_start; +} + +[[nodiscard]] ada_really_inline bool url_aggregator::is_at_path() + const noexcept { + return buffer.size() == components.pathname_start; +} + +inline void url_aggregator::update_base_search(std::string_view input) { + ada_log("url_aggregator::update_base_search ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (input.empty()) { + clear_search(); + return; + } + + if (input[0] == '?') { + input.remove_prefix(1); + } + + if (components.hash_start == url_components::omitted) { + if (components.search_start == url_components::omitted) { + components.search_start = uint32_t(buffer.size()); + buffer += "?"; + } else { + buffer.resize(components.search_start + 1); + } + + buffer.append(input); + } else { + if (components.search_start == url_components::omitted) { + components.search_start = components.hash_start; + } else { + buffer.erase(components.search_start, + components.hash_start - components.search_start); + components.hash_start = components.search_start; + } + + buffer.insert(components.search_start, "?"); + buffer.insert(components.search_start + 1, input); + components.hash_start += uint32_t(input.size() + 1); // Do not forget `?` + } + + ADA_ASSERT_TRUE(validate()); +} + +inline void url_aggregator::update_base_search( + std::string_view input, const uint8_t query_percent_encode_set[]) { + ada_log("url_aggregator::update_base_search ", input, + " with encoding parameter ", to_string(), "\n", to_diagram()); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + + if (components.hash_start == url_components::omitted) { + if (components.search_start == url_components::omitted) { + components.search_start = uint32_t(buffer.size()); + buffer += "?"; + } else { + buffer.resize(components.search_start + 1); + } + + bool encoding_required = + unicode::percent_encode(input, query_percent_encode_set, buffer); + // When encoding_required is false, then buffer is left unchanged, and + // percent encoding was not deemed required. + if (!encoding_required) { + buffer.append(input); + } + } else { + if (components.search_start == url_components::omitted) { + components.search_start = components.hash_start; + } else { + buffer.erase(components.search_start, + components.hash_start - components.search_start); + components.hash_start = components.search_start; + } + + buffer.insert(components.search_start, "?"); + size_t idx = + ada::unicode::percent_encode_index(input, query_percent_encode_set); + if (idx == input.size()) { + buffer.insert(components.search_start + 1, input); + components.hash_start += uint32_t(input.size() + 1); // Do not forget `?` + } else { + buffer.insert(components.search_start + 1, input, 0, idx); + input.remove_prefix(idx); + // We only create a temporary string if we need percent encoding and + // we attempt to create as small a temporary string as we can. + std::string encoded = + ada::unicode::percent_encode(input, query_percent_encode_set); + buffer.insert(components.search_start + idx + 1, encoded); + components.hash_start += + uint32_t(encoded.size() + idx + 1); // Do not forget `?` + } + } + + ADA_ASSERT_TRUE(validate()); +} + +inline void url_aggregator::update_base_pathname(const std::string_view input) { + ada_log("url_aggregator::update_base_pathname '", input, "' [", input.size(), + " bytes] \n", to_diagram()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + ADA_ASSERT_TRUE(validate()); + + const bool begins_with_dashdash = input.starts_with("//"); + if (!begins_with_dashdash && has_dash_dot()) { + // We must delete the ./ + delete_dash_dot(); + } + + if (begins_with_dashdash && !has_opaque_path && !has_authority() && + !has_dash_dot()) { + // If url's host is null, url does not have an opaque path, url's path's + // size is greater than 1, then append U+002F (/) followed by U+002E (.) to + // output. + buffer.insert(components.pathname_start, "/."); + components.pathname_start += 2; + if (components.search_start != url_components::omitted) { + components.search_start += 2; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += 2; + } + } + + uint32_t difference = replace_and_resize( + components.pathname_start, + components.pathname_start + get_pathname_length(), input); + if (components.search_start != url_components::omitted) { + components.search_start += difference; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += difference; + } + ADA_ASSERT_TRUE(validate()); +} + +inline void url_aggregator::append_base_pathname(const std::string_view input) { + ada_log("url_aggregator::append_base_pathname ", input, " ", to_string(), + "\n", to_diagram()); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); +#if ADA_DEVELOPMENT_CHECKS + // computing the expected password. + std::string path_expected(get_pathname()); + path_expected.append(input); +#endif // ADA_DEVELOPMENT_CHECKS + uint32_t ending_index = uint32_t(buffer.size()); + if (components.search_start != url_components::omitted) { + ending_index = components.search_start; + } else if (components.hash_start != url_components::omitted) { + ending_index = components.hash_start; + } + buffer.insert(ending_index, input); + + if (components.search_start != url_components::omitted) { + components.search_start += uint32_t(input.size()); + } + if (components.hash_start != url_components::omitted) { + components.hash_start += uint32_t(input.size()); + } +#if ADA_DEVELOPMENT_CHECKS + std::string path_after = std::string(get_pathname()); + ADA_ASSERT_EQUAL( + path_expected, path_after, + "append_base_pathname problem after inserting " + std::string(input)); +#endif // ADA_DEVELOPMENT_CHECKS + ADA_ASSERT_TRUE(validate()); +} + +inline void url_aggregator::update_base_username(const std::string_view input) { + ada_log("url_aggregator::update_base_username '", input, "' ", to_string(), + "\n", to_diagram()); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + + add_authority_slashes_if_needed(); + + bool has_password = has_non_empty_password(); + bool host_starts_with_at = buffer.size() > components.host_start && + buffer[components.host_start] == '@'; + uint32_t diff = replace_and_resize(components.protocol_end + 2, + components.username_end, input); + + components.username_end += diff; + components.host_start += diff; + + if (!input.empty() && !host_starts_with_at) { + buffer.insert(components.host_start, "@"); + diff++; + } else if (input.empty() && host_starts_with_at && !has_password) { + // Input is empty, there is no password, and we need to remove "@" from + // hostname + buffer.erase(components.host_start, 1); + diff--; + } + + components.host_end += diff; + components.pathname_start += diff; + if (components.search_start != url_components::omitted) { + components.search_start += diff; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += diff; + } + ADA_ASSERT_TRUE(validate()); +} + +inline void url_aggregator::append_base_username(const std::string_view input) { + ada_log("url_aggregator::append_base_username ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); +#if ADA_DEVELOPMENT_CHECKS + // computing the expected password. + std::string username_expected(get_username()); + username_expected.append(input); +#endif // ADA_DEVELOPMENT_CHECKS + add_authority_slashes_if_needed(); + + // If input is empty, do nothing. + if (input.empty()) { + return; + } + + uint32_t difference = uint32_t(input.size()); + buffer.insert(components.username_end, input); + components.username_end += difference; + components.host_start += difference; + + if (buffer[components.host_start] != '@' && + components.host_start != components.host_end) { + buffer.insert(components.host_start, "@"); + difference++; + } + + components.host_end += difference; + components.pathname_start += difference; + if (components.search_start != url_components::omitted) { + components.search_start += difference; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += difference; + } +#if ADA_DEVELOPMENT_CHECKS + std::string username_after(get_username()); + ADA_ASSERT_EQUAL( + username_expected, username_after, + "append_base_username problem after inserting " + std::string(input)); +#endif // ADA_DEVELOPMENT_CHECKS + ADA_ASSERT_TRUE(validate()); +} + +constexpr void url_aggregator::clear_password() { + ada_log("url_aggregator::clear_password ", to_string()); + ADA_ASSERT_TRUE(validate()); + if (!has_password()) { + return; + } + + uint32_t diff = components.host_start - components.username_end; + buffer.erase(components.username_end, diff); + components.host_start -= diff; + components.host_end -= diff; + components.pathname_start -= diff; + if (components.search_start != url_components::omitted) { + components.search_start -= diff; + } + if (components.hash_start != url_components::omitted) { + components.hash_start -= diff; + } +} + +inline void url_aggregator::update_base_password(const std::string_view input) { + ada_log("url_aggregator::update_base_password ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + + add_authority_slashes_if_needed(); + + // TODO: Optimization opportunity. Merge the following removal functions. + if (input.empty()) { + clear_password(); + + // Remove username too, if it is empty. + if (!has_non_empty_username()) { + update_base_username(""); + } + + return; + } + + bool password_exists = has_password(); + uint32_t difference = uint32_t(input.size()); + + if (password_exists) { + uint32_t current_length = + components.host_start - components.username_end - 1; + buffer.erase(components.username_end + 1, current_length); + difference -= current_length; + } else { + buffer.insert(components.username_end, ":"); + difference++; + } + + buffer.insert(components.username_end + 1, input); + components.host_start += difference; + + // The following line is required to add "@" to hostname. When updating + // password if hostname does not start with "@", it is "update_base_password"s + // responsibility to set it. + if (buffer[components.host_start] != '@') { + buffer.insert(components.host_start, "@"); + difference++; + } + + components.host_end += difference; + components.pathname_start += difference; + if (components.search_start != url_components::omitted) { + components.search_start += difference; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += difference; + } + ADA_ASSERT_TRUE(validate()); +} + +inline void url_aggregator::append_base_password(const std::string_view input) { + ada_log("url_aggregator::append_base_password ", input, " ", to_string(), + "\n", to_diagram()); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); +#if ADA_DEVELOPMENT_CHECKS + // computing the expected password. + std::string password_expected = std::string(get_password()); + password_expected.append(input); +#endif // ADA_DEVELOPMENT_CHECKS + add_authority_slashes_if_needed(); + + // If input is empty, do nothing. + if (input.empty()) { + return; + } + + uint32_t difference = uint32_t(input.size()); + if (has_password()) { + buffer.insert(components.host_start, input); + } else { + difference++; // Increment for ":" + buffer.insert(components.username_end, ":"); + buffer.insert(components.username_end + 1, input); + } + components.host_start += difference; + + // The following line is required to add "@" to hostname. When updating + // password if hostname does not start with "@", it is "append_base_password"s + // responsibility to set it. + if (buffer[components.host_start] != '@') { + buffer.insert(components.host_start, "@"); + difference++; + } + + components.host_end += difference; + components.pathname_start += difference; + if (components.search_start != url_components::omitted) { + components.search_start += difference; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += difference; + } +#if ADA_DEVELOPMENT_CHECKS + std::string password_after(get_password()); + ADA_ASSERT_EQUAL( + password_expected, password_after, + "append_base_password problem after inserting " + std::string(input)); +#endif // ADA_DEVELOPMENT_CHECKS + ADA_ASSERT_TRUE(validate()); +} + +inline void url_aggregator::update_base_port(uint32_t input) { + ada_log("url_aggregator::update_base_port"); + ADA_ASSERT_TRUE(validate()); + if (input == url_components::omitted) { + clear_port(); + return; + } + // calling std::to_string(input.value()) is unfortunate given that the port + // value is probably already available as a string. + std::string value = helpers::concat(":", std::to_string(input)); + uint32_t difference = uint32_t(value.size()); + + if (components.port != url_components::omitted) { + difference -= components.pathname_start - components.host_end; + buffer.erase(components.host_end, + components.pathname_start - components.host_end); + } + + buffer.insert(components.host_end, value); + components.pathname_start += difference; + if (components.search_start != url_components::omitted) { + components.search_start += difference; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += difference; + } + components.port = input; + ADA_ASSERT_TRUE(validate()); +} + +inline void url_aggregator::clear_port() { + ada_log("url_aggregator::clear_port"); + ADA_ASSERT_TRUE(validate()); + if (components.port == url_components::omitted) { + return; + } + uint32_t length = components.pathname_start - components.host_end; + buffer.erase(components.host_end, length); + components.pathname_start -= length; + if (components.search_start != url_components::omitted) { + components.search_start -= length; + } + if (components.hash_start != url_components::omitted) { + components.hash_start -= length; + } + components.port = url_components::omitted; + ADA_ASSERT_TRUE(validate()); +} + +[[nodiscard]] inline uint32_t url_aggregator::retrieve_base_port() const { + ada_log("url_aggregator::retrieve_base_port"); + return components.port; +} + +inline void url_aggregator::clear_search() { + ada_log("url_aggregator::clear_search"); + ADA_ASSERT_TRUE(validate()); + if (components.search_start == url_components::omitted) { + return; + } + + if (components.hash_start == url_components::omitted) { + buffer.resize(components.search_start); + } else { + buffer.erase(components.search_start, + components.hash_start - components.search_start); + components.hash_start = components.search_start; + } + + components.search_start = url_components::omitted; + +#if ADA_DEVELOPMENT_CHECKS + ADA_ASSERT_EQUAL(get_search(), "", + "search should have been cleared on buffer=" + buffer + + " with " + components.to_string() + "\n" + to_diagram()); +#endif + ADA_ASSERT_TRUE(validate()); +} + +inline void url_aggregator::clear_hash() { + ada_log("url_aggregator::clear_hash"); + ADA_ASSERT_TRUE(validate()); + if (components.hash_start == url_components::omitted) { + return; + } + buffer.resize(components.hash_start); + components.hash_start = url_components::omitted; + +#if ADA_DEVELOPMENT_CHECKS + ADA_ASSERT_EQUAL(get_hash(), "", + "hash should have been cleared on buffer=" + buffer + + " with " + components.to_string() + "\n" + to_diagram()); +#endif + ADA_ASSERT_TRUE(validate()); +} + +constexpr void url_aggregator::clear_pathname() { + ada_log("url_aggregator::clear_pathname"); + ADA_ASSERT_TRUE(validate()); + uint32_t ending_index = uint32_t(buffer.size()); + if (components.search_start != url_components::omitted) { + ending_index = components.search_start; + } else if (components.hash_start != url_components::omitted) { + ending_index = components.hash_start; + } + uint32_t pathname_length = ending_index - components.pathname_start; + buffer.erase(components.pathname_start, pathname_length); + uint32_t difference = pathname_length; + if (components.pathname_start == components.host_end + 2 && + buffer[components.host_end] == '/' && + buffer[components.host_end + 1] == '.') { + components.pathname_start -= 2; + buffer.erase(components.host_end, 2); + difference += 2; + } + if (components.search_start != url_components::omitted) { + components.search_start -= difference; + } + if (components.hash_start != url_components::omitted) { + components.hash_start -= difference; + } + ada_log("url_aggregator::clear_pathname completed, running checks..."); +#if ADA_DEVELOPMENT_CHECKS + ADA_ASSERT_EQUAL(get_pathname(), "", + "pathname should have been cleared on buffer=" + buffer + + " with " + components.to_string() + "\n" + to_diagram()); +#endif + ADA_ASSERT_TRUE(validate()); + ada_log("url_aggregator::clear_pathname completed, running checks... ok"); +} + +constexpr void url_aggregator::clear_hostname() { + ada_log("url_aggregator::clear_hostname"); + ADA_ASSERT_TRUE(validate()); + if (!has_authority()) { + return; + } + ADA_ASSERT_TRUE(has_authority()); + + uint32_t hostname_length = components.host_end - components.host_start; + uint32_t start = components.host_start; + + // If hostname starts with "@", we should not remove that character. + if (hostname_length > 0 && buffer[start] == '@') { + start++; + hostname_length--; + } + buffer.erase(start, hostname_length); + components.host_end = start; + components.pathname_start -= hostname_length; + if (components.search_start != url_components::omitted) { + components.search_start -= hostname_length; + } + if (components.hash_start != url_components::omitted) { + components.hash_start -= hostname_length; + } +#if ADA_DEVELOPMENT_CHECKS + ADA_ASSERT_EQUAL(get_hostname(), "", + "hostname should have been cleared on buffer=" + buffer + + " with " + components.to_string() + "\n" + to_diagram()); +#endif + ADA_ASSERT_TRUE(has_authority()); + ADA_ASSERT_EQUAL(has_empty_hostname(), true, + "hostname should have been cleared on buffer=" + buffer + + " with " + components.to_string() + "\n" + to_diagram()); + ADA_ASSERT_TRUE(validate()); +} + +[[nodiscard]] constexpr bool url_aggregator::has_hash() const noexcept { + ada_log("url_aggregator::has_hash"); + return components.hash_start != url_components::omitted; +} + +[[nodiscard]] constexpr bool url_aggregator::has_search() const noexcept { + ada_log("url_aggregator::has_search"); + return components.search_start != url_components::omitted; +} + +constexpr bool url_aggregator::has_credentials() const noexcept { + ada_log("url_aggregator::has_credentials"); + return has_non_empty_username() || has_non_empty_password(); +} + +constexpr bool url_aggregator::cannot_have_credentials_or_port() const { + ada_log("url_aggregator::cannot_have_credentials_or_port"); + return type == ada::scheme::type::FILE || + components.host_start == components.host_end; +} + +[[nodiscard]] ada_really_inline const ada::url_components& +url_aggregator::get_components() const noexcept { + return components; +} + +[[nodiscard]] constexpr bool ada::url_aggregator::has_authority() + const noexcept { + ada_log("url_aggregator::has_authority"); + // Performance: instead of doing this potentially expensive check, we could + // have a boolean in the struct. + return components.protocol_end + 2 <= components.host_start && + buffer[components.protocol_end] == '/' && + buffer[components.protocol_end + 1] == '/'; +} + +inline void ada::url_aggregator::add_authority_slashes_if_needed() { + ada_log("url_aggregator::add_authority_slashes_if_needed"); + ADA_ASSERT_TRUE(validate()); + // Protocol setter will insert `http:` to the URL. It is up to hostname setter + // to insert + // `//` initially to the buffer, since it depends on the hostname existence. + if (has_authority()) { + return; + } + // Performance: the common case is components.protocol_end == buffer.size() + // Optimization opportunity: in many cases, the "//" is part of the input and + // the insert could be fused with another insert. + buffer.insert(components.protocol_end, "//"); + components.username_end += 2; + components.host_start += 2; + components.host_end += 2; + components.pathname_start += 2; + if (components.search_start != url_components::omitted) { + components.search_start += 2; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += 2; + } + ADA_ASSERT_TRUE(validate()); +} + +constexpr void ada::url_aggregator::reserve(uint32_t capacity) { + buffer.reserve(capacity); +} + +constexpr bool url_aggregator::has_non_empty_username() const noexcept { + ada_log("url_aggregator::has_non_empty_username"); + return components.protocol_end + 2 < components.username_end; +} + +constexpr bool url_aggregator::has_non_empty_password() const noexcept { + ada_log("url_aggregator::has_non_empty_password"); + return components.host_start > components.username_end; +} + +constexpr bool url_aggregator::has_password() const noexcept { + ada_log("url_aggregator::has_password"); + // This function does not care about the length of the password + return components.host_start > components.username_end && + buffer[components.username_end] == ':'; +} + +constexpr bool url_aggregator::has_empty_hostname() const noexcept { + if (!has_hostname()) { + return false; + } + if (components.host_start == components.host_end) { + return true; + } + if (components.host_end > components.host_start + 1) { + return false; + } + return components.username_end != components.host_start; +} + +constexpr bool url_aggregator::has_hostname() const noexcept { + return has_authority(); +} + +constexpr bool url_aggregator::has_port() const noexcept { + ada_log("url_aggregator::has_port"); + // A URL cannot have a username/password/port if its host is null or the empty + // string, or its scheme is "file". + return has_hostname() && components.pathname_start != components.host_end; +} + +[[nodiscard]] constexpr bool url_aggregator::has_dash_dot() const noexcept { + // If url's host is null, url does not have an opaque path, url's path's size + // is greater than 1, and url's path[0] is the empty string, then append + // U+002F (/) followed by U+002E (.) to output. + ada_log("url_aggregator::has_dash_dot"); +#if ADA_DEVELOPMENT_CHECKS + // If pathname_start and host_end are exactly two characters apart, then we + // either have a one-digit port such as http://test.com:5?param=1 or else we + // have a /.: sequence such as "non-spec:/.//". We test that this is the case. + if (components.pathname_start == components.host_end + 2) { + ADA_ASSERT_TRUE((buffer[components.host_end] == '/' && + buffer[components.host_end + 1] == '.') || + (buffer[components.host_end] == ':' && + checkers::is_digit(buffer[components.host_end + 1]))); + } + if (components.pathname_start == components.host_end + 2 && + buffer[components.host_end] == '/' && + buffer[components.host_end + 1] == '.') { + ADA_ASSERT_TRUE(components.pathname_start + 1 < buffer.size()); + ADA_ASSERT_TRUE(buffer[components.pathname_start] == '/'); + ADA_ASSERT_TRUE(buffer[components.pathname_start + 1] == '/'); + } +#endif + // Performance: it should be uncommon for components.pathname_start == + // components.host_end + 2 to be true. So we put this check first in the + // sequence. Most times, we do not have an opaque path. Checking for '/.' is + // more expensive, but should be uncommon. + return components.pathname_start == components.host_end + 2 && + !has_opaque_path && buffer[components.host_end] == '/' && + buffer[components.host_end + 1] == '.'; +} + +[[nodiscard]] constexpr std::string_view url_aggregator::get_href() + const noexcept ada_lifetime_bound { + ada_log("url_aggregator::get_href"); + return buffer; +} + +[[nodiscard]] constexpr size_t url_aggregator::get_href_size() const noexcept { + return buffer.size(); +} + +ada_really_inline size_t +url_aggregator::parse_port(std::string_view view, bool check_trailing_content) { + ada_log("url_aggregator::parse_port('", view, "') ", view.size()); + if (!view.empty() && view[0] == '-') { + ada_log("parse_port: view[0] == '0' && view.size() > 1"); + is_valid = false; + return 0; + } + uint16_t parsed_port{}; + auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port); + if (r.ec == std::errc::result_out_of_range) { + ada_log("parse_port: r.ec == std::errc::result_out_of_range"); + is_valid = false; + return 0; + } + ada_log("parse_port: ", parsed_port); + const size_t consumed = size_t(r.ptr - view.data()); + ada_log("parse_port: consumed ", consumed); + if (check_trailing_content) { + is_valid &= + (consumed == view.size() || view[consumed] == '/' || + view[consumed] == '?' || (is_special() && view[consumed] == '\\')); + } + ada_log("parse_port: is_valid = ", is_valid); + if (is_valid) { + ada_log("parse_port", r.ec == std::errc()); + // scheme_default_port can return 0, and we should allow 0 as a base port. + auto default_port = scheme_default_port(); + bool is_port_valid = (default_port == 0 && parsed_port == 0) || + (default_port != parsed_port); + if (r.ec == std::errc() && is_port_valid) { + update_base_port(parsed_port); + } else { + clear_port(); + } + } + return consumed; +} + +constexpr void url_aggregator::set_protocol_as_file() { + ada_log("url_aggregator::set_protocol_as_file "); + ADA_ASSERT_TRUE(validate()); + type = ada::scheme::type::FILE; + // next line could overflow but unsigned arithmetic has well-defined + // overflows. + uint32_t new_difference = 5 - components.protocol_end; + + if (buffer.empty()) { + buffer.append("file:"); + } else { + buffer.erase(0, components.protocol_end); + buffer.insert(0, "file:"); + } + components.protocol_end = 5; + + // Update the rest of the components. + components.username_end += new_difference; + components.host_start += new_difference; + components.host_end += new_difference; + components.pathname_start += new_difference; + if (components.search_start != url_components::omitted) { + components.search_start += new_difference; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += new_difference; + } + ADA_ASSERT_TRUE(validate()); +} + +[[nodiscard]] constexpr bool url_aggregator::validate() const noexcept { + if (!is_valid) { + return true; + } + if (!components.check_offset_consistency()) { + ada_log("url_aggregator::validate inconsistent components \n", + to_diagram()); + return false; + } + // We have a credible components struct, but let us investivate more + // carefully: + /** + * https://user:pass@example.com:1234/foo/bar?baz#quux + * | | | | ^^^^| | | + * | | | | | | | `----- hash_start + * | | | | | | `--------- search_start + * | | | | | `----------------- pathname_start + * | | | | `--------------------- port + * | | | `----------------------- host_end + * | | `---------------------------------- host_start + * | `--------------------------------------- username_end + * `--------------------------------------------- protocol_end + */ + if (components.protocol_end == url_components::omitted) { + ada_log("url_aggregator::validate omitted protocol_end \n", to_diagram()); + return false; + } + if (components.username_end == url_components::omitted) { + ada_log("url_aggregator::validate omitted username_end \n", to_diagram()); + return false; + } + if (components.host_start == url_components::omitted) { + ada_log("url_aggregator::validate omitted host_start \n", to_diagram()); + return false; + } + if (components.host_end == url_components::omitted) { + ada_log("url_aggregator::validate omitted host_end \n", to_diagram()); + return false; + } + if (components.pathname_start == url_components::omitted) { + ada_log("url_aggregator::validate omitted pathname_start \n", to_diagram()); + return false; + } + + if (components.protocol_end > buffer.size()) { + ada_log("url_aggregator::validate protocol_end overflow \n", to_diagram()); + return false; + } + if (components.username_end > buffer.size()) { + ada_log("url_aggregator::validate username_end overflow \n", to_diagram()); + return false; + } + if (components.host_start > buffer.size()) { + ada_log("url_aggregator::validate host_start overflow \n", to_diagram()); + return false; + } + if (components.host_end > buffer.size()) { + ada_log("url_aggregator::validate host_end overflow \n", to_diagram()); + return false; + } + if (components.pathname_start > buffer.size()) { + ada_log("url_aggregator::validate pathname_start overflow \n", + to_diagram()); + return false; + } + + if (components.protocol_end > 0) { + if (buffer[components.protocol_end - 1] != ':') { + ada_log( + "url_aggregator::validate missing : at the end of the protocol \n", + to_diagram()); + return false; + } + } + + if (components.username_end != buffer.size() && + components.username_end > components.protocol_end + 2) { + if (buffer[components.username_end] != ':' && + buffer[components.username_end] != '@') { + ada_log( + "url_aggregator::validate missing : or @ at the end of the username " + "\n", + to_diagram()); + return false; + } + } + + if (components.host_start != buffer.size()) { + if (components.host_start > components.username_end) { + if (buffer[components.host_start] != '@') { + ada_log( + "url_aggregator::validate missing @ at the end of the password \n", + to_diagram()); + return false; + } + } else if (components.host_start == components.username_end && + components.host_end > components.host_start) { + if (components.host_start == components.protocol_end + 2) { + if (buffer[components.protocol_end] != '/' || + buffer[components.protocol_end + 1] != '/') { + ada_log( + "url_aggregator::validate missing // between protocol and host " + "\n", + to_diagram()); + return false; + } + } else { + if (components.host_start > components.protocol_end && + buffer[components.host_start] != '@') { + ada_log( + "url_aggregator::validate missing @ at the end of the username " + "\n", + to_diagram()); + return false; + } + } + } else { + if (components.host_end != components.host_start) { + ada_log("url_aggregator::validate expected omitted host \n", + to_diagram()); + return false; + } + } + } + if (components.host_end != buffer.size() && + components.pathname_start > components.host_end) { + if (components.pathname_start == components.host_end + 2 && + buffer[components.host_end] == '/' && + buffer[components.host_end + 1] == '.') { + if (components.pathname_start + 1 >= buffer.size() || + buffer[components.pathname_start] != '/' || + buffer[components.pathname_start + 1] != '/') { + ada_log( + "url_aggregator::validate expected the path to begin with // \n", + to_diagram()); + return false; + } + } else if (buffer[components.host_end] != ':') { + ada_log("url_aggregator::validate missing : at the port \n", + to_diagram()); + return false; + } + } + if (components.pathname_start != buffer.size() && + components.pathname_start < components.search_start && + components.pathname_start < components.hash_start && !has_opaque_path) { + if (buffer[components.pathname_start] != '/') { + ada_log("url_aggregator::validate missing / at the path \n", + to_diagram()); + return false; + } + } + if (components.search_start != url_components::omitted) { + if (buffer[components.search_start] != '?') { + ada_log("url_aggregator::validate missing ? at the search \n", + to_diagram()); + return false; + } + } + if (components.hash_start != url_components::omitted) { + if (buffer[components.hash_start] != '#') { + ada_log("url_aggregator::validate missing # at the hash \n", + to_diagram()); + return false; + } + } + + return true; +} + +[[nodiscard]] constexpr std::string_view url_aggregator::get_pathname() const + ada_lifetime_bound { + ada_log("url_aggregator::get_pathname pathname_start = ", + components.pathname_start, " buffer.size() = ", buffer.size(), + " components.search_start = ", components.search_start, + " components.hash_start = ", components.hash_start); + auto ending_index = uint32_t(buffer.size()); + if (components.search_start != url_components::omitted) { + ending_index = components.search_start; + } else if (components.hash_start != url_components::omitted) { + ending_index = components.hash_start; + } + return helpers::substring(buffer, components.pathname_start, ending_index); +} + +inline std::ostream& operator<<(std::ostream& out, + const ada::url_aggregator& u) { + return out << u.to_string(); +} + +void url_aggregator::update_host_to_base_host(const std::string_view input) { + ada_log("url_aggregator::update_host_to_base_host ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (type != ada::scheme::type::FILE) { + // Let host be the result of host parsing host_view with url is not special. + if (input.empty() && !is_special()) { + if (has_hostname()) { + clear_hostname(); + } else if (has_dash_dot()) { + add_authority_slashes_if_needed(); + delete_dash_dot(); + } + return; + } + } + update_base_hostname(input); + ADA_ASSERT_TRUE(validate()); + return; +} +} // namespace ada + +#endif // ADA_URL_AGGREGATOR_INL_H +/* end file include/ada/url_aggregator-inl.h */ +/* begin file include/ada/url_search_params.h */ +/** + * @file url_search_params.h + * @brief URL query string parameter manipulation. + * + * This file provides the `url_search_params` class for parsing, manipulating, + * and serializing URL query strings. It implements the URLSearchParams API + * from the WHATWG URL Standard. + * + * @see https://url.spec.whatwg.org/#interface-urlsearchparams + */ +#ifndef ADA_URL_SEARCH_PARAMS_H +#define ADA_URL_SEARCH_PARAMS_H + +#include +#include +#include +#include + +namespace ada { + +/** + * @brief Iterator types for url_search_params iteration. + */ +enum class url_search_params_iter_type { + KEYS, /**< Iterate over parameter keys only */ + VALUES, /**< Iterate over parameter values only */ + ENTRIES, /**< Iterate over key-value pairs */ +}; + +template +struct url_search_params_iter; + +/** Type alias for a key-value pair of string views. */ +typedef std::pair key_value_view_pair; + +/** Iterator over search parameter keys. */ +using url_search_params_keys_iter = + url_search_params_iter; +/** Iterator over search parameter values. */ +using url_search_params_values_iter = + url_search_params_iter; +/** Iterator over search parameter key-value pairs. */ +using url_search_params_entries_iter = + url_search_params_iter; + +/** + * @brief Class for parsing and manipulating URL query strings. + * + * The `url_search_params` class provides methods to parse, modify, and + * serialize URL query parameters (the part after '?' in a URL). It handles + * percent-encoding and decoding automatically. + * + * All string inputs must be valid UTF-8. The caller is responsible for + * ensuring UTF-8 validity. + * + * Construction and `reset` refuse query strings longer than + * `get_max_input_length()` (the object is left empty). Individual `append` / + * `set` calls are not length-capped. + * + * @see https://url.spec.whatwg.org/#interface-urlsearchparams + */ +struct url_search_params { + url_search_params() = default; + + /** + * Constructs url_search_params by parsing a query string. + * @param input A query string (with or without leading '?'). Must be UTF-8. + * If longer than `get_max_input_length()`, the object stays empty. + */ + explicit url_search_params(const std::string_view input) { + initialize(input); + } + + url_search_params(const url_search_params& u) = default; + url_search_params(url_search_params&& u) noexcept = default; + url_search_params& operator=(url_search_params&& u) noexcept = default; + url_search_params& operator=(const url_search_params& u) = default; + ~url_search_params() = default; + + /** + * Returns the number of key-value pairs. + * @return The total count of parameters. + */ + [[nodiscard]] inline size_t size() const noexcept; + + /** + * Appends a new key-value pair to the parameter list. + * @param key The parameter name (must be valid UTF-8). + * @param value The parameter value (must be valid UTF-8). + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-append + */ + inline void append(std::string_view key, std::string_view value); + + /** + * Removes all pairs with the given key. + * @param key The parameter name to remove. + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-delete + */ + inline void remove(std::string_view key); + + /** + * Removes all pairs with the given key and value. + * @param key The parameter name. + * @param value The parameter value to match. + */ + inline void remove(std::string_view key, std::string_view value); + + /** + * Returns the value of the first pair with the given key. + * @param key The parameter name to search for. + * @return The value if found, or std::nullopt if not present. + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-get + */ + inline std::optional get(std::string_view key); + + /** + * Returns all values for pairs with the given key. + * @param key The parameter name to search for. + * @return A vector of all matching values (may be empty). + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-getall + */ + inline std::vector get_all(std::string_view key); + + /** + * Checks if any pair has the given key. + * @param key The parameter name to search for. + * @return `true` if at least one pair has this key. + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-has + */ + inline bool has(std::string_view key) noexcept; + + /** + * Checks if any pair matches the given key and value. + * @param key The parameter name to search for. + * @param value The parameter value to match. + * @return `true` if a matching pair exists. + */ + inline bool has(std::string_view key, std::string_view value) noexcept; + + /** + * Sets a parameter value, replacing any existing pairs with the same key. + * @param key The parameter name (must be valid UTF-8). + * @param value The parameter value (must be valid UTF-8). + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-set + */ + inline void set(std::string_view key, std::string_view value); + + /** + * Sorts all key-value pairs by their keys using code unit comparison. + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-sort + */ + inline void sort(); + + /** + * Serializes the parameters to a query string (without leading '?'). + * @return The percent-encoded query string. + * @see https://url.spec.whatwg.org/#urlsearchparams-stringification-behavior + */ + inline std::string to_string() const; + + /** + * Returns an iterator over all parameter keys. + * Keys may repeat if there are duplicate parameters. + * @return An iterator yielding string_view keys. + * @note The iterator is invalidated if this object is modified. + */ + inline url_search_params_keys_iter get_keys(); + + /** + * Returns an iterator over all parameter values. + * @return An iterator yielding string_view values. + * @note The iterator is invalidated if this object is modified. + */ + inline url_search_params_values_iter get_values(); + + /** + * Returns an iterator over all key-value pairs. + * @return An iterator yielding key-value pair views. + * @note The iterator is invalidated if this object is modified. + */ + inline url_search_params_entries_iter get_entries(); + + /** + * C++ style conventional iterator support. const only because we + * do not really want the params to be modified via the iterator. + */ + inline auto begin() const { return params.begin(); } + inline auto end() const { return params.end(); } + inline auto front() const { return params.front(); } + inline auto back() const { return params.back(); } + inline auto operator[](size_t index) const { return params[index]; } + + /** + * @private + * Used to reset the search params to a new input. + * Used primarily for C API. + * @param input + */ + void reset(std::string_view input); + + private: + typedef std::pair key_value_pair; + std::vector params{}; + + /** + * The init parameter must be valid UTF-8. + * @see https://url.spec.whatwg.org/#concept-urlencoded-parser + */ + void initialize(std::string_view init); + + template + friend struct url_search_params_iter; +}; // url_search_params + +/** + * @brief JavaScript-style iterator for url_search_params. + * + * Provides a `next()` method that returns successive values until exhausted. + * This matches the iterator pattern used in the Web Platform. + * + * @tparam T The type of value returned by the iterator. + * @tparam Type The type of iteration (KEYS, VALUES, or ENTRIES). + * + * @see https://webidl.spec.whatwg.org/#idl-iterable + */ +template +struct url_search_params_iter { + inline url_search_params_iter() : params(EMPTY) {} + url_search_params_iter(const url_search_params_iter& u) = default; + url_search_params_iter(url_search_params_iter&& u) noexcept = default; + url_search_params_iter& operator=(url_search_params_iter&& u) noexcept = + default; + url_search_params_iter& operator=(const url_search_params_iter& u) = default; + ~url_search_params_iter() = default; + + /** + * Returns the next value in the iteration sequence. + * @return The next value, or std::nullopt if iteration is complete. + */ + inline std::optional next(); + + /** + * Checks if more values are available. + * @return `true` if `next()` will return a value, `false` if exhausted. + */ + inline bool has_next() const; + + private: + static url_search_params EMPTY; + inline url_search_params_iter(url_search_params& params_) : params(params_) {} + + url_search_params& params; + size_t pos = 0; + + friend struct url_search_params; +}; + +} // namespace ada +#endif +/* end file include/ada/url_search_params.h */ +/* begin file include/ada/url_search_params-inl.h */ +/** + * @file url_search_params-inl.h + * @brief Inline declarations for the URL Search Params + */ +#ifndef ADA_URL_SEARCH_PARAMS_INL_H +#define ADA_URL_SEARCH_PARAMS_INL_H + + +#include +#include +#include +#include +#include +#include +#include + +namespace ada { + +// Declared in implementation.h; used here as a DoS bound on untrusted query +// strings (ada.h includes both headers). +uint32_t get_max_input_length(); + +// A default, empty url_search_params for use with empty iterators. +template +url_search_params url_search_params_iter::EMPTY; + +inline void url_search_params::reset(std::string_view input) { + params.clear(); + initialize(input); +} + +inline void url_search_params::initialize(std::string_view input) { + if (!input.empty() && input.front() == '?') { + input.remove_prefix(1); + } + if (input.empty()) { + return; + } + // Refuse overlong query strings (same process-wide cap as URL parsing). + if (input.size() > get_max_input_length()) { + return; + } + + params.reserve(size_t(std::count(input.begin(), input.end(), '&')) + 1); + + auto process_key_value = [&](const std::string_view current) { + const auto equal = current.find('='); + if (equal == std::string_view::npos) { + params.emplace_back(unicode::form_urlencoded_decode(current), ""); + } else { + params.emplace_back( + unicode::form_urlencoded_decode(current.substr(0, equal)), + unicode::form_urlencoded_decode(current.substr(equal + 1))); + } + }; + + while (!input.empty()) { + const auto ampersand_index = input.find('&'); + + if (ampersand_index == std::string_view::npos) { + if (!input.empty()) { + process_key_value(input); + } + break; + } else if (ampersand_index != 0) { + process_key_value(input.substr(0, ampersand_index)); + } + + input.remove_prefix(ampersand_index + 1); + } +} + +inline void url_search_params::append(const std::string_view key, + const std::string_view value) { + params.emplace_back(key, value); +} + +inline size_t url_search_params::size() const noexcept { return params.size(); } + +inline std::optional url_search_params::get( + const std::string_view key) { + auto entry = std::ranges::find_if( + params, [&key](const auto& param) { return param.first == key; }); + + if (entry == params.end()) { + return std::nullopt; + } + + return entry->second; +} + +inline std::vector url_search_params::get_all( + const std::string_view key) { + std::vector out{}; + + for (auto& param : params) { + if (param.first == key) { + out.emplace_back(param.second); + } + } + + return out; +} + +inline bool url_search_params::has(const std::string_view key) noexcept { + auto entry = std::ranges::find_if( + params, [&key](const auto& param) { return param.first == key; }); + return entry != params.end(); +} + +inline bool url_search_params::has(std::string_view key, + std::string_view value) noexcept { + auto entry = std::ranges::find_if(params, [&key, &value](const auto& param) { + return param.first == key && param.second == value; + }); + return entry != params.end(); +} + +inline std::string url_search_params::to_string() const { + auto character_set = ada::character_sets::WWW_FORM_URLENCODED_PERCENT_ENCODE; + std::string out{}; + for (size_t i = 0; i < params.size(); i++) { + auto key = ada::unicode::percent_encode(params[i].first, character_set); + auto value = ada::unicode::percent_encode(params[i].second, character_set); + + // Performance optimization: Move this inside percent_encode. + std::ranges::replace(key, ' ', '+'); + std::ranges::replace(value, ' ', '+'); + + if (i != 0) { + out += "&"; + } + out.append(key); + out += "="; + out.append(value); + } + return out; +} + +inline void url_search_params::set(const std::string_view key, + const std::string_view value) { + const auto find = [&key](const auto& param) { return param.first == key; }; + + auto it = std::ranges::find_if(params, find); + + if (it == params.end()) { + params.emplace_back(key, value); + } else { + it->second = value; + params.erase(std::remove_if(std::next(it), params.end(), find), + params.end()); + } +} + +inline void url_search_params::remove(const std::string_view key) { + std::erase_if(params, + [&key](const auto& param) { return param.first == key; }); +} + +inline void url_search_params::remove(const std::string_view key, + const std::string_view value) { + std::erase_if(params, [&key, &value](const auto& param) { + return param.first == key && param.second == value; + }); +} + +inline void url_search_params::sort() { + // Keys are expected to be valid UTF-8, but percent_decode can produce + // arbitrary byte sequences. Handle truncated/invalid sequences gracefully. + std::ranges::stable_sort(params, [](const key_value_pair& lhs, + const key_value_pair& rhs) { + size_t i = 0, j = 0; + uint32_t low_surrogate1 = 0, low_surrogate2 = 0; + while ((i < lhs.first.size() || low_surrogate1 != 0) && + (j < rhs.first.size() || low_surrogate2 != 0)) { + uint32_t codePoint1 = 0, codePoint2 = 0; + + if (low_surrogate1 != 0) { + codePoint1 = low_surrogate1; + low_surrogate1 = 0; + } else { + uint8_t c1 = uint8_t(lhs.first[i]); + if (c1 > 0x7F && c1 <= 0xDF && i + 1 < lhs.first.size()) { + codePoint1 = ((c1 & 0x1F) << 6) | (uint8_t(lhs.first[i + 1]) & 0x3F); + i += 2; + } else if (c1 > 0xDF && c1 <= 0xEF && i + 2 < lhs.first.size()) { + codePoint1 = ((c1 & 0x0F) << 12) | + ((uint8_t(lhs.first[i + 1]) & 0x3F) << 6) | + (uint8_t(lhs.first[i + 2]) & 0x3F); + i += 3; + } else if (c1 > 0xEF && c1 <= 0xF7 && i + 3 < lhs.first.size()) { + codePoint1 = ((c1 & 0x07) << 18) | + ((uint8_t(lhs.first[i + 1]) & 0x3F) << 12) | + ((uint8_t(lhs.first[i + 2]) & 0x3F) << 6) | + (uint8_t(lhs.first[i + 3]) & 0x3F); + i += 4; + + codePoint1 -= 0x10000; + uint16_t high_surrogate = uint16_t(0xD800 + (codePoint1 >> 10)); + low_surrogate1 = uint16_t(0xDC00 + (codePoint1 & 0x3FF)); + codePoint1 = high_surrogate; + } else { + // ASCII (c1 <= 0x7F) or truncated/invalid UTF-8: treat as raw byte + codePoint1 = c1; + i++; + } + } + + if (low_surrogate2 != 0) { + codePoint2 = low_surrogate2; + low_surrogate2 = 0; + } else { + uint8_t c2 = uint8_t(rhs.first[j]); + if (c2 > 0x7F && c2 <= 0xDF && j + 1 < rhs.first.size()) { + codePoint2 = ((c2 & 0x1F) << 6) | (uint8_t(rhs.first[j + 1]) & 0x3F); + j += 2; + } else if (c2 > 0xDF && c2 <= 0xEF && j + 2 < rhs.first.size()) { + codePoint2 = ((c2 & 0x0F) << 12) | + ((uint8_t(rhs.first[j + 1]) & 0x3F) << 6) | + (uint8_t(rhs.first[j + 2]) & 0x3F); + j += 3; + } else if (c2 > 0xEF && c2 <= 0xF7 && j + 3 < rhs.first.size()) { + codePoint2 = ((c2 & 0x07) << 18) | + ((uint8_t(rhs.first[j + 1]) & 0x3F) << 12) | + ((uint8_t(rhs.first[j + 2]) & 0x3F) << 6) | + (uint8_t(rhs.first[j + 3]) & 0x3F); + j += 4; + codePoint2 -= 0x10000; + uint16_t high_surrogate = uint16_t(0xD800 + (codePoint2 >> 10)); + low_surrogate2 = uint16_t(0xDC00 + (codePoint2 & 0x3FF)); + codePoint2 = high_surrogate; + } else { + // ASCII (c2 <= 0x7F) or truncated/invalid UTF-8: treat as raw byte + codePoint2 = c2; + j++; + } + } + + if (codePoint1 != codePoint2) { + return (codePoint1 < codePoint2); + } + } + return (j < rhs.first.size() || low_surrogate2 != 0); + }); +} + +inline url_search_params_keys_iter url_search_params::get_keys() { + return url_search_params_keys_iter(*this); +} + +/** + * @see https://url.spec.whatwg.org/#interface-urlsearchparams + */ +inline url_search_params_values_iter url_search_params::get_values() { + return url_search_params_values_iter(*this); +} + +/** + * @see https://url.spec.whatwg.org/#interface-urlsearchparams + */ +inline url_search_params_entries_iter url_search_params::get_entries() { + return url_search_params_entries_iter(*this); +} + +template +inline bool url_search_params_iter::has_next() const { + return pos < params.params.size(); +} + +template <> +inline std::optional url_search_params_keys_iter::next() { + if (!has_next()) { + return std::nullopt; + } + return params.params[pos++].first; +} + +template <> +inline std::optional url_search_params_values_iter::next() { + if (!has_next()) { + return std::nullopt; + } + return params.params[pos++].second; +} + +template <> +inline std::optional +url_search_params_entries_iter::next() { + if (!has_next()) { + return std::nullopt; + } + return params.params[pos++]; +} + +} // namespace ada + +#endif // ADA_URL_SEARCH_PARAMS_INL_H +/* end file include/ada/url_search_params-inl.h */ + +/* begin file include/ada/url_pattern-inl.h */ +/** + * @file url_pattern-inl.h + * @brief Declaration for the URLPattern inline functions. + */ +#ifndef ADA_URL_PATTERN_INL_H +#define ADA_URL_PATTERN_INL_H + + +#include +#include +#include + +#if ADA_INCLUDE_URL_PATTERN +namespace ada { + +inline bool url_pattern_init::operator==(const url_pattern_init& other) const { + return protocol == other.protocol && username == other.username && + password == other.password && hostname == other.hostname && + port == other.port && search == other.search && hash == other.hash && + pathname == other.pathname; +} + +inline bool url_pattern_component_result::operator==( + const url_pattern_component_result& other) const { + return input == other.input && groups == other.groups; +} + +template +url_pattern_component_result +url_pattern_component::create_component_match_result( + std::string&& input, + std::vector>&& exec_result) { + // Let result be a new URLPatternComponentResult. + // Set result["input"] to input. + // Let groups be a record. + auto result = + url_pattern_component_result{.input = std::move(input), .groups = {}}; + + // We explicitly start iterating from 0 even though the spec + // says we should start from 1. This case is handled by the + // std_regex_provider which removes the full match from index 0. + // Use min() to guard against potential mismatches between + // exec_result size and group_name_list size. + const size_t size = std::min(exec_result.size(), group_name_list.size()); + result.groups.reserve(size); + for (size_t index = 0; index < size; index++) { + result.groups.emplace(group_name_list[index], + std::move(exec_result[index])); + } + return result; +} + +template +std::string_view url_pattern::get_protocol() const + ada_lifetime_bound { + // Return this's associated URL pattern's protocol component's pattern string. + return protocol_component.pattern; +} +template +std::string_view url_pattern::get_username() const + ada_lifetime_bound { + // Return this's associated URL pattern's username component's pattern string. + return username_component.pattern; +} +template +std::string_view url_pattern::get_password() const + ada_lifetime_bound { + // Return this's associated URL pattern's password component's pattern string. + return password_component.pattern; +} +template +std::string_view url_pattern::get_hostname() const + ada_lifetime_bound { + // Return this's associated URL pattern's hostname component's pattern string. + return hostname_component.pattern; +} +template +std::string_view url_pattern::get_port() const + ada_lifetime_bound { + // Return this's associated URL pattern's port component's pattern string. + return port_component.pattern; +} +template +std::string_view url_pattern::get_pathname() const + ada_lifetime_bound { + // Return this's associated URL pattern's pathname component's pattern string. + return pathname_component.pattern; +} +template +std::string_view url_pattern::get_search() const + ada_lifetime_bound { + // Return this's associated URL pattern's search component's pattern string. + return search_component.pattern; +} +template +std::string_view url_pattern::get_hash() const + ada_lifetime_bound { + // Return this's associated URL pattern's hash component's pattern string. + return hash_component.pattern; +} +template +bool url_pattern::ignore_case() const { + return ignore_case_; +} +template +bool url_pattern::has_regexp_groups() const { + // If this's associated URL pattern's has regexp groups, then return true. + return protocol_component.has_regexp_groups || + username_component.has_regexp_groups || + password_component.has_regexp_groups || + hostname_component.has_regexp_groups || + port_component.has_regexp_groups || + pathname_component.has_regexp_groups || + search_component.has_regexp_groups || hash_component.has_regexp_groups; +} + +inline bool url_pattern_part::is_regexp() const noexcept { + return type == url_pattern_part_type::REGEXP; +} + +inline std::string_view url_pattern_compile_component_options::get_delimiter() + const { + if (delimiter) { + return {&delimiter.value(), 1}; + } + return {}; +} + +inline std::string_view url_pattern_compile_component_options::get_prefix() + const { + if (prefix) { + return {&prefix.value(), 1}; + } + return {}; +} + +template +template +tl::expected, errors> +url_pattern_component::compile( + std::string_view input, F& encoding_callback, + url_pattern_compile_component_options& options) { + ada_log("url_pattern_component::compile input: ", input); + // Let part list be the result of running parse a pattern string given input, + // options, and encoding callback. + auto part_list = url_pattern_helpers::parse_pattern_string(input, options, + encoding_callback); + + if (!part_list) { + ada_log("parse_pattern_string failed"); + return tl::unexpected(part_list.error()); + } + + // Detect pattern type early to potentially skip expensive regex compilation + const auto has_regexp = [](const auto& part) { return part.is_regexp(); }; + const bool has_regexp_groups = std::ranges::any_of(*part_list, has_regexp); + + url_pattern_component_type component_type = + url_pattern_component_type::REGEXP; + std::string exact_match_value{}; + + if (part_list->empty()) { + component_type = url_pattern_component_type::EMPTY; + } else if (part_list->size() == 1) { + const auto& part = (*part_list)[0]; + if (part.type == url_pattern_part_type::FIXED_TEXT && + part.modifier == url_pattern_part_modifier::none && + !options.ignore_case) { + component_type = url_pattern_component_type::EXACT_MATCH; + exact_match_value = part.value; + } else if (part.type == url_pattern_part_type::FULL_WILDCARD && + part.modifier == url_pattern_part_modifier::none && + part.prefix.empty() && part.suffix.empty()) { + component_type = url_pattern_component_type::FULL_WILDCARD; + } + } + + // For simple patterns, skip regex generation and compilation entirely + if (component_type != url_pattern_component_type::REGEXP) { + auto pattern_string = + url_pattern_helpers::generate_pattern_string(*part_list, options); + // For FULL_WILDCARD, we need the group name from + // generate_regular_expression + std::vector name_list; + if (component_type == url_pattern_component_type::FULL_WILDCARD && + !part_list->empty()) { + name_list.push_back((*part_list)[0].name); + } + return url_pattern_component( + std::move(pattern_string), typename regex_provider::regex_type{}, + std::move(name_list), has_regexp_groups, component_type, + std::move(exact_match_value)); + } + + // Generate regex for complex patterns + auto [regular_expression_string, name_list] = + url_pattern_helpers::generate_regular_expression_and_name_list(*part_list, + options); + auto pattern_string = + url_pattern_helpers::generate_pattern_string(*part_list, options); + + std::optional regular_expression = + regex_provider::create_instance(regular_expression_string, + options.ignore_case); + if (!regular_expression) { + return tl::unexpected(errors::type_error); + } + + return url_pattern_component( + std::move(pattern_string), std::move(*regular_expression), + std::move(name_list), has_regexp_groups, component_type, + std::move(exact_match_value)); +} + +template +bool url_pattern_component::fast_test( + std::string_view input) const noexcept { + // Fast path for simple patterns - avoid regex evaluation + // Using if-else for better branch prediction on common cases + if (type == url_pattern_component_type::FULL_WILDCARD) { + return true; + } + if (type == url_pattern_component_type::EXACT_MATCH) { + return input == exact_match_value; + } + if (type == url_pattern_component_type::EMPTY) { + return input.empty(); + } + // type == REGEXP + return regex_provider::regex_match(input, regexp); +} + +template +std::optional>> +url_pattern_component::fast_match( + std::string_view input) const { + // Handle each type directly without redundant checks + if (type == url_pattern_component_type::FULL_WILDCARD) { + // FULL_WILDCARD always matches - capture the input (even if empty) + // If there's no group name, return empty groups + if (group_name_list.empty()) { + return std::vector>{}; + } + // Capture the matched input (including empty strings) + return std::vector>{std::string(input)}; + } + if (type == url_pattern_component_type::EXACT_MATCH) { + if (input == exact_match_value) { + return std::vector>{}; + } + return std::nullopt; + } + if (type == url_pattern_component_type::EMPTY) { + if (input.empty()) { + return std::vector>{}; + } + return std::nullopt; + } + // type == REGEXP - use regex + return regex_provider::regex_search(input, regexp); +} + +template +result> url_pattern::exec( + const url_pattern_input& input, const std::string_view* base_url) { + // Return the result of match given this's associated URL pattern, input, and + // baseURL if given. + return match(input, base_url); +} + +template +bool url_pattern::test_components( + std::string_view protocol, std::string_view username, + std::string_view password, std::string_view hostname, std::string_view port, + std::string_view pathname, std::string_view search, + std::string_view hash) const { + return protocol_component.fast_test(protocol) && + username_component.fast_test(username) && + password_component.fast_test(password) && + hostname_component.fast_test(hostname) && + port_component.fast_test(port) && + pathname_component.fast_test(pathname) && + search_component.fast_test(search) && hash_component.fast_test(hash); +} + +template +result url_pattern::test( + const url_pattern_input& input, const std::string_view* base_url_string) { + // If input is a URLPatternInit + if (std::holds_alternative(input)) { + if (base_url_string) { + return tl::unexpected(errors::type_error); + } + + std::string protocol{}, username{}, password{}, hostname{}; + std::string port{}, pathname{}, search{}, hash{}; + + auto apply_result = url_pattern_init::process( + std::get(input), url_pattern_init::process_type::url, + protocol, username, password, hostname, port, pathname, search, hash); + + if (!apply_result) { + return false; + } + + std::string_view search_view = *apply_result->search; + if (search_view.starts_with("?")) { + search_view.remove_prefix(1); + } + + return test_components(*apply_result->protocol, *apply_result->username, + *apply_result->password, *apply_result->hostname, + *apply_result->port, *apply_result->pathname, + search_view, *apply_result->hash); + } + + // URL string input path + result base_url; + if (base_url_string) { + base_url = ada::parse(*base_url_string, nullptr); + if (!base_url) { + return false; + } + } + + auto url = + ada::parse(std::get(input), + base_url.has_value() ? &*base_url : nullptr); + if (!url) { + return false; + } + + // Extract components as string_view + auto protocol_view = url->get_protocol(); + if (protocol_view.ends_with(":")) { + protocol_view.remove_suffix(1); + } + + auto search_view = url->get_search(); + if (search_view.starts_with("?")) { + search_view.remove_prefix(1); + } + + auto hash_view = url->get_hash(); + if (hash_view.starts_with("#")) { + hash_view.remove_prefix(1); + } + + return test_components(protocol_view, url->get_username(), + url->get_password(), url->get_hostname(), + url->get_port(), url->get_pathname(), search_view, + hash_view); +} + +template +result> url_pattern::match( + const url_pattern_input& input, const std::string_view* base_url_string) { + std::string protocol{}; + std::string username{}; + std::string password{}; + std::string hostname{}; + std::string port{}; + std::string pathname{}; + std::string search{}; + std::string hash{}; + + // Let inputs be an empty list. + // Append input to inputs. + std::vector inputs{input}; + + // If input is a URLPatternInit then: + if (std::holds_alternative(input)) { + ada_log( + "url_pattern::match called with url_pattern_init and base_url_string=", + base_url_string); + // If baseURLString was given, throw a TypeError. + if (base_url_string) { + ada_log("failed to match because base_url_string was given"); + return tl::unexpected(errors::type_error); + } + + // Let applyResult be the result of process a URLPatternInit given input, + // "url", protocol, username, password, hostname, port, pathname, search, + // and hash. + auto apply_result = url_pattern_init::process( + std::get(input), url_pattern_init::process_type::url, + protocol, username, password, hostname, port, pathname, search, hash); + + // If this throws an exception, catch it, and return null. + if (!apply_result.has_value()) { + ada_log("match returned std::nullopt because process threw"); + return std::nullopt; + } + + // Set protocol to applyResult["protocol"]. + ADA_ASSERT_TRUE(apply_result->protocol.has_value()); + protocol = std::move(apply_result->protocol.value()); + + // Set username to applyResult["username"]. + ADA_ASSERT_TRUE(apply_result->username.has_value()); + username = std::move(apply_result->username.value()); + + // Set password to applyResult["password"]. + ADA_ASSERT_TRUE(apply_result->password.has_value()); + password = std::move(apply_result->password.value()); + + // Set hostname to applyResult["hostname"]. + ADA_ASSERT_TRUE(apply_result->hostname.has_value()); + hostname = std::move(apply_result->hostname.value()); + + // Set port to applyResult["port"]. + ADA_ASSERT_TRUE(apply_result->port.has_value()); + port = std::move(apply_result->port.value()); + + // Set pathname to applyResult["pathname"]. + ADA_ASSERT_TRUE(apply_result->pathname.has_value()); + pathname = std::move(apply_result->pathname.value()); + + // Set search to applyResult["search"]. + ADA_ASSERT_TRUE(apply_result->search.has_value()); + if (apply_result->search->starts_with("?")) { + search = apply_result->search->substr(1); + } else { + search = std::move(apply_result->search.value()); + } + + // Set hash to applyResult["hash"]. + ADA_ASSERT_TRUE(apply_result->hash.has_value()); + ADA_ASSERT_TRUE(!apply_result->hash->starts_with("#")); + hash = std::move(apply_result->hash.value()); + } else { + ADA_ASSERT_TRUE(std::holds_alternative(input)); + + // Let baseURL be null. + result base_url; + + // If baseURLString was given, then: + if (base_url_string) { + // Let baseURL be the result of parsing baseURLString. + base_url = ada::parse(*base_url_string, nullptr); + + // If baseURL is failure, return null. + if (!base_url) { + ada_log("match returned std::nullopt because failed to parse base_url=", + *base_url_string); + return std::nullopt; + } + + // Append baseURLString to inputs. + inputs.emplace_back(*base_url_string); + } + + url_aggregator* base_url_value = + base_url.has_value() ? &*base_url : nullptr; + + // Set url to the result of parsing input given baseURL. + auto url = ada::parse(std::get(input), + base_url_value); + + // If url is failure, return null. + if (!url) { + ada_log("match returned std::nullopt because url failed"); + return std::nullopt; + } + + // Set protocol to url's scheme. + // IMPORTANT: Not documented on the URLPattern spec, but protocol suffix ':' + // is removed. Similar work was done on workerd: + // https://github.com/cloudflare/workerd/blob/8620d14012513a6ce04d079e401d3becac3c67bd/src/workerd/jsg/url.c%2B%2B#L2038 + protocol = url->get_protocol().substr(0, url->get_protocol().size() - 1); + // Set username to url's username. + username = url->get_username(); + // Set password to url's password. + password = url->get_password(); + // Set hostname to url's host, serialized, or the empty string if the value + // is null. + hostname = url->get_hostname(); + // Set port to url's port, serialized, or the empty string if the value is + // null. + port = url->get_port(); + // Set pathname to the result of URL path serializing url. + pathname = url->get_pathname(); + // Set search to url's query or the empty string if the value is null. + // IMPORTANT: Not documented on the URLPattern spec, but search prefix '?' + // is removed. Similar work was done on workerd: + // https://github.com/cloudflare/workerd/blob/8620d14012513a6ce04d079e401d3becac3c67bd/src/workerd/jsg/url.c%2B%2B#L2232 + if (url->has_search()) { + auto view = url->get_search(); + search = view.starts_with("?") ? url->get_search().substr(1) : view; + } + // Set hash to url's fragment or the empty string if the value is null. + // IMPORTANT: Not documented on the URLPattern spec, but hash prefix '#' is + // removed. Similar work was done on workerd: + // https://github.com/cloudflare/workerd/blob/8620d14012513a6ce04d079e401d3becac3c67bd/src/workerd/jsg/url.c%2B%2B#L2242 + if (url->has_hash()) { + auto view = url->get_hash(); + hash = view.starts_with("#") ? url->get_hash().substr(1) : view; + } + } + + // Use fast_match which skips regex for simple patterns (EMPTY, EXACT_MATCH, + // FULL_WILDCARD) and only falls back to regex for complex REGEXP patterns. + + // Let protocolExecResult be RegExpBuiltinExec(urlPattern's protocol + // component's regular expression, protocol). + auto protocol_exec_result = protocol_component.fast_match(protocol); + if (!protocol_exec_result) { + return std::nullopt; + } + + // Let usernameExecResult be RegExpBuiltinExec(urlPattern's username + // component's regular expression, username). + auto username_exec_result = username_component.fast_match(username); + if (!username_exec_result) { + return std::nullopt; + } + + // Let passwordExecResult be RegExpBuiltinExec(urlPattern's password + // component's regular expression, password). + auto password_exec_result = password_component.fast_match(password); + if (!password_exec_result) { + return std::nullopt; + } + + // Let hostnameExecResult be RegExpBuiltinExec(urlPattern's hostname + // component's regular expression, hostname). + auto hostname_exec_result = hostname_component.fast_match(hostname); + if (!hostname_exec_result) { + return std::nullopt; + } + + // Let portExecResult be RegExpBuiltinExec(urlPattern's port component's + // regular expression, port). + auto port_exec_result = port_component.fast_match(port); + if (!port_exec_result) { + return std::nullopt; + } + + // Let pathnameExecResult be RegExpBuiltinExec(urlPattern's pathname + // component's regular expression, pathname). + auto pathname_exec_result = pathname_component.fast_match(pathname); + if (!pathname_exec_result) { + return std::nullopt; + } + + // Let searchExecResult be RegExpBuiltinExec(urlPattern's search component's + // regular expression, search). + auto search_exec_result = search_component.fast_match(search); + if (!search_exec_result) { + return std::nullopt; + } + + // Let hashExecResult be RegExpBuiltinExec(urlPattern's hash component's + // regular expression, hash). + auto hash_exec_result = hash_component.fast_match(hash); + if (!hash_exec_result) { + return std::nullopt; + } + + // Let result be a new URLPatternResult. + auto result = url_pattern_result{}; + // Set result["inputs"] to inputs. + result.inputs = std::move(inputs); + // Set result["protocol"] to the result of creating a component match result + // given urlPattern's protocol component, protocol, and protocolExecResult. + result.protocol = protocol_component.create_component_match_result( + std::move(protocol), std::move(*protocol_exec_result)); + + // Set result["username"] to the result of creating a component match result + // given urlPattern's username component, username, and usernameExecResult. + result.username = username_component.create_component_match_result( + std::move(username), std::move(*username_exec_result)); + + // Set result["password"] to the result of creating a component match result + // given urlPattern's password component, password, and passwordExecResult. + result.password = password_component.create_component_match_result( + std::move(password), std::move(*password_exec_result)); + + // Set result["hostname"] to the result of creating a component match result + // given urlPattern's hostname component, hostname, and hostnameExecResult. + result.hostname = hostname_component.create_component_match_result( + std::move(hostname), std::move(*hostname_exec_result)); + + // Set result["port"] to the result of creating a component match result given + // urlPattern's port component, port, and portExecResult. + result.port = port_component.create_component_match_result( + std::move(port), std::move(*port_exec_result)); + + // Set result["pathname"] to the result of creating a component match result + // given urlPattern's pathname component, pathname, and pathnameExecResult. + result.pathname = pathname_component.create_component_match_result( + std::move(pathname), std::move(*pathname_exec_result)); + + // Set result["search"] to the result of creating a component match result + // given urlPattern's search component, search, and searchExecResult. + result.search = search_component.create_component_match_result( + std::move(search), std::move(*search_exec_result)); + + // Set result["hash"] to the result of creating a component match result given + // urlPattern's hash component, hash, and hashExecResult. + result.hash = hash_component.create_component_match_result( + std::move(hash), std::move(*hash_exec_result)); + + return result; +} + +} // namespace ada +#endif // ADA_INCLUDE_URL_PATTERN +#endif +/* end file include/ada/url_pattern-inl.h */ +/* begin file include/ada/url_pattern_helpers-inl.h */ +/** + * @file url_pattern_helpers-inl.h + * @brief Declaration for the URLPattern helpers. + */ +#ifndef ADA_URL_PATTERN_HELPERS_INL_H +#define ADA_URL_PATTERN_HELPERS_INL_H + +#include +#include + + +#if ADA_INCLUDE_URL_PATTERN +namespace ada::url_pattern_helpers { +#if defined(ADA_TESTING) || defined(ADA_LOGGING) +inline std::string to_string(token_type type) { + switch (type) { + case token_type::INVALID_CHAR: + return "INVALID_CHAR"; + case token_type::OPEN: + return "OPEN"; + case token_type::CLOSE: + return "CLOSE"; + case token_type::REGEXP: + return "REGEXP"; + case token_type::NAME: + return "NAME"; + case token_type::CHAR: + return "CHAR"; + case token_type::ESCAPED_CHAR: + return "ESCAPED_CHAR"; + case token_type::OTHER_MODIFIER: + return "OTHER_MODIFIER"; + case token_type::ASTERISK: + return "ASTERISK"; + case token_type::END: + return "END"; + default: + ada::unreachable(); + } +} +#endif // defined(ADA_TESTING) || defined(ADA_LOGGING) + +template +constexpr void constructor_string_parser::rewind() { + // Set parser's token index to parser's component start. + token_index = component_start; + // Set parser's token increment to 0. + token_increment = 0; +} + +template +constexpr bool constructor_string_parser::is_hash_prefix() { + // Return the result of running is a non-special pattern char given parser, + // parser's token index and "#". + return is_non_special_pattern_char(token_index, '#'); +} + +template +constexpr bool constructor_string_parser::is_search_prefix() { + // If result of running is a non-special pattern char given parser, parser's + // token index and "?" is true, then return true. + if (is_non_special_pattern_char(token_index, '?')) { + return true; + } + + // If parser's token list[parser's token index]'s value is not "?", then + // return false. + if (token_list[token_index].value != "?") { + return false; + } + + // If previous index is less than 0, then return true. + if (token_index == 0) return true; + // Let previous index be parser's token index - 1. + auto previous_index = token_index - 1; + // Let previous token be the result of running get a safe token given parser + // and previous index. + auto previous_token = get_safe_token(previous_index); + ADA_ASSERT_TRUE(previous_token); + // If any of the following are true, then return false: + // - previous token's type is "name". + // - previous token's type is "regexp". + // - previous token's type is "close". + // - previous token's type is "asterisk". + return !(previous_token->type == token_type::NAME || + previous_token->type == token_type::REGEXP || + previous_token->type == token_type::CLOSE || + previous_token->type == token_type::ASTERISK); +} + +template +constexpr bool +constructor_string_parser::is_non_special_pattern_char( + size_t index, uint32_t value) const { + // Let token be the result of running get a safe token given parser and index. + auto token = get_safe_token(index); + ADA_ASSERT_TRUE(token); + + // If token's value is not value, then return false. + // TODO: Remove this once we make sure get_safe_token returns a non-empty + // string. + if (!token->value.empty() && + static_cast(token->value[0]) != value) { + return false; + } + + // If any of the following are true: + // - token's type is "char"; + // - token's type is "escaped-char"; or + // - token's type is "invalid-char", + // - then return true. + return token->type == token_type::CHAR || + token->type == token_type::ESCAPED_CHAR || + token->type == token_type::INVALID_CHAR; +} + +template +constexpr const token* +constructor_string_parser::get_safe_token(size_t index) const { + // If index is less than parser's token list's size, then return parser's + // token list[index]. + if (index < token_list.size()) [[likely]] { + return &token_list[index]; + } + + // Assert: parser's token list's size is greater than or equal to 1. + ADA_ASSERT_TRUE(!token_list.empty()); + + // Let token be parser's token list[last index]. + // Assert: token's type is "end". + ADA_ASSERT_TRUE(token_list.back().type == token_type::END); + + // Return token. + return &token_list.back(); +} + +template +constexpr bool constructor_string_parser::is_group_open() + const { + // If parser's token list[parser's token index]'s type is "open", then return + // true. + return token_list[token_index].type == token_type::OPEN; +} + +template +constexpr bool constructor_string_parser::is_group_close() + const { + // If parser's token list[parser's token index]'s type is "close", then return + // true. + return token_list[token_index].type == token_type::CLOSE; +} + +template +constexpr bool +constructor_string_parser::next_is_authority_slashes() const { + // If the result of running is a non-special pattern char given parser, + // parser's token index + 1, and "/" is false, then return false. + if (!is_non_special_pattern_char(token_index + 1, '/')) { + return false; + } + // If the result of running is a non-special pattern char given parser, + // parser's token index + 2, and "/" is false, then return false. + if (!is_non_special_pattern_char(token_index + 2, '/')) { + return false; + } + return true; +} + +template +constexpr bool constructor_string_parser::is_protocol_suffix() + const { + // Return the result of running is a non-special pattern char given parser, + // parser's token index, and ":". + return is_non_special_pattern_char(token_index, ':'); +} + +template +void constructor_string_parser::change_state(State new_state, + size_t skip) { + // If parser's state is not "init", not "authority", and not "done", then set + // parser's result[parser's state] to the result of running make a component + // string given parser. + if (state != State::INIT && state != State::AUTHORITY && + state != State::DONE) { + auto value = make_component_string(); + // TODO: Simplify this. + switch (state) { + case State::PROTOCOL: { + result.protocol = value; + break; + } + case State::USERNAME: { + result.username = value; + break; + } + case State::PASSWORD: { + result.password = value; + break; + } + case State::HOSTNAME: { + result.hostname = value; + break; + } + case State::PORT: { + result.port = value; + break; + } + case State::PATHNAME: { + result.pathname = value; + break; + } + case State::SEARCH: { + result.search = value; + break; + } + case State::HASH: { + result.hash = value; + break; + } + default: + ada::unreachable(); + } + } + + // If parser's state is not "init" and new state is not "done", then: + if (state != State::INIT && new_state != State::DONE) { + // If parser's state is "protocol", "authority", "username", or "password"; + // new state is "port", "pathname", "search", or "hash"; and parser's + // result["hostname"] does not exist, then set parser's result["hostname"] + // to the empty string. + if ((state == State::PROTOCOL || state == State::AUTHORITY || + state == State::USERNAME || state == State::PASSWORD) && + (new_state == State::PORT || new_state == State::PATHNAME || + new_state == State::SEARCH || new_state == State::HASH) && + !result.hostname) + result.hostname = ""; + } + + // If parser's state is "protocol", "authority", "username", "password", + // "hostname", or "port"; new state is "search" or "hash"; and parser's + // result["pathname"] does not exist, then: + if ((state == State::PROTOCOL || state == State::AUTHORITY || + state == State::USERNAME || state == State::PASSWORD || + state == State::HOSTNAME || state == State::PORT) && + (new_state == State::SEARCH || new_state == State::HASH) && + !result.pathname) { + if (protocol_matches_a_special_scheme_flag) { + result.pathname = "/"; + } else { + // Otherwise, set parser's result["pathname"] to the empty string. + result.pathname = ""; + } + } + + // If parser's state is "protocol", "authority", "username", "password", + // "hostname", "port", or "pathname"; new state is "hash"; and parser's + // result["search"] does not exist, then set parser's result["search"] to + // the empty string. + if ((state == State::PROTOCOL || state == State::AUTHORITY || + state == State::USERNAME || state == State::PASSWORD || + state == State::HOSTNAME || state == State::PORT || + state == State::PATHNAME) && + new_state == State::HASH && !result.search) { + result.search = ""; + } + + // Set parser's state to new state. + state = new_state; + // Increment parser's token index by skip. + token_index += skip; + // Set parser's component start to parser's token index. + component_start = token_index; + // Set parser's token increment to 0. + token_increment = 0; +} + +template +std::string constructor_string_parser::make_component_string() { + // Assert: parser's token index is less than parser's token list's size. + ADA_ASSERT_TRUE(token_index < token_list.size()); + + // Let token be parser's token list[parser's token index]. + // Let end index be token's index. + const auto end_index = token_list[token_index].index; + // Let component start token be the result of running get a safe token given + // parser and parser's component start. + const auto component_start_token = get_safe_token(component_start); + ADA_ASSERT_TRUE(component_start_token); + // Let component start input index be component start token's index. + const auto component_start_input_index = component_start_token->index; + // Return the code point substring from component start input index to end + // index within parser's input. + return std::string(input.substr(component_start_input_index, + end_index - component_start_input_index)); +} + +template +constexpr bool +constructor_string_parser::is_an_identity_terminator() const { + // Return the result of running is a non-special pattern char given parser, + // parser's token index, and "@". + return is_non_special_pattern_char(token_index, '@'); +} + +template +constexpr bool constructor_string_parser::is_pathname_start() + const { + // Return the result of running is a non-special pattern char given parser, + // parser's token index, and "/". + return is_non_special_pattern_char(token_index, '/'); +} + +template +constexpr bool constructor_string_parser::is_password_prefix() + const { + // Return the result of running is a non-special pattern char given parser, + // parser's token index, and ":". + return is_non_special_pattern_char(token_index, ':'); +} + +template +constexpr bool constructor_string_parser::is_an_ipv6_open() + const { + // Return the result of running is a non-special pattern char given parser, + // parser's token index, and "[". + return is_non_special_pattern_char(token_index, '['); +} + +template +constexpr bool constructor_string_parser::is_an_ipv6_close() + const { + // Return the result of running is a non-special pattern char given parser, + // parser's token index, and "]". + return is_non_special_pattern_char(token_index, ']'); +} + +template +constexpr bool constructor_string_parser::is_port_prefix() + const { + // Return the result of running is a non-special pattern char given parser, + // parser's token index, and ":". + return is_non_special_pattern_char(token_index, ':'); +} + +constexpr void Tokenizer::get_next_code_point() { + ada_log("Tokenizer::get_next_code_point called with index=", next_index); + ADA_ASSERT_TRUE(next_index < input.size()); + // Decode the next UTF-8 code point. If malformed or truncated, mark it as + // invalid, return the offending byte as the code point, and advance by one + // to guarantee forward progress. + invalid_code_point = false; + code_point = 0; + size_t number_bytes = 0; + const size_t initial_index = next_index; + unsigned char first_byte = input[next_index]; + + if ((first_byte & 0x80) == 0) { + // 1-byte character (ASCII) + next_index++; + code_point = first_byte; + ada_log("Tokenizer::get_next_code_point returning ASCII code point=", + uint32_t(code_point)); + ada_log("Tokenizer::get_next_code_point next_index =", next_index, + " input.size()=", input.size()); + return; + } + ada_log("Tokenizer::get_next_code_point read first byte=", + uint32_t(first_byte)); + if ((first_byte & 0xE0) == 0xC0) { + code_point = first_byte & 0x1F; + number_bytes = 2; + ada_log("Tokenizer::get_next_code_point two bytes"); + } else if ((first_byte & 0xF0) == 0xE0) { + code_point = first_byte & 0x0F; + number_bytes = 3; + ada_log("Tokenizer::get_next_code_point three bytes"); + } else if ((first_byte & 0xF8) == 0xF0) { + code_point = first_byte & 0x07; + number_bytes = 4; + ada_log("Tokenizer::get_next_code_point four bytes"); + } + + // Invalid leading bytes that still match a multi-byte prefix. + if ((number_bytes == 2 && first_byte < 0xC2) || + (number_bytes == 4 && first_byte > 0xF4)) { + invalid_code_point = true; + code_point = first_byte; + next_index = initial_index + 1; + return; + } + + // Invalid leading byte (e.g., continuation byte outside a sequence). + if (number_bytes == 0) { + invalid_code_point = true; + code_point = first_byte; + next_index = initial_index + 1; + return; + } + + // Truncated UTF-8 sequence. + if (number_bytes + next_index > input.size()) { + invalid_code_point = true; + code_point = first_byte; + next_index = initial_index + 1; + return; + } + + for (size_t i = 1 + next_index; i < number_bytes + next_index; ++i) { + unsigned char byte = input[i]; + if ((byte & 0xC0) != 0x80) { + invalid_code_point = true; + code_point = first_byte; + next_index = initial_index + 1; + return; + } + ada_log("Tokenizer::get_next_code_point read byte=", uint32_t(byte)); + code_point = (code_point << 6) | (byte & 0x3F); + } + ada_log("Tokenizer::get_next_code_point returning non-ASCII code point=", + uint32_t(code_point)); + ada_log("Tokenizer::get_next_code_point next_index =", next_index, + " input.size()=", input.size()); + next_index += number_bytes; +} + +constexpr void Tokenizer::seek_and_get_next_code_point(size_t new_index) { + ada_log("Tokenizer::seek_and_get_next_code_point called with new_index=", + new_index); + // Set tokenizer's next index to index. + next_index = new_index; + // Run get the next code point given tokenizer. + get_next_code_point(); +} + +inline void Tokenizer::add_token(token_type type, size_t next_position, + size_t value_position, size_t value_length) { + ada_log("Tokenizer::add_token called with type=", to_string(type), + " next_position=", next_position, " value_position=", value_position); + ADA_ASSERT_TRUE(next_position >= value_position); + + // Let token be a new token. + // Set token's type to type. + // Set token's index to tokenizer's index. + // Set token's value to the code point substring from value position with + // length value length within tokenizer's input. + // Append token to the back of tokenizer's token list. + token_list.emplace_back(type, index, + input.substr(value_position, value_length)); + // Set tokenizer's index to next position. + index = next_position; +} + +inline void Tokenizer::add_token_with_default_length(token_type type, + size_t next_position, + size_t value_position) { + // Let computed length be next position - value position. + auto computed_length = next_position - value_position; + // Run add a token given tokenizer, type, next position, value position, and + // computed length. + add_token(type, next_position, value_position, computed_length); +} + +inline void Tokenizer::add_token_with_defaults(token_type type) { + ada_log("Tokenizer::add_token_with_defaults called with type=", + to_string(type)); + // Run add a token with default length given tokenizer, type, tokenizer's next + // index, and tokenizer's index. + add_token_with_default_length(type, next_index, index); +} + +inline ada_warn_unused std::optional +Tokenizer::process_tokenizing_error(size_t next_position, + size_t value_position) { + // If tokenizer's policy is "strict", then throw a TypeError. + if (policy == token_policy::strict) { + ada_log("process_tokenizing_error failed with next_position=", + next_position, " value_position=", value_position); + return errors::type_error; + } + // Assert: tokenizer's policy is "lenient". + ADA_ASSERT_TRUE(policy == token_policy::lenient); + // Run add a token with default length given tokenizer, "invalid-char", next + // position, and value position. + add_token_with_default_length(token_type::INVALID_CHAR, next_position, + value_position); + return std::nullopt; +} + +template +token* url_pattern_parser::try_consume_modifier_token() { + // Let token be the result of running try to consume a token given parser and + // "other-modifier". + auto token = try_consume_token(token_type::OTHER_MODIFIER); + // If token is not null, then return token. + if (token) return token; + // Set token to the result of running try to consume a token given parser and + // "asterisk". + // Return token. + return try_consume_token(token_type::ASTERISK); +} + +template +token* url_pattern_parser::try_consume_regexp_or_wildcard_token( + const token* name_token) { + // Let token be the result of running try to consume a token given parser and + // "regexp". + auto token = try_consume_token(token_type::REGEXP); + // If name token is null and token is null, then set token to the result of + // running try to consume a token given parser and "asterisk". + if (!name_token && !token) { + token = try_consume_token(token_type::ASTERISK); + } + // Return token. + return token; +} + +template +token* url_pattern_parser::try_consume_token(token_type type) { + ada_log("url_pattern_parser::try_consume_token called with type=", + to_string(type)); + // Assert: parser's index is less than parser's token list size. + ADA_ASSERT_TRUE(index < tokens.size()); + // Let next token be parser's token list[parser's index]. + auto& next_token = tokens[index]; + // If next token's type is not type return null. + if (next_token.type != type) return nullptr; + // Increase parser's index by 1. + index++; + // Return next token. + return &next_token; +} + +template +std::string url_pattern_parser::consume_text() { + // Let result be the empty string. + std::string result{}; + // While true: + while (true) { + // Let token be the result of running try to consume a token given parser + // and "char". + auto token = try_consume_token(token_type::CHAR); + // If token is null, then set token to the result of running try to consume + // a token given parser and "escaped-char". + if (!token) token = try_consume_token(token_type::ESCAPED_CHAR); + // If token is null, then break. + if (!token) break; + // Append token's value to the end of result. + result.append(token->value); + } + // Return result. + return result; +} + +template +bool url_pattern_parser::consume_required_token(token_type type) { + ada_log("url_pattern_parser::consume_required_token called with type=", + to_string(type)); + // Let result be the result of running try to consume a token given parser and + // type. + return try_consume_token(type) != nullptr; +} + +template +std::optional +url_pattern_parser::maybe_add_part_from_the_pending_fixed_value() { + // If parser's pending fixed value is the empty string, then return. + if (pending_fixed_value.empty()) { + ada_log("pending_fixed_value is empty"); + return std::nullopt; + } + // Let encoded value be the result of running parser's encoding callback given + // parser's pending fixed value. + auto encoded_value = encoding_callback(pending_fixed_value); + if (!encoded_value) { + ada_log("failed to encode pending_fixed_value: ", pending_fixed_value); + return encoded_value.error(); + } + // Set parser's pending fixed value to the empty string. + pending_fixed_value.clear(); + // Let part be a new part whose type is "fixed-text", value is encoded value, + // and modifier is "none". + // Append part to parser's part list. + parts.emplace_back(url_pattern_part_type::FIXED_TEXT, + std::move(*encoded_value), + url_pattern_part_modifier::none); + return std::nullopt; +} + +template +std::optional url_pattern_parser::add_part( + std::string_view prefix, token* name_token, token* regexp_or_wildcard_token, + std::string_view suffix, token* modifier_token) { + // Let modifier be "none". + auto modifier = url_pattern_part_modifier::none; + // If modifier token is not null: + if (modifier_token) { + // If modifier token's value is "?" then set modifier to "optional". + if (modifier_token->value == "?") { + modifier = url_pattern_part_modifier::optional; + } else if (modifier_token->value == "*") { + // Otherwise if modifier token's value is "*" then set modifier to + // "zero-or-more". + modifier = url_pattern_part_modifier::zero_or_more; + } else if (modifier_token->value == "+") { + // Otherwise if modifier token's value is "+" then set modifier to + // "one-or-more". + modifier = url_pattern_part_modifier::one_or_more; + } + } + // If name token is null and regexp or wildcard token is null and modifier + // is "none": + if (!name_token && !regexp_or_wildcard_token && + modifier == url_pattern_part_modifier::none) { + // Append prefix to the end of parser's pending fixed value. + pending_fixed_value.append(prefix); + return std::nullopt; + } + // Run maybe add a part from the pending fixed value given parser. + if (auto error = maybe_add_part_from_the_pending_fixed_value()) { + return *error; + } + // If name token is null and regexp or wildcard token is null: + if (!name_token && !regexp_or_wildcard_token) { + // Assert: suffix is the empty string. + ADA_ASSERT_TRUE(suffix.empty()); + // If prefix is the empty string, then return. + if (prefix.empty()) return std::nullopt; + // Let encoded value be the result of running parser's encoding callback + // given prefix. + auto encoded_value = encoding_callback(prefix); + if (!encoded_value) { + return encoded_value.error(); + } + // Let part be a new part whose type is "fixed-text", value is encoded + // value, and modifier is modifier. + // Append part to parser's part list. + parts.emplace_back(url_pattern_part_type::FIXED_TEXT, + std::move(*encoded_value), modifier); + return std::nullopt; + } + // Let regexp value be the empty string. + std::string regexp_value{}; + // If regexp or wildcard token is null, then set regexp value to parser's + // segment wildcard regexp. + if (!regexp_or_wildcard_token) { + regexp_value = segment_wildcard_regexp; + } else if (regexp_or_wildcard_token->type == token_type::ASTERISK) { + // Otherwise if regexp or wildcard token's type is "asterisk", then set + // regexp value to the full wildcard regexp value. + regexp_value = ".*"; + } else { + // Otherwise set regexp value to regexp or wildcard token's value. + regexp_value = regexp_or_wildcard_token->value; + } + // Let type be "regexp". + auto type = url_pattern_part_type::REGEXP; + // If regexp value is parser's segment wildcard regexp: + if (regexp_value == segment_wildcard_regexp) { + // Set type to "segment-wildcard". + type = url_pattern_part_type::SEGMENT_WILDCARD; + // Set regexp value to the empty string. + regexp_value.clear(); + } else if (regexp_value == ".*") { + // Otherwise if regexp value is the full wildcard regexp value: + // Set type to "full-wildcard". + type = url_pattern_part_type::FULL_WILDCARD; + // Set regexp value to the empty string. + regexp_value.clear(); + } + // Let name be the empty string. + std::string name{}; + // If name token is not null, then set name to name token's value. + if (name_token) { + name = name_token->value; + } else if (regexp_or_wildcard_token != nullptr) { + // Otherwise if regexp or wildcard token is not null: + // Set name to parser's next numeric name, serialized. + name = std::to_string(next_numeric_name); + // Increment parser's next numeric name by 1. + next_numeric_name++; + } + // If the result of running is a duplicate name given parser and name is + // true, then throw a TypeError. + if (std::ranges::any_of( + parts, [&name](const auto& part) { return part.name == name; })) { + return errors::type_error; + } + // Let encoded prefix be the result of running parser's encoding callback + // given prefix. + auto encoded_prefix = encoding_callback(prefix); + if (!encoded_prefix) return encoded_prefix.error(); + // Let encoded suffix be the result of running parser's encoding callback + // given suffix. + auto encoded_suffix = encoding_callback(suffix); + if (!encoded_suffix) return encoded_suffix.error(); + // Let part be a new part whose type is type, value is regexp value, + // modifier is modifier, name is name, prefix is encoded prefix, and suffix + // is encoded suffix. + // Append part to parser's part list. + parts.emplace_back(type, std::move(regexp_value), modifier, std::move(name), + std::move(*encoded_prefix), std::move(*encoded_suffix)); + return std::nullopt; +} + +template +tl::expected, errors> parse_pattern_string( + std::string_view input, url_pattern_compile_component_options& options, + F& encoding_callback) { + ada_log("parse_pattern_string input=", input); + // Let parser be a new pattern parser whose encoding callback is encoding + // callback and segment wildcard regexp is the result of running generate a + // segment wildcard regexp given options. + auto parser = url_pattern_parser( + encoding_callback, generate_segment_wildcard_regexp(options)); + // Set parser's token list to the result of running tokenize given input and + // "strict". + auto tokenize_result = tokenize(input, token_policy::strict); + if (!tokenize_result) { + ada_log("parse_pattern_string tokenize failed"); + return tl::unexpected(tokenize_result.error()); + } + parser.tokens = std::move(*tokenize_result); + + // While parser's index is less than parser's token list's size: + while (parser.can_continue()) { + // Let char token be the result of running try to consume a token given + // parser and "char". + auto char_token = parser.try_consume_token(token_type::CHAR); + // Let name token be the result of running try to consume a token given + // parser and "name". + auto name_token = parser.try_consume_token(token_type::NAME); + // Let regexp or wildcard token be the result of running try to consume a + // regexp or wildcard token given parser and name token. + auto regexp_or_wildcard_token = + parser.try_consume_regexp_or_wildcard_token(name_token); + // If name token is not null or regexp or wildcard token is not null: + if (name_token || regexp_or_wildcard_token) { + // Let prefix be the empty string. + std::string prefix{}; + // If char token is not null then set prefix to char token's value. + if (char_token) prefix = char_token->value; + // If prefix is not the empty string and not options's prefix code point: + if (!prefix.empty() && prefix != options.get_prefix()) { + // Append prefix to the end of parser's pending fixed value. + parser.pending_fixed_value.append(prefix); + // Set prefix to the empty string. + prefix.clear(); + } + // Run maybe add a part from the pending fixed value given parser. + if (auto error = parser.maybe_add_part_from_the_pending_fixed_value()) { + ada_log("maybe_add_part_from_the_pending_fixed_value failed"); + return tl::unexpected(*error); + } + // Let modifier token be the result of running try to consume a modifier + // token given parser. + auto modifier_token = parser.try_consume_modifier_token(); + // Run add a part given parser, prefix, name token, regexp or wildcard + // token, the empty string, and modifier token. + if (auto error = + parser.add_part(prefix, name_token, regexp_or_wildcard_token, "", + modifier_token)) { + ada_log("parser.add_part failed"); + return tl::unexpected(*error); + } + // Continue. + continue; + } + + // Let fixed token be char token. + auto fixed_token = char_token; + // If fixed token is null, then set fixed token to the result of running try + // to consume a token given parser and "escaped-char". + if (!fixed_token) + fixed_token = parser.try_consume_token(token_type::ESCAPED_CHAR); + // If fixed token is not null: + if (fixed_token) { + // Append fixed token's value to parser's pending fixed value. + parser.pending_fixed_value.append(fixed_token->value); + // Continue. + continue; + } + // Let open token be the result of running try to consume a token given + // parser and "open". + auto open_token = parser.try_consume_token(token_type::OPEN); + // If open token is not null: + if (open_token) { + // Set prefix be the result of running consume text given parser. + auto prefix_ = parser.consume_text(); + // Set name token to the result of running try to consume a token given + // parser and "name". + name_token = parser.try_consume_token(token_type::NAME); + // Set regexp or wildcard token to the result of running try to consume a + // regexp or wildcard token given parser and name token. + regexp_or_wildcard_token = + parser.try_consume_regexp_or_wildcard_token(name_token); + // Let suffix be the result of running consume text given parser. + auto suffix_ = parser.consume_text(); + // Run consume a required token given parser and "close". + if (!parser.consume_required_token(token_type::CLOSE)) { + ada_log("parser.consume_required_token failed"); + return tl::unexpected(errors::type_error); + } + // Set modifier token to the result of running try to consume a modifier + // token given parser. + auto modifier_token = parser.try_consume_modifier_token(); + // Run add a part given parser, prefix, name token, regexp or wildcard + // token, suffix, and modifier token. + if (auto error = + parser.add_part(prefix_, name_token, regexp_or_wildcard_token, + suffix_, modifier_token)) { + return tl::unexpected(*error); + } + // Continue. + continue; + } + // Run maybe add a part from the pending fixed value given parser. + if (auto error = parser.maybe_add_part_from_the_pending_fixed_value()) { + ada_log("maybe_add_part_from_the_pending_fixed_value failed on line 992"); + return tl::unexpected(*error); + } + // Run consume a required token given parser and "end". + if (!parser.consume_required_token(token_type::END)) { + return tl::unexpected(errors::type_error); + } + } + ada_log("parser.parts size is: ", parser.parts.size()); + // Return parser's part list. + return parser.parts; +} + +template +bool protocol_component_matches_special_scheme( + url_pattern_component& component) { + // Optimization: Use fast_test for simple patterns to avoid regex overhead + switch (component.type) { + case url_pattern_component_type::EMPTY: + // Empty pattern can't match any special scheme + return false; + case url_pattern_component_type::EXACT_MATCH: + // Direct string comparison for exact match patterns + return component.exact_match_value == "http" || + component.exact_match_value == "https" || + component.exact_match_value == "ws" || + component.exact_match_value == "wss" || + component.exact_match_value == "ftp" || + component.exact_match_value == "file"; + case url_pattern_component_type::FULL_WILDCARD: + // Full wildcard matches everything including special schemes + return true; + case url_pattern_component_type::REGEXP: + // Fall back to regex matching for complex patterns + auto& regex = component.regexp; + return regex_provider::regex_match("http", regex) || + regex_provider::regex_match("https", regex) || + regex_provider::regex_match("ws", regex) || + regex_provider::regex_match("wss", regex) || + regex_provider::regex_match("ftp", regex) || + regex_provider::regex_match("file", regex); + } + ada::unreachable(); +} + +template +inline std::optional constructor_string_parser< + regex_provider>::compute_protocol_matches_special_scheme_flag() { + ada_log( + "constructor_string_parser::compute_protocol_matches_special_scheme_" + "flag"); + // Let protocol string be the result of running make a component string given + // parser. + auto protocol_string = make_component_string(); + // Let protocol component be the result of compiling a component given + // protocol string, canonicalize a protocol, and default options. + auto protocol_component = url_pattern_component::compile( + protocol_string, canonicalize_protocol, + url_pattern_compile_component_options::DEFAULT); + if (!protocol_component) { + ada_log("url_pattern_component::compile failed for protocol_string ", + protocol_string); + return protocol_component.error(); + } + // If the result of running protocol component matches a special scheme given + // protocol component is true, then set parser's protocol matches a special + // scheme flag to true. + if (protocol_component_matches_special_scheme(*protocol_component)) { + protocol_matches_a_special_scheme_flag = true; + } + return std::nullopt; +} + +template +tl::expected +constructor_string_parser::parse(std::string_view input) { + ada_log("constructor_string_parser::parse input=", input); + // Let parser be a new constructor string parser whose input is input and + // token list is the result of running tokenize given input and "lenient". + auto token_list = tokenize(input, token_policy::lenient); + if (!token_list) { + return tl::unexpected(token_list.error()); + } + auto parser = constructor_string_parser(input, std::move(*token_list)); + + // While parser's token index is less than parser's token list size: + while (parser.token_index < parser.token_list.size()) { + // Set parser's token increment to 1. + parser.token_increment = 1; + + // If parser's token list[parser's token index]'s type is "end" then: + if (parser.token_list[parser.token_index].type == token_type::END) { + // If parser's state is "init": + if (parser.state == State::INIT) { + // Run rewind given parser. + parser.rewind(); + // If the result of running is a hash prefix given parser is true, then + // run change state given parser, "hash" and 1. + if (parser.is_hash_prefix()) { + parser.change_state(State::HASH, 1); + } else if (parser.is_search_prefix()) { + // Otherwise if the result of running is a search prefix given parser + // is true: Run change state given parser, "search" and 1. + parser.change_state(State::SEARCH, 1); + } else { + // Run change state given parser, "pathname" and 0. + parser.change_state(State::PATHNAME, 0); + } + // Increment parser's token index by parser's token increment. + parser.token_index += parser.token_increment; + // Continue. + continue; + } + + if (parser.state == State::AUTHORITY) { + // If parser's state is "authority": + // Run rewind and set state given parser, and "hostname". + parser.rewind(); + parser.change_state(State::HOSTNAME, 0); + // Increment parser's token index by parser's token increment. + parser.token_index += parser.token_increment; + // Continue. + continue; + } + + // Run change state given parser, "done" and 0. + parser.change_state(State::DONE, 0); + // Break. + break; + } + + // If the result of running is a group open given parser is true: + if (parser.is_group_open()) { + // Increment parser's group depth by 1. + parser.group_depth += 1; + // Increment parser's token index by parser's token increment. + parser.token_index += parser.token_increment; + // Continue. + continue; + } + + // If parser's group depth is greater than 0: + if (parser.group_depth > 0) { + // If the result of running is a group close given parser is true, then + // decrement parser's group depth by 1. + if (parser.is_group_close()) { + parser.group_depth -= 1; + } else { + // Increment parser's token index by parser's token increment. + parser.token_index += parser.token_increment; + continue; + } + } + + // Switch on parser's state and run the associated steps: + switch (parser.state) { + case State::INIT: { + // If the result of running is a protocol suffix given parser is true: + if (parser.is_protocol_suffix()) { + // Run rewind and set state given parser and "protocol". + parser.rewind(); + parser.change_state(State::PROTOCOL, 0); + } + break; + } + case State::PROTOCOL: { + // If the result of running is a protocol suffix given parser is true: + if (parser.is_protocol_suffix()) { + // Run compute protocol matches a special scheme flag given parser. + if (const auto error = + parser.compute_protocol_matches_special_scheme_flag()) { + ada_log("compute_protocol_matches_special_scheme_flag failed"); + return tl::unexpected(*error); + } + // Let next state be "pathname". + auto next_state = State::PATHNAME; + // Let skip be 1. + auto skip = 1; + // If the result of running next is authority slashes given parser is + // true: + if (parser.next_is_authority_slashes()) { + // Set next state to "authority". + next_state = State::AUTHORITY; + // Set skip to 3. + skip = 3; + } else if (parser.protocol_matches_a_special_scheme_flag) { + // Otherwise if parser's protocol matches a special scheme flag is + // true, then set next state to "authority". + next_state = State::AUTHORITY; + } + + // Run change state given parser, next state, and skip. + parser.change_state(next_state, skip); + } + break; + } + case State::AUTHORITY: { + // If the result of running is an identity terminator given parser is + // true, then run rewind and set state given parser and "username". + if (parser.is_an_identity_terminator()) { + parser.rewind(); + parser.change_state(State::USERNAME, 0); + } else if (parser.is_pathname_start() || parser.is_search_prefix() || + parser.is_hash_prefix()) { + // Otherwise if any of the following are true: + // - the result of running is a pathname start given parser; + // - the result of running is a search prefix given parser; or + // - the result of running is a hash prefix given parser, + // then run rewind and set state given parser and "hostname". + parser.rewind(); + parser.change_state(State::HOSTNAME, 0); + } + break; + } + case State::USERNAME: { + // If the result of running is a password prefix given parser is true, + // then run change state given parser, "password", and 1. + if (parser.is_password_prefix()) { + parser.change_state(State::PASSWORD, 1); + } else if (parser.is_an_identity_terminator()) { + // Otherwise if the result of running is an identity terminator given + // parser is true, then run change state given parser, "hostname", + // and 1. + parser.change_state(State::HOSTNAME, 1); + } + break; + } + case State::PASSWORD: { + // If the result of running is an identity terminator given parser is + // true, then run change state given parser, "hostname", and 1. + if (parser.is_an_identity_terminator()) { + parser.change_state(State::HOSTNAME, 1); + } + break; + } + case State::HOSTNAME: { + // If the result of running is an IPv6 open given parser is true, then + // increment parser's hostname IPv6 bracket depth by 1. + if (parser.is_an_ipv6_open()) { + parser.hostname_ipv6_bracket_depth += 1; + } else if (parser.is_an_ipv6_close()) { + // Otherwise if the result of running is an IPv6 close given parser is + // true, then decrement parser's hostname IPv6 bracket depth by 1. + parser.hostname_ipv6_bracket_depth -= 1; + } else if (parser.is_port_prefix() && + parser.hostname_ipv6_bracket_depth == 0) { + // Otherwise if the result of running is a port prefix given parser is + // true and parser's hostname IPv6 bracket depth is zero, then run + // change state given parser, "port", and 1. + parser.change_state(State::PORT, 1); + } else if (parser.is_pathname_start()) { + // Otherwise if the result of running is a pathname start given parser + // is true, then run change state given parser, "pathname", and 0. + parser.change_state(State::PATHNAME, 0); + } else if (parser.is_search_prefix()) { + // Otherwise if the result of running is a search prefix given parser + // is true, then run change state given parser, "search", and 1. + parser.change_state(State::SEARCH, 1); + } else if (parser.is_hash_prefix()) { + // Otherwise if the result of running is a hash prefix given parser is + // true, then run change state given parser, "hash", and 1. + parser.change_state(State::HASH, 1); + } + + break; + } + case State::PORT: { + // If the result of running is a pathname start given parser is true, + // then run change state given parser, "pathname", and 0. + if (parser.is_pathname_start()) { + parser.change_state(State::PATHNAME, 0); + } else if (parser.is_search_prefix()) { + // Otherwise if the result of running is a search prefix given parser + // is true, then run change state given parser, "search", and 1. + parser.change_state(State::SEARCH, 1); + } else if (parser.is_hash_prefix()) { + // Otherwise if the result of running is a hash prefix given parser is + // true, then run change state given parser, "hash", and 1. + parser.change_state(State::HASH, 1); + } + break; + } + case State::PATHNAME: { + // If the result of running is a search prefix given parser is true, + // then run change state given parser, "search", and 1. + if (parser.is_search_prefix()) { + parser.change_state(State::SEARCH, 1); + } else if (parser.is_hash_prefix()) { + // Otherwise if the result of running is a hash prefix given parser is + // true, then run change state given parser, "hash", and 1. + parser.change_state(State::HASH, 1); + } + break; + } + case State::SEARCH: { + // If the result of running is a hash prefix given parser is true, then + // run change state given parser, "hash", and 1. + if (parser.is_hash_prefix()) { + parser.change_state(State::HASH, 1); + } + break; + } + case State::HASH: { + // Do nothing + break; + } + default: { + // Assert: This step is never reached. + unreachable(); + } + } + + // Increment parser's token index by parser's token increment. + parser.token_index += parser.token_increment; + } + + // If parser's result contains "hostname" and not "port", then set parser's + // result["port"] to the empty string. + if (parser.result.hostname && !parser.result.port) { + parser.result.port = ""; + } + + // Return parser's result. + return parser.result; +} + +} // namespace ada::url_pattern_helpers +#endif // ADA_INCLUDE_URL_PATTERN +#endif +/* end file include/ada/url_pattern_helpers-inl.h */ + +// Public API +/* begin file include/ada/ada_version.h */ +/** + * @file ada_version.h + * @brief Definitions for Ada's version number. + */ +#ifndef ADA_ADA_VERSION_H +#define ADA_ADA_VERSION_H + +#define ADA_VERSION "4.0.0" + +namespace ada { + +enum { + ADA_VERSION_MAJOR = 4, + ADA_VERSION_MINOR = 0, + ADA_VERSION_REVISION = 0, +}; + +} // namespace ada + +#endif // ADA_ADA_VERSION_H +/* end file include/ada/ada_version.h */ +/* begin file include/ada/implementation-inl.h */ +/** + * @file implementation-inl.h + */ +#ifndef ADA_IMPLEMENTATION_INL_H +#define ADA_IMPLEMENTATION_INL_H + + + +#include +#include + +namespace ada { + +#if ADA_INCLUDE_URL_PATTERN +template +ada_warn_unused tl::expected, errors> +parse_url_pattern(std::variant&& input, + const std::string_view* base_url, + const url_pattern_options* options) { + return parser::parse_url_pattern_impl(std::move(input), + base_url, options); +} +#endif // ADA_INCLUDE_URL_PATTERN + +} // namespace ada + +#endif // ADA_IMPLEMENTATION_INL_H +/* end file include/ada/implementation-inl.h */ + +#endif // ADA_H +/* end file include/ada.h */ diff --git a/NativeScript/include/APIDesign.md b/NativeScript/include/APIDesign.md deleted file mode 100644 index fe42c8ed..00000000 --- a/NativeScript/include/APIDesign.md +++ /dev/null @@ -1,72 +0,0 @@ -# The V8 public C++ API - -# Overview - -The V8 public C++ API aims to support four use cases: - -1. Enable applications that embed V8 (called the embedder) to configure and run - one or more instances of V8. -2. Expose ECMAScript-like capabilities to the embedder. -3. Enable the embedder to interact with ECMAScript by exposing API objects. -4. Provide access to the V8 debugger (inspector). - -# Configuring and running an instance of V8 - -V8 requires access to certain OS-level primitives such as the ability to -schedule work on threads, or allocate memory. - -The embedder can define how to access those primitives via the v8::Platform -interface. While V8 bundles a basic implementation, embedders are highly -encouraged to implement v8::Platform themselves. - -Currently, the v8::ArrayBuffer::Allocator is passed to the v8::Isolate factory -method, however, conceptually it should also be part of the v8::Platform since -all instances of V8 should share one allocator. - -Once the v8::Platform is configured, an v8::Isolate can be created. All -further interactions with V8 should explicitly reference the v8::Isolate they -refer to. All API methods should eventually take an v8::Isolate parameter. - -When a given instance of V8 is no longer needed, it can be destroyed by -disposing the respective v8::Isolate. If the embedder wishes to free all memory -associated with the v8::Isolate, it has to first clear all global handles -associated with that v8::Isolate. - -# ECMAScript-like capabilities - -In general, the C++ API shouldn't enable capabilities that aren't available to -scripts running in V8. Experience has shown that it's not possible to maintain -such API methods in the long term. However, capabilities also available to -scripts, i.e., ones that are defined in the ECMAScript standard are there to -stay, and we can safely expose them to embedders. - -The C++ API should also be pleasant to use, and not require learning new -paradigms. Similarly to how the API exposed to scripts aims to provide good -ergonomics, we should aim to provide a reasonable developer experience for this -API surface. - -ECMAScript makes heavy use of exceptions, however, V8's C++ code doesn't use -C++ exceptions. Therefore, all API methods that can throw exceptions should -indicate so by returning a v8::Maybe<> or v8::MaybeLocal<> result, -and by taking a v8::Local<v8::Context> parameter that indicates in which -context a possible exception should be thrown. - -# API objects - -V8 allows embedders to define special objects that expose additional -capabilities and APIs to scripts. The most prominent example is exposing the -HTML DOM in Blink. Other examples are e.g. node.js. It is less clear what kind -of capabilities we want to expose via this API surface. As a rule of thumb, we -want to expose operations as defined in the WebIDL and HTML spec: we -assume that those requirements are somewhat stable, and that they are a -superset of the requirements of other embedders including node.js. - -Ideally, the API surfaces defined in those specs hook into the ECMAScript spec -which in turn guarantees long-term stability of the API. - -# The V8 inspector - -All debugging capabilities of V8 should be exposed via the inspector protocol. -The exception to this are profiling features exposed via v8-profiler.h. -Changes to the inspector protocol need to ensure backwards compatibility and -commitment to maintain. diff --git a/NativeScript/include/DEPS b/NativeScript/include/DEPS deleted file mode 100644 index 21ce3d96..00000000 --- a/NativeScript/include/DEPS +++ /dev/null @@ -1,10 +0,0 @@ -include_rules = [ - # v8-inspector-protocol.h depends on generated files under include/inspector. - "+inspector", - "+cppgc/common.h", - # Used by v8-cppgc.h to bridge to cppgc. - "+cppgc/custom-space.h", - "+cppgc/heap-statistics.h", - "+cppgc/internal/write-barrier.h", - "+cppgc/visitor.h", -] diff --git a/NativeScript/include/DIR_METADATA b/NativeScript/include/DIR_METADATA deleted file mode 100644 index a27ea1b5..00000000 --- a/NativeScript/include/DIR_METADATA +++ /dev/null @@ -1,11 +0,0 @@ -# Metadata information for this directory. -# -# For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md -# -# For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto - -monorail { - component: "Blink>JavaScript>API" -} \ No newline at end of file diff --git a/NativeScript/include/OWNERS b/NativeScript/include/OWNERS deleted file mode 100644 index 535040c5..00000000 --- a/NativeScript/include/OWNERS +++ /dev/null @@ -1,23 +0,0 @@ -adamk@chromium.org -cbruni@chromium.org -leszeks@chromium.org -mlippautz@chromium.org -verwaest@chromium.org -yangguo@chromium.org - -per-file *DEPS=file:../COMMON_OWNERS -per-file v8-internal.h=file:../COMMON_OWNERS - -per-file v8-debug.h=file:../src/debug/OWNERS - -per-file js_protocol.pdl=file:../src/inspector/OWNERS -per-file v8-inspector*=file:../src/inspector/OWNERS -per-file v8-inspector*=file:../src/inspector/OWNERS - -# Needed by the auto_tag builder -per-file v8-version.h=v8-ci-autoroll-builder@chops-service-accounts.iam.gserviceaccount.com - -# For branch updates: -per-file v8-version.h=file:../INFRA_OWNERS -per-file v8-version.h=hablich@chromium.org -per-file v8-version.h=vahl@chromium.org diff --git a/NativeScript/include/cppgc/DEPS b/NativeScript/include/cppgc/DEPS deleted file mode 100644 index 861d1187..00000000 --- a/NativeScript/include/cppgc/DEPS +++ /dev/null @@ -1,8 +0,0 @@ -include_rules = [ - "-include", - "+v8config.h", - "+v8-platform.h", - "+cppgc", - "-src", - "+libplatform/libplatform.h", -] diff --git a/NativeScript/include/cppgc/OWNERS b/NativeScript/include/cppgc/OWNERS deleted file mode 100644 index 6ccabf60..00000000 --- a/NativeScript/include/cppgc/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -bikineev@chromium.org -omerkatz@chromium.org \ No newline at end of file diff --git a/NativeScript/include/cppgc/README.md b/NativeScript/include/cppgc/README.md deleted file mode 100644 index a7d08f86..00000000 --- a/NativeScript/include/cppgc/README.md +++ /dev/null @@ -1,133 +0,0 @@ -# Oilpan: C++ Garbage Collection - -Oilpan is an open-source garbage collection library for C++ that can be used stand-alone or in collaboration with V8's JavaScript garbage collector. -Oilpan implements mark-and-sweep garbage collection (GC) with limited compaction (for a subset of objects). - -**Key properties** - -- Trace-based garbage collection; -- Incremental and concurrent marking; -- Incremental and concurrent sweeping; -- Precise on-heap memory layout; -- Conservative on-stack memory layout; -- Allows for collection with and without considering stack; -- Non-incremental and non-concurrent compaction for selected spaces; - -See the [Hello World](https://chromium.googlesource.com/v8/v8/+/main/samples/cppgc/hello-world.cc) example on how to get started using Oilpan to manage C++ code. - -Oilpan follows V8's project organization, see e.g. on how we accept [contributions](https://v8.dev/docs/contribute) and [provide a stable API](https://v8.dev/docs/api). - -## Threading model - -Oilpan features thread-local garbage collection and assumes heaps are not shared among threads. -In other words, objects are accessed and ultimately reclaimed by the garbage collector on the same thread that allocates them. -This allows Oilpan to run garbage collection in parallel with mutators running in other threads. - -References to objects belonging to another thread's heap are modeled using cross-thread roots. -This is even true for on-heap to on-heap references. - -## Heap partitioning - -Oilpan's heaps are partitioned into spaces. -The space for an object is chosen depending on a number of criteria, e.g.: - -- Objects over 64KiB are allocated in a large object space -- Objects can be assigned to a dedicated custom space. - Custom spaces can also be marked as compactable. -- Other objects are allocated in one of the normal page spaces bucketed depending on their size. - -## Precise and conservative garbage collection - -Oilpan supports two kinds of GCs: - -1. **Conservative GC.** -A GC is called conservative when it is executed while the regular native stack is not empty. -In this case, the native stack might contain references to objects in Oilpan's heap, which should be kept alive. -The GC scans the native stack and treats the pointers discovered via the native stack as part of the root set. -This kind of GC is considered imprecise because values on stack other than references may accidentally appear as references to on-heap object, which means these objects will be kept alive despite being in practice unreachable from the application as an actual reference. - -2. **Precise GC.** -A precise GC is triggered at the end of an event loop, which is controlled by an embedder via a platform. -At this point, it is guaranteed that there are no on-stack references pointing to Oilpan's heap. -This means there is no risk of confusing other value types with references. -Oilpan has precise knowledge of on-heap object layouts, and so it knows exactly where pointers lie in memory. -Oilpan can just start marking from the regular root set and collect all garbage precisely. - -## Atomic, incremental and concurrent garbage collection - -Oilpan has three modes of operation: - -1. **Atomic GC.** -The entire GC cycle, including all its phases (e.g. see [Marking](#Marking-phase) and [Sweeping](#Sweeping-phase)), are executed back to back in a single pause. -This mode of operation is also known as Stop-The-World (STW) garbage collection. -It results in the most jank (due to a single long pause), but is overall the most efficient (e.g. no need for write barriers). - -2. **Incremental GC.** -Garbage collection work is split up into multiple steps which are interleaved with the mutator, i.e. user code chunked into tasks. -Each step is a small chunk of work that is executed either as dedicated tasks between mutator tasks or, as needed, during mutator tasks. -Using incremental GC introduces the need for write barriers that record changes to the object graph so that a consistent state is observed and no objects are accidentally considered dead and reclaimed. -The incremental steps are followed by a smaller atomic pause to finalize garbage collection. -The smaller pause times, due to smaller chunks of work, helps with reducing jank. - -3. **Concurrent GC.** -This is the most common type of GC. -It builds on top of incremental GC and offloads much of the garbage collection work away from the mutator thread and on to background threads. -Using concurrent GC allows the mutator thread to spend less time on GC and more on the actual mutator. - -## Marking phase - -The marking phase consists of the following steps: - -1. Mark all objects in the root set. - -2. Mark all objects transitively reachable from the root set by calling `Trace()` methods defined on each object. - -3. Clear out all weak handles to unreachable objects and run weak callbacks. - -The marking phase can be executed atomically in a stop-the-world manner, in which all 3 steps are executed one after the other. - -Alternatively, it can also be executed incrementally/concurrently. -With incremental/concurrent marking, step 1 is executed in a short pause after which the mutator regains control. -Step 2 is repeatedly executed in an interleaved manner with the mutator. -When the GC is ready to finalize, i.e. step 2 is (almost) finished, another short pause is triggered in which step 2 is finished and step 3 is performed. - -To prevent a user-after-free (UAF) issues it is required for Oilpan to know about all edges in the object graph. -This means that all pointers except on-stack pointers must be wrapped with Oilpan's handles (i.e., Persistent<>, Member<>, WeakMember<>). -Raw pointers to on-heap objects create an edge that Oilpan cannot observe and cause UAF issues -Thus, raw pointers shall not be used to reference on-heap objects (except for raw pointers on native stacks). - -## Sweeping phase - -The sweeping phase consists of the following steps: - -1. Invoke pre-finalizers. -At this point, no destructors have been invoked and no memory has been reclaimed. -Pre-finalizers are allowed to access any other on-heap objects, even those that may get destructed. - -2. Sweeping invokes destructors of the dead (unreachable) objects and reclaims memory to be reused by future allocations. - -Assumptions should not be made about the order and the timing of their execution. -There is no guarantee on the order in which the destructors are invoked. -That's why destructors must not access any other on-heap objects (which might have already been destructed). -If some destructor unavoidably needs to access other on-heap objects, it will have to be converted to a pre-finalizer. -The pre-finalizer is allowed to access other on-heap objects. - -The mutator is resumed before all destructors have ran. -For example, imagine a case where X is a client of Y, and Y holds a list of clients. -If the code relies on X's destructor removing X from the list, there is a risk that Y iterates the list and calls some method of X which may touch other on-heap objects. -This causes a use-after-free. -Care must be taken to make sure that X is explicitly removed from the list before the mutator resumes its execution in a way that doesn't rely on X's destructor (e.g. a pre-finalizer). - -Similar to marking, sweeping can be executed in either an atomic stop-the-world manner or incrementally/concurrently. -With incremental/concurrent sweeping, step 2 is interleaved with mutator. -Incremental/concurrent sweeping can be atomically finalized in case it is needed to trigger another GC cycle. -Even with concurrent sweeping, destructors are guaranteed to run on the thread the object has been allocated on to preserve C++ semantics. - -Notes: - -* Weak processing runs only when the holder object of the WeakMember outlives the pointed object. -If the holder object and the pointed object die at the same time, weak processing doesn't run. -It is wrong to write code assuming that the weak processing always runs. - -* Pre-finalizers are heavy because the thread needs to scan all pre-finalizers at each sweeping phase to determine which pre-finalizers should be invoked (the thread needs to invoke pre-finalizers of dead objects). -Adding pre-finalizers to frequently created objects should be avoided. diff --git a/NativeScript/include/cppgc/allocation.h b/NativeScript/include/cppgc/allocation.h deleted file mode 100644 index 69883fb3..00000000 --- a/NativeScript/include/cppgc/allocation.h +++ /dev/null @@ -1,310 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_ALLOCATION_H_ -#define INCLUDE_CPPGC_ALLOCATION_H_ - -#include -#include -#include -#include -#include -#include - -#include "cppgc/custom-space.h" -#include "cppgc/internal/api-constants.h" -#include "cppgc/internal/gc-info.h" -#include "cppgc/type-traits.h" -#include "v8config.h" // NOLINT(build/include_directory) - -#if defined(__has_attribute) -#if __has_attribute(assume_aligned) -#define CPPGC_DEFAULT_ALIGNED \ - __attribute__((assume_aligned(api_constants::kDefaultAlignment))) -#define CPPGC_DOUBLE_WORD_ALIGNED \ - __attribute__((assume_aligned(2 * api_constants::kDefaultAlignment))) -#endif // __has_attribute(assume_aligned) -#endif // defined(__has_attribute) - -#if !defined(CPPGC_DEFAULT_ALIGNED) -#define CPPGC_DEFAULT_ALIGNED -#endif - -#if !defined(CPPGC_DOUBLE_WORD_ALIGNED) -#define CPPGC_DOUBLE_WORD_ALIGNED -#endif - -namespace cppgc { - -/** - * AllocationHandle is used to allocate garbage-collected objects. - */ -class AllocationHandle; - -namespace internal { - -// Similar to C++17 std::align_val_t; -enum class AlignVal : size_t {}; - -class V8_EXPORT MakeGarbageCollectedTraitInternal { - protected: - static inline void MarkObjectAsFullyConstructed(const void* payload) { - // See api_constants for an explanation of the constants. - std::atomic* atomic_mutable_bitfield = - reinterpret_cast*>( - const_cast(reinterpret_cast( - reinterpret_cast(payload) - - api_constants::kFullyConstructedBitFieldOffsetFromPayload))); - // It's safe to split use load+store here (instead of a read-modify-write - // operation), since it's guaranteed that this 16-bit bitfield is only - // modified by a single thread. This is cheaper in terms of code bloat (on - // ARM) and performance. - uint16_t value = atomic_mutable_bitfield->load(std::memory_order_relaxed); - value |= api_constants::kFullyConstructedBitMask; - atomic_mutable_bitfield->store(value, std::memory_order_release); - } - - // Dispatch based on compile-time information. - // - // Default implementation is for a custom space with >`kDefaultAlignment` byte - // alignment. - template - struct AllocationDispatcher final { - static void* Invoke(AllocationHandle& handle, size_t size) { - static_assert(std::is_base_of::value, - "Custom space must inherit from CustomSpaceBase."); - static_assert( - !CustomSpace::kSupportsCompaction, - "Custom spaces that support compaction do not support allocating " - "objects with non-default (i.e. word-sized) alignment."); - return MakeGarbageCollectedTraitInternal::Allocate( - handle, size, static_cast(alignment), - internal::GCInfoTrait::Index(), CustomSpace::kSpaceIndex); - } - }; - - // Fast path for regular allocations for the default space with - // `kDefaultAlignment` byte alignment. - template - struct AllocationDispatcher - final { - static void* Invoke(AllocationHandle& handle, size_t size) { - return MakeGarbageCollectedTraitInternal::Allocate( - handle, size, internal::GCInfoTrait::Index()); - } - }; - - // Default space with >`kDefaultAlignment` byte alignment. - template - struct AllocationDispatcher final { - static void* Invoke(AllocationHandle& handle, size_t size) { - return MakeGarbageCollectedTraitInternal::Allocate( - handle, size, static_cast(alignment), - internal::GCInfoTrait::Index()); - } - }; - - // Custom space with `kDefaultAlignment` byte alignment. - template - struct AllocationDispatcher - final { - static void* Invoke(AllocationHandle& handle, size_t size) { - static_assert(std::is_base_of::value, - "Custom space must inherit from CustomSpaceBase."); - return MakeGarbageCollectedTraitInternal::Allocate( - handle, size, internal::GCInfoTrait::Index(), - CustomSpace::kSpaceIndex); - } - }; - - private: - static void* CPPGC_DEFAULT_ALIGNED Allocate(cppgc::AllocationHandle&, size_t, - GCInfoIndex); - static void* CPPGC_DOUBLE_WORD_ALIGNED Allocate(cppgc::AllocationHandle&, - size_t, AlignVal, - GCInfoIndex); - static void* CPPGC_DEFAULT_ALIGNED Allocate(cppgc::AllocationHandle&, size_t, - GCInfoIndex, CustomSpaceIndex); - static void* CPPGC_DOUBLE_WORD_ALIGNED Allocate(cppgc::AllocationHandle&, - size_t, AlignVal, GCInfoIndex, - CustomSpaceIndex); - - friend class HeapObjectHeader; -}; - -} // namespace internal - -/** - * Base trait that provides utilities for advancers users that have custom - * allocation needs (e.g., overriding size). It's expected that users override - * MakeGarbageCollectedTrait (see below) and inherit from - * MakeGarbageCollectedTraitBase and make use of the low-level primitives - * offered to allocate and construct an object. - */ -template -class MakeGarbageCollectedTraitBase - : private internal::MakeGarbageCollectedTraitInternal { - private: - static_assert(internal::IsGarbageCollectedType::value, - "T needs to be a garbage collected object"); - static_assert(!IsGarbageCollectedWithMixinTypeV || - sizeof(T) <= - internal::api_constants::kLargeObjectSizeThreshold, - "GarbageCollectedMixin may not be a large object"); - - protected: - /** - * Allocates memory for an object of type T. - * - * \param handle AllocationHandle identifying the heap to allocate the object - * on. - * \param size The size that should be reserved for the object. - * \returns the memory to construct an object of type T on. - */ - V8_INLINE static void* Allocate(AllocationHandle& handle, size_t size) { - static_assert( - std::is_base_of::value, - "U of GarbageCollected must be a base of T. Check " - "GarbageCollected base class inheritance."); - static constexpr size_t kWantedAlignment = - alignof(T) < internal::api_constants::kDefaultAlignment - ? internal::api_constants::kDefaultAlignment - : alignof(T); - static_assert( - kWantedAlignment <= internal::api_constants::kMaxSupportedAlignment, - "Requested alignment larger than alignof(std::max_align_t) bytes. " - "Please file a bug to possibly get this restriction lifted."); - return AllocationDispatcher< - typename internal::GCInfoFolding< - T, typename T::ParentMostGarbageCollectedType>::ResultType, - typename SpaceTrait::Space, kWantedAlignment>::Invoke(handle, size); - } - - /** - * Marks an object as fully constructed, resulting in precise handling by the - * garbage collector. - * - * \param payload The base pointer the object is allocated at. - */ - V8_INLINE static void MarkObjectAsFullyConstructed(const void* payload) { - internal::MakeGarbageCollectedTraitInternal::MarkObjectAsFullyConstructed( - payload); - } -}; - -/** - * Passed to MakeGarbageCollected to specify how many bytes should be appended - * to the allocated object. - * - * Example: - * \code - * class InlinedArray final : public GarbageCollected { - * public: - * explicit InlinedArray(size_t bytes) : size(bytes), byte_array(this + 1) {} - * void Trace(Visitor*) const {} - - * size_t size; - * char* byte_array; - * }; - * - * auto* inlined_array = MakeGarbageCollectedbyte_array[i]); - * } - * \endcode - */ -struct AdditionalBytes { - constexpr explicit AdditionalBytes(size_t bytes) : value(bytes) {} - const size_t value; -}; - -/** - * Default trait class that specifies how to construct an object of type T. - * Advanced users may override how an object is constructed using the utilities - * that are provided through MakeGarbageCollectedTraitBase. - * - * Any trait overriding construction must - * - allocate through `MakeGarbageCollectedTraitBase::Allocate`; - * - mark the object as fully constructed using - * `MakeGarbageCollectedTraitBase::MarkObjectAsFullyConstructed`; - */ -template -class MakeGarbageCollectedTrait : public MakeGarbageCollectedTraitBase { - public: - template - static T* Call(AllocationHandle& handle, Args&&... args) { - void* memory = - MakeGarbageCollectedTraitBase::Allocate(handle, sizeof(T)); - T* object = ::new (memory) T(std::forward(args)...); - MakeGarbageCollectedTraitBase::MarkObjectAsFullyConstructed(object); - return object; - } - - template - static T* Call(AllocationHandle& handle, AdditionalBytes additional_bytes, - Args&&... args) { - void* memory = MakeGarbageCollectedTraitBase::Allocate( - handle, sizeof(T) + additional_bytes.value); - T* object = ::new (memory) T(std::forward(args)...); - MakeGarbageCollectedTraitBase::MarkObjectAsFullyConstructed(object); - return object; - } -}; - -/** - * Allows users to specify a post-construction callback for specific types. The - * callback is invoked on the instance of type T right after it has been - * constructed. This can be useful when the callback requires a - * fully-constructed object to be able to dispatch to virtual methods. - */ -template -struct PostConstructionCallbackTrait { - static void Call(T*) {} -}; - -/** - * Constructs a managed object of type T where T transitively inherits from - * GarbageCollected. - * - * \param args List of arguments with which an instance of T will be - * constructed. - * \returns an instance of type T. - */ -template -V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle, Args&&... args) { - T* object = - MakeGarbageCollectedTrait::Call(handle, std::forward(args)...); - PostConstructionCallbackTrait::Call(object); - return object; -} - -/** - * Constructs a managed object of type T where T transitively inherits from - * GarbageCollected. Created objects will have additional bytes appended to - * it. Allocated memory would suffice for `sizeof(T) + additional_bytes`. - * - * \param additional_bytes Denotes how many bytes to append to T. - * \param args List of arguments with which an instance of T will be - * constructed. - * \returns an instance of type T. - */ -template -V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle, - AdditionalBytes additional_bytes, - Args&&... args) { - T* object = MakeGarbageCollectedTrait::Call(handle, additional_bytes, - std::forward(args)...); - PostConstructionCallbackTrait::Call(object); - return object; -} - -} // namespace cppgc - -#undef CPPGC_DEFAULT_ALIGNED -#undef CPPGC_DOUBLE_WORD_ALIGNED - -#endif // INCLUDE_CPPGC_ALLOCATION_H_ diff --git a/NativeScript/include/cppgc/common.h b/NativeScript/include/cppgc/common.h deleted file mode 100644 index b6dbff3d..00000000 --- a/NativeScript/include/cppgc/common.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_COMMON_H_ -#define INCLUDE_CPPGC_COMMON_H_ - -// TODO(chromium:1056170): Remove dependency on v8. -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -/** - * Indicator for the stack state of the embedder. - */ -enum class EmbedderStackState { - /** - * Stack may contain interesting heap pointers. - */ - kMayContainHeapPointers, - /** - * Stack does not contain any interesting heap pointers. - */ - kNoHeapPointers, -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_COMMON_H_ diff --git a/NativeScript/include/cppgc/cross-thread-persistent.h b/NativeScript/include/cppgc/cross-thread-persistent.h deleted file mode 100644 index c8751e1d..00000000 --- a/NativeScript/include/cppgc/cross-thread-persistent.h +++ /dev/null @@ -1,465 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_ -#define INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_ - -#include - -#include "cppgc/internal/persistent-node.h" -#include "cppgc/internal/pointer-policies.h" -#include "cppgc/persistent.h" -#include "cppgc/visitor.h" - -namespace cppgc { -namespace internal { - -// Wrapper around PersistentBase that allows accessing poisoned memory when -// using ASAN. This is needed as the GC of the heap that owns the value -// of a CTP, may clear it (heap termination, weakness) while the object -// holding the CTP may be poisoned as itself may be deemed dead. -class CrossThreadPersistentBase : public PersistentBase { - public: - CrossThreadPersistentBase() = default; - explicit CrossThreadPersistentBase(const void* raw) : PersistentBase(raw) {} - - V8_CLANG_NO_SANITIZE("address") const void* GetValueFromGC() const { - return raw_; - } - - V8_CLANG_NO_SANITIZE("address") - PersistentNode* GetNodeFromGC() const { return node_; } - - V8_CLANG_NO_SANITIZE("address") - void ClearFromGC() const { - raw_ = nullptr; - SetNodeSafe(nullptr); - } - - // GetNodeSafe() can be used for a thread-safe IsValid() check in a - // double-checked locking pattern. See ~BasicCrossThreadPersistent. - PersistentNode* GetNodeSafe() const { - return reinterpret_cast*>(&node_)->load( - std::memory_order_acquire); - } - - // The GC writes using SetNodeSafe() while holding the lock. - V8_CLANG_NO_SANITIZE("address") - void SetNodeSafe(PersistentNode* value) const { -#if defined(__has_feature) -#if __has_feature(address_sanitizer) -#define V8_IS_ASAN 1 -#endif -#endif - -#ifdef V8_IS_ASAN - __atomic_store(&node_, &value, __ATOMIC_RELEASE); -#else // !V8_IS_ASAN - // Non-ASAN builds can use atomics. This also covers MSVC which does not - // have the __atomic_store intrinsic. - reinterpret_cast*>(&node_)->store( - value, std::memory_order_release); -#endif // !V8_IS_ASAN - -#undef V8_IS_ASAN - } -}; - -template -class BasicCrossThreadPersistent final : public CrossThreadPersistentBase, - public LocationPolicy, - private WeaknessPolicy, - private CheckingPolicy { - public: - using typename WeaknessPolicy::IsStrongPersistent; - using PointeeType = T; - - ~BasicCrossThreadPersistent() { - // This implements fast path for destroying empty/sentinel. - // - // Simplified version of `AssignUnsafe()` to allow calling without a - // complete type `T`. Uses double-checked locking with a simple thread-safe - // check for a valid handle based on a node. - if (GetNodeSafe()) { - PersistentRegionLock guard; - const void* old_value = GetValue(); - // The fast path check (GetNodeSafe()) does not acquire the lock. Recheck - // validity while holding the lock to ensure the reference has not been - // cleared. - if (IsValid(old_value)) { - CrossThreadPersistentRegion& region = - this->GetPersistentRegion(old_value); - region.FreeNode(GetNode()); - SetNode(nullptr); - } else { - CPPGC_DCHECK(!GetNode()); - } - } - // No need to call SetValue() as the handle is not used anymore. This can - // leave behind stale sentinel values but will always destroy the underlying - // node. - } - - BasicCrossThreadPersistent( - const SourceLocation& loc = SourceLocation::Current()) - : LocationPolicy(loc) {} - - BasicCrossThreadPersistent( - std::nullptr_t, const SourceLocation& loc = SourceLocation::Current()) - : LocationPolicy(loc) {} - - BasicCrossThreadPersistent( - SentinelPointer s, const SourceLocation& loc = SourceLocation::Current()) - : CrossThreadPersistentBase(s), LocationPolicy(loc) {} - - BasicCrossThreadPersistent( - T* raw, const SourceLocation& loc = SourceLocation::Current()) - : CrossThreadPersistentBase(raw), LocationPolicy(loc) { - if (!IsValid(raw)) return; - PersistentRegionLock guard; - CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw); - SetNode(region.AllocateNode(this, &Trace)); - this->CheckPointer(raw); - } - - class UnsafeCtorTag { - private: - UnsafeCtorTag() = default; - template - friend class BasicCrossThreadPersistent; - }; - - BasicCrossThreadPersistent( - UnsafeCtorTag, T* raw, - const SourceLocation& loc = SourceLocation::Current()) - : CrossThreadPersistentBase(raw), LocationPolicy(loc) { - if (!IsValid(raw)) return; - CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw); - SetNode(region.AllocateNode(this, &Trace)); - this->CheckPointer(raw); - } - - BasicCrossThreadPersistent( - T& raw, const SourceLocation& loc = SourceLocation::Current()) - : BasicCrossThreadPersistent(&raw, loc) {} - - template ::value>> - BasicCrossThreadPersistent( - internal::BasicMember - member, - const SourceLocation& loc = SourceLocation::Current()) - : BasicCrossThreadPersistent(member.Get(), loc) {} - - BasicCrossThreadPersistent( - const BasicCrossThreadPersistent& other, - const SourceLocation& loc = SourceLocation::Current()) - : BasicCrossThreadPersistent(loc) { - // Invoke operator=. - *this = other; - } - - // Heterogeneous ctor. - template ::value>> - BasicCrossThreadPersistent( - const BasicCrossThreadPersistent& other, - const SourceLocation& loc = SourceLocation::Current()) - : BasicCrossThreadPersistent(loc) { - *this = other; - } - - BasicCrossThreadPersistent( - BasicCrossThreadPersistent&& other, - const SourceLocation& loc = SourceLocation::Current()) noexcept { - // Invoke operator=. - *this = std::move(other); - } - - BasicCrossThreadPersistent& operator=( - const BasicCrossThreadPersistent& other) { - PersistentRegionLock guard; - AssignSafe(guard, other.Get()); - return *this; - } - - template ::value>> - BasicCrossThreadPersistent& operator=( - const BasicCrossThreadPersistent& other) { - PersistentRegionLock guard; - AssignSafe(guard, other.Get()); - return *this; - } - - BasicCrossThreadPersistent& operator=(BasicCrossThreadPersistent&& other) { - if (this == &other) return *this; - Clear(); - PersistentRegionLock guard; - PersistentBase::operator=(std::move(other)); - LocationPolicy::operator=(std::move(other)); - if (!IsValid(GetValue())) return *this; - GetNode()->UpdateOwner(this); - other.SetValue(nullptr); - other.SetNode(nullptr); - this->CheckPointer(Get()); - return *this; - } - - /** - * Assigns a raw pointer. - * - * Note: **Not thread-safe.** - */ - BasicCrossThreadPersistent& operator=(T* other) { - AssignUnsafe(other); - return *this; - } - - // Assignment from member. - template ::value>> - BasicCrossThreadPersistent& operator=( - internal::BasicMember - member) { - return operator=(member.Get()); - } - - /** - * Assigns a nullptr. - * - * \returns the handle. - */ - BasicCrossThreadPersistent& operator=(std::nullptr_t) { - Clear(); - return *this; - } - - /** - * Assigns the sentinel pointer. - * - * \returns the handle. - */ - BasicCrossThreadPersistent& operator=(SentinelPointer s) { - PersistentRegionLock guard; - AssignSafe(guard, s); - return *this; - } - - /** - * Returns a pointer to the stored object. - * - * Note: **Not thread-safe.** - * - * \returns a pointer to the stored object. - */ - // CFI cast exemption to allow passing SentinelPointer through T* and support - // heterogeneous assignments between different Member and Persistent handles - // based on their actual types. - V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const { - return static_cast(const_cast(GetValue())); - } - - /** - * Clears the stored object. - */ - void Clear() { - PersistentRegionLock guard; - AssignSafe(guard, nullptr); - } - - /** - * Returns a pointer to the stored object and releases it. - * - * Note: **Not thread-safe.** - * - * \returns a pointer to the stored object. - */ - T* Release() { - T* result = Get(); - Clear(); - return result; - } - - /** - * Conversio to boolean. - * - * Note: **Not thread-safe.** - * - * \returns true if an actual object has been stored and false otherwise. - */ - explicit operator bool() const { return Get(); } - - /** - * Conversion to object of type T. - * - * Note: **Not thread-safe.** - * - * \returns the object. - */ - operator T*() const { return Get(); } - - /** - * Dereferences the stored object. - * - * Note: **Not thread-safe.** - */ - T* operator->() const { return Get(); } - T& operator*() const { return *Get(); } - - template - BasicCrossThreadPersistent - To() const { - using OtherBasicCrossThreadPersistent = - BasicCrossThreadPersistent; - PersistentRegionLock guard; - return OtherBasicCrossThreadPersistent( - typename OtherBasicCrossThreadPersistent::UnsafeCtorTag(), - static_cast(Get())); - } - - template ::IsStrongPersistent::value>::type> - BasicCrossThreadPersistent - Lock() const { - return BasicCrossThreadPersistent< - U, internal::StrongCrossThreadPersistentPolicy>(*this); - } - - private: - static bool IsValid(const void* ptr) { - return ptr && ptr != kSentinelPointer; - } - - static void Trace(Visitor* v, const void* ptr) { - const auto* handle = static_cast(ptr); - v->TraceRoot(*handle, handle->Location()); - } - - void AssignUnsafe(T* ptr) { - const void* old_value = GetValue(); - if (IsValid(old_value)) { - PersistentRegionLock guard; - old_value = GetValue(); - // The fast path check (IsValid()) does not acquire the lock. Reload - // the value to ensure the reference has not been cleared. - if (IsValid(old_value)) { - CrossThreadPersistentRegion& region = - this->GetPersistentRegion(old_value); - if (IsValid(ptr) && (®ion == &this->GetPersistentRegion(ptr))) { - SetValue(ptr); - this->CheckPointer(ptr); - return; - } - region.FreeNode(GetNode()); - SetNode(nullptr); - } else { - CPPGC_DCHECK(!GetNode()); - } - } - SetValue(ptr); - if (!IsValid(ptr)) return; - PersistentRegionLock guard; - SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &Trace)); - this->CheckPointer(ptr); - } - - void AssignSafe(PersistentRegionLock&, T* ptr) { - PersistentRegionLock::AssertLocked(); - const void* old_value = GetValue(); - if (IsValid(old_value)) { - CrossThreadPersistentRegion& region = - this->GetPersistentRegion(old_value); - if (IsValid(ptr) && (®ion == &this->GetPersistentRegion(ptr))) { - SetValue(ptr); - this->CheckPointer(ptr); - return; - } - region.FreeNode(GetNode()); - SetNode(nullptr); - } - SetValue(ptr); - if (!IsValid(ptr)) return; - SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &Trace)); - this->CheckPointer(ptr); - } - - void ClearFromGC() const { - if (IsValid(GetValueFromGC())) { - WeaknessPolicy::GetPersistentRegion(GetValueFromGC()) - .FreeNode(GetNodeFromGC()); - CrossThreadPersistentBase::ClearFromGC(); - } - } - - // See Get() for details. - V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") - T* GetFromGC() const { - return static_cast(const_cast(GetValueFromGC())); - } - - friend class cppgc::Visitor; -}; - -template -struct IsWeak< - BasicCrossThreadPersistent> - : std::true_type {}; - -} // namespace internal - -namespace subtle { - -/** - * **DO NOT USE: Has known caveats, see below.** - * - * CrossThreadPersistent allows retaining objects from threads other than the - * thread the owning heap is operating on. - * - * Known caveats: - * - Does not protect the heap owning an object from terminating. - * - Reaching transitively through the graph is unsupported as objects may be - * moved concurrently on the thread owning the object. - */ -template -using CrossThreadPersistent = internal::BasicCrossThreadPersistent< - T, internal::StrongCrossThreadPersistentPolicy>; - -/** - * **DO NOT USE: Has known caveats, see below.** - * - * CrossThreadPersistent allows weakly retaining objects from threads other than - * the thread the owning heap is operating on. - * - * Known caveats: - * - Does not protect the heap owning an object from terminating. - * - Reaching transitively through the graph is unsupported as objects may be - * moved concurrently on the thread owning the object. - */ -template -using WeakCrossThreadPersistent = internal::BasicCrossThreadPersistent< - T, internal::WeakCrossThreadPersistentPolicy>; - -} // namespace subtle -} // namespace cppgc - -#endif // INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_ diff --git a/NativeScript/include/cppgc/custom-space.h b/NativeScript/include/cppgc/custom-space.h deleted file mode 100644 index 757c4fde..00000000 --- a/NativeScript/include/cppgc/custom-space.h +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_CUSTOM_SPACE_H_ -#define INCLUDE_CPPGC_CUSTOM_SPACE_H_ - -#include - -namespace cppgc { - -/** - * Index identifying a custom space. - */ -struct CustomSpaceIndex { - constexpr CustomSpaceIndex(size_t value) : value(value) {} // NOLINT - size_t value; -}; - -/** - * Top-level base class for custom spaces. Users must inherit from CustomSpace - * below. - */ -class CustomSpaceBase { - public: - virtual ~CustomSpaceBase() = default; - virtual CustomSpaceIndex GetCustomSpaceIndex() const = 0; - virtual bool IsCompactable() const = 0; -}; - -/** - * Base class custom spaces should directly inherit from. The class inheriting - * from `CustomSpace` must define `kSpaceIndex` as unique space index. These - * indices need for form a sequence starting at 0. - * - * Example: - * \code - * class CustomSpace1 : public CustomSpace { - * public: - * static constexpr CustomSpaceIndex kSpaceIndex = 0; - * }; - * class CustomSpace2 : public CustomSpace { - * public: - * static constexpr CustomSpaceIndex kSpaceIndex = 1; - * }; - * \endcode - */ -template -class CustomSpace : public CustomSpaceBase { - public: - /** - * Compaction is only supported on spaces that manually manage slots - * recording. - */ - static constexpr bool kSupportsCompaction = false; - - CustomSpaceIndex GetCustomSpaceIndex() const final { - return ConcreteCustomSpace::kSpaceIndex; - } - bool IsCompactable() const final { - return ConcreteCustomSpace::kSupportsCompaction; - } -}; - -/** - * User-overridable trait that allows pinning types to custom spaces. - */ -template -struct SpaceTrait { - using Space = void; -}; - -namespace internal { - -template -struct IsAllocatedOnCompactableSpaceImpl { - static constexpr bool value = CustomSpace::kSupportsCompaction; -}; - -template <> -struct IsAllocatedOnCompactableSpaceImpl { - // Non-custom spaces are by default not compactable. - static constexpr bool value = false; -}; - -template -struct IsAllocatedOnCompactableSpace { - public: - static constexpr bool value = - IsAllocatedOnCompactableSpaceImpl::Space>::value; -}; - -} // namespace internal - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_CUSTOM_SPACE_H_ diff --git a/NativeScript/include/cppgc/default-platform.h b/NativeScript/include/cppgc/default-platform.h deleted file mode 100644 index a27871cc..00000000 --- a/NativeScript/include/cppgc/default-platform.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_DEFAULT_PLATFORM_H_ -#define INCLUDE_CPPGC_DEFAULT_PLATFORM_H_ - -#include - -#include "cppgc/platform.h" -#include "libplatform/libplatform.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -/** - * Platform provided by cppgc. Uses V8's DefaultPlatform provided by - * libplatform internally. Exception: `GetForegroundTaskRunner()`, see below. - */ -class V8_EXPORT DefaultPlatform : public Platform { - public: - using IdleTaskSupport = v8::platform::IdleTaskSupport; - explicit DefaultPlatform( - int thread_pool_size = 0, - IdleTaskSupport idle_task_support = IdleTaskSupport::kDisabled, - std::unique_ptr tracing_controller = {}) - : v8_platform_(v8::platform::NewDefaultPlatform( - thread_pool_size, idle_task_support, - v8::platform::InProcessStackDumping::kDisabled, - std::move(tracing_controller))) {} - - cppgc::PageAllocator* GetPageAllocator() override { - return v8_platform_->GetPageAllocator(); - } - - double MonotonicallyIncreasingTime() override { - return v8_platform_->MonotonicallyIncreasingTime(); - } - - std::shared_ptr GetForegroundTaskRunner() override { - // V8's default platform creates a new task runner when passed the - // `v8::Isolate` pointer the first time. For non-default platforms this will - // require getting the appropriate task runner. - return v8_platform_->GetForegroundTaskRunner(kNoIsolate); - } - - std::unique_ptr PostJob( - cppgc::TaskPriority priority, - std::unique_ptr job_task) override { - return v8_platform_->PostJob(priority, std::move(job_task)); - } - - TracingController* GetTracingController() override { - return v8_platform_->GetTracingController(); - } - - v8::Platform* GetV8Platform() const { return v8_platform_.get(); } - - protected: - static constexpr v8::Isolate* kNoIsolate = nullptr; - - std::unique_ptr v8_platform_; -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_DEFAULT_PLATFORM_H_ diff --git a/NativeScript/include/cppgc/ephemeron-pair.h b/NativeScript/include/cppgc/ephemeron-pair.h deleted file mode 100644 index e16cf1f0..00000000 --- a/NativeScript/include/cppgc/ephemeron-pair.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_EPHEMERON_PAIR_H_ -#define INCLUDE_CPPGC_EPHEMERON_PAIR_H_ - -#include "cppgc/liveness-broker.h" -#include "cppgc/member.h" - -namespace cppgc { - -/** - * An ephemeron pair is used to conditionally retain an object. - * The `value` will be kept alive only if the `key` is alive. - */ -template -struct EphemeronPair { - EphemeronPair(K* k, V* v) : key(k), value(v) {} - WeakMember key; - Member value; - - void ClearValueIfKeyIsDead(const LivenessBroker& broker) { - if (!broker.IsHeapObjectAlive(key)) value = nullptr; - } -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_EPHEMERON_PAIR_H_ diff --git a/NativeScript/include/cppgc/explicit-management.h b/NativeScript/include/cppgc/explicit-management.h deleted file mode 100644 index 0290328d..00000000 --- a/NativeScript/include/cppgc/explicit-management.h +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_ -#define INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_ - -#include - -#include "cppgc/allocation.h" -#include "cppgc/internal/logging.h" -#include "cppgc/type-traits.h" - -namespace cppgc { - -class HeapHandle; - -namespace subtle { - -template -void FreeUnreferencedObject(HeapHandle& heap_handle, T& object); -template -bool Resize(T& object, AdditionalBytes additional_bytes); - -} // namespace subtle - -namespace internal { - -class ExplicitManagementImpl final { - private: - V8_EXPORT static void FreeUnreferencedObject(HeapHandle&, void*); - V8_EXPORT static bool Resize(void*, size_t); - - template - friend void subtle::FreeUnreferencedObject(HeapHandle&, T&); - template - friend bool subtle::Resize(T&, AdditionalBytes); -}; -} // namespace internal - -namespace subtle { - -/** - * Informs the garbage collector that `object` can be immediately reclaimed. The - * destructor may not be invoked immediately but only on next garbage - * collection. - * - * It is up to the embedder to guarantee that no other object holds a reference - * to `object` after calling `FreeUnreferencedObject()`. In case such a - * reference exists, it's use results in a use-after-free. - * - * To aid in using the API, `FreeUnreferencedObject()` may be called from - * destructors on objects that would be reclaimed in the same garbage collection - * cycle. - * - * \param heap_handle The corresponding heap. - * \param object Reference to an object that is of type `GarbageCollected` and - * should be immediately reclaimed. - */ -template -void FreeUnreferencedObject(HeapHandle& heap_handle, T& object) { - static_assert(IsGarbageCollectedTypeV, - "Object must be of type GarbageCollected."); - internal::ExplicitManagementImpl::FreeUnreferencedObject(heap_handle, - &object); -} - -/** - * Tries to resize `object` of type `T` with additional bytes on top of - * sizeof(T). Resizing is only useful with trailing inlined storage, see e.g. - * `MakeGarbageCollected(AllocationHandle&, AdditionalBytes)`. - * - * `Resize()` performs growing or shrinking as needed and may skip the operation - * for internal reasons, see return value. - * - * It is up to the embedder to guarantee that in case of shrinking a larger - * object down, the reclaimed area is not used anymore. Any subsequent use - * results in a use-after-free. - * - * The `object` must be live when calling `Resize()`. - * - * \param object Reference to an object that is of type `GarbageCollected` and - * should be resized. - * \param additional_bytes Bytes in addition to sizeof(T) that the object should - * provide. - * \returns true when the operation was successful and the result can be relied - * on, and false otherwise. - */ -template -bool Resize(T& object, AdditionalBytes additional_bytes) { - static_assert(IsGarbageCollectedTypeV, - "Object must be of type GarbageCollected."); - return internal::ExplicitManagementImpl::Resize( - &object, sizeof(T) + additional_bytes.value); -} - -} // namespace subtle -} // namespace cppgc - -#endif // INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_ diff --git a/NativeScript/include/cppgc/garbage-collected.h b/NativeScript/include/cppgc/garbage-collected.h deleted file mode 100644 index 6737c8be..00000000 --- a/NativeScript/include/cppgc/garbage-collected.h +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_GARBAGE_COLLECTED_H_ -#define INCLUDE_CPPGC_GARBAGE_COLLECTED_H_ - -#include "cppgc/internal/api-constants.h" -#include "cppgc/platform.h" -#include "cppgc/trace-trait.h" -#include "cppgc/type-traits.h" - -namespace cppgc { - -class Visitor; - -/** - * Base class for managed objects. Only descendent types of `GarbageCollected` - * can be constructed using `MakeGarbageCollected()`. Must be inherited from as - * left-most base class. - * - * Types inheriting from GarbageCollected must provide a method of - * signature `void Trace(cppgc::Visitor*) const` that dispatchs all managed - * pointers to the visitor and delegates to garbage-collected base classes. - * The method must be virtual if the type is not directly a child of - * GarbageCollected and marked as final. - * - * \code - * // Example using final class. - * class FinalType final : public GarbageCollected { - * public: - * void Trace(cppgc::Visitor* visitor) const { - * // Dispatch using visitor->Trace(...); - * } - * }; - * - * // Example using non-final base class. - * class NonFinalBase : public GarbageCollected { - * public: - * virtual void Trace(cppgc::Visitor*) const {} - * }; - * - * class FinalChild final : public NonFinalBase { - * public: - * void Trace(cppgc::Visitor* visitor) const final { - * // Dispatch using visitor->Trace(...); - * NonFinalBase::Trace(visitor); - * } - * }; - * \endcode - */ -template -class GarbageCollected { - public: - using IsGarbageCollectedTypeMarker = void; - using ParentMostGarbageCollectedType = T; - - // Must use MakeGarbageCollected. - void* operator new(size_t) = delete; - void* operator new[](size_t) = delete; - // The garbage collector is taking care of reclaiming the object. Also, - // virtual destructor requires an unambiguous, accessible 'operator delete'. - void operator delete(void*) { -#ifdef V8_ENABLE_CHECKS - internal::Fatal( - "Manually deleting a garbage collected object is not allowed"); -#endif // V8_ENABLE_CHECKS - } - void operator delete[](void*) = delete; - - protected: - GarbageCollected() = default; -}; - -/** - * Base class for managed mixin objects. Such objects cannot be constructed - * directly but must be mixed into the inheritance hierarchy of a - * GarbageCollected object. - * - * Types inheriting from GarbageCollectedMixin must override a virtual method - * of signature `void Trace(cppgc::Visitor*) const` that dispatchs all managed - * pointers to the visitor and delegates to base classes. - * - * \code - * class Mixin : public GarbageCollectedMixin { - * public: - * void Trace(cppgc::Visitor* visitor) const override { - * // Dispatch using visitor->Trace(...); - * } - * }; - * \endcode - */ -class GarbageCollectedMixin { - public: - using IsGarbageCollectedMixinTypeMarker = void; - - /** - * This Trace method must be overriden by objects inheriting from - * GarbageCollectedMixin. - */ - virtual void Trace(cppgc::Visitor*) const {} -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_GARBAGE_COLLECTED_H_ diff --git a/NativeScript/include/cppgc/heap-consistency.h b/NativeScript/include/cppgc/heap-consistency.h deleted file mode 100644 index 54a4dbc2..00000000 --- a/NativeScript/include/cppgc/heap-consistency.h +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_HEAP_CONSISTENCY_H_ -#define INCLUDE_CPPGC_HEAP_CONSISTENCY_H_ - -#include - -#include "cppgc/internal/write-barrier.h" -#include "cppgc/macros.h" -#include "cppgc/trace-trait.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -class HeapHandle; - -namespace subtle { - -/** - * **DO NOT USE: Use the appropriate managed types.** - * - * Consistency helpers that aid in maintaining a consistent internal state of - * the garbage collector. - */ -class HeapConsistency final { - public: - using WriteBarrierParams = internal::WriteBarrier::Params; - using WriteBarrierType = internal::WriteBarrier::Type; - - /** - * Gets the required write barrier type for a specific write. - * - * \param slot Slot containing the pointer to the object. The slot itself - * must reside in an object that has been allocated using - * `MakeGarbageCollected()`. - * \param value The pointer to the object. May be an interior pointer to an - * interface of the actual object. - * \param params Parameters that may be used for actual write barrier calls. - * Only filled if return value indicates that a write barrier is needed. The - * contents of the `params` are an implementation detail. - * \returns whether a write barrier is needed and which barrier to invoke. - */ - static V8_INLINE WriteBarrierType GetWriteBarrierType( - const void* slot, const void* value, WriteBarrierParams& params) { - return internal::WriteBarrier::GetWriteBarrierType(slot, value, params); - } - - /** - * Gets the required write barrier type for a specific write. - * - * \param slot Slot to some part of an object. The object must not necessarily - have been allocated using `MakeGarbageCollected()` but can also live - off-heap or on stack. - * \param params Parameters that may be used for actual write barrier calls. - * Only filled if return value indicates that a write barrier is needed. The - * contents of the `params` are an implementation detail. - * \param callback Callback returning the corresponding heap handle. The - * callback is only invoked if the heap cannot otherwise be figured out. The - * callback must not allocate. - * \returns whether a write barrier is needed and which barrier to invoke. - */ - template - static V8_INLINE WriteBarrierType - GetWriteBarrierType(const void* slot, WriteBarrierParams& params, - HeapHandleCallback callback) { - return internal::WriteBarrier::GetWriteBarrierType(slot, params, callback); - } - - /** - * Gets the required write barrier type for a specific write. - * This version is meant to be used in conjunction with with a marking write - * barrier barrier which doesn't consider the slot. - * - * \param value The pointer to the object. May be an interior pointer to an - * interface of the actual object. - * \param params Parameters that may be used for actual write barrier calls. - * Only filled if return value indicates that a write barrier is needed. The - * contents of the `params` are an implementation detail. - * \returns whether a write barrier is needed and which barrier to invoke. - */ - static V8_INLINE WriteBarrierType - GetWriteBarrierType(const void* value, WriteBarrierParams& params) { - return internal::WriteBarrier::GetWriteBarrierType(value, params); - } - - /** - * Conservative Dijkstra-style write barrier that processes an object if it - * has not yet been processed. - * - * \param params The parameters retrieved from `GetWriteBarrierType()`. - * \param object The pointer to the object. May be an interior pointer to a - * an interface of the actual object. - */ - static V8_INLINE void DijkstraWriteBarrier(const WriteBarrierParams& params, - const void* object) { - internal::WriteBarrier::DijkstraMarkingBarrier(params, object); - } - - /** - * Conservative Dijkstra-style write barrier that processes a range of - * elements if they have not yet been processed. - * - * \param params The parameters retrieved from `GetWriteBarrierType()`. - * \param first_element Pointer to the first element that should be processed. - * The slot itself must reside in an object that has been allocated using - * `MakeGarbageCollected()`. - * \param element_size Size of the element in bytes. - * \param number_of_elements Number of elements that should be processed, - * starting with `first_element`. - * \param trace_callback The trace callback that should be invoked for each - * element if necessary. - */ - static V8_INLINE void DijkstraWriteBarrierRange( - const WriteBarrierParams& params, const void* first_element, - size_t element_size, size_t number_of_elements, - TraceCallback trace_callback) { - internal::WriteBarrier::DijkstraMarkingBarrierRange( - params, first_element, element_size, number_of_elements, - trace_callback); - } - - /** - * Steele-style write barrier that re-processes an object if it has already - * been processed. - * - * \param params The parameters retrieved from `GetWriteBarrierType()`. - * \param object The pointer to the object which must point to an object that - * has been allocated using `MakeGarbageCollected()`. Interior pointers are - * not supported. - */ - static V8_INLINE void SteeleWriteBarrier(const WriteBarrierParams& params, - const void* object) { - internal::WriteBarrier::SteeleMarkingBarrier(params, object); - } - - /** - * Generational barrier for maintaining consistency when running with multiple - * generations. - * - * \param params The parameters retrieved from `GetWriteBarrierType()`. - * \param slot Slot containing the pointer to the object. The slot itself - * must reside in an object that has been allocated using - * `MakeGarbageCollected()`. - */ - static V8_INLINE void GenerationalBarrier(const WriteBarrierParams& params, - const void* slot) { - internal::WriteBarrier::GenerationalBarrier(params, slot); - } - - /** - * Generational barrier for source object that may contain outgoing pointers - * to objects in young generation. - * - * \param params The parameters retrieved from `GetWriteBarrierType()`. - * \param inner_pointer Pointer to the source object. - */ - static V8_INLINE void GenerationalBarrierForSourceObject( - const WriteBarrierParams& params, const void* inner_pointer) { - internal::WriteBarrier::GenerationalBarrierForSourceObject(params, - inner_pointer); - } - - private: - HeapConsistency() = delete; -}; - -/** - * Disallows garbage collection finalizations. Any garbage collection triggers - * result in a crash when in this scope. - * - * Note that the garbage collector already covers paths that can lead to garbage - * collections, so user code does not require checking - * `IsGarbageCollectionAllowed()` before allocations. - */ -class V8_EXPORT V8_NODISCARD DisallowGarbageCollectionScope final { - CPPGC_STACK_ALLOCATED(); - - public: - /** - * \returns whether garbage collections are currently allowed. - */ - static bool IsGarbageCollectionAllowed(HeapHandle& heap_handle); - - /** - * Enters a disallow garbage collection scope. Must be paired with `Leave()`. - * Prefer a scope instance of `DisallowGarbageCollectionScope`. - * - * \param heap_handle The corresponding heap. - */ - static void Enter(HeapHandle& heap_handle); - - /** - * Leaves a disallow garbage collection scope. Must be paired with `Enter()`. - * Prefer a scope instance of `DisallowGarbageCollectionScope`. - * - * \param heap_handle The corresponding heap. - */ - static void Leave(HeapHandle& heap_handle); - - /** - * Constructs a scoped object that automatically enters and leaves a disallow - * garbage collection scope based on its lifetime. - * - * \param heap_handle The corresponding heap. - */ - explicit DisallowGarbageCollectionScope(HeapHandle& heap_handle); - ~DisallowGarbageCollectionScope(); - - DisallowGarbageCollectionScope(const DisallowGarbageCollectionScope&) = - delete; - DisallowGarbageCollectionScope& operator=( - const DisallowGarbageCollectionScope&) = delete; - - private: - HeapHandle& heap_handle_; -}; - -/** - * Avoids invoking garbage collection finalizations. Already running garbage - * collection phase are unaffected by this scope. - * - * Should only be used temporarily as the scope has an impact on memory usage - * and follow up garbage collections. - */ -class V8_EXPORT V8_NODISCARD NoGarbageCollectionScope final { - CPPGC_STACK_ALLOCATED(); - - public: - /** - * Enters a no garbage collection scope. Must be paired with `Leave()`. Prefer - * a scope instance of `NoGarbageCollectionScope`. - * - * \param heap_handle The corresponding heap. - */ - static void Enter(HeapHandle& heap_handle); - - /** - * Leaves a no garbage collection scope. Must be paired with `Enter()`. Prefer - * a scope instance of `NoGarbageCollectionScope`. - * - * \param heap_handle The corresponding heap. - */ - static void Leave(HeapHandle& heap_handle); - - /** - * Constructs a scoped object that automatically enters and leaves a no - * garbage collection scope based on its lifetime. - * - * \param heap_handle The corresponding heap. - */ - explicit NoGarbageCollectionScope(HeapHandle& heap_handle); - ~NoGarbageCollectionScope(); - - NoGarbageCollectionScope(const NoGarbageCollectionScope&) = delete; - NoGarbageCollectionScope& operator=(const NoGarbageCollectionScope&) = delete; - - private: - HeapHandle& heap_handle_; -}; - -} // namespace subtle -} // namespace cppgc - -#endif // INCLUDE_CPPGC_HEAP_CONSISTENCY_H_ diff --git a/NativeScript/include/cppgc/heap-state.h b/NativeScript/include/cppgc/heap-state.h deleted file mode 100644 index 28212589..00000000 --- a/NativeScript/include/cppgc/heap-state.h +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_HEAP_STATE_H_ -#define INCLUDE_CPPGC_HEAP_STATE_H_ - -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -class HeapHandle; - -namespace subtle { - -/** - * Helpers to peek into heap-internal state. - */ -class V8_EXPORT HeapState final { - public: - /** - * Returns whether the garbage collector is marking. This API is experimental - * and is expected to be removed in future. - * - * \param heap_handle The corresponding heap. - * \returns true if the garbage collector is currently marking, and false - * otherwise. - */ - static bool IsMarking(const HeapHandle& heap_handle); - - /* - * Returns whether the garbage collector is sweeping. This API is experimental - * and is expected to be removed in future. - * - * \param heap_handle The corresponding heap. - * \returns true if the garbage collector is currently sweeping, and false - * otherwise. - */ - static bool IsSweeping(const HeapHandle& heap_handle); - - /* - * Returns whether the garbage collector is currently sweeping on the thread - * owning this heap. This API allows the caller to determine whether it has - * been called from a destructor of a managed object. This API is experimental - * and may be removed in future. - * - * \param heap_handle The corresponding heap. - * \returns true if the garbage collector is currently sweeping on this - * thread, and false otherwise. - */ - static bool IsSweepingOnOwningThread(const HeapHandle& heap_handle); - - /** - * Returns whether the garbage collector is in the atomic pause, i.e., the - * mutator is stopped from running. This API is experimental and is expected - * to be removed in future. - * - * \param heap_handle The corresponding heap. - * \returns true if the garbage collector is currently in the atomic pause, - * and false otherwise. - */ - static bool IsInAtomicPause(const HeapHandle& heap_handle); - - /** - * Returns whether the last garbage collection was finalized conservatively - * (i.e., with a non-empty stack). This API is experimental and is expected to - * be removed in future. - * - * \param heap_handle The corresponding heap. - * \returns true if the last garbage collection was finalized conservatively, - * and false otherwise. - */ - static bool PreviousGCWasConservative(const HeapHandle& heap_handle); - - private: - HeapState() = delete; -}; - -} // namespace subtle -} // namespace cppgc - -#endif // INCLUDE_CPPGC_HEAP_STATE_H_ diff --git a/NativeScript/include/cppgc/heap-statistics.h b/NativeScript/include/cppgc/heap-statistics.h deleted file mode 100644 index 8e626596..00000000 --- a/NativeScript/include/cppgc/heap-statistics.h +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_HEAP_STATISTICS_H_ -#define INCLUDE_CPPGC_HEAP_STATISTICS_H_ - -#include -#include -#include -#include - -namespace cppgc { - -/** - * `HeapStatistics` contains memory consumption and utilization statistics for a - * cppgc heap. - */ -struct HeapStatistics final { - /** - * Specifies the detail level of the heap statistics. Brief statistics contain - * only the top-level allocated and used memory statistics for the entire - * heap. Detailed statistics also contain a break down per space and page, as - * well as freelist statistics and object type histograms. Note that used - * memory reported by brief statistics and detailed statistics might differ - * slightly. - */ - enum DetailLevel : uint8_t { - kBrief, - kDetailed, - }; - - /** - * Object statistics for a single type. - */ - struct ObjectStatsEntry { - /** - * Number of allocated bytes. - */ - size_t allocated_bytes; - /** - * Number of allocated objects. - */ - size_t object_count; - }; - - /** - * Page granularity statistics. For each page the statistics record the - * allocated memory size and overall used memory size for the page. - */ - struct PageStatistics { - /** Overall committed amount of memory for the page. */ - size_t committed_size_bytes = 0; - /** Resident amount of memory held by the page. */ - size_t resident_size_bytes = 0; - /** Amount of memory actually used on the page. */ - size_t used_size_bytes = 0; - /** Statistics for object allocated on the page. Filled only when - * NameProvider::HideInternalNames() is false. */ - std::vector object_statistics; - }; - - /** - * Statistics of the freelist (used only in non-large object spaces). For - * each bucket in the freelist the statistics record the bucket size, the - * number of freelist entries in the bucket, and the overall allocated memory - * consumed by these freelist entries. - */ - struct FreeListStatistics { - /** bucket sizes in the freelist. */ - std::vector bucket_size; - /** number of freelist entries per bucket. */ - std::vector free_count; - /** memory size consumed by freelist entries per size. */ - std::vector free_size; - }; - - /** - * Space granularity statistics. For each space the statistics record the - * space name, the amount of allocated memory and overall used memory for the - * space. The statistics also contain statistics for each of the space's - * pages, its freelist and the objects allocated on the space. - */ - struct SpaceStatistics { - /** The space name */ - std::string name; - /** Overall committed amount of memory for the heap. */ - size_t committed_size_bytes = 0; - /** Resident amount of memory held by the heap. */ - size_t resident_size_bytes = 0; - /** Amount of memory actually used on the space. */ - size_t used_size_bytes = 0; - /** Statistics for each of the pages in the space. */ - std::vector page_stats; - /** Statistics for the freelist of the space. */ - FreeListStatistics free_list_stats; - }; - - /** Overall committed amount of memory for the heap. */ - size_t committed_size_bytes = 0; - /** Resident amount of memory help by the heap. */ - size_t resident_size_bytes = 0; - /** Amount of memory actually used on the heap. */ - size_t used_size_bytes = 0; - /** Detail level of this HeapStatistics. */ - DetailLevel detail_level; - - /** Statistics for each of the spaces in the heap. Filled only when - * `detail_level` is `DetailLevel::kDetailed`. */ - std::vector space_stats; - - /** - * Vector of `cppgc::GarbageCollected` type names. - */ - std::vector type_names; -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_HEAP_STATISTICS_H_ diff --git a/NativeScript/include/cppgc/heap.h b/NativeScript/include/cppgc/heap.h deleted file mode 100644 index aa3c6f46..00000000 --- a/NativeScript/include/cppgc/heap.h +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_HEAP_H_ -#define INCLUDE_CPPGC_HEAP_H_ - -#include -#include -#include -#include - -#include "cppgc/common.h" -#include "cppgc/custom-space.h" -#include "cppgc/platform.h" -#include "v8config.h" // NOLINT(build/include_directory) - -/** - * cppgc - A C++ garbage collection library. - */ -namespace cppgc { - -class AllocationHandle; - -/** - * Implementation details of cppgc. Those details are considered internal and - * may change at any point in time without notice. Users should never rely on - * the contents of this namespace. - */ -namespace internal { -class Heap; -} // namespace internal - -/** - * Used for additional heap APIs. - */ -class HeapHandle; - -class V8_EXPORT Heap { - public: - /** - * Specifies the stack state the embedder is in. - */ - using StackState = EmbedderStackState; - - /** - * Specifies whether conservative stack scanning is supported. - */ - enum class StackSupport : uint8_t { - /** - * Conservative stack scan is supported. - */ - kSupportsConservativeStackScan, - /** - * Conservative stack scan is not supported. Embedders may use this option - * when using custom infrastructure that is unsupported by the library. - */ - kNoConservativeStackScan, - }; - - /** - * Specifies supported marking types - */ - enum class MarkingType : uint8_t { - /** - * Atomic stop-the-world marking. This option does not require any write - * barriers but is the most intrusive in terms of jank. - */ - kAtomic, - /** - * Incremental marking interleaves marking with the rest of the application - * workload on the same thread. - */ - kIncremental, - /** - * Incremental and concurrent marking. - */ - kIncrementalAndConcurrent - }; - - /** - * Specifies supported sweeping types - */ - enum class SweepingType : uint8_t { - /** - * Atomic stop-the-world sweeping. All of sweeping is performed at once. - */ - kAtomic, - /** - * Incremental sweeping interleaves sweeping with the rest of the - * application workload on the same thread. - */ - kIncremental, - /** - * Incremental and concurrent sweeping. Sweeping is split and interleaved - * with the rest of the application. - */ - kIncrementalAndConcurrent - }; - - /** - * Constraints for a Heap setup. - */ - struct ResourceConstraints { - /** - * Allows the heap to grow to some initial size in bytes before triggering - * garbage collections. This is useful when it is known that applications - * need a certain minimum heap to run to avoid repeatedly invoking the - * garbage collector when growing the heap. - */ - size_t initial_heap_size_bytes = 0; - }; - - /** - * Options specifying Heap properties (e.g. custom spaces) when initializing a - * heap through `Heap::Create()`. - */ - struct HeapOptions { - /** - * Creates reasonable defaults for instantiating a Heap. - * - * \returns the HeapOptions that can be passed to `Heap::Create()`. - */ - static HeapOptions Default() { return {}; } - - /** - * Custom spaces added to heap are required to have indices forming a - * numbered sequence starting at 0, i.e., their `kSpaceIndex` must - * correspond to the index they reside in the vector. - */ - std::vector> custom_spaces; - - /** - * Specifies whether conservative stack scan is supported. When conservative - * stack scan is not supported, the collector may try to invoke - * garbage collections using non-nestable task, which are guaranteed to have - * no interesting stack, through the provided Platform. If such tasks are - * not supported by the Platform, the embedder must take care of invoking - * the GC through `ForceGarbageCollectionSlow()`. - */ - StackSupport stack_support = StackSupport::kSupportsConservativeStackScan; - - /** - * Specifies which types of marking are supported by the heap. - */ - MarkingType marking_support = MarkingType::kIncrementalAndConcurrent; - - /** - * Specifies which types of sweeping are supported by the heap. - */ - SweepingType sweeping_support = SweepingType::kIncrementalAndConcurrent; - - /** - * Resource constraints specifying various properties that the internal - * GC scheduler follows. - */ - ResourceConstraints resource_constraints; - }; - - /** - * Creates a new heap that can be used for object allocation. - * - * \param platform implemented and provided by the embedder. - * \param options HeapOptions specifying various properties for the Heap. - * \returns a new Heap instance. - */ - static std::unique_ptr Create( - std::shared_ptr platform, - HeapOptions options = HeapOptions::Default()); - - virtual ~Heap() = default; - - /** - * Forces garbage collection. - * - * \param source String specifying the source (or caller) triggering a - * forced garbage collection. - * \param reason String specifying the reason for the forced garbage - * collection. - * \param stack_state The embedder stack state, see StackState. - */ - void ForceGarbageCollectionSlow( - const char* source, const char* reason, - StackState stack_state = StackState::kMayContainHeapPointers); - - /** - * \returns the opaque handle for allocating objects using - * `MakeGarbageCollected()`. - */ - AllocationHandle& GetAllocationHandle(); - - /** - * \returns the opaque heap handle which may be used to refer to this heap in - * other APIs. Valid as long as the underlying `Heap` is alive. - */ - HeapHandle& GetHeapHandle(); - - private: - Heap() = default; - - friend class internal::Heap; -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_HEAP_H_ diff --git a/NativeScript/include/cppgc/internal/api-constants.h b/NativeScript/include/cppgc/internal/api-constants.h deleted file mode 100644 index a50d4d04..00000000 --- a/NativeScript/include/cppgc/internal/api-constants.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_API_CONSTANTS_H_ -#define INCLUDE_CPPGC_INTERNAL_API_CONSTANTS_H_ - -#include -#include - -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { -namespace internal { - -// Embedders should not rely on this code! - -// Internal constants to avoid exposing internal types on the API surface. -namespace api_constants { - -constexpr size_t kKB = 1024; -constexpr size_t kMB = kKB * 1024; -constexpr size_t kGB = kMB * 1024; - -// Offset of the uint16_t bitfield from the payload contaning the -// in-construction bit. This is subtracted from the payload pointer to get -// to the right bitfield. -static constexpr size_t kFullyConstructedBitFieldOffsetFromPayload = - 2 * sizeof(uint16_t); -// Mask for in-construction bit. -static constexpr uint16_t kFullyConstructedBitMask = uint16_t{1}; - -static constexpr size_t kPageSize = size_t{1} << 17; - -static constexpr size_t kLargeObjectSizeThreshold = kPageSize / 2; - -#if defined(CPPGC_CAGED_HEAP) -constexpr size_t kCagedHeapReservationSize = static_cast(4) * kGB; -constexpr size_t kCagedHeapReservationAlignment = kCagedHeapReservationSize; -#endif - -static constexpr size_t kDefaultAlignment = sizeof(void*); - -// Maximum support alignment for a type as in `alignof(T)`. -static constexpr size_t kMaxSupportedAlignment = 2 * kDefaultAlignment; - -// Granularity of heap allocations. -constexpr size_t kAllocationGranularity = sizeof(void*); - -} // namespace api_constants - -} // namespace internal -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_API_CONSTANTS_H_ diff --git a/NativeScript/include/cppgc/internal/atomic-entry-flag.h b/NativeScript/include/cppgc/internal/atomic-entry-flag.h deleted file mode 100644 index 5a7d3b8f..00000000 --- a/NativeScript/include/cppgc/internal/atomic-entry-flag.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_ -#define INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_ - -#include - -namespace cppgc { -namespace internal { - -// A flag which provides a fast check whether a scope may be entered on the -// current thread, without needing to access thread-local storage or mutex. Can -// have false positives (i.e., spuriously report that it might be entered), so -// it is expected that this will be used in tandem with a precise check that the -// scope is in fact entered on that thread. -// -// Example: -// g_frobnicating_flag.MightBeEntered() && -// ThreadLocalFrobnicator().IsFrobnicating() -// -// Relaxed atomic operations are sufficient, since: -// - all accesses remain atomic -// - each thread must observe its own operations in order -// - no thread ever exits the flag more times than it enters (if used correctly) -// And so if a thread observes zero, it must be because it has observed an equal -// number of exits as entries. -class AtomicEntryFlag final { - public: - void Enter() { entries_.fetch_add(1, std::memory_order_relaxed); } - void Exit() { entries_.fetch_sub(1, std::memory_order_relaxed); } - - // Returns false only if the current thread is not between a call to Enter - // and a call to Exit. Returns true if this thread or another thread may - // currently be in the scope guarded by this flag. - bool MightBeEntered() const { - return entries_.load(std::memory_order_relaxed) != 0; - } - - private: - std::atomic_int entries_{0}; -}; - -} // namespace internal -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_ diff --git a/NativeScript/include/cppgc/internal/caged-heap-local-data.h b/NativeScript/include/cppgc/internal/caged-heap-local-data.h deleted file mode 100644 index a27649c1..00000000 --- a/NativeScript/include/cppgc/internal/caged-heap-local-data.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_ -#define INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_ - -#include -#include -#include - -#include "cppgc/internal/api-constants.h" -#include "cppgc/internal/logging.h" -#include "cppgc/platform.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { -namespace internal { - -class HeapBase; - -#if defined(CPPGC_YOUNG_GENERATION) - -// AgeTable is the bytemap needed for the fast generation check in the write -// barrier. AgeTable contains entries that correspond to 512 bytes memory -// regions (cards). Each entry in the table represents generation of the objects -// that reside on the corresponding card (young, old or mixed). -class AgeTable final { - static constexpr size_t kRequiredSize = 1 * api_constants::kMB; - static constexpr size_t kAllocationGranularity = - api_constants::kAllocationGranularity; - - public: - enum class Age : uint8_t { kOld, kYoung, kMixed }; - - static constexpr size_t kCardSizeInBytes = - (api_constants::kCagedHeapReservationSize / kAllocationGranularity) / - kRequiredSize; - - void SetAge(uintptr_t cage_offset, Age age) { - table_[card(cage_offset)] = age; - } - V8_INLINE Age GetAge(uintptr_t cage_offset) const { - return table_[card(cage_offset)]; - } - - void Reset(PageAllocator* allocator); - - private: - V8_INLINE size_t card(uintptr_t offset) const { - constexpr size_t kGranularityBits = - __builtin_ctz(static_cast(kCardSizeInBytes)); - const size_t entry = offset >> kGranularityBits; - CPPGC_DCHECK(table_.size() > entry); - return entry; - } - - std::array table_; -}; - -static_assert(sizeof(AgeTable) == 1 * api_constants::kMB, - "Size of AgeTable is 1MB"); - -#endif // CPPGC_YOUNG_GENERATION - -struct CagedHeapLocalData final { - CagedHeapLocalData(HeapBase&, PageAllocator&); - - bool is_incremental_marking_in_progress = false; - HeapBase& heap_base; -#if defined(CPPGC_YOUNG_GENERATION) - AgeTable age_table; -#endif -}; - -} // namespace internal -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_ diff --git a/NativeScript/include/cppgc/internal/compiler-specific.h b/NativeScript/include/cppgc/internal/compiler-specific.h deleted file mode 100644 index 595b6398..00000000 --- a/NativeScript/include/cppgc/internal/compiler-specific.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_ -#define INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_ - -namespace cppgc { - -#if defined(__has_attribute) -#define CPPGC_HAS_ATTRIBUTE(FEATURE) __has_attribute(FEATURE) -#else -#define CPPGC_HAS_ATTRIBUTE(FEATURE) 0 -#endif - -#if defined(__has_cpp_attribute) -#define CPPGC_HAS_CPP_ATTRIBUTE(FEATURE) __has_cpp_attribute(FEATURE) -#else -#define CPPGC_HAS_CPP_ATTRIBUTE(FEATURE) 0 -#endif - -// [[no_unique_address]] comes in C++20 but supported in clang with -std >= -// c++11. -#if CPPGC_HAS_CPP_ATTRIBUTE(no_unique_address) -#define CPPGC_NO_UNIQUE_ADDRESS [[no_unique_address]] -#else -#define CPPGC_NO_UNIQUE_ADDRESS -#endif - -#if CPPGC_HAS_ATTRIBUTE(unused) -#define CPPGC_UNUSED __attribute__((unused)) -#else -#define CPPGC_UNUSED -#endif - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_ diff --git a/NativeScript/include/cppgc/internal/finalizer-trait.h b/NativeScript/include/cppgc/internal/finalizer-trait.h deleted file mode 100644 index ab49af87..00000000 --- a/NativeScript/include/cppgc/internal/finalizer-trait.h +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_ -#define INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_ - -#include - -#include "cppgc/type-traits.h" - -namespace cppgc { -namespace internal { - -using FinalizationCallback = void (*)(void*); - -template -struct HasFinalizeGarbageCollectedObject : std::false_type {}; - -template -struct HasFinalizeGarbageCollectedObject< - T, - std::void_t().FinalizeGarbageCollectedObject())>> - : std::true_type {}; - -// The FinalizerTraitImpl specifies how to finalize objects. -template -struct FinalizerTraitImpl; - -template -struct FinalizerTraitImpl { - private: - // Dispatch to custom FinalizeGarbageCollectedObject(). - struct Custom { - static void Call(void* obj) { - static_cast(obj)->FinalizeGarbageCollectedObject(); - } - }; - - // Dispatch to regular destructor. - struct Destructor { - static void Call(void* obj) { static_cast(obj)->~T(); } - }; - - using FinalizeImpl = - std::conditional_t::value, Custom, - Destructor>; - - public: - static void Finalize(void* obj) { - static_assert(sizeof(T), "T must be fully defined"); - FinalizeImpl::Call(obj); - } -}; - -template -struct FinalizerTraitImpl { - static void Finalize(void* obj) { - static_assert(sizeof(T), "T must be fully defined"); - } -}; - -// The FinalizerTrait is used to determine if a type requires finalization and -// what finalization means. -template -struct FinalizerTrait { - private: - // Object has a finalizer if it has - // - a custom FinalizeGarbageCollectedObject method, or - // - a destructor. - static constexpr bool kNonTrivialFinalizer = - internal::HasFinalizeGarbageCollectedObject::value || - !std::is_trivially_destructible::type>::value; - - static void Finalize(void* obj) { - internal::FinalizerTraitImpl::Finalize(obj); - } - - public: - static constexpr bool HasFinalizer() { return kNonTrivialFinalizer; } - - // The callback used to finalize an object of type T. - static constexpr FinalizationCallback kCallback = - kNonTrivialFinalizer ? Finalize : nullptr; -}; - -template -constexpr FinalizationCallback FinalizerTrait::kCallback; - -} // namespace internal -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_ diff --git a/NativeScript/include/cppgc/internal/gc-info.h b/NativeScript/include/cppgc/internal/gc-info.h deleted file mode 100644 index 82a0d053..00000000 --- a/NativeScript/include/cppgc/internal/gc-info.h +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_GC_INFO_H_ -#define INCLUDE_CPPGC_INTERNAL_GC_INFO_H_ - -#include -#include -#include - -#include "cppgc/internal/finalizer-trait.h" -#include "cppgc/internal/name-trait.h" -#include "cppgc/trace-trait.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { -namespace internal { - -using GCInfoIndex = uint16_t; - -struct V8_EXPORT EnsureGCInfoIndexTrait final { - // Acquires a new GC info object and returns the index. In addition, also - // updates `registered_index` atomically. - template - V8_INLINE static GCInfoIndex EnsureIndex( - std::atomic& registered_index) { - return EnsureGCInfoIndexTraitDispatch{}(registered_index); - } - - private: - template ::value, - bool = FinalizerTrait::HasFinalizer(), - bool = NameTrait::HasNonHiddenName()> - struct EnsureGCInfoIndexTraitDispatch; - - static GCInfoIndex EnsureGCInfoIndexPolymorphic(std::atomic&, - TraceCallback, - FinalizationCallback, - NameCallback); - static GCInfoIndex EnsureGCInfoIndexPolymorphic(std::atomic&, - TraceCallback, - FinalizationCallback); - static GCInfoIndex EnsureGCInfoIndexPolymorphic(std::atomic&, - TraceCallback, NameCallback); - static GCInfoIndex EnsureGCInfoIndexPolymorphic(std::atomic&, - TraceCallback); - static GCInfoIndex EnsureGCInfoIndexNonPolymorphic(std::atomic&, - TraceCallback, - FinalizationCallback, - - NameCallback); - static GCInfoIndex EnsureGCInfoIndexNonPolymorphic(std::atomic&, - TraceCallback, - FinalizationCallback); - static GCInfoIndex EnsureGCInfoIndexNonPolymorphic(std::atomic&, - TraceCallback, - NameCallback); - static GCInfoIndex EnsureGCInfoIndexNonPolymorphic(std::atomic&, - TraceCallback); -}; - -#define DISPATCH(is_polymorphic, has_finalizer, has_non_hidden_name, function) \ - template \ - struct EnsureGCInfoIndexTrait::EnsureGCInfoIndexTraitDispatch< \ - T, is_polymorphic, has_finalizer, has_non_hidden_name> { \ - V8_INLINE GCInfoIndex \ - operator()(std::atomic& registered_index) { \ - return function; \ - } \ - }; - -// --------------------------------------------------------------------- // -// DISPATCH(is_polymorphic, has_finalizer, has_non_hidden_name, function) -// --------------------------------------------------------------------- // -DISPATCH(true, true, true, // - EnsureGCInfoIndexPolymorphic(registered_index, // - TraceTrait::Trace, // - FinalizerTrait::kCallback, // - NameTrait::GetName)) // -DISPATCH(true, true, false, // - EnsureGCInfoIndexPolymorphic(registered_index, // - TraceTrait::Trace, // - FinalizerTrait::kCallback)) // -DISPATCH(true, false, true, // - EnsureGCInfoIndexPolymorphic(registered_index, // - TraceTrait::Trace, // - NameTrait::GetName)) // -DISPATCH(true, false, false, // - EnsureGCInfoIndexPolymorphic(registered_index, // - TraceTrait::Trace)) // -DISPATCH(false, true, true, // - EnsureGCInfoIndexNonPolymorphic(registered_index, // - TraceTrait::Trace, // - FinalizerTrait::kCallback, // - NameTrait::GetName)) // -DISPATCH(false, true, false, // - EnsureGCInfoIndexNonPolymorphic(registered_index, // - TraceTrait::Trace, // - FinalizerTrait::kCallback)) // -DISPATCH(false, false, true, // - EnsureGCInfoIndexNonPolymorphic(registered_index, // - TraceTrait::Trace, // - NameTrait::GetName)) // -DISPATCH(false, false, false, // - EnsureGCInfoIndexNonPolymorphic(registered_index, // - TraceTrait::Trace)) // - -#undef DISPATCH - -// Fold types based on finalizer behavior. Note that finalizer characteristics -// align with trace behavior, i.e., destructors are virtual when trace methods -// are and vice versa. -template -struct GCInfoFolding { - static constexpr bool kHasVirtualDestructorAtBase = - std::has_virtual_destructor::value; - static constexpr bool kBothTypesAreTriviallyDestructible = - std::is_trivially_destructible::value && - std::is_trivially_destructible::value; - static constexpr bool kHasCustomFinalizerDispatchAtBase = - internal::HasFinalizeGarbageCollectedObject< - ParentMostGarbageCollectedType>::value; -#ifdef CPPGC_SUPPORTS_OBJECT_NAMES - static constexpr bool kWantsDetailedObjectNames = true; -#else // !CPPGC_SUPPORTS_OBJECT_NAMES - static constexpr bool kWantsDetailedObjectNames = false; -#endif // !CPPGC_SUPPORTS_OBJECT_NAMES - - // Folding would regresses name resolution when deriving names from C++ - // class names as it would just folds a name to the base class name. - using ResultType = std::conditional_t<(kHasVirtualDestructorAtBase || - kBothTypesAreTriviallyDestructible || - kHasCustomFinalizerDispatchAtBase) && - !kWantsDetailedObjectNames, - ParentMostGarbageCollectedType, T>; -}; - -// Trait determines how the garbage collector treats objects wrt. to traversing, -// finalization, and naming. -template -struct GCInfoTrait final { - V8_INLINE static GCInfoIndex Index() { - static_assert(sizeof(T), "T must be fully defined"); - static std::atomic - registered_index; // Uses zero initialization. - const GCInfoIndex index = registered_index.load(std::memory_order_acquire); - return index ? index - : EnsureGCInfoIndexTrait::EnsureIndex(registered_index); - } -}; - -} // namespace internal -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_GC_INFO_H_ diff --git a/NativeScript/include/cppgc/internal/logging.h b/NativeScript/include/cppgc/internal/logging.h deleted file mode 100644 index 3a279fe0..00000000 --- a/NativeScript/include/cppgc/internal/logging.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_LOGGING_H_ -#define INCLUDE_CPPGC_INTERNAL_LOGGING_H_ - -#include "cppgc/source-location.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { -namespace internal { - -void V8_EXPORT DCheckImpl(const char*, - const SourceLocation& = SourceLocation::Current()); -[[noreturn]] void V8_EXPORT -FatalImpl(const char*, const SourceLocation& = SourceLocation::Current()); - -// Used to ignore -Wunused-variable. -template -struct EatParams {}; - -#if defined(DEBUG) -#define CPPGC_DCHECK_MSG(condition, message) \ - do { \ - if (V8_UNLIKELY(!(condition))) { \ - ::cppgc::internal::DCheckImpl(message); \ - } \ - } while (false) -#else // !defined(DEBUG) -#define CPPGC_DCHECK_MSG(condition, message) \ - (static_cast(::cppgc::internal::EatParams(condition), message)>{})) -#endif // !defined(DEBUG) - -#define CPPGC_DCHECK(condition) CPPGC_DCHECK_MSG(condition, #condition) - -#define CPPGC_CHECK_MSG(condition, message) \ - do { \ - if (V8_UNLIKELY(!(condition))) { \ - ::cppgc::internal::FatalImpl(message); \ - } \ - } while (false) - -#define CPPGC_CHECK(condition) CPPGC_CHECK_MSG(condition, #condition) - -} // namespace internal -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_LOGGING_H_ diff --git a/NativeScript/include/cppgc/internal/name-trait.h b/NativeScript/include/cppgc/internal/name-trait.h deleted file mode 100644 index 32a33478..00000000 --- a/NativeScript/include/cppgc/internal/name-trait.h +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_ -#define INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_ - -#include -#include - -#include "cppgc/name-provider.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { -namespace internal { - -#if CPPGC_SUPPORTS_OBJECT_NAMES && defined(__clang__) -#define CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME 1 - -// Provides constexpr c-string storage for a name of fixed |Size| characters. -// Automatically appends terminating 0 byte. -template -struct NameBuffer { - char name[Size + 1]{}; - - static constexpr NameBuffer FromCString(const char* str) { - NameBuffer result; - for (size_t i = 0; i < Size; ++i) result.name[i] = str[i]; - result.name[Size] = 0; - return result; - } -}; - -template -const char* GetTypename() { - static constexpr char kSelfPrefix[] = - "const char *cppgc::internal::GetTypename() [T ="; - static_assert(__builtin_strncmp(__PRETTY_FUNCTION__, kSelfPrefix, - sizeof(kSelfPrefix) - 1) == 0, - "The prefix must match"); - static constexpr const char* kTypenameStart = - __PRETTY_FUNCTION__ + sizeof(kSelfPrefix); - static constexpr size_t kTypenameSize = - __builtin_strlen(__PRETTY_FUNCTION__) - sizeof(kSelfPrefix) - 1; - // NameBuffer is an indirection that is needed to make sure that only a - // substring of __PRETTY_FUNCTION__ gets materialized in the binary. - static constexpr auto buffer = - NameBuffer::FromCString(kTypenameStart); - return buffer.name; -} - -#else -#define CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME 0 -#endif - -struct HeapObjectName { - const char* value; - bool name_was_hidden; -}; - -class V8_EXPORT NameTraitBase { - protected: - static HeapObjectName GetNameFromTypeSignature(const char*); -}; - -// Trait that specifies how the garbage collector retrieves the name for a -// given object. -template -class NameTrait final : public NameTraitBase { - public: - static constexpr bool HasNonHiddenName() { -#if CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME - return true; -#elif CPPGC_SUPPORTS_OBJECT_NAMES - return true; -#else // !CPPGC_SUPPORTS_OBJECT_NAMES - return std::is_base_of::value; -#endif // !CPPGC_SUPPORTS_OBJECT_NAMES - } - - static HeapObjectName GetName(const void* obj) { - return GetNameFor(static_cast(obj)); - } - - private: - static HeapObjectName GetNameFor(const NameProvider* name_provider) { - return {name_provider->GetHumanReadableName(), false}; - } - - static HeapObjectName GetNameFor(...) { -#if CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME - return {GetTypename(), false}; -#elif CPPGC_SUPPORTS_OBJECT_NAMES - -#if defined(V8_CC_GNU) -#define PRETTY_FUNCTION_VALUE __PRETTY_FUNCTION__ -#elif defined(V8_CC_MSVC) -#define PRETTY_FUNCTION_VALUE __FUNCSIG__ -#else -#define PRETTY_FUNCTION_VALUE nullptr -#endif - - static const HeapObjectName leaky_name = - GetNameFromTypeSignature(PRETTY_FUNCTION_VALUE); - return {leaky_name, false}; - -#undef PRETTY_FUNCTION_VALUE - -#else // !CPPGC_SUPPORTS_OBJECT_NAMES - return {NameProvider::kHiddenName, true}; -#endif // !CPPGC_SUPPORTS_OBJECT_NAMES - } -}; - -using NameCallback = HeapObjectName (*)(const void*); - -} // namespace internal -} // namespace cppgc - -#undef CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME - -#endif // INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_ diff --git a/NativeScript/include/cppgc/internal/persistent-node.h b/NativeScript/include/cppgc/internal/persistent-node.h deleted file mode 100644 index 22b4cf09..00000000 --- a/NativeScript/include/cppgc/internal/persistent-node.h +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_ -#define INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_ - -#include -#include -#include - -#include "cppgc/internal/logging.h" -#include "cppgc/trace-trait.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -class Visitor; - -namespace internal { - -class CrossThreadPersistentRegion; -class FatalOutOfMemoryHandler; - -// PersistentNode represents a variant of two states: -// 1) traceable node with a back pointer to the Persistent object; -// 2) freelist entry. -class PersistentNode final { - public: - PersistentNode() = default; - - PersistentNode(const PersistentNode&) = delete; - PersistentNode& operator=(const PersistentNode&) = delete; - - void InitializeAsUsedNode(void* owner, TraceCallback trace) { - CPPGC_DCHECK(trace); - owner_ = owner; - trace_ = trace; - } - - void InitializeAsFreeNode(PersistentNode* next) { - next_ = next; - trace_ = nullptr; - } - - void UpdateOwner(void* owner) { - CPPGC_DCHECK(IsUsed()); - owner_ = owner; - } - - PersistentNode* FreeListNext() const { - CPPGC_DCHECK(!IsUsed()); - return next_; - } - - void Trace(Visitor* visitor) const { - CPPGC_DCHECK(IsUsed()); - trace_(visitor, owner_); - } - - bool IsUsed() const { return trace_; } - - void* owner() const { - CPPGC_DCHECK(IsUsed()); - return owner_; - } - - private: - // PersistentNode acts as a designated union: - // If trace_ != nullptr, owner_ points to the corresponding Persistent handle. - // Otherwise, next_ points to the next freed PersistentNode. - union { - void* owner_ = nullptr; - PersistentNode* next_; - }; - TraceCallback trace_ = nullptr; -}; - -class V8_EXPORT PersistentRegionBase { - using PersistentNodeSlots = std::array; - - public: - // Clears Persistent fields to avoid stale pointers after heap teardown. - ~PersistentRegionBase(); - - PersistentRegionBase(const PersistentRegionBase&) = delete; - PersistentRegionBase& operator=(const PersistentRegionBase&) = delete; - - void Trace(Visitor*); - - size_t NodesInUse() const; - - void ClearAllUsedNodes(); - - protected: - explicit PersistentRegionBase(const FatalOutOfMemoryHandler& oom_handler); - - PersistentNode* TryAllocateNodeFromFreeList(void* owner, - TraceCallback trace) { - PersistentNode* node = nullptr; - if (V8_LIKELY(free_list_head_)) { - node = free_list_head_; - free_list_head_ = free_list_head_->FreeListNext(); - CPPGC_DCHECK(!node->IsUsed()); - node->InitializeAsUsedNode(owner, trace); - nodes_in_use_++; - } - return node; - } - - void FreeNode(PersistentNode* node) { - CPPGC_DCHECK(node); - CPPGC_DCHECK(node->IsUsed()); - node->InitializeAsFreeNode(free_list_head_); - free_list_head_ = node; - CPPGC_DCHECK(nodes_in_use_ > 0); - nodes_in_use_--; - } - - PersistentNode* RefillFreeListAndAllocateNode(void* owner, - TraceCallback trace); - - private: - template - void ClearAllUsedNodes(); - - void RefillFreeList(); - - std::vector> nodes_; - PersistentNode* free_list_head_ = nullptr; - size_t nodes_in_use_ = 0; - const FatalOutOfMemoryHandler& oom_handler_; - - friend class CrossThreadPersistentRegion; -}; - -// Variant of PersistentRegionBase that checks whether the allocation and -// freeing happens only on the thread that created the region. -class V8_EXPORT PersistentRegion final : public PersistentRegionBase { - public: - explicit PersistentRegion(const FatalOutOfMemoryHandler&); - // Clears Persistent fields to avoid stale pointers after heap teardown. - ~PersistentRegion() = default; - - PersistentRegion(const PersistentRegion&) = delete; - PersistentRegion& operator=(const PersistentRegion&) = delete; - - V8_INLINE PersistentNode* AllocateNode(void* owner, TraceCallback trace) { - CPPGC_DCHECK(IsCreationThread()); - auto* node = TryAllocateNodeFromFreeList(owner, trace); - if (V8_LIKELY(node)) return node; - - // Slow path allocation allows for checking thread correspondence. - CPPGC_CHECK(IsCreationThread()); - return RefillFreeListAndAllocateNode(owner, trace); - } - - V8_INLINE void FreeNode(PersistentNode* node) { - CPPGC_DCHECK(IsCreationThread()); - PersistentRegionBase::FreeNode(node); - } - - private: - bool IsCreationThread(); - - int creation_thread_id_; -}; - -// CrossThreadPersistent uses PersistentRegionBase but protects it using this -// lock when needed. -class V8_EXPORT PersistentRegionLock final { - public: - PersistentRegionLock(); - ~PersistentRegionLock(); - - static void AssertLocked(); -}; - -// Variant of PersistentRegionBase that checks whether the PersistentRegionLock -// is locked. -class V8_EXPORT CrossThreadPersistentRegion final - : protected PersistentRegionBase { - public: - explicit CrossThreadPersistentRegion(const FatalOutOfMemoryHandler&); - // Clears Persistent fields to avoid stale pointers after heap teardown. - ~CrossThreadPersistentRegion(); - - CrossThreadPersistentRegion(const CrossThreadPersistentRegion&) = delete; - CrossThreadPersistentRegion& operator=(const CrossThreadPersistentRegion&) = - delete; - - V8_INLINE PersistentNode* AllocateNode(void* owner, TraceCallback trace) { - PersistentRegionLock::AssertLocked(); - auto* node = TryAllocateNodeFromFreeList(owner, trace); - if (V8_LIKELY(node)) return node; - - return RefillFreeListAndAllocateNode(owner, trace); - } - - V8_INLINE void FreeNode(PersistentNode* node) { - PersistentRegionLock::AssertLocked(); - PersistentRegionBase::FreeNode(node); - } - - void Trace(Visitor*); - - size_t NodesInUse() const; - - void ClearAllUsedNodes(); -}; - -} // namespace internal - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_ diff --git a/NativeScript/include/cppgc/internal/pointer-policies.h b/NativeScript/include/cppgc/internal/pointer-policies.h deleted file mode 100644 index 853d7031..00000000 --- a/NativeScript/include/cppgc/internal/pointer-policies.h +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_ -#define INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_ - -#include -#include - -#include "cppgc/internal/write-barrier.h" -#include "cppgc/sentinel-pointer.h" -#include "cppgc/source-location.h" -#include "cppgc/type-traits.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { -namespace internal { - -class HeapBase; -class PersistentRegion; -class CrossThreadPersistentRegion; - -// Tags to distinguish between strong and weak member types. -class StrongMemberTag; -class WeakMemberTag; -class UntracedMemberTag; - -struct DijkstraWriteBarrierPolicy { - static void InitializingBarrier(const void*, const void*) { - // Since in initializing writes the source object is always white, having no - // barrier doesn't break the tri-color invariant. - } - static void AssigningBarrier(const void* slot, const void* value) { - WriteBarrier::Params params; - switch (WriteBarrier::GetWriteBarrierType(slot, value, params)) { - case WriteBarrier::Type::kGenerational: - WriteBarrier::GenerationalBarrier(params, slot); - break; - case WriteBarrier::Type::kMarking: - WriteBarrier::DijkstraMarkingBarrier(params, value); - break; - case WriteBarrier::Type::kNone: - break; - } - } -}; - -struct NoWriteBarrierPolicy { - static void InitializingBarrier(const void*, const void*) {} - static void AssigningBarrier(const void*, const void*) {} -}; - -class V8_EXPORT SameThreadEnabledCheckingPolicyBase { - protected: - void CheckPointerImpl(const void* ptr, bool points_to_payload, - bool check_off_heap_assignments); - - const HeapBase* heap_ = nullptr; -}; - -template -class V8_EXPORT SameThreadEnabledCheckingPolicy - : private SameThreadEnabledCheckingPolicyBase { - protected: - template - void CheckPointer(const T* ptr) { - if (!ptr || (kSentinelPointer == ptr)) return; - - CheckPointersImplTrampoline::Call(this, ptr); - } - - private: - template > - struct CheckPointersImplTrampoline { - static void Call(SameThreadEnabledCheckingPolicy* policy, const T* ptr) { - policy->CheckPointerImpl(ptr, false, kCheckOffHeapAssignments); - } - }; - - template - struct CheckPointersImplTrampoline { - static void Call(SameThreadEnabledCheckingPolicy* policy, const T* ptr) { - policy->CheckPointerImpl(ptr, IsGarbageCollectedTypeV, - kCheckOffHeapAssignments); - } - }; -}; - -class DisabledCheckingPolicy { - protected: - void CheckPointer(const void*) {} -}; - -#ifdef DEBUG -// Off heap members are not connected to object graph and thus cannot ressurect -// dead objects. -using DefaultMemberCheckingPolicy = - SameThreadEnabledCheckingPolicy; -using DefaultPersistentCheckingPolicy = - SameThreadEnabledCheckingPolicy; -#else // !DEBUG -using DefaultMemberCheckingPolicy = DisabledCheckingPolicy; -using DefaultPersistentCheckingPolicy = DisabledCheckingPolicy; -#endif // !DEBUG -// For CT(W)P neither marking information (for value), nor objectstart bitmap -// (for slot) are guaranteed to be present because there's no synchronization -// between heaps after marking. -using DefaultCrossThreadPersistentCheckingPolicy = DisabledCheckingPolicy; - -class KeepLocationPolicy { - public: - constexpr const SourceLocation& Location() const { return location_; } - - protected: - constexpr KeepLocationPolicy() = default; - constexpr explicit KeepLocationPolicy(const SourceLocation& location) - : location_(location) {} - - // KeepLocationPolicy must not copy underlying source locations. - KeepLocationPolicy(const KeepLocationPolicy&) = delete; - KeepLocationPolicy& operator=(const KeepLocationPolicy&) = delete; - - // Location of the original moved from object should be preserved. - KeepLocationPolicy(KeepLocationPolicy&&) = default; - KeepLocationPolicy& operator=(KeepLocationPolicy&&) = default; - - private: - SourceLocation location_; -}; - -class IgnoreLocationPolicy { - public: - constexpr SourceLocation Location() const { return {}; } - - protected: - constexpr IgnoreLocationPolicy() = default; - constexpr explicit IgnoreLocationPolicy(const SourceLocation&) {} -}; - -#if CPPGC_SUPPORTS_OBJECT_NAMES -using DefaultLocationPolicy = KeepLocationPolicy; -#else -using DefaultLocationPolicy = IgnoreLocationPolicy; -#endif - -struct StrongPersistentPolicy { - using IsStrongPersistent = std::true_type; - static V8_EXPORT PersistentRegion& GetPersistentRegion(const void* object); -}; - -struct WeakPersistentPolicy { - using IsStrongPersistent = std::false_type; - static V8_EXPORT PersistentRegion& GetPersistentRegion(const void* object); -}; - -struct StrongCrossThreadPersistentPolicy { - using IsStrongPersistent = std::true_type; - static V8_EXPORT CrossThreadPersistentRegion& GetPersistentRegion( - const void* object); -}; - -struct WeakCrossThreadPersistentPolicy { - using IsStrongPersistent = std::false_type; - static V8_EXPORT CrossThreadPersistentRegion& GetPersistentRegion( - const void* object); -}; - -// Forward declarations setting up the default policies. -template -class BasicCrossThreadPersistent; -template -class BasicPersistent; -template -class BasicMember; - -} // namespace internal - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_ diff --git a/NativeScript/include/cppgc/internal/write-barrier.h b/NativeScript/include/cppgc/internal/write-barrier.h deleted file mode 100644 index bfabc31e..00000000 --- a/NativeScript/include/cppgc/internal/write-barrier.h +++ /dev/null @@ -1,435 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_ -#define INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_ - -#include -#include - -#include "cppgc/heap-state.h" -#include "cppgc/internal/api-constants.h" -#include "cppgc/internal/atomic-entry-flag.h" -#include "cppgc/platform.h" -#include "cppgc/sentinel-pointer.h" -#include "cppgc/trace-trait.h" -#include "v8config.h" // NOLINT(build/include_directory) - -#if defined(CPPGC_CAGED_HEAP) -#include "cppgc/internal/caged-heap-local-data.h" -#endif - -namespace cppgc { - -class HeapHandle; - -namespace internal { - -#if defined(CPPGC_CAGED_HEAP) -class WriteBarrierTypeForCagedHeapPolicy; -#else // !CPPGC_CAGED_HEAP -class WriteBarrierTypeForNonCagedHeapPolicy; -#endif // !CPPGC_CAGED_HEAP - -class V8_EXPORT WriteBarrier final { - public: - enum class Type : uint8_t { - kNone, - kMarking, - kGenerational, - }; - - struct Params { - HeapHandle* heap = nullptr; -#if V8_ENABLE_CHECKS - Type type = Type::kNone; -#endif // !V8_ENABLE_CHECKS -#if defined(CPPGC_CAGED_HEAP) - uintptr_t start = 0; - CagedHeapLocalData& caged_heap() const { - return *reinterpret_cast(start); - } - uintptr_t slot_offset = 0; - uintptr_t value_offset = 0; -#endif // CPPGC_CAGED_HEAP - }; - - enum class ValueMode { - kValuePresent, - kNoValuePresent, - }; - - // Returns the required write barrier for a given `slot` and `value`. - static V8_INLINE Type GetWriteBarrierType(const void* slot, const void* value, - Params& params); - // Returns the required write barrier for a given `slot`. - template - static V8_INLINE Type GetWriteBarrierType(const void* slot, Params& params, - HeapHandleCallback callback); - // Returns the required write barrier for a given `value`. - static V8_INLINE Type GetWriteBarrierType(const void* value, Params& params); - - static V8_INLINE void DijkstraMarkingBarrier(const Params& params, - const void* object); - static V8_INLINE void DijkstraMarkingBarrierRange( - const Params& params, const void* first_element, size_t element_size, - size_t number_of_elements, TraceCallback trace_callback); - static V8_INLINE void SteeleMarkingBarrier(const Params& params, - const void* object); -#if defined(CPPGC_YOUNG_GENERATION) - static V8_INLINE void GenerationalBarrier(const Params& params, - const void* slot); - static V8_INLINE void GenerationalBarrierForSourceObject( - const Params& params, const void* inner_pointer); -#else // !CPPGC_YOUNG_GENERATION - static V8_INLINE void GenerationalBarrier(const Params& params, - const void* slot) {} - static V8_INLINE void GenerationalBarrierForSourceObject( - const Params& params, const void* inner_pointer) {} -#endif // CPPGC_YOUNG_GENERATION - -#if V8_ENABLE_CHECKS - static void CheckParams(Type expected_type, const Params& params); -#else // !V8_ENABLE_CHECKS - static void CheckParams(Type expected_type, const Params& params) {} -#endif // !V8_ENABLE_CHECKS - - // The IncrementalOrConcurrentUpdater class allows cppgc internal to update - // |incremental_or_concurrent_marking_flag_|. - class IncrementalOrConcurrentMarkingFlagUpdater; - static bool IsAnyIncrementalOrConcurrentMarking() { - return incremental_or_concurrent_marking_flag_.MightBeEntered(); - } - - private: - WriteBarrier() = delete; - -#if defined(CPPGC_CAGED_HEAP) - using WriteBarrierTypePolicy = WriteBarrierTypeForCagedHeapPolicy; -#else // !CPPGC_CAGED_HEAP - using WriteBarrierTypePolicy = WriteBarrierTypeForNonCagedHeapPolicy; -#endif // !CPPGC_CAGED_HEAP - - static void DijkstraMarkingBarrierSlow(const void* value); - static void DijkstraMarkingBarrierSlowWithSentinelCheck(const void* value); - static void DijkstraMarkingBarrierRangeSlow(HeapHandle& heap_handle, - const void* first_element, - size_t element_size, - size_t number_of_elements, - TraceCallback trace_callback); - static void SteeleMarkingBarrierSlow(const void* value); - static void SteeleMarkingBarrierSlowWithSentinelCheck(const void* value); - -#if defined(CPPGC_YOUNG_GENERATION) - static CagedHeapLocalData& GetLocalData(HeapHandle&); - static void GenerationalBarrierSlow(const CagedHeapLocalData& local_data, - const AgeTable& age_table, - const void* slot, uintptr_t value_offset); - static void GenerationalBarrierForSourceObjectSlow( - const CagedHeapLocalData& local_data, const void* object); -#endif // CPPGC_YOUNG_GENERATION - - static AtomicEntryFlag incremental_or_concurrent_marking_flag_; -}; - -template -V8_INLINE WriteBarrier::Type SetAndReturnType(WriteBarrier::Params& params) { - if (type == WriteBarrier::Type::kNone) return WriteBarrier::Type::kNone; -#if V8_ENABLE_CHECKS - params.type = type; -#endif // !V8_ENABLE_CHECKS - return type; -} - -#if defined(CPPGC_CAGED_HEAP) -class V8_EXPORT WriteBarrierTypeForCagedHeapPolicy final { - public: - template - static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value, - WriteBarrier::Params& params, - HeapHandleCallback callback) { - return ValueModeDispatch::Get(slot, value, params, callback); - } - - template - static V8_INLINE WriteBarrier::Type Get(const void* value, - WriteBarrier::Params& params, - HeapHandleCallback callback) { - return GetNoSlot(value, params, callback); - } - - private: - WriteBarrierTypeForCagedHeapPolicy() = delete; - - template - static V8_INLINE WriteBarrier::Type GetNoSlot(const void* value, - WriteBarrier::Params& params, - HeapHandleCallback) { - if (!TryGetCagedHeap(value, value, params)) { - return WriteBarrier::Type::kNone; - } - if (V8_UNLIKELY(params.caged_heap().is_incremental_marking_in_progress)) { - return SetAndReturnType(params); - } - return SetAndReturnType(params); - } - - template - struct ValueModeDispatch; - - static V8_INLINE bool TryGetCagedHeap(const void* slot, const void* value, - WriteBarrier::Params& params) { - // TODO(chromium:1056170): Check if the null check can be folded in with - // the rest of the write barrier. - if (!value) return false; - params.start = reinterpret_cast(value) & - ~(api_constants::kCagedHeapReservationAlignment - 1); - const uintptr_t slot_offset = - reinterpret_cast(slot) - params.start; - if (slot_offset > api_constants::kCagedHeapReservationSize) { - // Check if slot is on stack or value is sentinel or nullptr. This relies - // on the fact that kSentinelPointer is encoded as 0x1. - return false; - } - return true; - } - - // Returns whether marking is in progress. If marking is not in progress - // sets the start of the cage accordingly. - // - // TODO(chromium:1056170): Create fast path on API. - static bool IsMarking(const HeapHandle&, WriteBarrier::Params&); -}; - -template <> -struct WriteBarrierTypeForCagedHeapPolicy::ValueModeDispatch< - WriteBarrier::ValueMode::kValuePresent> { - template - static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value, - WriteBarrier::Params& params, - HeapHandleCallback) { -#if !defined(CPPGC_YOUNG_GENERATION) - if (V8_LIKELY(!WriteBarrier::IsAnyIncrementalOrConcurrentMarking())) { - return SetAndReturnType(params); - } -#endif // !CPPGC_YOUNG_GENERATION - bool within_cage = TryGetCagedHeap(slot, value, params); - if (!within_cage) { - return WriteBarrier::Type::kNone; - } - if (V8_LIKELY(!params.caged_heap().is_incremental_marking_in_progress)) { -#if defined(CPPGC_YOUNG_GENERATION) - params.heap = reinterpret_cast(params.start); - params.slot_offset = reinterpret_cast(slot) - params.start; - params.value_offset = reinterpret_cast(value) - params.start; - return SetAndReturnType(params); -#else // !CPPGC_YOUNG_GENERATION - return SetAndReturnType(params); -#endif // !CPPGC_YOUNG_GENERATION - } - params.heap = reinterpret_cast(params.start); - return SetAndReturnType(params); - } -}; - -template <> -struct WriteBarrierTypeForCagedHeapPolicy::ValueModeDispatch< - WriteBarrier::ValueMode::kNoValuePresent> { - template - static V8_INLINE WriteBarrier::Type Get(const void* slot, const void*, - WriteBarrier::Params& params, - HeapHandleCallback callback) { -#if defined(CPPGC_YOUNG_GENERATION) - HeapHandle& handle = callback(); - if (V8_LIKELY(!IsMarking(handle, params))) { - // params.start is populated by IsMarking(). - params.heap = &handle; - params.slot_offset = reinterpret_cast(slot) - params.start; - // params.value_offset stays 0. - if (params.slot_offset > api_constants::kCagedHeapReservationSize) { - // Check if slot is on stack. - return SetAndReturnType(params); - } - return SetAndReturnType(params); - } -#else // !CPPGC_YOUNG_GENERATION - if (V8_LIKELY(!WriteBarrier::IsAnyIncrementalOrConcurrentMarking())) { - return SetAndReturnType(params); - } - HeapHandle& handle = callback(); - if (V8_UNLIKELY(!subtle::HeapState::IsMarking(handle))) { - return SetAndReturnType(params); - } -#endif // !CPPGC_YOUNG_GENERATION - params.heap = &handle; - return SetAndReturnType(params); - } -}; - -#endif // CPPGC_CAGED_HEAP - -class V8_EXPORT WriteBarrierTypeForNonCagedHeapPolicy final { - public: - template - static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value, - WriteBarrier::Params& params, - HeapHandleCallback callback) { - return ValueModeDispatch::Get(slot, value, params, callback); - } - - template - static V8_INLINE WriteBarrier::Type Get(const void* value, - WriteBarrier::Params& params, - HeapHandleCallback callback) { - // The slot will never be used in `Get()` below. - return Get(nullptr, value, params, - callback); - } - - private: - template - struct ValueModeDispatch; - - // TODO(chromium:1056170): Create fast path on API. - static bool IsMarking(const void*, HeapHandle**); - // TODO(chromium:1056170): Create fast path on API. - static bool IsMarking(HeapHandle&); - - WriteBarrierTypeForNonCagedHeapPolicy() = delete; -}; - -template <> -struct WriteBarrierTypeForNonCagedHeapPolicy::ValueModeDispatch< - WriteBarrier::ValueMode::kValuePresent> { - template - static V8_INLINE WriteBarrier::Type Get(const void*, const void* object, - WriteBarrier::Params& params, - HeapHandleCallback callback) { - // The following check covers nullptr as well as sentinel pointer. - if (object <= static_cast(kSentinelPointer)) { - return SetAndReturnType(params); - } - if (V8_LIKELY(!WriteBarrier::IsAnyIncrementalOrConcurrentMarking())) { - return SetAndReturnType(params); - } - if (IsMarking(object, ¶ms.heap)) { - return SetAndReturnType(params); - } - return SetAndReturnType(params); - } -}; - -template <> -struct WriteBarrierTypeForNonCagedHeapPolicy::ValueModeDispatch< - WriteBarrier::ValueMode::kNoValuePresent> { - template - static V8_INLINE WriteBarrier::Type Get(const void*, const void*, - WriteBarrier::Params& params, - HeapHandleCallback callback) { - if (V8_UNLIKELY(WriteBarrier::IsAnyIncrementalOrConcurrentMarking())) { - HeapHandle& handle = callback(); - if (IsMarking(handle)) { - params.heap = &handle; - return SetAndReturnType(params); - } - } - return WriteBarrier::Type::kNone; - } -}; - -// static -WriteBarrier::Type WriteBarrier::GetWriteBarrierType( - const void* slot, const void* value, WriteBarrier::Params& params) { - return WriteBarrierTypePolicy::Get(slot, value, - params, []() {}); -} - -// static -template -WriteBarrier::Type WriteBarrier::GetWriteBarrierType( - const void* slot, WriteBarrier::Params& params, - HeapHandleCallback callback) { - return WriteBarrierTypePolicy::Get( - slot, nullptr, params, callback); -} - -// static -WriteBarrier::Type WriteBarrier::GetWriteBarrierType( - const void* value, WriteBarrier::Params& params) { - return WriteBarrierTypePolicy::Get(value, params, - []() {}); -} - -// static -void WriteBarrier::DijkstraMarkingBarrier(const Params& params, - const void* object) { - CheckParams(Type::kMarking, params); -#if defined(CPPGC_CAGED_HEAP) - // Caged heap already filters out sentinels. - DijkstraMarkingBarrierSlow(object); -#else // !CPPGC_CAGED_HEAP - DijkstraMarkingBarrierSlowWithSentinelCheck(object); -#endif // !CPPGC_CAGED_HEAP -} - -// static -void WriteBarrier::DijkstraMarkingBarrierRange(const Params& params, - const void* first_element, - size_t element_size, - size_t number_of_elements, - TraceCallback trace_callback) { - CheckParams(Type::kMarking, params); - DijkstraMarkingBarrierRangeSlow(*params.heap, first_element, element_size, - number_of_elements, trace_callback); -} - -// static -void WriteBarrier::SteeleMarkingBarrier(const Params& params, - const void* object) { - CheckParams(Type::kMarking, params); -#if defined(CPPGC_CAGED_HEAP) - // Caged heap already filters out sentinels. - SteeleMarkingBarrierSlow(object); -#else // !CPPGC_CAGED_HEAP - SteeleMarkingBarrierSlowWithSentinelCheck(object); -#endif // !CPPGC_CAGED_HEAP -} - -#if defined(CPPGC_YOUNG_GENERATION) -// static -void WriteBarrier::GenerationalBarrier(const Params& params, const void* slot) { - CheckParams(Type::kGenerational, params); - - const CagedHeapLocalData& local_data = params.caged_heap(); - const AgeTable& age_table = local_data.age_table; - - // Bail out if the slot is in young generation. - if (V8_LIKELY(age_table.GetAge(params.slot_offset) == AgeTable::Age::kYoung)) - return; - - GenerationalBarrierSlow(local_data, age_table, slot, params.value_offset); -} - -// static -void WriteBarrier::GenerationalBarrierForSourceObject( - const Params& params, const void* inner_pointer) { - CheckParams(Type::kGenerational, params); - - const CagedHeapLocalData& local_data = params.caged_heap(); - const AgeTable& age_table = local_data.age_table; - - // Assume that if the first element is in young generation, the whole range is - // in young generation. - if (V8_LIKELY(age_table.GetAge(params.slot_offset) == AgeTable::Age::kYoung)) - return; - - GenerationalBarrierForSourceObjectSlow(local_data, inner_pointer); -} - -#endif // !CPPGC_YOUNG_GENERATION - -} // namespace internal -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_ diff --git a/NativeScript/include/cppgc/liveness-broker.h b/NativeScript/include/cppgc/liveness-broker.h deleted file mode 100644 index c94eef0d..00000000 --- a/NativeScript/include/cppgc/liveness-broker.h +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_LIVENESS_BROKER_H_ -#define INCLUDE_CPPGC_LIVENESS_BROKER_H_ - -#include "cppgc/heap.h" -#include "cppgc/member.h" -#include "cppgc/trace-trait.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -namespace internal { -class LivenessBrokerFactory; -} // namespace internal - -/** - * The broker is passed to weak callbacks to allow (temporarily) querying - * the liveness state of an object. References to non-live objects must be - * cleared when `IsHeapObjectAlive()` returns false. - * - * \code - * class GCedWithCustomWeakCallback final - * : public GarbageCollected { - * public: - * UntracedMember bar; - * - * void CustomWeakCallbackMethod(const LivenessBroker& broker) { - * if (!broker.IsHeapObjectAlive(bar)) - * bar = nullptr; - * } - * - * void Trace(cppgc::Visitor* visitor) const { - * visitor->RegisterWeakCallbackMethod< - * GCedWithCustomWeakCallback, - * &GCedWithCustomWeakCallback::CustomWeakCallbackMethod>(this); - * } - * }; - * \endcode - */ -class V8_EXPORT LivenessBroker final { - public: - template - bool IsHeapObjectAlive(const T* object) const { - // nullptr objects are considered alive to allow weakness to be used from - // stack while running into a conservative GC. Treating nullptr as dead - // would mean that e.g. custom collectins could not be strongified on stack. - return !object || - IsHeapObjectAliveImpl( - TraceTrait::GetTraceDescriptor(object).base_object_payload); - } - - template - bool IsHeapObjectAlive(const WeakMember& weak_member) const { - return (weak_member != kSentinelPointer) && - IsHeapObjectAlive(weak_member.Get()); - } - - template - bool IsHeapObjectAlive(const UntracedMember& untraced_member) const { - return (untraced_member != kSentinelPointer) && - IsHeapObjectAlive(untraced_member.Get()); - } - - private: - LivenessBroker() = default; - - bool IsHeapObjectAliveImpl(const void*) const; - - friend class internal::LivenessBrokerFactory; -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_LIVENESS_BROKER_H_ diff --git a/NativeScript/include/cppgc/macros.h b/NativeScript/include/cppgc/macros.h deleted file mode 100644 index 030f397e..00000000 --- a/NativeScript/include/cppgc/macros.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_MACROS_H_ -#define INCLUDE_CPPGC_MACROS_H_ - -#include - -#include "cppgc/internal/compiler-specific.h" - -namespace cppgc { - -// Use if the object is only stack allocated. -#define CPPGC_STACK_ALLOCATED() \ - public: \ - using IsStackAllocatedTypeMarker CPPGC_UNUSED = int; \ - \ - private: \ - void* operator new(size_t) = delete; \ - void* operator new(size_t, void*) = delete; \ - static_assert(true, "Force semicolon.") - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_MACROS_H_ diff --git a/NativeScript/include/cppgc/member.h b/NativeScript/include/cppgc/member.h deleted file mode 100644 index 66a8cfd8..00000000 --- a/NativeScript/include/cppgc/member.h +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_MEMBER_H_ -#define INCLUDE_CPPGC_MEMBER_H_ - -#include -#include -#include - -#include "cppgc/internal/pointer-policies.h" -#include "cppgc/sentinel-pointer.h" -#include "cppgc/type-traits.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -class Visitor; - -namespace internal { - -// MemberBase always refers to the object as const object and defers to -// BasicMember on casting to the right type as needed. -class MemberBase { - protected: - struct AtomicInitializerTag {}; - - MemberBase() : raw_(nullptr) {} - explicit MemberBase(const void* value) : raw_(value) {} - MemberBase(const void* value, AtomicInitializerTag) { SetRawAtomic(value); } - - const void** GetRawSlot() const { return &raw_; } - const void* GetRaw() const { return raw_; } - void SetRaw(void* value) { raw_ = value; } - - const void* GetRawAtomic() const { - return reinterpret_cast*>(&raw_)->load( - std::memory_order_relaxed); - } - void SetRawAtomic(const void* value) { - reinterpret_cast*>(&raw_)->store( - value, std::memory_order_relaxed); - } - - void ClearFromGC() const { raw_ = nullptr; } - - private: - // All constructors initialize `raw_`. Do not add a default value here as it - // results in a non-atomic write on some builds, even when the atomic version - // of the constructor is used. - mutable const void* raw_; -}; - -// The basic class from which all Member classes are 'generated'. -template -class BasicMember final : private MemberBase, private CheckingPolicy { - public: - using PointeeType = T; - - constexpr BasicMember() = default; - constexpr BasicMember(std::nullptr_t) {} // NOLINT - BasicMember(SentinelPointer s) : MemberBase(s) {} // NOLINT - BasicMember(T* raw) : MemberBase(raw) { // NOLINT - InitializingWriteBarrier(); - this->CheckPointer(Get()); - } - BasicMember(T& raw) : BasicMember(&raw) {} // NOLINT - // Atomic ctor. Using the AtomicInitializerTag forces BasicMember to - // initialize using atomic assignments. This is required for preventing - // data races with concurrent marking. - using AtomicInitializerTag = MemberBase::AtomicInitializerTag; - BasicMember(std::nullptr_t, AtomicInitializerTag atomic) - : MemberBase(nullptr, atomic) {} - BasicMember(SentinelPointer s, AtomicInitializerTag atomic) - : MemberBase(s, atomic) {} - BasicMember(T* raw, AtomicInitializerTag atomic) : MemberBase(raw, atomic) { - InitializingWriteBarrier(); - this->CheckPointer(Get()); - } - BasicMember(T& raw, AtomicInitializerTag atomic) - : BasicMember(&raw, atomic) {} - // Copy ctor. - BasicMember(const BasicMember& other) : BasicMember(other.Get()) {} - // Allow heterogeneous construction. - template ::value>> - BasicMember( // NOLINT - const BasicMember& other) - : BasicMember(other.Get()) {} - // Move ctor. - BasicMember(BasicMember&& other) noexcept : BasicMember(other.Get()) { - other.Clear(); - } - // Allow heterogeneous move construction. - template ::value>> - BasicMember(BasicMember&& other) noexcept - : BasicMember(other.Get()) { - other.Clear(); - } - // Construction from Persistent. - template ::value>> - BasicMember(const BasicPersistent& p) - : BasicMember(p.Get()) {} - - // Copy assignment. - BasicMember& operator=(const BasicMember& other) { - return operator=(other.Get()); - } - // Allow heterogeneous copy assignment. - template ::value>> - BasicMember& operator=( - const BasicMember& other) { - return operator=(other.Get()); - } - // Move assignment. - BasicMember& operator=(BasicMember&& other) noexcept { - operator=(other.Get()); - other.Clear(); - return *this; - } - // Heterogeneous move assignment. - template ::value>> - BasicMember& operator=(BasicMember&& other) noexcept { - operator=(other.Get()); - other.Clear(); - return *this; - } - // Assignment from Persistent. - template ::value>> - BasicMember& operator=( - const BasicPersistent& - other) { - return operator=(other.Get()); - } - BasicMember& operator=(T* other) { - SetRawAtomic(other); - AssigningWriteBarrier(); - this->CheckPointer(Get()); - return *this; - } - BasicMember& operator=(std::nullptr_t) { - Clear(); - return *this; - } - BasicMember& operator=(SentinelPointer s) { - SetRawAtomic(s); - return *this; - } - - template - void Swap(BasicMember& other) { - T* tmp = Get(); - *this = other; - other = tmp; - } - - explicit operator bool() const { return Get(); } - operator T*() const { return Get(); } - T* operator->() const { return Get(); } - T& operator*() const { return *Get(); } - - // CFI cast exemption to allow passing SentinelPointer through T* and support - // heterogeneous assignments between different Member and Persistent handles - // based on their actual types. - V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const { - // Executed by the mutator, hence non atomic load. - // - // The const_cast below removes the constness from MemberBase storage. The - // following static_cast re-adds any constness if specified through the - // user-visible template parameter T. - return static_cast(const_cast(MemberBase::GetRaw())); - } - - void Clear() { SetRawAtomic(nullptr); } - - T* Release() { - T* result = Get(); - Clear(); - return result; - } - - const T** GetSlotForTesting() const { - return reinterpret_cast(GetRawSlot()); - } - - private: - const T* GetRawAtomic() const { - return static_cast(MemberBase::GetRawAtomic()); - } - - void InitializingWriteBarrier() const { - WriteBarrierPolicy::InitializingBarrier(GetRawSlot(), GetRaw()); - } - void AssigningWriteBarrier() const { - WriteBarrierPolicy::AssigningBarrier(GetRawSlot(), GetRaw()); - } - - void ClearFromGC() const { MemberBase::ClearFromGC(); } - - T* GetFromGC() const { return Get(); } - - friend class cppgc::Visitor; - template - friend struct cppgc::TraceTrait; -}; - -template -bool operator==(const BasicMember& member1, - const BasicMember& member2) { - return member1.Get() == member2.Get(); -} - -template -bool operator!=(const BasicMember& member1, - const BasicMember& member2) { - return !(member1 == member2); -} - -template -struct IsWeak< - internal::BasicMember> - : std::true_type {}; - -} // namespace internal - -/** - * Members are used in classes to contain strong pointers to other garbage - * collected objects. All Member fields of a class must be traced in the class' - * trace method. - */ -template -using Member = internal::BasicMember; - -/** - * WeakMember is similar to Member in that it is used to point to other garbage - * collected objects. However instead of creating a strong pointer to the - * object, the WeakMember creates a weak pointer, which does not keep the - * pointee alive. Hence if all pointers to to a heap allocated object are weak - * the object will be garbage collected. At the time of GC the weak pointers - * will automatically be set to null. - */ -template -using WeakMember = internal::BasicMember; - -/** - * UntracedMember is a pointer to an on-heap object that is not traced for some - * reason. Do not use this unless you know what you are doing. Keeping raw - * pointers to on-heap objects is prohibited unless used from stack. Pointee - * must be kept alive through other means. - */ -template -using UntracedMember = internal::BasicMember; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_MEMBER_H_ diff --git a/NativeScript/include/cppgc/name-provider.h b/NativeScript/include/cppgc/name-provider.h deleted file mode 100644 index 224dd4b5..00000000 --- a/NativeScript/include/cppgc/name-provider.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_NAME_PROVIDER_H_ -#define INCLUDE_CPPGC_NAME_PROVIDER_H_ - -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -/** - * NameProvider allows for providing a human-readable name for garbage-collected - * objects. - * - * There's two cases of names to distinguish: - * a. Explicitly specified names via using NameProvider. Such names are always - * preserved in the system. - * b. Internal names that Oilpan infers from a C++ type on the class hierarchy - * of the object. This is not necessarily the type of the actually - * instantiated object. - * - * Depending on the build configuration, Oilpan may hide names, i.e., represent - * them with kHiddenName, of case b. to avoid exposing internal details. - */ -class V8_EXPORT NameProvider { - public: - /** - * Name that is used when hiding internals. - */ - static constexpr const char kHiddenName[] = "InternalNode"; - - /** - * Name that is used in case compiler support is missing for composing a name - * from C++ types. - */ - static constexpr const char kNoNameDeducible[] = ""; - - /** - * Indicating whether internal names are hidden or not. - * - * @returns true if C++ names should be hidden and represented by kHiddenName. - */ - static constexpr bool HideInternalNames() { -#if CPPGC_SUPPORTS_OBJECT_NAMES - return false; -#else // !CPPGC_SUPPORTS_OBJECT_NAMES - return true; -#endif // !CPPGC_SUPPORTS_OBJECT_NAMES - } - - virtual ~NameProvider() = default; - - /** - * Specifies a name for the garbage-collected object. Such names will never - * be hidden, as they are explicitly specified by the user of this API. - * - * @returns a human readable name for the object. - */ - virtual const char* GetHumanReadableName() const = 0; -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_NAME_PROVIDER_H_ diff --git a/NativeScript/include/cppgc/object-size-trait.h b/NativeScript/include/cppgc/object-size-trait.h deleted file mode 100644 index 35795596..00000000 --- a/NativeScript/include/cppgc/object-size-trait.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_OBJECT_SIZE_TRAIT_H_ -#define INCLUDE_CPPGC_OBJECT_SIZE_TRAIT_H_ - -#include - -#include "cppgc/type-traits.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -namespace internal { - -struct V8_EXPORT BaseObjectSizeTrait { - protected: - static size_t GetObjectSizeForGarbageCollected(const void*); - static size_t GetObjectSizeForGarbageCollectedMixin(const void*); -}; - -} // namespace internal - -namespace subtle { - -/** - * Trait specifying how to get the size of an object that was allocated using - * `MakeGarbageCollected()`. Also supports querying the size with an inner - * pointer to a mixin. - */ -template > -struct ObjectSizeTrait; - -template -struct ObjectSizeTrait : cppgc::internal::BaseObjectSizeTrait { - static_assert(sizeof(T), "T must be fully defined"); - static_assert(IsGarbageCollectedTypeV, - "T must be of type GarbageCollected or GarbageCollectedMixin"); - - static size_t GetSize(const T& object) { - return GetObjectSizeForGarbageCollected(&object); - } -}; - -template -struct ObjectSizeTrait : cppgc::internal::BaseObjectSizeTrait { - static_assert(sizeof(T), "T must be fully defined"); - - static size_t GetSize(const T& object) { - return GetObjectSizeForGarbageCollectedMixin(&object); - } -}; - -} // namespace subtle -} // namespace cppgc - -#endif // INCLUDE_CPPGC_OBJECT_SIZE_TRAIT_H_ diff --git a/NativeScript/include/cppgc/persistent.h b/NativeScript/include/cppgc/persistent.h deleted file mode 100644 index 244f94c8..00000000 --- a/NativeScript/include/cppgc/persistent.h +++ /dev/null @@ -1,370 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_PERSISTENT_H_ -#define INCLUDE_CPPGC_PERSISTENT_H_ - -#include - -#include "cppgc/internal/persistent-node.h" -#include "cppgc/internal/pointer-policies.h" -#include "cppgc/sentinel-pointer.h" -#include "cppgc/source-location.h" -#include "cppgc/type-traits.h" -#include "cppgc/visitor.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -class Visitor; - -namespace internal { - -// PersistentBase always refers to the object as const object and defers to -// BasicPersistent on casting to the right type as needed. -class PersistentBase { - protected: - PersistentBase() = default; - explicit PersistentBase(const void* raw) : raw_(raw) {} - - const void* GetValue() const { return raw_; } - void SetValue(const void* value) { raw_ = value; } - - PersistentNode* GetNode() const { return node_; } - void SetNode(PersistentNode* node) { node_ = node; } - - // Performs a shallow clear which assumes that internal persistent nodes are - // destroyed elsewhere. - void ClearFromGC() const { - raw_ = nullptr; - node_ = nullptr; - } - - protected: - mutable const void* raw_ = nullptr; - mutable PersistentNode* node_ = nullptr; - - friend class PersistentRegionBase; -}; - -// The basic class from which all Persistent classes are generated. -template -class BasicPersistent final : public PersistentBase, - public LocationPolicy, - private WeaknessPolicy, - private CheckingPolicy { - public: - using typename WeaknessPolicy::IsStrongPersistent; - using PointeeType = T; - - // Null-state/sentinel constructors. - BasicPersistent( // NOLINT - const SourceLocation& loc = SourceLocation::Current()) - : LocationPolicy(loc) {} - - BasicPersistent(std::nullptr_t, // NOLINT - const SourceLocation& loc = SourceLocation::Current()) - : LocationPolicy(loc) {} - - BasicPersistent( // NOLINT - SentinelPointer s, const SourceLocation& loc = SourceLocation::Current()) - : PersistentBase(s), LocationPolicy(loc) {} - - // Raw value constructors. - BasicPersistent(T* raw, // NOLINT - const SourceLocation& loc = SourceLocation::Current()) - : PersistentBase(raw), LocationPolicy(loc) { - if (!IsValid()) return; - SetNode(WeaknessPolicy::GetPersistentRegion(GetValue()) - .AllocateNode(this, &BasicPersistent::Trace)); - this->CheckPointer(Get()); - } - - BasicPersistent(T& raw, // NOLINT - const SourceLocation& loc = SourceLocation::Current()) - : BasicPersistent(&raw, loc) {} - - // Copy ctor. - BasicPersistent(const BasicPersistent& other, - const SourceLocation& loc = SourceLocation::Current()) - : BasicPersistent(other.Get(), loc) {} - - // Heterogeneous ctor. - template ::value>> - BasicPersistent( - const BasicPersistent& other, - const SourceLocation& loc = SourceLocation::Current()) - : BasicPersistent(other.Get(), loc) {} - - // Move ctor. The heterogeneous move ctor is not supported since e.g. - // persistent can't reuse persistent node from weak persistent. - BasicPersistent( - BasicPersistent&& other, - const SourceLocation& loc = SourceLocation::Current()) noexcept - : PersistentBase(std::move(other)), LocationPolicy(std::move(other)) { - if (!IsValid()) return; - GetNode()->UpdateOwner(this); - other.SetValue(nullptr); - other.SetNode(nullptr); - this->CheckPointer(Get()); - } - - // Constructor from member. - template ::value>> - BasicPersistent( - const internal::BasicMember& member, - const SourceLocation& loc = SourceLocation::Current()) - : BasicPersistent(member.Get(), loc) {} - - ~BasicPersistent() { Clear(); } - - // Copy assignment. - BasicPersistent& operator=(const BasicPersistent& other) { - return operator=(other.Get()); - } - - template ::value>> - BasicPersistent& operator=( - const BasicPersistent& other) { - return operator=(other.Get()); - } - - // Move assignment. - BasicPersistent& operator=(BasicPersistent&& other) noexcept { - if (this == &other) return *this; - Clear(); - PersistentBase::operator=(std::move(other)); - LocationPolicy::operator=(std::move(other)); - if (!IsValid()) return *this; - GetNode()->UpdateOwner(this); - other.SetValue(nullptr); - other.SetNode(nullptr); - this->CheckPointer(Get()); - return *this; - } - - // Assignment from member. - template ::value>> - BasicPersistent& operator=( - const internal::BasicMember& member) { - return operator=(member.Get()); - } - - BasicPersistent& operator=(T* other) { - Assign(other); - return *this; - } - - BasicPersistent& operator=(std::nullptr_t) { - Clear(); - return *this; - } - - BasicPersistent& operator=(SentinelPointer s) { - Assign(s); - return *this; - } - - explicit operator bool() const { return Get(); } - operator T*() const { return Get(); } - T* operator->() const { return Get(); } - T& operator*() const { return *Get(); } - - // CFI cast exemption to allow passing SentinelPointer through T* and support - // heterogeneous assignments between different Member and Persistent handles - // based on their actual types. - V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const { - // The const_cast below removes the constness from PersistentBase storage. - // The following static_cast re-adds any constness if specified through the - // user-visible template parameter T. - return static_cast(const_cast(GetValue())); - } - - void Clear() { - // Simplified version of `Assign()` to allow calling without a complete type - // `T`. - if (IsValid()) { - WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode()); - SetNode(nullptr); - } - SetValue(nullptr); - } - - T* Release() { - T* result = Get(); - Clear(); - return result; - } - - template - BasicPersistent - To() const { - return BasicPersistent(static_cast(Get())); - } - - private: - static void Trace(Visitor* v, const void* ptr) { - const auto* persistent = static_cast(ptr); - v->TraceRoot(*persistent, persistent->Location()); - } - - bool IsValid() const { - // Ideally, handling kSentinelPointer would be done by the embedder. On the - // other hand, having Persistent aware of it is beneficial since no node - // gets wasted. - return GetValue() != nullptr && GetValue() != kSentinelPointer; - } - - void Assign(T* ptr) { - if (IsValid()) { - if (ptr && ptr != kSentinelPointer) { - // Simply assign the pointer reusing the existing node. - SetValue(ptr); - this->CheckPointer(ptr); - return; - } - WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode()); - SetNode(nullptr); - } - SetValue(ptr); - if (!IsValid()) return; - SetNode(WeaknessPolicy::GetPersistentRegion(GetValue()) - .AllocateNode(this, &BasicPersistent::Trace)); - this->CheckPointer(Get()); - } - - void ClearFromGC() const { - if (IsValid()) { - WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode()); - PersistentBase::ClearFromGC(); - } - } - - // Set Get() for details. - V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") - T* GetFromGC() const { - return static_cast(const_cast(GetValue())); - } - - friend class cppgc::Visitor; -}; - -template -bool operator==(const BasicPersistent& p1, - const BasicPersistent& p2) { - return p1.Get() == p2.Get(); -} - -template -bool operator!=(const BasicPersistent& p1, - const BasicPersistent& p2) { - return !(p1 == p2); -} - -template -bool operator==( - const BasicPersistent& - p, - const BasicMember& m) { - return p.Get() == m.Get(); -} - -template -bool operator!=( - const BasicPersistent& - p, - const BasicMember& m) { - return !(p == m); -} - -template -bool operator==( - const BasicMember& m, - const BasicPersistent& - p) { - return m.Get() == p.Get(); -} - -template -bool operator!=( - const BasicMember& m, - const BasicPersistent& - p) { - return !(m == p); -} - -template -struct IsWeak> : std::true_type {}; -} // namespace internal - -/** - * Persistent is a way to create a strong pointer from an off-heap object to - * another on-heap object. As long as the Persistent handle is alive the GC will - * keep the object pointed to alive. The Persistent handle is always a GC root - * from the point of view of the GC. Persistent must be constructed and - * destructed in the same thread. - */ -template -using Persistent = - internal::BasicPersistent; - -/** - * WeakPersistent is a way to create a weak pointer from an off-heap object to - * an on-heap object. The pointer is automatically cleared when the pointee gets - * collected. WeakPersistent must be constructed and destructed in the same - * thread. - */ -template -using WeakPersistent = - internal::BasicPersistent; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_PERSISTENT_H_ diff --git a/NativeScript/include/cppgc/platform.h b/NativeScript/include/cppgc/platform.h deleted file mode 100644 index 5d5f8796..00000000 --- a/NativeScript/include/cppgc/platform.h +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_PLATFORM_H_ -#define INCLUDE_CPPGC_PLATFORM_H_ - -#include - -#include "cppgc/source-location.h" -#include "v8-platform.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -// TODO(v8:10346): Create separate includes for concepts that are not -// V8-specific. -using IdleTask = v8::IdleTask; -using JobHandle = v8::JobHandle; -using JobDelegate = v8::JobDelegate; -using JobTask = v8::JobTask; -using PageAllocator = v8::PageAllocator; -using Task = v8::Task; -using TaskPriority = v8::TaskPriority; -using TaskRunner = v8::TaskRunner; -using TracingController = v8::TracingController; - -/** - * Platform interface used by Heap. Contains allocators and executors. - */ -class V8_EXPORT Platform { - public: - virtual ~Platform() = default; - - /** - * Returns the allocator used by cppgc to allocate its heap and various - * support structures. - */ - virtual PageAllocator* GetPageAllocator() = 0; - - /** - * Monotonically increasing time in seconds from an arbitrary fixed point in - * the past. This function is expected to return at least - * millisecond-precision values. For this reason, - * it is recommended that the fixed point be no further in the past than - * the epoch. - **/ - virtual double MonotonicallyIncreasingTime() = 0; - - /** - * Foreground task runner that should be used by a Heap. - */ - virtual std::shared_ptr GetForegroundTaskRunner() { - return nullptr; - } - - /** - * Posts `job_task` to run in parallel. Returns a `JobHandle` associated with - * the `Job`, which can be joined or canceled. - * This avoids degenerate cases: - * - Calling `CallOnWorkerThread()` for each work item, causing significant - * overhead. - * - Fixed number of `CallOnWorkerThread()` calls that split the work and - * might run for a long time. This is problematic when many components post - * "num cores" tasks and all expect to use all the cores. In these cases, - * the scheduler lacks context to be fair to multiple same-priority requests - * and/or ability to request lower priority work to yield when high priority - * work comes in. - * A canonical implementation of `job_task` looks like: - * \code - * class MyJobTask : public JobTask { - * public: - * MyJobTask(...) : worker_queue_(...) {} - * // JobTask implementation. - * void Run(JobDelegate* delegate) override { - * while (!delegate->ShouldYield()) { - * // Smallest unit of work. - * auto work_item = worker_queue_.TakeWorkItem(); // Thread safe. - * if (!work_item) return; - * ProcessWork(work_item); - * } - * } - * - * size_t GetMaxConcurrency() const override { - * return worker_queue_.GetSize(); // Thread safe. - * } - * }; - * - * // ... - * auto handle = PostJob(TaskPriority::kUserVisible, - * std::make_unique(...)); - * handle->Join(); - * \endcode - * - * `PostJob()` and methods of the returned JobHandle/JobDelegate, must never - * be called while holding a lock that could be acquired by `JobTask::Run()` - * or `JobTask::GetMaxConcurrency()` -- that could result in a deadlock. This - * is because (1) `JobTask::GetMaxConcurrency()` may be invoked while holding - * internal lock (A), hence `JobTask::GetMaxConcurrency()` can only use a lock - * (B) if that lock is *never* held while calling back into `JobHandle` from - * any thread (A=>B/B=>A deadlock) and (2) `JobTask::Run()` or - * `JobTask::GetMaxConcurrency()` may be invoked synchronously from - * `JobHandle` (B=>JobHandle::foo=>B deadlock). - * - * A sufficient `PostJob()` implementation that uses the default Job provided - * in libplatform looks like: - * \code - * std::unique_ptr PostJob( - * TaskPriority priority, std::unique_ptr job_task) override { - * return std::make_unique( - * std::make_shared( - * this, std::move(job_task), kNumThreads)); - * } - * \endcode - */ - virtual std::unique_ptr PostJob( - TaskPriority priority, std::unique_ptr job_task) { - return nullptr; - } - - /** - * Returns an instance of a `TracingController`. This must be non-nullptr. The - * default implementation returns an empty `TracingController` that consumes - * trace data without effect. - */ - virtual TracingController* GetTracingController(); -}; - -/** - * Process-global initialization of the garbage collector. Must be called before - * creating a Heap. - * - * Can be called multiple times when paired with `ShutdownProcess()`. - * - * \param page_allocator The allocator used for maintaining meta data. Must not - * change between multiple calls to InitializeProcess. - */ -V8_EXPORT void InitializeProcess(PageAllocator* page_allocator); - -/** - * Must be called after destroying the last used heap. Some process-global - * metadata may not be returned and reused upon a subsequent - * `InitializeProcess()` call. - */ -V8_EXPORT void ShutdownProcess(); - -namespace internal { - -V8_EXPORT void Fatal(const std::string& reason = std::string(), - const SourceLocation& = SourceLocation::Current()); - -} // namespace internal - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_PLATFORM_H_ diff --git a/NativeScript/include/cppgc/prefinalizer.h b/NativeScript/include/cppgc/prefinalizer.h deleted file mode 100644 index 51f2eac8..00000000 --- a/NativeScript/include/cppgc/prefinalizer.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_PREFINALIZER_H_ -#define INCLUDE_CPPGC_PREFINALIZER_H_ - -#include "cppgc/internal/compiler-specific.h" -#include "cppgc/liveness-broker.h" - -namespace cppgc { - -namespace internal { - -class V8_EXPORT PrefinalizerRegistration final { - public: - using Callback = bool (*)(const cppgc::LivenessBroker&, void*); - - PrefinalizerRegistration(void*, Callback); - - void* operator new(size_t, void* location) = delete; - void* operator new(size_t) = delete; -}; - -} // namespace internal - -/** - * Macro must be used in the private section of `Class` and registers a - * prefinalization callback `void Class::PreFinalizer()`. The callback is - * invoked on garbage collection after the collector has found an object to be - * dead. - * - * Callback properties: - * - The callback is invoked before a possible destructor for the corresponding - * object. - * - The callback may access the whole object graph, irrespective of whether - * objects are considered dead or alive. - * - The callback is invoked on the same thread as the object was created on. - * - * Example: - * \code - * class WithPrefinalizer : public GarbageCollected { - * CPPGC_USING_PRE_FINALIZER(WithPrefinalizer, Dispose); - * - * public: - * void Trace(Visitor*) const {} - * void Dispose() { prefinalizer_called = true; } - * ~WithPrefinalizer() { - * // prefinalizer_called == true - * } - * private: - * bool prefinalizer_called = false; - * }; - * \endcode - */ -#define CPPGC_USING_PRE_FINALIZER(Class, PreFinalizer) \ - public: \ - static bool InvokePreFinalizer(const cppgc::LivenessBroker& liveness_broker, \ - void* object) { \ - static_assert(cppgc::IsGarbageCollectedOrMixinTypeV, \ - "Only garbage collected objects can have prefinalizers"); \ - Class* self = static_cast(object); \ - if (liveness_broker.IsHeapObjectAlive(self)) return false; \ - self->PreFinalizer(); \ - return true; \ - } \ - \ - private: \ - CPPGC_NO_UNIQUE_ADDRESS cppgc::internal::PrefinalizerRegistration \ - prefinalizer_dummy_{this, Class::InvokePreFinalizer}; \ - static_assert(true, "Force semicolon.") - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_PREFINALIZER_H_ diff --git a/NativeScript/include/cppgc/process-heap-statistics.h b/NativeScript/include/cppgc/process-heap-statistics.h deleted file mode 100644 index 774cc92f..00000000 --- a/NativeScript/include/cppgc/process-heap-statistics.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_PROCESS_HEAP_STATISTICS_H_ -#define INCLUDE_CPPGC_PROCESS_HEAP_STATISTICS_H_ - -#include -#include - -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { -namespace internal { -class ProcessHeapStatisticsUpdater; -} // namespace internal - -class V8_EXPORT ProcessHeapStatistics final { - public: - static size_t TotalAllocatedObjectSize() { - return total_allocated_object_size_.load(std::memory_order_relaxed); - } - static size_t TotalAllocatedSpace() { - return total_allocated_space_.load(std::memory_order_relaxed); - } - - private: - static std::atomic_size_t total_allocated_space_; - static std::atomic_size_t total_allocated_object_size_; - - friend class internal::ProcessHeapStatisticsUpdater; -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_PROCESS_HEAP_STATISTICS_H_ diff --git a/NativeScript/include/cppgc/sentinel-pointer.h b/NativeScript/include/cppgc/sentinel-pointer.h deleted file mode 100644 index b049d1a2..00000000 --- a/NativeScript/include/cppgc/sentinel-pointer.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_SENTINEL_POINTER_H_ -#define INCLUDE_CPPGC_SENTINEL_POINTER_H_ - -#include - -namespace cppgc { -namespace internal { - -// Special tag type used to denote some sentinel member. The semantics of the -// sentinel is defined by the embedder. -struct SentinelPointer { - template - operator T*() const { - static constexpr intptr_t kSentinelValue = 1; - return reinterpret_cast(kSentinelValue); - } - // Hidden friends. - friend bool operator==(SentinelPointer, SentinelPointer) { return true; } - friend bool operator!=(SentinelPointer, SentinelPointer) { return false; } -}; - -} // namespace internal - -constexpr internal::SentinelPointer kSentinelPointer; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_SENTINEL_POINTER_H_ diff --git a/NativeScript/include/cppgc/source-location.h b/NativeScript/include/cppgc/source-location.h deleted file mode 100644 index da5a5ede..00000000 --- a/NativeScript/include/cppgc/source-location.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_SOURCE_LOCATION_H_ -#define INCLUDE_CPPGC_SOURCE_LOCATION_H_ - -#include -#include - -#include "v8config.h" // NOLINT(build/include_directory) - -#if defined(__has_builtin) -#define CPPGC_SUPPORTS_SOURCE_LOCATION \ - (__has_builtin(__builtin_FUNCTION) && __has_builtin(__builtin_FILE) && \ - __has_builtin(__builtin_LINE)) // NOLINT -#elif defined(V8_CC_GNU) && __GNUC__ >= 7 -#define CPPGC_SUPPORTS_SOURCE_LOCATION 1 -#elif defined(V8_CC_INTEL) && __ICC >= 1800 -#define CPPGC_SUPPORTS_SOURCE_LOCATION 1 -#else -#define CPPGC_SUPPORTS_SOURCE_LOCATION 0 -#endif - -namespace cppgc { - -/** - * Encapsulates source location information. Mimics C++20's - * `std::source_location`. - */ -class V8_EXPORT SourceLocation final { - public: - /** - * Construct source location information corresponding to the location of the - * call site. - */ -#if CPPGC_SUPPORTS_SOURCE_LOCATION - static constexpr SourceLocation Current( - const char* function = __builtin_FUNCTION(), - const char* file = __builtin_FILE(), size_t line = __builtin_LINE()) { - return SourceLocation(function, file, line); - } -#else - static constexpr SourceLocation Current() { return SourceLocation(); } -#endif // CPPGC_SUPPORTS_SOURCE_LOCATION - - /** - * Constructs unspecified source location information. - */ - constexpr SourceLocation() = default; - - /** - * Returns the name of the function associated with the position represented - * by this object, if any. - * - * \returns the function name as cstring. - */ - constexpr const char* Function() const { return function_; } - - /** - * Returns the name of the current source file represented by this object. - * - * \returns the file name as cstring. - */ - constexpr const char* FileName() const { return file_; } - - /** - * Returns the line number represented by this object. - * - * \returns the line number. - */ - constexpr size_t Line() const { return line_; } - - /** - * Returns a human-readable string representing this object. - * - * \returns a human-readable string representing source location information. - */ - std::string ToString() const; - - private: - constexpr SourceLocation(const char* function, const char* file, size_t line) - : function_(function), file_(file), line_(line) {} - - const char* function_ = nullptr; - const char* file_ = nullptr; - size_t line_ = 0u; -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_SOURCE_LOCATION_H_ diff --git a/NativeScript/include/cppgc/testing.h b/NativeScript/include/cppgc/testing.h deleted file mode 100644 index bddd1fc1..00000000 --- a/NativeScript/include/cppgc/testing.h +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_TESTING_H_ -#define INCLUDE_CPPGC_TESTING_H_ - -#include "cppgc/common.h" -#include "cppgc/macros.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -class HeapHandle; - -/** - * Namespace contains testing helpers. - */ -namespace testing { - -/** - * Overrides the state of the stack with the provided value. Parameters passed - * to explicit garbage collection calls still take precedence. Must not be - * nested. - * - * This scope is useful to make the garbage collector consider the stack when - * tasks that invoke garbage collection (through the provided platform) contain - * interesting pointers on its stack. - */ -class V8_EXPORT V8_NODISCARD OverrideEmbedderStackStateScope final { - CPPGC_STACK_ALLOCATED(); - - public: - /** - * Constructs a scoped object that automatically enters and leaves the scope. - * - * \param heap_handle The corresponding heap. - */ - explicit OverrideEmbedderStackStateScope(HeapHandle& heap_handle, - EmbedderStackState state); - ~OverrideEmbedderStackStateScope(); - - OverrideEmbedderStackStateScope(const OverrideEmbedderStackStateScope&) = - delete; - OverrideEmbedderStackStateScope& operator=( - const OverrideEmbedderStackStateScope&) = delete; - - private: - HeapHandle& heap_handle_; -}; - -/** - * Testing interface for managed heaps that allows for controlling garbage - * collection timings. Embedders should use this class when testing the - * interaction of their code with incremental/concurrent garbage collection. - */ -class V8_EXPORT StandaloneTestingHeap final { - public: - explicit StandaloneTestingHeap(HeapHandle&); - - /** - * Start an incremental garbage collection. - */ - void StartGarbageCollection(); - - /** - * Perform an incremental step. This will also schedule concurrent steps if - * needed. - * - * \param stack_state The state of the stack during the step. - */ - bool PerformMarkingStep(EmbedderStackState stack_state); - - /** - * Finalize the current garbage collection cycle atomically. - * Assumes that garbage collection is in progress. - * - * \param stack_state The state of the stack for finalizing the garbage - * collection cycle. - */ - void FinalizeGarbageCollection(EmbedderStackState stack_state); - - /** - * Toggle main thread marking on/off. Allows to stress concurrent marking - * (e.g. to better detect data races). - * - * \param should_mark Denotes whether the main thread should contribute to - * marking. Defaults to true. - */ - void ToggleMainThreadMarking(bool should_mark); - - /** - * Force enable compaction for the next garbage collection cycle. - */ - void ForceCompactionForNextGarbageCollection(); - - private: - HeapHandle& heap_handle_; -}; - -V8_EXPORT bool IsHeapObjectOld(void*); - -} // namespace testing -} // namespace cppgc - -#endif // INCLUDE_CPPGC_TESTING_H_ diff --git a/NativeScript/include/cppgc/trace-trait.h b/NativeScript/include/cppgc/trace-trait.h deleted file mode 100644 index 83619b1d..00000000 --- a/NativeScript/include/cppgc/trace-trait.h +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_TRACE_TRAIT_H_ -#define INCLUDE_CPPGC_TRACE_TRAIT_H_ - -#include - -#include "cppgc/type-traits.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -class Visitor; - -namespace internal { - -// Implementation of the default TraceTrait handling GarbageCollected and -// GarbageCollectedMixin. -template ::type>> -struct TraceTraitImpl; - -} // namespace internal - -/** - * Callback for invoking tracing on a given object. - * - * \param visitor The visitor to dispatch to. - * \param object The object to invoke tracing on. - */ -using TraceCallback = void (*)(Visitor* visitor, const void* object); - -/** - * Describes how to trace an object, i.e., how to visit all Oilpan-relevant - * fields of an object. - */ -struct TraceDescriptor { - /** - * Adjusted base pointer, i.e., the pointer to the class inheriting directly - * from GarbageCollected, of the object that is being traced. - */ - const void* base_object_payload; - /** - * Callback for tracing the object. - */ - TraceCallback callback; -}; - -namespace internal { - -struct V8_EXPORT TraceTraitFromInnerAddressImpl { - static TraceDescriptor GetTraceDescriptor(const void* address); -}; - -/** - * Trait specifying how the garbage collector processes an object of type T. - * - * Advanced users may override handling by creating a specialization for their - * type. - */ -template -struct TraceTraitBase { - static_assert(internal::IsTraceableV, "T must have a Trace() method"); - - /** - * Accessor for retrieving a TraceDescriptor to process an object of type T. - * - * \param self The object to be processed. - * \returns a TraceDescriptor to process the object. - */ - static TraceDescriptor GetTraceDescriptor(const void* self) { - return internal::TraceTraitImpl::GetTraceDescriptor( - static_cast(self)); - } - - /** - * Function invoking the tracing for an object of type T. - * - * \param visitor The visitor to dispatch to. - * \param self The object to invoke tracing on. - */ - static void Trace(Visitor* visitor, const void* self) { - static_cast(self)->Trace(visitor); - } -}; - -} // namespace internal - -template -struct TraceTrait : public internal::TraceTraitBase {}; - -namespace internal { - -template -struct TraceTraitImpl { - static_assert(IsGarbageCollectedTypeV, - "T must be of type GarbageCollected or GarbageCollectedMixin"); - static TraceDescriptor GetTraceDescriptor(const void* self) { - return {self, TraceTrait::Trace}; - } -}; - -template -struct TraceTraitImpl { - static TraceDescriptor GetTraceDescriptor(const void* self) { - return internal::TraceTraitFromInnerAddressImpl::GetTraceDescriptor(self); - } -}; - -} // namespace internal -} // namespace cppgc - -#endif // INCLUDE_CPPGC_TRACE_TRAIT_H_ diff --git a/NativeScript/include/cppgc/type-traits.h b/NativeScript/include/cppgc/type-traits.h deleted file mode 100644 index 970ffd48..00000000 --- a/NativeScript/include/cppgc/type-traits.h +++ /dev/null @@ -1,240 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_TYPE_TRAITS_H_ -#define INCLUDE_CPPGC_TYPE_TRAITS_H_ - -// This file should stay with minimal dependencies to allow embedder to check -// against Oilpan types without including any other parts. -#include -#include - -namespace cppgc { - -class Visitor; - -namespace internal { -template -class BasicMember; -struct DijkstraWriteBarrierPolicy; -struct NoWriteBarrierPolicy; -class StrongMemberTag; -class UntracedMemberTag; -class WeakMemberTag; - -// Not supposed to be specialized by the user. -template -struct IsWeak : std::false_type {}; - -// IsTraceMethodConst is used to verify that all Trace methods are marked as -// const. It is equivalent to IsTraceable but for a non-const object. -template -struct IsTraceMethodConst : std::false_type {}; - -template -struct IsTraceMethodConst().Trace( - std::declval()))>> : std::true_type { -}; - -template -struct IsTraceable : std::false_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template -struct IsTraceable< - T, std::void_t().Trace(std::declval()))>> - : std::true_type { - // All Trace methods should be marked as const. If an object of type - // 'T' is traceable then any object of type 'const T' should also - // be traceable. - static_assert(IsTraceMethodConst(), - "Trace methods should be marked as const."); -}; - -template -constexpr bool IsTraceableV = IsTraceable::value; - -template -struct HasGarbageCollectedMixinTypeMarker : std::false_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template -struct HasGarbageCollectedMixinTypeMarker< - T, std::void_t< - typename std::remove_const_t::IsGarbageCollectedMixinTypeMarker>> - : std::true_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template -struct HasGarbageCollectedTypeMarker : std::false_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template -struct HasGarbageCollectedTypeMarker< - T, - std::void_t::IsGarbageCollectedTypeMarker>> - : std::true_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template ::value, - bool = HasGarbageCollectedMixinTypeMarker::value> -struct IsGarbageCollectedMixinType : std::false_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template -struct IsGarbageCollectedMixinType : std::true_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template ::value> -struct IsGarbageCollectedType : std::false_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template -struct IsGarbageCollectedType : std::true_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template -struct IsGarbageCollectedOrMixinType - : std::integral_constant::value || - IsGarbageCollectedMixinType::value> { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template ::value && - HasGarbageCollectedMixinTypeMarker::value)> -struct IsGarbageCollectedWithMixinType : std::false_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template -struct IsGarbageCollectedWithMixinType : std::true_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template -struct IsSubclassOfBasicMemberTemplate { - private: - template - static std::true_type SubclassCheck( - BasicMember*); - static std::false_type SubclassCheck(...); - - public: - static constexpr bool value = - decltype(SubclassCheck(std::declval()))::value; -}; - -template ::value> -struct IsMemberType : std::false_type {}; - -template -struct IsMemberType : std::true_type {}; - -template ::value> -struct IsWeakMemberType : std::false_type {}; - -template -struct IsWeakMemberType : std::true_type {}; - -template ::value> -struct IsUntracedMemberType : std::false_type {}; - -template -struct IsUntracedMemberType : std::true_type {}; - -template -struct IsComplete { - private: - template - static std::true_type IsSizeOfKnown(U*); - static std::false_type IsSizeOfKnown(...); - - public: - static constexpr bool value = - decltype(IsSizeOfKnown(std::declval()))::value; -}; - -} // namespace internal - -/** - * Value is true for types that inherit from `GarbageCollectedMixin` but not - * `GarbageCollected` (i.e., they are free mixins), and false otherwise. - */ -template -constexpr bool IsGarbageCollectedMixinTypeV = - internal::IsGarbageCollectedMixinType::value; - -/** - * Value is true for types that inherit from `GarbageCollected`, and false - * otherwise. - */ -template -constexpr bool IsGarbageCollectedTypeV = - internal::IsGarbageCollectedType::value; - -/** - * Value is true for types that inherit from either `GarbageCollected` or - * `GarbageCollectedMixin`, and false otherwise. - */ -template -constexpr bool IsGarbageCollectedOrMixinTypeV = - internal::IsGarbageCollectedOrMixinType::value; - -/** - * Value is true for types that inherit from `GarbageCollected` and - * `GarbageCollectedMixin`, and false otherwise. - */ -template -constexpr bool IsGarbageCollectedWithMixinTypeV = - internal::IsGarbageCollectedWithMixinType::value; - -/** - * Value is true for types of type `Member`, and false otherwise. - */ -template -constexpr bool IsMemberTypeV = internal::IsMemberType::value; - -/** - * Value is true for types of type `UntracedMember`, and false otherwise. - */ -template -constexpr bool IsUntracedMemberTypeV = internal::IsUntracedMemberType::value; - -/** - * Value is true for types of type `WeakMember`, and false otherwise. - */ -template -constexpr bool IsWeakMemberTypeV = internal::IsWeakMemberType::value; - -/** - * Value is true for types that are considered weak references, and false - * otherwise. - */ -template -constexpr bool IsWeakV = internal::IsWeak::value; - -/** - * Value is true for types that are complete, and false otherwise. - */ -template -constexpr bool IsCompleteV = internal::IsComplete::value; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_TYPE_TRAITS_H_ diff --git a/NativeScript/include/cppgc/visitor.h b/NativeScript/include/cppgc/visitor.h deleted file mode 100644 index 57e2ce39..00000000 --- a/NativeScript/include/cppgc/visitor.h +++ /dev/null @@ -1,379 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_VISITOR_H_ -#define INCLUDE_CPPGC_VISITOR_H_ - -#include "cppgc/custom-space.h" -#include "cppgc/ephemeron-pair.h" -#include "cppgc/garbage-collected.h" -#include "cppgc/internal/logging.h" -#include "cppgc/internal/pointer-policies.h" -#include "cppgc/liveness-broker.h" -#include "cppgc/member.h" -#include "cppgc/sentinel-pointer.h" -#include "cppgc/source-location.h" -#include "cppgc/trace-trait.h" -#include "cppgc/type-traits.h" - -namespace cppgc { - -namespace internal { -template -class BasicCrossThreadPersistent; -template -class BasicPersistent; -class ConservativeTracingVisitor; -class VisitorBase; -class VisitorFactory; -} // namespace internal - -using WeakCallback = void (*)(const LivenessBroker&, const void*); - -/** - * Visitor passed to trace methods. All managed pointers must have called the - * Visitor's trace method on them. - * - * \code - * class Foo final : public GarbageCollected { - * public: - * void Trace(Visitor* visitor) const { - * visitor->Trace(foo_); - * visitor->Trace(weak_foo_); - * } - * private: - * Member foo_; - * WeakMember weak_foo_; - * }; - * \endcode - */ -class V8_EXPORT Visitor { - public: - class Key { - private: - Key() = default; - friend class internal::VisitorFactory; - }; - - explicit Visitor(Key) {} - - virtual ~Visitor() = default; - - /** - * Trace method for raw pointers. Prefer the versions for managed pointers. - * - * \param member Reference retaining an object. - */ - template - void Trace(const T* t) { - static_assert(sizeof(T), "Pointee type must be fully defined."); - static_assert(internal::IsGarbageCollectedOrMixinType::value, - "T must be GarbageCollected or GarbageCollectedMixin type"); - if (!t) { - return; - } - Visit(t, TraceTrait::GetTraceDescriptor(t)); - } - - /** - * Trace method for Member. - * - * \param member Member reference retaining an object. - */ - template - void Trace(const Member& member) { - const T* value = member.GetRawAtomic(); - CPPGC_DCHECK(value != kSentinelPointer); - Trace(value); - } - - /** - * Trace method for WeakMember. - * - * \param weak_member WeakMember reference weakly retaining an object. - */ - template - void Trace(const WeakMember& weak_member) { - static_assert(sizeof(T), "Pointee type must be fully defined."); - static_assert(internal::IsGarbageCollectedOrMixinType::value, - "T must be GarbageCollected or GarbageCollectedMixin type"); - static_assert(!internal::IsAllocatedOnCompactableSpace::value, - "Weak references to compactable objects are not allowed"); - - const T* value = weak_member.GetRawAtomic(); - - // Bailout assumes that WeakMember emits write barrier. - if (!value) { - return; - } - - CPPGC_DCHECK(value != kSentinelPointer); - VisitWeak(value, TraceTrait::GetTraceDescriptor(value), - &HandleWeak>, &weak_member); - } - - /** - * Trace method for inlined objects that are not allocated themselves but - * otherwise follow managed heap layout and have a Trace() method. - * - * \param object reference of the inlined object. - */ - template - void Trace(const T& object) { -#if V8_ENABLE_CHECKS - // This object is embedded in potentially multiple nested objects. The - // outermost object must not be in construction as such objects are (a) not - // processed immediately, and (b) only processed conservatively if not - // otherwise possible. - CheckObjectNotInConstruction(&object); -#endif // V8_ENABLE_CHECKS - TraceTrait::Trace(this, &object); - } - - /** - * Registers a weak callback method on the object of type T. See - * LivenessBroker for an usage example. - * - * \param object of type T specifying a weak callback method. - */ - template - void RegisterWeakCallbackMethod(const T* object) { - RegisterWeakCallback(&WeakCallbackMethodDelegate, object); - } - - /** - * Trace method for EphemeronPair. - * - * \param ephemeron_pair EphemeronPair reference weakly retaining a key object - * and strongly retaining a value object in case the key object is alive. - */ - template - void Trace(const EphemeronPair& ephemeron_pair) { - TraceEphemeron(ephemeron_pair.key, &ephemeron_pair.value); - RegisterWeakCallbackMethod, - &EphemeronPair::ClearValueIfKeyIsDead>( - &ephemeron_pair); - } - - /** - * Trace method for a single ephemeron. Used for tracing a raw ephemeron in - * which the `key` and `value` are kept separately. - * - * \param weak_member_key WeakMember reference weakly retaining a key object. - * \param member_value Member reference with ephemeron semantics. - */ - template - void TraceEphemeron(const WeakMember& weak_member_key, - const Member* member_value) { - const KeyType* key = weak_member_key.GetRawAtomic(); - if (!key) return; - - // `value` must always be non-null. - CPPGC_DCHECK(member_value); - const ValueType* value = member_value->GetRawAtomic(); - if (!value) return; - - // KeyType and ValueType may refer to GarbageCollectedMixin. - TraceDescriptor value_desc = - TraceTrait::GetTraceDescriptor(value); - CPPGC_DCHECK(value_desc.base_object_payload); - const void* key_base_object_payload = - TraceTrait::GetTraceDescriptor(key).base_object_payload; - CPPGC_DCHECK(key_base_object_payload); - - VisitEphemeron(key_base_object_payload, value, value_desc); - } - - /** - * Trace method for a single ephemeron. Used for tracing a raw ephemeron in - * which the `key` and `value` are kept separately. Note that this overload - * is for non-GarbageCollected `value`s that can be traced though. - * - * \param key `WeakMember` reference weakly retaining a key object. - * \param value Reference weakly retaining a value object. Note that - * `ValueType` here should not be `Member`. It is expected that - * `TraceTrait::GetTraceDescriptor(value)` returns a - * `TraceDescriptor` with a null base pointer but a valid trace method. - */ - template - void TraceEphemeron(const WeakMember& weak_member_key, - const ValueType* value) { - static_assert(!IsGarbageCollectedOrMixinTypeV, - "garbage-collected types must use WeakMember and Member"); - const KeyType* key = weak_member_key.GetRawAtomic(); - if (!key) return; - - // `value` must always be non-null. - CPPGC_DCHECK(value); - TraceDescriptor value_desc = - TraceTrait::GetTraceDescriptor(value); - // `value_desc.base_object_payload` must be null as this override is only - // taken for non-garbage-collected values. - CPPGC_DCHECK(!value_desc.base_object_payload); - - // KeyType might be a GarbageCollectedMixin. - const void* key_base_object_payload = - TraceTrait::GetTraceDescriptor(key).base_object_payload; - CPPGC_DCHECK(key_base_object_payload); - - VisitEphemeron(key_base_object_payload, value, value_desc); - } - - /** - * Trace method that strongifies a WeakMember. - * - * \param weak_member WeakMember reference retaining an object. - */ - template - void TraceStrongly(const WeakMember& weak_member) { - const T* value = weak_member.GetRawAtomic(); - CPPGC_DCHECK(value != kSentinelPointer); - Trace(value); - } - - /** - * Trace method for weak containers. - * - * \param object reference of the weak container. - * \param callback to be invoked. - * \param data custom data that is passed to the callback. - */ - template - void TraceWeakContainer(const T* object, WeakCallback callback, - const void* data) { - if (!object) return; - VisitWeakContainer(object, TraceTrait::GetTraceDescriptor(object), - TraceTrait::GetWeakTraceDescriptor(object), callback, - data); - } - - /** - * Registers a slot containing a reference to an object allocated on a - * compactable space. Such references maybe be arbitrarily moved by the GC. - * - * \param slot location of reference to object that might be moved by the GC. - */ - template - void RegisterMovableReference(const T** slot) { - static_assert(internal::IsAllocatedOnCompactableSpace::value, - "Only references to objects allocated on compactable spaces " - "should be registered as movable slots."); - static_assert(!IsGarbageCollectedMixinTypeV, - "Mixin types do not support compaction."); - HandleMovableReference(reinterpret_cast(slot)); - } - - /** - * Registers a weak callback that is invoked during garbage collection. - * - * \param callback to be invoked. - * \param data custom data that is passed to the callback. - */ - virtual void RegisterWeakCallback(WeakCallback callback, const void* data) {} - - /** - * Defers tracing an object from a concurrent thread to the mutator thread. - * Should be called by Trace methods of types that are not safe to trace - * concurrently. - * - * \param parameter tells the trace callback which object was deferred. - * \param callback to be invoked for tracing on the mutator thread. - * \param deferred_size size of deferred object. - * - * \returns false if the object does not need to be deferred (i.e. currently - * traced on the mutator thread) and true otherwise (i.e. currently traced on - * a concurrent thread). - */ - virtual V8_WARN_UNUSED_RESULT bool DeferTraceToMutatorThreadIfConcurrent( - const void* parameter, TraceCallback callback, size_t deferred_size) { - // By default tracing is not deferred. - return false; - } - - protected: - virtual void Visit(const void* self, TraceDescriptor) {} - virtual void VisitWeak(const void* self, TraceDescriptor, WeakCallback, - const void* weak_member) {} - virtual void VisitRoot(const void*, TraceDescriptor, const SourceLocation&) {} - virtual void VisitWeakRoot(const void* self, TraceDescriptor, WeakCallback, - const void* weak_root, const SourceLocation&) {} - virtual void VisitEphemeron(const void* key, const void* value, - TraceDescriptor value_desc) {} - virtual void VisitWeakContainer(const void* self, TraceDescriptor strong_desc, - TraceDescriptor weak_desc, - WeakCallback callback, const void* data) {} - virtual void HandleMovableReference(const void**) {} - - private: - template - static void WeakCallbackMethodDelegate(const LivenessBroker& info, - const void* self) { - // Callback is registered through a potential const Trace method but needs - // to be able to modify fields. See HandleWeak. - (const_cast(static_cast(self))->*method)(info); - } - - template - static void HandleWeak(const LivenessBroker& info, const void* object) { - const PointerType* weak = static_cast(object); - auto* raw_ptr = weak->GetFromGC(); - // Sentinel values are preserved for weak pointers. - if (raw_ptr == kSentinelPointer) return; - if (!info.IsHeapObjectAlive(raw_ptr)) { - weak->ClearFromGC(); - } - } - - template * = nullptr> - void TraceRoot(const Persistent& p, const SourceLocation& loc) { - using PointeeType = typename Persistent::PointeeType; - static_assert(sizeof(PointeeType), - "Persistent's pointee type must be fully defined"); - static_assert(internal::IsGarbageCollectedOrMixinType::value, - "Persistent's pointee type must be GarbageCollected or " - "GarbageCollectedMixin"); - auto* ptr = p.GetFromGC(); - if (!ptr) { - return; - } - VisitRoot(ptr, TraceTrait::GetTraceDescriptor(ptr), loc); - } - - template < - typename WeakPersistent, - std::enable_if_t* = nullptr> - void TraceRoot(const WeakPersistent& p, const SourceLocation& loc) { - using PointeeType = typename WeakPersistent::PointeeType; - static_assert(sizeof(PointeeType), - "Persistent's pointee type must be fully defined"); - static_assert(internal::IsGarbageCollectedOrMixinType::value, - "Persistent's pointee type must be GarbageCollected or " - "GarbageCollectedMixin"); - static_assert(!internal::IsAllocatedOnCompactableSpace::value, - "Weak references to compactable objects are not allowed"); - auto* ptr = p.GetFromGC(); - VisitWeakRoot(ptr, TraceTrait::GetTraceDescriptor(ptr), - &HandleWeak, &p, loc); - } - -#if V8_ENABLE_CHECKS - void CheckObjectNotInConstruction(const void* address); -#endif // V8_ENABLE_CHECKS - - template - friend class internal::BasicCrossThreadPersistent; - template - friend class internal::BasicPersistent; - friend class internal::ConservativeTracingVisitor; - friend class internal::VisitorBase; -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_VISITOR_H_ diff --git a/NativeScript/include/inspector/Debugger.h b/NativeScript/include/inspector/Debugger.h deleted file mode 100644 index d984c6a4..00000000 --- a/NativeScript/include/inspector/Debugger.h +++ /dev/null @@ -1,59 +0,0 @@ -// This file is generated by Exported_h.template. - -// Copyright (c) 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef v8_inspector_protocol_Debugger_api_h -#define v8_inspector_protocol_Debugger_api_h - -#include "v8-inspector.h" - -namespace v8_inspector { -namespace protocol { - -#ifndef v8_inspector_protocol_exported_api_h -#define v8_inspector_protocol_exported_api_h -class V8_EXPORT Exported { -public: - virtual void AppendSerialized(std::vector* out) const = 0; - - virtual ~Exported() { } -}; -#endif // !defined(v8_inspector_protocol_exported_api_h) - -namespace Debugger { -namespace API { - -// ------------- Enums. - -namespace Paused { -namespace ReasonEnum { -V8_EXPORT extern const char* Ambiguous; -V8_EXPORT extern const char* Assert; -V8_EXPORT extern const char* CSPViolation; -V8_EXPORT extern const char* DebugCommand; -V8_EXPORT extern const char* DOM; -V8_EXPORT extern const char* EventListener; -V8_EXPORT extern const char* Exception; -V8_EXPORT extern const char* Instrumentation; -V8_EXPORT extern const char* OOM; -V8_EXPORT extern const char* Other; -V8_EXPORT extern const char* PromiseRejection; -V8_EXPORT extern const char* XHR; -} // ReasonEnum -} // Paused - -// ------------- Types. - -class V8_EXPORT SearchMatch : public Exported { -public: - static std::unique_ptr fromBinary(const uint8_t* data, size_t length); -}; - -} // namespace API -} // namespace Debugger -} // namespace v8_inspector -} // namespace protocol - -#endif // !defined(v8_inspector_protocol_Debugger_api_h) diff --git a/NativeScript/include/inspector/Runtime.h b/NativeScript/include/inspector/Runtime.h deleted file mode 100644 index f9d515ba..00000000 --- a/NativeScript/include/inspector/Runtime.h +++ /dev/null @@ -1,52 +0,0 @@ -// This file is generated by Exported_h.template. - -// Copyright (c) 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef v8_inspector_protocol_Runtime_api_h -#define v8_inspector_protocol_Runtime_api_h - -#include "v8-inspector.h" - -namespace v8_inspector { -namespace protocol { - -#ifndef v8_inspector_protocol_exported_api_h -#define v8_inspector_protocol_exported_api_h -class V8_EXPORT Exported { -public: - virtual void AppendSerialized(std::vector* out) const = 0; - - virtual ~Exported() { } -}; -#endif // !defined(v8_inspector_protocol_exported_api_h) - -namespace Runtime { -namespace API { - -// ------------- Enums. - -// ------------- Types. - -class V8_EXPORT RemoteObject : public Exported { -public: - static std::unique_ptr fromBinary(const uint8_t* data, size_t length); -}; - -class V8_EXPORT StackTrace : public Exported { -public: - static std::unique_ptr fromBinary(const uint8_t* data, size_t length); -}; - -class V8_EXPORT StackTraceId : public Exported { -public: - static std::unique_ptr fromBinary(const uint8_t* data, size_t length); -}; - -} // namespace API -} // namespace Runtime -} // namespace v8_inspector -} // namespace protocol - -#endif // !defined(v8_inspector_protocol_Runtime_api_h) diff --git a/NativeScript/include/inspector/Schema.h b/NativeScript/include/inspector/Schema.h deleted file mode 100644 index 03a76fa9..00000000 --- a/NativeScript/include/inspector/Schema.h +++ /dev/null @@ -1,42 +0,0 @@ -// This file is generated by Exported_h.template. - -// Copyright (c) 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef v8_inspector_protocol_Schema_api_h -#define v8_inspector_protocol_Schema_api_h - -#include "v8-inspector.h" - -namespace v8_inspector { -namespace protocol { - -#ifndef v8_inspector_protocol_exported_api_h -#define v8_inspector_protocol_exported_api_h -class V8_EXPORT Exported { -public: - virtual void AppendSerialized(std::vector* out) const = 0; - - virtual ~Exported() { } -}; -#endif // !defined(v8_inspector_protocol_exported_api_h) - -namespace Schema { -namespace API { - -// ------------- Enums. - -// ------------- Types. - -class V8_EXPORT Domain : public Exported { -public: - static std::unique_ptr fromBinary(const uint8_t* data, size_t length); -}; - -} // namespace API -} // namespace Schema -} // namespace v8_inspector -} // namespace protocol - -#endif // !defined(v8_inspector_protocol_Schema_api_h) diff --git a/NativeScript/include/js_protocol-1.2.json b/NativeScript/include/js_protocol-1.2.json deleted file mode 100644 index aff68062..00000000 --- a/NativeScript/include/js_protocol-1.2.json +++ /dev/null @@ -1,997 +0,0 @@ -{ - "version": { "major": "1", "minor": "2" }, - "domains": [ - { - "domain": "Schema", - "description": "Provides information about the protocol schema.", - "types": [ - { - "id": "Domain", - "type": "object", - "description": "Description of the protocol domain.", - "exported": true, - "properties": [ - { "name": "name", "type": "string", "description": "Domain name." }, - { "name": "version", "type": "string", "description": "Domain version." } - ] - } - ], - "commands": [ - { - "name": "getDomains", - "description": "Returns supported domains.", - "handlers": ["browser", "renderer"], - "returns": [ - { "name": "domains", "type": "array", "items": { "$ref": "Domain" }, "description": "List of supported domains." } - ] - } - ] - }, - { - "domain": "Runtime", - "description": "Runtime domain exposes JavaScript runtime by means of remote evaluation and mirror objects. Evaluation results are returned as mirror object that expose object type, string representation and unique identifier that can be used for further object reference. Original objects are maintained in memory unless they are either explicitly released or are released along with the other objects in their object group.", - "types": [ - { - "id": "ScriptId", - "type": "string", - "description": "Unique script identifier." - }, - { - "id": "RemoteObjectId", - "type": "string", - "description": "Unique object identifier." - }, - { - "id": "UnserializableValue", - "type": "string", - "enum": ["Infinity", "NaN", "-Infinity", "-0"], - "description": "Primitive value which cannot be JSON-stringified." - }, - { - "id": "RemoteObject", - "type": "object", - "description": "Mirror object referencing original JavaScript object.", - "exported": true, - "properties": [ - { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol"], "description": "Object type." }, - { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "map", "set", "iterator", "generator", "error", "proxy", "promise", "typedarray"], "description": "Object subtype hint. Specified for object type values only." }, - { "name": "className", "type": "string", "optional": true, "description": "Object class (constructor) name. Specified for object type values only." }, - { "name": "value", "type": "any", "optional": true, "description": "Remote object value in case of primitive values or JSON values (if it was requested)." }, - { "name": "unserializableValue", "$ref": "UnserializableValue", "optional": true, "description": "Primitive value which can not be JSON-stringified does not have value, but gets this property." }, - { "name": "description", "type": "string", "optional": true, "description": "String representation of the object." }, - { "name": "objectId", "$ref": "RemoteObjectId", "optional": true, "description": "Unique object identifier (for non-primitive values)." }, - { "name": "preview", "$ref": "ObjectPreview", "optional": true, "description": "Preview containing abbreviated property values. Specified for object type values only.", "experimental": true }, - { "name": "customPreview", "$ref": "CustomPreview", "optional": true, "experimental": true} - ] - }, - { - "id": "CustomPreview", - "type": "object", - "experimental": true, - "properties": [ - { "name": "header", "type": "string"}, - { "name": "hasBody", "type": "boolean"}, - { "name": "formatterObjectId", "$ref": "RemoteObjectId"}, - { "name": "bindRemoteObjectFunctionId", "$ref": "RemoteObjectId" }, - { "name": "configObjectId", "$ref": "RemoteObjectId", "optional": true } - ] - }, - { - "id": "ObjectPreview", - "type": "object", - "experimental": true, - "description": "Object containing abbreviated remote object value.", - "properties": [ - { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol"], "description": "Object type." }, - { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "map", "set", "iterator", "generator", "error"], "description": "Object subtype hint. Specified for object type values only." }, - { "name": "description", "type": "string", "optional": true, "description": "String representation of the object." }, - { "name": "overflow", "type": "boolean", "description": "True iff some of the properties or entries of the original object did not fit." }, - { "name": "properties", "type": "array", "items": { "$ref": "PropertyPreview" }, "description": "List of the properties." }, - { "name": "entries", "type": "array", "items": { "$ref": "EntryPreview" }, "optional": true, "description": "List of the entries. Specified for map and set subtype values only." } - ] - }, - { - "id": "PropertyPreview", - "type": "object", - "experimental": true, - "properties": [ - { "name": "name", "type": "string", "description": "Property name." }, - { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol", "accessor"], "description": "Object type. Accessor means that the property itself is an accessor property." }, - { "name": "value", "type": "string", "optional": true, "description": "User-friendly property value string." }, - { "name": "valuePreview", "$ref": "ObjectPreview", "optional": true, "description": "Nested value preview." }, - { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "map", "set", "iterator", "generator", "error"], "description": "Object subtype hint. Specified for object type values only." } - ] - }, - { - "id": "EntryPreview", - "type": "object", - "experimental": true, - "properties": [ - { "name": "key", "$ref": "ObjectPreview", "optional": true, "description": "Preview of the key. Specified for map-like collection entries." }, - { "name": "value", "$ref": "ObjectPreview", "description": "Preview of the value." } - ] - }, - { - "id": "PropertyDescriptor", - "type": "object", - "description": "Object property descriptor.", - "properties": [ - { "name": "name", "type": "string", "description": "Property name or symbol description." }, - { "name": "value", "$ref": "RemoteObject", "optional": true, "description": "The value associated with the property." }, - { "name": "writable", "type": "boolean", "optional": true, "description": "True if the value associated with the property may be changed (data descriptors only)." }, - { "name": "get", "$ref": "RemoteObject", "optional": true, "description": "A function which serves as a getter for the property, or undefined if there is no getter (accessor descriptors only)." }, - { "name": "set", "$ref": "RemoteObject", "optional": true, "description": "A function which serves as a setter for the property, or undefined if there is no setter (accessor descriptors only)." }, - { "name": "configurable", "type": "boolean", "description": "True if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object." }, - { "name": "enumerable", "type": "boolean", "description": "True if this property shows up during enumeration of the properties on the corresponding object." }, - { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." }, - { "name": "isOwn", "optional": true, "type": "boolean", "description": "True if the property is owned for the object." }, - { "name": "symbol", "$ref": "RemoteObject", "optional": true, "description": "Property symbol object, if the property is of the symbol type." } - ] - }, - { - "id": "InternalPropertyDescriptor", - "type": "object", - "description": "Object internal property descriptor. This property isn't normally visible in JavaScript code.", - "properties": [ - { "name": "name", "type": "string", "description": "Conventional property name." }, - { "name": "value", "$ref": "RemoteObject", "optional": true, "description": "The value associated with the property." } - ] - }, - { - "id": "CallArgument", - "type": "object", - "description": "Represents function call argument. Either remote object id objectId, primitive value, unserializable primitive value or neither of (for undefined) them should be specified.", - "properties": [ - { "name": "value", "type": "any", "optional": true, "description": "Primitive value." }, - { "name": "unserializableValue", "$ref": "UnserializableValue", "optional": true, "description": "Primitive value which can not be JSON-stringified." }, - { "name": "objectId", "$ref": "RemoteObjectId", "optional": true, "description": "Remote object handle." } - ] - }, - { - "id": "ExecutionContextId", - "type": "integer", - "description": "Id of an execution context." - }, - { - "id": "ExecutionContextDescription", - "type": "object", - "description": "Description of an isolated world.", - "properties": [ - { "name": "id", "$ref": "ExecutionContextId", "description": "Unique id of the execution context. It can be used to specify in which execution context script evaluation should be performed." }, - { "name": "origin", "type": "string", "description": "Execution context origin." }, - { "name": "name", "type": "string", "description": "Human readable name describing given context." }, - { "name": "auxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data." } - ] - }, - { - "id": "ExceptionDetails", - "type": "object", - "description": "Detailed information about exception (or error) that was thrown during script compilation or execution.", - "properties": [ - { "name": "exceptionId", "type": "integer", "description": "Exception id." }, - { "name": "text", "type": "string", "description": "Exception text, which should be used together with exception object when available." }, - { "name": "lineNumber", "type": "integer", "description": "Line number of the exception location (0-based)." }, - { "name": "columnNumber", "type": "integer", "description": "Column number of the exception location (0-based)." }, - { "name": "scriptId", "$ref": "ScriptId", "optional": true, "description": "Script ID of the exception location." }, - { "name": "url", "type": "string", "optional": true, "description": "URL of the exception location, to be used when the script was not reported." }, - { "name": "stackTrace", "$ref": "StackTrace", "optional": true, "description": "JavaScript stack trace if available." }, - { "name": "exception", "$ref": "RemoteObject", "optional": true, "description": "Exception object if available." }, - { "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Identifier of the context where exception happened." } - ] - }, - { - "id": "Timestamp", - "type": "number", - "description": "Number of milliseconds since epoch." - }, - { - "id": "CallFrame", - "type": "object", - "description": "Stack entry for runtime errors and assertions.", - "properties": [ - { "name": "functionName", "type": "string", "description": "JavaScript function name." }, - { "name": "scriptId", "$ref": "ScriptId", "description": "JavaScript script id." }, - { "name": "url", "type": "string", "description": "JavaScript script name or url." }, - { "name": "lineNumber", "type": "integer", "description": "JavaScript script line number (0-based)." }, - { "name": "columnNumber", "type": "integer", "description": "JavaScript script column number (0-based)." } - ] - }, - { - "id": "StackTrace", - "type": "object", - "description": "Call frames for assertions or error messages.", - "exported": true, - "properties": [ - { "name": "description", "type": "string", "optional": true, "description": "String label of this stack trace. For async traces this may be a name of the function that initiated the async call." }, - { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "JavaScript function name." }, - { "name": "parent", "$ref": "StackTrace", "optional": true, "description": "Asynchronous JavaScript stack trace that preceded this stack, if available." } - ] - } - ], - "commands": [ - { - "name": "evaluate", - "async": true, - "parameters": [ - { "name": "expression", "type": "string", "description": "Expression to evaluate." }, - { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." }, - { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Determines whether Command Line API should be available during the evaluation." }, - { "name": "silent", "type": "boolean", "optional": true, "description": "In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides setPauseOnException state." }, - { "name": "contextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to perform evaluation. If the parameter is omitted the evaluation will be performed in the context of the inspected page." }, - { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." }, - { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the result." }, - { "name": "userGesture", "type": "boolean", "optional": true, "experimental": true, "description": "Whether execution should be treated as initiated by user in the UI." }, - { "name": "awaitPromise", "type": "boolean", "optional":true, "description": "Whether execution should wait for promise to be resolved. If the result of evaluation is not a Promise, it's considered to be an error." } - ], - "returns": [ - { "name": "result", "$ref": "RemoteObject", "description": "Evaluation result." }, - { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."} - ], - "description": "Evaluates expression on global object." - }, - { - "name": "awaitPromise", - "async": true, - "parameters": [ - { "name": "promiseObjectId", "$ref": "RemoteObjectId", "description": "Identifier of the promise." }, - { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." }, - { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." } - ], - "returns": [ - { "name": "result", "$ref": "RemoteObject", "description": "Promise result. Will contain rejected value if promise was rejected." }, - { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details if stack strace is available."} - ], - "description": "Add handler to promise with given promise object id." - }, - { - "name": "callFunctionOn", - "async": true, - "parameters": [ - { "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to call function on." }, - { "name": "functionDeclaration", "type": "string", "description": "Declaration of the function to call." }, - { "name": "arguments", "type": "array", "items": { "$ref": "CallArgument", "description": "Call argument." }, "optional": true, "description": "Call arguments. All call arguments must belong to the same JavaScript world as the target object." }, - { "name": "silent", "type": "boolean", "optional": true, "description": "In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides setPauseOnException state." }, - { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object which should be sent by value." }, - { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the result." }, - { "name": "userGesture", "type": "boolean", "optional": true, "experimental": true, "description": "Whether execution should be treated as initiated by user in the UI." }, - { "name": "awaitPromise", "type": "boolean", "optional":true, "description": "Whether execution should wait for promise to be resolved. If the result of evaluation is not a Promise, it's considered to be an error." } - ], - "returns": [ - { "name": "result", "$ref": "RemoteObject", "description": "Call result." }, - { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."} - ], - "description": "Calls function with given declaration on the given object. Object group of the result is inherited from the target object." - }, - { - "name": "getProperties", - "parameters": [ - { "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to return properties for." }, - { "name": "ownProperties", "optional": true, "type": "boolean", "description": "If true, returns properties belonging only to the element itself, not to its prototype chain." }, - { "name": "accessorPropertiesOnly", "optional": true, "type": "boolean", "description": "If true, returns accessor properties (with getter/setter) only; internal properties are not returned either.", "experimental": true }, - { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the results." } - ], - "returns": [ - { "name": "result", "type": "array", "items": { "$ref": "PropertyDescriptor" }, "description": "Object properties." }, - { "name": "internalProperties", "optional": true, "type": "array", "items": { "$ref": "InternalPropertyDescriptor" }, "description": "Internal object properties (only of the element itself)." }, - { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."} - ], - "description": "Returns properties of a given object. Object group of the result is inherited from the target object." - }, - { - "name": "releaseObject", - "parameters": [ - { "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to release." } - ], - "description": "Releases remote object with given id." - }, - { - "name": "releaseObjectGroup", - "parameters": [ - { "name": "objectGroup", "type": "string", "description": "Symbolic object group name." } - ], - "description": "Releases all remote objects that belong to a given group." - }, - { - "name": "runIfWaitingForDebugger", - "description": "Tells inspected instance to run if it was waiting for debugger to attach." - }, - { - "name": "enable", - "description": "Enables reporting of execution contexts creation by means of executionContextCreated event. When the reporting gets enabled the event will be sent immediately for each existing execution context." - }, - { - "name": "disable", - "description": "Disables reporting of execution contexts creation." - }, - { - "name": "discardConsoleEntries", - "description": "Discards collected exceptions and console API calls." - }, - { - "name": "setCustomObjectFormatterEnabled", - "parameters": [ - { - "name": "enabled", - "type": "boolean" - } - ], - "experimental": true - }, - { - "name": "compileScript", - "parameters": [ - { "name": "expression", "type": "string", "description": "Expression to compile." }, - { "name": "sourceURL", "type": "string", "description": "Source url to be set for the script." }, - { "name": "persistScript", "type": "boolean", "description": "Specifies whether the compiled script should be persisted." }, - { "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to perform script run. If the parameter is omitted the evaluation will be performed in the context of the inspected page." } - ], - "returns": [ - { "name": "scriptId", "$ref": "ScriptId", "optional": true, "description": "Id of the script." }, - { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."} - ], - "description": "Compiles expression." - }, - { - "name": "runScript", - "async": true, - "parameters": [ - { "name": "scriptId", "$ref": "ScriptId", "description": "Id of the script to run." }, - { "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to perform script run. If the parameter is omitted the evaluation will be performed in the context of the inspected page." }, - { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." }, - { "name": "silent", "type": "boolean", "optional": true, "description": "In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides setPauseOnException state." }, - { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Determines whether Command Line API should be available during the evaluation." }, - { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object which should be sent by value." }, - { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." }, - { "name": "awaitPromise", "type": "boolean", "optional": true, "description": "Whether execution should wait for promise to be resolved. If the result of evaluation is not a Promise, it's considered to be an error." } - ], - "returns": [ - { "name": "result", "$ref": "RemoteObject", "description": "Run result." }, - { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."} - ], - "description": "Runs script with given id in a given context." - } - ], - "events": [ - { - "name": "executionContextCreated", - "parameters": [ - { "name": "context", "$ref": "ExecutionContextDescription", "description": "A newly created execution contex." } - ], - "description": "Issued when new execution context is created." - }, - { - "name": "executionContextDestroyed", - "parameters": [ - { "name": "executionContextId", "$ref": "ExecutionContextId", "description": "Id of the destroyed context" } - ], - "description": "Issued when execution context is destroyed." - }, - { - "name": "executionContextsCleared", - "description": "Issued when all executionContexts were cleared in browser" - }, - { - "name": "exceptionThrown", - "description": "Issued when exception was thrown and unhandled.", - "parameters": [ - { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp of the exception." }, - { "name": "exceptionDetails", "$ref": "ExceptionDetails" } - ] - }, - { - "name": "exceptionRevoked", - "description": "Issued when unhandled exception was revoked.", - "parameters": [ - { "name": "reason", "type": "string", "description": "Reason describing why exception was revoked." }, - { "name": "exceptionId", "type": "integer", "description": "The id of revoked exception, as reported in exceptionUnhandled." } - ] - }, - { - "name": "consoleAPICalled", - "description": "Issued when console API was called.", - "parameters": [ - { "name": "type", "type": "string", "enum": ["log", "debug", "info", "error", "warning", "dir", "dirxml", "table", "trace", "clear", "startGroup", "startGroupCollapsed", "endGroup", "assert", "profile", "profileEnd"], "description": "Type of the call." }, - { "name": "args", "type": "array", "items": { "$ref": "RemoteObject" }, "description": "Call arguments." }, - { "name": "executionContextId", "$ref": "ExecutionContextId", "description": "Identifier of the context where the call was made." }, - { "name": "timestamp", "$ref": "Timestamp", "description": "Call timestamp." }, - { "name": "stackTrace", "$ref": "StackTrace", "optional": true, "description": "Stack trace captured when the call was made." } - ] - }, - { - "name": "inspectRequested", - "description": "Issued when object should be inspected (for example, as a result of inspect() command line API call).", - "parameters": [ - { "name": "object", "$ref": "RemoteObject" }, - { "name": "hints", "type": "object" } - ] - } - ] - }, - { - "domain": "Debugger", - "description": "Debugger domain exposes JavaScript debugging capabilities. It allows setting and removing breakpoints, stepping through execution, exploring stack traces, etc.", - "dependencies": ["Runtime"], - "types": [ - { - "id": "BreakpointId", - "type": "string", - "description": "Breakpoint identifier." - }, - { - "id": "CallFrameId", - "type": "string", - "description": "Call frame identifier." - }, - { - "id": "Location", - "type": "object", - "properties": [ - { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Script identifier as reported in the Debugger.scriptParsed." }, - { "name": "lineNumber", "type": "integer", "description": "Line number in the script (0-based)." }, - { "name": "columnNumber", "type": "integer", "optional": true, "description": "Column number in the script (0-based)." } - ], - "description": "Location in the source code." - }, - { - "id": "ScriptPosition", - "experimental": true, - "type": "object", - "properties": [ - { "name": "lineNumber", "type": "integer" }, - { "name": "columnNumber", "type": "integer" } - ], - "description": "Location in the source code." - }, - { - "id": "CallFrame", - "type": "object", - "properties": [ - { "name": "callFrameId", "$ref": "CallFrameId", "description": "Call frame identifier. This identifier is only valid while the virtual machine is paused." }, - { "name": "functionName", "type": "string", "description": "Name of the JavaScript function called on this call frame." }, - { "name": "functionLocation", "$ref": "Location", "optional": true, "experimental": true, "description": "Location in the source code." }, - { "name": "location", "$ref": "Location", "description": "Location in the source code." }, - { "name": "scopeChain", "type": "array", "items": { "$ref": "Scope" }, "description": "Scope chain for this call frame." }, - { "name": "this", "$ref": "Runtime.RemoteObject", "description": "this object for this call frame." }, - { "name": "returnValue", "$ref": "Runtime.RemoteObject", "optional": true, "description": "The value being returned, if the function is at return point." } - ], - "description": "JavaScript call frame. Array of call frames form the call stack." - }, - { - "id": "Scope", - "type": "object", - "properties": [ - { "name": "type", "type": "string", "enum": ["global", "local", "with", "closure", "catch", "block", "script"], "description": "Scope type." }, - { "name": "object", "$ref": "Runtime.RemoteObject", "description": "Object representing the scope. For global and with scopes it represents the actual object; for the rest of the scopes, it is artificial transient object enumerating scope variables as its properties." }, - { "name": "name", "type": "string", "optional": true }, - { "name": "startLocation", "$ref": "Location", "optional": true, "description": "Location in the source code where scope starts" }, - { "name": "endLocation", "$ref": "Location", "optional": true, "description": "Location in the source code where scope ends" } - ], - "description": "Scope description." - }, - { - "id": "SearchMatch", - "type": "object", - "description": "Search match for resource.", - "exported": true, - "properties": [ - { "name": "lineNumber", "type": "number", "description": "Line number in resource content." }, - { "name": "lineContent", "type": "string", "description": "Line with match content." } - ], - "experimental": true - } - ], - "commands": [ - { - "name": "enable", - "description": "Enables debugger for the given page. Clients should not assume that the debugging has been enabled until the result for this command is received." - }, - { - "name": "disable", - "description": "Disables debugger for given page." - }, - { - "name": "setBreakpointsActive", - "parameters": [ - { "name": "active", "type": "boolean", "description": "New value for breakpoints active state." } - ], - "description": "Activates / deactivates all breakpoints on the page." - }, - { - "name": "setSkipAllPauses", - "parameters": [ - { "name": "skip", "type": "boolean", "description": "New value for skip pauses state." } - ], - "description": "Makes page not interrupt on any pauses (breakpoint, exception, dom exception etc)." - }, - { - "name": "setBreakpointByUrl", - "parameters": [ - { "name": "lineNumber", "type": "integer", "description": "Line number to set breakpoint at." }, - { "name": "url", "type": "string", "optional": true, "description": "URL of the resources to set breakpoint on." }, - { "name": "urlRegex", "type": "string", "optional": true, "description": "Regex pattern for the URLs of the resources to set breakpoints on. Either url or urlRegex must be specified." }, - { "name": "columnNumber", "type": "integer", "optional": true, "description": "Offset in the line to set breakpoint at." }, - { "name": "condition", "type": "string", "optional": true, "description": "Expression to use as a breakpoint condition. When specified, debugger will only stop on the breakpoint if this expression evaluates to true." } - ], - "returns": [ - { "name": "breakpointId", "$ref": "BreakpointId", "description": "Id of the created breakpoint for further reference." }, - { "name": "locations", "type": "array", "items": { "$ref": "Location" }, "description": "List of the locations this breakpoint resolved into upon addition." } - ], - "description": "Sets JavaScript breakpoint at given location specified either by URL or URL regex. Once this command is issued, all existing parsed scripts will have breakpoints resolved and returned in locations property. Further matching script parsing will result in subsequent breakpointResolved events issued. This logical breakpoint will survive page reloads." - }, - { - "name": "setBreakpoint", - "parameters": [ - { "name": "location", "$ref": "Location", "description": "Location to set breakpoint in." }, - { "name": "condition", "type": "string", "optional": true, "description": "Expression to use as a breakpoint condition. When specified, debugger will only stop on the breakpoint if this expression evaluates to true." } - ], - "returns": [ - { "name": "breakpointId", "$ref": "BreakpointId", "description": "Id of the created breakpoint for further reference." }, - { "name": "actualLocation", "$ref": "Location", "description": "Location this breakpoint resolved into." } - ], - "description": "Sets JavaScript breakpoint at a given location." - }, - { - "name": "removeBreakpoint", - "parameters": [ - { "name": "breakpointId", "$ref": "BreakpointId" } - ], - "description": "Removes JavaScript breakpoint." - }, - { - "name": "continueToLocation", - "parameters": [ - { "name": "location", "$ref": "Location", "description": "Location to continue to." } - ], - "description": "Continues execution until specific location is reached." - }, - { - "name": "stepOver", - "description": "Steps over the statement." - }, - { - "name": "stepInto", - "description": "Steps into the function call." - }, - { - "name": "stepOut", - "description": "Steps out of the function call." - }, - { - "name": "pause", - "description": "Stops on the next JavaScript statement." - }, - { - "name": "resume", - "description": "Resumes JavaScript execution." - }, - { - "name": "searchInContent", - "parameters": [ - { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script to search in." }, - { "name": "query", "type": "string", "description": "String to search for." }, - { "name": "caseSensitive", "type": "boolean", "optional": true, "description": "If true, search is case sensitive." }, - { "name": "isRegex", "type": "boolean", "optional": true, "description": "If true, treats string parameter as regex." } - ], - "returns": [ - { "name": "result", "type": "array", "items": { "$ref": "SearchMatch" }, "description": "List of search matches." } - ], - "experimental": true, - "description": "Searches for given string in script content." - }, - { - "name": "setScriptSource", - "parameters": [ - { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script to edit." }, - { "name": "scriptSource", "type": "string", "description": "New content of the script." }, - { "name": "dryRun", "type": "boolean", "optional": true, "description": " If true the change will not actually be applied. Dry run may be used to get result description without actually modifying the code." } - ], - "returns": [ - { "name": "callFrames", "type": "array", "optional": true, "items": { "$ref": "CallFrame" }, "description": "New stack trace in case editing has happened while VM was stopped." }, - { "name": "stackChanged", "type": "boolean", "optional": true, "description": "Whether current call stack was modified after applying the changes." }, - { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any." }, - { "name": "exceptionDetails", "optional": true, "$ref": "Runtime.ExceptionDetails", "description": "Exception details if any." } - ], - "description": "Edits JavaScript source live." - }, - { - "name": "restartFrame", - "parameters": [ - { "name": "callFrameId", "$ref": "CallFrameId", "description": "Call frame identifier to evaluate on." } - ], - "returns": [ - { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "New stack trace." }, - { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any." } - ], - "description": "Restarts particular call frame from the beginning." - }, - { - "name": "getScriptSource", - "parameters": [ - { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script to get source for." } - ], - "returns": [ - { "name": "scriptSource", "type": "string", "description": "Script source." } - ], - "description": "Returns source for the script with given id." - }, - { - "name": "setPauseOnExceptions", - "parameters": [ - { "name": "state", "type": "string", "enum": ["none", "uncaught", "all"], "description": "Pause on exceptions mode." } - ], - "description": "Defines pause on exceptions state. Can be set to stop on all exceptions, uncaught exceptions or no exceptions. Initial pause on exceptions state is none." - }, - { - "name": "evaluateOnCallFrame", - "parameters": [ - { "name": "callFrameId", "$ref": "CallFrameId", "description": "Call frame identifier to evaluate on." }, - { "name": "expression", "type": "string", "description": "Expression to evaluate." }, - { "name": "objectGroup", "type": "string", "optional": true, "description": "String object group name to put result into (allows rapid releasing resulting object handles using releaseObjectGroup)." }, - { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Specifies whether command line API should be available to the evaluated expression, defaults to false." }, - { "name": "silent", "type": "boolean", "optional": true, "description": "In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides setPauseOnException state." }, - { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." }, - { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the result." } - ], - "returns": [ - { "name": "result", "$ref": "Runtime.RemoteObject", "description": "Object wrapper for the evaluation result." }, - { "name": "exceptionDetails", "$ref": "Runtime.ExceptionDetails", "optional": true, "description": "Exception details."} - ], - "description": "Evaluates expression on a given call frame." - }, - { - "name": "setVariableValue", - "parameters": [ - { "name": "scopeNumber", "type": "integer", "description": "0-based number of scope as was listed in scope chain. Only 'local', 'closure' and 'catch' scope types are allowed. Other scopes could be manipulated manually." }, - { "name": "variableName", "type": "string", "description": "Variable name." }, - { "name": "newValue", "$ref": "Runtime.CallArgument", "description": "New variable value." }, - { "name": "callFrameId", "$ref": "CallFrameId", "description": "Id of callframe that holds variable." } - ], - "description": "Changes value of variable in a callframe. Object-based scopes are not supported and must be mutated manually." - }, - { - "name": "setAsyncCallStackDepth", - "parameters": [ - { "name": "maxDepth", "type": "integer", "description": "Maximum depth of async call stacks. Setting to 0 will effectively disable collecting async call stacks (default)." } - ], - "description": "Enables or disables async call stacks tracking." - }, - { - "name": "setBlackboxPatterns", - "parameters": [ - { "name": "patterns", "type": "array", "items": { "type": "string" }, "description": "Array of regexps that will be used to check script url for blackbox state." } - ], - "experimental": true, - "description": "Replace previous blackbox patterns with passed ones. Forces backend to skip stepping/pausing in scripts with url matching one of the patterns. VM will try to leave blackboxed script by performing 'step in' several times, finally resorting to 'step out' if unsuccessful." - }, - { - "name": "setBlackboxedRanges", - "parameters": [ - { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script." }, - { "name": "positions", "type": "array", "items": { "$ref": "ScriptPosition" } } - ], - "experimental": true, - "description": "Makes backend skip steps in the script in blackboxed ranges. VM will try leave blacklisted scripts by performing 'step in' several times, finally resorting to 'step out' if unsuccessful. Positions array contains positions where blackbox state is changed. First interval isn't blackboxed. Array should be sorted." - } - ], - "events": [ - { - "name": "scriptParsed", - "parameters": [ - { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Identifier of the script parsed." }, - { "name": "url", "type": "string", "description": "URL or name of the script parsed (if any)." }, - { "name": "startLine", "type": "integer", "description": "Line offset of the script within the resource with given URL (for script tags)." }, - { "name": "startColumn", "type": "integer", "description": "Column offset of the script within the resource with given URL." }, - { "name": "endLine", "type": "integer", "description": "Last line of the script." }, - { "name": "endColumn", "type": "integer", "description": "Length of the last line of the script." }, - { "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "description": "Specifies script creation context." }, - { "name": "hash", "type": "string", "description": "Content hash of the script."}, - { "name": "executionContextAuxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data." }, - { "name": "isLiveEdit", "type": "boolean", "optional": true, "description": "True, if this script is generated as a result of the live edit operation.", "experimental": true }, - { "name": "sourceMapURL", "type": "string", "optional": true, "description": "URL of source map associated with script (if any)." }, - { "name": "hasSourceURL", "type": "boolean", "optional": true, "description": "True, if this script has sourceURL.", "experimental": true } - ], - "description": "Fired when virtual machine parses script. This event is also fired for all known and uncollected scripts upon enabling debugger." - }, - { - "name": "scriptFailedToParse", - "parameters": [ - { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Identifier of the script parsed." }, - { "name": "url", "type": "string", "description": "URL or name of the script parsed (if any)." }, - { "name": "startLine", "type": "integer", "description": "Line offset of the script within the resource with given URL (for script tags)." }, - { "name": "startColumn", "type": "integer", "description": "Column offset of the script within the resource with given URL." }, - { "name": "endLine", "type": "integer", "description": "Last line of the script." }, - { "name": "endColumn", "type": "integer", "description": "Length of the last line of the script." }, - { "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "description": "Specifies script creation context." }, - { "name": "hash", "type": "string", "description": "Content hash of the script."}, - { "name": "executionContextAuxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data." }, - { "name": "sourceMapURL", "type": "string", "optional": true, "description": "URL of source map associated with script (if any)." }, - { "name": "hasSourceURL", "type": "boolean", "optional": true, "description": "True, if this script has sourceURL.", "experimental": true } - ], - "description": "Fired when virtual machine fails to parse the script." - }, - { - "name": "breakpointResolved", - "parameters": [ - { "name": "breakpointId", "$ref": "BreakpointId", "description": "Breakpoint unique identifier." }, - { "name": "location", "$ref": "Location", "description": "Actual breakpoint location." } - ], - "description": "Fired when breakpoint is resolved to an actual script and location." - }, - { - "name": "paused", - "parameters": [ - { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "Call stack the virtual machine stopped on." }, - { "name": "reason", "type": "string", "enum": [ "XHR", "DOM", "EventListener", "exception", "assert", "debugCommand", "promiseRejection", "other" ], "description": "Pause reason.", "exported": true }, - { "name": "data", "type": "object", "optional": true, "description": "Object containing break-specific auxiliary properties." }, - { "name": "hitBreakpoints", "type": "array", "optional": true, "items": { "type": "string" }, "description": "Hit breakpoints IDs" }, - { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any." } - ], - "description": "Fired when the virtual machine stopped on breakpoint or exception or any other stop criteria." - }, - { - "name": "resumed", - "description": "Fired when the virtual machine resumed execution." - } - ] - }, - { - "domain": "Console", - "description": "This domain is deprecated - use Runtime or Log instead.", - "dependencies": ["Runtime"], - "deprecated": true, - "types": [ - { - "id": "ConsoleMessage", - "type": "object", - "description": "Console message.", - "properties": [ - { "name": "source", "type": "string", "enum": ["xml", "javascript", "network", "console-api", "storage", "appcache", "rendering", "security", "other", "deprecation", "worker"], "description": "Message source." }, - { "name": "level", "type": "string", "enum": ["log", "warning", "error", "debug", "info"], "description": "Message severity." }, - { "name": "text", "type": "string", "description": "Message text." }, - { "name": "url", "type": "string", "optional": true, "description": "URL of the message origin." }, - { "name": "line", "type": "integer", "optional": true, "description": "Line number in the resource that generated this message (1-based)." }, - { "name": "column", "type": "integer", "optional": true, "description": "Column number in the resource that generated this message (1-based)." } - ] - } - ], - "commands": [ - { - "name": "enable", - "description": "Enables console domain, sends the messages collected so far to the client by means of the messageAdded notification." - }, - { - "name": "disable", - "description": "Disables console domain, prevents further console messages from being reported to the client." - }, - { - "name": "clearMessages", - "description": "Does nothing." - } - ], - "events": [ - { - "name": "messageAdded", - "parameters": [ - { "name": "message", "$ref": "ConsoleMessage", "description": "Console message that has been added." } - ], - "description": "Issued when new console message is added." - } - ] - }, - { - "domain": "Profiler", - "dependencies": ["Runtime", "Debugger"], - "types": [ - { - "id": "ProfileNode", - "type": "object", - "description": "Profile node. Holds callsite information, execution statistics and child nodes.", - "properties": [ - { "name": "id", "type": "integer", "description": "Unique id of the node." }, - { "name": "callFrame", "$ref": "Runtime.CallFrame", "description": "Function location." }, - { "name": "hitCount", "type": "integer", "optional": true, "experimental": true, "description": "Number of samples where this node was on top of the call stack." }, - { "name": "children", "type": "array", "items": { "type": "integer" }, "optional": true, "description": "Child node ids." }, - { "name": "deoptReason", "type": "string", "optional": true, "description": "The reason of being not optimized. The function may be deoptimized or marked as don't optimize."}, - { "name": "positionTicks", "type": "array", "items": { "$ref": "PositionTickInfo" }, "optional": true, "experimental": true, "description": "An array of source position ticks." } - ] - }, - { - "id": "Profile", - "type": "object", - "description": "Profile.", - "properties": [ - { "name": "nodes", "type": "array", "items": { "$ref": "ProfileNode" }, "description": "The list of profile nodes. First item is the root node." }, - { "name": "startTime", "type": "number", "description": "Profiling start timestamp in microseconds." }, - { "name": "endTime", "type": "number", "description": "Profiling end timestamp in microseconds." }, - { "name": "samples", "optional": true, "type": "array", "items": { "type": "integer" }, "description": "Ids of samples top nodes." }, - { "name": "timeDeltas", "optional": true, "type": "array", "items": { "type": "integer" }, "description": "Time intervals between adjacent samples in microseconds. The first delta is relative to the profile startTime." } - ] - }, - { - "id": "PositionTickInfo", - "type": "object", - "experimental": true, - "description": "Specifies a number of samples attributed to a certain source position.", - "properties": [ - { "name": "line", "type": "integer", "description": "Source line number (1-based)." }, - { "name": "ticks", "type": "integer", "description": "Number of samples attributed to the source line." } - ] - } - ], - "commands": [ - { - "name": "enable" - }, - { - "name": "disable" - }, - { - "name": "setSamplingInterval", - "parameters": [ - { "name": "interval", "type": "integer", "description": "New sampling interval in microseconds." } - ], - "description": "Changes CPU profiler sampling interval. Must be called before CPU profiles recording started." - }, - { - "name": "start" - }, - { - "name": "stop", - "returns": [ - { "name": "profile", "$ref": "Profile", "description": "Recorded profile." } - ] - } - ], - "events": [ - { - "name": "consoleProfileStarted", - "parameters": [ - { "name": "id", "type": "string" }, - { "name": "location", "$ref": "Debugger.Location", "description": "Location of console.profile()." }, - { "name": "title", "type": "string", "optional": true, "description": "Profile title passed as an argument to console.profile()." } - ], - "description": "Sent when new profile recodring is started using console.profile() call." - }, - { - "name": "consoleProfileFinished", - "parameters": [ - { "name": "id", "type": "string" }, - { "name": "location", "$ref": "Debugger.Location", "description": "Location of console.profileEnd()." }, - { "name": "profile", "$ref": "Profile" }, - { "name": "title", "type": "string", "optional": true, "description": "Profile title passed as an argument to console.profile()." } - ] - } - ] - }, - { - "domain": "HeapProfiler", - "dependencies": ["Runtime"], - "experimental": true, - "types": [ - { - "id": "HeapSnapshotObjectId", - "type": "string", - "description": "Heap snapshot object id." - }, - { - "id": "SamplingHeapProfileNode", - "type": "object", - "description": "Sampling Heap Profile node. Holds callsite information, allocation statistics and child nodes.", - "properties": [ - { "name": "callFrame", "$ref": "Runtime.CallFrame", "description": "Function location." }, - { "name": "selfSize", "type": "number", "description": "Allocations size in bytes for the node excluding children." }, - { "name": "children", "type": "array", "items": { "$ref": "SamplingHeapProfileNode" }, "description": "Child nodes." } - ] - }, - { - "id": "SamplingHeapProfile", - "type": "object", - "description": "Profile.", - "properties": [ - { "name": "head", "$ref": "SamplingHeapProfileNode" } - ] - } - ], - "commands": [ - { - "name": "enable" - }, - { - "name": "disable" - }, - { - "name": "startTrackingHeapObjects", - "parameters": [ - { "name": "trackAllocations", "type": "boolean", "optional": true } - ] - }, - { - "name": "stopTrackingHeapObjects", - "parameters": [ - { "name": "reportProgress", "type": "boolean", "optional": true, "description": "If true 'reportHeapSnapshotProgress' events will be generated while snapshot is being taken when the tracking is stopped." } - ] - }, - { - "name": "takeHeapSnapshot", - "parameters": [ - { "name": "reportProgress", "type": "boolean", "optional": true, "description": "If true 'reportHeapSnapshotProgress' events will be generated while snapshot is being taken." } - ] - }, - { - "name": "collectGarbage" - }, - { - "name": "getObjectByHeapObjectId", - "parameters": [ - { "name": "objectId", "$ref": "HeapSnapshotObjectId" }, - { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." } - ], - "returns": [ - { "name": "result", "$ref": "Runtime.RemoteObject", "description": "Evaluation result." } - ] - }, - { - "name": "addInspectedHeapObject", - "parameters": [ - { "name": "heapObjectId", "$ref": "HeapSnapshotObjectId", "description": "Heap snapshot object id to be accessible by means of $x command line API." } - ], - "description": "Enables console to refer to the node with given id via $x (see Command Line API for more details $x functions)." - }, - { - "name": "getHeapObjectId", - "parameters": [ - { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "description": "Identifier of the object to get heap object id for." } - ], - "returns": [ - { "name": "heapSnapshotObjectId", "$ref": "HeapSnapshotObjectId", "description": "Id of the heap snapshot object corresponding to the passed remote object id." } - ] - }, - { - "name": "startSampling", - "parameters": [ - { "name": "samplingInterval", "type": "number", "optional": true, "description": "Average sample interval in bytes. Poisson distribution is used for the intervals. The default value is 32768 bytes." } - ] - }, - { - "name": "stopSampling", - "returns": [ - { "name": "profile", "$ref": "SamplingHeapProfile", "description": "Recorded sampling heap profile." } - ] - } - ], - "events": [ - { - "name": "addHeapSnapshotChunk", - "parameters": [ - { "name": "chunk", "type": "string" } - ] - }, - { - "name": "resetProfiles" - }, - { - "name": "reportHeapSnapshotProgress", - "parameters": [ - { "name": "done", "type": "integer" }, - { "name": "total", "type": "integer" }, - { "name": "finished", "type": "boolean", "optional": true } - ] - }, - { - "name": "lastSeenObjectId", - "description": "If heap objects tracking has been started then backend regulary sends a current value for last seen object id and corresponding timestamp. If the were changes in the heap since last event then one or more heapStatsUpdate events will be sent before a new lastSeenObjectId event.", - "parameters": [ - { "name": "lastSeenObjectId", "type": "integer" }, - { "name": "timestamp", "type": "number" } - ] - }, - { - "name": "heapStatsUpdate", - "description": "If heap objects tracking has been started then backend may send update for one or more fragments", - "parameters": [ - { "name": "statsUpdate", "type": "array", "items": { "type": "integer" }, "description": "An array of triplets. Each triplet describes a fragment. The first integer is the fragment index, the second integer is a total count of objects for the fragment, the third integer is a total size of the objects for the fragment."} - ] - } - ] - }] -} diff --git a/NativeScript/include/js_protocol-1.3.json b/NativeScript/include/js_protocol-1.3.json deleted file mode 100644 index ea573d11..00000000 --- a/NativeScript/include/js_protocol-1.3.json +++ /dev/null @@ -1,1205 +0,0 @@ -{ - "version": { "major": "1", "minor": "3" }, - "domains": [ - { - "domain": "Schema", - "description": "This domain is deprecated.", - "deprecated": true, - "types": [ - { - "id": "Domain", - "type": "object", - "description": "Description of the protocol domain.", - "properties": [ - { "name": "name", "type": "string", "description": "Domain name." }, - { "name": "version", "type": "string", "description": "Domain version." } - ] - } - ], - "commands": [ - { - "name": "getDomains", - "description": "Returns supported domains.", - "handlers": ["browser", "renderer"], - "returns": [ - { "name": "domains", "type": "array", "items": { "$ref": "Domain" }, "description": "List of supported domains." } - ] - } - ] - }, - { - "domain": "Runtime", - "description": "Runtime domain exposes JavaScript runtime by means of remote evaluation and mirror objects. Evaluation results are returned as mirror object that expose object type, string representation and unique identifier that can be used for further object reference. Original objects are maintained in memory unless they are either explicitly released or are released along with the other objects in their object group.", - "types": [ - { - "id": "ScriptId", - "type": "string", - "description": "Unique script identifier." - }, - { - "id": "RemoteObjectId", - "type": "string", - "description": "Unique object identifier." - }, - { - "id": "UnserializableValue", - "type": "string", - "enum": ["Infinity", "NaN", "-Infinity", "-0"], - "description": "Primitive value which cannot be JSON-stringified." - }, - { - "id": "RemoteObject", - "type": "object", - "description": "Mirror object referencing original JavaScript object.", - "properties": [ - { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol"], "description": "Object type." }, - { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "map", "set", "weakmap", "weakset", "iterator", "generator", "error", "proxy", "promise", "typedarray"], "description": "Object subtype hint. Specified for object type values only." }, - { "name": "className", "type": "string", "optional": true, "description": "Object class (constructor) name. Specified for object type values only." }, - { "name": "value", "type": "any", "optional": true, "description": "Remote object value in case of primitive values or JSON values (if it was requested)." }, - { "name": "unserializableValue", "$ref": "UnserializableValue", "optional": true, "description": "Primitive value which can not be JSON-stringified does not have value, but gets this property." }, - { "name": "description", "type": "string", "optional": true, "description": "String representation of the object." }, - { "name": "objectId", "$ref": "RemoteObjectId", "optional": true, "description": "Unique object identifier (for non-primitive values)." }, - { "name": "preview", "$ref": "ObjectPreview", "optional": true, "description": "Preview containing abbreviated property values. Specified for object type values only.", "experimental": true }, - { "name": "customPreview", "$ref": "CustomPreview", "optional": true, "experimental": true} - ] - }, - { - "id": "CustomPreview", - "type": "object", - "experimental": true, - "properties": [ - { "name": "header", "type": "string"}, - { "name": "hasBody", "type": "boolean"}, - { "name": "formatterObjectId", "$ref": "RemoteObjectId"}, - { "name": "bindRemoteObjectFunctionId", "$ref": "RemoteObjectId" }, - { "name": "configObjectId", "$ref": "RemoteObjectId", "optional": true } - ] - }, - { - "id": "ObjectPreview", - "type": "object", - "experimental": true, - "description": "Object containing abbreviated remote object value.", - "properties": [ - { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol"], "description": "Object type." }, - { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "map", "set", "weakmap", "weakset", "iterator", "generator", "error"], "description": "Object subtype hint. Specified for object type values only." }, - { "name": "description", "type": "string", "optional": true, "description": "String representation of the object." }, - { "name": "overflow", "type": "boolean", "description": "True iff some of the properties or entries of the original object did not fit." }, - { "name": "properties", "type": "array", "items": { "$ref": "PropertyPreview" }, "description": "List of the properties." }, - { "name": "entries", "type": "array", "items": { "$ref": "EntryPreview" }, "optional": true, "description": "List of the entries. Specified for map and set subtype values only." } - ] - }, - { - "id": "PropertyPreview", - "type": "object", - "experimental": true, - "properties": [ - { "name": "name", "type": "string", "description": "Property name." }, - { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol", "accessor"], "description": "Object type. Accessor means that the property itself is an accessor property." }, - { "name": "value", "type": "string", "optional": true, "description": "User-friendly property value string." }, - { "name": "valuePreview", "$ref": "ObjectPreview", "optional": true, "description": "Nested value preview." }, - { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "map", "set", "weakmap", "weakset", "iterator", "generator", "error"], "description": "Object subtype hint. Specified for object type values only." } - ] - }, - { - "id": "EntryPreview", - "type": "object", - "experimental": true, - "properties": [ - { "name": "key", "$ref": "ObjectPreview", "optional": true, "description": "Preview of the key. Specified for map-like collection entries." }, - { "name": "value", "$ref": "ObjectPreview", "description": "Preview of the value." } - ] - }, - { - "id": "PropertyDescriptor", - "type": "object", - "description": "Object property descriptor.", - "properties": [ - { "name": "name", "type": "string", "description": "Property name or symbol description." }, - { "name": "value", "$ref": "RemoteObject", "optional": true, "description": "The value associated with the property." }, - { "name": "writable", "type": "boolean", "optional": true, "description": "True if the value associated with the property may be changed (data descriptors only)." }, - { "name": "get", "$ref": "RemoteObject", "optional": true, "description": "A function which serves as a getter for the property, or undefined if there is no getter (accessor descriptors only)." }, - { "name": "set", "$ref": "RemoteObject", "optional": true, "description": "A function which serves as a setter for the property, or undefined if there is no setter (accessor descriptors only)." }, - { "name": "configurable", "type": "boolean", "description": "True if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object." }, - { "name": "enumerable", "type": "boolean", "description": "True if this property shows up during enumeration of the properties on the corresponding object." }, - { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." }, - { "name": "isOwn", "optional": true, "type": "boolean", "description": "True if the property is owned for the object." }, - { "name": "symbol", "$ref": "RemoteObject", "optional": true, "description": "Property symbol object, if the property is of the symbol type." } - ] - }, - { - "id": "InternalPropertyDescriptor", - "type": "object", - "description": "Object internal property descriptor. This property isn't normally visible in JavaScript code.", - "properties": [ - { "name": "name", "type": "string", "description": "Conventional property name." }, - { "name": "value", "$ref": "RemoteObject", "optional": true, "description": "The value associated with the property." } - ] - }, - { - "id": "CallArgument", - "type": "object", - "description": "Represents function call argument. Either remote object id objectId, primitive value, unserializable primitive value or neither of (for undefined) them should be specified.", - "properties": [ - { "name": "value", "type": "any", "optional": true, "description": "Primitive value or serializable javascript object." }, - { "name": "unserializableValue", "$ref": "UnserializableValue", "optional": true, "description": "Primitive value which can not be JSON-stringified." }, - { "name": "objectId", "$ref": "RemoteObjectId", "optional": true, "description": "Remote object handle." } - ] - }, - { - "id": "ExecutionContextId", - "type": "integer", - "description": "Id of an execution context." - }, - { - "id": "ExecutionContextDescription", - "type": "object", - "description": "Description of an isolated world.", - "properties": [ - { "name": "id", "$ref": "ExecutionContextId", "description": "Unique id of the execution context. It can be used to specify in which execution context script evaluation should be performed." }, - { "name": "origin", "type": "string", "description": "Execution context origin." }, - { "name": "name", "type": "string", "description": "Human readable name describing given context." }, - { "name": "auxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data." } - ] - }, - { - "id": "ExceptionDetails", - "type": "object", - "description": "Detailed information about exception (or error) that was thrown during script compilation or execution.", - "properties": [ - { "name": "exceptionId", "type": "integer", "description": "Exception id." }, - { "name": "text", "type": "string", "description": "Exception text, which should be used together with exception object when available." }, - { "name": "lineNumber", "type": "integer", "description": "Line number of the exception location (0-based)." }, - { "name": "columnNumber", "type": "integer", "description": "Column number of the exception location (0-based)." }, - { "name": "scriptId", "$ref": "ScriptId", "optional": true, "description": "Script ID of the exception location." }, - { "name": "url", "type": "string", "optional": true, "description": "URL of the exception location, to be used when the script was not reported." }, - { "name": "stackTrace", "$ref": "StackTrace", "optional": true, "description": "JavaScript stack trace if available." }, - { "name": "exception", "$ref": "RemoteObject", "optional": true, "description": "Exception object if available." }, - { "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Identifier of the context where exception happened." } - ] - }, - { - "id": "Timestamp", - "type": "number", - "description": "Number of milliseconds since epoch." - }, - { - "id": "CallFrame", - "type": "object", - "description": "Stack entry for runtime errors and assertions.", - "properties": [ - { "name": "functionName", "type": "string", "description": "JavaScript function name." }, - { "name": "scriptId", "$ref": "ScriptId", "description": "JavaScript script id." }, - { "name": "url", "type": "string", "description": "JavaScript script name or url." }, - { "name": "lineNumber", "type": "integer", "description": "JavaScript script line number (0-based)." }, - { "name": "columnNumber", "type": "integer", "description": "JavaScript script column number (0-based)." } - ] - }, - { - "id": "StackTrace", - "type": "object", - "description": "Call frames for assertions or error messages.", - "properties": [ - { "name": "description", "type": "string", "optional": true, "description": "String label of this stack trace. For async traces this may be a name of the function that initiated the async call." }, - { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "JavaScript function name." }, - { "name": "parent", "$ref": "StackTrace", "optional": true, "description": "Asynchronous JavaScript stack trace that preceded this stack, if available." }, - { "name": "parentId", "$ref": "StackTraceId", "optional": true, "experimental": true, "description": "Asynchronous JavaScript stack trace that preceded this stack, if available." } - ] - }, - { - "id": "UniqueDebuggerId", - "type": "string", - "description": "Unique identifier of current debugger.", - "experimental": true - }, - { - "id": "StackTraceId", - "type": "object", - "description": "If debuggerId is set stack trace comes from another debugger and can be resolved there. This allows to track cross-debugger calls. See Runtime.StackTrace and Debugger.paused for usages.", - "properties": [ - { "name": "id", "type": "string" }, - { "name": "debuggerId", "$ref": "UniqueDebuggerId", "optional": true } - ], - "experimental": true - } - ], - "commands": [ - { - "name": "evaluate", - "parameters": [ - { "name": "expression", "type": "string", "description": "Expression to evaluate." }, - { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." }, - { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Determines whether Command Line API should be available during the evaluation." }, - { "name": "silent", "type": "boolean", "optional": true, "description": "In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides setPauseOnException state." }, - { "name": "contextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to perform evaluation. If the parameter is omitted the evaluation will be performed in the context of the inspected page." }, - { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." }, - { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the result." }, - { "name": "userGesture", "type": "boolean", "optional": true, "description": "Whether execution should be treated as initiated by user in the UI." }, - { "name": "awaitPromise", "type": "boolean", "optional":true, "description": "Whether execution should await for resulting value and return once awaited promise is resolved." } - ], - "returns": [ - { "name": "result", "$ref": "RemoteObject", "description": "Evaluation result." }, - { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."} - ], - "description": "Evaluates expression on global object." - }, - { - "name": "awaitPromise", - "parameters": [ - { "name": "promiseObjectId", "$ref": "RemoteObjectId", "description": "Identifier of the promise." }, - { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." }, - { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." } - ], - "returns": [ - { "name": "result", "$ref": "RemoteObject", "description": "Promise result. Will contain rejected value if promise was rejected." }, - { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details if stack strace is available."} - ], - "description": "Add handler to promise with given promise object id." - }, - { - "name": "callFunctionOn", - "parameters": [ - { "name": "functionDeclaration", "type": "string", "description": "Declaration of the function to call." }, - { "name": "objectId", "$ref": "RemoteObjectId", "optional": true, "description": "Identifier of the object to call function on. Either objectId or executionContextId should be specified." }, - { "name": "arguments", "type": "array", "items": { "$ref": "CallArgument", "description": "Call argument." }, "optional": true, "description": "Call arguments. All call arguments must belong to the same JavaScript world as the target object." }, - { "name": "silent", "type": "boolean", "optional": true, "description": "In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides setPauseOnException state." }, - { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object which should be sent by value." }, - { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the result." }, - { "name": "userGesture", "type": "boolean", "optional": true, "description": "Whether execution should be treated as initiated by user in the UI." }, - { "name": "awaitPromise", "type": "boolean", "optional":true, "description": "Whether execution should await for resulting value and return once awaited promise is resolved." }, - { "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies execution context which global object will be used to call function on. Either executionContextId or objectId should be specified." }, - { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects. If objectGroup is not specified and objectId is, objectGroup will be inherited from object." } - ], - "returns": [ - { "name": "result", "$ref": "RemoteObject", "description": "Call result." }, - { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."} - ], - "description": "Calls function with given declaration on the given object. Object group of the result is inherited from the target object." - }, - { - "name": "getProperties", - "parameters": [ - { "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to return properties for." }, - { "name": "ownProperties", "optional": true, "type": "boolean", "description": "If true, returns properties belonging only to the element itself, not to its prototype chain." }, - { "name": "accessorPropertiesOnly", "optional": true, "type": "boolean", "description": "If true, returns accessor properties (with getter/setter) only; internal properties are not returned either.", "experimental": true }, - { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the results." } - ], - "returns": [ - { "name": "result", "type": "array", "items": { "$ref": "PropertyDescriptor" }, "description": "Object properties." }, - { "name": "internalProperties", "optional": true, "type": "array", "items": { "$ref": "InternalPropertyDescriptor" }, "description": "Internal object properties (only of the element itself)." }, - { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."} - ], - "description": "Returns properties of a given object. Object group of the result is inherited from the target object." - }, - { - "name": "releaseObject", - "parameters": [ - { "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to release." } - ], - "description": "Releases remote object with given id." - }, - { - "name": "releaseObjectGroup", - "parameters": [ - { "name": "objectGroup", "type": "string", "description": "Symbolic object group name." } - ], - "description": "Releases all remote objects that belong to a given group." - }, - { - "name": "runIfWaitingForDebugger", - "description": "Tells inspected instance to run if it was waiting for debugger to attach." - }, - { - "name": "enable", - "description": "Enables reporting of execution contexts creation by means of executionContextCreated event. When the reporting gets enabled the event will be sent immediately for each existing execution context." - }, - { - "name": "disable", - "description": "Disables reporting of execution contexts creation." - }, - { - "name": "discardConsoleEntries", - "description": "Discards collected exceptions and console API calls." - }, - { - "name": "setCustomObjectFormatterEnabled", - "parameters": [ - { - "name": "enabled", - "type": "boolean" - } - ], - "experimental": true - }, - { - "name": "compileScript", - "parameters": [ - { "name": "expression", "type": "string", "description": "Expression to compile." }, - { "name": "sourceURL", "type": "string", "description": "Source url to be set for the script." }, - { "name": "persistScript", "type": "boolean", "description": "Specifies whether the compiled script should be persisted." }, - { "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to perform script run. If the parameter is omitted the evaluation will be performed in the context of the inspected page." } - ], - "returns": [ - { "name": "scriptId", "$ref": "ScriptId", "optional": true, "description": "Id of the script." }, - { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."} - ], - "description": "Compiles expression." - }, - { - "name": "runScript", - "parameters": [ - { "name": "scriptId", "$ref": "ScriptId", "description": "Id of the script to run." }, - { "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to perform script run. If the parameter is omitted the evaluation will be performed in the context of the inspected page." }, - { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." }, - { "name": "silent", "type": "boolean", "optional": true, "description": "In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides setPauseOnException state." }, - { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Determines whether Command Line API should be available during the evaluation." }, - { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object which should be sent by value." }, - { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." }, - { "name": "awaitPromise", "type": "boolean", "optional": true, "description": "Whether execution should await for resulting value and return once awaited promise is resolved." } - ], - "returns": [ - { "name": "result", "$ref": "RemoteObject", "description": "Run result." }, - { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."} - ], - "description": "Runs script with given id in a given context." - }, - { - "name": "queryObjects", - "parameters": [ - { "name": "prototypeObjectId", "$ref": "RemoteObjectId", "description": "Identifier of the prototype to return objects for." } - ], - "returns": [ - { "name": "objects", "$ref": "RemoteObject", "description": "Array with objects." } - ] - }, - { - "name": "globalLexicalScopeNames", - "parameters": [ - { "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to lookup global scope variables." } - ], - "returns": [ - { "name": "names", "type": "array", "items": { "type": "string" } } - ], - "description": "Returns all let, const and class variables from global scope." - } - ], - "events": [ - { - "name": "executionContextCreated", - "parameters": [ - { "name": "context", "$ref": "ExecutionContextDescription", "description": "A newly created execution context." } - ], - "description": "Issued when new execution context is created." - }, - { - "name": "executionContextDestroyed", - "parameters": [ - { "name": "executionContextId", "$ref": "ExecutionContextId", "description": "Id of the destroyed context" } - ], - "description": "Issued when execution context is destroyed." - }, - { - "name": "executionContextsCleared", - "description": "Issued when all executionContexts were cleared in browser" - }, - { - "name": "exceptionThrown", - "description": "Issued when exception was thrown and unhandled.", - "parameters": [ - { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp of the exception." }, - { "name": "exceptionDetails", "$ref": "ExceptionDetails" } - ] - }, - { - "name": "exceptionRevoked", - "description": "Issued when unhandled exception was revoked.", - "parameters": [ - { "name": "reason", "type": "string", "description": "Reason describing why exception was revoked." }, - { "name": "exceptionId", "type": "integer", "description": "The id of revoked exception, as reported in exceptionThrown." } - ] - }, - { - "name": "consoleAPICalled", - "description": "Issued when console API was called.", - "parameters": [ - { "name": "type", "type": "string", "enum": ["log", "debug", "info", "error", "warning", "dir", "dirxml", "table", "trace", "clear", "startGroup", "startGroupCollapsed", "endGroup", "assert", "profile", "profileEnd", "count", "timeEnd"], "description": "Type of the call." }, - { "name": "args", "type": "array", "items": { "$ref": "RemoteObject" }, "description": "Call arguments." }, - { "name": "executionContextId", "$ref": "ExecutionContextId", "description": "Identifier of the context where the call was made." }, - { "name": "timestamp", "$ref": "Timestamp", "description": "Call timestamp." }, - { "name": "stackTrace", "$ref": "StackTrace", "optional": true, "description": "Stack trace captured when the call was made." }, - { "name": "context", "type": "string", "optional": true, "experimental": true, "description": "Console context descriptor for calls on non-default console context (not console.*): 'anonymous#unique-logger-id' for call on unnamed context, 'name#unique-logger-id' for call on named context." } - ] - }, - { - "name": "inspectRequested", - "description": "Issued when object should be inspected (for example, as a result of inspect() command line API call).", - "parameters": [ - { "name": "object", "$ref": "RemoteObject" }, - { "name": "hints", "type": "object" } - ] - } - ] - }, - { - "domain": "Debugger", - "description": "Debugger domain exposes JavaScript debugging capabilities. It allows setting and removing breakpoints, stepping through execution, exploring stack traces, etc.", - "dependencies": ["Runtime"], - "types": [ - { - "id": "BreakpointId", - "type": "string", - "description": "Breakpoint identifier." - }, - { - "id": "CallFrameId", - "type": "string", - "description": "Call frame identifier." - }, - { - "id": "Location", - "type": "object", - "properties": [ - { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Script identifier as reported in the Debugger.scriptParsed." }, - { "name": "lineNumber", "type": "integer", "description": "Line number in the script (0-based)." }, - { "name": "columnNumber", "type": "integer", "optional": true, "description": "Column number in the script (0-based)." } - ], - "description": "Location in the source code." - }, - { - "id": "ScriptPosition", - "experimental": true, - "type": "object", - "properties": [ - { "name": "lineNumber", "type": "integer" }, - { "name": "columnNumber", "type": "integer" } - ], - "description": "Location in the source code." - }, - { - "id": "CallFrame", - "type": "object", - "properties": [ - { "name": "callFrameId", "$ref": "CallFrameId", "description": "Call frame identifier. This identifier is only valid while the virtual machine is paused." }, - { "name": "functionName", "type": "string", "description": "Name of the JavaScript function called on this call frame." }, - { "name": "functionLocation", "$ref": "Location", "optional": true, "description": "Location in the source code." }, - { "name": "location", "$ref": "Location", "description": "Location in the source code." }, - { "name": "url", "type": "string", "description": "JavaScript script name or url." }, - { "name": "scopeChain", "type": "array", "items": { "$ref": "Scope" }, "description": "Scope chain for this call frame." }, - { "name": "this", "$ref": "Runtime.RemoteObject", "description": "this object for this call frame." }, - { "name": "returnValue", "$ref": "Runtime.RemoteObject", "optional": true, "description": "The value being returned, if the function is at return point." } - ], - "description": "JavaScript call frame. Array of call frames form the call stack." - }, - { - "id": "Scope", - "type": "object", - "properties": [ - { "name": "type", "type": "string", "enum": ["global", "local", "with", "closure", "catch", "block", "script", "eval", "module"], "description": "Scope type." }, - { "name": "object", "$ref": "Runtime.RemoteObject", "description": "Object representing the scope. For global and with scopes it represents the actual object; for the rest of the scopes, it is artificial transient object enumerating scope variables as its properties." }, - { "name": "name", "type": "string", "optional": true }, - { "name": "startLocation", "$ref": "Location", "optional": true, "description": "Location in the source code where scope starts" }, - { "name": "endLocation", "$ref": "Location", "optional": true, "description": "Location in the source code where scope ends" } - ], - "description": "Scope description." - }, - { - "id": "SearchMatch", - "type": "object", - "description": "Search match for resource.", - "properties": [ - { "name": "lineNumber", "type": "number", "description": "Line number in resource content." }, - { "name": "lineContent", "type": "string", "description": "Line with match content." } - ] - }, - { - "id": "BreakLocation", - "type": "object", - "properties": [ - { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Script identifier as reported in the Debugger.scriptParsed." }, - { "name": "lineNumber", "type": "integer", "description": "Line number in the script (0-based)." }, - { "name": "columnNumber", "type": "integer", "optional": true, "description": "Column number in the script (0-based)." }, - { "name": "type", "type": "string", "enum": [ "debuggerStatement", "call", "return" ], "optional": true } - ] - } - ], - "commands": [ - { - "name": "enable", - "returns": [ - { "name": "debuggerId", "$ref": "Runtime.UniqueDebuggerId", "experimental": true, "description": "Unique identifier of the debugger." } - ], - "description": "Enables debugger for the given page. Clients should not assume that the debugging has been enabled until the result for this command is received." - }, - { - "name": "disable", - "description": "Disables debugger for given page." - }, - { - "name": "setBreakpointsActive", - "parameters": [ - { "name": "active", "type": "boolean", "description": "New value for breakpoints active state." } - ], - "description": "Activates / deactivates all breakpoints on the page." - }, - { - "name": "setSkipAllPauses", - "parameters": [ - { "name": "skip", "type": "boolean", "description": "New value for skip pauses state." } - ], - "description": "Makes page not interrupt on any pauses (breakpoint, exception, dom exception etc)." - }, - { - "name": "setBreakpointByUrl", - "parameters": [ - { "name": "lineNumber", "type": "integer", "description": "Line number to set breakpoint at." }, - { "name": "url", "type": "string", "optional": true, "description": "URL of the resources to set breakpoint on." }, - { "name": "urlRegex", "type": "string", "optional": true, "description": "Regex pattern for the URLs of the resources to set breakpoints on. Either url or urlRegex must be specified." }, - { "name": "scriptHash", "type": "string", "optional": true, "description": "Script hash of the resources to set breakpoint on." }, - { "name": "columnNumber", "type": "integer", "optional": true, "description": "Offset in the line to set breakpoint at." }, - { "name": "condition", "type": "string", "optional": true, "description": "Expression to use as a breakpoint condition. When specified, debugger will only stop on the breakpoint if this expression evaluates to true." } - ], - "returns": [ - { "name": "breakpointId", "$ref": "BreakpointId", "description": "Id of the created breakpoint for further reference." }, - { "name": "locations", "type": "array", "items": { "$ref": "Location" }, "description": "List of the locations this breakpoint resolved into upon addition." } - ], - "description": "Sets JavaScript breakpoint at given location specified either by URL or URL regex. Once this command is issued, all existing parsed scripts will have breakpoints resolved and returned in locations property. Further matching script parsing will result in subsequent breakpointResolved events issued. This logical breakpoint will survive page reloads." - }, - { - "name": "setBreakpoint", - "parameters": [ - { "name": "location", "$ref": "Location", "description": "Location to set breakpoint in." }, - { "name": "condition", "type": "string", "optional": true, "description": "Expression to use as a breakpoint condition. When specified, debugger will only stop on the breakpoint if this expression evaluates to true." } - ], - "returns": [ - { "name": "breakpointId", "$ref": "BreakpointId", "description": "Id of the created breakpoint for further reference." }, - { "name": "actualLocation", "$ref": "Location", "description": "Location this breakpoint resolved into." } - ], - "description": "Sets JavaScript breakpoint at a given location." - }, - { - "name": "removeBreakpoint", - "parameters": [ - { "name": "breakpointId", "$ref": "BreakpointId" } - ], - "description": "Removes JavaScript breakpoint." - }, - { - "name": "getPossibleBreakpoints", - "parameters": [ - { "name": "start", "$ref": "Location", "description": "Start of range to search possible breakpoint locations in." }, - { "name": "end", "$ref": "Location", "optional": true, "description": "End of range to search possible breakpoint locations in (excluding). When not specified, end of scripts is used as end of range." }, - { "name": "restrictToFunction", "type": "boolean", "optional": true, "description": "Only consider locations which are in the same (non-nested) function as start." } - ], - "returns": [ - { "name": "locations", "type": "array", "items": { "$ref": "BreakLocation" }, "description": "List of the possible breakpoint locations." } - ], - "description": "Returns possible locations for breakpoint. scriptId in start and end range locations should be the same." - }, - { - "name": "continueToLocation", - "parameters": [ - { "name": "location", "$ref": "Location", "description": "Location to continue to." }, - { "name": "targetCallFrames", "type": "string", "enum": ["any", "current"], "optional": true } - ], - "description": "Continues execution until specific location is reached." - }, - { - "name": "pauseOnAsyncCall", - "parameters": [ - { "name": "parentStackTraceId", "$ref": "Runtime.StackTraceId", "description": "Debugger will pause when async call with given stack trace is started." } - ], - "experimental": true - }, - { - "name": "stepOver", - "description": "Steps over the statement." - }, - { - "name": "stepInto", - "parameters": [ - { "name": "breakOnAsyncCall", "type": "boolean", "optional": true, "experimental": true, "description": "Debugger will issue additional Debugger.paused notification if any async task is scheduled before next pause." } - ], - "description": "Steps into the function call." - }, - { - "name": "stepOut", - "description": "Steps out of the function call." - }, - { - "name": "pause", - "description": "Stops on the next JavaScript statement." - }, - { - "name": "scheduleStepIntoAsync", - "description": "This method is deprecated - use Debugger.stepInto with breakOnAsyncCall and Debugger.pauseOnAsyncTask instead. Steps into next scheduled async task if any is scheduled before next pause. Returns success when async task is actually scheduled, returns error if no task were scheduled or another scheduleStepIntoAsync was called.", - "experimental": true - }, - { - "name": "resume", - "description": "Resumes JavaScript execution." - }, - { - "name": "getStackTrace", - "parameters": [ - { "name": "stackTraceId", "$ref": "Runtime.StackTraceId" } - ], - "returns": [ - { "name": "stackTrace", "$ref": "Runtime.StackTrace" } - ], - "description": "Returns stack trace with given stackTraceId.", - "experimental": true - }, - { - "name": "searchInContent", - "parameters": [ - { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script to search in." }, - { "name": "query", "type": "string", "description": "String to search for." }, - { "name": "caseSensitive", "type": "boolean", "optional": true, "description": "If true, search is case sensitive." }, - { "name": "isRegex", "type": "boolean", "optional": true, "description": "If true, treats string parameter as regex." } - ], - "returns": [ - { "name": "result", "type": "array", "items": { "$ref": "SearchMatch" }, "description": "List of search matches." } - ], - "description": "Searches for given string in script content." - }, - { - "name": "setScriptSource", - "parameters": [ - { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script to edit." }, - { "name": "scriptSource", "type": "string", "description": "New content of the script." }, - { "name": "dryRun", "type": "boolean", "optional": true, "description": " If true the change will not actually be applied. Dry run may be used to get result description without actually modifying the code." } - ], - "returns": [ - { "name": "callFrames", "type": "array", "optional": true, "items": { "$ref": "CallFrame" }, "description": "New stack trace in case editing has happened while VM was stopped." }, - { "name": "stackChanged", "type": "boolean", "optional": true, "description": "Whether current call stack was modified after applying the changes." }, - { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any." }, - { "name": "asyncStackTraceId", "$ref": "Runtime.StackTraceId", "optional": true, "experimental": true, "description": "Async stack trace, if any." }, - { "name": "exceptionDetails", "optional": true, "$ref": "Runtime.ExceptionDetails", "description": "Exception details if any." } - ], - "description": "Edits JavaScript source live." - }, - { - "name": "restartFrame", - "parameters": [ - { "name": "callFrameId", "$ref": "CallFrameId", "description": "Call frame identifier to evaluate on." } - ], - "returns": [ - { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "New stack trace." }, - { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any." }, - { "name": "asyncStackTraceId", "$ref": "Runtime.StackTraceId", "optional": true, "experimental": true, "description": "Async stack trace, if any." } - ], - "description": "Restarts particular call frame from the beginning." - }, - { - "name": "getScriptSource", - "parameters": [ - { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script to get source for." } - ], - "returns": [ - { "name": "scriptSource", "type": "string", "description": "Script source." } - ], - "description": "Returns source for the script with given id." - }, - { - "name": "setPauseOnExceptions", - "parameters": [ - { "name": "state", "type": "string", "enum": ["none", "uncaught", "all"], "description": "Pause on exceptions mode." } - ], - "description": "Defines pause on exceptions state. Can be set to stop on all exceptions, uncaught exceptions or no exceptions. Initial pause on exceptions state is none." - }, - { - "name": "evaluateOnCallFrame", - "parameters": [ - { "name": "callFrameId", "$ref": "CallFrameId", "description": "Call frame identifier to evaluate on." }, - { "name": "expression", "type": "string", "description": "Expression to evaluate." }, - { "name": "objectGroup", "type": "string", "optional": true, "description": "String object group name to put result into (allows rapid releasing resulting object handles using releaseObjectGroup)." }, - { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Specifies whether command line API should be available to the evaluated expression, defaults to false." }, - { "name": "silent", "type": "boolean", "optional": true, "description": "In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides setPauseOnException state." }, - { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." }, - { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the result." }, - { "name": "throwOnSideEffect", "type": "boolean", "optional": true, "description": "Whether to throw an exception if side effect cannot be ruled out during evaluation." } - ], - "returns": [ - { "name": "result", "$ref": "Runtime.RemoteObject", "description": "Object wrapper for the evaluation result." }, - { "name": "exceptionDetails", "$ref": "Runtime.ExceptionDetails", "optional": true, "description": "Exception details."} - ], - "description": "Evaluates expression on a given call frame." - }, - { - "name": "setVariableValue", - "parameters": [ - { "name": "scopeNumber", "type": "integer", "description": "0-based number of scope as was listed in scope chain. Only 'local', 'closure' and 'catch' scope types are allowed. Other scopes could be manipulated manually." }, - { "name": "variableName", "type": "string", "description": "Variable name." }, - { "name": "newValue", "$ref": "Runtime.CallArgument", "description": "New variable value." }, - { "name": "callFrameId", "$ref": "CallFrameId", "description": "Id of callframe that holds variable." } - ], - "description": "Changes value of variable in a callframe. Object-based scopes are not supported and must be mutated manually." - }, - { - "name": "setReturnValue", - "parameters": [ - { "name": "newValue", "$ref": "Runtime.CallArgument", "description": "New return value." } - ], - "experimental": true, - "description": "Changes return value in top frame. Available only at return break position." - }, - { - "name": "setAsyncCallStackDepth", - "parameters": [ - { "name": "maxDepth", "type": "integer", "description": "Maximum depth of async call stacks. Setting to 0 will effectively disable collecting async call stacks (default)." } - ], - "description": "Enables or disables async call stacks tracking." - }, - { - "name": "setBlackboxPatterns", - "parameters": [ - { "name": "patterns", "type": "array", "items": { "type": "string" }, "description": "Array of regexps that will be used to check script url for blackbox state." } - ], - "experimental": true, - "description": "Replace previous blackbox patterns with passed ones. Forces backend to skip stepping/pausing in scripts with url matching one of the patterns. VM will try to leave blackboxed script by performing 'step in' several times, finally resorting to 'step out' if unsuccessful." - }, - { - "name": "setBlackboxedRanges", - "parameters": [ - { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script." }, - { "name": "positions", "type": "array", "items": { "$ref": "ScriptPosition" } } - ], - "experimental": true, - "description": "Makes backend skip steps in the script in blackboxed ranges. VM will try leave blacklisted scripts by performing 'step in' several times, finally resorting to 'step out' if unsuccessful. Positions array contains positions where blackbox state is changed. First interval isn't blackboxed. Array should be sorted." - } - ], - "events": [ - { - "name": "scriptParsed", - "parameters": [ - { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Identifier of the script parsed." }, - { "name": "url", "type": "string", "description": "URL or name of the script parsed (if any)." }, - { "name": "startLine", "type": "integer", "description": "Line offset of the script within the resource with given URL (for script tags)." }, - { "name": "startColumn", "type": "integer", "description": "Column offset of the script within the resource with given URL." }, - { "name": "endLine", "type": "integer", "description": "Last line of the script." }, - { "name": "endColumn", "type": "integer", "description": "Length of the last line of the script." }, - { "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "description": "Specifies script creation context." }, - { "name": "hash", "type": "string", "description": "Content hash of the script."}, - { "name": "executionContextAuxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data." }, - { "name": "isLiveEdit", "type": "boolean", "optional": true, "description": "True, if this script is generated as a result of the live edit operation.", "experimental": true }, - { "name": "sourceMapURL", "type": "string", "optional": true, "description": "URL of source map associated with script (if any)." }, - { "name": "hasSourceURL", "type": "boolean", "optional": true, "description": "True, if this script has sourceURL." }, - { "name": "isModule", "type": "boolean", "optional": true, "description": "True, if this script is ES6 module." }, - { "name": "length", "type": "integer", "optional": true, "description": "This script length." }, - { "name": "stackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "JavaScript top stack frame of where the script parsed event was triggered if available.", "experimental": true } - ], - "description": "Fired when virtual machine parses script. This event is also fired for all known and uncollected scripts upon enabling debugger." - }, - { - "name": "scriptFailedToParse", - "parameters": [ - { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Identifier of the script parsed." }, - { "name": "url", "type": "string", "description": "URL or name of the script parsed (if any)." }, - { "name": "startLine", "type": "integer", "description": "Line offset of the script within the resource with given URL (for script tags)." }, - { "name": "startColumn", "type": "integer", "description": "Column offset of the script within the resource with given URL." }, - { "name": "endLine", "type": "integer", "description": "Last line of the script." }, - { "name": "endColumn", "type": "integer", "description": "Length of the last line of the script." }, - { "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "description": "Specifies script creation context." }, - { "name": "hash", "type": "string", "description": "Content hash of the script."}, - { "name": "executionContextAuxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data." }, - { "name": "sourceMapURL", "type": "string", "optional": true, "description": "URL of source map associated with script (if any)." }, - { "name": "hasSourceURL", "type": "boolean", "optional": true, "description": "True, if this script has sourceURL." }, - { "name": "isModule", "type": "boolean", "optional": true, "description": "True, if this script is ES6 module." }, - { "name": "length", "type": "integer", "optional": true, "description": "This script length." }, - { "name": "stackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "JavaScript top stack frame of where the script parsed event was triggered if available.", "experimental": true } - ], - "description": "Fired when virtual machine fails to parse the script." - }, - { - "name": "breakpointResolved", - "parameters": [ - { "name": "breakpointId", "$ref": "BreakpointId", "description": "Breakpoint unique identifier." }, - { "name": "location", "$ref": "Location", "description": "Actual breakpoint location." } - ], - "description": "Fired when breakpoint is resolved to an actual script and location." - }, - { - "name": "paused", - "parameters": [ - { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "Call stack the virtual machine stopped on." }, - { "name": "reason", "type": "string", "enum": [ "XHR", "DOM", "EventListener", "exception", "assert", "debugCommand", "promiseRejection", "OOM", "other", "ambiguous" ], "description": "Pause reason." }, - { "name": "data", "type": "object", "optional": true, "description": "Object containing break-specific auxiliary properties." }, - { "name": "hitBreakpoints", "type": "array", "optional": true, "items": { "type": "string" }, "description": "Hit breakpoints IDs" }, - { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any." }, - { "name": "asyncStackTraceId", "$ref": "Runtime.StackTraceId", "optional": true, "experimental": true, "description": "Async stack trace, if any." }, - { "name": "asyncCallStackTraceId", "$ref": "Runtime.StackTraceId", "optional": true, "experimental": true, "description": "Just scheduled async call will have this stack trace as parent stack during async execution. This field is available only after Debugger.stepInto call with breakOnAsynCall flag." } - ], - "description": "Fired when the virtual machine stopped on breakpoint or exception or any other stop criteria." - }, - { - "name": "resumed", - "description": "Fired when the virtual machine resumed execution." - } - ] - }, - { - "domain": "Console", - "description": "This domain is deprecated - use Runtime or Log instead.", - "dependencies": ["Runtime"], - "deprecated": true, - "types": [ - { - "id": "ConsoleMessage", - "type": "object", - "description": "Console message.", - "properties": [ - { "name": "source", "type": "string", "enum": ["xml", "javascript", "network", "console-api", "storage", "appcache", "rendering", "security", "other", "deprecation", "worker"], "description": "Message source." }, - { "name": "level", "type": "string", "enum": ["log", "warning", "error", "debug", "info"], "description": "Message severity." }, - { "name": "text", "type": "string", "description": "Message text." }, - { "name": "url", "type": "string", "optional": true, "description": "URL of the message origin." }, - { "name": "line", "type": "integer", "optional": true, "description": "Line number in the resource that generated this message (1-based)." }, - { "name": "column", "type": "integer", "optional": true, "description": "Column number in the resource that generated this message (1-based)." } - ] - } - ], - "commands": [ - { - "name": "enable", - "description": "Enables console domain, sends the messages collected so far to the client by means of the messageAdded notification." - }, - { - "name": "disable", - "description": "Disables console domain, prevents further console messages from being reported to the client." - }, - { - "name": "clearMessages", - "description": "Does nothing." - } - ], - "events": [ - { - "name": "messageAdded", - "parameters": [ - { "name": "message", "$ref": "ConsoleMessage", "description": "Console message that has been added." } - ], - "description": "Issued when new console message is added." - } - ] - }, - { - "domain": "Profiler", - "dependencies": ["Runtime", "Debugger"], - "types": [ - { - "id": "ProfileNode", - "type": "object", - "description": "Profile node. Holds callsite information, execution statistics and child nodes.", - "properties": [ - { "name": "id", "type": "integer", "description": "Unique id of the node." }, - { "name": "callFrame", "$ref": "Runtime.CallFrame", "description": "Function location." }, - { "name": "hitCount", "type": "integer", "optional": true, "description": "Number of samples where this node was on top of the call stack." }, - { "name": "children", "type": "array", "items": { "type": "integer" }, "optional": true, "description": "Child node ids." }, - { "name": "deoptReason", "type": "string", "optional": true, "description": "The reason of being not optimized. The function may be deoptimized or marked as don't optimize."}, - { "name": "positionTicks", "type": "array", "items": { "$ref": "PositionTickInfo" }, "optional": true, "description": "An array of source position ticks." } - ] - }, - { - "id": "Profile", - "type": "object", - "description": "Profile.", - "properties": [ - { "name": "nodes", "type": "array", "items": { "$ref": "ProfileNode" }, "description": "The list of profile nodes. First item is the root node." }, - { "name": "startTime", "type": "number", "description": "Profiling start timestamp in microseconds." }, - { "name": "endTime", "type": "number", "description": "Profiling end timestamp in microseconds." }, - { "name": "samples", "optional": true, "type": "array", "items": { "type": "integer" }, "description": "Ids of samples top nodes." }, - { "name": "timeDeltas", "optional": true, "type": "array", "items": { "type": "integer" }, "description": "Time intervals between adjacent samples in microseconds. The first delta is relative to the profile startTime." } - ] - }, - { - "id": "PositionTickInfo", - "type": "object", - "description": "Specifies a number of samples attributed to a certain source position.", - "properties": [ - { "name": "line", "type": "integer", "description": "Source line number (1-based)." }, - { "name": "ticks", "type": "integer", "description": "Number of samples attributed to the source line." } - ] - }, - { "id": "CoverageRange", - "type": "object", - "description": "Coverage data for a source range.", - "properties": [ - { "name": "startOffset", "type": "integer", "description": "JavaScript script source offset for the range start." }, - { "name": "endOffset", "type": "integer", "description": "JavaScript script source offset for the range end." }, - { "name": "count", "type": "integer", "description": "Collected execution count of the source range." } - ] - }, - { "id": "FunctionCoverage", - "type": "object", - "description": "Coverage data for a JavaScript function.", - "properties": [ - { "name": "functionName", "type": "string", "description": "JavaScript function name." }, - { "name": "ranges", "type": "array", "items": { "$ref": "CoverageRange" }, "description": "Source ranges inside the function with coverage data." }, - { "name": "isBlockCoverage", "type": "boolean", "description": "Whether coverage data for this function has block granularity." } - ] - }, - { - "id": "ScriptCoverage", - "type": "object", - "description": "Coverage data for a JavaScript script.", - "properties": [ - { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "JavaScript script id." }, - { "name": "url", "type": "string", "description": "JavaScript script name or url." }, - { "name": "functions", "type": "array", "items": { "$ref": "FunctionCoverage" }, "description": "Functions contained in the script that has coverage data." } - ] - }, - { "id": "TypeObject", - "type": "object", - "description": "Describes a type collected during runtime.", - "properties": [ - { "name": "name", "type": "string", "description": "Name of a type collected with type profiling." } - ], - "experimental": true - }, - { "id": "TypeProfileEntry", - "type": "object", - "description": "Source offset and types for a parameter or return value.", - "properties": [ - { "name": "offset", "type": "integer", "description": "Source offset of the parameter or end of function for return values." }, - { "name": "types", "type": "array", "items": {"$ref": "TypeObject"}, "description": "The types for this parameter or return value."} - ], - "experimental": true - }, - { - "id": "ScriptTypeProfile", - "type": "object", - "description": "Type profile data collected during runtime for a JavaScript script.", - "properties": [ - { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "JavaScript script id." }, - { "name": "url", "type": "string", "description": "JavaScript script name or url." }, - { "name": "entries", "type": "array", "items": { "$ref": "TypeProfileEntry" }, "description": "Type profile entries for parameters and return values of the functions in the script." } - ], - "experimental": true - } - ], - "commands": [ - { - "name": "enable" - }, - { - "name": "disable" - }, - { - "name": "setSamplingInterval", - "parameters": [ - { "name": "interval", "type": "integer", "description": "New sampling interval in microseconds." } - ], - "description": "Changes CPU profiler sampling interval. Must be called before CPU profiles recording started." - }, - { - "name": "start" - }, - { - "name": "stop", - "returns": [ - { "name": "profile", "$ref": "Profile", "description": "Recorded profile." } - ] - }, - { - "name": "startPreciseCoverage", - "parameters": [ - { "name": "callCount", "type": "boolean", "optional": true, "description": "Collect accurate call counts beyond simple 'covered' or 'not covered'." }, - { "name": "detailed", "type": "boolean", "optional": true, "description": "Collect block-based coverage." } - ], - "description": "Enable precise code coverage. Coverage data for JavaScript executed before enabling precise code coverage may be incomplete. Enabling prevents running optimized code and resets execution counters." - }, - { - "name": "stopPreciseCoverage", - "description": "Disable precise code coverage. Disabling releases unnecessary execution count records and allows executing optimized code." - }, - { - "name": "takePreciseCoverage", - "returns": [ - { "name": "result", "type": "array", "items": { "$ref": "ScriptCoverage" }, "description": "Coverage data for the current isolate." } - ], - "description": "Collect coverage data for the current isolate, and resets execution counters. Precise code coverage needs to have started." - }, - { - "name": "getBestEffortCoverage", - "returns": [ - { "name": "result", "type": "array", "items": { "$ref": "ScriptCoverage" }, "description": "Coverage data for the current isolate." } - ], - "description": "Collect coverage data for the current isolate. The coverage data may be incomplete due to garbage collection." - }, - { - "name": "startTypeProfile", - "description": "Enable type profile.", - "experimental": true - }, - { - "name": "stopTypeProfile", - "description": "Disable type profile. Disabling releases type profile data collected so far.", - "experimental": true - }, - { - "name": "takeTypeProfile", - "returns": [ - { "name": "result", "type": "array", "items": { "$ref": "ScriptTypeProfile" }, "description": "Type profile for all scripts since startTypeProfile() was turned on." } - ], - "description": "Collect type profile.", - "experimental": true - } - ], - "events": [ - { - "name": "consoleProfileStarted", - "parameters": [ - { "name": "id", "type": "string" }, - { "name": "location", "$ref": "Debugger.Location", "description": "Location of console.profile()." }, - { "name": "title", "type": "string", "optional": true, "description": "Profile title passed as an argument to console.profile()." } - ], - "description": "Sent when new profile recording is started using console.profile() call." - }, - { - "name": "consoleProfileFinished", - "parameters": [ - { "name": "id", "type": "string" }, - { "name": "location", "$ref": "Debugger.Location", "description": "Location of console.profileEnd()." }, - { "name": "profile", "$ref": "Profile" }, - { "name": "title", "type": "string", "optional": true, "description": "Profile title passed as an argument to console.profile()." } - ] - } - ] - }, - { - "domain": "HeapProfiler", - "dependencies": ["Runtime"], - "experimental": true, - "types": [ - { - "id": "HeapSnapshotObjectId", - "type": "string", - "description": "Heap snapshot object id." - }, - { - "id": "SamplingHeapProfileNode", - "type": "object", - "description": "Sampling Heap Profile node. Holds callsite information, allocation statistics and child nodes.", - "properties": [ - { "name": "callFrame", "$ref": "Runtime.CallFrame", "description": "Function location." }, - { "name": "selfSize", "type": "number", "description": "Allocations size in bytes for the node excluding children." }, - { "name": "children", "type": "array", "items": { "$ref": "SamplingHeapProfileNode" }, "description": "Child nodes." } - ] - }, - { - "id": "SamplingHeapProfile", - "type": "object", - "description": "Profile.", - "properties": [ - { "name": "head", "$ref": "SamplingHeapProfileNode" } - ] - } - ], - "commands": [ - { - "name": "enable" - }, - { - "name": "disable" - }, - { - "name": "startTrackingHeapObjects", - "parameters": [ - { "name": "trackAllocations", "type": "boolean", "optional": true } - ] - }, - { - "name": "stopTrackingHeapObjects", - "parameters": [ - { "name": "reportProgress", "type": "boolean", "optional": true, "description": "If true 'reportHeapSnapshotProgress' events will be generated while snapshot is being taken when the tracking is stopped." } - ] - }, - { - "name": "takeHeapSnapshot", - "parameters": [ - { "name": "reportProgress", "type": "boolean", "optional": true, "description": "If true 'reportHeapSnapshotProgress' events will be generated while snapshot is being taken." } - ] - }, - { - "name": "collectGarbage" - }, - { - "name": "getObjectByHeapObjectId", - "parameters": [ - { "name": "objectId", "$ref": "HeapSnapshotObjectId" }, - { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." } - ], - "returns": [ - { "name": "result", "$ref": "Runtime.RemoteObject", "description": "Evaluation result." } - ] - }, - { - "name": "addInspectedHeapObject", - "parameters": [ - { "name": "heapObjectId", "$ref": "HeapSnapshotObjectId", "description": "Heap snapshot object id to be accessible by means of $x command line API." } - ], - "description": "Enables console to refer to the node with given id via $x (see Command Line API for more details $x functions)." - }, - { - "name": "getHeapObjectId", - "parameters": [ - { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "description": "Identifier of the object to get heap object id for." } - ], - "returns": [ - { "name": "heapSnapshotObjectId", "$ref": "HeapSnapshotObjectId", "description": "Id of the heap snapshot object corresponding to the passed remote object id." } - ] - }, - { - "name": "startSampling", - "parameters": [ - { "name": "samplingInterval", "type": "number", "optional": true, "description": "Average sample interval in bytes. Poisson distribution is used for the intervals. The default value is 32768 bytes." } - ] - }, - { - "name": "stopSampling", - "returns": [ - { "name": "profile", "$ref": "SamplingHeapProfile", "description": "Recorded sampling heap profile." } - ] - }, - { - "name": "getSamplingProfile", - "returns": [ - { "name": "profile", "$ref": "SamplingHeapProfile", "description": "Return the sampling profile being collected." } - ] - } - ], - "events": [ - { - "name": "addHeapSnapshotChunk", - "parameters": [ - { "name": "chunk", "type": "string" } - ] - }, - { - "name": "resetProfiles" - }, - { - "name": "reportHeapSnapshotProgress", - "parameters": [ - { "name": "done", "type": "integer" }, - { "name": "total", "type": "integer" }, - { "name": "finished", "type": "boolean", "optional": true } - ] - }, - { - "name": "lastSeenObjectId", - "description": "If heap objects tracking has been started then backend regularly sends a current value for last seen object id and corresponding timestamp. If the were changes in the heap since last event then one or more heapStatsUpdate events will be sent before a new lastSeenObjectId event.", - "parameters": [ - { "name": "lastSeenObjectId", "type": "integer" }, - { "name": "timestamp", "type": "number" } - ] - }, - { - "name": "heapStatsUpdate", - "description": "If heap objects tracking has been started then backend may send update for one or more fragments", - "parameters": [ - { "name": "statsUpdate", "type": "array", "items": { "type": "integer" }, "description": "An array of triplets. Each triplet describes a fragment. The first integer is the fragment index, the second integer is a total count of objects for the fragment, the third integer is a total size of the objects for the fragment."} - ] - } - ] - }] -} diff --git a/NativeScript/include/js_protocol.pdl b/NativeScript/include/js_protocol.pdl deleted file mode 100644 index bd277eb0..00000000 --- a/NativeScript/include/js_protocol.pdl +++ /dev/null @@ -1,1709 +0,0 @@ -# Copyright 2017 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -version - major 1 - minor 3 - -# This domain is deprecated - use Runtime or Log instead. -deprecated domain Console - depends on Runtime - - # Console message. - type ConsoleMessage extends object - properties - # Message source. - enum source - xml - javascript - network - console-api - storage - appcache - rendering - security - other - deprecation - worker - # Message severity. - enum level - log - warning - error - debug - info - # Message text. - string text - # URL of the message origin. - optional string url - # Line number in the resource that generated this message (1-based). - optional integer line - # Column number in the resource that generated this message (1-based). - optional integer column - - # Does nothing. - command clearMessages - - # Disables console domain, prevents further console messages from being reported to the client. - command disable - - # Enables console domain, sends the messages collected so far to the client by means of the - # `messageAdded` notification. - command enable - - # Issued when new console message is added. - event messageAdded - parameters - # Console message that has been added. - ConsoleMessage message - -# Debugger domain exposes JavaScript debugging capabilities. It allows setting and removing -# breakpoints, stepping through execution, exploring stack traces, etc. -domain Debugger - depends on Runtime - - # Breakpoint identifier. - type BreakpointId extends string - - # Call frame identifier. - type CallFrameId extends string - - # Location in the source code. - type Location extends object - properties - # Script identifier as reported in the `Debugger.scriptParsed`. - Runtime.ScriptId scriptId - # Line number in the script (0-based). - integer lineNumber - # Column number in the script (0-based). - optional integer columnNumber - - # Location in the source code. - experimental type ScriptPosition extends object - properties - integer lineNumber - integer columnNumber - - # Location range within one script. - experimental type LocationRange extends object - properties - Runtime.ScriptId scriptId - ScriptPosition start - ScriptPosition end - - # JavaScript call frame. Array of call frames form the call stack. - type CallFrame extends object - properties - # Call frame identifier. This identifier is only valid while the virtual machine is paused. - CallFrameId callFrameId - # Name of the JavaScript function called on this call frame. - string functionName - # Location in the source code. - optional Location functionLocation - # Location in the source code. - Location location - # JavaScript script name or url. - # Deprecated in favor of using the `location.scriptId` to resolve the URL via a previously - # sent `Debugger.scriptParsed` event. - deprecated string url - # Scope chain for this call frame. - array of Scope scopeChain - # `this` object for this call frame. - Runtime.RemoteObject this - # The value being returned, if the function is at return point. - optional Runtime.RemoteObject returnValue - # Valid only while the VM is paused and indicates whether this frame - # can be restarted or not. Note that a `true` value here does not - # guarantee that Debugger#restartFrame with this CallFrameId will be - # successful, but it is very likely. - experimental optional boolean canBeRestarted - - # Scope description. - type Scope extends object - properties - # Scope type. - enum type - global - local - with - closure - catch - block - script - eval - module - wasm-expression-stack - # Object representing the scope. For `global` and `with` scopes it represents the actual - # object; for the rest of the scopes, it is artificial transient object enumerating scope - # variables as its properties. - Runtime.RemoteObject object - optional string name - # Location in the source code where scope starts - optional Location startLocation - # Location in the source code where scope ends - optional Location endLocation - - # Search match for resource. - type SearchMatch extends object - properties - # Line number in resource content. - number lineNumber - # Line with match content. - string lineContent - - type BreakLocation extends object - properties - # Script identifier as reported in the `Debugger.scriptParsed`. - Runtime.ScriptId scriptId - # Line number in the script (0-based). - integer lineNumber - # Column number in the script (0-based). - optional integer columnNumber - optional enum type - debuggerStatement - call - return - - # Continues execution until specific location is reached. - command continueToLocation - parameters - # Location to continue to. - Location location - optional enum targetCallFrames - any - current - - # Disables debugger for given page. - command disable - - # Enables debugger for the given page. Clients should not assume that the debugging has been - # enabled until the result for this command is received. - command enable - parameters - # The maximum size in bytes of collected scripts (not referenced by other heap objects) - # the debugger can hold. Puts no limit if parameter is omitted. - experimental optional number maxScriptsCacheSize - returns - # Unique identifier of the debugger. - experimental Runtime.UniqueDebuggerId debuggerId - - # Evaluates expression on a given call frame. - command evaluateOnCallFrame - parameters - # Call frame identifier to evaluate on. - CallFrameId callFrameId - # Expression to evaluate. - string expression - # String object group name to put result into (allows rapid releasing resulting object handles - # using `releaseObjectGroup`). - optional string objectGroup - # Specifies whether command line API should be available to the evaluated expression, defaults - # to false. - optional boolean includeCommandLineAPI - # In silent mode exceptions thrown during evaluation are not reported and do not pause - # execution. Overrides `setPauseOnException` state. - optional boolean silent - # Whether the result is expected to be a JSON object that should be sent by value. - optional boolean returnByValue - # Whether preview should be generated for the result. - experimental optional boolean generatePreview - # Whether to throw an exception if side effect cannot be ruled out during evaluation. - optional boolean throwOnSideEffect - # Terminate execution after timing out (number of milliseconds). - experimental optional Runtime.TimeDelta timeout - returns - # Object wrapper for the evaluation result. - Runtime.RemoteObject result - # Exception details. - optional Runtime.ExceptionDetails exceptionDetails - - # Returns possible locations for breakpoint. scriptId in start and end range locations should be - # the same. - command getPossibleBreakpoints - parameters - # Start of range to search possible breakpoint locations in. - Location start - # End of range to search possible breakpoint locations in (excluding). When not specified, end - # of scripts is used as end of range. - optional Location end - # Only consider locations which are in the same (non-nested) function as start. - optional boolean restrictToFunction - returns - # List of the possible breakpoint locations. - array of BreakLocation locations - - # Returns source for the script with given id. - command getScriptSource - parameters - # Id of the script to get source for. - Runtime.ScriptId scriptId - returns - # Script source (empty in case of Wasm bytecode). - string scriptSource - # Wasm bytecode. - optional binary bytecode - - # This command is deprecated. Use getScriptSource instead. - deprecated command getWasmBytecode - parameters - # Id of the Wasm script to get source for. - Runtime.ScriptId scriptId - returns - # Script source. - binary bytecode - - # Returns stack trace with given `stackTraceId`. - experimental command getStackTrace - parameters - Runtime.StackTraceId stackTraceId - returns - Runtime.StackTrace stackTrace - - # Stops on the next JavaScript statement. - command pause - - experimental deprecated command pauseOnAsyncCall - parameters - # Debugger will pause when async call with given stack trace is started. - Runtime.StackTraceId parentStackTraceId - - # Removes JavaScript breakpoint. - command removeBreakpoint - parameters - BreakpointId breakpointId - - # Restarts particular call frame from the beginning. - deprecated command restartFrame - parameters - # Call frame identifier to evaluate on. - CallFrameId callFrameId - returns - # New stack trace. - array of CallFrame callFrames - # Async stack trace, if any. - optional Runtime.StackTrace asyncStackTrace - # Async stack trace, if any. - experimental optional Runtime.StackTraceId asyncStackTraceId - - # Resumes JavaScript execution. - command resume - parameters - # Set to true to terminate execution upon resuming execution. In contrast - # to Runtime.terminateExecution, this will allows to execute further - # JavaScript (i.e. via evaluation) until execution of the paused code - # is actually resumed, at which point termination is triggered. - # If execution is currently not paused, this parameter has no effect. - optional boolean terminateOnResume - - # Searches for given string in script content. - command searchInContent - parameters - # Id of the script to search in. - Runtime.ScriptId scriptId - # String to search for. - string query - # If true, search is case sensitive. - optional boolean caseSensitive - # If true, treats string parameter as regex. - optional boolean isRegex - returns - # List of search matches. - array of SearchMatch result - - # Enables or disables async call stacks tracking. - command setAsyncCallStackDepth - parameters - # Maximum depth of async call stacks. Setting to `0` will effectively disable collecting async - # call stacks (default). - integer maxDepth - - # Replace previous blackbox patterns with passed ones. Forces backend to skip stepping/pausing in - # scripts with url matching one of the patterns. VM will try to leave blackboxed script by - # performing 'step in' several times, finally resorting to 'step out' if unsuccessful. - experimental command setBlackboxPatterns - parameters - # Array of regexps that will be used to check script url for blackbox state. - array of string patterns - - # Makes backend skip steps in the script in blackboxed ranges. VM will try leave blacklisted - # scripts by performing 'step in' several times, finally resorting to 'step out' if unsuccessful. - # Positions array contains positions where blackbox state is changed. First interval isn't - # blackboxed. Array should be sorted. - experimental command setBlackboxedRanges - parameters - # Id of the script. - Runtime.ScriptId scriptId - array of ScriptPosition positions - - # Sets JavaScript breakpoint at a given location. - command setBreakpoint - parameters - # Location to set breakpoint in. - Location location - # Expression to use as a breakpoint condition. When specified, debugger will only stop on the - # breakpoint if this expression evaluates to true. - optional string condition - returns - # Id of the created breakpoint for further reference. - BreakpointId breakpointId - # Location this breakpoint resolved into. - Location actualLocation - - # Sets instrumentation breakpoint. - command setInstrumentationBreakpoint - parameters - # Instrumentation name. - enum instrumentation - beforeScriptExecution - beforeScriptWithSourceMapExecution - returns - # Id of the created breakpoint for further reference. - BreakpointId breakpointId - - # Sets JavaScript breakpoint at given location specified either by URL or URL regex. Once this - # command is issued, all existing parsed scripts will have breakpoints resolved and returned in - # `locations` property. Further matching script parsing will result in subsequent - # `breakpointResolved` events issued. This logical breakpoint will survive page reloads. - command setBreakpointByUrl - parameters - # Line number to set breakpoint at. - integer lineNumber - # URL of the resources to set breakpoint on. - optional string url - # Regex pattern for the URLs of the resources to set breakpoints on. Either `url` or - # `urlRegex` must be specified. - optional string urlRegex - # Script hash of the resources to set breakpoint on. - optional string scriptHash - # Offset in the line to set breakpoint at. - optional integer columnNumber - # Expression to use as a breakpoint condition. When specified, debugger will only stop on the - # breakpoint if this expression evaluates to true. - optional string condition - returns - # Id of the created breakpoint for further reference. - BreakpointId breakpointId - # List of the locations this breakpoint resolved into upon addition. - array of Location locations - - # Sets JavaScript breakpoint before each call to the given function. - # If another function was created from the same source as a given one, - # calling it will also trigger the breakpoint. - experimental command setBreakpointOnFunctionCall - parameters - # Function object id. - Runtime.RemoteObjectId objectId - # Expression to use as a breakpoint condition. When specified, debugger will - # stop on the breakpoint if this expression evaluates to true. - optional string condition - returns - # Id of the created breakpoint for further reference. - BreakpointId breakpointId - - # Activates / deactivates all breakpoints on the page. - command setBreakpointsActive - parameters - # New value for breakpoints active state. - boolean active - - # Defines pause on exceptions state. Can be set to stop on all exceptions, uncaught exceptions or - # no exceptions. Initial pause on exceptions state is `none`. - command setPauseOnExceptions - parameters - # Pause on exceptions mode. - enum state - none - uncaught - all - - # Changes return value in top frame. Available only at return break position. - experimental command setReturnValue - parameters - # New return value. - Runtime.CallArgument newValue - - # Edits JavaScript source live. - command setScriptSource - parameters - # Id of the script to edit. - Runtime.ScriptId scriptId - # New content of the script. - string scriptSource - # If true the change will not actually be applied. Dry run may be used to get result - # description without actually modifying the code. - optional boolean dryRun - returns - # New stack trace in case editing has happened while VM was stopped. - optional array of CallFrame callFrames - # Whether current call stack was modified after applying the changes. - optional boolean stackChanged - # Async stack trace, if any. - optional Runtime.StackTrace asyncStackTrace - # Async stack trace, if any. - experimental optional Runtime.StackTraceId asyncStackTraceId - # Exception details if any. - optional Runtime.ExceptionDetails exceptionDetails - - # Makes page not interrupt on any pauses (breakpoint, exception, dom exception etc). - command setSkipAllPauses - parameters - # New value for skip pauses state. - boolean skip - - # Changes value of variable in a callframe. Object-based scopes are not supported and must be - # mutated manually. - command setVariableValue - parameters - # 0-based number of scope as was listed in scope chain. Only 'local', 'closure' and 'catch' - # scope types are allowed. Other scopes could be manipulated manually. - integer scopeNumber - # Variable name. - string variableName - # New variable value. - Runtime.CallArgument newValue - # Id of callframe that holds variable. - CallFrameId callFrameId - - # Steps into the function call. - command stepInto - parameters - # Debugger will pause on the execution of the first async task which was scheduled - # before next pause. - experimental optional boolean breakOnAsyncCall - # The skipList specifies location ranges that should be skipped on step into. - experimental optional array of LocationRange skipList - - # Steps out of the function call. - command stepOut - - # Steps over the statement. - command stepOver - parameters - # The skipList specifies location ranges that should be skipped on step over. - experimental optional array of LocationRange skipList - - # Fired when breakpoint is resolved to an actual script and location. - event breakpointResolved - parameters - # Breakpoint unique identifier. - BreakpointId breakpointId - # Actual breakpoint location. - Location location - - # Fired when the virtual machine stopped on breakpoint or exception or any other stop criteria. - event paused - parameters - # Call stack the virtual machine stopped on. - array of CallFrame callFrames - # Pause reason. - enum reason - ambiguous - assert - CSPViolation - debugCommand - DOM - EventListener - exception - instrumentation - OOM - other - promiseRejection - XHR - # Object containing break-specific auxiliary properties. - optional object data - # Hit breakpoints IDs - optional array of string hitBreakpoints - # Async stack trace, if any. - optional Runtime.StackTrace asyncStackTrace - # Async stack trace, if any. - experimental optional Runtime.StackTraceId asyncStackTraceId - # Never present, will be removed. - experimental deprecated optional Runtime.StackTraceId asyncCallStackTraceId - - # Fired when the virtual machine resumed execution. - event resumed - - # Enum of possible script languages. - type ScriptLanguage extends string - enum - JavaScript - WebAssembly - - # Debug symbols available for a wasm script. - type DebugSymbols extends object - properties - # Type of the debug symbols. - enum type - None - SourceMap - EmbeddedDWARF - ExternalDWARF - # URL of the external symbol source. - optional string externalURL - - # Fired when virtual machine fails to parse the script. - event scriptFailedToParse - parameters - # Identifier of the script parsed. - Runtime.ScriptId scriptId - # URL or name of the script parsed (if any). - string url - # Line offset of the script within the resource with given URL (for script tags). - integer startLine - # Column offset of the script within the resource with given URL. - integer startColumn - # Last line of the script. - integer endLine - # Length of the last line of the script. - integer endColumn - # Specifies script creation context. - Runtime.ExecutionContextId executionContextId - # Content hash of the script. - string hash - # Embedder-specific auxiliary data. - optional object executionContextAuxData - # URL of source map associated with script (if any). - optional string sourceMapURL - # True, if this script has sourceURL. - optional boolean hasSourceURL - # True, if this script is ES6 module. - optional boolean isModule - # This script length. - optional integer length - # JavaScript top stack frame of where the script parsed event was triggered if available. - experimental optional Runtime.StackTrace stackTrace - # If the scriptLanguage is WebAssembly, the code section offset in the module. - experimental optional integer codeOffset - # The language of the script. - experimental optional Debugger.ScriptLanguage scriptLanguage - # The name the embedder supplied for this script. - experimental optional string embedderName - - # Fired when virtual machine parses script. This event is also fired for all known and uncollected - # scripts upon enabling debugger. - event scriptParsed - parameters - # Identifier of the script parsed. - Runtime.ScriptId scriptId - # URL or name of the script parsed (if any). - string url - # Line offset of the script within the resource with given URL (for script tags). - integer startLine - # Column offset of the script within the resource with given URL. - integer startColumn - # Last line of the script. - integer endLine - # Length of the last line of the script. - integer endColumn - # Specifies script creation context. - Runtime.ExecutionContextId executionContextId - # Content hash of the script. - string hash - # Embedder-specific auxiliary data. - optional object executionContextAuxData - # True, if this script is generated as a result of the live edit operation. - experimental optional boolean isLiveEdit - # URL of source map associated with script (if any). - optional string sourceMapURL - # True, if this script has sourceURL. - optional boolean hasSourceURL - # True, if this script is ES6 module. - optional boolean isModule - # This script length. - optional integer length - # JavaScript top stack frame of where the script parsed event was triggered if available. - experimental optional Runtime.StackTrace stackTrace - # If the scriptLanguage is WebAssembly, the code section offset in the module. - experimental optional integer codeOffset - # The language of the script. - experimental optional Debugger.ScriptLanguage scriptLanguage - # If the scriptLanguage is WebASsembly, the source of debug symbols for the module. - experimental optional Debugger.DebugSymbols debugSymbols - # The name the embedder supplied for this script. - experimental optional string embedderName - -experimental domain HeapProfiler - depends on Runtime - - # Heap snapshot object id. - type HeapSnapshotObjectId extends string - - # Sampling Heap Profile node. Holds callsite information, allocation statistics and child nodes. - type SamplingHeapProfileNode extends object - properties - # Function location. - Runtime.CallFrame callFrame - # Allocations size in bytes for the node excluding children. - number selfSize - # Node id. Ids are unique across all profiles collected between startSampling and stopSampling. - integer id - # Child nodes. - array of SamplingHeapProfileNode children - - # A single sample from a sampling profile. - type SamplingHeapProfileSample extends object - properties - # Allocation size in bytes attributed to the sample. - number size - # Id of the corresponding profile tree node. - integer nodeId - # Time-ordered sample ordinal number. It is unique across all profiles retrieved - # between startSampling and stopSampling. - number ordinal - - # Sampling profile. - type SamplingHeapProfile extends object - properties - SamplingHeapProfileNode head - array of SamplingHeapProfileSample samples - - # Enables console to refer to the node with given id via $x (see Command Line API for more details - # $x functions). - command addInspectedHeapObject - parameters - # Heap snapshot object id to be accessible by means of $x command line API. - HeapSnapshotObjectId heapObjectId - - command collectGarbage - - command disable - - command enable - - command getHeapObjectId - parameters - # Identifier of the object to get heap object id for. - Runtime.RemoteObjectId objectId - returns - # Id of the heap snapshot object corresponding to the passed remote object id. - HeapSnapshotObjectId heapSnapshotObjectId - - command getObjectByHeapObjectId - parameters - HeapSnapshotObjectId objectId - # Symbolic group name that can be used to release multiple objects. - optional string objectGroup - returns - # Evaluation result. - Runtime.RemoteObject result - - command getSamplingProfile - returns - # Return the sampling profile being collected. - SamplingHeapProfile profile - - command startSampling - parameters - # Average sample interval in bytes. Poisson distribution is used for the intervals. The - # default value is 32768 bytes. - optional number samplingInterval - - command startTrackingHeapObjects - parameters - optional boolean trackAllocations - - command stopSampling - returns - # Recorded sampling heap profile. - SamplingHeapProfile profile - - command stopTrackingHeapObjects - parameters - # If true 'reportHeapSnapshotProgress' events will be generated while snapshot is being taken - # when the tracking is stopped. - optional boolean reportProgress - optional boolean treatGlobalObjectsAsRoots - # If true, numerical values are included in the snapshot - optional boolean captureNumericValue - - command takeHeapSnapshot - parameters - # If true 'reportHeapSnapshotProgress' events will be generated while snapshot is being taken. - optional boolean reportProgress - # If true, a raw snapshot without artificial roots will be generated - optional boolean treatGlobalObjectsAsRoots - # If true, numerical values are included in the snapshot - optional boolean captureNumericValue - - event addHeapSnapshotChunk - parameters - string chunk - - # If heap objects tracking has been started then backend may send update for one or more fragments - event heapStatsUpdate - parameters - # An array of triplets. Each triplet describes a fragment. The first integer is the fragment - # index, the second integer is a total count of objects for the fragment, the third integer is - # a total size of the objects for the fragment. - array of integer statsUpdate - - # If heap objects tracking has been started then backend regularly sends a current value for last - # seen object id and corresponding timestamp. If the were changes in the heap since last event - # then one or more heapStatsUpdate events will be sent before a new lastSeenObjectId event. - event lastSeenObjectId - parameters - integer lastSeenObjectId - number timestamp - - event reportHeapSnapshotProgress - parameters - integer done - integer total - optional boolean finished - - event resetProfiles - -domain Profiler - depends on Runtime - depends on Debugger - - # Profile node. Holds callsite information, execution statistics and child nodes. - type ProfileNode extends object - properties - # Unique id of the node. - integer id - # Function location. - Runtime.CallFrame callFrame - # Number of samples where this node was on top of the call stack. - optional integer hitCount - # Child node ids. - optional array of integer children - # The reason of being not optimized. The function may be deoptimized or marked as don't - # optimize. - optional string deoptReason - # An array of source position ticks. - optional array of PositionTickInfo positionTicks - - # Profile. - type Profile extends object - properties - # The list of profile nodes. First item is the root node. - array of ProfileNode nodes - # Profiling start timestamp in microseconds. - number startTime - # Profiling end timestamp in microseconds. - number endTime - # Ids of samples top nodes. - optional array of integer samples - # Time intervals between adjacent samples in microseconds. The first delta is relative to the - # profile startTime. - optional array of integer timeDeltas - - # Specifies a number of samples attributed to a certain source position. - type PositionTickInfo extends object - properties - # Source line number (1-based). - integer line - # Number of samples attributed to the source line. - integer ticks - - # Coverage data for a source range. - type CoverageRange extends object - properties - # JavaScript script source offset for the range start. - integer startOffset - # JavaScript script source offset for the range end. - integer endOffset - # Collected execution count of the source range. - integer count - - # Coverage data for a JavaScript function. - type FunctionCoverage extends object - properties - # JavaScript function name. - string functionName - # Source ranges inside the function with coverage data. - array of CoverageRange ranges - # Whether coverage data for this function has block granularity. - boolean isBlockCoverage - - # Coverage data for a JavaScript script. - type ScriptCoverage extends object - properties - # JavaScript script id. - Runtime.ScriptId scriptId - # JavaScript script name or url. - string url - # Functions contained in the script that has coverage data. - array of FunctionCoverage functions - - # Describes a type collected during runtime. - experimental type TypeObject extends object - properties - # Name of a type collected with type profiling. - string name - - # Source offset and types for a parameter or return value. - experimental type TypeProfileEntry extends object - properties - # Source offset of the parameter or end of function for return values. - integer offset - # The types for this parameter or return value. - array of TypeObject types - - # Type profile data collected during runtime for a JavaScript script. - experimental type ScriptTypeProfile extends object - properties - # JavaScript script id. - Runtime.ScriptId scriptId - # JavaScript script name or url. - string url - # Type profile entries for parameters and return values of the functions in the script. - array of TypeProfileEntry entries - - command disable - - command enable - - # Collect coverage data for the current isolate. The coverage data may be incomplete due to - # garbage collection. - command getBestEffortCoverage - returns - # Coverage data for the current isolate. - array of ScriptCoverage result - - # Changes CPU profiler sampling interval. Must be called before CPU profiles recording started. - command setSamplingInterval - parameters - # New sampling interval in microseconds. - integer interval - - command start - - # Enable precise code coverage. Coverage data for JavaScript executed before enabling precise code - # coverage may be incomplete. Enabling prevents running optimized code and resets execution - # counters. - command startPreciseCoverage - parameters - # Collect accurate call counts beyond simple 'covered' or 'not covered'. - optional boolean callCount - # Collect block-based coverage. - optional boolean detailed - # Allow the backend to send updates on its own initiative - optional boolean allowTriggeredUpdates - returns - # Monotonically increasing time (in seconds) when the coverage update was taken in the backend. - number timestamp - - # Enable type profile. - experimental command startTypeProfile - - command stop - returns - # Recorded profile. - Profile profile - - # Disable precise code coverage. Disabling releases unnecessary execution count records and allows - # executing optimized code. - command stopPreciseCoverage - - # Disable type profile. Disabling releases type profile data collected so far. - experimental command stopTypeProfile - - # Collect coverage data for the current isolate, and resets execution counters. Precise code - # coverage needs to have started. - command takePreciseCoverage - returns - # Coverage data for the current isolate. - array of ScriptCoverage result - # Monotonically increasing time (in seconds) when the coverage update was taken in the backend. - number timestamp - - # Collect type profile. - experimental command takeTypeProfile - returns - # Type profile for all scripts since startTypeProfile() was turned on. - array of ScriptTypeProfile result - - event consoleProfileFinished - parameters - string id - # Location of console.profileEnd(). - Debugger.Location location - Profile profile - # Profile title passed as an argument to console.profile(). - optional string title - - # Sent when new profile recording is started using console.profile() call. - event consoleProfileStarted - parameters - string id - # Location of console.profile(). - Debugger.Location location - # Profile title passed as an argument to console.profile(). - optional string title - - # Reports coverage delta since the last poll (either from an event like this, or from - # `takePreciseCoverage` for the current isolate. May only be sent if precise code - # coverage has been started. This event can be trigged by the embedder to, for example, - # trigger collection of coverage data immediately at a certain point in time. - experimental event preciseCoverageDeltaUpdate - parameters - # Monotonically increasing time (in seconds) when the coverage update was taken in the backend. - number timestamp - # Identifier for distinguishing coverage events. - string occasion - # Coverage data for the current isolate. - array of ScriptCoverage result - -# Runtime domain exposes JavaScript runtime by means of remote evaluation and mirror objects. -# Evaluation results are returned as mirror object that expose object type, string representation -# and unique identifier that can be used for further object reference. Original objects are -# maintained in memory unless they are either explicitly released or are released along with the -# other objects in their object group. -domain Runtime - - # Unique script identifier. - type ScriptId extends string - - # Represents the value serialiazed by the WebDriver BiDi specification - # https://w3c.github.io/webdriver-bidi. - type WebDriverValue extends object - properties - enum type - undefined - null - string - number - boolean - bigint - regexp - date - symbol - array - object - function - map - set - weakmap - weakset - error - proxy - promise - typedarray - arraybuffer - node - window - optional any value - optional string objectId - - # Unique object identifier. - type RemoteObjectId extends string - - # Primitive value which cannot be JSON-stringified. Includes values `-0`, `NaN`, `Infinity`, - # `-Infinity`, and bigint literals. - type UnserializableValue extends string - - # Mirror object referencing original JavaScript object. - type RemoteObject extends object - properties - # Object type. - enum type - object - function - undefined - string - number - boolean - symbol - bigint - # Object subtype hint. Specified for `object` type values only. - # NOTE: If you change anything here, make sure to also update - # `subtype` in `ObjectPreview` and `PropertyPreview` below. - optional enum subtype - array - null - node - regexp - date - map - set - weakmap - weakset - iterator - generator - error - proxy - promise - typedarray - arraybuffer - dataview - webassemblymemory - wasmvalue - # Object class (constructor) name. Specified for `object` type values only. - optional string className - # Remote object value in case of primitive values or JSON values (if it was requested). - optional any value - # Primitive value which can not be JSON-stringified does not have `value`, but gets this - # property. - optional UnserializableValue unserializableValue - # String representation of the object. - optional string description - # WebDriver BiDi representation of the value. - experimental optional WebDriverValue webDriverValue - # Unique object identifier (for non-primitive values). - optional RemoteObjectId objectId - # Preview containing abbreviated property values. Specified for `object` type values only. - experimental optional ObjectPreview preview - experimental optional CustomPreview customPreview - - experimental type CustomPreview extends object - properties - # The JSON-stringified result of formatter.header(object, config) call. - # It contains json ML array that represents RemoteObject. - string header - # If formatter returns true as a result of formatter.hasBody call then bodyGetterId will - # contain RemoteObjectId for the function that returns result of formatter.body(object, config) call. - # The result value is json ML array. - optional RemoteObjectId bodyGetterId - - # Object containing abbreviated remote object value. - experimental type ObjectPreview extends object - properties - # Object type. - enum type - object - function - undefined - string - number - boolean - symbol - bigint - # Object subtype hint. Specified for `object` type values only. - optional enum subtype - array - null - node - regexp - date - map - set - weakmap - weakset - iterator - generator - error - proxy - promise - typedarray - arraybuffer - dataview - webassemblymemory - wasmvalue - # String representation of the object. - optional string description - # True iff some of the properties or entries of the original object did not fit. - boolean overflow - # List of the properties. - array of PropertyPreview properties - # List of the entries. Specified for `map` and `set` subtype values only. - optional array of EntryPreview entries - - experimental type PropertyPreview extends object - properties - # Property name. - string name - # Object type. Accessor means that the property itself is an accessor property. - enum type - object - function - undefined - string - number - boolean - symbol - accessor - bigint - # User-friendly property value string. - optional string value - # Nested value preview. - optional ObjectPreview valuePreview - # Object subtype hint. Specified for `object` type values only. - optional enum subtype - array - null - node - regexp - date - map - set - weakmap - weakset - iterator - generator - error - proxy - promise - typedarray - arraybuffer - dataview - webassemblymemory - wasmvalue - - experimental type EntryPreview extends object - properties - # Preview of the key. Specified for map-like collection entries. - optional ObjectPreview key - # Preview of the value. - ObjectPreview value - - # Object property descriptor. - type PropertyDescriptor extends object - properties - # Property name or symbol description. - string name - # The value associated with the property. - optional RemoteObject value - # True if the value associated with the property may be changed (data descriptors only). - optional boolean writable - # A function which serves as a getter for the property, or `undefined` if there is no getter - # (accessor descriptors only). - optional RemoteObject get - # A function which serves as a setter for the property, or `undefined` if there is no setter - # (accessor descriptors only). - optional RemoteObject set - # True if the type of this property descriptor may be changed and if the property may be - # deleted from the corresponding object. - boolean configurable - # True if this property shows up during enumeration of the properties on the corresponding - # object. - boolean enumerable - # True if the result was thrown during the evaluation. - optional boolean wasThrown - # True if the property is owned for the object. - optional boolean isOwn - # Property symbol object, if the property is of the `symbol` type. - optional RemoteObject symbol - - # Object internal property descriptor. This property isn't normally visible in JavaScript code. - type InternalPropertyDescriptor extends object - properties - # Conventional property name. - string name - # The value associated with the property. - optional RemoteObject value - - # Object private field descriptor. - experimental type PrivatePropertyDescriptor extends object - properties - # Private property name. - string name - # The value associated with the private property. - optional RemoteObject value - # A function which serves as a getter for the private property, - # or `undefined` if there is no getter (accessor descriptors only). - optional RemoteObject get - # A function which serves as a setter for the private property, - # or `undefined` if there is no setter (accessor descriptors only). - optional RemoteObject set - - # Represents function call argument. Either remote object id `objectId`, primitive `value`, - # unserializable primitive value or neither of (for undefined) them should be specified. - type CallArgument extends object - properties - # Primitive value or serializable javascript object. - optional any value - # Primitive value which can not be JSON-stringified. - optional UnserializableValue unserializableValue - # Remote object handle. - optional RemoteObjectId objectId - - # Id of an execution context. - type ExecutionContextId extends integer - - # Description of an isolated world. - type ExecutionContextDescription extends object - properties - # Unique id of the execution context. It can be used to specify in which execution context - # script evaluation should be performed. - ExecutionContextId id - # Execution context origin. - string origin - # Human readable name describing given context. - string name - # A system-unique execution context identifier. Unlike the id, this is unique across - # multiple processes, so can be reliably used to identify specific context while backend - # performs a cross-process navigation. - experimental string uniqueId - # Embedder-specific auxiliary data. - optional object auxData - - # Detailed information about exception (or error) that was thrown during script compilation or - # execution. - type ExceptionDetails extends object - properties - # Exception id. - integer exceptionId - # Exception text, which should be used together with exception object when available. - string text - # Line number of the exception location (0-based). - integer lineNumber - # Column number of the exception location (0-based). - integer columnNumber - # Script ID of the exception location. - optional ScriptId scriptId - # URL of the exception location, to be used when the script was not reported. - optional string url - # JavaScript stack trace if available. - optional StackTrace stackTrace - # Exception object if available. - optional RemoteObject exception - # Identifier of the context where exception happened. - optional ExecutionContextId executionContextId - # Dictionary with entries of meta data that the client associated - # with this exception, such as information about associated network - # requests, etc. - experimental optional object exceptionMetaData - - # Number of milliseconds since epoch. - type Timestamp extends number - - # Number of milliseconds. - type TimeDelta extends number - - # Stack entry for runtime errors and assertions. - type CallFrame extends object - properties - # JavaScript function name. - string functionName - # JavaScript script id. - ScriptId scriptId - # JavaScript script name or url. - string url - # JavaScript script line number (0-based). - integer lineNumber - # JavaScript script column number (0-based). - integer columnNumber - - # Call frames for assertions or error messages. - type StackTrace extends object - properties - # String label of this stack trace. For async traces this may be a name of the function that - # initiated the async call. - optional string description - # JavaScript function name. - array of CallFrame callFrames - # Asynchronous JavaScript stack trace that preceded this stack, if available. - optional StackTrace parent - # Asynchronous JavaScript stack trace that preceded this stack, if available. - experimental optional StackTraceId parentId - - # Unique identifier of current debugger. - experimental type UniqueDebuggerId extends string - - # If `debuggerId` is set stack trace comes from another debugger and can be resolved there. This - # allows to track cross-debugger calls. See `Runtime.StackTrace` and `Debugger.paused` for usages. - experimental type StackTraceId extends object - properties - string id - optional UniqueDebuggerId debuggerId - - # Add handler to promise with given promise object id. - command awaitPromise - parameters - # Identifier of the promise. - RemoteObjectId promiseObjectId - # Whether the result is expected to be a JSON object that should be sent by value. - optional boolean returnByValue - # Whether preview should be generated for the result. - optional boolean generatePreview - returns - # Promise result. Will contain rejected value if promise was rejected. - RemoteObject result - # Exception details if stack strace is available. - optional ExceptionDetails exceptionDetails - - # Calls function with given declaration on the given object. Object group of the result is - # inherited from the target object. - command callFunctionOn - parameters - # Declaration of the function to call. - string functionDeclaration - # Identifier of the object to call function on. Either objectId or executionContextId should - # be specified. - optional RemoteObjectId objectId - # Call arguments. All call arguments must belong to the same JavaScript world as the target - # object. - optional array of CallArgument arguments - # In silent mode exceptions thrown during evaluation are not reported and do not pause - # execution. Overrides `setPauseOnException` state. - optional boolean silent - # Whether the result is expected to be a JSON object which should be sent by value. - optional boolean returnByValue - # Whether preview should be generated for the result. - experimental optional boolean generatePreview - # Whether execution should be treated as initiated by user in the UI. - optional boolean userGesture - # Whether execution should `await` for resulting value and return once awaited promise is - # resolved. - optional boolean awaitPromise - # Specifies execution context which global object will be used to call function on. Either - # executionContextId or objectId should be specified. - optional ExecutionContextId executionContextId - # Symbolic group name that can be used to release multiple objects. If objectGroup is not - # specified and objectId is, objectGroup will be inherited from object. - optional string objectGroup - # Whether to throw an exception if side effect cannot be ruled out during evaluation. - experimental optional boolean throwOnSideEffect - # Whether the result should be serialized according to https://w3c.github.io/webdriver-bidi. - experimental optional boolean generateWebDriverValue - returns - # Call result. - RemoteObject result - # Exception details. - optional ExceptionDetails exceptionDetails - - # Compiles expression. - command compileScript - parameters - # Expression to compile. - string expression - # Source url to be set for the script. - string sourceURL - # Specifies whether the compiled script should be persisted. - boolean persistScript - # Specifies in which execution context to perform script run. If the parameter is omitted the - # evaluation will be performed in the context of the inspected page. - optional ExecutionContextId executionContextId - returns - # Id of the script. - optional ScriptId scriptId - # Exception details. - optional ExceptionDetails exceptionDetails - - # Disables reporting of execution contexts creation. - command disable - - # Discards collected exceptions and console API calls. - command discardConsoleEntries - - # Enables reporting of execution contexts creation by means of `executionContextCreated` event. - # When the reporting gets enabled the event will be sent immediately for each existing execution - # context. - command enable - - # Evaluates expression on global object. - command evaluate - parameters - # Expression to evaluate. - string expression - # Symbolic group name that can be used to release multiple objects. - optional string objectGroup - # Determines whether Command Line API should be available during the evaluation. - optional boolean includeCommandLineAPI - # In silent mode exceptions thrown during evaluation are not reported and do not pause - # execution. Overrides `setPauseOnException` state. - optional boolean silent - # Specifies in which execution context to perform evaluation. If the parameter is omitted the - # evaluation will be performed in the context of the inspected page. - # This is mutually exclusive with `uniqueContextId`, which offers an - # alternative way to identify the execution context that is more reliable - # in a multi-process environment. - optional ExecutionContextId contextId - # Whether the result is expected to be a JSON object that should be sent by value. - optional boolean returnByValue - # Whether preview should be generated for the result. - experimental optional boolean generatePreview - # Whether execution should be treated as initiated by user in the UI. - optional boolean userGesture - # Whether execution should `await` for resulting value and return once awaited promise is - # resolved. - optional boolean awaitPromise - # Whether to throw an exception if side effect cannot be ruled out during evaluation. - # This implies `disableBreaks` below. - experimental optional boolean throwOnSideEffect - # Terminate execution after timing out (number of milliseconds). - experimental optional TimeDelta timeout - # Disable breakpoints during execution. - experimental optional boolean disableBreaks - # Setting this flag to true enables `let` re-declaration and top-level `await`. - # Note that `let` variables can only be re-declared if they originate from - # `replMode` themselves. - experimental optional boolean replMode - # The Content Security Policy (CSP) for the target might block 'unsafe-eval' - # which includes eval(), Function(), setTimeout() and setInterval() - # when called with non-callable arguments. This flag bypasses CSP for this - # evaluation and allows unsafe-eval. Defaults to true. - experimental optional boolean allowUnsafeEvalBlockedByCSP - # An alternative way to specify the execution context to evaluate in. - # Compared to contextId that may be reused across processes, this is guaranteed to be - # system-unique, so it can be used to prevent accidental evaluation of the expression - # in context different than intended (e.g. as a result of navigation across process - # boundaries). - # This is mutually exclusive with `contextId`. - experimental optional string uniqueContextId - # Whether the result should be serialized according to https://w3c.github.io/webdriver-bidi. - experimental optional boolean generateWebDriverValue - returns - # Evaluation result. - RemoteObject result - # Exception details. - optional ExceptionDetails exceptionDetails - - # Returns the isolate id. - experimental command getIsolateId - returns - # The isolate id. - string id - - # Returns the JavaScript heap usage. - # It is the total usage of the corresponding isolate not scoped to a particular Runtime. - experimental command getHeapUsage - returns - # Used heap size in bytes. - number usedSize - # Allocated heap size in bytes. - number totalSize - - # Returns properties of a given object. Object group of the result is inherited from the target - # object. - command getProperties - parameters - # Identifier of the object to return properties for. - RemoteObjectId objectId - # If true, returns properties belonging only to the element itself, not to its prototype - # chain. - optional boolean ownProperties - # If true, returns accessor properties (with getter/setter) only; internal properties are not - # returned either. - experimental optional boolean accessorPropertiesOnly - # Whether preview should be generated for the results. - experimental optional boolean generatePreview - # If true, returns non-indexed properties only. - experimental optional boolean nonIndexedPropertiesOnly - returns - # Object properties. - array of PropertyDescriptor result - # Internal object properties (only of the element itself). - optional array of InternalPropertyDescriptor internalProperties - # Object private properties. - experimental optional array of PrivatePropertyDescriptor privateProperties - # Exception details. - optional ExceptionDetails exceptionDetails - - # Returns all let, const and class variables from global scope. - command globalLexicalScopeNames - parameters - # Specifies in which execution context to lookup global scope variables. - optional ExecutionContextId executionContextId - returns - array of string names - - command queryObjects - parameters - # Identifier of the prototype to return objects for. - RemoteObjectId prototypeObjectId - # Symbolic group name that can be used to release the results. - optional string objectGroup - returns - # Array with objects. - RemoteObject objects - - # Releases remote object with given id. - command releaseObject - parameters - # Identifier of the object to release. - RemoteObjectId objectId - - # Releases all remote objects that belong to a given group. - command releaseObjectGroup - parameters - # Symbolic object group name. - string objectGroup - - # Tells inspected instance to run if it was waiting for debugger to attach. - command runIfWaitingForDebugger - - # Runs script with given id in a given context. - command runScript - parameters - # Id of the script to run. - ScriptId scriptId - # Specifies in which execution context to perform script run. If the parameter is omitted the - # evaluation will be performed in the context of the inspected page. - optional ExecutionContextId executionContextId - # Symbolic group name that can be used to release multiple objects. - optional string objectGroup - # In silent mode exceptions thrown during evaluation are not reported and do not pause - # execution. Overrides `setPauseOnException` state. - optional boolean silent - # Determines whether Command Line API should be available during the evaluation. - optional boolean includeCommandLineAPI - # Whether the result is expected to be a JSON object which should be sent by value. - optional boolean returnByValue - # Whether preview should be generated for the result. - optional boolean generatePreview - # Whether execution should `await` for resulting value and return once awaited promise is - # resolved. - optional boolean awaitPromise - returns - # Run result. - RemoteObject result - # Exception details. - optional ExceptionDetails exceptionDetails - - # Enables or disables async call stacks tracking. - command setAsyncCallStackDepth - redirect Debugger - parameters - # Maximum depth of async call stacks. Setting to `0` will effectively disable collecting async - # call stacks (default). - integer maxDepth - - experimental command setCustomObjectFormatterEnabled - parameters - boolean enabled - - experimental command setMaxCallStackSizeToCapture - parameters - integer size - - # Terminate current or next JavaScript execution. - # Will cancel the termination when the outer-most script execution ends. - experimental command terminateExecution - - # If executionContextId is empty, adds binding with the given name on the - # global objects of all inspected contexts, including those created later, - # bindings survive reloads. - # Binding function takes exactly one argument, this argument should be string, - # in case of any other input, function throws an exception. - # Each binding function call produces Runtime.bindingCalled notification. - experimental command addBinding - parameters - string name - # If specified, the binding would only be exposed to the specified - # execution context. If omitted and `executionContextName` is not set, - # the binding is exposed to all execution contexts of the target. - # This parameter is mutually exclusive with `executionContextName`. - # Deprecated in favor of `executionContextName` due to an unclear use case - # and bugs in implementation (crbug.com/1169639). `executionContextId` will be - # removed in the future. - deprecated optional ExecutionContextId executionContextId - # If specified, the binding is exposed to the executionContext with - # matching name, even for contexts created after the binding is added. - # See also `ExecutionContext.name` and `worldName` parameter to - # `Page.addScriptToEvaluateOnNewDocument`. - # This parameter is mutually exclusive with `executionContextId`. - experimental optional string executionContextName - - # This method does not remove binding function from global object but - # unsubscribes current runtime agent from Runtime.bindingCalled notifications. - experimental command removeBinding - parameters - string name - - # This method tries to lookup and populate exception details for a - # JavaScript Error object. - # Note that the stackTrace portion of the resulting exceptionDetails will - # only be populated if the Runtime domain was enabled at the time when the - # Error was thrown. - experimental command getExceptionDetails - parameters - # The error object for which to resolve the exception details. - RemoteObjectId errorObjectId - returns - optional ExceptionDetails exceptionDetails - - # Notification is issued every time when binding is called. - experimental event bindingCalled - parameters - string name - string payload - # Identifier of the context where the call was made. - ExecutionContextId executionContextId - - # Issued when console API was called. - event consoleAPICalled - parameters - # Type of the call. - enum type - log - debug - info - error - warning - dir - dirxml - table - trace - clear - startGroup - startGroupCollapsed - endGroup - assert - profile - profileEnd - count - timeEnd - # Call arguments. - array of RemoteObject args - # Identifier of the context where the call was made. - ExecutionContextId executionContextId - # Call timestamp. - Timestamp timestamp - # Stack trace captured when the call was made. The async stack chain is automatically reported for - # the following call types: `assert`, `error`, `trace`, `warning`. For other types the async call - # chain can be retrieved using `Debugger.getStackTrace` and `stackTrace.parentId` field. - optional StackTrace stackTrace - # Console context descriptor for calls on non-default console context (not console.*): - # 'anonymous#unique-logger-id' for call on unnamed context, 'name#unique-logger-id' for call - # on named context. - experimental optional string context - - # Issued when unhandled exception was revoked. - event exceptionRevoked - parameters - # Reason describing why exception was revoked. - string reason - # The id of revoked exception, as reported in `exceptionThrown`. - integer exceptionId - - # Issued when exception was thrown and unhandled. - event exceptionThrown - parameters - # Timestamp of the exception. - Timestamp timestamp - ExceptionDetails exceptionDetails - - # Issued when new execution context is created. - event executionContextCreated - parameters - # A newly created execution context. - ExecutionContextDescription context - - # Issued when execution context is destroyed. - event executionContextDestroyed - parameters - # Id of the destroyed context - ExecutionContextId executionContextId - - # Issued when all executionContexts were cleared in browser - event executionContextsCleared - - # Issued when object should be inspected (for example, as a result of inspect() command line API - # call). - event inspectRequested - parameters - RemoteObject object - object hints - # Identifier of the context where the call was made. - experimental optional ExecutionContextId executionContextId - -# This domain is deprecated. -deprecated domain Schema - - # Description of the protocol domain. - type Domain extends object - properties - # Domain name. - string name - # Domain version. - string version - - # Returns supported domains. - command getDomains - returns - # List of supported domains. - array of Domain domains diff --git a/NativeScript/include/libffi/arm64/ffi.h b/NativeScript/include/libffi/arm64/ffi.h index 5185731a..d281418c 100644 --- a/NativeScript/include/libffi/arm64/ffi.h +++ b/NativeScript/include/libffi/arm64/ffi.h @@ -1,6 +1,7 @@ /* -----------------------------------------------------------------*-C-*- - libffi 3.3-rc0 - Copyright (c) 2011, 2014 Anthony Green - - Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc. + libffi 3.7.1 + - Copyright (c) 2011, 2014, 2019, 2021, 2022, 2024, 2025, 2026 Anthony Green + - Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation @@ -55,6 +56,34 @@ extern "C" { /* ---- System configuration information --------------------------------- */ +/* If these change, update src/mips/ffitarget.h. */ +#define FFI_TYPE_VOID 0 +#define FFI_TYPE_INT 1 +#define FFI_TYPE_FLOAT 2 +#define FFI_TYPE_DOUBLE 3 +#if 0 +#define FFI_TYPE_LONGDOUBLE 4 +#else +#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE +#endif +#define FFI_TYPE_UINT8 5 +#define FFI_TYPE_SINT8 6 +#define FFI_TYPE_UINT16 7 +#define FFI_TYPE_SINT16 8 +#define FFI_TYPE_UINT32 9 +#define FFI_TYPE_SINT32 10 +#define FFI_TYPE_UINT64 11 +#define FFI_TYPE_SINT64 12 +#define FFI_TYPE_STRUCT 13 +#define FFI_TYPE_POINTER 14 +#define FFI_TYPE_COMPLEX 15 +#define FFI_TYPE_UINT128 16 +#define FFI_TYPE_SINT128 17 +#define FFI_TYPE_VECTOR 18 + +/* This should always refer to the last type code (for sanity checks). */ +#define FFI_TYPE_LAST FFI_TYPE_VECTOR + #include "ffitarget.h" #ifndef LIBFFI_ASM @@ -114,13 +143,11 @@ typedef struct _ffi_type when using the static version of the library. Besides, as a workaround, they can define FFI_BUILDING if they *know* they are going to link with the static library. */ -#if defined _MSC_VER +#if defined _MSC_VER && !defined(FFI_STATIC_BUILD) # if defined FFI_BUILDING_DLL /* Building libffi.DLL with msvcc.sh */ # define FFI_API __declspec(dllexport) -# elif !defined FFI_BUILDING /* Importing libffi.DLL */ +# else /* Importing libffi.DLL */ # define FFI_API __declspec(dllimport) -# else /* Building/linking static library */ -# define FFI_API # endif #else # define FFI_API @@ -196,28 +223,25 @@ FFI_EXTERN ffi_type ffi_type_sint64; FFI_EXTERN ffi_type ffi_type_float; FFI_EXTERN ffi_type ffi_type_double; FFI_EXTERN ffi_type ffi_type_pointer; - -#if 0 FFI_EXTERN ffi_type ffi_type_longdouble; -#else -#define ffi_type_longdouble ffi_type_double -#endif #ifdef FFI_TARGET_HAS_COMPLEX_TYPE FFI_EXTERN ffi_type ffi_type_complex_float; FFI_EXTERN ffi_type ffi_type_complex_double; -#if 0 FFI_EXTERN ffi_type ffi_type_complex_longdouble; -#else -#define ffi_type_complex_longdouble ffi_type_complex_double #endif + +#ifdef FFI_TARGET_HAS_INT128 +FFI_EXTERN ffi_type ffi_type_uint128; +FFI_EXTERN ffi_type ffi_type_sint128; #endif #endif /* LIBFFI_HIDE_BASIC_TYPES */ typedef enum { FFI_OK = 0, FFI_BAD_TYPEDEF, - FFI_BAD_ABI + FFI_BAD_ABI, + FFI_BAD_ARGTYPE } ffi_status; typedef struct { @@ -288,15 +312,33 @@ FFI_API void ffi_java_raw_call (ffi_cif *cif, void (*fn)(void), void *rvalue, - ffi_java_raw *avalue); + ffi_java_raw *avalue) __attribute__((deprecated)); #endif FFI_API -void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw); +void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw) __attribute__((deprecated)); FFI_API -void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args); +void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args) __attribute__((deprecated)); FFI_API -size_t ffi_java_raw_size (ffi_cif *cif); +size_t ffi_java_raw_size (ffi_cif *cif) __attribute__((deprecated)); + +/* ---- Version API ------------------------------------------------------ */ + +#define FFI_VERSION_STRING "3.7.1" +#define FFI_VERSION_NUMBER 30701 + +#ifndef LIBFFI_ASM +/* Return a version string. */ +FFI_API const char *ffi_get_version (void); + +/* Return the version as an unsigned long value: (x * 10000 + y * 100 + z) */ +FFI_API unsigned long ffi_get_version_number (void); +#endif + +/* ---- Internals API ---------------------------------------------------- */ + +FFI_API unsigned int ffi_get_default_abi (void); +FFI_API size_t ffi_get_closure_size (void); /* ---- Definitions for closures ----------------------------------------- */ @@ -310,11 +352,22 @@ typedef struct { void *trampoline_table; void *trampoline_table_entry; #else - char tramp[FFI_TRAMPOLINE_SIZE]; + /* Anonymous unions are C11 (a GNU extension in C99); __extension__ keeps + the field names without tripping -Wpedantic under -std=c99 (#795). */ +#ifdef __GNUC__ + __extension__ +#endif + union { + char tramp[FFI_TRAMPOLINE_SIZE]; + void *ftramp; + }; #endif ffi_cif *cif; void (*fun)(ffi_cif*,void*,void**,void*); void *user_data; +#if defined(_MSC_VER) && defined(_M_IX86) + void *padding; +#endif } ffi_closure #ifdef __GNUC__ __attribute__((aligned (8))) @@ -347,7 +400,7 @@ ffi_prep_closure_loc (ffi_closure*, ffi_cif *, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data, - void*codeloc); + void *codeloc); #ifdef __sgi # pragma pack 8 @@ -365,7 +418,7 @@ typedef struct { /* If this is enabled, then a raw closure has the same layout as a regular closure. We use this to install an intermediate - handler to do the transaltion, void** -> ffi_raw*. */ + handler to do the translation, void** -> ffi_raw*. */ void (*translate_args)(ffi_cif*,void*,void**,void*); void *this_closure; @@ -421,19 +474,19 @@ FFI_API ffi_status ffi_prep_java_raw_closure (ffi_java_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), - void *user_data); + void *user_data) __attribute__((deprecated)); FFI_API ffi_status ffi_prep_java_raw_closure_loc (ffi_java_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), void *user_data, - void *codeloc); + void *codeloc) __attribute__((deprecated)); #endif #endif /* FFI_CLOSURES */ -#if FFI_GO_CLOSURES +#ifdef FFI_GO_CLOSURES typedef struct { void *tramp; @@ -472,49 +525,47 @@ void ffi_call(ffi_cif *cif, void *rvalue, void **avalue); +/* Reusable call plans. + + A plan captures a signature's argument placement once so that repeated + calls skip the per-call work that ffi_call would otherwise redo. Build one + with ffi_call_plan_alloc, invoke it as many times as you like, and release + it with ffi_call_plan_free. + + The plan is opaque and caller-owned. The cif must outlive the plan. + ffi_call_plan_alloc returns NULL only on allocation failure; a signature + with no fast path is still valid and ffi_call_plan_invoke falls back to + ffi_call for it. A plan is immutable once built, so it may be shared and + invoked concurrently from multiple threads. */ +typedef struct ffi_call_plan ffi_call_plan; + FFI_API -ffi_status ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type, - size_t *offsets); +ffi_call_plan *ffi_call_plan_alloc (ffi_cif *cif); -/* Useful for eliminating compiler warnings. */ -#define FFI_FN(f) ((void (*)(void))f) +FFI_API +void ffi_call_plan_invoke (ffi_call_plan *plan, + void (*fn)(void), + void *rvalue, + void **avalue); -/* ---- Definitions shared with assembly code ---------------------------- */ +FFI_API +void ffi_call_plan_free (ffi_call_plan *plan); -#endif +FFI_API +ffi_status ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type, + size_t *offsets); -/* If these change, update src/mips/ffitarget.h. */ -#define FFI_TYPE_VOID 0 -#define FFI_TYPE_INT 1 -#define FFI_TYPE_FLOAT 2 -#define FFI_TYPE_DOUBLE 3 -#if 0 -#define FFI_TYPE_LONGDOUBLE 4 +/* Convert between closure and function pointers. */ +#if defined(PA_LINUX) || defined(PA_HPUX) +#define FFI_FN(f) ((void (*)(void))((unsigned int)(f) | 2)) +#define FFI_CL(f) ((void *)((unsigned int)(f) & ~3)) #else -#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE -#endif -#define FFI_TYPE_UINT8 5 -#define FFI_TYPE_SINT8 6 -#define FFI_TYPE_UINT16 7 -#define FFI_TYPE_SINT16 8 -#define FFI_TYPE_UINT32 9 -#define FFI_TYPE_SINT32 10 -#define FFI_TYPE_UINT64 11 -#define FFI_TYPE_SINT64 12 -#define FFI_TYPE_STRUCT 13 -#define FFI_TYPE_POINTER 14 -#define FFI_TYPE_COMPLEX 15 -#if 1 -#define FFI_TYPE_EXT_VECTOR 16 -#else -#define FFI_TYPE_EXT_VECTOR FFI_TYPE_STRUCT +#define FFI_FN(f) ((void (*)(void))f) +#define FFI_CL(f) ((void *)(f)) #endif -/* This should always refer to the last type code (for sanity checks). */ -#if 1 -#define FFI_TYPE_LAST FFI_TYPE_EXT_VECTOR -#else -#define FFI_TYPE_LAST FFI_TYPE_COMPLEX +/* ---- Definitions shared with assembly code ---------------------------- */ + #endif #ifdef __cplusplus diff --git a/NativeScript/include/libffi/arm64/ffitarget.h b/NativeScript/include/libffi/arm64/ffitarget.h index ecb6d2de..8ba86799 100644 --- a/NativeScript/include/libffi/arm64/ffitarget.h +++ b/NativeScript/include/libffi/arm64/ffitarget.h @@ -32,7 +32,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; -#elif defined(_M_ARM64) +#elif defined(_WIN32) #define FFI_SIZEOF_ARG 8 typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; @@ -45,8 +45,13 @@ typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, + FFI_WIN64, FFI_LAST_ABI, +#if defined(_WIN32) + FFI_DEFAULT_ABI = FFI_WIN64 +#else FFI_DEFAULT_ABI = FFI_SYSV +#endif } ffi_abi; #endif @@ -69,24 +74,30 @@ typedef enum ffi_abi #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE #endif -#ifdef _M_ARM64 +#ifdef _WIN32 #define FFI_EXTRA_CIF_FIELDS unsigned is_variadic #endif +#define FFI_TARGET_SPECIFIC_VARIADIC /* ---- Internal ---- */ #if defined (__APPLE__) -#define FFI_TARGET_SPECIFIC_VARIADIC #define FFI_EXTRA_CIF_FIELDS unsigned aarch64_nfixedargs -#elif !defined(_M_ARM64) -/* iOS and Windows reserve x18 for the system. Disable Go closures until +#elif !defined(_WIN32) && !defined(__ANDROID__) +/* iOS, Windows and Android reserve x18 for the system. Disable Go closures until a new static chain is chosen. */ #define FFI_GO_CLOSURES 1 #endif -#ifndef _M_ARM64 +#ifndef _WIN32 /* No complex type on Windows */ #define FFI_TARGET_HAS_COMPLEX_TYPE #endif +/* AAPCS64 passes 8- and 16-byte vectors in V/Q registers and homogeneous + vector aggregates in consecutive V/Q registers; see is_vfp_type. */ +#define FFI_TARGET_HAS_VECTOR_TYPE + +#define FFI_TARGET_HAS_INT128 1 + #endif diff --git a/NativeScript/include/libffi/x86_64/ffi.h b/NativeScript/include/libffi/x86_64/ffi.h index 0cb32bf1..07044832 100644 --- a/NativeScript/include/libffi/x86_64/ffi.h +++ b/NativeScript/include/libffi/x86_64/ffi.h @@ -1,6 +1,7 @@ /* -----------------------------------------------------------------*-C-*- - libffi 3.3-rc0 - Copyright (c) 2011, 2014 Anthony Green - - Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc. + libffi 3.7.1 + - Copyright (c) 2011, 2014, 2019, 2021, 2022, 2024, 2025, 2026 Anthony Green + - Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation @@ -55,6 +56,34 @@ extern "C" { /* ---- System configuration information --------------------------------- */ +/* If these change, update src/mips/ffitarget.h. */ +#define FFI_TYPE_VOID 0 +#define FFI_TYPE_INT 1 +#define FFI_TYPE_FLOAT 2 +#define FFI_TYPE_DOUBLE 3 +#if 1 +#define FFI_TYPE_LONGDOUBLE 4 +#else +#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE +#endif +#define FFI_TYPE_UINT8 5 +#define FFI_TYPE_SINT8 6 +#define FFI_TYPE_UINT16 7 +#define FFI_TYPE_SINT16 8 +#define FFI_TYPE_UINT32 9 +#define FFI_TYPE_SINT32 10 +#define FFI_TYPE_UINT64 11 +#define FFI_TYPE_SINT64 12 +#define FFI_TYPE_STRUCT 13 +#define FFI_TYPE_POINTER 14 +#define FFI_TYPE_COMPLEX 15 +#define FFI_TYPE_UINT128 16 +#define FFI_TYPE_SINT128 17 +#define FFI_TYPE_VECTOR 18 + +/* This should always refer to the last type code (for sanity checks). */ +#define FFI_TYPE_LAST FFI_TYPE_VECTOR + #include "ffitarget.h" #ifndef LIBFFI_ASM @@ -114,13 +143,11 @@ typedef struct _ffi_type when using the static version of the library. Besides, as a workaround, they can define FFI_BUILDING if they *know* they are going to link with the static library. */ -#if defined _MSC_VER +#if defined _MSC_VER && !defined(FFI_STATIC_BUILD) # if defined FFI_BUILDING_DLL /* Building libffi.DLL with msvcc.sh */ # define FFI_API __declspec(dllexport) -# elif !defined FFI_BUILDING /* Importing libffi.DLL */ +# else /* Importing libffi.DLL */ # define FFI_API __declspec(dllimport) -# else /* Building/linking static library */ -# define FFI_API # endif #else # define FFI_API @@ -196,28 +223,25 @@ FFI_EXTERN ffi_type ffi_type_sint64; FFI_EXTERN ffi_type ffi_type_float; FFI_EXTERN ffi_type ffi_type_double; FFI_EXTERN ffi_type ffi_type_pointer; - -#if 1 FFI_EXTERN ffi_type ffi_type_longdouble; -#else -#define ffi_type_longdouble ffi_type_double -#endif #ifdef FFI_TARGET_HAS_COMPLEX_TYPE FFI_EXTERN ffi_type ffi_type_complex_float; FFI_EXTERN ffi_type ffi_type_complex_double; -#if 1 FFI_EXTERN ffi_type ffi_type_complex_longdouble; -#else -#define ffi_type_complex_longdouble ffi_type_complex_double #endif + +#ifdef FFI_TARGET_HAS_INT128 +FFI_EXTERN ffi_type ffi_type_uint128; +FFI_EXTERN ffi_type ffi_type_sint128; #endif #endif /* LIBFFI_HIDE_BASIC_TYPES */ typedef enum { FFI_OK = 0, FFI_BAD_TYPEDEF, - FFI_BAD_ABI + FFI_BAD_ABI, + FFI_BAD_ARGTYPE } ffi_status; typedef struct { @@ -288,15 +312,33 @@ FFI_API void ffi_java_raw_call (ffi_cif *cif, void (*fn)(void), void *rvalue, - ffi_java_raw *avalue); + ffi_java_raw *avalue) __attribute__((deprecated)); #endif FFI_API -void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw); +void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw) __attribute__((deprecated)); FFI_API -void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args); +void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args) __attribute__((deprecated)); FFI_API -size_t ffi_java_raw_size (ffi_cif *cif); +size_t ffi_java_raw_size (ffi_cif *cif) __attribute__((deprecated)); + +/* ---- Version API ------------------------------------------------------ */ + +#define FFI_VERSION_STRING "3.7.1" +#define FFI_VERSION_NUMBER 30701 + +#ifndef LIBFFI_ASM +/* Return a version string. */ +FFI_API const char *ffi_get_version (void); + +/* Return the version as an unsigned long value: (x * 10000 + y * 100 + z) */ +FFI_API unsigned long ffi_get_version_number (void); +#endif + +/* ---- Internals API ---------------------------------------------------- */ + +FFI_API unsigned int ffi_get_default_abi (void); +FFI_API size_t ffi_get_closure_size (void); /* ---- Definitions for closures ----------------------------------------- */ @@ -310,11 +352,22 @@ typedef struct { void *trampoline_table; void *trampoline_table_entry; #else - char tramp[FFI_TRAMPOLINE_SIZE]; + /* Anonymous unions are C11 (a GNU extension in C99); __extension__ keeps + the field names without tripping -Wpedantic under -std=c99 (#795). */ +#ifdef __GNUC__ + __extension__ +#endif + union { + char tramp[FFI_TRAMPOLINE_SIZE]; + void *ftramp; + }; #endif ffi_cif *cif; void (*fun)(ffi_cif*,void*,void**,void*); void *user_data; +#if defined(_MSC_VER) && defined(_M_IX86) + void *padding; +#endif } ffi_closure #ifdef __GNUC__ __attribute__((aligned (8))) @@ -347,7 +400,7 @@ ffi_prep_closure_loc (ffi_closure*, ffi_cif *, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data, - void*codeloc); + void *codeloc); #ifdef __sgi # pragma pack 8 @@ -365,7 +418,7 @@ typedef struct { /* If this is enabled, then a raw closure has the same layout as a regular closure. We use this to install an intermediate - handler to do the transaltion, void** -> ffi_raw*. */ + handler to do the translation, void** -> ffi_raw*. */ void (*translate_args)(ffi_cif*,void*,void**,void*); void *this_closure; @@ -421,19 +474,19 @@ FFI_API ffi_status ffi_prep_java_raw_closure (ffi_java_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), - void *user_data); + void *user_data) __attribute__((deprecated)); FFI_API ffi_status ffi_prep_java_raw_closure_loc (ffi_java_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), void *user_data, - void *codeloc); + void *codeloc) __attribute__((deprecated)); #endif #endif /* FFI_CLOSURES */ -#if FFI_GO_CLOSURES +#ifdef FFI_GO_CLOSURES typedef struct { void *tramp; @@ -472,49 +525,47 @@ void ffi_call(ffi_cif *cif, void *rvalue, void **avalue); +/* Reusable call plans. + + A plan captures a signature's argument placement once so that repeated + calls skip the per-call work that ffi_call would otherwise redo. Build one + with ffi_call_plan_alloc, invoke it as many times as you like, and release + it with ffi_call_plan_free. + + The plan is opaque and caller-owned. The cif must outlive the plan. + ffi_call_plan_alloc returns NULL only on allocation failure; a signature + with no fast path is still valid and ffi_call_plan_invoke falls back to + ffi_call for it. A plan is immutable once built, so it may be shared and + invoked concurrently from multiple threads. */ +typedef struct ffi_call_plan ffi_call_plan; + FFI_API -ffi_status ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type, - size_t *offsets); +ffi_call_plan *ffi_call_plan_alloc (ffi_cif *cif); -/* Useful for eliminating compiler warnings. */ -#define FFI_FN(f) ((void (*)(void))f) +FFI_API +void ffi_call_plan_invoke (ffi_call_plan *plan, + void (*fn)(void), + void *rvalue, + void **avalue); -/* ---- Definitions shared with assembly code ---------------------------- */ +FFI_API +void ffi_call_plan_free (ffi_call_plan *plan); -#endif +FFI_API +ffi_status ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type, + size_t *offsets); -/* If these change, update src/mips/ffitarget.h. */ -#define FFI_TYPE_VOID 0 -#define FFI_TYPE_INT 1 -#define FFI_TYPE_FLOAT 2 -#define FFI_TYPE_DOUBLE 3 -#if 1 -#define FFI_TYPE_LONGDOUBLE 4 +/* Convert between closure and function pointers. */ +#if defined(PA_LINUX) || defined(PA_HPUX) +#define FFI_FN(f) ((void (*)(void))((unsigned int)(f) | 2)) +#define FFI_CL(f) ((void *)((unsigned int)(f) & ~3)) #else -#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE -#endif -#define FFI_TYPE_UINT8 5 -#define FFI_TYPE_SINT8 6 -#define FFI_TYPE_UINT16 7 -#define FFI_TYPE_SINT16 8 -#define FFI_TYPE_UINT32 9 -#define FFI_TYPE_SINT32 10 -#define FFI_TYPE_UINT64 11 -#define FFI_TYPE_SINT64 12 -#define FFI_TYPE_STRUCT 13 -#define FFI_TYPE_POINTER 14 -#define FFI_TYPE_COMPLEX 15 -#if 1 -#define FFI_TYPE_EXT_VECTOR 16 -#else -#define FFI_TYPE_EXT_VECTOR FFI_TYPE_STRUCT +#define FFI_FN(f) ((void (*)(void))f) +#define FFI_CL(f) ((void *)(f)) #endif -/* This should always refer to the last type code (for sanity checks). */ -#if 1 -#define FFI_TYPE_LAST FFI_TYPE_EXT_VECTOR -#else -#define FFI_TYPE_LAST FFI_TYPE_COMPLEX +/* ---- Definitions shared with assembly code ---------------------------- */ + #endif #ifdef __cplusplus diff --git a/NativeScript/include/libffi/x86_64/ffitarget.h b/NativeScript/include/libffi/x86_64/ffitarget.h index 85ccedfe..734ac955 100644 --- a/NativeScript/include/libffi/x86_64/ffitarget.h +++ b/NativeScript/include/libffi/x86_64/ffitarget.h @@ -1,5 +1,5 @@ /* -----------------------------------------------------------------*-C-*- - ffitarget.h - Copyright (c) 2012, 2014, 2018 Anthony Green + ffitarget.h - Copyright (c) 2012, 2014, 2018, 2026 Anthony Green Copyright (c) 1996-2003, 2010 Red Hat, Inc. Copyright (C) 2008 Free Software Foundation, Inc. @@ -54,6 +54,17 @@ #define FFI_TARGET_HAS_COMPLEX_TYPE #endif +#ifdef X86_64 +#define FFI_TARGET_HAS_INT128 +#endif + +/* The System V x86-64 psABI passes 8- and 16-byte vectors in SSE registers; + this is implemented by the ffi64.c (FFI_UNIX64) backend only. 32-bit x86 + and the Windows x86-64 backend (ffiw64.c) do not marshal vectors. */ +#if defined(X86_64) && !defined(X86_WIN64) +#define FFI_TARGET_HAS_VECTOR_TYPE +#endif + /* ---- Generic type definitions ----------------------------------------- */ #ifndef LIBFFI_ASM @@ -85,9 +96,9 @@ typedef enum ffi_abi { FFI_LAST_ABI, #ifdef __GNUC__ FFI_DEFAULT_ABI = FFI_GNUW64 -#else +#else FFI_DEFAULT_ABI = FFI_WIN64 -#endif +#endif #elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) FFI_FIRST_ABI = 1, @@ -136,12 +147,26 @@ typedef enum ffi_abi { #if defined (X86_64) || defined(X86_WIN64) \ || (defined (__x86_64__) && defined (X86_DARWIN)) -# define FFI_TRAMPOLINE_SIZE 24 +/* 4 bytes of ENDBR64 + 7 bytes of LEA + 6 bytes of JMP + 7 bytes of NOP + + 8 bytes of pointer. */ +# define FFI_TRAMPOLINE_SIZE 32 # define FFI_NATIVE_RAW_API 0 #else -# define FFI_TRAMPOLINE_SIZE 12 +/* 4 bytes of ENDBR32 + 5 bytes of MOV + 5 bytes of JMP + 2 unused + bytes. */ +# define FFI_TRAMPOLINE_SIZE 16 # define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ #endif +#if !defined(GENERATE_LIBFFI_MAP) && defined(__CET__) +# include +# if (__CET__ & 1) != 0 +# define ENDBR_PRESENT +# endif +# define _CET_NOTRACK notrack +#else +# define _CET_ENDBR +# define _CET_NOTRACK #endif +#endif diff --git a/NativeScript/include/libplatform/DEPS b/NativeScript/include/libplatform/DEPS deleted file mode 100644 index d8bcf998..00000000 --- a/NativeScript/include/libplatform/DEPS +++ /dev/null @@ -1,9 +0,0 @@ -include_rules = [ - "+libplatform/libplatform-export.h", -] - -specific_include_rules = { - "libplatform\.h": [ - "+libplatform/v8-tracing.h", - ], -} diff --git a/NativeScript/include/libplatform/libplatform-export.h b/NativeScript/include/libplatform/libplatform-export.h deleted file mode 100644 index 15618434..00000000 --- a/NativeScript/include/libplatform/libplatform-export.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2016 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_LIBPLATFORM_LIBPLATFORM_EXPORT_H_ -#define V8_LIBPLATFORM_LIBPLATFORM_EXPORT_H_ - -#if defined(_WIN32) - -#ifdef BUILDING_V8_PLATFORM_SHARED -#define V8_PLATFORM_EXPORT __declspec(dllexport) -#elif USING_V8_PLATFORM_SHARED -#define V8_PLATFORM_EXPORT __declspec(dllimport) -#else -#define V8_PLATFORM_EXPORT -#endif // BUILDING_V8_PLATFORM_SHARED - -#else // defined(_WIN32) - -// Setup for Linux shared library export. -#ifdef BUILDING_V8_PLATFORM_SHARED -#define V8_PLATFORM_EXPORT __attribute__((visibility("default"))) -#else -#define V8_PLATFORM_EXPORT -#endif - -#endif // defined(_WIN32) - -#endif // V8_LIBPLATFORM_LIBPLATFORM_EXPORT_H_ diff --git a/NativeScript/include/libplatform/libplatform.h b/NativeScript/include/libplatform/libplatform.h deleted file mode 100644 index 9ec60c04..00000000 --- a/NativeScript/include/libplatform/libplatform.h +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2014 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_LIBPLATFORM_LIBPLATFORM_H_ -#define V8_LIBPLATFORM_LIBPLATFORM_H_ - -#include - -#include "libplatform/libplatform-export.h" -#include "libplatform/v8-tracing.h" -#include "v8-platform.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { -namespace platform { - -enum class IdleTaskSupport { kDisabled, kEnabled }; -enum class InProcessStackDumping { kDisabled, kEnabled }; - -enum class MessageLoopBehavior : bool { - kDoNotWait = false, - kWaitForWork = true -}; - -/** - * Returns a new instance of the default v8::Platform implementation. - * - * The caller will take ownership of the returned pointer. |thread_pool_size| - * is the number of worker threads to allocate for background jobs. If a value - * of zero is passed, a suitable default based on the current number of - * processors online will be chosen. - * If |idle_task_support| is enabled then the platform will accept idle - * tasks (IdleTasksEnabled will return true) and will rely on the embedder - * calling v8::platform::RunIdleTasks to process the idle tasks. - * If |tracing_controller| is nullptr, the default platform will create a - * v8::platform::TracingController instance and use it. - */ -V8_PLATFORM_EXPORT std::unique_ptr NewDefaultPlatform( - int thread_pool_size = 0, - IdleTaskSupport idle_task_support = IdleTaskSupport::kDisabled, - InProcessStackDumping in_process_stack_dumping = - InProcessStackDumping::kDisabled, - std::unique_ptr tracing_controller = {}); - -/** - * The same as NewDefaultPlatform but disables the worker thread pool. - * It must be used with the --single-threaded V8 flag. - */ -V8_PLATFORM_EXPORT std::unique_ptr -NewSingleThreadedDefaultPlatform( - IdleTaskSupport idle_task_support = IdleTaskSupport::kDisabled, - InProcessStackDumping in_process_stack_dumping = - InProcessStackDumping::kDisabled, - std::unique_ptr tracing_controller = {}); - -/** - * Returns a new instance of the default v8::JobHandle implementation. - * - * The job will be executed by spawning up to |num_worker_threads| many worker - * threads on the provided |platform| with the given |priority|. - */ -V8_PLATFORM_EXPORT std::unique_ptr NewDefaultJobHandle( - v8::Platform* platform, v8::TaskPriority priority, - std::unique_ptr job_task, size_t num_worker_threads); - -/** - * Pumps the message loop for the given isolate. - * - * The caller has to make sure that this is called from the right thread. - * Returns true if a task was executed, and false otherwise. If the call to - * PumpMessageLoop is nested within another call to PumpMessageLoop, only - * nestable tasks may run. Otherwise, any task may run. Unless requested through - * the |behavior| parameter, this call does not block if no task is pending. The - * |platform| has to be created using |NewDefaultPlatform|. - */ -V8_PLATFORM_EXPORT bool PumpMessageLoop( - v8::Platform* platform, v8::Isolate* isolate, - MessageLoopBehavior behavior = MessageLoopBehavior::kDoNotWait); - -/** - * Runs pending idle tasks for at most |idle_time_in_seconds| seconds. - * - * The caller has to make sure that this is called from the right thread. - * This call does not block if no task is pending. The |platform| has to be - * created using |NewDefaultPlatform|. - */ -V8_PLATFORM_EXPORT void RunIdleTasks(v8::Platform* platform, - v8::Isolate* isolate, - double idle_time_in_seconds); - -/** - * Notifies the given platform about the Isolate getting deleted soon. Has to be - * called for all Isolates which are deleted - unless we're shutting down the - * platform. - * - * The |platform| has to be created using |NewDefaultPlatform|. - * - */ -V8_PLATFORM_EXPORT void NotifyIsolateShutdown(v8::Platform* platform, - Isolate* isolate); - -} // namespace platform -} // namespace v8 - -#endif // V8_LIBPLATFORM_LIBPLATFORM_H_ diff --git a/NativeScript/include/libplatform/v8-tracing.h b/NativeScript/include/libplatform/v8-tracing.h deleted file mode 100644 index 12489327..00000000 --- a/NativeScript/include/libplatform/v8-tracing.h +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright 2016 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_LIBPLATFORM_V8_TRACING_H_ -#define V8_LIBPLATFORM_V8_TRACING_H_ - -#include -#include -#include -#include -#include - -#include "libplatform/libplatform-export.h" -#include "v8-platform.h" // NOLINT(build/include_directory) - -namespace perfetto { -namespace trace_processor { -class TraceProcessorStorage; -} -class TracingSession; -} - -namespace v8 { - -namespace base { -class Mutex; -} // namespace base - -namespace platform { -namespace tracing { - -class TraceEventListener; - -const int kTraceMaxNumArgs = 2; - -class V8_PLATFORM_EXPORT TraceObject { - public: - union ArgValue { - uint64_t as_uint; - int64_t as_int; - double as_double; - const void* as_pointer; - const char* as_string; - }; - - TraceObject() = default; - ~TraceObject(); - void Initialize( - char phase, const uint8_t* category_enabled_flag, const char* name, - const char* scope, uint64_t id, uint64_t bind_id, int num_args, - const char** arg_names, const uint8_t* arg_types, - const uint64_t* arg_values, - std::unique_ptr* arg_convertables, - unsigned int flags, int64_t timestamp, int64_t cpu_timestamp); - void UpdateDuration(int64_t timestamp, int64_t cpu_timestamp); - void InitializeForTesting( - char phase, const uint8_t* category_enabled_flag, const char* name, - const char* scope, uint64_t id, uint64_t bind_id, int num_args, - const char** arg_names, const uint8_t* arg_types, - const uint64_t* arg_values, - std::unique_ptr* arg_convertables, - unsigned int flags, int pid, int tid, int64_t ts, int64_t tts, - uint64_t duration, uint64_t cpu_duration); - - int pid() const { return pid_; } - int tid() const { return tid_; } - char phase() const { return phase_; } - const uint8_t* category_enabled_flag() const { - return category_enabled_flag_; - } - const char* name() const { return name_; } - const char* scope() const { return scope_; } - uint64_t id() const { return id_; } - uint64_t bind_id() const { return bind_id_; } - int num_args() const { return num_args_; } - const char** arg_names() { return arg_names_; } - uint8_t* arg_types() { return arg_types_; } - ArgValue* arg_values() { return arg_values_; } - std::unique_ptr* arg_convertables() { - return arg_convertables_; - } - unsigned int flags() const { return flags_; } - int64_t ts() { return ts_; } - int64_t tts() { return tts_; } - uint64_t duration() { return duration_; } - uint64_t cpu_duration() { return cpu_duration_; } - - private: - int pid_; - int tid_; - char phase_; - const char* name_; - const char* scope_; - const uint8_t* category_enabled_flag_; - uint64_t id_; - uint64_t bind_id_; - int num_args_ = 0; - const char* arg_names_[kTraceMaxNumArgs]; - uint8_t arg_types_[kTraceMaxNumArgs]; - ArgValue arg_values_[kTraceMaxNumArgs]; - std::unique_ptr - arg_convertables_[kTraceMaxNumArgs]; - char* parameter_copy_storage_ = nullptr; - unsigned int flags_; - int64_t ts_; - int64_t tts_; - uint64_t duration_; - uint64_t cpu_duration_; - - // Disallow copy and assign - TraceObject(const TraceObject&) = delete; - void operator=(const TraceObject&) = delete; -}; - -class V8_PLATFORM_EXPORT TraceWriter { - public: - TraceWriter() = default; - virtual ~TraceWriter() = default; - virtual void AppendTraceEvent(TraceObject* trace_event) = 0; - virtual void Flush() = 0; - - static TraceWriter* CreateJSONTraceWriter(std::ostream& stream); - static TraceWriter* CreateJSONTraceWriter(std::ostream& stream, - const std::string& tag); - - static TraceWriter* CreateSystemInstrumentationTraceWriter(); - - private: - // Disallow copy and assign - TraceWriter(const TraceWriter&) = delete; - void operator=(const TraceWriter&) = delete; -}; - -class V8_PLATFORM_EXPORT TraceBufferChunk { - public: - explicit TraceBufferChunk(uint32_t seq); - - void Reset(uint32_t new_seq); - bool IsFull() const { return next_free_ == kChunkSize; } - TraceObject* AddTraceEvent(size_t* event_index); - TraceObject* GetEventAt(size_t index) { return &chunk_[index]; } - - uint32_t seq() const { return seq_; } - size_t size() const { return next_free_; } - - static const size_t kChunkSize = 64; - - private: - size_t next_free_ = 0; - TraceObject chunk_[kChunkSize]; - uint32_t seq_; - - // Disallow copy and assign - TraceBufferChunk(const TraceBufferChunk&) = delete; - void operator=(const TraceBufferChunk&) = delete; -}; - -class V8_PLATFORM_EXPORT TraceBuffer { - public: - TraceBuffer() = default; - virtual ~TraceBuffer() = default; - - virtual TraceObject* AddTraceEvent(uint64_t* handle) = 0; - virtual TraceObject* GetEventByHandle(uint64_t handle) = 0; - virtual bool Flush() = 0; - - static const size_t kRingBufferChunks = 1024; - - static TraceBuffer* CreateTraceBufferRingBuffer(size_t max_chunks, - TraceWriter* trace_writer); - - private: - // Disallow copy and assign - TraceBuffer(const TraceBuffer&) = delete; - void operator=(const TraceBuffer&) = delete; -}; - -// Options determines how the trace buffer stores data. -enum TraceRecordMode { - // Record until the trace buffer is full. - RECORD_UNTIL_FULL, - - // Record until the user ends the trace. The trace buffer is a fixed size - // and we use it as a ring buffer during recording. - RECORD_CONTINUOUSLY, - - // Record until the trace buffer is full, but with a huge buffer size. - RECORD_AS_MUCH_AS_POSSIBLE, - - // Echo to console. Events are discarded. - ECHO_TO_CONSOLE, -}; - -class V8_PLATFORM_EXPORT TraceConfig { - public: - typedef std::vector StringList; - - static TraceConfig* CreateDefaultTraceConfig(); - - TraceConfig() : enable_systrace_(false), enable_argument_filter_(false) {} - TraceRecordMode GetTraceRecordMode() const { return record_mode_; } - const StringList& GetEnabledCategories() const { - return included_categories_; - } - bool IsSystraceEnabled() const { return enable_systrace_; } - bool IsArgumentFilterEnabled() const { return enable_argument_filter_; } - - void SetTraceRecordMode(TraceRecordMode mode) { record_mode_ = mode; } - void EnableSystrace() { enable_systrace_ = true; } - void EnableArgumentFilter() { enable_argument_filter_ = true; } - - void AddIncludedCategory(const char* included_category); - - bool IsCategoryGroupEnabled(const char* category_group) const; - - private: - TraceRecordMode record_mode_; - bool enable_systrace_ : 1; - bool enable_argument_filter_ : 1; - StringList included_categories_; - - // Disallow copy and assign - TraceConfig(const TraceConfig&) = delete; - void operator=(const TraceConfig&) = delete; -}; - -#if defined(_MSC_VER) -#define V8_PLATFORM_NON_EXPORTED_BASE(code) \ - __pragma(warning(suppress : 4275)) code -#else -#define V8_PLATFORM_NON_EXPORTED_BASE(code) code -#endif // defined(_MSC_VER) - -class V8_PLATFORM_EXPORT TracingController - : public V8_PLATFORM_NON_EXPORTED_BASE(v8::TracingController) { - public: - TracingController(); - ~TracingController() override; - -#if defined(V8_USE_PERFETTO) - // Must be called before StartTracing() if V8_USE_PERFETTO is true. Provides - // the output stream for the JSON trace data. - void InitializeForPerfetto(std::ostream* output_stream); - // Provide an optional listener for testing that will receive trace events. - // Must be called before StartTracing(). - void SetTraceEventListenerForTesting(TraceEventListener* listener); -#else // defined(V8_USE_PERFETTO) - // The pointer returned from GetCategoryGroupEnabled() points to a value with - // zero or more of the following bits. Used in this class only. The - // TRACE_EVENT macros should only use the value as a bool. These values must - // be in sync with macro values in TraceEvent.h in Blink. - enum CategoryGroupEnabledFlags { - // Category group enabled for the recording mode. - ENABLED_FOR_RECORDING = 1 << 0, - // Category group enabled by SetEventCallbackEnabled(). - ENABLED_FOR_EVENT_CALLBACK = 1 << 2, - // Category group enabled to export events to ETW. - ENABLED_FOR_ETW_EXPORT = 1 << 3 - }; - - // Takes ownership of |trace_buffer|. - void Initialize(TraceBuffer* trace_buffer); - - // v8::TracingController implementation. - const uint8_t* GetCategoryGroupEnabled(const char* category_group) override; - uint64_t AddTraceEvent( - char phase, const uint8_t* category_enabled_flag, const char* name, - const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args, - const char** arg_names, const uint8_t* arg_types, - const uint64_t* arg_values, - std::unique_ptr* arg_convertables, - unsigned int flags) override; - uint64_t AddTraceEventWithTimestamp( - char phase, const uint8_t* category_enabled_flag, const char* name, - const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args, - const char** arg_names, const uint8_t* arg_types, - const uint64_t* arg_values, - std::unique_ptr* arg_convertables, - unsigned int flags, int64_t timestamp) override; - void UpdateTraceEventDuration(const uint8_t* category_enabled_flag, - const char* name, uint64_t handle) override; - - static const char* GetCategoryGroupName(const uint8_t* category_enabled_flag); -#endif // !defined(V8_USE_PERFETTO) - - void AddTraceStateObserver( - v8::TracingController::TraceStateObserver* observer) override; - void RemoveTraceStateObserver( - v8::TracingController::TraceStateObserver* observer) override; - - void StartTracing(TraceConfig* trace_config); - void StopTracing(); - - protected: -#if !defined(V8_USE_PERFETTO) - virtual int64_t CurrentTimestampMicroseconds(); - virtual int64_t CurrentCpuTimestampMicroseconds(); -#endif // !defined(V8_USE_PERFETTO) - - private: -#if !defined(V8_USE_PERFETTO) - void UpdateCategoryGroupEnabledFlag(size_t category_index); - void UpdateCategoryGroupEnabledFlags(); -#endif // !defined(V8_USE_PERFETTO) - - std::unique_ptr mutex_; - std::unique_ptr trace_config_; - std::atomic_bool recording_{false}; - std::unordered_set observers_; - -#if defined(V8_USE_PERFETTO) - std::ostream* output_stream_ = nullptr; - std::unique_ptr - trace_processor_; - TraceEventListener* listener_for_testing_ = nullptr; - std::unique_ptr tracing_session_; -#else // !defined(V8_USE_PERFETTO) - std::unique_ptr trace_buffer_; -#endif // !defined(V8_USE_PERFETTO) - - // Disallow copy and assign - TracingController(const TracingController&) = delete; - void operator=(const TracingController&) = delete; -}; - -#undef V8_PLATFORM_NON_EXPORTED_BASE - -} // namespace tracing -} // namespace platform -} // namespace v8 - -#endif // V8_LIBPLATFORM_V8_TRACING_H_ diff --git a/NativeScript/include/v8-array-buffer.h b/NativeScript/include/v8-array-buffer.h deleted file mode 100644 index e9047b79..00000000 --- a/NativeScript/include/v8-array-buffer.h +++ /dev/null @@ -1,433 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_ARRAY_BUFFER_H_ -#define INCLUDE_V8_ARRAY_BUFFER_H_ - -#include - -#include - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-object.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class SharedArrayBuffer; - -#ifndef V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT -// The number of required internal fields can be defined by embedder. -#define V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT 2 -#endif - -enum class ArrayBufferCreationMode { kInternalized, kExternalized }; - -/** - * A wrapper around the backing store (i.e. the raw memory) of an array buffer. - * See a document linked in http://crbug.com/v8/9908 for more information. - * - * The allocation and destruction of backing stores is generally managed by - * V8. Clients should always use standard C++ memory ownership types (i.e. - * std::unique_ptr and std::shared_ptr) to manage lifetimes of backing stores - * properly, since V8 internal objects may alias backing stores. - * - * This object does not keep the underlying |ArrayBuffer::Allocator| alive by - * default. Use Isolate::CreateParams::array_buffer_allocator_shared when - * creating the Isolate to make it hold a reference to the allocator itself. - */ -class V8_EXPORT BackingStore : public v8::internal::BackingStoreBase { - public: - ~BackingStore(); - - /** - * Return a pointer to the beginning of the memory block for this backing - * store. The pointer is only valid as long as this backing store object - * lives. - */ - void* Data() const; - - /** - * The length (in bytes) of this backing store. - */ - size_t ByteLength() const; - - /** - * Indicates whether the backing store was created for an ArrayBuffer or - * a SharedArrayBuffer. - */ - bool IsShared() const; - - /** - * Prevent implicit instantiation of operator delete with size_t argument. - * The size_t argument would be incorrect because ptr points to the - * internal BackingStore object. - */ - void operator delete(void* ptr) { ::operator delete(ptr); } - - /** - * Wrapper around ArrayBuffer::Allocator::Reallocate that preserves IsShared. - * Assumes that the backing_store was allocated by the ArrayBuffer allocator - * of the given isolate. - */ - static std::unique_ptr Reallocate( - v8::Isolate* isolate, std::unique_ptr backing_store, - size_t byte_length); - - /** - * This callback is used only if the memory block for a BackingStore cannot be - * allocated with an ArrayBuffer::Allocator. In such cases the destructor of - * the BackingStore invokes the callback to free the memory block. - */ - using DeleterCallback = void (*)(void* data, size_t length, - void* deleter_data); - - /** - * If the memory block of a BackingStore is static or is managed manually, - * then this empty deleter along with nullptr deleter_data can be passed to - * ArrayBuffer::NewBackingStore to indicate that. - * - * The manually managed case should be used with caution and only when it - * is guaranteed that the memory block freeing happens after detaching its - * ArrayBuffer. - */ - static void EmptyDeleter(void* data, size_t length, void* deleter_data); - - private: - /** - * See [Shared]ArrayBuffer::GetBackingStore and - * [Shared]ArrayBuffer::NewBackingStore. - */ - BackingStore(); -}; - -#if !defined(V8_IMMINENT_DEPRECATION_WARNINGS) -// Use v8::BackingStore::DeleterCallback instead. -using BackingStoreDeleterCallback = void (*)(void* data, size_t length, - void* deleter_data); - -#endif - -/** - * An instance of the built-in ArrayBuffer constructor (ES6 draft 15.13.5). - */ -class V8_EXPORT ArrayBuffer : public Object { - public: - /** - * A thread-safe allocator that V8 uses to allocate |ArrayBuffer|'s memory. - * The allocator is a global V8 setting. It has to be set via - * Isolate::CreateParams. - * - * Memory allocated through this allocator by V8 is accounted for as external - * memory by V8. Note that V8 keeps track of the memory for all internalized - * |ArrayBuffer|s. Responsibility for tracking external memory (using - * Isolate::AdjustAmountOfExternalAllocatedMemory) is handed over to the - * embedder upon externalization and taken over upon internalization (creating - * an internalized buffer from an existing buffer). - * - * Note that it is unsafe to call back into V8 from any of the allocator - * functions. - */ - class V8_EXPORT Allocator { - public: - virtual ~Allocator() = default; - - /** - * Allocate |length| bytes. Return nullptr if allocation is not successful. - * Memory should be initialized to zeroes. - */ - virtual void* Allocate(size_t length) = 0; - - /** - * Allocate |length| bytes. Return nullptr if allocation is not successful. - * Memory does not have to be initialized. - */ - virtual void* AllocateUninitialized(size_t length) = 0; - - /** - * Free the memory block of size |length|, pointed to by |data|. - * That memory is guaranteed to be previously allocated by |Allocate|. - */ - virtual void Free(void* data, size_t length) = 0; - - /** - * Reallocate the memory block of size |old_length| to a memory block of - * size |new_length| by expanding, contracting, or copying the existing - * memory block. If |new_length| > |old_length|, then the new part of - * the memory must be initialized to zeros. Return nullptr if reallocation - * is not successful. - * - * The caller guarantees that the memory block was previously allocated - * using Allocate or AllocateUninitialized. - * - * The default implementation allocates a new block and copies data. - */ - virtual void* Reallocate(void* data, size_t old_length, size_t new_length); - - /** - * ArrayBuffer allocation mode. kNormal is a malloc/free style allocation, - * while kReservation is for larger allocations with the ability to set - * access permissions. - */ - enum class AllocationMode { kNormal, kReservation }; - - /** - * Convenience allocator. - * - * When the sandbox is enabled, this allocator will allocate its backing - * memory inside the sandbox. Otherwise, it will rely on malloc/free. - * - * Caller takes ownership, i.e. the returned object needs to be freed using - * |delete allocator| once it is no longer in use. - */ - static Allocator* NewDefaultAllocator(); - }; - - /** - * Data length in bytes. - */ - size_t ByteLength() const; - - /** - * Create a new ArrayBuffer. Allocate |byte_length| bytes. - * Allocated memory will be owned by a created ArrayBuffer and - * will be deallocated when it is garbage-collected, - * unless the object is externalized. - */ - static Local New(Isolate* isolate, size_t byte_length); - - /** - * Create a new ArrayBuffer with an existing backing store. - * The created array keeps a reference to the backing store until the array - * is garbage collected. Note that the IsExternal bit does not affect this - * reference from the array to the backing store. - * - * In future IsExternal bit will be removed. Until then the bit is set as - * follows. If the backing store does not own the underlying buffer, then - * the array is created in externalized state. Otherwise, the array is created - * in internalized state. In the latter case the array can be transitioned - * to the externalized state using Externalize(backing_store). - */ - static Local New(Isolate* isolate, - std::shared_ptr backing_store); - - /** - * Returns a new standalone BackingStore that is allocated using the array - * buffer allocator of the isolate. The result can be later passed to - * ArrayBuffer::New. - * - * If the allocator returns nullptr, then the function may cause GCs in the - * given isolate and re-try the allocation. If GCs do not help, then the - * function will crash with an out-of-memory error. - */ - static std::unique_ptr NewBackingStore(Isolate* isolate, - size_t byte_length); - /** - * Returns a new standalone BackingStore that takes over the ownership of - * the given buffer. The destructor of the BackingStore invokes the given - * deleter callback. - * - * The result can be later passed to ArrayBuffer::New. The raw pointer - * to the buffer must not be passed again to any V8 API function. - */ - static std::unique_ptr NewBackingStore( - void* data, size_t byte_length, v8::BackingStore::DeleterCallback deleter, - void* deleter_data); - - /** - * Returns true if this ArrayBuffer may be detached. - */ - bool IsDetachable() const; - - /** - * Detaches this ArrayBuffer and all its views (typed arrays). - * Detaching sets the byte length of the buffer and all typed arrays to zero, - * preventing JavaScript from ever accessing underlying backing store. - * ArrayBuffer should have been externalized and must be detachable. - */ - void Detach(); - - /** - * Get a shared pointer to the backing store of this array buffer. This - * pointer coordinates the lifetime management of the internal storage - * with any live ArrayBuffers on the heap, even across isolates. The embedder - * should not attempt to manage lifetime of the storage through other means. - */ - std::shared_ptr GetBackingStore(); - - V8_INLINE static ArrayBuffer* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - static const int kInternalFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT; - static const int kEmbedderFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT; - - private: - ArrayBuffer(); - static void CheckCast(Value* obj); -}; - -#ifndef V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT -// The number of required internal fields can be defined by embedder. -#define V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT 2 -#endif - -/** - * A base class for an instance of one of "views" over ArrayBuffer, - * including TypedArrays and DataView (ES6 draft 15.13). - */ -class V8_EXPORT ArrayBufferView : public Object { - public: - /** - * Returns underlying ArrayBuffer. - */ - Local Buffer(); - /** - * Byte offset in |Buffer|. - */ - size_t ByteOffset(); - /** - * Size of a view in bytes. - */ - size_t ByteLength(); - - /** - * Copy the contents of the ArrayBufferView's buffer to an embedder defined - * memory without additional overhead that calling ArrayBufferView::Buffer - * might incur. - * - * Will write at most min(|byte_length|, ByteLength) bytes starting at - * ByteOffset of the underlying buffer to the memory starting at |dest|. - * Returns the number of bytes actually written. - */ - size_t CopyContents(void* dest, size_t byte_length); - - /** - * Returns true if ArrayBufferView's backing ArrayBuffer has already been - * allocated. - */ - bool HasBuffer() const; - - V8_INLINE static ArrayBufferView* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - static const int kInternalFieldCount = - V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT; - static const int kEmbedderFieldCount = - V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT; - - private: - ArrayBufferView(); - static void CheckCast(Value* obj); -}; - -/** - * An instance of DataView constructor (ES6 draft 15.13.7). - */ -class V8_EXPORT DataView : public ArrayBufferView { - public: - static Local New(Local array_buffer, - size_t byte_offset, size_t length); - static Local New(Local shared_array_buffer, - size_t byte_offset, size_t length); - V8_INLINE static DataView* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - DataView(); - static void CheckCast(Value* obj); -}; - -/** - * An instance of the built-in SharedArrayBuffer constructor. - */ -class V8_EXPORT SharedArrayBuffer : public Object { - public: - /** - * Data length in bytes. - */ - size_t ByteLength() const; - - /** - * Create a new SharedArrayBuffer. Allocate |byte_length| bytes. - * Allocated memory will be owned by a created SharedArrayBuffer and - * will be deallocated when it is garbage-collected, - * unless the object is externalized. - */ - static Local New(Isolate* isolate, size_t byte_length); - - /** - * Create a new SharedArrayBuffer with an existing backing store. - * The created array keeps a reference to the backing store until the array - * is garbage collected. Note that the IsExternal bit does not affect this - * reference from the array to the backing store. - * - * In future IsExternal bit will be removed. Until then the bit is set as - * follows. If the backing store does not own the underlying buffer, then - * the array is created in externalized state. Otherwise, the array is created - * in internalized state. In the latter case the array can be transitioned - * to the externalized state using Externalize(backing_store). - */ - static Local New( - Isolate* isolate, std::shared_ptr backing_store); - - /** - * Returns a new standalone BackingStore that is allocated using the array - * buffer allocator of the isolate. The result can be later passed to - * SharedArrayBuffer::New. - * - * If the allocator returns nullptr, then the function may cause GCs in the - * given isolate and re-try the allocation. If GCs do not help, then the - * function will crash with an out-of-memory error. - */ - static std::unique_ptr NewBackingStore(Isolate* isolate, - size_t byte_length); - /** - * Returns a new standalone BackingStore that takes over the ownership of - * the given buffer. The destructor of the BackingStore invokes the given - * deleter callback. - * - * The result can be later passed to SharedArrayBuffer::New. The raw pointer - * to the buffer must not be passed again to any V8 functions. - */ - static std::unique_ptr NewBackingStore( - void* data, size_t byte_length, v8::BackingStore::DeleterCallback deleter, - void* deleter_data); - - /** - * Get a shared pointer to the backing store of this array buffer. This - * pointer coordinates the lifetime management of the internal storage - * with any live ArrayBuffers on the heap, even across isolates. The embedder - * should not attempt to manage lifetime of the storage through other means. - */ - std::shared_ptr GetBackingStore(); - - V8_INLINE static SharedArrayBuffer* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - static const int kInternalFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT; - - private: - SharedArrayBuffer(); - static void CheckCast(Value* obj); -}; - -} // namespace v8 - -#endif // INCLUDE_V8_ARRAY_BUFFER_H_ diff --git a/NativeScript/include/v8-callbacks.h b/NativeScript/include/v8-callbacks.h deleted file mode 100644 index 70b9c2ae..00000000 --- a/NativeScript/include/v8-callbacks.h +++ /dev/null @@ -1,397 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_ISOLATE_CALLBACKS_H_ -#define INCLUDE_V8_ISOLATE_CALLBACKS_H_ - -#include - -#include - -#include "cppgc/common.h" -#include "v8-data.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -#if defined(V8_OS_WIN) -struct _EXCEPTION_POINTERS; -#endif - -namespace v8 { - -template -class FunctionCallbackInfo; -class Isolate; -class Message; -class Module; -class Object; -class Promise; -class ScriptOrModule; -class String; -class UnboundScript; -class Value; - -/** - * A JIT code event is issued each time code is added, moved or removed. - * - * \note removal events are not currently issued. - */ -struct JitCodeEvent { - enum EventType { - CODE_ADDED, - CODE_MOVED, - CODE_REMOVED, - CODE_ADD_LINE_POS_INFO, - CODE_START_LINE_INFO_RECORDING, - CODE_END_LINE_INFO_RECORDING - }; - // Definition of the code position type. The "POSITION" type means the place - // in the source code which are of interest when making stack traces to - // pin-point the source location of a stack frame as close as possible. - // The "STATEMENT_POSITION" means the place at the beginning of each - // statement, and is used to indicate possible break locations. - enum PositionType { POSITION, STATEMENT_POSITION }; - - // There are three different kinds of CodeType, one for JIT code generated - // by the optimizing compiler, one for byte code generated for the - // interpreter, and one for code generated from Wasm. For JIT_CODE and - // WASM_CODE, |code_start| points to the beginning of jitted assembly code, - // while for BYTE_CODE events, |code_start| points to the first bytecode of - // the interpreted function. - enum CodeType { BYTE_CODE, JIT_CODE, WASM_CODE }; - - // Type of event. - EventType type; - CodeType code_type; - // Start of the instructions. - void* code_start; - // Size of the instructions. - size_t code_len; - // Script info for CODE_ADDED event. - Local script; - // User-defined data for *_LINE_INFO_* event. It's used to hold the source - // code line information which is returned from the - // CODE_START_LINE_INFO_RECORDING event. And it's passed to subsequent - // CODE_ADD_LINE_POS_INFO and CODE_END_LINE_INFO_RECORDING events. - void* user_data; - - struct name_t { - // Name of the object associated with the code, note that the string is not - // zero-terminated. - const char* str; - // Number of chars in str. - size_t len; - }; - - struct line_info_t { - // PC offset - size_t offset; - // Code position - size_t pos; - // The position type. - PositionType position_type; - }; - - struct wasm_source_info_t { - // Source file name. - const char* filename; - // Length of filename. - size_t filename_size; - // Line number table, which maps offsets of JITted code to line numbers of - // source file. - const line_info_t* line_number_table; - // Number of entries in the line number table. - size_t line_number_table_size; - }; - - wasm_source_info_t* wasm_source_info; - - union { - // Only valid for CODE_ADDED. - struct name_t name; - - // Only valid for CODE_ADD_LINE_POS_INFO - struct line_info_t line_info; - - // New location of instructions. Only valid for CODE_MOVED. - void* new_code_start; - }; - - Isolate* isolate; -}; - -/** - * Option flags passed to the SetJitCodeEventHandler function. - */ -enum JitCodeEventOptions { - kJitCodeEventDefault = 0, - // Generate callbacks for already existent code. - kJitCodeEventEnumExisting = 1 -}; - -/** - * Callback function passed to SetJitCodeEventHandler. - * - * \param event code add, move or removal event. - */ -using JitCodeEventHandler = void (*)(const JitCodeEvent* event); - -// --- Garbage Collection Callbacks --- - -/** - * Applications can register callback functions which will be called before and - * after certain garbage collection operations. Allocations are not allowed in - * the callback functions, you therefore cannot manipulate objects (set or - * delete properties for example) since it is possible such operations will - * result in the allocation of objects. - */ -enum GCType { - kGCTypeScavenge = 1 << 0, - kGCTypeMinorMarkCompact = 1 << 1, - kGCTypeMarkSweepCompact = 1 << 2, - kGCTypeIncrementalMarking = 1 << 3, - kGCTypeProcessWeakCallbacks = 1 << 4, - kGCTypeAll = kGCTypeScavenge | kGCTypeMinorMarkCompact | - kGCTypeMarkSweepCompact | kGCTypeIncrementalMarking | - kGCTypeProcessWeakCallbacks -}; - -/** - * GCCallbackFlags is used to notify additional information about the GC - * callback. - * - kGCCallbackFlagConstructRetainedObjectInfos: The GC callback is for - * constructing retained object infos. - * - kGCCallbackFlagForced: The GC callback is for a forced GC for testing. - * - kGCCallbackFlagSynchronousPhantomCallbackProcessing: The GC callback - * is called synchronously without getting posted to an idle task. - * - kGCCallbackFlagCollectAllAvailableGarbage: The GC callback is called - * in a phase where V8 is trying to collect all available garbage - * (e.g., handling a low memory notification). - * - kGCCallbackScheduleIdleGarbageCollection: The GC callback is called to - * trigger an idle garbage collection. - */ -enum GCCallbackFlags { - kNoGCCallbackFlags = 0, - kGCCallbackFlagConstructRetainedObjectInfos = 1 << 1, - kGCCallbackFlagForced = 1 << 2, - kGCCallbackFlagSynchronousPhantomCallbackProcessing = 1 << 3, - kGCCallbackFlagCollectAllAvailableGarbage = 1 << 4, - kGCCallbackFlagCollectAllExternalMemory = 1 << 5, - kGCCallbackScheduleIdleGarbageCollection = 1 << 6, -}; - -using GCCallback = void (*)(GCType type, GCCallbackFlags flags); - -using InterruptCallback = void (*)(Isolate* isolate, void* data); - -/** - * This callback is invoked when the heap size is close to the heap limit and - * V8 is likely to abort with out-of-memory error. - * The callback can extend the heap limit by returning a value that is greater - * than the current_heap_limit. The initial heap limit is the limit that was - * set after heap setup. - */ -using NearHeapLimitCallback = size_t (*)(void* data, size_t current_heap_limit, - size_t initial_heap_limit); - -/** - * Callback function passed to SetUnhandledExceptionCallback. - */ -#if defined(V8_OS_WIN) -using UnhandledExceptionCallback = - int (*)(_EXCEPTION_POINTERS* exception_pointers); -#endif - -// --- Counters Callbacks --- - -using CounterLookupCallback = int* (*)(const char* name); - -using CreateHistogramCallback = void* (*)(const char* name, int min, int max, - size_t buckets); - -using AddHistogramSampleCallback = void (*)(void* histogram, int sample); - -// --- Exceptions --- - -using FatalErrorCallback = void (*)(const char* location, const char* message); - -using OOMErrorCallback = void (*)(const char* location, bool is_heap_oom); - -using MessageCallback = void (*)(Local message, Local data); - -// --- Tracing --- - -enum LogEventStatus : int { kStart = 0, kEnd = 1, kStamp = 2 }; -using LogEventCallback = void (*)(const char* name, - int /* LogEventStatus */ status); - -// --- Crashkeys Callback --- -enum class CrashKeyId { - kIsolateAddress, - kReadonlySpaceFirstPageAddress, - kMapSpaceFirstPageAddress, - kCodeSpaceFirstPageAddress, - kDumpType, -}; - -using AddCrashKeyCallback = void (*)(CrashKeyId id, const std::string& value); - -// --- Enter/Leave Script Callback --- -using BeforeCallEnteredCallback = void (*)(Isolate*); -using CallCompletedCallback = void (*)(Isolate*); - -// --- AllowCodeGenerationFromStrings callbacks --- - -/** - * Callback to check if code generation from strings is allowed. See - * Context::AllowCodeGenerationFromStrings. - */ -using AllowCodeGenerationFromStringsCallback = bool (*)(Local context, - Local source); - -struct ModifyCodeGenerationFromStringsResult { - // If true, proceed with the codegen algorithm. Otherwise, block it. - bool codegen_allowed = false; - // Overwrite the original source with this string, if present. - // Use the original source if empty. - // This field is considered only if codegen_allowed is true. - MaybeLocal modified_source; -}; - -/** - * Access type specification. - */ -enum AccessType { - ACCESS_GET, - ACCESS_SET, - ACCESS_HAS, - ACCESS_DELETE, - ACCESS_KEYS -}; - -// --- Failed Access Check Callback --- - -using FailedAccessCheckCallback = void (*)(Local target, - AccessType type, Local data); - -/** - * Callback to check if codegen is allowed from a source object, and convert - * the source to string if necessary. See: ModifyCodeGenerationFromStrings. - */ -using ModifyCodeGenerationFromStringsCallback = - ModifyCodeGenerationFromStringsResult (*)(Local context, - Local source); -using ModifyCodeGenerationFromStringsCallback2 = - ModifyCodeGenerationFromStringsResult (*)(Local context, - Local source, - bool is_code_like); - -// --- WebAssembly compilation callbacks --- -using ExtensionCallback = bool (*)(const FunctionCallbackInfo&); - -using AllowWasmCodeGenerationCallback = bool (*)(Local context, - Local source); - -// --- Callback for APIs defined on v8-supported objects, but implemented -// by the embedder. Example: WebAssembly.{compile|instantiate}Streaming --- -using ApiImplementationCallback = void (*)(const FunctionCallbackInfo&); - -// --- Callback for WebAssembly.compileStreaming --- -using WasmStreamingCallback = void (*)(const FunctionCallbackInfo&); - -// --- Callback for loading source map file for Wasm profiling support -using WasmLoadSourceMapCallback = Local (*)(Isolate* isolate, - const char* name); - -// --- Callback for checking if WebAssembly Simd is enabled --- -using WasmSimdEnabledCallback = bool (*)(Local context); - -// --- Callback for checking if WebAssembly exceptions are enabled --- -using WasmExceptionsEnabledCallback = bool (*)(Local context); - -// --- Callback for checking if WebAssembly dynamic tiering is enabled --- -using WasmDynamicTieringEnabledCallback = bool (*)(Local context); - -// --- Callback for checking if the SharedArrayBuffer constructor is enabled --- -using SharedArrayBufferConstructorEnabledCallback = - bool (*)(Local context); - -/** - * HostImportModuleDynamicallyCallback is called when we - * require the embedder to load a module. This is used as part of the dynamic - * import syntax. - * - * The referrer contains metadata about the script/module that calls - * import. - * - * The specifier is the name of the module that should be imported. - * - * The import_assertions are import assertions for this request in the form: - * [key1, value1, key2, value2, ...] where the keys and values are of type - * v8::String. Note, unlike the FixedArray passed to ResolveModuleCallback and - * returned from ModuleRequest::GetImportAssertions(), this array does not - * contain the source Locations of the assertions. - * - * The embedder must compile, instantiate, evaluate the Module, and - * obtain its namespace object. - * - * The Promise returned from this function is forwarded to userland - * JavaScript. The embedder must resolve this promise with the module - * namespace object. In case of an exception, the embedder must reject - * this promise with the exception. If the promise creation itself - * fails (e.g. due to stack overflow), the embedder must propagate - * that exception by returning an empty MaybeLocal. - */ -using HostImportModuleDynamicallyWithImportAssertionsCallback = - MaybeLocal (*)(Local context, - Local referrer, - Local specifier, - Local import_assertions); -using HostImportModuleDynamicallyCallback = MaybeLocal (*)( - Local context, Local host_defined_options, - Local resource_name, Local specifier, - Local import_assertions); - -/** - * HostInitializeImportMetaObjectCallback is called the first time import.meta - * is accessed for a module. Subsequent access will reuse the same value. - * - * The method combines two implementation-defined abstract operations into one: - * HostGetImportMetaProperties and HostFinalizeImportMeta. - * - * The embedder should use v8::Object::CreateDataProperty to add properties on - * the meta object. - */ -using HostInitializeImportMetaObjectCallback = void (*)(Local context, - Local module, - Local meta); - -/** - * HostCreateShadowRealmContextCallback is called each time a ShadowRealm is - * being constructed in the initiator_context. - * - * The method combines Context creation and implementation defined abstract - * operation HostInitializeShadowRealm into one. - * - * The embedder should use v8::Context::New or v8::Context:NewFromSnapshot to - * create a new context. If the creation fails, the embedder must propagate - * that exception by returning an empty MaybeLocal. - */ -using HostCreateShadowRealmContextCallback = - MaybeLocal (*)(Local initiator_context); - -/** - * PrepareStackTraceCallback is called when the stack property of an error is - * first accessed. The return value will be used as the stack value. If this - * callback is registed, the |Error.prepareStackTrace| API will be disabled. - * |sites| is an array of call sites, specified in - * https://v8.dev/docs/stack-trace-api - */ -using PrepareStackTraceCallback = MaybeLocal (*)(Local context, - Local error, - Local sites); - -} // namespace v8 - -#endif // INCLUDE_V8_ISOLATE_CALLBACKS_H_ diff --git a/NativeScript/include/v8-container.h b/NativeScript/include/v8-container.h deleted file mode 100644 index ce068603..00000000 --- a/NativeScript/include/v8-container.h +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_CONTAINER_H_ -#define INCLUDE_V8_CONTAINER_H_ - -#include -#include - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-object.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; -class Isolate; - -/** - * An instance of the built-in array constructor (ECMA-262, 15.4.2). - */ -class V8_EXPORT Array : public Object { - public: - uint32_t Length() const; - - /** - * Creates a JavaScript array with the given length. If the length - * is negative the returned array will have length 0. - */ - static Local New(Isolate* isolate, int length = 0); - - /** - * Creates a JavaScript array out of a Local array in C++ - * with a known length. - */ - static Local New(Isolate* isolate, Local* elements, - size_t length); - V8_INLINE static Array* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - Array(); - static void CheckCast(Value* obj); -}; - -/** - * An instance of the built-in Map constructor (ECMA-262, 6th Edition, 23.1.1). - */ -class V8_EXPORT Map : public Object { - public: - size_t Size() const; - void Clear(); - V8_WARN_UNUSED_RESULT MaybeLocal Get(Local context, - Local key); - V8_WARN_UNUSED_RESULT MaybeLocal Set(Local context, - Local key, - Local value); - V8_WARN_UNUSED_RESULT Maybe Has(Local context, - Local key); - V8_WARN_UNUSED_RESULT Maybe Delete(Local context, - Local key); - - /** - * Returns an array of length Size() * 2, where index N is the Nth key and - * index N + 1 is the Nth value. - */ - Local AsArray() const; - - /** - * Creates a new empty Map. - */ - static Local New(Isolate* isolate); - - V8_INLINE static Map* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - Map(); - static void CheckCast(Value* obj); -}; - -/** - * An instance of the built-in Set constructor (ECMA-262, 6th Edition, 23.2.1). - */ -class V8_EXPORT Set : public Object { - public: - size_t Size() const; - void Clear(); - V8_WARN_UNUSED_RESULT MaybeLocal Add(Local context, - Local key); - V8_WARN_UNUSED_RESULT Maybe Has(Local context, - Local key); - V8_WARN_UNUSED_RESULT Maybe Delete(Local context, - Local key); - - /** - * Returns an array of the keys in this Set. - */ - Local AsArray() const; - - /** - * Creates a new empty Set. - */ - static Local New(Isolate* isolate); - - V8_INLINE static Set* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - Set(); - static void CheckCast(Value* obj); -}; - -} // namespace v8 - -#endif // INCLUDE_V8_CONTAINER_H_ diff --git a/NativeScript/include/v8-context.h b/NativeScript/include/v8-context.h deleted file mode 100644 index 72dfbaad..00000000 --- a/NativeScript/include/v8-context.h +++ /dev/null @@ -1,407 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_CONTEXT_H_ -#define INCLUDE_V8_CONTEXT_H_ - -#include - -#include "v8-data.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-snapshot.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Function; -class MicrotaskQueue; -class Object; -class ObjectTemplate; -class Value; -class String; - -/** - * A container for extension names. - */ -class V8_EXPORT ExtensionConfiguration { - public: - ExtensionConfiguration() : name_count_(0), names_(nullptr) {} - ExtensionConfiguration(int name_count, const char* names[]) - : name_count_(name_count), names_(names) {} - - const char** begin() const { return &names_[0]; } - const char** end() const { return &names_[name_count_]; } - - private: - const int name_count_; - const char** names_; -}; - -/** - * A sandboxed execution context with its own set of built-in objects - * and functions. - */ -class V8_EXPORT Context : public Data { - public: - /** - * Returns the global proxy object. - * - * Global proxy object is a thin wrapper whose prototype points to actual - * context's global object with the properties like Object, etc. This is done - * that way for security reasons (for more details see - * https://wiki.mozilla.org/Gecko:SplitWindow). - * - * Please note that changes to global proxy object prototype most probably - * would break VM---v8 expects only global object as a prototype of global - * proxy object. - */ - Local Global(); - - /** - * Detaches the global object from its context before - * the global object can be reused to create a new context. - */ - void DetachGlobal(); - - /** - * Creates a new context and returns a handle to the newly allocated - * context. - * - * \param isolate The isolate in which to create the context. - * - * \param extensions An optional extension configuration containing - * the extensions to be installed in the newly created context. - * - * \param global_template An optional object template from which the - * global object for the newly created context will be created. - * - * \param global_object An optional global object to be reused for - * the newly created context. This global object must have been - * created by a previous call to Context::New with the same global - * template. The state of the global object will be completely reset - * and only object identify will remain. - */ - static Local New( - Isolate* isolate, ExtensionConfiguration* extensions = nullptr, - MaybeLocal global_template = MaybeLocal(), - MaybeLocal global_object = MaybeLocal(), - DeserializeInternalFieldsCallback internal_fields_deserializer = - DeserializeInternalFieldsCallback(), - MicrotaskQueue* microtask_queue = nullptr); - - /** - * Create a new context from a (non-default) context snapshot. There - * is no way to provide a global object template since we do not create - * a new global object from template, but we can reuse a global object. - * - * \param isolate See v8::Context::New. - * - * \param context_snapshot_index The index of the context snapshot to - * deserialize from. Use v8::Context::New for the default snapshot. - * - * \param embedder_fields_deserializer Optional callback to deserialize - * internal fields. It should match the SerializeInternalFieldCallback used - * to serialize. - * - * \param extensions See v8::Context::New. - * - * \param global_object See v8::Context::New. - */ - static MaybeLocal FromSnapshot( - Isolate* isolate, size_t context_snapshot_index, - DeserializeInternalFieldsCallback embedder_fields_deserializer = - DeserializeInternalFieldsCallback(), - ExtensionConfiguration* extensions = nullptr, - MaybeLocal global_object = MaybeLocal(), - MicrotaskQueue* microtask_queue = nullptr); - - /** - * Returns an global object that isn't backed by an actual context. - * - * The global template needs to have access checks with handlers installed. - * If an existing global object is passed in, the global object is detached - * from its context. - * - * Note that this is different from a detached context where all accesses to - * the global proxy will fail. Instead, the access check handlers are invoked. - * - * It is also not possible to detach an object returned by this method. - * Instead, the access check handlers need to return nothing to achieve the - * same effect. - * - * It is possible, however, to create a new context from the global object - * returned by this method. - */ - static MaybeLocal NewRemoteContext( - Isolate* isolate, Local global_template, - MaybeLocal global_object = MaybeLocal()); - - /** - * Sets the security token for the context. To access an object in - * another context, the security tokens must match. - */ - void SetSecurityToken(Local token); - - /** Restores the security token to the default value. */ - void UseDefaultSecurityToken(); - - /** Returns the security token of this context.*/ - Local GetSecurityToken(); - - /** - * Enter this context. After entering a context, all code compiled - * and run is compiled and run in this context. If another context - * is already entered, this old context is saved so it can be - * restored when the new context is exited. - */ - void Enter(); - - /** - * Exit this context. Exiting the current context restores the - * context that was in place when entering the current context. - */ - void Exit(); - - /** Returns the isolate associated with a current context. */ - Isolate* GetIsolate(); - - /** Returns the microtask queue associated with a current context. */ - MicrotaskQueue* GetMicrotaskQueue(); - - /** - * The field at kDebugIdIndex used to be reserved for the inspector. - * It now serves no purpose. - */ - enum EmbedderDataFields { kDebugIdIndex = 0 }; - - /** - * Return the number of fields allocated for embedder data. - */ - uint32_t GetNumberOfEmbedderDataFields(); - - /** - * Gets the embedder data with the given index, which must have been set by a - * previous call to SetEmbedderData with the same index. - */ - V8_INLINE Local GetEmbedderData(int index); - - /** - * Gets the binding object used by V8 extras. Extra natives get a reference - * to this object and can use it to "export" functionality by adding - * properties. Extra natives can also "import" functionality by accessing - * properties added by the embedder using the V8 API. - */ - Local GetExtrasBindingObject(); - - /** - * Sets the embedder data with the given index, growing the data as - * needed. Note that index 0 currently has a special meaning for Chrome's - * debugger. - */ - void SetEmbedderData(int index, Local value); - - /** - * Gets a 2-byte-aligned native pointer from the embedder data with the given - * index, which must have been set by a previous call to - * SetAlignedPointerInEmbedderData with the same index. Note that index 0 - * currently has a special meaning for Chrome's debugger. - */ - V8_INLINE void* GetAlignedPointerFromEmbedderData(int index); - - /** - * Sets a 2-byte-aligned native pointer in the embedder data with the given - * index, growing the data as needed. Note that index 0 currently has a - * special meaning for Chrome's debugger. - */ - void SetAlignedPointerInEmbedderData(int index, void* value); - - /** - * Control whether code generation from strings is allowed. Calling - * this method with false will disable 'eval' and the 'Function' - * constructor for code running in this context. If 'eval' or the - * 'Function' constructor are used an exception will be thrown. - * - * If code generation from strings is not allowed the - * V8::AllowCodeGenerationFromStrings callback will be invoked if - * set before blocking the call to 'eval' or the 'Function' - * constructor. If that callback returns true, the call will be - * allowed, otherwise an exception will be thrown. If no callback is - * set an exception will be thrown. - */ - void AllowCodeGenerationFromStrings(bool allow); - - /** - * Returns true if code generation from strings is allowed for the context. - * For more details see AllowCodeGenerationFromStrings(bool) documentation. - */ - bool IsCodeGenerationFromStringsAllowed() const; - - /** - * Sets the error description for the exception that is thrown when - * code generation from strings is not allowed and 'eval' or the 'Function' - * constructor are called. - */ - void SetErrorMessageForCodeGenerationFromStrings(Local message); - - /** - * Return data that was previously attached to the context snapshot via - * SnapshotCreator, and removes the reference to it. - * Repeated call with the same index returns an empty MaybeLocal. - */ - template - V8_INLINE MaybeLocal GetDataFromSnapshotOnce(size_t index); - - /** - * If callback is set, abort any attempt to execute JavaScript in this - * context, call the specified callback, and throw an exception. - * To unset abort, pass nullptr as callback. - */ - using AbortScriptExecutionCallback = void (*)(Isolate* isolate, - Local context); - void SetAbortScriptExecution(AbortScriptExecutionCallback callback); - - /** - * Returns the value that was set or restored by - * SetContinuationPreservedEmbedderData(), if any. - */ - Local GetContinuationPreservedEmbedderData() const; - - /** - * Sets a value that will be stored on continuations and reset while the - * continuation runs. - */ - void SetContinuationPreservedEmbedderData(Local context); - - /** - * Set or clear hooks to be invoked for promise lifecycle operations. - * To clear a hook, set it to an empty v8::Function. Each function will - * receive the observed promise as the first argument. If a chaining - * operation is used on a promise, the init will additionally receive - * the parent promise as the second argument. - */ - void SetPromiseHooks(Local init_hook, Local before_hook, - Local after_hook, - Local resolve_hook); - - /** - * Stack-allocated class which sets the execution context for all - * operations executed within a local scope. - */ - class V8_NODISCARD Scope { - public: - explicit V8_INLINE Scope(Local context) : context_(context) { - context_->Enter(); - } - V8_INLINE ~Scope() { context_->Exit(); } - - private: - Local context_; - }; - - /** - * Stack-allocated class to support the backup incumbent settings object - * stack. - * https://html.spec.whatwg.org/multipage/webappapis.html#backup-incumbent-settings-object-stack - */ - class V8_EXPORT V8_NODISCARD BackupIncumbentScope final { - public: - /** - * |backup_incumbent_context| is pushed onto the backup incumbent settings - * object stack. - */ - explicit BackupIncumbentScope(Local backup_incumbent_context); - ~BackupIncumbentScope(); - - private: - friend class internal::Isolate; - - uintptr_t JSStackComparableAddressPrivate() const { - return js_stack_comparable_address_; - } - - Local backup_incumbent_context_; - uintptr_t js_stack_comparable_address_ = 0; - const BackupIncumbentScope* prev_ = nullptr; - }; - - V8_INLINE static Context* Cast(Data* data); - - private: - friend class Value; - friend class Script; - friend class Object; - friend class Function; - - static void CheckCast(Data* obj); - - internal::Address* GetDataFromSnapshotOnce(size_t index); - Local SlowGetEmbedderData(int index); - void* SlowGetAlignedPointerFromEmbedderData(int index); -}; - -// --- Implementation --- - -Local Context::GetEmbedderData(int index) { -#ifndef V8_ENABLE_CHECKS - using A = internal::Address; - using I = internal::Internals; - A ctx = *reinterpret_cast(this); - A embedder_data = - I::ReadTaggedPointerField(ctx, I::kNativeContextEmbedderDataOffset); - int value_offset = - I::kEmbedderDataArrayHeaderSize + (I::kEmbedderDataSlotSize * index); - A value = I::ReadRawField(embedder_data, value_offset); -#ifdef V8_COMPRESS_POINTERS - // We read the full pointer value and then decompress it in order to avoid - // dealing with potential endiannes issues. - value = - I::DecompressTaggedAnyField(embedder_data, static_cast(value)); -#endif - internal::Isolate* isolate = internal::IsolateFromNeverReadOnlySpaceObject( - *reinterpret_cast(this)); - A* result = HandleScope::CreateHandle(isolate, value); - return Local(reinterpret_cast(result)); -#else - return SlowGetEmbedderData(index); -#endif -} - -void* Context::GetAlignedPointerFromEmbedderData(int index) { -#if !defined(V8_ENABLE_CHECKS) - using A = internal::Address; - using I = internal::Internals; - A ctx = *reinterpret_cast(this); - A embedder_data = - I::ReadTaggedPointerField(ctx, I::kNativeContextEmbedderDataOffset); - int value_offset = - I::kEmbedderDataArrayHeaderSize + (I::kEmbedderDataSlotSize * index); -#ifdef V8_SANDBOXED_EXTERNAL_POINTERS - value_offset += I::kEmbedderDataSlotRawPayloadOffset; -#endif - internal::Isolate* isolate = I::GetIsolateForSandbox(ctx); - return reinterpret_cast( - I::ReadExternalPointerField(isolate, embedder_data, value_offset, - internal::kEmbedderDataSlotPayloadTag)); -#else - return SlowGetAlignedPointerFromEmbedderData(index); -#endif -} - -template -MaybeLocal Context::GetDataFromSnapshotOnce(size_t index) { - T* data = reinterpret_cast(GetDataFromSnapshotOnce(index)); - if (data) internal::PerformCastCheck(data); - return Local(data); -} - -Context* Context::Cast(v8::Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return static_cast(data); -} - -} // namespace v8 - -#endif // INCLUDE_V8_CONTEXT_H_ diff --git a/NativeScript/include/v8-cppgc.h b/NativeScript/include/v8-cppgc.h deleted file mode 100644 index 41215493..00000000 --- a/NativeScript/include/v8-cppgc.h +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_CPPGC_H_ -#define INCLUDE_V8_CPPGC_H_ - -#include -#include -#include - -#include "cppgc/common.h" -#include "cppgc/custom-space.h" -#include "cppgc/heap-statistics.h" -#include "cppgc/visitor.h" -#include "v8-internal.h" // NOLINT(build/include_directory) -#include "v8-platform.h" // NOLINT(build/include_directory) -#include "v8-traced-handle.h" // NOLINT(build/include_directory) - -namespace cppgc { -class AllocationHandle; -class HeapHandle; -} // namespace cppgc - -namespace v8 { - -class Object; - -namespace internal { -class CppHeap; -} // namespace internal - -class CustomSpaceStatisticsReceiver; - -/** - * Describes how V8 wrapper objects maintain references to garbage-collected C++ - * objects. - */ -struct WrapperDescriptor final { - /** - * The index used on `v8::Ojbect::SetAlignedPointerFromInternalField()` and - * related APIs to add additional data to an object which is used to identify - * JS->C++ references. - */ - using InternalFieldIndex = int; - - /** - * Unknown embedder id. The value is reserved for internal usages and must not - * be used with `CppHeap`. - */ - static constexpr uint16_t kUnknownEmbedderId = UINT16_MAX; - - constexpr WrapperDescriptor(InternalFieldIndex wrappable_type_index, - InternalFieldIndex wrappable_instance_index, - uint16_t embedder_id_for_garbage_collected) - : wrappable_type_index(wrappable_type_index), - wrappable_instance_index(wrappable_instance_index), - embedder_id_for_garbage_collected(embedder_id_for_garbage_collected) {} - - /** - * Index of the wrappable type. - */ - InternalFieldIndex wrappable_type_index; - - /** - * Index of the wrappable instance. - */ - InternalFieldIndex wrappable_instance_index; - - /** - * Embedder id identifying instances of garbage-collected objects. It is - * expected that the first field of the wrappable type is a uint16_t holding - * the id. Only references to instances of wrappables types with an id of - * `embedder_id_for_garbage_collected` will be considered by CppHeap. - */ - uint16_t embedder_id_for_garbage_collected; -}; - -struct V8_EXPORT CppHeapCreateParams { - std::vector> custom_spaces; - WrapperDescriptor wrapper_descriptor; -}; - -/** - * A heap for allocating managed C++ objects. - */ -class V8_EXPORT CppHeap { - public: - static std::unique_ptr Create(v8::Platform* platform, - const CppHeapCreateParams& params); - - virtual ~CppHeap() = default; - - /** - * \returns the opaque handle for allocating objects using - * `MakeGarbageCollected()`. - */ - cppgc::AllocationHandle& GetAllocationHandle(); - - /** - * \returns the opaque heap handle which may be used to refer to this heap in - * other APIs. Valid as long as the underlying `CppHeap` is alive. - */ - cppgc::HeapHandle& GetHeapHandle(); - - /** - * Terminate clears all roots and performs multiple garbage collections to - * reclaim potentially newly created objects in destructors. - * - * After this call, object allocation is prohibited. - */ - void Terminate(); - - /** - * \param detail_level specifies whether should return detailed - * statistics or only brief summary statistics. - * \returns current CppHeap statistics regarding memory consumption - * and utilization. - */ - cppgc::HeapStatistics CollectStatistics( - cppgc::HeapStatistics::DetailLevel detail_level); - - /** - * Collects statistics for the given spaces and reports them to the receiver. - * - * \param custom_spaces a collection of custom space indicies. - * \param receiver an object that gets the results. - */ - void CollectCustomSpaceStatisticsAtLastGC( - std::vector custom_spaces, - std::unique_ptr receiver); - - /** - * Enables a detached mode that allows testing garbage collection using - * `cppgc::testing` APIs. Once used, the heap cannot be attached to an - * `Isolate` anymore. - */ - void EnableDetachedGarbageCollectionsForTesting(); - - /** - * Performs a stop-the-world garbage collection for testing purposes. - * - * \param stack_state The stack state to assume for the garbage collection. - */ - void CollectGarbageForTesting(cppgc::EmbedderStackState stack_state); - - /** - * Performs a stop-the-world minor garbage collection for testing purposes. - * - * \param stack_state The stack state to assume for the garbage collection. - */ - void CollectGarbageInYoungGenerationForTesting( - cppgc::EmbedderStackState stack_state); - - private: - CppHeap() = default; - - friend class internal::CppHeap; -}; - -class JSVisitor : public cppgc::Visitor { - public: - explicit JSVisitor(cppgc::Visitor::Key key) : cppgc::Visitor(key) {} - ~JSVisitor() override = default; - - void Trace(const TracedReferenceBase& ref) { - if (ref.IsEmptyThreadSafe()) return; - Visit(ref); - } - - protected: - using cppgc::Visitor::Visit; - - virtual void Visit(const TracedReferenceBase& ref) {} -}; - -/** - * Provided as input to `CppHeap::CollectCustomSpaceStatisticsAtLastGC()`. - * - * Its method is invoked with the results of the statistic collection. - */ -class CustomSpaceStatisticsReceiver { - public: - virtual ~CustomSpaceStatisticsReceiver() = default; - /** - * Reports the size of a space at the last GC. It is called for each space - * that was requested in `CollectCustomSpaceStatisticsAtLastGC()`. - * - * \param space_index The index of the space. - * \param bytes The total size of live objects in the space at the last GC. - * It is zero if there was no GC yet. - */ - virtual void AllocatedBytes(cppgc::CustomSpaceIndex space_index, - size_t bytes) = 0; -}; - -} // namespace v8 - -namespace cppgc { - -template -struct TraceTrait> { - static cppgc::TraceDescriptor GetTraceDescriptor(const void* self) { - return {nullptr, Trace}; - } - - static void Trace(Visitor* visitor, const void* self) { - static_cast(visitor)->Trace( - *static_cast*>(self)); - } -}; - -} // namespace cppgc - -#endif // INCLUDE_V8_CPPGC_H_ diff --git a/NativeScript/include/v8-data.h b/NativeScript/include/v8-data.h deleted file mode 100644 index cc51fefe..00000000 --- a/NativeScript/include/v8-data.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_DATA_H_ -#define INCLUDE_V8_DATA_H_ - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; - -/** - * The superclass of objects that can reside on V8's heap. - */ -class V8_EXPORT Data { - public: - /** - * Returns true if this data is a |v8::Value|. - */ - bool IsValue() const; - - /** - * Returns true if this data is a |v8::Module|. - */ - bool IsModule() const; - - /** - * Returns tru if this data is a |v8::FixedArray| - */ - bool IsFixedArray() const; - - /** - * Returns true if this data is a |v8::Private|. - */ - bool IsPrivate() const; - - /** - * Returns true if this data is a |v8::ObjectTemplate|. - */ - bool IsObjectTemplate() const; - - /** - * Returns true if this data is a |v8::FunctionTemplate|. - */ - bool IsFunctionTemplate() const; - - /** - * Returns true if this data is a |v8::Context|. - */ - bool IsContext() const; - - private: - Data(); -}; - -/** - * A fixed-sized array with elements of type Data. - */ -class V8_EXPORT FixedArray : public Data { - public: - int Length() const; - Local Get(Local context, int i) const; - - V8_INLINE static FixedArray* Cast(Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return reinterpret_cast(data); - } - - private: - static void CheckCast(Data* obj); -}; - -} // namespace v8 - -#endif // INCLUDE_V8_DATA_H_ diff --git a/NativeScript/include/v8-date.h b/NativeScript/include/v8-date.h deleted file mode 100644 index e7a01f29..00000000 --- a/NativeScript/include/v8-date.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_DATE_H_ -#define INCLUDE_V8_DATE_H_ - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-object.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; - -/** - * An instance of the built-in Date constructor (ECMA-262, 15.9). - */ -class V8_EXPORT Date : public Object { - public: - static V8_WARN_UNUSED_RESULT MaybeLocal New(Local context, - double time); - - /** - * A specialization of Value::NumberValue that is more efficient - * because we know the structure of this object. - */ - double ValueOf() const; - - V8_INLINE static Date* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - static void CheckCast(Value* obj); -}; - -} // namespace v8 - -#endif // INCLUDE_V8_DATE_H_ diff --git a/NativeScript/include/v8-debug.h b/NativeScript/include/v8-debug.h deleted file mode 100644 index 52255f37..00000000 --- a/NativeScript/include/v8-debug.h +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_DEBUG_H_ -#define INCLUDE_V8_DEBUG_H_ - -#include - -#include "v8-script.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Isolate; -class String; - -/** - * A single JavaScript stack frame. - */ -class V8_EXPORT StackFrame { - public: - /** - * Returns the source location, 0-based, for the associated function call. - */ - Location GetLocation() const; - - /** - * Returns the number, 1-based, of the line for the associate function call. - * This method will return Message::kNoLineNumberInfo if it is unable to - * retrieve the line number, or if kLineNumber was not passed as an option - * when capturing the StackTrace. - */ - int GetLineNumber() const { return GetLocation().GetLineNumber() + 1; } - - /** - * Returns the 1-based column offset on the line for the associated function - * call. - * This method will return Message::kNoColumnInfo if it is unable to retrieve - * the column number, or if kColumnOffset was not passed as an option when - * capturing the StackTrace. - */ - int GetColumn() const { return GetLocation().GetColumnNumber() + 1; } - - /** - * Returns the id of the script for the function for this StackFrame. - * This method will return Message::kNoScriptIdInfo if it is unable to - * retrieve the script id, or if kScriptId was not passed as an option when - * capturing the StackTrace. - */ - int GetScriptId() const; - - /** - * Returns the name of the resource that contains the script for the - * function for this StackFrame. - */ - Local GetScriptName() const; - - /** - * Returns the name of the resource that contains the script for the - * function for this StackFrame or sourceURL value if the script name - * is undefined and its source ends with //# sourceURL=... string or - * deprecated //@ sourceURL=... string. - */ - Local GetScriptNameOrSourceURL() const; - - /** - * Returns the source of the script for the function for this StackFrame. - */ - Local GetScriptSource() const; - - /** - * Returns the source mapping URL (if one is present) of the script for - * the function for this StackFrame. - */ - Local GetScriptSourceMappingURL() const; - - /** - * Returns the name of the function associated with this stack frame. - */ - Local GetFunctionName() const; - - /** - * Returns whether or not the associated function is compiled via a call to - * eval(). - */ - bool IsEval() const; - - /** - * Returns whether or not the associated function is called as a - * constructor via "new". - */ - bool IsConstructor() const; - - /** - * Returns whether or not the associated functions is defined in wasm. - */ - bool IsWasm() const; - - /** - * Returns whether or not the associated function is defined by the user. - */ - bool IsUserJavaScript() const; -}; - -/** - * Representation of a JavaScript stack trace. The information collected is a - * snapshot of the execution stack and the information remains valid after - * execution continues. - */ -class V8_EXPORT StackTrace { - public: - /** - * Flags that determine what information is placed captured for each - * StackFrame when grabbing the current stack trace. - * Note: these options are deprecated and we always collect all available - * information (kDetailed). - */ - enum StackTraceOptions { - kLineNumber = 1, - kColumnOffset = 1 << 1 | kLineNumber, - kScriptName = 1 << 2, - kFunctionName = 1 << 3, - kIsEval = 1 << 4, - kIsConstructor = 1 << 5, - kScriptNameOrSourceURL = 1 << 6, - kScriptId = 1 << 7, - kExposeFramesAcrossSecurityOrigins = 1 << 8, - kOverview = kLineNumber | kColumnOffset | kScriptName | kFunctionName, - kDetailed = kOverview | kIsEval | kIsConstructor | kScriptNameOrSourceURL - }; - - /** - * Returns a StackFrame at a particular index. - */ - Local GetFrame(Isolate* isolate, uint32_t index) const; - - /** - * Returns the number of StackFrames. - */ - int GetFrameCount() const; - - /** - * Grab a snapshot of the current JavaScript execution stack. - * - * \param frame_limit The maximum number of stack frames we want to capture. - * \param options Enumerates the set of things we will capture for each - * StackFrame. - */ - static Local CurrentStackTrace( - Isolate* isolate, int frame_limit, StackTraceOptions options = kDetailed); - - /** - * Returns the first valid script name or source URL starting at the top of - * the JS stack. The returned string is either an empty handle if no script - * name/url was found or a non-zero-length string. - * - * This method is equivalent to calling StackTrace::CurrentStackTrace and - * walking the resulting frames from the beginning until a non-empty script - * name/url is found. The difference is that this method won't allocate - * a stack trace. - */ - static Local CurrentScriptNameOrSourceURL(Isolate* isolate); -}; - -} // namespace v8 - -#endif // INCLUDE_V8_DEBUG_H_ diff --git a/NativeScript/include/v8-embedder-heap.h b/NativeScript/include/v8-embedder-heap.h deleted file mode 100644 index 09dbae1f..00000000 --- a/NativeScript/include/v8-embedder-heap.h +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_EMBEDDER_HEAP_H_ -#define INCLUDE_V8_EMBEDDER_HEAP_H_ - -#include -#include - -#include -#include - -#include "cppgc/common.h" -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-traced-handle.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Data; -class Isolate; -class Value; - -namespace internal { -class LocalEmbedderHeapTracer; -} // namespace internal - -/** - * Handler for embedder roots on non-unified heap garbage collections. - */ -class V8_EXPORT EmbedderRootsHandler { - public: - virtual ~EmbedderRootsHandler() = default; - - /** - * Returns true if the |TracedReference| handle should be considered as root - * for the currently running non-tracing garbage collection and false - * otherwise. The default implementation will keep all |TracedReference| - * references as roots. - * - * If this returns false, then V8 may decide that the object referred to by - * such a handle is reclaimed. In that case, V8 calls |ResetRoot()| for the - * |TracedReference|. - * - * Note that the `handle` is different from the handle that the embedder holds - * for retaining the object. The embedder may use |WrapperClassId()| to - * distinguish cases where it wants handles to be treated as roots from not - * being treated as roots. - */ - virtual bool IsRoot(const v8::TracedReference& handle) = 0; - - /** - * Used in combination with |IsRoot|. Called by V8 when an - * object that is backed by a handle is reclaimed by a non-tracing garbage - * collection. It is up to the embedder to reset the original handle. - * - * Note that the |handle| is different from the handle that the embedder holds - * for retaining the object. It is up to the embedder to find the original - * handle via the object or class id. - */ - virtual void ResetRoot(const v8::TracedReference& handle) = 0; -}; - -/** - * Interface for tracing through the embedder heap. During a V8 garbage - * collection, V8 collects hidden fields of all potential wrappers, and at the - * end of its marking phase iterates the collection and asks the embedder to - * trace through its heap and use reporter to report each JavaScript object - * reachable from any of the given wrappers. - */ -class V8_EXPORT EmbedderHeapTracer { - public: - using EmbedderStackState = cppgc::EmbedderStackState; - - enum TraceFlags : uint64_t { - kNoFlags = 0, - kReduceMemory = 1 << 0, - kForced = 1 << 2, - }; - - /** - * Interface for iterating through |TracedReference| handles. - */ - class V8_EXPORT TracedGlobalHandleVisitor { - public: - virtual ~TracedGlobalHandleVisitor() = default; - virtual void VisitTracedReference(const TracedReference& handle) {} - }; - - /** - * Summary of a garbage collection cycle. See |TraceEpilogue| on how the - * summary is reported. - */ - struct TraceSummary { - /** - * Time spent managing the retained memory in milliseconds. This can e.g. - * include the time tracing through objects in the embedder. - */ - double time = 0.0; - - /** - * Memory retained by the embedder through the |EmbedderHeapTracer| - * mechanism in bytes. - */ - size_t allocated_size = 0; - }; - - virtual ~EmbedderHeapTracer() = default; - - /** - * Iterates all |TracedReference| handles created for the |v8::Isolate| the - * tracer is attached to. - */ - void IterateTracedGlobalHandles(TracedGlobalHandleVisitor* visitor); - - /** - * Called by the embedder to set the start of the stack which is e.g. used by - * V8 to determine whether handles are used from stack or heap. - */ - void SetStackStart(void* stack_start); - - /** - * Called by v8 to register internal fields of found wrappers. - * - * The embedder is expected to store them somewhere and trace reachable - * wrappers from them when called through |AdvanceTracing|. - */ - virtual void RegisterV8References( - const std::vector>& embedder_fields) = 0; - - void RegisterEmbedderReference(const BasicTracedReference& ref); - - /** - * Called at the beginning of a GC cycle. - */ - virtual void TracePrologue(TraceFlags flags) {} - - /** - * Called to advance tracing in the embedder. - * - * The embedder is expected to trace its heap starting from wrappers reported - * by RegisterV8References method, and report back all reachable wrappers. - * Furthermore, the embedder is expected to stop tracing by the given - * deadline. A deadline of infinity means that tracing should be finished. - * - * Returns |true| if tracing is done, and false otherwise. - */ - virtual bool AdvanceTracing(double deadline_in_ms) = 0; - - /* - * Returns true if there no more tracing work to be done (see AdvanceTracing) - * and false otherwise. - */ - virtual bool IsTracingDone() = 0; - - /** - * Called at the end of a GC cycle. - * - * Note that allocation is *not* allowed within |TraceEpilogue|. Can be - * overriden to fill a |TraceSummary| that is used by V8 to schedule future - * garbage collections. - */ - virtual void TraceEpilogue(TraceSummary* trace_summary) {} - - /** - * Called upon entering the final marking pause. No more incremental marking - * steps will follow this call. - */ - virtual void EnterFinalPause(EmbedderStackState stack_state) = 0; - - /* - * Called by the embedder to request immediate finalization of the currently - * running tracing phase that has been started with TracePrologue and not - * yet finished with TraceEpilogue. - * - * Will be a noop when currently not in tracing. - * - * This is an experimental feature. - */ - void FinalizeTracing(); - - /** - * See documentation on EmbedderRootsHandler. - */ - virtual bool IsRootForNonTracingGC( - const v8::TracedReference& handle); - - /** - * See documentation on EmbedderRootsHandler. - */ - virtual void ResetHandleInNonTracingGC( - const v8::TracedReference& handle); - - /* - * Called by the embedder to signal newly allocated or freed memory. Not bound - * to tracing phases. Embedders should trade off when increments are reported - * as V8 may consult global heuristics on whether to trigger garbage - * collection on this change. - */ - void IncreaseAllocatedSize(size_t bytes); - void DecreaseAllocatedSize(size_t bytes); - - /* - * Returns the v8::Isolate this tracer is attached too and |nullptr| if it - * is not attached to any v8::Isolate. - */ - v8::Isolate* isolate() const { return isolate_; } - - protected: - v8::Isolate* isolate_ = nullptr; - - friend class internal::LocalEmbedderHeapTracer; -}; - -} // namespace v8 - -#endif // INCLUDE_V8_EMBEDDER_HEAP_H_ diff --git a/NativeScript/include/v8-embedder-state-scope.h b/NativeScript/include/v8-embedder-state-scope.h deleted file mode 100644 index d8a3b08d..00000000 --- a/NativeScript/include/v8-embedder-state-scope.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_EMBEDDER_STATE_SCOPE_H_ -#define INCLUDE_V8_EMBEDDER_STATE_SCOPE_H_ - -#include - -#include "v8-context.h" // NOLINT(build/include_directory) -#include "v8-internal.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) - -namespace v8 { - -namespace internal { -class EmbedderState; -} // namespace internal - -// A StateTag represents a possible state of the embedder. -enum class EmbedderStateTag : uint8_t { - // reserved - EMPTY = 0, - OTHER = 1, - // embedder can define any state after -}; - -// A stack-allocated class that manages an embedder state on the isolate. -// After an EmbedderState scope has been created, a new embedder state will be -// pushed on the isolate stack. -class V8_EXPORT EmbedderStateScope { - public: - EmbedderStateScope(Isolate* isolate, Local context, - EmbedderStateTag tag); - - ~EmbedderStateScope(); - - private: - // Declaring operator new and delete as deleted is not spec compliant. - // Therefore declare them private instead to disable dynamic alloc - void* operator new(size_t size); - void* operator new[](size_t size); - void operator delete(void*, size_t); - void operator delete[](void*, size_t); - - std::unique_ptr embedder_state_; -}; - -} // namespace v8 - -#endif // INCLUDE_V8_EMBEDDER_STATE_SCOPE_H_ diff --git a/NativeScript/include/v8-exception.h b/NativeScript/include/v8-exception.h deleted file mode 100644 index 64126c42..00000000 --- a/NativeScript/include/v8-exception.h +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_EXCEPTION_H_ -#define INCLUDE_V8_EXCEPTION_H_ - -#include - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; -class Isolate; -class Message; -class StackTrace; -class String; -class Value; - -namespace internal { -class Isolate; -class ThreadLocalTop; -} // namespace internal - -/** - * Create new error objects by calling the corresponding error object - * constructor with the message. - */ -class V8_EXPORT Exception { - public: - static Local RangeError(Local message); - static Local ReferenceError(Local message); - static Local SyntaxError(Local message); - static Local TypeError(Local message); - static Local WasmCompileError(Local message); - static Local WasmLinkError(Local message); - static Local WasmRuntimeError(Local message); - static Local Error(Local message); - - /** - * Creates an error message for the given exception. - * Will try to reconstruct the original stack trace from the exception value, - * or capture the current stack trace if not available. - */ - static Local CreateMessage(Isolate* isolate, Local exception); - - /** - * Returns the original stack trace that was captured at the creation time - * of a given exception, or an empty handle if not available. - */ - static Local GetStackTrace(Local exception); -}; - -/** - * An external exception handler. - */ -class V8_EXPORT TryCatch { - public: - /** - * Creates a new try/catch block and registers it with v8. Note that - * all TryCatch blocks should be stack allocated because the memory - * location itself is compared against JavaScript try/catch blocks. - */ - explicit TryCatch(Isolate* isolate); - - /** - * Unregisters and deletes this try/catch block. - */ - ~TryCatch(); - - /** - * Returns true if an exception has been caught by this try/catch block. - */ - bool HasCaught() const; - - /** - * For certain types of exceptions, it makes no sense to continue execution. - * - * If CanContinue returns false, the correct action is to perform any C++ - * cleanup needed and then return. If CanContinue returns false and - * HasTerminated returns true, it is possible to call - * CancelTerminateExecution in order to continue calling into the engine. - */ - bool CanContinue() const; - - /** - * Returns true if an exception has been caught due to script execution - * being terminated. - * - * There is no JavaScript representation of an execution termination - * exception. Such exceptions are thrown when the TerminateExecution - * methods are called to terminate a long-running script. - * - * If such an exception has been thrown, HasTerminated will return true, - * indicating that it is possible to call CancelTerminateExecution in order - * to continue calling into the engine. - */ - bool HasTerminated() const; - - /** - * Throws the exception caught by this TryCatch in a way that avoids - * it being caught again by this same TryCatch. As with ThrowException - * it is illegal to execute any JavaScript operations after calling - * ReThrow; the caller must return immediately to where the exception - * is caught. - */ - Local ReThrow(); - - /** - * Returns the exception caught by this try/catch block. If no exception has - * been caught an empty handle is returned. - */ - Local Exception() const; - - /** - * Returns the .stack property of an object. If no .stack - * property is present an empty handle is returned. - */ - V8_WARN_UNUSED_RESULT static MaybeLocal StackTrace( - Local context, Local exception); - - /** - * Returns the .stack property of the thrown object. If no .stack property is - * present or if this try/catch block has not caught an exception, an empty - * handle is returned. - */ - V8_WARN_UNUSED_RESULT MaybeLocal StackTrace( - Local context) const; - - /** - * Returns the message associated with this exception. If there is - * no message associated an empty handle is returned. - */ - Local Message() const; - - /** - * Clears any exceptions that may have been caught by this try/catch block. - * After this method has been called, HasCaught() will return false. Cancels - * the scheduled exception if it is caught and ReThrow() is not called before. - * - * It is not necessary to clear a try/catch block before using it again; if - * another exception is thrown the previously caught exception will just be - * overwritten. However, it is often a good idea since it makes it easier - * to determine which operation threw a given exception. - */ - void Reset(); - - /** - * Set verbosity of the external exception handler. - * - * By default, exceptions that are caught by an external exception - * handler are not reported. Call SetVerbose with true on an - * external exception handler to have exceptions caught by the - * handler reported as if they were not caught. - */ - void SetVerbose(bool value); - - /** - * Returns true if verbosity is enabled. - */ - bool IsVerbose() const; - - /** - * Set whether or not this TryCatch should capture a Message object - * which holds source information about where the exception - * occurred. True by default. - */ - void SetCaptureMessage(bool value); - - TryCatch(const TryCatch&) = delete; - void operator=(const TryCatch&) = delete; - - private: - // Declaring operator new and delete as deleted is not spec compliant. - // Therefore declare them private instead to disable dynamic alloc - void* operator new(size_t size); - void* operator new[](size_t size); - void operator delete(void*, size_t); - void operator delete[](void*, size_t); - - /** - * There are cases when the raw address of C++ TryCatch object cannot be - * used for comparisons with addresses into the JS stack. The cases are: - * 1) ARM, ARM64 and MIPS simulators which have separate JS stack. - * 2) Address sanitizer allocates local C++ object in the heap when - * UseAfterReturn mode is enabled. - * This method returns address that can be used for comparisons with - * addresses into the JS stack. When neither simulator nor ASAN's - * UseAfterReturn is enabled, then the address returned will be the address - * of the C++ try catch handler itself. - */ - internal::Address JSStackComparableAddressPrivate() { - return js_stack_comparable_address_; - } - - void ResetInternal(); - - internal::Isolate* isolate_; - TryCatch* next_; - void* exception_; - void* message_obj_; - internal::Address js_stack_comparable_address_; - bool is_verbose_ : 1; - bool can_continue_ : 1; - bool capture_message_ : 1; - bool rethrow_ : 1; - bool has_terminated_ : 1; - - friend class internal::Isolate; - friend class internal::ThreadLocalTop; -}; - -} // namespace v8 - -#endif // INCLUDE_V8_EXCEPTION_H_ diff --git a/NativeScript/include/v8-extension.h b/NativeScript/include/v8-extension.h deleted file mode 100644 index 0705e2af..00000000 --- a/NativeScript/include/v8-extension.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_EXTENSION_H_ -#define INCLUDE_V8_EXTENSION_H_ - -#include - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-primitive.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class FunctionTemplate; - -// --- Extensions --- - -/** - * Ignore - */ -class V8_EXPORT Extension { - public: - // Note that the strings passed into this constructor must live as long - // as the Extension itself. - Extension(const char* name, const char* source = nullptr, int dep_count = 0, - const char** deps = nullptr, int source_length = -1); - virtual ~Extension() { delete source_; } - virtual Local GetNativeFunctionTemplate( - Isolate* isolate, Local name) { - return Local(); - } - - const char* name() const { return name_; } - size_t source_length() const { return source_length_; } - const String::ExternalOneByteStringResource* source() const { - return source_; - } - int dependency_count() const { return dep_count_; } - const char** dependencies() const { return deps_; } - void set_auto_enable(bool value) { auto_enable_ = value; } - bool auto_enable() { return auto_enable_; } - - // Disallow copying and assigning. - Extension(const Extension&) = delete; - void operator=(const Extension&) = delete; - - private: - const char* name_; - size_t source_length_; // expected to initialize before source_ - String::ExternalOneByteStringResource* source_; - int dep_count_; - const char** deps_; - bool auto_enable_; -}; - -void V8_EXPORT RegisterExtension(std::unique_ptr); - -} // namespace v8 - -#endif // INCLUDE_V8_EXTENSION_H_ diff --git a/NativeScript/include/v8-external.h b/NativeScript/include/v8-external.h deleted file mode 100644 index 2e245036..00000000 --- a/NativeScript/include/v8-external.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_EXTERNAL_H_ -#define INCLUDE_V8_EXTERNAL_H_ - -#include "v8-value.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Isolate; - -/** - * A JavaScript value that wraps a C++ void*. This type of value is mainly used - * to associate C++ data structures with JavaScript objects. - */ -class V8_EXPORT External : public Value { - public: - static Local New(Isolate* isolate, void* value); - V8_INLINE static External* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - void* Value() const; - - private: - static void CheckCast(v8::Value* obj); -}; - -} // namespace v8 - -#endif // INCLUDE_V8_EXTERNAL_H_ diff --git a/NativeScript/include/v8-fast-api-calls.h b/NativeScript/include/v8-fast-api-calls.h deleted file mode 100644 index 3403de93..00000000 --- a/NativeScript/include/v8-fast-api-calls.h +++ /dev/null @@ -1,939 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * This file provides additional API on top of the default one for making - * API calls, which come from embedder C++ functions. The functions are being - * called directly from optimized code, doing all the necessary typechecks - * in the compiler itself, instead of on the embedder side. Hence the "fast" - * in the name. Example usage might look like: - * - * \code - * void FastMethod(int param, bool another_param); - * - * v8::FunctionTemplate::New(isolate, SlowCallback, data, - * signature, length, constructor_behavior - * side_effect_type, - * &v8::CFunction::Make(FastMethod)); - * \endcode - * - * By design, fast calls are limited by the following requirements, which - * the embedder should enforce themselves: - * - they should not allocate on the JS heap; - * - they should not trigger JS execution. - * To enforce them, the embedder could use the existing - * v8::Isolate::DisallowJavascriptExecutionScope and a utility similar to - * Blink's NoAllocationScope: - * https://source.chromium.org/chromium/chromium/src/+/master:third_party/blink/renderer/platform/heap/thread_state_scopes.h;l=16 - * - * Due to these limitations, it's not directly possible to report errors by - * throwing a JS exception or to otherwise do an allocation. There is an - * alternative way of creating fast calls that supports falling back to the - * slow call and then performing the necessary allocation. When one creates - * the fast method by using CFunction::MakeWithFallbackSupport instead of - * CFunction::Make, the fast callback gets as last parameter an output variable, - * through which it can request falling back to the slow call. So one might - * declare their method like: - * - * \code - * void FastMethodWithFallback(int param, FastApiCallbackOptions& options); - * \endcode - * - * If the callback wants to signal an error condition or to perform an - * allocation, it must set options.fallback to true and do an early return from - * the fast method. Then V8 checks the value of options.fallback and if it's - * true, falls back to executing the SlowCallback, which is capable of reporting - * the error (either by throwing a JS exception or logging to the console) or - * doing the allocation. It's the embedder's responsibility to ensure that the - * fast callback is idempotent up to the point where error and fallback - * conditions are checked, because otherwise executing the slow callback might - * produce visible side-effects twice. - * - * An example for custom embedder type support might employ a way to wrap/ - * unwrap various C++ types in JSObject instances, e.g: - * - * \code - * - * // Helper method with a check for field count. - * template - * inline T* GetInternalField(v8::Local wrapper) { - * assert(offset < wrapper->InternalFieldCount()); - * return reinterpret_cast( - * wrapper->GetAlignedPointerFromInternalField(offset)); - * } - * - * class CustomEmbedderType { - * public: - * // Returns the raw C object from a wrapper JS object. - * static CustomEmbedderType* Unwrap(v8::Local wrapper) { - * return GetInternalField(wrapper); - * } - * static void FastMethod(v8::Local receiver_obj, int param) { - * CustomEmbedderType* receiver = static_cast( - * receiver_obj->GetAlignedPointerFromInternalField( - * kV8EmbedderWrapperObjectIndex)); - * - * // Type checks are already done by the optimized code. - * // Then call some performance-critical method like: - * // receiver->Method(param); - * } - * - * static void SlowMethod( - * const v8::FunctionCallbackInfo& info) { - * v8::Local instance = - * v8::Local::Cast(info.Holder()); - * CustomEmbedderType* receiver = Unwrap(instance); - * // TODO: Do type checks and extract {param}. - * receiver->Method(param); - * } - * }; - * - * // TODO(mslekova): Clean-up these constants - * // The constants kV8EmbedderWrapperTypeIndex and - * // kV8EmbedderWrapperObjectIndex describe the offsets for the type info - * // struct and the native object, when expressed as internal field indices - * // within a JSObject. The existance of this helper function assumes that - * // all embedder objects have their JSObject-side type info at the same - * // offset, but this is not a limitation of the API itself. For a detailed - * // use case, see the third example. - * static constexpr int kV8EmbedderWrapperTypeIndex = 0; - * static constexpr int kV8EmbedderWrapperObjectIndex = 1; - * - * // The following setup function can be templatized based on - * // the {embedder_object} argument. - * void SetupCustomEmbedderObject(v8::Isolate* isolate, - * v8::Local context, - * CustomEmbedderType* embedder_object) { - * isolate->set_embedder_wrapper_type_index( - * kV8EmbedderWrapperTypeIndex); - * isolate->set_embedder_wrapper_object_index( - * kV8EmbedderWrapperObjectIndex); - * - * v8::CFunction c_func = - * MakeV8CFunction(CustomEmbedderType::FastMethod); - * - * Local method_template = - * v8::FunctionTemplate::New( - * isolate, CustomEmbedderType::SlowMethod, v8::Local(), - * v8::Local(), 1, v8::ConstructorBehavior::kAllow, - * v8::SideEffectType::kHasSideEffect, &c_func); - * - * v8::Local object_template = - * v8::ObjectTemplate::New(isolate); - * object_template->SetInternalFieldCount( - * kV8EmbedderWrapperObjectIndex + 1); - * object_template->Set(isolate, "method", method_template); - * - * // Instantiate the wrapper JS object. - * v8::Local object = - * object_template->NewInstance(context).ToLocalChecked(); - * object->SetAlignedPointerInInternalField( - * kV8EmbedderWrapperObjectIndex, - * reinterpret_cast(embedder_object)); - * - * // TODO: Expose {object} where it's necessary. - * } - * \endcode - * - * For instance if {object} is exposed via a global "obj" variable, - * one could write in JS: - * function hot_func() { - * obj.method(42); - * } - * and once {hot_func} gets optimized, CustomEmbedderType::FastMethod - * will be called instead of the slow version, with the following arguments: - * receiver := the {embedder_object} from above - * param := 42 - * - * Currently supported return types: - * - void - * - bool - * - int32_t - * - uint32_t - * - float32_t - * - float64_t - * Currently supported argument types: - * - pointer to an embedder type - * - JavaScript array of primitive types - * - bool - * - int32_t - * - uint32_t - * - int64_t - * - uint64_t - * - float32_t - * - float64_t - * - * The 64-bit integer types currently have the IDL (unsigned) long long - * semantics: https://heycam.github.io/webidl/#abstract-opdef-converttoint - * In the future we'll extend the API to also provide conversions from/to - * BigInt to preserve full precision. - * The floating point types currently have the IDL (unrestricted) semantics, - * which is the only one used by WebGL. We plan to add support also for - * restricted floats/doubles, similarly to the BigInt conversion policies. - * We also differ from the specific NaN bit pattern that WebIDL prescribes - * (https://heycam.github.io/webidl/#es-unrestricted-float) in that Blink - * passes NaN values as-is, i.e. doesn't normalize them. - * - * To be supported types: - * - TypedArrays and ArrayBuffers - * - arrays of embedder types - * - * - * The API offers a limited support for function overloads: - * - * \code - * void FastMethod_2Args(int param, bool another_param); - * void FastMethod_3Args(int param, bool another_param, int third_param); - * - * v8::CFunction fast_method_2args_c_func = - * MakeV8CFunction(FastMethod_2Args); - * v8::CFunction fast_method_3args_c_func = - * MakeV8CFunction(FastMethod_3Args); - * const v8::CFunction fast_method_overloads[] = {fast_method_2args_c_func, - * fast_method_3args_c_func}; - * Local method_template = - * v8::FunctionTemplate::NewWithCFunctionOverloads( - * isolate, SlowCallback, data, signature, length, - * constructor_behavior, side_effect_type, - * {fast_method_overloads, 2}); - * \endcode - * - * In this example a single FunctionTemplate is associated to multiple C++ - * functions. The overload resolution is currently only based on the number of - * arguments passed in a call. For example, if this method_template is - * registered with a wrapper JS object as described above, a call with two - * arguments: - * obj.method(42, true); - * will result in a fast call to FastMethod_2Args, while a call with three or - * more arguments: - * obj.method(42, true, 11); - * will result in a fast call to FastMethod_3Args. Instead a call with less than - * two arguments, like: - * obj.method(42); - * would not result in a fast call but would fall back to executing the - * associated SlowCallback. - */ - -#ifndef INCLUDE_V8_FAST_API_CALLS_H_ -#define INCLUDE_V8_FAST_API_CALLS_H_ - -#include -#include - -#include -#include - -#include "v8-internal.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-typed-array.h" // NOLINT(build/include_directory) -#include "v8-value.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Isolate; - -class CTypeInfo { - public: - enum class Type : uint8_t { - kVoid, - kBool, - kInt32, - kUint32, - kInt64, - kUint64, - kFloat32, - kFloat64, - kV8Value, - kApiObject, // This will be deprecated once all users have - // migrated from v8::ApiObject to v8::Local. - kAny, // This is added to enable untyped representation of fast - // call arguments for test purposes. It can represent any of - // the other types stored in the same memory as a union (see - // the AnyCType struct declared below). This allows for - // uniform passing of arguments w.r.t. their location - // (in a register or on the stack), independent of their - // actual type. It's currently used by the arm64 simulator - // and can be added to the other simulators as well when fast - // calls having both GP and FP params need to be supported. - }; - - // kCallbackOptionsType is not part of the Type enum - // because it is only used internally. Use value 255 that is larger - // than any valid Type enum. - static constexpr Type kCallbackOptionsType = Type(255); - - enum class SequenceType : uint8_t { - kScalar, - kIsSequence, // sequence - kIsTypedArray, // TypedArray of T or any ArrayBufferView if T - // is void - kIsArrayBuffer // ArrayBuffer - }; - - enum class Flags : uint8_t { - kNone = 0, - kAllowSharedBit = 1 << 0, // Must be an ArrayBuffer or TypedArray - kEnforceRangeBit = 1 << 1, // T must be integral - kClampBit = 1 << 2, // T must be integral - kIsRestrictedBit = 1 << 3, // T must be float or double - }; - - explicit constexpr CTypeInfo( - Type type, SequenceType sequence_type = SequenceType::kScalar, - Flags flags = Flags::kNone) - : type_(type), sequence_type_(sequence_type), flags_(flags) {} - - typedef uint32_t Identifier; - explicit constexpr CTypeInfo(Identifier identifier) - : CTypeInfo(static_cast(identifier >> 16), - static_cast((identifier >> 8) & 255), - static_cast(identifier & 255)) {} - constexpr Identifier GetId() const { - return static_cast(type_) << 16 | - static_cast(sequence_type_) << 8 | - static_cast(flags_); - } - - constexpr Type GetType() const { return type_; } - constexpr SequenceType GetSequenceType() const { return sequence_type_; } - constexpr Flags GetFlags() const { return flags_; } - - static constexpr bool IsIntegralType(Type type) { - return type == Type::kInt32 || type == Type::kUint32 || - type == Type::kInt64 || type == Type::kUint64; - } - - static constexpr bool IsFloatingPointType(Type type) { - return type == Type::kFloat32 || type == Type::kFloat64; - } - - static constexpr bool IsPrimitive(Type type) { - return IsIntegralType(type) || IsFloatingPointType(type) || - type == Type::kBool; - } - - private: - Type type_; - SequenceType sequence_type_; - Flags flags_; -}; - -struct FastApiTypedArrayBase { - public: - // Returns the length in number of elements. - size_t V8_EXPORT length() const { return length_; } - // Checks whether the given index is within the bounds of the collection. - void V8_EXPORT ValidateIndex(size_t index) const; - - protected: - size_t length_ = 0; -}; - -template -struct FastApiTypedArray : public FastApiTypedArrayBase { - public: - V8_INLINE T get(size_t index) const { -#ifdef DEBUG - ValidateIndex(index); -#endif // DEBUG - T tmp; - memcpy(&tmp, reinterpret_cast(data_) + index, sizeof(T)); - return tmp; - } - - bool getStorageIfAligned(T** elements) const { - if (reinterpret_cast(data_) % alignof(T) != 0) { - return false; - } - *elements = reinterpret_cast(data_); - return true; - } - - private: - // This pointer should include the typed array offset applied. - // It's not guaranteed that it's aligned to sizeof(T), it's only - // guaranteed that it's 4-byte aligned, so for 8-byte types we need to - // provide a special implementation for reading from it, which hides - // the possibly unaligned read in the `get` method. - void* data_; -}; - -// Any TypedArray. It uses kTypedArrayBit with base type void -// Overloaded args of ArrayBufferView and TypedArray are not supported -// (for now) because the generic “any” ArrayBufferView doesn’t have its -// own instance type. It could be supported if we specify that -// TypedArray always has precedence over the generic ArrayBufferView, -// but this complicates overload resolution. -struct FastApiArrayBufferView { - void* data; - size_t byte_length; -}; - -struct FastApiArrayBuffer { - void* data; - size_t byte_length; -}; - -class V8_EXPORT CFunctionInfo { - public: - // Construct a struct to hold a CFunction's type information. - // |return_info| describes the function's return type. - // |arg_info| is an array of |arg_count| CTypeInfos describing the - // arguments. Only the last argument may be of the special type - // CTypeInfo::kCallbackOptionsType. - CFunctionInfo(const CTypeInfo& return_info, unsigned int arg_count, - const CTypeInfo* arg_info); - - const CTypeInfo& ReturnInfo() const { return return_info_; } - - // The argument count, not including the v8::FastApiCallbackOptions - // if present. - unsigned int ArgumentCount() const { - return HasOptions() ? arg_count_ - 1 : arg_count_; - } - - // |index| must be less than ArgumentCount(). - // Note: if the last argument passed on construction of CFunctionInfo - // has type CTypeInfo::kCallbackOptionsType, it is not included in - // ArgumentCount(). - const CTypeInfo& ArgumentInfo(unsigned int index) const; - - bool HasOptions() const { - // The options arg is always the last one. - return arg_count_ > 0 && arg_info_[arg_count_ - 1].GetType() == - CTypeInfo::kCallbackOptionsType; - } - - private: - const CTypeInfo return_info_; - const unsigned int arg_count_; - const CTypeInfo* arg_info_; -}; - -struct FastApiCallbackOptions; - -// Provided for testing. -struct AnyCType { - AnyCType() : int64_value(0) {} - - union { - bool bool_value; - int32_t int32_value; - uint32_t uint32_value; - int64_t int64_value; - uint64_t uint64_value; - float float_value; - double double_value; - Local object_value; - Local sequence_value; - const FastApiTypedArray* int32_ta_value; - const FastApiTypedArray* uint32_ta_value; - const FastApiTypedArray* int64_ta_value; - const FastApiTypedArray* uint64_ta_value; - const FastApiTypedArray* float_ta_value; - const FastApiTypedArray* double_ta_value; - FastApiCallbackOptions* options_value; - }; -}; - -static_assert( - sizeof(AnyCType) == 8, - "The AnyCType struct should have size == 64 bits, as this is assumed " - "by EffectControlLinearizer."); - -class V8_EXPORT CFunction { - public: - constexpr CFunction() : address_(nullptr), type_info_(nullptr) {} - - const CTypeInfo& ReturnInfo() const { return type_info_->ReturnInfo(); } - - const CTypeInfo& ArgumentInfo(unsigned int index) const { - return type_info_->ArgumentInfo(index); - } - - unsigned int ArgumentCount() const { return type_info_->ArgumentCount(); } - - const void* GetAddress() const { return address_; } - const CFunctionInfo* GetTypeInfo() const { return type_info_; } - - enum class OverloadResolution { kImpossible, kAtRuntime, kAtCompileTime }; - - // Returns whether an overload between this and the given CFunction can - // be resolved at runtime by the RTTI available for the arguments or at - // compile time for functions with different number of arguments. - OverloadResolution GetOverloadResolution(const CFunction* other) { - // Runtime overload resolution can only deal with functions with the - // same number of arguments. Functions with different arity are handled - // by compile time overload resolution though. - if (ArgumentCount() != other->ArgumentCount()) { - return OverloadResolution::kAtCompileTime; - } - - // The functions can only differ by a single argument position. - int diff_index = -1; - for (unsigned int i = 0; i < ArgumentCount(); ++i) { - if (ArgumentInfo(i).GetSequenceType() != - other->ArgumentInfo(i).GetSequenceType()) { - if (diff_index >= 0) { - return OverloadResolution::kImpossible; - } - diff_index = i; - - // We only support overload resolution between sequence types. - if (ArgumentInfo(i).GetSequenceType() == - CTypeInfo::SequenceType::kScalar || - other->ArgumentInfo(i).GetSequenceType() == - CTypeInfo::SequenceType::kScalar) { - return OverloadResolution::kImpossible; - } - } - } - - return OverloadResolution::kAtRuntime; - } - - template - static CFunction Make(F* func) { - return ArgUnwrap::Make(func); - } - - // Provided for testing purposes. - template - static CFunction Make(R (*func)(Args...), - R_Patch (*patching_func)(Args_Patch...)) { - CFunction c_func = ArgUnwrap::Make(func); - static_assert( - sizeof...(Args_Patch) == sizeof...(Args), - "The patching function must have the same number of arguments."); - c_func.address_ = reinterpret_cast(patching_func); - return c_func; - } - - CFunction(const void* address, const CFunctionInfo* type_info); - - private: - const void* address_; - const CFunctionInfo* type_info_; - - template - class ArgUnwrap { - static_assert(sizeof(F) != sizeof(F), - "CFunction must be created from a function pointer."); - }; - - template - class ArgUnwrap { - public: - static CFunction Make(R (*func)(Args...)); - }; -}; - -/** - * A struct which may be passed to a fast call callback, like so: - * \code - * void FastMethodWithOptions(int param, FastApiCallbackOptions& options); - * \endcode - */ -struct FastApiCallbackOptions { - /** - * Creates a new instance of FastApiCallbackOptions for testing purpose. The - * returned instance may be filled with mock data. - */ - static FastApiCallbackOptions CreateForTesting(Isolate* isolate) { - return {false, {0}}; - } - - /** - * If the callback wants to signal an error condition or to perform an - * allocation, it must set options.fallback to true and do an early return - * from the fast method. Then V8 checks the value of options.fallback and if - * it's true, falls back to executing the SlowCallback, which is capable of - * reporting the error (either by throwing a JS exception or logging to the - * console) or doing the allocation. It's the embedder's responsibility to - * ensure that the fast callback is idempotent up to the point where error and - * fallback conditions are checked, because otherwise executing the slow - * callback might produce visible side-effects twice. - */ - bool fallback; - - /** - * The `data` passed to the FunctionTemplate constructor, or `undefined`. - * `data_ptr` allows for default constructing FastApiCallbackOptions. - */ - union { - uintptr_t data_ptr; - v8::Value data; - }; -}; - -namespace internal { - -// Helper to count the number of occurances of `T` in `List` -template -struct count : std::integral_constant {}; -template -struct count - : std::integral_constant::value> {}; -template -struct count : count {}; - -template -class CFunctionInfoImpl : public CFunctionInfo { - static constexpr int kOptionsArgCount = - count(); - static constexpr int kReceiverCount = 1; - - static_assert(kOptionsArgCount == 0 || kOptionsArgCount == 1, - "Only one options parameter is supported."); - - static_assert(sizeof...(ArgBuilders) >= kOptionsArgCount + kReceiverCount, - "The receiver or the options argument is missing."); - - public: - constexpr CFunctionInfoImpl() - : CFunctionInfo(RetBuilder::Build(), sizeof...(ArgBuilders), - arg_info_storage_), - arg_info_storage_{ArgBuilders::Build()...} { - constexpr CTypeInfo::Type kReturnType = RetBuilder::Build().GetType(); - static_assert(kReturnType == CTypeInfo::Type::kVoid || - kReturnType == CTypeInfo::Type::kBool || - kReturnType == CTypeInfo::Type::kInt32 || - kReturnType == CTypeInfo::Type::kUint32 || - kReturnType == CTypeInfo::Type::kFloat32 || - kReturnType == CTypeInfo::Type::kFloat64 || - kReturnType == CTypeInfo::Type::kAny, - "64-bit int and api object values are not currently " - "supported return types."); - } - - private: - const CTypeInfo arg_info_storage_[sizeof...(ArgBuilders)]; -}; - -template -struct TypeInfoHelper { - static_assert(sizeof(T) != sizeof(T), "This type is not supported"); -}; - -#define SPECIALIZE_GET_TYPE_INFO_HELPER_FOR(T, Enum) \ - template <> \ - struct TypeInfoHelper { \ - static constexpr CTypeInfo::Flags Flags() { \ - return CTypeInfo::Flags::kNone; \ - } \ - \ - static constexpr CTypeInfo::Type Type() { return CTypeInfo::Type::Enum; } \ - static constexpr CTypeInfo::SequenceType SequenceType() { \ - return CTypeInfo::SequenceType::kScalar; \ - } \ - }; - -template -struct CTypeInfoTraits {}; - -#define DEFINE_TYPE_INFO_TRAITS(CType, Enum) \ - template <> \ - struct CTypeInfoTraits { \ - using ctype = CType; \ - }; - -#define PRIMITIVE_C_TYPES(V) \ - V(bool, kBool) \ - V(int32_t, kInt32) \ - V(uint32_t, kUint32) \ - V(int64_t, kInt64) \ - V(uint64_t, kUint64) \ - V(float, kFloat32) \ - V(double, kFloat64) - -// Same as above, but includes deprecated types for compatibility. -#define ALL_C_TYPES(V) \ - PRIMITIVE_C_TYPES(V) \ - V(void, kVoid) \ - V(v8::Local, kV8Value) \ - V(v8::Local, kV8Value) \ - V(AnyCType, kAny) - -// ApiObject was a temporary solution to wrap the pointer to the v8::Value. -// Please use v8::Local in new code for the arguments and -// v8::Local for the receiver, as ApiObject will be deprecated. - -ALL_C_TYPES(SPECIALIZE_GET_TYPE_INFO_HELPER_FOR) -PRIMITIVE_C_TYPES(DEFINE_TYPE_INFO_TRAITS) - -#undef PRIMITIVE_C_TYPES -#undef ALL_C_TYPES - -#define SPECIALIZE_GET_TYPE_INFO_HELPER_FOR_TA(T, Enum) \ - template <> \ - struct TypeInfoHelper&> { \ - static constexpr CTypeInfo::Flags Flags() { \ - return CTypeInfo::Flags::kNone; \ - } \ - \ - static constexpr CTypeInfo::Type Type() { return CTypeInfo::Type::Enum; } \ - static constexpr CTypeInfo::SequenceType SequenceType() { \ - return CTypeInfo::SequenceType::kIsTypedArray; \ - } \ - }; - -#define TYPED_ARRAY_C_TYPES(V) \ - V(int32_t, kInt32) \ - V(uint32_t, kUint32) \ - V(int64_t, kInt64) \ - V(uint64_t, kUint64) \ - V(float, kFloat32) \ - V(double, kFloat64) - -TYPED_ARRAY_C_TYPES(SPECIALIZE_GET_TYPE_INFO_HELPER_FOR_TA) - -#undef TYPED_ARRAY_C_TYPES - -template <> -struct TypeInfoHelper> { - static constexpr CTypeInfo::Flags Flags() { return CTypeInfo::Flags::kNone; } - - static constexpr CTypeInfo::Type Type() { return CTypeInfo::Type::kVoid; } - static constexpr CTypeInfo::SequenceType SequenceType() { - return CTypeInfo::SequenceType::kIsSequence; - } -}; - -template <> -struct TypeInfoHelper> { - static constexpr CTypeInfo::Flags Flags() { return CTypeInfo::Flags::kNone; } - - static constexpr CTypeInfo::Type Type() { return CTypeInfo::Type::kUint32; } - static constexpr CTypeInfo::SequenceType SequenceType() { - return CTypeInfo::SequenceType::kIsTypedArray; - } -}; - -template <> -struct TypeInfoHelper { - static constexpr CTypeInfo::Flags Flags() { return CTypeInfo::Flags::kNone; } - - static constexpr CTypeInfo::Type Type() { - return CTypeInfo::kCallbackOptionsType; - } - static constexpr CTypeInfo::SequenceType SequenceType() { - return CTypeInfo::SequenceType::kScalar; - } -}; - -#define STATIC_ASSERT_IMPLIES(COND, ASSERTION, MSG) \ - static_assert(((COND) == 0) || (ASSERTION), MSG) - -} // namespace internal - -template -class V8_EXPORT CTypeInfoBuilder { - public: - using BaseType = T; - - static constexpr CTypeInfo Build() { - constexpr CTypeInfo::Flags kFlags = - MergeFlags(internal::TypeInfoHelper::Flags(), Flags...); - constexpr CTypeInfo::Type kType = internal::TypeInfoHelper::Type(); - constexpr CTypeInfo::SequenceType kSequenceType = - internal::TypeInfoHelper::SequenceType(); - - STATIC_ASSERT_IMPLIES( - uint8_t(kFlags) & uint8_t(CTypeInfo::Flags::kAllowSharedBit), - (kSequenceType == CTypeInfo::SequenceType::kIsTypedArray || - kSequenceType == CTypeInfo::SequenceType::kIsArrayBuffer), - "kAllowSharedBit is only allowed for TypedArrays and ArrayBuffers."); - STATIC_ASSERT_IMPLIES( - uint8_t(kFlags) & uint8_t(CTypeInfo::Flags::kEnforceRangeBit), - CTypeInfo::IsIntegralType(kType), - "kEnforceRangeBit is only allowed for integral types."); - STATIC_ASSERT_IMPLIES( - uint8_t(kFlags) & uint8_t(CTypeInfo::Flags::kClampBit), - CTypeInfo::IsIntegralType(kType), - "kClampBit is only allowed for integral types."); - STATIC_ASSERT_IMPLIES( - uint8_t(kFlags) & uint8_t(CTypeInfo::Flags::kIsRestrictedBit), - CTypeInfo::IsFloatingPointType(kType), - "kIsRestrictedBit is only allowed for floating point types."); - STATIC_ASSERT_IMPLIES(kSequenceType == CTypeInfo::SequenceType::kIsSequence, - kType == CTypeInfo::Type::kVoid, - "Sequences are only supported from void type."); - STATIC_ASSERT_IMPLIES( - kSequenceType == CTypeInfo::SequenceType::kIsTypedArray, - CTypeInfo::IsPrimitive(kType) || kType == CTypeInfo::Type::kVoid, - "TypedArrays are only supported from primitive types or void."); - - // Return the same type with the merged flags. - return CTypeInfo(internal::TypeInfoHelper::Type(), - internal::TypeInfoHelper::SequenceType(), kFlags); - } - - private: - template - static constexpr CTypeInfo::Flags MergeFlags(CTypeInfo::Flags flags, - Rest... rest) { - return CTypeInfo::Flags(uint8_t(flags) | uint8_t(MergeFlags(rest...))); - } - static constexpr CTypeInfo::Flags MergeFlags() { return CTypeInfo::Flags(0); } -}; - -namespace internal { -template -class CFunctionBuilderWithFunction { - public: - explicit constexpr CFunctionBuilderWithFunction(const void* fn) : fn_(fn) {} - - template - constexpr auto Ret() { - return CFunctionBuilderWithFunction< - CTypeInfoBuilder, - ArgBuilders...>(fn_); - } - - template - constexpr auto Arg() { - // Return a copy of the builder with the Nth arg builder merged with - // template parameter pack Flags. - return ArgImpl( - std::make_index_sequence()); - } - - auto Build() { - static CFunctionInfoImpl instance; - return CFunction(fn_, &instance); - } - - private: - template - struct GetArgBuilder; - - // Returns the same ArgBuilder as the one at index N, including its flags. - // Flags in the template parameter pack are ignored. - template - struct GetArgBuilder { - using type = - typename std::tuple_element>::type; - }; - - // Returns an ArgBuilder with the same base type as the one at index N, - // but merges the flags with the flags in the template parameter pack. - template - struct GetArgBuilder { - using type = CTypeInfoBuilder< - typename std::tuple_element>::type::BaseType, - std::tuple_element>::type::Build() - .GetFlags(), - Flags...>; - }; - - // Return a copy of the CFunctionBuilder, but merges the Flags on - // ArgBuilder index N with the new Flags passed in the template parameter - // pack. - template - constexpr auto ArgImpl(std::index_sequence) { - return CFunctionBuilderWithFunction< - RetBuilder, typename GetArgBuilder::type...>(fn_); - } - - const void* fn_; -}; - -class CFunctionBuilder { - public: - constexpr CFunctionBuilder() {} - - template - constexpr auto Fn(R (*fn)(Args...)) { - return CFunctionBuilderWithFunction, - CTypeInfoBuilder...>( - reinterpret_cast(fn)); - } -}; - -} // namespace internal - -// static -template -CFunction CFunction::ArgUnwrap::Make(R (*func)(Args...)) { - return internal::CFunctionBuilder().Fn(func).Build(); -} - -using CFunctionBuilder = internal::CFunctionBuilder; - -static constexpr CTypeInfo kTypeInfoInt32 = CTypeInfo(CTypeInfo::Type::kInt32); -static constexpr CTypeInfo kTypeInfoFloat64 = - CTypeInfo(CTypeInfo::Type::kFloat64); - -/** - * Copies the contents of this JavaScript array to a C++ buffer with - * a given max_length. A CTypeInfo is passed as an argument, - * instructing different rules for conversion (e.g. restricted float/double). - * The element type T of the destination array must match the C type - * corresponding to the CTypeInfo (specified by CTypeInfoTraits). - * If the array length is larger than max_length or the array is of - * unsupported type, the operation will fail, returning false. Generally, an - * array which contains objects, undefined, null or anything not convertible - * to the requested destination type, is considered unsupported. The operation - * returns true on success. `type_info` will be used for conversions. - */ -template -V8_DEPRECATED( - "Use TryToCopyAndConvertArrayToCppBuffer()") -bool V8_EXPORT V8_WARN_UNUSED_RESULT - TryCopyAndConvertArrayToCppBuffer(Local src, T* dst, - uint32_t max_length); - -template <> -V8_DEPRECATED( - "Use TryToCopyAndConvertArrayToCppBuffer()") -inline bool V8_WARN_UNUSED_RESULT - TryCopyAndConvertArrayToCppBuffer<&kTypeInfoInt32, int32_t>( - Local src, int32_t* dst, uint32_t max_length) { - return false; -} - -template <> -V8_DEPRECATED( - "Use TryToCopyAndConvertArrayToCppBuffer()") -inline bool V8_WARN_UNUSED_RESULT - TryCopyAndConvertArrayToCppBuffer<&kTypeInfoFloat64, double>( - Local src, double* dst, uint32_t max_length) { - return false; -} - -template -bool V8_EXPORT V8_WARN_UNUSED_RESULT TryToCopyAndConvertArrayToCppBuffer( - Local src, T* dst, uint32_t max_length); - -template <> -bool V8_EXPORT V8_WARN_UNUSED_RESULT -TryToCopyAndConvertArrayToCppBuffer::Build().GetId(), - int32_t>(Local src, int32_t* dst, - uint32_t max_length); - -template <> -bool V8_EXPORT V8_WARN_UNUSED_RESULT -TryToCopyAndConvertArrayToCppBuffer::Build().GetId(), - uint32_t>(Local src, uint32_t* dst, - uint32_t max_length); - -template <> -bool V8_EXPORT V8_WARN_UNUSED_RESULT -TryToCopyAndConvertArrayToCppBuffer::Build().GetId(), - float>(Local src, float* dst, - uint32_t max_length); - -template <> -bool V8_EXPORT V8_WARN_UNUSED_RESULT -TryToCopyAndConvertArrayToCppBuffer::Build().GetId(), - double>(Local src, double* dst, - uint32_t max_length); - -} // namespace v8 - -#endif // INCLUDE_V8_FAST_API_CALLS_H_ diff --git a/NativeScript/include/v8-forward.h b/NativeScript/include/v8-forward.h deleted file mode 100644 index db3a2017..00000000 --- a/NativeScript/include/v8-forward.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_FORWARD_H_ -#define INCLUDE_V8_FORWARD_H_ - -// This header is intended to be used by headers that pass around V8 types, -// either by pointer or using Local. The full definitions can be included -// either via v8.h or the more fine-grained headers. - -#include "v8-local-handle.h" // NOLINT(build/include_directory) - -namespace v8 { - -class AccessorSignature; -class Array; -class ArrayBuffer; -class ArrayBufferView; -class BigInt; -class BigInt64Array; -class BigIntObject; -class BigUint64Array; -class Boolean; -class BooleanObject; -class Context; -class DataView; -class Data; -class Date; -class Extension; -class External; -class FixedArray; -class Float32Array; -class Float64Array; -class Function; -template -class FunctionCallbackInfo; -class FunctionTemplate; -class Int16Array; -class Int32; -class Int32Array; -class Int8Array; -class Integer; -class Isolate; -class Map; -class Module; -class Name; -class Number; -class NumberObject; -class Object; -class ObjectTemplate; -class Platform; -class Primitive; -class Private; -class Promise; -class Proxy; -class RegExp; -class Script; -class Set; -class SharedArrayBuffer; -class Signature; -class String; -class StringObject; -class Symbol; -class SymbolObject; -class Template; -class TryCatch; -class TypedArray; -class Uint16Array; -class Uint32; -class Uint32Array; -class Uint8Array; -class Uint8ClampedArray; -class UnboundModuleScript; -class Value; -class WasmMemoryObject; -class WasmModuleObject; - -} // namespace v8 - -#endif // INCLUDE_V8_FORWARD_H_ diff --git a/NativeScript/include/v8-function-callback.h b/NativeScript/include/v8-function-callback.h deleted file mode 100644 index 2adff99b..00000000 --- a/NativeScript/include/v8-function-callback.h +++ /dev/null @@ -1,475 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_FUNCTION_CALLBACK_H_ -#define INCLUDE_V8_FUNCTION_CALLBACK_H_ - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-primitive.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -template -class BasicTracedReference; -template -class Global; -class Object; -class Value; - -namespace internal { -class FunctionCallbackArguments; -class PropertyCallbackArguments; -} // namespace internal - -namespace debug { -class ConsoleCallArguments; -} // namespace debug - -template -class ReturnValue { - public: - template - V8_INLINE ReturnValue(const ReturnValue& that) : value_(that.value_) { - static_assert(std::is_base_of::value, "type check"); - } - // Local setters - template - V8_INLINE void Set(const Global& handle); - template - V8_INLINE void Set(const BasicTracedReference& handle); - template - V8_INLINE void Set(const Local handle); - // Fast primitive setters - V8_INLINE void Set(bool value); - V8_INLINE void Set(double i); - V8_INLINE void Set(int32_t i); - V8_INLINE void Set(uint32_t i); - // Fast JS primitive setters - V8_INLINE void SetNull(); - V8_INLINE void SetUndefined(); - V8_INLINE void SetEmptyString(); - // Convenience getter for Isolate - V8_INLINE Isolate* GetIsolate() const; - - // Pointer setter: Uncompilable to prevent inadvertent misuse. - template - V8_INLINE void Set(S* whatever); - - // Getter. Creates a new Local<> so it comes with a certain performance - // hit. If the ReturnValue was not yet set, this will return the undefined - // value. - V8_INLINE Local Get() const; - - private: - template - friend class ReturnValue; - template - friend class FunctionCallbackInfo; - template - friend class PropertyCallbackInfo; - template - friend class PersistentValueMapBase; - V8_INLINE void SetInternal(internal::Address value) { *value_ = value; } - V8_INLINE internal::Address GetDefaultValue(); - V8_INLINE explicit ReturnValue(internal::Address* slot); - internal::Address* value_; -}; - -/** - * The argument information given to function call callbacks. This - * class provides access to information about the context of the call, - * including the receiver, the number and values of arguments, and - * the holder of the function. - */ -template -class FunctionCallbackInfo { - public: - /** The number of available arguments. */ - V8_INLINE int Length() const; - /** - * Accessor for the available arguments. Returns `undefined` if the index - * is out of bounds. - */ - V8_INLINE Local operator[](int i) const; - /** Returns the receiver. This corresponds to the "this" value. */ - V8_INLINE Local This() const; - /** - * If the callback was created without a Signature, this is the same - * value as This(). If there is a signature, and the signature didn't match - * This() but one of its hidden prototypes, this will be the respective - * hidden prototype. - * - * Note that this is not the prototype of This() on which the accessor - * referencing this callback was found (which in V8 internally is often - * referred to as holder [sic]). - */ - V8_INLINE Local Holder() const; - /** For construct calls, this returns the "new.target" value. */ - V8_INLINE Local NewTarget() const; - /** Indicates whether this is a regular call or a construct call. */ - V8_INLINE bool IsConstructCall() const; - /** The data argument specified when creating the callback. */ - V8_INLINE Local Data() const; - /** The current Isolate. */ - V8_INLINE Isolate* GetIsolate() const; - /** The ReturnValue for the call. */ - V8_INLINE ReturnValue GetReturnValue() const; - // This shouldn't be public, but the arm compiler needs it. - static const int kArgsLength = 6; - - protected: - friend class internal::FunctionCallbackArguments; - friend class internal::CustomArguments; - friend class debug::ConsoleCallArguments; - static const int kHolderIndex = 0; - static const int kIsolateIndex = 1; - static const int kReturnValueDefaultValueIndex = 2; - static const int kReturnValueIndex = 3; - static const int kDataIndex = 4; - static const int kNewTargetIndex = 5; - - V8_INLINE FunctionCallbackInfo(internal::Address* implicit_args, - internal::Address* values, int length); - internal::Address* implicit_args_; - internal::Address* values_; - int length_; -}; - -/** - * The information passed to a property callback about the context - * of the property access. - */ -template -class PropertyCallbackInfo { - public: - /** - * \return The isolate of the property access. - */ - V8_INLINE Isolate* GetIsolate() const; - - /** - * \return The data set in the configuration, i.e., in - * `NamedPropertyHandlerConfiguration` or - * `IndexedPropertyHandlerConfiguration.` - */ - V8_INLINE Local Data() const; - - /** - * \return The receiver. In many cases, this is the object on which the - * property access was intercepted. When using - * `Reflect.get`, `Function.prototype.call`, or similar functions, it is the - * object passed in as receiver or thisArg. - * - * \code - * void GetterCallback(Local name, - * const v8::PropertyCallbackInfo& info) { - * auto context = info.GetIsolate()->GetCurrentContext(); - * - * v8::Local a_this = - * info.This() - * ->GetRealNamedProperty(context, v8_str("a")) - * .ToLocalChecked(); - * v8::Local a_holder = - * info.Holder() - * ->GetRealNamedProperty(context, v8_str("a")) - * .ToLocalChecked(); - * - * CHECK(v8_str("r")->Equals(context, a_this).FromJust()); - * CHECK(v8_str("obj")->Equals(context, a_holder).FromJust()); - * - * info.GetReturnValue().Set(name); - * } - * - * v8::Local templ = - * v8::FunctionTemplate::New(isolate); - * templ->InstanceTemplate()->SetHandler( - * v8::NamedPropertyHandlerConfiguration(GetterCallback)); - * LocalContext env; - * env->Global() - * ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local()) - * .ToLocalChecked() - * ->NewInstance(env.local()) - * .ToLocalChecked()) - * .FromJust(); - * - * CompileRun("obj.a = 'obj'; var r = {a: 'r'}; Reflect.get(obj, 'x', r)"); - * \endcode - */ - V8_INLINE Local This() const; - - /** - * \return The object in the prototype chain of the receiver that has the - * interceptor. Suppose you have `x` and its prototype is `y`, and `y` - * has an interceptor. Then `info.This()` is `x` and `info.Holder()` is `y`. - * The Holder() could be a hidden object (the global object, rather - * than the global proxy). - * - * \note For security reasons, do not pass the object back into the runtime. - */ - V8_INLINE Local Holder() const; - - /** - * \return The return value of the callback. - * Can be changed by calling Set(). - * \code - * info.GetReturnValue().Set(...) - * \endcode - * - */ - V8_INLINE ReturnValue GetReturnValue() const; - - /** - * \return True if the intercepted function should throw if an error occurs. - * Usually, `true` corresponds to `'use strict'`. - * - * \note Always `false` when intercepting `Reflect.set()` - * independent of the language mode. - */ - V8_INLINE bool ShouldThrowOnError() const; - - // This shouldn't be public, but the arm compiler needs it. - static const int kArgsLength = 7; - - protected: - friend class MacroAssembler; - friend class internal::PropertyCallbackArguments; - friend class internal::CustomArguments; - static const int kShouldThrowOnErrorIndex = 0; - static const int kHolderIndex = 1; - static const int kIsolateIndex = 2; - static const int kReturnValueDefaultValueIndex = 3; - static const int kReturnValueIndex = 4; - static const int kDataIndex = 5; - static const int kThisIndex = 6; - - V8_INLINE PropertyCallbackInfo(internal::Address* args) : args_(args) {} - internal::Address* args_; -}; - -using FunctionCallback = void (*)(const FunctionCallbackInfo& info); - -// --- Implementation --- - -template -ReturnValue::ReturnValue(internal::Address* slot) : value_(slot) {} - -template -template -void ReturnValue::Set(const Global& handle) { - static_assert(std::is_base_of::value, "type check"); - if (V8_UNLIKELY(handle.IsEmpty())) { - *value_ = GetDefaultValue(); - } else { - *value_ = *reinterpret_cast(*handle); - } -} - -template -template -void ReturnValue::Set(const BasicTracedReference& handle) { - static_assert(std::is_base_of::value, "type check"); - if (V8_UNLIKELY(handle.IsEmpty())) { - *value_ = GetDefaultValue(); - } else { - *value_ = *reinterpret_cast(handle.val_); - } -} - -template -template -void ReturnValue::Set(const Local handle) { - static_assert(std::is_void::value || std::is_base_of::value, - "type check"); - if (V8_UNLIKELY(handle.IsEmpty())) { - *value_ = GetDefaultValue(); - } else { - *value_ = *reinterpret_cast(*handle); - } -} - -template -void ReturnValue::Set(double i) { - static_assert(std::is_base_of::value, "type check"); - Set(Number::New(GetIsolate(), i)); -} - -template -void ReturnValue::Set(int32_t i) { - static_assert(std::is_base_of::value, "type check"); - using I = internal::Internals; - if (V8_LIKELY(I::IsValidSmi(i))) { - *value_ = I::IntToSmi(i); - return; - } - Set(Integer::New(GetIsolate(), i)); -} - -template -void ReturnValue::Set(uint32_t i) { - static_assert(std::is_base_of::value, "type check"); - // Can't simply use INT32_MAX here for whatever reason. - bool fits_into_int32_t = (i & (1U << 31)) == 0; - if (V8_LIKELY(fits_into_int32_t)) { - Set(static_cast(i)); - return; - } - Set(Integer::NewFromUnsigned(GetIsolate(), i)); -} - -template -void ReturnValue::Set(bool value) { - static_assert(std::is_base_of::value, "type check"); - using I = internal::Internals; - int root_index; - if (value) { - root_index = I::kTrueValueRootIndex; - } else { - root_index = I::kFalseValueRootIndex; - } - *value_ = *I::GetRoot(GetIsolate(), root_index); -} - -template -void ReturnValue::SetNull() { - static_assert(std::is_base_of::value, "type check"); - using I = internal::Internals; - *value_ = *I::GetRoot(GetIsolate(), I::kNullValueRootIndex); -} - -template -void ReturnValue::SetUndefined() { - static_assert(std::is_base_of::value, "type check"); - using I = internal::Internals; - *value_ = *I::GetRoot(GetIsolate(), I::kUndefinedValueRootIndex); -} - -template -void ReturnValue::SetEmptyString() { - static_assert(std::is_base_of::value, "type check"); - using I = internal::Internals; - *value_ = *I::GetRoot(GetIsolate(), I::kEmptyStringRootIndex); -} - -template -Isolate* ReturnValue::GetIsolate() const { - // Isolate is always the pointer below the default value on the stack. - return *reinterpret_cast(&value_[-2]); -} - -template -Local ReturnValue::Get() const { - using I = internal::Internals; - if (*value_ == *I::GetRoot(GetIsolate(), I::kTheHoleValueRootIndex)) - return Local(*Undefined(GetIsolate())); - return Local::New(GetIsolate(), reinterpret_cast(value_)); -} - -template -template -void ReturnValue::Set(S* whatever) { - static_assert(sizeof(S) < 0, "incompilable to prevent inadvertent misuse"); -} - -template -internal::Address ReturnValue::GetDefaultValue() { - // Default value is always the pointer below value_ on the stack. - return value_[-1]; -} - -template -FunctionCallbackInfo::FunctionCallbackInfo(internal::Address* implicit_args, - internal::Address* values, - int length) - : implicit_args_(implicit_args), values_(values), length_(length) {} - -template -Local FunctionCallbackInfo::operator[](int i) const { - // values_ points to the first argument (not the receiver). - if (i < 0 || length_ <= i) return Local(*Undefined(GetIsolate())); - return Local(reinterpret_cast(values_ + i)); -} - -template -Local FunctionCallbackInfo::This() const { - // values_ points to the first argument (not the receiver). - return Local(reinterpret_cast(values_ - 1)); -} - -template -Local FunctionCallbackInfo::Holder() const { - return Local( - reinterpret_cast(&implicit_args_[kHolderIndex])); -} - -template -Local FunctionCallbackInfo::NewTarget() const { - return Local( - reinterpret_cast(&implicit_args_[kNewTargetIndex])); -} - -template -Local FunctionCallbackInfo::Data() const { - return Local(reinterpret_cast(&implicit_args_[kDataIndex])); -} - -template -Isolate* FunctionCallbackInfo::GetIsolate() const { - return *reinterpret_cast(&implicit_args_[kIsolateIndex]); -} - -template -ReturnValue FunctionCallbackInfo::GetReturnValue() const { - return ReturnValue(&implicit_args_[kReturnValueIndex]); -} - -template -bool FunctionCallbackInfo::IsConstructCall() const { - return !NewTarget()->IsUndefined(); -} - -template -int FunctionCallbackInfo::Length() const { - return length_; -} - -template -Isolate* PropertyCallbackInfo::GetIsolate() const { - return *reinterpret_cast(&args_[kIsolateIndex]); -} - -template -Local PropertyCallbackInfo::Data() const { - return Local(reinterpret_cast(&args_[kDataIndex])); -} - -template -Local PropertyCallbackInfo::This() const { - return Local(reinterpret_cast(&args_[kThisIndex])); -} - -template -Local PropertyCallbackInfo::Holder() const { - return Local(reinterpret_cast(&args_[kHolderIndex])); -} - -template -ReturnValue PropertyCallbackInfo::GetReturnValue() const { - return ReturnValue(&args_[kReturnValueIndex]); -} - -template -bool PropertyCallbackInfo::ShouldThrowOnError() const { - using I = internal::Internals; - if (args_[kShouldThrowOnErrorIndex] != - I::IntToSmi(I::kInferShouldThrowMode)) { - return args_[kShouldThrowOnErrorIndex] != I::IntToSmi(I::kDontThrow); - } - return v8::internal::ShouldThrowOnError( - reinterpret_cast(GetIsolate())); -} - -} // namespace v8 - -#endif // INCLUDE_V8_FUNCTION_CALLBACK_H_ diff --git a/NativeScript/include/v8-function.h b/NativeScript/include/v8-function.h deleted file mode 100644 index 897e6ed6..00000000 --- a/NativeScript/include/v8-function.h +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_FUNCTION_H_ -#define INCLUDE_V8_FUNCTION_H_ - -#include -#include - -#include "v8-function-callback.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-message.h" // NOLINT(build/include_directory) -#include "v8-object.h" // NOLINT(build/include_directory) -#include "v8-template.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; -class UnboundScript; - -/** - * A JavaScript function object (ECMA-262, 15.3). - */ -class V8_EXPORT Function : public Object { - public: - /** - * Create a function in the current execution context - * for a given FunctionCallback. - */ - static MaybeLocal New( - Local context, FunctionCallback callback, - Local data = Local(), int length = 0, - ConstructorBehavior behavior = ConstructorBehavior::kAllow, - SideEffectType side_effect_type = SideEffectType::kHasSideEffect); - - V8_WARN_UNUSED_RESULT MaybeLocal NewInstance( - Local context, int argc, Local argv[]) const; - - V8_WARN_UNUSED_RESULT MaybeLocal NewInstance( - Local context) const { - return NewInstance(context, 0, nullptr); - } - - /** - * When side effect checks are enabled, passing kHasNoSideEffect allows the - * constructor to be invoked without throwing. Calls made within the - * constructor are still checked. - */ - V8_WARN_UNUSED_RESULT MaybeLocal NewInstanceWithSideEffectType( - Local context, int argc, Local argv[], - SideEffectType side_effect_type = SideEffectType::kHasSideEffect) const; - - V8_WARN_UNUSED_RESULT MaybeLocal Call(Local context, - Local recv, int argc, - Local argv[]); - - void SetName(Local name); - Local GetName() const; - - MaybeLocal GetUnboundScript() const; - - /** - * Name inferred from variable or property assignment of this function. - * Used to facilitate debugging and profiling of JavaScript code written - * in an OO style, where many functions are anonymous but are assigned - * to object properties. - */ - Local GetInferredName() const; - - /** - * displayName if it is set, otherwise name if it is configured, otherwise - * function name, otherwise inferred name. - */ - Local GetDebugName() const; - - /** - * Returns zero based line number of function body and - * kLineOffsetNotFound if no information available. - */ - int GetScriptLineNumber() const; - /** - * Returns zero based column number of function body and - * kLineOffsetNotFound if no information available. - */ - int GetScriptColumnNumber() const; - - /** - * Returns scriptId. - */ - int ScriptId() const; - - /** - * Returns the original function if this function is bound, else returns - * v8::Undefined. - */ - Local GetBoundFunction() const; - - /** - * Calls builtin Function.prototype.toString on this function. - * This is different from Value::ToString() that may call a user-defined - * toString() function, and different than Object::ObjectProtoToString() which - * always serializes "[object Function]". - */ - V8_WARN_UNUSED_RESULT MaybeLocal FunctionProtoToString( - Local context); - - ScriptOrigin GetScriptOrigin() const; - V8_INLINE static Function* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - static const int kLineOffsetNotFound; - - private: - Function(); - static void CheckCast(Value* obj); -}; -} // namespace v8 - -#endif // INCLUDE_V8_FUNCTION_H_ diff --git a/NativeScript/include/v8-initialization.h b/NativeScript/include/v8-initialization.h deleted file mode 100644 index 3d59c73f..00000000 --- a/NativeScript/include/v8-initialization.h +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_INITIALIZATION_H_ -#define INCLUDE_V8_INITIALIZATION_H_ - -#include -#include - -#include "v8-callbacks.h" // NOLINT(build/include_directory) -#include "v8-internal.h" // NOLINT(build/include_directory) -#include "v8-isolate.h" // NOLINT(build/include_directory) -#include "v8-platform.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -// We reserve the V8_* prefix for macros defined in V8 public API and -// assume there are no name conflicts with the embedder's code. - -/** - * The v8 JavaScript engine. - */ -namespace v8 { - -class PageAllocator; -class Platform; -template -class PersistentValueMapBase; - -/** - * EntropySource is used as a callback function when v8 needs a source - * of entropy. - */ -using EntropySource = bool (*)(unsigned char* buffer, size_t length); - -/** - * ReturnAddressLocationResolver is used as a callback function when v8 is - * resolving the location of a return address on the stack. Profilers that - * change the return address on the stack can use this to resolve the stack - * location to wherever the profiler stashed the original return address. - * - * \param return_addr_location A location on stack where a machine - * return address resides. - * \returns Either return_addr_location, or else a pointer to the profiler's - * copy of the original return address. - * - * \note The resolver function must not cause garbage collection. - */ -using ReturnAddressLocationResolver = - uintptr_t (*)(uintptr_t return_addr_location); - -using DcheckErrorCallback = void (*)(const char* file, int line, - const char* message); - -/** - * Container class for static utility functions. - */ -class V8_EXPORT V8 { - public: - /** - * Hand startup data to V8, in case the embedder has chosen to build - * V8 with external startup data. - * - * Note: - * - By default the startup data is linked into the V8 library, in which - * case this function is not meaningful. - * - If this needs to be called, it needs to be called before V8 - * tries to make use of its built-ins. - * - To avoid unnecessary copies of data, V8 will point directly into the - * given data blob, so pretty please keep it around until V8 exit. - * - Compression of the startup blob might be useful, but needs to - * handled entirely on the embedders' side. - * - The call will abort if the data is invalid. - */ - static void SetSnapshotDataBlob(StartupData* startup_blob); - - /** Set the callback to invoke in case of Dcheck failures. */ - static void SetDcheckErrorHandler(DcheckErrorCallback that); - - /** - * Sets V8 flags from a string. - */ - static void SetFlagsFromString(const char* str); - static void SetFlagsFromString(const char* str, size_t length); - - /** - * Sets V8 flags from the command line. - */ - static void SetFlagsFromCommandLine(int* argc, char** argv, - bool remove_flags); - - /** Get the version string. */ - static const char* GetVersion(); - - /** - * Initializes V8. This function needs to be called before the first Isolate - * is created. It always returns true. - */ - V8_INLINE static bool Initialize() { - const int kBuildConfiguration = - (internal::PointerCompressionIsEnabled() ? kPointerCompression : 0) | - (internal::SmiValuesAre31Bits() ? k31BitSmis : 0) | - (internal::SandboxedExternalPointersAreEnabled() - ? kSandboxedExternalPointers - : 0) | - (internal::SandboxIsEnabled() ? kSandbox : 0); - return Initialize(kBuildConfiguration); - } - - /** - * Allows the host application to provide a callback which can be used - * as a source of entropy for random number generators. - */ - static void SetEntropySource(EntropySource source); - - /** - * Allows the host application to provide a callback that allows v8 to - * cooperate with a profiler that rewrites return addresses on stack. - */ - static void SetReturnAddressLocationResolver( - ReturnAddressLocationResolver return_address_resolver); - - /** - * Releases any resources used by v8 and stops any utility threads - * that may be running. Note that disposing v8 is permanent, it - * cannot be reinitialized. - * - * It should generally not be necessary to dispose v8 before exiting - * a process, this should happen automatically. It is only necessary - * to use if the process needs the resources taken up by v8. - */ - static bool Dispose(); - - /** - * Initialize the ICU library bundled with V8. The embedder should only - * invoke this method when using the bundled ICU. Returns true on success. - * - * If V8 was compiled with the ICU data in an external file, the location - * of the data file has to be provided. - */ - static bool InitializeICU(const char* icu_data_file = nullptr); - - /** - * Initialize the ICU library bundled with V8. The embedder should only - * invoke this method when using the bundled ICU. If V8 was compiled with - * the ICU data in an external file and when the default location of that - * file should be used, a path to the executable must be provided. - * Returns true on success. - * - * The default is a file called icudtl.dat side-by-side with the executable. - * - * Optionally, the location of the data file can be provided to override the - * default. - */ - static bool InitializeICUDefaultLocation(const char* exec_path, - const char* icu_data_file = nullptr); - - /** - * Initialize the external startup data. The embedder only needs to - * invoke this method when external startup data was enabled in a build. - * - * If V8 was compiled with the startup data in an external file, then - * V8 needs to be given those external files during startup. There are - * three ways to do this: - * - InitializeExternalStartupData(const char*) - * This will look in the given directory for the file "snapshot_blob.bin". - * - InitializeExternalStartupDataFromFile(const char*) - * As above, but will directly use the given file name. - * - Call SetSnapshotDataBlob. - * This will read the blobs from the given data structure and will - * not perform any file IO. - */ - static void InitializeExternalStartupData(const char* directory_path); - static void InitializeExternalStartupDataFromFile(const char* snapshot_blob); - - /** - * Sets the v8::Platform to use. This should be invoked before V8 is - * initialized. - */ - static void InitializePlatform(Platform* platform); - - /** - * Clears all references to the v8::Platform. This should be invoked after - * V8 was disposed. - */ - static void DisposePlatform(); - V8_DEPRECATED("Use DisposePlatform()") - static void ShutdownPlatform() { DisposePlatform(); } - -#ifdef V8_SANDBOX - // - // Sandbox related API. - // - // This API is not yet stable and subject to changes in the future. - // - - /** - * Initializes the V8 sandbox. - * - * This must be invoked after the platform was initialized but before V8 is - * initialized. The sandbox is torn down during platform shutdown. - * Returns true on success, false otherwise. - * - * TODO(saelo) Once it is no longer optional to initialize the sandbox when - * compiling with V8_SANDBOX, the sandbox initialization will likely happen - * as part of V8::Initialize, at which point this function should be removed. - */ - static bool InitializeSandbox(); - V8_DEPRECATE_SOON("Use InitializeSandbox()") - static bool InitializeVirtualMemoryCage() { return InitializeSandbox(); } - - /** - * Provides access to the virtual address subspace backing the sandbox. - * - * This can be used to allocate pages inside the sandbox, for example to - * obtain virtual memory for ArrayBuffer backing stores, which must be - * located inside the sandbox. - * - * It should be assumed that an attacker can corrupt data inside the sandbox, - * and so in particular the contents of pages allocagted in this virtual - * address space, arbitrarily and concurrently. Due to this, it is - * recommended to to only place pure data buffers in them. - * - * This function must only be called after initializing the sandbox. - */ - static VirtualAddressSpace* GetSandboxAddressSpace(); - V8_DEPRECATE_SOON("Use GetSandboxAddressSpace()") - static PageAllocator* GetVirtualMemoryCagePageAllocator(); - - /** - * Returns the size of the sandbox in bytes. - * - * If the sandbox has not been initialized, or if the initialization failed, - * this returns zero. - */ - static size_t GetSandboxSizeInBytes(); - V8_DEPRECATE_SOON("Use GetSandboxSizeInBytes()") - static size_t GetVirtualMemoryCageSizeInBytes() { - return GetSandboxSizeInBytes(); - } - - /** - * Returns whether the sandbox is configured securely. - * - * If V8 cannot create a proper sandbox, it will fall back to creating a - * sandbox that doesn't have the desired security properties but at least - * still allows V8 to function. This API can be used to determine if such an - * insecure sandbox is being used, in which case it will return false. - */ - static bool IsSandboxConfiguredSecurely(); - V8_DEPRECATE_SOON("Use IsSandboxConfiguredSecurely()") - static bool IsUsingSecureVirtualMemoryCage() { - return IsSandboxConfiguredSecurely(); - } -#endif - - /** - * Activate trap-based bounds checking for WebAssembly. - * - * \param use_v8_signal_handler Whether V8 should install its own signal - * handler or rely on the embedder's. - */ - static bool EnableWebAssemblyTrapHandler(bool use_v8_signal_handler); - -#if defined(V8_OS_WIN) - /** - * On Win64, by default V8 does not emit unwinding data for jitted code, - * which means the OS cannot walk the stack frames and the system Structured - * Exception Handling (SEH) cannot unwind through V8-generated code: - * https://code.google.com/p/v8/issues/detail?id=3598. - * - * This function allows embedders to register a custom exception handler for - * exceptions in V8-generated code. - */ - static void SetUnhandledExceptionCallback( - UnhandledExceptionCallback unhandled_exception_callback); -#endif - - /** - * Allows the host application to provide a callback that will be called when - * v8 has encountered a fatal failure to allocate memory and is about to - * terminate. - */ - - static void SetFatalMemoryErrorCallback(OOMErrorCallback oom_error_callback); - - /** - * Get statistics about the shared memory usage. - */ - static void GetSharedMemoryStatistics(SharedMemoryStatistics* statistics); - - private: - V8(); - - enum BuildConfigurationFeatures { - kPointerCompression = 1 << 0, - k31BitSmis = 1 << 1, - kSandboxedExternalPointers = 1 << 2, - kSandbox = 1 << 3, - }; - - /** - * Checks that the embedder build configuration is compatible with - * the V8 binary and if so initializes V8. - */ - static bool Initialize(int build_config); - - friend class Context; - template - friend class PersistentValueMapBase; -}; - -} // namespace v8 - -#endif // INCLUDE_V8_INITIALIZATION_H_ diff --git a/NativeScript/include/v8-inspector-protocol.h b/NativeScript/include/v8-inspector-protocol.h deleted file mode 100644 index a5ffb7d6..00000000 --- a/NativeScript/include/v8-inspector-protocol.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2016 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_V8_INSPECTOR_PROTOCOL_H_ -#define V8_V8_INSPECTOR_PROTOCOL_H_ - -#include "inspector/Debugger.h" // NOLINT(build/include_directory) -#include "inspector/Runtime.h" // NOLINT(build/include_directory) -#include "inspector/Schema.h" // NOLINT(build/include_directory) -#include "v8-inspector.h" // NOLINT(build/include_directory) - -#endif // V8_V8_INSPECTOR_PROTOCOL_H_ diff --git a/NativeScript/include/v8-inspector.h b/NativeScript/include/v8-inspector.h deleted file mode 100644 index ce5430bd..00000000 --- a/NativeScript/include/v8-inspector.h +++ /dev/null @@ -1,376 +0,0 @@ -// Copyright 2016 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_V8_INSPECTOR_H_ -#define V8_V8_INSPECTOR_H_ - -#include - -#include -#include - -#include "v8-isolate.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) - -namespace v8 { -class Context; -class Name; -class Object; -class StackTrace; -class Value; -} // namespace v8 - -namespace v8_inspector { - -namespace internal { -class V8DebuggerId; -} // namespace internal - -namespace protocol { -namespace Debugger { -namespace API { -class SearchMatch; -} -} -namespace Runtime { -namespace API { -class RemoteObject; -class StackTrace; -class StackTraceId; -} -} -namespace Schema { -namespace API { -class Domain; -} -} -} // namespace protocol - -class V8_EXPORT StringView { - public: - StringView() : m_is8Bit(true), m_length(0), m_characters8(nullptr) {} - - StringView(const uint8_t* characters, size_t length) - : m_is8Bit(true), m_length(length), m_characters8(characters) {} - - StringView(const uint16_t* characters, size_t length) - : m_is8Bit(false), m_length(length), m_characters16(characters) {} - - bool is8Bit() const { return m_is8Bit; } - size_t length() const { return m_length; } - - // TODO(dgozman): add DCHECK(m_is8Bit) to accessors once platform can be used - // here. - const uint8_t* characters8() const { return m_characters8; } - const uint16_t* characters16() const { return m_characters16; } - - private: - bool m_is8Bit; - size_t m_length; - union { - const uint8_t* m_characters8; - const uint16_t* m_characters16; - }; -}; - -class V8_EXPORT StringBuffer { - public: - virtual ~StringBuffer() = default; - virtual StringView string() const = 0; - // This method copies contents. - static std::unique_ptr create(StringView); -}; - -class V8_EXPORT V8ContextInfo { - public: - V8ContextInfo(v8::Local context, int contextGroupId, - StringView humanReadableName) - : context(context), - contextGroupId(contextGroupId), - humanReadableName(humanReadableName), - hasMemoryOnConsole(false) {} - - v8::Local context; - // Each v8::Context is a part of a group. The group id must be non-zero. - int contextGroupId; - StringView humanReadableName; - StringView origin; - StringView auxData; - bool hasMemoryOnConsole; - - static int executionContextId(v8::Local context); - - // Disallow copying and allocating this one. - enum NotNullTagEnum { NotNullLiteral }; - void* operator new(size_t) = delete; - void* operator new(size_t, NotNullTagEnum, void*) = delete; - void* operator new(size_t, void*) = delete; - V8ContextInfo(const V8ContextInfo&) = delete; - V8ContextInfo& operator=(const V8ContextInfo&) = delete; -}; - -// This debugger id tries to be unique by generating two random -// numbers, which should most likely avoid collisions. -// Debugger id has a 1:1 mapping to context group. It is used to -// attribute stack traces to a particular debugging, when doing any -// cross-debugger operations (e.g. async step in). -// See also Runtime.UniqueDebuggerId in the protocol. -class V8_EXPORT V8DebuggerId { - public: - V8DebuggerId() = default; - V8DebuggerId(const V8DebuggerId&) = default; - V8DebuggerId& operator=(const V8DebuggerId&) = default; - - std::unique_ptr toString() const; - bool isValid() const; - std::pair pair() const; - - private: - friend class internal::V8DebuggerId; - explicit V8DebuggerId(std::pair); - - int64_t m_first = 0; - int64_t m_second = 0; -}; - -class V8_EXPORT V8StackTrace { - public: - virtual StringView firstNonEmptySourceURL() const = 0; - virtual bool isEmpty() const = 0; - virtual StringView topSourceURL() const = 0; - virtual int topLineNumber() const = 0; - virtual int topColumnNumber() const = 0; - virtual int topScriptId() const = 0; - virtual StringView topFunctionName() const = 0; - - virtual ~V8StackTrace() = default; - virtual std::unique_ptr - buildInspectorObject(int maxAsyncDepth) const = 0; - virtual std::unique_ptr toString() const = 0; - - // Safe to pass between threads, drops async chain. - virtual std::unique_ptr clone() = 0; -}; - -class V8_EXPORT V8InspectorSession { - public: - virtual ~V8InspectorSession() = default; - - // Cross-context inspectable values (DOM nodes in different worlds, etc.). - class V8_EXPORT Inspectable { - public: - virtual v8::Local get(v8::Local) = 0; - virtual ~Inspectable() = default; - }; - class V8_EXPORT CommandLineAPIScope { - public: - virtual ~CommandLineAPIScope() = default; - }; - virtual void addInspectedObject(std::unique_ptr) = 0; - - // Dispatching protocol messages. - static bool canDispatchMethod(StringView method); - virtual void dispatchProtocolMessage(StringView message) = 0; - virtual std::vector state() = 0; - virtual std::vector> - supportedDomains() = 0; - - virtual std::unique_ptr - initializeCommandLineAPIScope(int executionContextId) = 0; - - // Debugger actions. - virtual void schedulePauseOnNextStatement(StringView breakReason, - StringView breakDetails) = 0; - virtual void cancelPauseOnNextStatement() = 0; - virtual void breakProgram(StringView breakReason, - StringView breakDetails) = 0; - virtual void setSkipAllPauses(bool) = 0; - virtual void resume(bool setTerminateOnResume = false) = 0; - virtual void stepOver() = 0; - virtual std::vector> - searchInTextByLines(StringView text, StringView query, bool caseSensitive, - bool isRegex) = 0; - - // Remote objects. - virtual std::unique_ptr wrapObject( - v8::Local, v8::Local, StringView groupName, - bool generatePreview) = 0; - - virtual bool unwrapObject(std::unique_ptr* error, - StringView objectId, v8::Local*, - v8::Local*, - std::unique_ptr* objectGroup) = 0; - virtual void releaseObjectGroup(StringView) = 0; - virtual void triggerPreciseCoverageDeltaUpdate(StringView occasion) = 0; -}; - -class V8_EXPORT WebDriverValue { - public: - explicit WebDriverValue(StringView type, v8::MaybeLocal value = {}) - : type(type), value(value) {} - - StringView type; - v8::MaybeLocal value; -}; - -class V8_EXPORT V8InspectorClient { - public: - virtual ~V8InspectorClient() = default; - - virtual void runMessageLoopOnPause(int contextGroupId) {} - virtual void quitMessageLoopOnPause() {} - virtual void runIfWaitingForDebugger(int contextGroupId) {} - - virtual void muteMetrics(int contextGroupId) {} - virtual void unmuteMetrics(int contextGroupId) {} - - virtual void beginUserGesture() {} - virtual void endUserGesture() {} - - virtual std::unique_ptr serializeToWebDriverValue( - v8::Local v8_value, int max_depth) { - return nullptr; - } - virtual std::unique_ptr valueSubtype(v8::Local) { - return nullptr; - } - virtual std::unique_ptr descriptionForValueSubtype( - v8::Local, v8::Local) { - return nullptr; - } - virtual bool isInspectableHeapObject(v8::Local) { return true; } - - virtual v8::Local ensureDefaultContextInGroup( - int contextGroupId) { - return v8::Local(); - } - virtual void beginEnsureAllContextsInGroup(int contextGroupId) {} - virtual void endEnsureAllContextsInGroup(int contextGroupId) {} - - virtual void installAdditionalCommandLineAPI(v8::Local, - v8::Local) {} - virtual void consoleAPIMessage(int contextGroupId, - v8::Isolate::MessageErrorLevel level, - const StringView& message, - const StringView& url, unsigned lineNumber, - unsigned columnNumber, V8StackTrace*) {} - virtual v8::MaybeLocal memoryInfo(v8::Isolate*, - v8::Local) { - return v8::MaybeLocal(); - } - - virtual void consoleTime(const StringView& title) {} - virtual void consoleTimeEnd(const StringView& title) {} - virtual void consoleTimeStamp(const StringView& title) {} - virtual void consoleClear(int contextGroupId) {} - virtual double currentTimeMS() { return 0; } - typedef void (*TimerCallback)(void*); - virtual void startRepeatingTimer(double, TimerCallback, void* data) {} - virtual void cancelTimer(void* data) {} - - // TODO(dgozman): this was added to support service worker shadow page. We - // should not connect at all. - virtual bool canExecuteScripts(int contextGroupId) { return true; } - - virtual void maxAsyncCallStackDepthChanged(int depth) {} - - virtual std::unique_ptr resourceNameToUrl( - const StringView& resourceName) { - return nullptr; - } - - // The caller would defer to generating a random 64 bit integer if - // this method returns 0. - virtual int64_t generateUniqueId() { return 0; } - - virtual void dispatchError(v8::Local, v8::Local, - v8::Local) {} -}; - -// These stack trace ids are intended to be passed between debuggers and be -// resolved later. This allows to track cross-debugger calls and step between -// them if a single client connects to multiple debuggers. -struct V8_EXPORT V8StackTraceId { - uintptr_t id; - std::pair debugger_id; - bool should_pause = false; - - V8StackTraceId(); - V8StackTraceId(const V8StackTraceId&) = default; - V8StackTraceId(uintptr_t id, const std::pair debugger_id); - V8StackTraceId(uintptr_t id, const std::pair debugger_id, - bool should_pause); - explicit V8StackTraceId(StringView); - V8StackTraceId& operator=(const V8StackTraceId&) = default; - V8StackTraceId& operator=(V8StackTraceId&&) noexcept = default; - ~V8StackTraceId() = default; - - bool IsInvalid() const; - std::unique_ptr ToString(); -}; - -class V8_EXPORT V8Inspector { - public: - static std::unique_ptr create(v8::Isolate*, V8InspectorClient*); - virtual ~V8Inspector() = default; - - // Contexts instrumentation. - virtual void contextCreated(const V8ContextInfo&) = 0; - virtual void contextDestroyed(v8::Local) = 0; - virtual void resetContextGroup(int contextGroupId) = 0; - virtual v8::MaybeLocal contextById(int contextId) = 0; - virtual V8DebuggerId uniqueDebuggerId(int contextId) = 0; - - // Various instrumentation. - virtual void idleStarted() = 0; - virtual void idleFinished() = 0; - - // Async stack traces instrumentation. - virtual void asyncTaskScheduled(StringView taskName, void* task, - bool recurring) = 0; - virtual void asyncTaskCanceled(void* task) = 0; - virtual void asyncTaskStarted(void* task) = 0; - virtual void asyncTaskFinished(void* task) = 0; - virtual void allAsyncTasksCanceled() = 0; - - virtual V8StackTraceId storeCurrentStackTrace(StringView description) = 0; - virtual void externalAsyncTaskStarted(const V8StackTraceId& parent) = 0; - virtual void externalAsyncTaskFinished(const V8StackTraceId& parent) = 0; - - // Exceptions instrumentation. - virtual unsigned exceptionThrown(v8::Local, StringView message, - v8::Local exception, - StringView detailedMessage, StringView url, - unsigned lineNumber, unsigned columnNumber, - std::unique_ptr, - int scriptId) = 0; - virtual void exceptionRevoked(v8::Local, unsigned exceptionId, - StringView message) = 0; - virtual bool associateExceptionData(v8::Local, - v8::Local exception, - v8::Local key, - v8::Local value) = 0; - - // Connection. - class V8_EXPORT Channel { - public: - virtual ~Channel() = default; - virtual void sendResponse(int callId, - std::unique_ptr message) = 0; - virtual void sendNotification(std::unique_ptr message) = 0; - virtual void flushProtocolNotifications() = 0; - }; - virtual std::unique_ptr connect(int contextGroupId, - Channel*, - StringView state) = 0; - - // API methods. - virtual std::unique_ptr createStackTrace( - v8::Local) = 0; - virtual std::unique_ptr captureStackTrace(bool fullStack) = 0; -}; - -} // namespace v8_inspector - -#endif // V8_V8_INSPECTOR_H_ diff --git a/NativeScript/include/v8-internal.h b/NativeScript/include/v8-internal.h deleted file mode 100644 index 37c5b336..00000000 --- a/NativeScript/include/v8-internal.h +++ /dev/null @@ -1,661 +0,0 @@ -// Copyright 2018 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_INTERNAL_H_ -#define INCLUDE_V8_INTERNAL_H_ - -#include -#include -#include -#include - -#include "v8-version.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Array; -class Context; -class Data; -class Isolate; -template -class Local; - -namespace internal { - -class Isolate; - -typedef uintptr_t Address; -static const Address kNullAddress = 0; - -constexpr int KB = 1024; -constexpr int MB = KB * 1024; -constexpr int GB = MB * 1024; -#ifdef V8_TARGET_ARCH_X64 -constexpr size_t TB = size_t{GB} * 1024; -#endif - -/** - * Configuration of tagging scheme. - */ -const int kApiSystemPointerSize = sizeof(void*); -const int kApiDoubleSize = sizeof(double); -const int kApiInt32Size = sizeof(int32_t); -const int kApiInt64Size = sizeof(int64_t); -const int kApiSizetSize = sizeof(size_t); - -// Tag information for HeapObject. -const int kHeapObjectTag = 1; -const int kWeakHeapObjectTag = 3; -const int kHeapObjectTagSize = 2; -const intptr_t kHeapObjectTagMask = (1 << kHeapObjectTagSize) - 1; - -// Tag information for fowarding pointers stored in object headers. -// 0b00 at the lowest 2 bits in the header indicates that the map word is a -// forwarding pointer. -const int kForwardingTag = 0; -const int kForwardingTagSize = 2; -const intptr_t kForwardingTagMask = (1 << kForwardingTagSize) - 1; - -// Tag information for Smi. -const int kSmiTag = 0; -const int kSmiTagSize = 1; -const intptr_t kSmiTagMask = (1 << kSmiTagSize) - 1; - -template -struct SmiTagging; - -constexpr intptr_t kIntptrAllBitsSet = intptr_t{-1}; -constexpr uintptr_t kUintptrAllBitsSet = - static_cast(kIntptrAllBitsSet); - -// Smi constants for systems where tagged pointer is a 32-bit value. -template <> -struct SmiTagging<4> { - enum { kSmiShiftSize = 0, kSmiValueSize = 31 }; - - static constexpr intptr_t kSmiMinValue = - static_cast(kUintptrAllBitsSet << (kSmiValueSize - 1)); - static constexpr intptr_t kSmiMaxValue = -(kSmiMinValue + 1); - - V8_INLINE static int SmiToInt(const internal::Address value) { - int shift_bits = kSmiTagSize + kSmiShiftSize; - // Truncate and shift down (requires >> to be sign extending). - return static_cast(static_cast(value)) >> shift_bits; - } - V8_INLINE static constexpr bool IsValidSmi(intptr_t value) { - // Is value in range [kSmiMinValue, kSmiMaxValue]. - // Use unsigned operations in order to avoid undefined behaviour in case of - // signed integer overflow. - return (static_cast(value) - - static_cast(kSmiMinValue)) <= - (static_cast(kSmiMaxValue) - - static_cast(kSmiMinValue)); - } -}; - -// Smi constants for systems where tagged pointer is a 64-bit value. -template <> -struct SmiTagging<8> { - enum { kSmiShiftSize = 31, kSmiValueSize = 32 }; - - static constexpr intptr_t kSmiMinValue = - static_cast(kUintptrAllBitsSet << (kSmiValueSize - 1)); - static constexpr intptr_t kSmiMaxValue = -(kSmiMinValue + 1); - - V8_INLINE static int SmiToInt(const internal::Address value) { - int shift_bits = kSmiTagSize + kSmiShiftSize; - // Shift down and throw away top 32 bits. - return static_cast(static_cast(value) >> shift_bits); - } - V8_INLINE static constexpr bool IsValidSmi(intptr_t value) { - // To be representable as a long smi, the value must be a 32-bit integer. - return (value == static_cast(value)); - } -}; - -#ifdef V8_COMPRESS_POINTERS -// See v8:7703 or src/common/ptr-compr-inl.h for details about pointer -// compression. -constexpr size_t kPtrComprCageReservationSize = size_t{1} << 32; -constexpr size_t kPtrComprCageBaseAlignment = size_t{1} << 32; - -static_assert( - kApiSystemPointerSize == kApiInt64Size, - "Pointer compression can be enabled only for 64-bit architectures"); -const int kApiTaggedSize = kApiInt32Size; -#else -const int kApiTaggedSize = kApiSystemPointerSize; -#endif - -constexpr bool PointerCompressionIsEnabled() { - return kApiTaggedSize != kApiSystemPointerSize; -} - -#ifdef V8_31BIT_SMIS_ON_64BIT_ARCH -using PlatformSmiTagging = SmiTagging; -#else -using PlatformSmiTagging = SmiTagging; -#endif - -// TODO(ishell): Consinder adding kSmiShiftBits = kSmiShiftSize + kSmiTagSize -// since it's used much more often than the inividual constants. -const int kSmiShiftSize = PlatformSmiTagging::kSmiShiftSize; -const int kSmiValueSize = PlatformSmiTagging::kSmiValueSize; -const int kSmiMinValue = static_cast(PlatformSmiTagging::kSmiMinValue); -const int kSmiMaxValue = static_cast(PlatformSmiTagging::kSmiMaxValue); -constexpr bool SmiValuesAre31Bits() { return kSmiValueSize == 31; } -constexpr bool SmiValuesAre32Bits() { return kSmiValueSize == 32; } - -V8_INLINE static constexpr internal::Address IntToSmi(int value) { - return (static_cast
(value) << (kSmiTagSize + kSmiShiftSize)) | - kSmiTag; -} - -/* - * Sandbox related types, constants, and functions. - */ -constexpr bool SandboxIsEnabled() { -#ifdef V8_SANDBOX - return true; -#else - return false; -#endif -} - -constexpr bool SandboxedExternalPointersAreEnabled() { -#ifdef V8_SANDBOXED_EXTERNAL_POINTERS - return true; -#else - return false; -#endif -} - -// SandboxedPointers are guaranteed to point into the sandbox. This is achieved -// for example by storing them as offset rather than as raw pointers. -using SandboxedPointer_t = Address; - -// ExternalPointers point to objects located outside the sandbox. When sandboxed -// external pointers are enabled, these are stored in an external pointer table -// and referenced from HeapObjects through indices. -#ifdef V8_SANDBOXED_EXTERNAL_POINTERS -using ExternalPointer_t = uint32_t; -#else -using ExternalPointer_t = Address; -#endif - -#ifdef V8_SANDBOX_IS_AVAILABLE - -// Size of the sandbox, excluding the guard regions surrounding it. -constexpr size_t kSandboxSizeLog2 = 40; // 1 TB -constexpr size_t kSandboxSize = 1ULL << kSandboxSizeLog2; - -// Required alignment of the sandbox. For simplicity, we require the -// size of the guard regions to be a multiple of this, so that this specifies -// the alignment of the sandbox including and excluding surrounding guard -// regions. The alignment requirement is due to the pointer compression cage -// being located at the start of the sandbox. -constexpr size_t kSandboxAlignment = kPtrComprCageBaseAlignment; - -// Sandboxed pointers are stored inside the heap as offset from the sandbox -// base shifted to the left. This way, it is guaranteed that the offset is -// smaller than the sandbox size after shifting it to the right again. This -// constant specifies the shift amount. -constexpr uint64_t kSandboxedPointerShift = 64 - kSandboxSizeLog2; - -// Size of the guard regions surrounding the sandbox. This assumes a worst-case -// scenario of a 32-bit unsigned index used to access an array of 64-bit -// values. -constexpr size_t kSandboxGuardRegionSize = 32ULL * GB; - -static_assert((kSandboxGuardRegionSize % kSandboxAlignment) == 0, - "The size of the guard regions around the sandbox must be a " - "multiple of its required alignment."); - -// Minimum size of the sandbox, excluding the guard regions surrounding it. If -// the virtual memory reservation for the sandbox fails, its size is currently -// halved until either the reservation succeeds or the minimum size is reached. -// A minimum of 32GB allows the 4GB pointer compression region as well as the -// ArrayBuffer partition and two 10GB Wasm memory cages to fit into the -// sandbox. 32GB should also be the minimum possible size of the userspace -// address space as there are some machine configurations with only 36 virtual -// address bits. -constexpr size_t kSandboxMinimumSize = 32ULL * GB; - -static_assert(kSandboxMinimumSize <= kSandboxSize, - "The minimal size of the sandbox must be smaller or equal to the " - "regular size."); - -// On OSes where reserving virtual memory is too expensive to reserve the -// entire address space backing the sandbox, notably Windows pre 8.1, we create -// a partially reserved sandbox that doesn't actually reserve most of the -// memory, and so doesn't have the desired security properties as unrelated -// memory allocations could end up inside of it, but which still ensures that -// objects that should be located inside the sandbox are allocated within -// kSandboxSize bytes from the start of the sandbox. The minimum size of the -// region that is actually reserved for such a sandbox is specified by this -// constant and should be big enough to contain the pointer compression cage as -// well as the ArrayBuffer partition. -constexpr size_t kSandboxMinimumReservationSize = 8ULL * GB; - -static_assert(kSandboxMinimumSize > kPtrComprCageReservationSize, - "The sandbox must be larger than the pointer compression cage " - "contained within it."); -static_assert(kSandboxMinimumReservationSize > kPtrComprCageReservationSize, - "The minimum reservation size for a sandbox must be larger than " - "the pointer compression cage contained within it."); - -// For now, even if the sandbox is enabled, we still allow backing stores to be -// allocated outside of it as fallback. This will simplify the initial rollout. -// However, if sandboxed pointers are also enabled, we must always place -// backing stores inside the sandbox as they will be referenced though them. -#ifdef V8_SANDBOXED_POINTERS -constexpr bool kAllowBackingStoresOutsideSandbox = false; -#else -constexpr bool kAllowBackingStoresOutsideSandbox = true; -#endif // V8_SANDBOXED_POINTERS - -// The size of the virtual memory reservation for an external pointer table. -// This determines the maximum number of entries in a table. Using a maximum -// size allows omitting bounds checks on table accesses if the indices are -// guaranteed (e.g. through shifting) to be below the maximum index. This -// value must be a power of two. -static const size_t kExternalPointerTableReservationSize = 128 * MB; - -// The maximum number of entries in an external pointer table. -static const size_t kMaxSandboxedExternalPointers = - kExternalPointerTableReservationSize / kApiSystemPointerSize; - -// The external pointer table indices stored in HeapObjects as external -// pointers are shifted to the left by this amount to guarantee that they are -// smaller than the maximum table size. -static const uint32_t kExternalPointerIndexShift = 8; -static_assert((1 << (32 - kExternalPointerIndexShift)) == - kMaxSandboxedExternalPointers, - "kExternalPointerTableReservationSize and " - "kExternalPointerIndexShift don't match"); - -#endif // V8_SANDBOX_IS_AVAILABLE - -// If sandboxed external pointers are enabled, these tag values will be ORed -// with the external pointers in the external pointer table to prevent use of -// pointers of the wrong type. When a pointer is loaded, it is ANDed with the -// inverse of the expected type's tag. The tags are constructed in a way that -// guarantees that a failed type check will result in one or more of the top -// bits of the pointer to be set, rendering the pointer inacessible. Besides -// the type tag bits (48 through 62), the tags also have the GC mark bit (63) -// set, so that the mark bit is automatically set when a pointer is written -// into the external pointer table (in which case it is clearly alive) and is -// cleared when the pointer is loaded. The exception to this is the free entry -// tag, which doesn't have the mark bit set, as the entry is not alive. This -// construction allows performing the type check and removing GC marking bits -// (the MSB) from the pointer at the same time. -// Note: this scheme assumes a 48-bit address space and will likely break if -// more virtual address bits are used. -constexpr uint64_t kExternalPointerTagMask = 0xffff000000000000; -constexpr uint64_t kExternalPointerTagShift = 48; -#define MAKE_TAG(v) (static_cast(v) << kExternalPointerTagShift) -// clang-format off -enum ExternalPointerTag : uint64_t { - kExternalPointerNullTag = MAKE_TAG(0b0000000000000000), - kExternalPointerFreeEntryTag = MAKE_TAG(0b0111111110000000), - kExternalStringResourceTag = MAKE_TAG(0b1000000011111111), - kExternalStringResourceDataTag = MAKE_TAG(0b1000000101111111), - kForeignForeignAddressTag = MAKE_TAG(0b1000000110111111), - kNativeContextMicrotaskQueueTag = MAKE_TAG(0b1000000111011111), - kEmbedderDataSlotPayloadTag = MAKE_TAG(0b1000000111101111), - kCodeEntryPointTag = MAKE_TAG(0b1000000111110111), - kExternalObjectValueTag = MAKE_TAG(0b1000000111111011), -}; -// clang-format on -#undef MAKE_TAG - -// Converts encoded external pointer to address. -V8_EXPORT Address DecodeExternalPointerImpl(const Isolate* isolate, - ExternalPointer_t pointer, - ExternalPointerTag tag); - -// {obj} must be the raw tagged pointer representation of a HeapObject -// that's guaranteed to never be in ReadOnlySpace. -V8_EXPORT internal::Isolate* IsolateFromNeverReadOnlySpaceObject(Address obj); - -// Returns if we need to throw when an error occurs. This infers the language -// mode based on the current context and the closure. This returns true if the -// language mode is strict. -V8_EXPORT bool ShouldThrowOnError(v8::internal::Isolate* isolate); - -V8_EXPORT bool CanHaveInternalField(int instance_type); - -/** - * This class exports constants and functionality from within v8 that - * is necessary to implement inline functions in the v8 api. Don't - * depend on functions and constants defined here. - */ -class Internals { -#ifdef V8_MAP_PACKING - V8_INLINE static constexpr internal::Address UnpackMapWord( - internal::Address mapword) { - // TODO(wenyuzhao): Clear header metadata. - return mapword ^ kMapWordXorMask; - } -#endif - - public: - // These values match non-compiler-dependent values defined within - // the implementation of v8. - static const int kHeapObjectMapOffset = 0; - static const int kMapInstanceTypeOffset = 1 * kApiTaggedSize + kApiInt32Size; - static const int kStringResourceOffset = - 1 * kApiTaggedSize + 2 * kApiInt32Size; - - static const int kOddballKindOffset = 4 * kApiTaggedSize + kApiDoubleSize; - static const int kJSObjectHeaderSize = 3 * kApiTaggedSize; - static const int kFixedArrayHeaderSize = 2 * kApiTaggedSize; - static const int kEmbedderDataArrayHeaderSize = 2 * kApiTaggedSize; - static const int kEmbedderDataSlotSize = kApiSystemPointerSize; -#ifdef V8_SANDBOXED_EXTERNAL_POINTERS - static const int kEmbedderDataSlotRawPayloadOffset = kApiTaggedSize; -#endif - static const int kNativeContextEmbedderDataOffset = 6 * kApiTaggedSize; - static const int kStringRepresentationAndEncodingMask = 0x0f; - static const int kStringEncodingMask = 0x8; - static const int kExternalTwoByteRepresentationTag = 0x02; - static const int kExternalOneByteRepresentationTag = 0x0a; - - static const uint32_t kNumIsolateDataSlots = 4; - static const int kStackGuardSize = 7 * kApiSystemPointerSize; - static const int kBuiltinTier0EntryTableSize = 9 * kApiSystemPointerSize; - static const int kBuiltinTier0TableSize = 9 * kApiSystemPointerSize; - - // IsolateData layout guarantees. - static const int kIsolateCageBaseOffset = 0; - static const int kIsolateStackGuardOffset = - kIsolateCageBaseOffset + kApiSystemPointerSize; - static const int kBuiltinTier0EntryTableOffset = - kIsolateStackGuardOffset + kStackGuardSize; - static const int kBuiltinTier0TableOffset = - kBuiltinTier0EntryTableOffset + kBuiltinTier0EntryTableSize; - static const int kIsolateEmbedderDataOffset = - kBuiltinTier0TableOffset + kBuiltinTier0TableSize; - static const int kIsolateFastCCallCallerFpOffset = - kIsolateEmbedderDataOffset + kNumIsolateDataSlots * kApiSystemPointerSize; - static const int kIsolateFastCCallCallerPcOffset = - kIsolateFastCCallCallerFpOffset + kApiSystemPointerSize; - static const int kIsolateFastApiCallTargetOffset = - kIsolateFastCCallCallerPcOffset + kApiSystemPointerSize; - static const int kIsolateLongTaskStatsCounterOffset = - kIsolateFastApiCallTargetOffset + kApiSystemPointerSize; - static const int kIsolateRootsOffset = - kIsolateLongTaskStatsCounterOffset + kApiSizetSize; - - static const int kExternalPointerTableBufferOffset = 0; - static const int kExternalPointerTableCapacityOffset = - kExternalPointerTableBufferOffset + kApiSystemPointerSize; - static const int kExternalPointerTableFreelistHeadOffset = - kExternalPointerTableCapacityOffset + kApiInt32Size; - - static const int kUndefinedValueRootIndex = 4; - static const int kTheHoleValueRootIndex = 5; - static const int kNullValueRootIndex = 6; - static const int kTrueValueRootIndex = 7; - static const int kFalseValueRootIndex = 8; - static const int kEmptyStringRootIndex = 9; - - static const int kNodeClassIdOffset = 1 * kApiSystemPointerSize; - static const int kNodeFlagsOffset = 1 * kApiSystemPointerSize + 3; - static const int kNodeStateMask = 0x7; - static const int kNodeStateIsWeakValue = 2; - static const int kNodeStateIsPendingValue = 3; - - static const int kFirstNonstringType = 0x80; - static const int kOddballType = 0x83; - static const int kForeignType = 0xcc; - static const int kJSSpecialApiObjectType = 0x410; - static const int kJSObjectType = 0x421; - static const int kFirstJSApiObjectType = 0x422; - static const int kLastJSApiObjectType = 0x80A; - - static const int kUndefinedOddballKind = 5; - static const int kNullOddballKind = 3; - - // Constants used by PropertyCallbackInfo to check if we should throw when an - // error occurs. - static const int kThrowOnError = 0; - static const int kDontThrow = 1; - static const int kInferShouldThrowMode = 2; - - // Soft limit for AdjustAmountofExternalAllocatedMemory. Trigger an - // incremental GC once the external memory reaches this limit. - static constexpr int kExternalAllocationSoftLimit = 64 * 1024 * 1024; - -#ifdef V8_MAP_PACKING - static const uintptr_t kMapWordMetadataMask = 0xffffULL << 48; - // The lowest two bits of mapwords are always `0b10` - static const uintptr_t kMapWordSignature = 0b10; - // XORing a (non-compressed) map with this mask ensures that the two - // low-order bits are 0b10. The 0 at the end makes this look like a Smi, - // although real Smis have all lower 32 bits unset. We only rely on these - // values passing as Smis in very few places. - static const int kMapWordXorMask = 0b11; -#endif - - V8_EXPORT static void CheckInitializedImpl(v8::Isolate* isolate); - V8_INLINE static void CheckInitialized(v8::Isolate* isolate) { -#ifdef V8_ENABLE_CHECKS - CheckInitializedImpl(isolate); -#endif - } - - V8_INLINE static bool HasHeapObjectTag(const internal::Address value) { - return (value & kHeapObjectTagMask) == static_cast
(kHeapObjectTag); - } - - V8_INLINE static int SmiValue(const internal::Address value) { - return PlatformSmiTagging::SmiToInt(value); - } - - V8_INLINE static constexpr internal::Address IntToSmi(int value) { - return internal::IntToSmi(value); - } - - V8_INLINE static constexpr bool IsValidSmi(intptr_t value) { - return PlatformSmiTagging::IsValidSmi(value); - } - - V8_INLINE static int GetInstanceType(const internal::Address obj) { - typedef internal::Address A; - A map = ReadTaggedPointerField(obj, kHeapObjectMapOffset); -#ifdef V8_MAP_PACKING - map = UnpackMapWord(map); -#endif - return ReadRawField(map, kMapInstanceTypeOffset); - } - - V8_INLINE static int GetOddballKind(const internal::Address obj) { - return SmiValue(ReadTaggedSignedField(obj, kOddballKindOffset)); - } - - V8_INLINE static bool IsExternalTwoByteString(int instance_type) { - int representation = (instance_type & kStringRepresentationAndEncodingMask); - return representation == kExternalTwoByteRepresentationTag; - } - - V8_INLINE static uint8_t GetNodeFlag(internal::Address* obj, int shift) { - uint8_t* addr = reinterpret_cast(obj) + kNodeFlagsOffset; - return *addr & static_cast(1U << shift); - } - - V8_INLINE static void UpdateNodeFlag(internal::Address* obj, bool value, - int shift) { - uint8_t* addr = reinterpret_cast(obj) + kNodeFlagsOffset; - uint8_t mask = static_cast(1U << shift); - *addr = static_cast((*addr & ~mask) | (value << shift)); - } - - V8_INLINE static uint8_t GetNodeState(internal::Address* obj) { - uint8_t* addr = reinterpret_cast(obj) + kNodeFlagsOffset; - return *addr & kNodeStateMask; - } - - V8_INLINE static void UpdateNodeState(internal::Address* obj, uint8_t value) { - uint8_t* addr = reinterpret_cast(obj) + kNodeFlagsOffset; - *addr = static_cast((*addr & ~kNodeStateMask) | value); - } - - V8_INLINE static void SetEmbedderData(v8::Isolate* isolate, uint32_t slot, - void* data) { - internal::Address addr = reinterpret_cast(isolate) + - kIsolateEmbedderDataOffset + - slot * kApiSystemPointerSize; - *reinterpret_cast(addr) = data; - } - - V8_INLINE static void* GetEmbedderData(const v8::Isolate* isolate, - uint32_t slot) { - internal::Address addr = reinterpret_cast(isolate) + - kIsolateEmbedderDataOffset + - slot * kApiSystemPointerSize; - return *reinterpret_cast(addr); - } - - V8_INLINE static void IncrementLongTasksStatsCounter(v8::Isolate* isolate) { - internal::Address addr = reinterpret_cast(isolate) + - kIsolateLongTaskStatsCounterOffset; - ++(*reinterpret_cast(addr)); - } - - V8_INLINE static internal::Address* GetRoot(v8::Isolate* isolate, int index) { - internal::Address addr = reinterpret_cast(isolate) + - kIsolateRootsOffset + - index * kApiSystemPointerSize; - return reinterpret_cast(addr); - } - - template - V8_INLINE static T ReadRawField(internal::Address heap_object_ptr, - int offset) { - internal::Address addr = heap_object_ptr + offset - kHeapObjectTag; -#ifdef V8_COMPRESS_POINTERS - if (sizeof(T) > kApiTaggedSize) { - // TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size - // fields (external pointers, doubles and BigInt data) are only - // kTaggedSize aligned so we have to use unaligned pointer friendly way of - // accessing them in order to avoid undefined behavior in C++ code. - T r; - memcpy(&r, reinterpret_cast(addr), sizeof(T)); - return r; - } -#endif - return *reinterpret_cast(addr); - } - - V8_INLINE static internal::Address ReadTaggedPointerField( - internal::Address heap_object_ptr, int offset) { -#ifdef V8_COMPRESS_POINTERS - uint32_t value = ReadRawField(heap_object_ptr, offset); - internal::Address base = - GetPtrComprCageBaseFromOnHeapAddress(heap_object_ptr); - return base + static_cast(static_cast(value)); -#else - return ReadRawField(heap_object_ptr, offset); -#endif - } - - V8_INLINE static internal::Address ReadTaggedSignedField( - internal::Address heap_object_ptr, int offset) { -#ifdef V8_COMPRESS_POINTERS - uint32_t value = ReadRawField(heap_object_ptr, offset); - return static_cast(static_cast(value)); -#else - return ReadRawField(heap_object_ptr, offset); -#endif - } - - V8_INLINE static internal::Isolate* GetIsolateForSandbox( - internal::Address obj) { -#ifdef V8_SANDBOXED_EXTERNAL_POINTERS - return internal::IsolateFromNeverReadOnlySpaceObject(obj); -#else - // Not used in non-sandbox mode. - return nullptr; -#endif - } - - V8_INLINE static Address DecodeExternalPointer( - const Isolate* isolate, ExternalPointer_t encoded_pointer, - ExternalPointerTag tag) { -#ifdef V8_SANDBOXED_EXTERNAL_POINTERS - return internal::DecodeExternalPointerImpl(isolate, encoded_pointer, tag); -#else - return encoded_pointer; -#endif - } - - V8_INLINE static internal::Address ReadExternalPointerField( - internal::Isolate* isolate, internal::Address heap_object_ptr, int offset, - ExternalPointerTag tag) { -#ifdef V8_SANDBOXED_EXTERNAL_POINTERS - internal::ExternalPointer_t encoded_value = - ReadRawField(heap_object_ptr, offset); - // We currently have to treat zero as nullptr in embedder slots. - return encoded_value ? DecodeExternalPointer(isolate, encoded_value, tag) - : 0; -#else - return ReadRawField
(heap_object_ptr, offset); -#endif - } - -#ifdef V8_COMPRESS_POINTERS - V8_INLINE static internal::Address GetPtrComprCageBaseFromOnHeapAddress( - internal::Address addr) { - return addr & -static_cast(kPtrComprCageBaseAlignment); - } - - V8_INLINE static internal::Address DecompressTaggedAnyField( - internal::Address heap_object_ptr, uint32_t value) { - internal::Address base = - GetPtrComprCageBaseFromOnHeapAddress(heap_object_ptr); - return base + static_cast(static_cast(value)); - } - -#endif // V8_COMPRESS_POINTERS -}; - -// Only perform cast check for types derived from v8::Data since -// other types do not implement the Cast method. -template -struct CastCheck { - template - static void Perform(T* data); -}; - -template <> -template -void CastCheck::Perform(T* data) { - T::Cast(data); -} - -template <> -template -void CastCheck::Perform(T* data) {} - -template -V8_INLINE void PerformCastCheck(T* data) { - CastCheck::value && - !std::is_same>::value>::Perform(data); -} - -// A base class for backing stores, which is needed due to vagaries of -// how static casts work with std::shared_ptr. -class BackingStoreBase {}; - -// The maximum value in enum GarbageCollectionReason, defined in heap.h. -// This is needed for histograms sampling garbage collection reasons. -constexpr int kGarbageCollectionReasonMaxValue = 25; - -} // namespace internal - -} // namespace v8 - -#endif // INCLUDE_V8_INTERNAL_H_ diff --git a/NativeScript/include/v8-isolate.h b/NativeScript/include/v8-isolate.h deleted file mode 100644 index 2849d7ca..00000000 --- a/NativeScript/include/v8-isolate.h +++ /dev/null @@ -1,1709 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_ISOLATE_H_ -#define INCLUDE_V8_ISOLATE_H_ - -#include -#include - -#include -#include - -#include "cppgc/common.h" -#include "v8-array-buffer.h" // NOLINT(build/include_directory) -#include "v8-callbacks.h" // NOLINT(build/include_directory) -#include "v8-data.h" // NOLINT(build/include_directory) -#include "v8-debug.h" // NOLINT(build/include_directory) -#include "v8-embedder-heap.h" // NOLINT(build/include_directory) -#include "v8-function-callback.h" // NOLINT(build/include_directory) -#include "v8-internal.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-microtask.h" // NOLINT(build/include_directory) -#include "v8-persistent-handle.h" // NOLINT(build/include_directory) -#include "v8-primitive.h" // NOLINT(build/include_directory) -#include "v8-statistics.h" // NOLINT(build/include_directory) -#include "v8-unwinder.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class CppHeap; -class HeapProfiler; -class MicrotaskQueue; -class StartupData; -class ScriptOrModule; -class SharedArrayBuffer; - -namespace internal { -class MicrotaskQueue; -class ThreadLocalTop; -} // namespace internal - -namespace metrics { -class Recorder; -} // namespace metrics - -/** - * A set of constraints that specifies the limits of the runtime's memory use. - * You must set the heap size before initializing the VM - the size cannot be - * adjusted after the VM is initialized. - * - * If you are using threads then you should hold the V8::Locker lock while - * setting the stack limit and you must set a non-default stack limit separately - * for each thread. - * - * The arguments for set_max_semi_space_size, set_max_old_space_size, - * set_max_executable_size, set_code_range_size specify limits in MB. - * - * The argument for set_max_semi_space_size_in_kb is in KB. - */ -class V8_EXPORT ResourceConstraints { - public: - /** - * Configures the constraints with reasonable default values based on the - * provided heap size limit. The heap size includes both the young and - * the old generation. - * - * \param initial_heap_size_in_bytes The initial heap size or zero. - * By default V8 starts with a small heap and dynamically grows it to - * match the set of live objects. This may lead to ineffective - * garbage collections at startup if the live set is large. - * Setting the initial heap size avoids such garbage collections. - * Note that this does not affect young generation garbage collections. - * - * \param maximum_heap_size_in_bytes The hard limit for the heap size. - * When the heap size approaches this limit, V8 will perform series of - * garbage collections and invoke the NearHeapLimitCallback. If the garbage - * collections do not help and the callback does not increase the limit, - * then V8 will crash with V8::FatalProcessOutOfMemory. - */ - void ConfigureDefaultsFromHeapSize(size_t initial_heap_size_in_bytes, - size_t maximum_heap_size_in_bytes); - - /** - * Configures the constraints with reasonable default values based on the - * capabilities of the current device the VM is running on. - * - * \param physical_memory The total amount of physical memory on the current - * device, in bytes. - * \param virtual_memory_limit The amount of virtual memory on the current - * device, in bytes, or zero, if there is no limit. - */ - void ConfigureDefaults(uint64_t physical_memory, - uint64_t virtual_memory_limit); - - /** - * The address beyond which the VM's stack may not grow. - */ - uint32_t* stack_limit() const { return stack_limit_; } - void set_stack_limit(uint32_t* value) { stack_limit_ = value; } - - /** - * The amount of virtual memory reserved for generated code. This is relevant - * for 64-bit architectures that rely on code range for calls in code. - * - * When V8_COMPRESS_POINTERS_IN_SHARED_CAGE is defined, there is a shared - * process-wide code range that is lazily initialized. This value is used to - * configure that shared code range when the first Isolate is - * created. Subsequent Isolates ignore this value. - */ - size_t code_range_size_in_bytes() const { return code_range_size_; } - void set_code_range_size_in_bytes(size_t limit) { code_range_size_ = limit; } - - /** - * The maximum size of the old generation. - * When the old generation approaches this limit, V8 will perform series of - * garbage collections and invoke the NearHeapLimitCallback. - * If the garbage collections do not help and the callback does not - * increase the limit, then V8 will crash with V8::FatalProcessOutOfMemory. - */ - size_t max_old_generation_size_in_bytes() const { - return max_old_generation_size_; - } - void set_max_old_generation_size_in_bytes(size_t limit) { - max_old_generation_size_ = limit; - } - - /** - * The maximum size of the young generation, which consists of two semi-spaces - * and a large object space. This affects frequency of Scavenge garbage - * collections and should be typically much smaller that the old generation. - */ - size_t max_young_generation_size_in_bytes() const { - return max_young_generation_size_; - } - void set_max_young_generation_size_in_bytes(size_t limit) { - max_young_generation_size_ = limit; - } - - size_t initial_old_generation_size_in_bytes() const { - return initial_old_generation_size_; - } - void set_initial_old_generation_size_in_bytes(size_t initial_size) { - initial_old_generation_size_ = initial_size; - } - - size_t initial_young_generation_size_in_bytes() const { - return initial_young_generation_size_; - } - void set_initial_young_generation_size_in_bytes(size_t initial_size) { - initial_young_generation_size_ = initial_size; - } - - private: - static constexpr size_t kMB = 1048576u; - size_t code_range_size_ = 0; - size_t max_old_generation_size_ = 0; - size_t max_young_generation_size_ = 0; - size_t initial_old_generation_size_ = 0; - size_t initial_young_generation_size_ = 0; - uint32_t* stack_limit_ = nullptr; -}; - -/** - * Option flags passed to the SetRAILMode function. - * See documentation https://developers.google.com/web/tools/chrome-devtools/ - * profile/evaluate-performance/rail - */ -enum RAILMode : unsigned { - // Response performance mode: In this mode very low virtual machine latency - // is provided. V8 will try to avoid JavaScript execution interruptions. - // Throughput may be throttled. - PERFORMANCE_RESPONSE, - // Animation performance mode: In this mode low virtual machine latency is - // provided. V8 will try to avoid as many JavaScript execution interruptions - // as possible. Throughput may be throttled. This is the default mode. - PERFORMANCE_ANIMATION, - // Idle performance mode: The embedder is idle. V8 can complete deferred work - // in this mode. - PERFORMANCE_IDLE, - // Load performance mode: In this mode high throughput is provided. V8 may - // turn off latency optimizations. - PERFORMANCE_LOAD -}; - -/** - * Memory pressure level for the MemoryPressureNotification. - * kNone hints V8 that there is no memory pressure. - * kModerate hints V8 to speed up incremental garbage collection at the cost of - * of higher latency due to garbage collection pauses. - * kCritical hints V8 to free memory as soon as possible. Garbage collection - * pauses at this level will be large. - */ -enum class MemoryPressureLevel { kNone, kModerate, kCritical }; - -/** - * Isolate represents an isolated instance of the V8 engine. V8 isolates have - * completely separate states. Objects from one isolate must not be used in - * other isolates. The embedder can create multiple isolates and use them in - * parallel in multiple threads. An isolate can be entered by at most one - * thread at any given time. The Locker/Unlocker API must be used to - * synchronize. - */ -class V8_EXPORT Isolate { - public: - /** - * Initial configuration parameters for a new Isolate. - */ - struct V8_EXPORT CreateParams { - CreateParams(); - ~CreateParams(); - - /** - * Allows the host application to provide the address of a function that is - * notified each time code is added, moved or removed. - */ - JitCodeEventHandler code_event_handler = nullptr; - - /** - * ResourceConstraints to use for the new Isolate. - */ - ResourceConstraints constraints; - - /** - * Explicitly specify a startup snapshot blob. The embedder owns the blob. - * The embedder *must* ensure that the snapshot is from a trusted source. - */ - StartupData* snapshot_blob = nullptr; - - /** - * Enables the host application to provide a mechanism for recording - * statistics counters. - */ - CounterLookupCallback counter_lookup_callback = nullptr; - - /** - * Enables the host application to provide a mechanism for recording - * histograms. The CreateHistogram function returns a - * histogram which will later be passed to the AddHistogramSample - * function. - */ - CreateHistogramCallback create_histogram_callback = nullptr; - AddHistogramSampleCallback add_histogram_sample_callback = nullptr; - - /** - * The ArrayBuffer::Allocator to use for allocating and freeing the backing - * store of ArrayBuffers. - * - * If the shared_ptr version is used, the Isolate instance and every - * |BackingStore| allocated using this allocator hold a std::shared_ptr - * to the allocator, in order to facilitate lifetime - * management for the allocator instance. - */ - ArrayBuffer::Allocator* array_buffer_allocator = nullptr; - std::shared_ptr array_buffer_allocator_shared; - - /** - * Specifies an optional nullptr-terminated array of raw addresses in the - * embedder that V8 can match against during serialization and use for - * deserialization. This array and its content must stay valid for the - * entire lifetime of the isolate. - */ - const intptr_t* external_references = nullptr; - - /** - * Whether calling Atomics.wait (a function that may block) is allowed in - * this isolate. This can also be configured via SetAllowAtomicsWait. - */ - bool allow_atomics_wait = true; - - /** - * Termination is postponed when there is no active SafeForTerminationScope. - */ - bool only_terminate_in_safe_scope = false; - - /** - * The following parameters describe the offsets for addressing type info - * for wrapped API objects and are used by the fast C API - * (for details see v8-fast-api-calls.h). - */ - int embedder_wrapper_type_index = -1; - int embedder_wrapper_object_index = -1; - - /** - * Callbacks to invoke in case of fatal or OOM errors. - */ - FatalErrorCallback fatal_error_callback = nullptr; - OOMErrorCallback oom_error_callback = nullptr; - - /** - * The following parameter is experimental and may change significantly. - * This is currently for internal testing. - */ - Isolate* experimental_attach_to_shared_isolate = nullptr; - }; - - /** - * Stack-allocated class which sets the isolate for all operations - * executed within a local scope. - */ - class V8_EXPORT V8_NODISCARD Scope { - public: - explicit Scope(Isolate* isolate) : isolate_(isolate) { isolate->Enter(); } - - ~Scope() { isolate_->Exit(); } - - // Prevent copying of Scope objects. - Scope(const Scope&) = delete; - Scope& operator=(const Scope&) = delete; - - private: - Isolate* const isolate_; - }; - - /** - * Assert that no Javascript code is invoked. - */ - class V8_EXPORT V8_NODISCARD DisallowJavascriptExecutionScope { - public: - enum OnFailure { CRASH_ON_FAILURE, THROW_ON_FAILURE, DUMP_ON_FAILURE }; - - DisallowJavascriptExecutionScope(Isolate* isolate, OnFailure on_failure); - ~DisallowJavascriptExecutionScope(); - - // Prevent copying of Scope objects. - DisallowJavascriptExecutionScope(const DisallowJavascriptExecutionScope&) = - delete; - DisallowJavascriptExecutionScope& operator=( - const DisallowJavascriptExecutionScope&) = delete; - - private: - OnFailure on_failure_; - Isolate* isolate_; - - bool was_execution_allowed_assert_; - bool was_execution_allowed_throws_; - bool was_execution_allowed_dump_; - }; - - /** - * Introduce exception to DisallowJavascriptExecutionScope. - */ - class V8_EXPORT V8_NODISCARD AllowJavascriptExecutionScope { - public: - explicit AllowJavascriptExecutionScope(Isolate* isolate); - ~AllowJavascriptExecutionScope(); - - // Prevent copying of Scope objects. - AllowJavascriptExecutionScope(const AllowJavascriptExecutionScope&) = - delete; - AllowJavascriptExecutionScope& operator=( - const AllowJavascriptExecutionScope&) = delete; - - private: - Isolate* isolate_; - bool was_execution_allowed_assert_; - bool was_execution_allowed_throws_; - bool was_execution_allowed_dump_; - }; - - /** - * Do not run microtasks while this scope is active, even if microtasks are - * automatically executed otherwise. - */ - class V8_EXPORT V8_NODISCARD SuppressMicrotaskExecutionScope { - public: - explicit SuppressMicrotaskExecutionScope( - Isolate* isolate, MicrotaskQueue* microtask_queue = nullptr); - ~SuppressMicrotaskExecutionScope(); - - // Prevent copying of Scope objects. - SuppressMicrotaskExecutionScope(const SuppressMicrotaskExecutionScope&) = - delete; - SuppressMicrotaskExecutionScope& operator=( - const SuppressMicrotaskExecutionScope&) = delete; - - private: - internal::Isolate* const isolate_; - internal::MicrotaskQueue* const microtask_queue_; - internal::Address previous_stack_height_; - - friend class internal::ThreadLocalTop; - }; - - /** - * This scope allows terminations inside direct V8 API calls and forbid them - * inside any recursive API calls without explicit SafeForTerminationScope. - */ - class V8_EXPORT V8_NODISCARD SafeForTerminationScope { - public: - explicit SafeForTerminationScope(v8::Isolate* isolate); - ~SafeForTerminationScope(); - - // Prevent copying of Scope objects. - SafeForTerminationScope(const SafeForTerminationScope&) = delete; - SafeForTerminationScope& operator=(const SafeForTerminationScope&) = delete; - - private: - internal::Isolate* isolate_; - bool prev_value_; - }; - - /** - * Types of garbage collections that can be requested via - * RequestGarbageCollectionForTesting. - */ - enum GarbageCollectionType { - kFullGarbageCollection, - kMinorGarbageCollection - }; - - /** - * Features reported via the SetUseCounterCallback callback. Do not change - * assigned numbers of existing items; add new features to the end of this - * list. - */ - enum UseCounterFeature { - kUseAsm = 0, - kBreakIterator = 1, - kLegacyConst = 2, - kMarkDequeOverflow = 3, - kStoreBufferOverflow = 4, - kSlotsBufferOverflow = 5, - kObjectObserve = 6, - kForcedGC = 7, - kSloppyMode = 8, - kStrictMode = 9, - kStrongMode = 10, - kRegExpPrototypeStickyGetter = 11, - kRegExpPrototypeToString = 12, - kRegExpPrototypeUnicodeGetter = 13, - kIntlV8Parse = 14, - kIntlPattern = 15, - kIntlResolved = 16, - kPromiseChain = 17, - kPromiseAccept = 18, - kPromiseDefer = 19, - kHtmlCommentInExternalScript = 20, - kHtmlComment = 21, - kSloppyModeBlockScopedFunctionRedefinition = 22, - kForInInitializer = 23, - kArrayProtectorDirtied = 24, - kArraySpeciesModified = 25, - kArrayPrototypeConstructorModified = 26, - kArrayInstanceProtoModified = 27, - kArrayInstanceConstructorModified = 28, - kLegacyFunctionDeclaration = 29, - kRegExpPrototypeSourceGetter = 30, // Unused. - kRegExpPrototypeOldFlagGetter = 31, // Unused. - kDecimalWithLeadingZeroInStrictMode = 32, - kLegacyDateParser = 33, - kDefineGetterOrSetterWouldThrow = 34, - kFunctionConstructorReturnedUndefined = 35, - kAssigmentExpressionLHSIsCallInSloppy = 36, - kAssigmentExpressionLHSIsCallInStrict = 37, - kPromiseConstructorReturnedUndefined = 38, - kConstructorNonUndefinedPrimitiveReturn = 39, - kLabeledExpressionStatement = 40, - kLineOrParagraphSeparatorAsLineTerminator = 41, - kIndexAccessor = 42, - kErrorCaptureStackTrace = 43, - kErrorPrepareStackTrace = 44, - kErrorStackTraceLimit = 45, - kWebAssemblyInstantiation = 46, - kDeoptimizerDisableSpeculation = 47, - kArrayPrototypeSortJSArrayModifiedPrototype = 48, - kFunctionTokenOffsetTooLongForToString = 49, - kWasmSharedMemory = 50, - kWasmThreadOpcodes = 51, - kAtomicsNotify = 52, // Unused. - kAtomicsWake = 53, // Unused. - kCollator = 54, - kNumberFormat = 55, - kDateTimeFormat = 56, - kPluralRules = 57, - kRelativeTimeFormat = 58, - kLocale = 59, - kListFormat = 60, - kSegmenter = 61, - kStringLocaleCompare = 62, - kStringToLocaleUpperCase = 63, - kStringToLocaleLowerCase = 64, - kNumberToLocaleString = 65, - kDateToLocaleString = 66, - kDateToLocaleDateString = 67, - kDateToLocaleTimeString = 68, - kAttemptOverrideReadOnlyOnPrototypeSloppy = 69, - kAttemptOverrideReadOnlyOnPrototypeStrict = 70, - kOptimizedFunctionWithOneShotBytecode = 71, // Unused. - kRegExpMatchIsTrueishOnNonJSRegExp = 72, - kRegExpMatchIsFalseishOnJSRegExp = 73, - kDateGetTimezoneOffset = 74, // Unused. - kStringNormalize = 75, - kCallSiteAPIGetFunctionSloppyCall = 76, - kCallSiteAPIGetThisSloppyCall = 77, - kRegExpMatchAllWithNonGlobalRegExp = 78, - kRegExpExecCalledOnSlowRegExp = 79, - kRegExpReplaceCalledOnSlowRegExp = 80, - kDisplayNames = 81, - kSharedArrayBufferConstructed = 82, - kArrayPrototypeHasElements = 83, - kObjectPrototypeHasElements = 84, - kNumberFormatStyleUnit = 85, - kDateTimeFormatRange = 86, - kDateTimeFormatDateTimeStyle = 87, - kBreakIteratorTypeWord = 88, - kBreakIteratorTypeLine = 89, - kInvalidatedArrayBufferDetachingProtector = 90, - kInvalidatedArrayConstructorProtector = 91, - kInvalidatedArrayIteratorLookupChainProtector = 92, - kInvalidatedArraySpeciesLookupChainProtector = 93, - kInvalidatedIsConcatSpreadableLookupChainProtector = 94, - kInvalidatedMapIteratorLookupChainProtector = 95, - kInvalidatedNoElementsProtector = 96, - kInvalidatedPromiseHookProtector = 97, - kInvalidatedPromiseResolveLookupChainProtector = 98, - kInvalidatedPromiseSpeciesLookupChainProtector = 99, - kInvalidatedPromiseThenLookupChainProtector = 100, - kInvalidatedRegExpSpeciesLookupChainProtector = 101, - kInvalidatedSetIteratorLookupChainProtector = 102, - kInvalidatedStringIteratorLookupChainProtector = 103, - kInvalidatedStringLengthOverflowLookupChainProtector = 104, - kInvalidatedTypedArraySpeciesLookupChainProtector = 105, - kWasmSimdOpcodes = 106, - kVarRedeclaredCatchBinding = 107, - kWasmRefTypes = 108, - kWasmBulkMemory = 109, // Unused. - kWasmMultiValue = 110, - kWasmExceptionHandling = 111, - kInvalidatedMegaDOMProtector = 112, - kFunctionPrototypeArguments = 113, - kFunctionPrototypeCaller = 114, - - // If you add new values here, you'll also need to update Chromium's: - // web_feature.mojom, use_counter_callback.cc, and enums.xml. V8 changes to - // this list need to be landed first, then changes on the Chromium side. - kUseCounterFeatureCount // This enum value must be last. - }; - - enum MessageErrorLevel { - kMessageLog = (1 << 0), - kMessageDebug = (1 << 1), - kMessageInfo = (1 << 2), - kMessageError = (1 << 3), - kMessageWarning = (1 << 4), - kMessageAll = kMessageLog | kMessageDebug | kMessageInfo | kMessageError | - kMessageWarning, - }; - - using UseCounterCallback = void (*)(Isolate* isolate, - UseCounterFeature feature); - - /** - * Allocates a new isolate but does not initialize it. Does not change the - * currently entered isolate. - * - * Only Isolate::GetData() and Isolate::SetData(), which access the - * embedder-controlled parts of the isolate, are allowed to be called on the - * uninitialized isolate. To initialize the isolate, call - * Isolate::Initialize(). - * - * When an isolate is no longer used its resources should be freed - * by calling Dispose(). Using the delete operator is not allowed. - * - * V8::Initialize() must have run prior to this. - */ - static Isolate* Allocate(); - - /** - * Initialize an Isolate previously allocated by Isolate::Allocate(). - */ - static void Initialize(Isolate* isolate, const CreateParams& params); - - /** - * Creates a new isolate. Does not change the currently entered - * isolate. - * - * When an isolate is no longer used its resources should be freed - * by calling Dispose(). Using the delete operator is not allowed. - * - * V8::Initialize() must have run prior to this. - */ - static Isolate* New(const CreateParams& params); - - /** - * Returns the entered isolate for the current thread or NULL in - * case there is no current isolate. - * - * This method must not be invoked before V8::Initialize() was invoked. - */ - static Isolate* GetCurrent(); - - /** - * Returns the entered isolate for the current thread or NULL in - * case there is no current isolate. - * - * No checks are performed by this method. - */ - static Isolate* TryGetCurrent(); - - /** - * Return true if this isolate is currently active. - **/ - bool IsCurrent() const; - - /** - * Clears the set of objects held strongly by the heap. This set of - * objects are originally built when a WeakRef is created or - * successfully dereferenced. - * - * This is invoked automatically after microtasks are run. See - * MicrotasksPolicy for when microtasks are run. - * - * This needs to be manually invoked only if the embedder is manually running - * microtasks via a custom MicrotaskQueue class's PerformCheckpoint. In that - * case, it is the embedder's responsibility to make this call at a time which - * does not interrupt synchronous ECMAScript code execution. - */ - void ClearKeptObjects(); - - /** - * Custom callback used by embedders to help V8 determine if it should abort - * when it throws and no internal handler is predicted to catch the - * exception. If --abort-on-uncaught-exception is used on the command line, - * then V8 will abort if either: - * - no custom callback is set. - * - the custom callback set returns true. - * Otherwise, the custom callback will not be called and V8 will not abort. - */ - using AbortOnUncaughtExceptionCallback = bool (*)(Isolate*); - void SetAbortOnUncaughtExceptionCallback( - AbortOnUncaughtExceptionCallback callback); - - /** - * This specifies the callback called by the upcoming dynamic - * import() language feature to load modules. - */ - V8_DEPRECATED("Use HostImportModuleDynamicallyCallback") - void SetHostImportModuleDynamicallyCallback( - HostImportModuleDynamicallyWithImportAssertionsCallback callback); - void SetHostImportModuleDynamicallyCallback( - HostImportModuleDynamicallyCallback callback); - - /** - * This specifies the callback called by the upcoming import.meta - * language feature to retrieve host-defined meta data for a module. - */ - void SetHostInitializeImportMetaObjectCallback( - HostInitializeImportMetaObjectCallback callback); - - /** - * This specifies the callback called by the upcoming ShadowRealm - * construction language feature to retrieve host created globals. - */ - void SetHostCreateShadowRealmContextCallback( - HostCreateShadowRealmContextCallback callback); - - /** - * This specifies the callback called when the stack property of Error - * is accessed. - */ - void SetPrepareStackTraceCallback(PrepareStackTraceCallback callback); - - /** - * Optional notification that the system is running low on memory. - * V8 uses these notifications to guide heuristics. - * It is allowed to call this function from another thread while - * the isolate is executing long running JavaScript code. - */ - void MemoryPressureNotification(MemoryPressureLevel level); - - /** - * Drop non-essential caches. Should only be called from testing code. - * The method can potentially block for a long time and does not necessarily - * trigger GC. - */ - void ClearCachesForTesting(); - - /** - * Methods below this point require holding a lock (using Locker) in - * a multi-threaded environment. - */ - - /** - * Sets this isolate as the entered one for the current thread. - * Saves the previously entered one (if any), so that it can be - * restored when exiting. Re-entering an isolate is allowed. - */ - void Enter(); - - /** - * Exits this isolate by restoring the previously entered one in the - * current thread. The isolate may still stay the same, if it was - * entered more than once. - * - * Requires: this == Isolate::GetCurrent(). - */ - void Exit(); - - /** - * Disposes the isolate. The isolate must not be entered by any - * thread to be disposable. - */ - void Dispose(); - - /** - * Dumps activated low-level V8 internal stats. This can be used instead - * of performing a full isolate disposal. - */ - void DumpAndResetStats(); - - /** - * Discards all V8 thread-specific data for the Isolate. Should be used - * if a thread is terminating and it has used an Isolate that will outlive - * the thread -- all thread-specific data for an Isolate is discarded when - * an Isolate is disposed so this call is pointless if an Isolate is about - * to be Disposed. - */ - void DiscardThreadSpecificMetadata(); - - /** - * Associate embedder-specific data with the isolate. |slot| has to be - * between 0 and GetNumberOfDataSlots() - 1. - */ - V8_INLINE void SetData(uint32_t slot, void* data); - - /** - * Retrieve embedder-specific data from the isolate. - * Returns NULL if SetData has never been called for the given |slot|. - */ - V8_INLINE void* GetData(uint32_t slot); - - /** - * Returns the maximum number of available embedder data slots. Valid slots - * are in the range of 0 - GetNumberOfDataSlots() - 1. - */ - V8_INLINE static uint32_t GetNumberOfDataSlots(); - - /** - * Return data that was previously attached to the isolate snapshot via - * SnapshotCreator, and removes the reference to it. - * Repeated call with the same index returns an empty MaybeLocal. - */ - template - V8_INLINE MaybeLocal GetDataFromSnapshotOnce(size_t index); - - /** - * Get statistics about the heap memory usage. - */ - void GetHeapStatistics(HeapStatistics* heap_statistics); - - /** - * Returns the number of spaces in the heap. - */ - size_t NumberOfHeapSpaces(); - - /** - * Get the memory usage of a space in the heap. - * - * \param space_statistics The HeapSpaceStatistics object to fill in - * statistics. - * \param index The index of the space to get statistics from, which ranges - * from 0 to NumberOfHeapSpaces() - 1. - * \returns true on success. - */ - bool GetHeapSpaceStatistics(HeapSpaceStatistics* space_statistics, - size_t index); - - /** - * Returns the number of types of objects tracked in the heap at GC. - */ - size_t NumberOfTrackedHeapObjectTypes(); - - /** - * Get statistics about objects in the heap. - * - * \param object_statistics The HeapObjectStatistics object to fill in - * statistics of objects of given type, which were live in the previous GC. - * \param type_index The index of the type of object to fill details about, - * which ranges from 0 to NumberOfTrackedHeapObjectTypes() - 1. - * \returns true on success. - */ - bool GetHeapObjectStatisticsAtLastGC(HeapObjectStatistics* object_statistics, - size_t type_index); - - /** - * Get statistics about code and its metadata in the heap. - * - * \param object_statistics The HeapCodeStatistics object to fill in - * statistics of code, bytecode and their metadata. - * \returns true on success. - */ - bool GetHeapCodeAndMetadataStatistics(HeapCodeStatistics* object_statistics); - - /** - * This API is experimental and may change significantly. - * - * Enqueues a memory measurement request and invokes the delegate with the - * results. - * - * \param delegate the delegate that defines which contexts to measure and - * reports the results. - * - * \param execution promptness executing the memory measurement. - * The kEager value is expected to be used only in tests. - */ - bool MeasureMemory( - std::unique_ptr delegate, - MeasureMemoryExecution execution = MeasureMemoryExecution::kDefault); - - /** - * Get a call stack sample from the isolate. - * \param state Execution state. - * \param frames Caller allocated buffer to store stack frames. - * \param frames_limit Maximum number of frames to capture. The buffer must - * be large enough to hold the number of frames. - * \param sample_info The sample info is filled up by the function - * provides number of actual captured stack frames and - * the current VM state. - * \note GetStackSample should only be called when the JS thread is paused or - * interrupted. Otherwise the behavior is undefined. - */ - void GetStackSample(const RegisterState& state, void** frames, - size_t frames_limit, SampleInfo* sample_info); - - /** - * Adjusts the amount of registered external memory. Used to give V8 an - * indication of the amount of externally allocated memory that is kept alive - * by JavaScript objects. V8 uses this to decide when to perform global - * garbage collections. Registering externally allocated memory will trigger - * global garbage collections more often than it would otherwise in an attempt - * to garbage collect the JavaScript objects that keep the externally - * allocated memory alive. - * - * \param change_in_bytes the change in externally allocated memory that is - * kept alive by JavaScript objects. - * \returns the adjusted value. - */ - int64_t AdjustAmountOfExternalAllocatedMemory(int64_t change_in_bytes); - - /** - * Returns the number of phantom handles without callbacks that were reset - * by the garbage collector since the last call to this function. - */ - size_t NumberOfPhantomHandleResetsSinceLastCall(); - - /** - * Returns heap profiler for this isolate. Will return NULL until the isolate - * is initialized. - */ - HeapProfiler* GetHeapProfiler(); - - /** - * Tells the VM whether the embedder is idle or not. - */ - void SetIdle(bool is_idle); - - /** Returns the ArrayBuffer::Allocator used in this isolate. */ - ArrayBuffer::Allocator* GetArrayBufferAllocator(); - - /** Returns true if this isolate has a current context. */ - bool InContext(); - - /** - * Returns the context of the currently running JavaScript, or the context - * on the top of the stack if no JavaScript is running. - */ - Local GetCurrentContext(); - - /** - * Returns either the last context entered through V8's C++ API, or the - * context of the currently running microtask while processing microtasks. - * If a context is entered while executing a microtask, that context is - * returned. - */ - Local GetEnteredOrMicrotaskContext(); - - /** - * Returns the Context that corresponds to the Incumbent realm in HTML spec. - * https://html.spec.whatwg.org/multipage/webappapis.html#incumbent - */ - Local GetIncumbentContext(); - - /** - * Schedules a v8::Exception::Error with the given message. - * See ThrowException for more details. Templatized to provide compile-time - * errors in case of too long strings (see v8::String::NewFromUtf8Literal). - */ - template - Local ThrowError(const char (&message)[N]) { - return ThrowError(String::NewFromUtf8Literal(this, message)); - } - Local ThrowError(Local message); - - /** - * Schedules an exception to be thrown when returning to JavaScript. When an - * exception has been scheduled it is illegal to invoke any JavaScript - * operation; the caller must return immediately and only after the exception - * has been handled does it become legal to invoke JavaScript operations. - */ - Local ThrowException(Local exception); - - using GCCallback = void (*)(Isolate* isolate, GCType type, - GCCallbackFlags flags); - using GCCallbackWithData = void (*)(Isolate* isolate, GCType type, - GCCallbackFlags flags, void* data); - - /** - * Enables the host application to receive a notification before a - * garbage collection. Allocations are allowed in the callback function, - * but the callback is not re-entrant: if the allocation inside it will - * trigger the garbage collection, the callback won't be called again. - * It is possible to specify the GCType filter for your callback. But it is - * not possible to register the same callback function two times with - * different GCType filters. - */ - void AddGCPrologueCallback(GCCallbackWithData callback, void* data = nullptr, - GCType gc_type_filter = kGCTypeAll); - void AddGCPrologueCallback(GCCallback callback, - GCType gc_type_filter = kGCTypeAll); - - /** - * This function removes callback which was installed by - * AddGCPrologueCallback function. - */ - void RemoveGCPrologueCallback(GCCallbackWithData, void* data = nullptr); - void RemoveGCPrologueCallback(GCCallback callback); - - /** - * Sets the embedder heap tracer for the isolate. - * SetEmbedderHeapTracer cannot be used simultaneously with AttachCppHeap. - */ - void SetEmbedderHeapTracer(EmbedderHeapTracer* tracer); - - /* - * Gets the currently active heap tracer for the isolate that was set with - * SetEmbedderHeapTracer. - */ - EmbedderHeapTracer* GetEmbedderHeapTracer(); - - /** - * Sets an embedder roots handle that V8 should consider when performing - * non-unified heap garbage collections. - * - * Using only EmbedderHeapTracer automatically sets up a default handler. - * The intended use case is for setting a custom handler after invoking - * `AttachCppHeap()`. - * - * V8 does not take ownership of the handler. - */ - void SetEmbedderRootsHandler(EmbedderRootsHandler* handler); - - /** - * Attaches a managed C++ heap as an extension to the JavaScript heap. The - * embedder maintains ownership of the CppHeap. At most one C++ heap can be - * attached to V8. - * AttachCppHeap cannot be used simultaneously with SetEmbedderHeapTracer. - * - * This is an experimental feature and may still change significantly. - */ - void AttachCppHeap(CppHeap*); - - /** - * Detaches a managed C++ heap if one was attached using `AttachCppHeap()`. - * - * This is an experimental feature and may still change significantly. - */ - void DetachCppHeap(); - - /** - * This is an experimental feature and may still change significantly. - - * \returns the C++ heap managed by V8. Only available if such a heap has been - * attached using `AttachCppHeap()`. - */ - CppHeap* GetCppHeap() const; - - /** - * Use for |AtomicsWaitCallback| to indicate the type of event it receives. - */ - enum class AtomicsWaitEvent { - /** Indicates that this call is happening before waiting. */ - kStartWait, - /** `Atomics.wait()` finished because of an `Atomics.wake()` call. */ - kWokenUp, - /** `Atomics.wait()` finished because it timed out. */ - kTimedOut, - /** `Atomics.wait()` was interrupted through |TerminateExecution()|. */ - kTerminatedExecution, - /** `Atomics.wait()` was stopped through |AtomicsWaitWakeHandle|. */ - kAPIStopped, - /** `Atomics.wait()` did not wait, as the initial condition was not met. */ - kNotEqual - }; - - /** - * Passed to |AtomicsWaitCallback| as a means of stopping an ongoing - * `Atomics.wait` call. - */ - class V8_EXPORT AtomicsWaitWakeHandle { - public: - /** - * Stop this `Atomics.wait()` call and call the |AtomicsWaitCallback| - * with |kAPIStopped|. - * - * This function may be called from another thread. The caller has to ensure - * through proper synchronization that it is not called after - * the finishing |AtomicsWaitCallback|. - * - * Note that the ECMAScript specification does not plan for the possibility - * of wakeups that are neither coming from a timeout or an `Atomics.wake()` - * call, so this may invalidate assumptions made by existing code. - * The embedder may accordingly wish to schedule an exception in the - * finishing |AtomicsWaitCallback|. - */ - void Wake(); - }; - - /** - * Embedder callback for `Atomics.wait()` that can be added through - * |SetAtomicsWaitCallback|. - * - * This will be called just before starting to wait with the |event| value - * |kStartWait| and after finishing waiting with one of the other - * values of |AtomicsWaitEvent| inside of an `Atomics.wait()` call. - * - * |array_buffer| will refer to the underlying SharedArrayBuffer, - * |offset_in_bytes| to the location of the waited-on memory address inside - * the SharedArrayBuffer. - * - * |value| and |timeout_in_ms| will be the values passed to - * the `Atomics.wait()` call. If no timeout was used, |timeout_in_ms| - * will be `INFINITY`. - * - * In the |kStartWait| callback, |stop_handle| will be an object that - * is only valid until the corresponding finishing callback and that - * can be used to stop the wait process while it is happening. - * - * This callback may schedule exceptions, *unless* |event| is equal to - * |kTerminatedExecution|. - */ - using AtomicsWaitCallback = void (*)(AtomicsWaitEvent event, - Local array_buffer, - size_t offset_in_bytes, int64_t value, - double timeout_in_ms, - AtomicsWaitWakeHandle* stop_handle, - void* data); - - /** - * Set a new |AtomicsWaitCallback|. This overrides an earlier - * |AtomicsWaitCallback|, if there was any. If |callback| is nullptr, - * this unsets the callback. |data| will be passed to the callback - * as its last parameter. - */ - void SetAtomicsWaitCallback(AtomicsWaitCallback callback, void* data); - - /** - * Enables the host application to receive a notification after a - * garbage collection. Allocations are allowed in the callback function, - * but the callback is not re-entrant: if the allocation inside it will - * trigger the garbage collection, the callback won't be called again. - * It is possible to specify the GCType filter for your callback. But it is - * not possible to register the same callback function two times with - * different GCType filters. - */ - void AddGCEpilogueCallback(GCCallbackWithData callback, void* data = nullptr, - GCType gc_type_filter = kGCTypeAll); - void AddGCEpilogueCallback(GCCallback callback, - GCType gc_type_filter = kGCTypeAll); - - /** - * This function removes callback which was installed by - * AddGCEpilogueCallback function. - */ - void RemoveGCEpilogueCallback(GCCallbackWithData callback, - void* data = nullptr); - void RemoveGCEpilogueCallback(GCCallback callback); - - using GetExternallyAllocatedMemoryInBytesCallback = size_t (*)(); - - /** - * Set the callback that tells V8 how much memory is currently allocated - * externally of the V8 heap. Ideally this memory is somehow connected to V8 - * objects and may get freed-up when the corresponding V8 objects get - * collected by a V8 garbage collection. - */ - void SetGetExternallyAllocatedMemoryInBytesCallback( - GetExternallyAllocatedMemoryInBytesCallback callback); - - /** - * Forcefully terminate the current thread of JavaScript execution - * in the given isolate. - * - * This method can be used by any thread even if that thread has not - * acquired the V8 lock with a Locker object. - */ - void TerminateExecution(); - - /** - * Is V8 terminating JavaScript execution. - * - * Returns true if JavaScript execution is currently terminating - * because of a call to TerminateExecution. In that case there are - * still JavaScript frames on the stack and the termination - * exception is still active. - */ - bool IsExecutionTerminating(); - - /** - * Resume execution capability in the given isolate, whose execution - * was previously forcefully terminated using TerminateExecution(). - * - * When execution is forcefully terminated using TerminateExecution(), - * the isolate can not resume execution until all JavaScript frames - * have propagated the uncatchable exception which is generated. This - * method allows the program embedding the engine to handle the - * termination event and resume execution capability, even if - * JavaScript frames remain on the stack. - * - * This method can be used by any thread even if that thread has not - * acquired the V8 lock with a Locker object. - */ - void CancelTerminateExecution(); - - /** - * Request V8 to interrupt long running JavaScript code and invoke - * the given |callback| passing the given |data| to it. After |callback| - * returns control will be returned to the JavaScript code. - * There may be a number of interrupt requests in flight. - * Can be called from another thread without acquiring a |Locker|. - * Registered |callback| must not reenter interrupted Isolate. - */ - void RequestInterrupt(InterruptCallback callback, void* data); - - /** - * Returns true if there is ongoing background work within V8 that will - * eventually post a foreground task, like asynchronous WebAssembly - * compilation. - */ - bool HasPendingBackgroundTasks(); - - /** - * Request garbage collection in this Isolate. It is only valid to call this - * function if --expose_gc was specified. - * - * This should only be used for testing purposes and not to enforce a garbage - * collection schedule. It has strong negative impact on the garbage - * collection performance. Use IdleNotificationDeadline() or - * LowMemoryNotification() instead to influence the garbage collection - * schedule. - */ - void RequestGarbageCollectionForTesting(GarbageCollectionType type); - - /** - * Request garbage collection with a specific embedderstack state in this - * Isolate. It is only valid to call this function if --expose_gc was - * specified. - * - * This should only be used for testing purposes and not to enforce a garbage - * collection schedule. It has strong negative impact on the garbage - * collection performance. Use IdleNotificationDeadline() or - * LowMemoryNotification() instead to influence the garbage collection - * schedule. - */ - void RequestGarbageCollectionForTesting( - GarbageCollectionType type, - EmbedderHeapTracer::EmbedderStackState stack_state); - - /** - * Set the callback to invoke for logging event. - */ - void SetEventLogger(LogEventCallback that); - - /** - * Adds a callback to notify the host application right before a script - * is about to run. If a script re-enters the runtime during executing, the - * BeforeCallEnteredCallback is invoked for each re-entrance. - * Executing scripts inside the callback will re-trigger the callback. - */ - void AddBeforeCallEnteredCallback(BeforeCallEnteredCallback callback); - - /** - * Removes callback that was installed by AddBeforeCallEnteredCallback. - */ - void RemoveBeforeCallEnteredCallback(BeforeCallEnteredCallback callback); - - /** - * Adds a callback to notify the host application when a script finished - * running. If a script re-enters the runtime during executing, the - * CallCompletedCallback is only invoked when the outer-most script - * execution ends. Executing scripts inside the callback do not trigger - * further callbacks. - */ - void AddCallCompletedCallback(CallCompletedCallback callback); - - /** - * Removes callback that was installed by AddCallCompletedCallback. - */ - void RemoveCallCompletedCallback(CallCompletedCallback callback); - - /** - * Set the PromiseHook callback for various promise lifecycle - * events. - */ - void SetPromiseHook(PromiseHook hook); - - /** - * Set callback to notify about promise reject with no handler, or - * revocation of such a previous notification once the handler is added. - */ - void SetPromiseRejectCallback(PromiseRejectCallback callback); - - /** - * Runs the default MicrotaskQueue until it gets empty and perform other - * microtask checkpoint steps, such as calling ClearKeptObjects. Asserts that - * the MicrotasksPolicy is not kScoped. Any exceptions thrown by microtask - * callbacks are swallowed. - */ - void PerformMicrotaskCheckpoint(); - - /** - * Enqueues the callback to the default MicrotaskQueue - */ - void EnqueueMicrotask(Local microtask); - - /** - * Enqueues the callback to the default MicrotaskQueue - */ - void EnqueueMicrotask(MicrotaskCallback callback, void* data = nullptr); - - /** - * Controls how Microtasks are invoked. See MicrotasksPolicy for details. - */ - void SetMicrotasksPolicy(MicrotasksPolicy policy); - - /** - * Returns the policy controlling how Microtasks are invoked. - */ - MicrotasksPolicy GetMicrotasksPolicy() const; - - /** - * Adds a callback to notify the host application after - * microtasks were run on the default MicrotaskQueue. The callback is - * triggered by explicit RunMicrotasks call or automatic microtasks execution - * (see SetMicrotaskPolicy). - * - * Callback will trigger even if microtasks were attempted to run, - * but the microtasks queue was empty and no single microtask was actually - * executed. - * - * Executing scripts inside the callback will not re-trigger microtasks and - * the callback. - */ - void AddMicrotasksCompletedCallback( - MicrotasksCompletedCallbackWithData callback, void* data = nullptr); - - /** - * Removes callback that was installed by AddMicrotasksCompletedCallback. - */ - void RemoveMicrotasksCompletedCallback( - MicrotasksCompletedCallbackWithData callback, void* data = nullptr); - - /** - * Sets a callback for counting the number of times a feature of V8 is used. - */ - void SetUseCounterCallback(UseCounterCallback callback); - - /** - * Enables the host application to provide a mechanism for recording - * statistics counters. - */ - void SetCounterFunction(CounterLookupCallback); - - /** - * Enables the host application to provide a mechanism for recording - * histograms. The CreateHistogram function returns a - * histogram which will later be passed to the AddHistogramSample - * function. - */ - void SetCreateHistogramFunction(CreateHistogramCallback); - void SetAddHistogramSampleFunction(AddHistogramSampleCallback); - - /** - * Enables the host application to provide a mechanism for recording - * event based metrics. In order to use this interface - * include/v8-metrics.h - * needs to be included and the recorder needs to be derived from the - * Recorder base class defined there. - * This method can only be called once per isolate and must happen during - * isolate initialization before background threads are spawned. - */ - void SetMetricsRecorder( - const std::shared_ptr& metrics_recorder); - - /** - * Enables the host application to provide a mechanism for recording a - * predefined set of data as crash keys to be used in postmortem debugging in - * case of a crash. - */ - void SetAddCrashKeyCallback(AddCrashKeyCallback); - - /** - * Optional notification that the embedder is idle. - * V8 uses the notification to perform garbage collection. - * This call can be used repeatedly if the embedder remains idle. - * Returns true if the embedder should stop calling IdleNotificationDeadline - * until real work has been done. This indicates that V8 has done - * as much cleanup as it will be able to do. - * - * The deadline_in_seconds argument specifies the deadline V8 has to finish - * garbage collection work. deadline_in_seconds is compared with - * MonotonicallyIncreasingTime() and should be based on the same timebase as - * that function. There is no guarantee that the actual work will be done - * within the time limit. - */ - bool IdleNotificationDeadline(double deadline_in_seconds); - - /** - * Optional notification that the system is running low on memory. - * V8 uses these notifications to attempt to free memory. - */ - void LowMemoryNotification(); - - /** - * Optional notification that a context has been disposed. V8 uses these - * notifications to guide the GC heuristic and cancel FinalizationRegistry - * cleanup tasks. Returns the number of context disposals - including this one - * - since the last time V8 had a chance to clean up. - * - * The optional parameter |dependant_context| specifies whether the disposed - * context was depending on state from other contexts or not. - */ - int ContextDisposedNotification(bool dependant_context = true); - - /** - * Optional notification that the isolate switched to the foreground. - * V8 uses these notifications to guide heuristics. - */ - void IsolateInForegroundNotification(); - - /** - * Optional notification that the isolate switched to the background. - * V8 uses these notifications to guide heuristics. - */ - void IsolateInBackgroundNotification(); - - /** - * Optional notification which will enable the memory savings mode. - * V8 uses this notification to guide heuristics which may result in a - * smaller memory footprint at the cost of reduced runtime performance. - */ - void EnableMemorySavingsMode(); - - /** - * Optional notification which will disable the memory savings mode. - */ - void DisableMemorySavingsMode(); - - /** - * Optional notification to tell V8 the current performance requirements - * of the embedder based on RAIL. - * V8 uses these notifications to guide heuristics. - * This is an unfinished experimental feature. Semantics and implementation - * may change frequently. - */ - void SetRAILMode(RAILMode rail_mode); - - /** - * Update load start time of the RAIL mode - */ - void UpdateLoadStartTime(); - - /** - * Optional notification to tell V8 the current isolate is used for debugging - * and requires higher heap limit. - */ - void IncreaseHeapLimitForDebugging(); - - /** - * Restores the original heap limit after IncreaseHeapLimitForDebugging(). - */ - void RestoreOriginalHeapLimit(); - - /** - * Returns true if the heap limit was increased for debugging and the - * original heap limit was not restored yet. - */ - bool IsHeapLimitIncreasedForDebugging(); - - /** - * Allows the host application to provide the address of a function that is - * notified each time code is added, moved or removed. - * - * \param options options for the JIT code event handler. - * \param event_handler the JIT code event handler, which will be invoked - * each time code is added, moved or removed. - * \note \p event_handler won't get notified of existent code. - * \note since code removal notifications are not currently issued, the - * \p event_handler may get notifications of code that overlaps earlier - * code notifications. This happens when code areas are reused, and the - * earlier overlapping code areas should therefore be discarded. - * \note the events passed to \p event_handler and the strings they point to - * are not guaranteed to live past each call. The \p event_handler must - * copy strings and other parameters it needs to keep around. - * \note the set of events declared in JitCodeEvent::EventType is expected to - * grow over time, and the JitCodeEvent structure is expected to accrue - * new members. The \p event_handler function must ignore event codes - * it does not recognize to maintain future compatibility. - * \note Use Isolate::CreateParams to get events for code executed during - * Isolate setup. - */ - void SetJitCodeEventHandler(JitCodeEventOptions options, - JitCodeEventHandler event_handler); - - /** - * Modifies the stack limit for this Isolate. - * - * \param stack_limit An address beyond which the Vm's stack may not grow. - * - * \note If you are using threads then you should hold the V8::Locker lock - * while setting the stack limit and you must set a non-default stack - * limit separately for each thread. - */ - void SetStackLimit(uintptr_t stack_limit); - - /** - * Returns a memory range that can potentially contain jitted code. Code for - * V8's 'builtins' will not be in this range if embedded builtins is enabled. - * - * On Win64, embedders are advised to install function table callbacks for - * these ranges, as default SEH won't be able to unwind through jitted code. - * The first page of the code range is reserved for the embedder and is - * committed, writable, and executable, to be used to store unwind data, as - * documented in - * https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64. - * - * Might be empty on other platforms. - * - * https://code.google.com/p/v8/issues/detail?id=3598 - */ - void GetCodeRange(void** start, size_t* length_in_bytes); - - /** - * As GetCodeRange, but for embedded builtins (these live in a distinct - * memory region from other V8 Code objects). - */ - void GetEmbeddedCodeRange(const void** start, size_t* length_in_bytes); - - /** - * Returns the JSEntryStubs necessary for use with the Unwinder API. - */ - JSEntryStubs GetJSEntryStubs(); - - static constexpr size_t kMinCodePagesBufferSize = 32; - - /** - * Copies the code heap pages currently in use by V8 into |code_pages_out|. - * |code_pages_out| must have at least kMinCodePagesBufferSize capacity and - * must be empty. - * - * Signal-safe, does not allocate, does not access the V8 heap. - * No code on the stack can rely on pages that might be missing. - * - * Returns the number of pages available to be copied, which might be greater - * than |capacity|. In this case, only |capacity| pages will be copied into - * |code_pages_out|. The caller should provide a bigger buffer on the next - * call in order to get all available code pages, but this is not required. - */ - size_t CopyCodePages(size_t capacity, MemoryRange* code_pages_out); - - /** Set the callback to invoke in case of fatal errors. */ - void SetFatalErrorHandler(FatalErrorCallback that); - - /** Set the callback to invoke in case of OOM errors. */ - void SetOOMErrorHandler(OOMErrorCallback that); - - /** - * Add a callback to invoke in case the heap size is close to the heap limit. - * If multiple callbacks are added, only the most recently added callback is - * invoked. - */ - void AddNearHeapLimitCallback(NearHeapLimitCallback callback, void* data); - - /** - * Remove the given callback and restore the heap limit to the - * given limit. If the given limit is zero, then it is ignored. - * If the current heap size is greater than the given limit, - * then the heap limit is restored to the minimal limit that - * is possible for the current heap size. - */ - void RemoveNearHeapLimitCallback(NearHeapLimitCallback callback, - size_t heap_limit); - - /** - * If the heap limit was changed by the NearHeapLimitCallback, then the - * initial heap limit will be restored once the heap size falls below the - * given threshold percentage of the initial heap limit. - * The threshold percentage is a number in (0.0, 1.0) range. - */ - void AutomaticallyRestoreInitialHeapLimit(double threshold_percent = 0.5); - - /** - * Set the callback to invoke to check if code generation from - * strings should be allowed. - */ - void SetModifyCodeGenerationFromStringsCallback( - ModifyCodeGenerationFromStringsCallback2 callback); - - /** - * Set the callback to invoke to check if wasm code generation should - * be allowed. - */ - void SetAllowWasmCodeGenerationCallback( - AllowWasmCodeGenerationCallback callback); - - /** - * Embedder over{ride|load} injection points for wasm APIs. The expectation - * is that the embedder sets them at most once. - */ - void SetWasmModuleCallback(ExtensionCallback callback); - void SetWasmInstanceCallback(ExtensionCallback callback); - - void SetWasmStreamingCallback(WasmStreamingCallback callback); - - void SetWasmLoadSourceMapCallback(WasmLoadSourceMapCallback callback); - - void SetWasmSimdEnabledCallback(WasmSimdEnabledCallback callback); - - void SetWasmExceptionsEnabledCallback(WasmExceptionsEnabledCallback callback); - - void SetWasmDynamicTieringEnabledCallback( - WasmDynamicTieringEnabledCallback callback); - - void SetSharedArrayBufferConstructorEnabledCallback( - SharedArrayBufferConstructorEnabledCallback callback); - - /** - * This function can be called by the embedder to signal V8 that the dynamic - * enabling of features has finished. V8 can now set up dynamically added - * features. - */ - void InstallConditionalFeatures(Local context); - - /** - * Check if V8 is dead and therefore unusable. This is the case after - * fatal errors such as out-of-memory situations. - */ - bool IsDead(); - - /** - * Adds a message listener (errors only). - * - * The same message listener can be added more than once and in that - * case it will be called more than once for each message. - * - * If data is specified, it will be passed to the callback when it is called. - * Otherwise, the exception object will be passed to the callback instead. - */ - bool AddMessageListener(MessageCallback that, - Local data = Local()); - - /** - * Adds a message listener. - * - * The same message listener can be added more than once and in that - * case it will be called more than once for each message. - * - * If data is specified, it will be passed to the callback when it is called. - * Otherwise, the exception object will be passed to the callback instead. - * - * A listener can listen for particular error levels by providing a mask. - */ - bool AddMessageListenerWithErrorLevel(MessageCallback that, - int message_levels, - Local data = Local()); - - /** - * Remove all message listeners from the specified callback function. - */ - void RemoveMessageListeners(MessageCallback that); - - /** Callback function for reporting failed access checks.*/ - void SetFailedAccessCheckCallbackFunction(FailedAccessCheckCallback); - - /** - * Tells V8 to capture current stack trace when uncaught exception occurs - * and report it to the message listeners. The option is off by default. - */ - void SetCaptureStackTraceForUncaughtExceptions( - bool capture, int frame_limit = 10, - StackTrace::StackTraceOptions options = StackTrace::kOverview); - - /** - * Iterates through all external resources referenced from current isolate - * heap. GC is not invoked prior to iterating, therefore there is no - * guarantee that visited objects are still alive. - */ - void VisitExternalResources(ExternalResourceVisitor* visitor); - - /** - * Iterates through all the persistent handles in the current isolate's heap - * that have class_ids. - */ - void VisitHandlesWithClassIds(PersistentHandleVisitor* visitor); - - /** - * Iterates through all the persistent handles in the current isolate's heap - * that have class_ids and are weak to be marked as inactive if there is no - * pending activity for the handle. - */ - void VisitWeakHandles(PersistentHandleVisitor* visitor); - - /** - * Check if this isolate is in use. - * True if at least one thread Enter'ed this isolate. - */ - bool IsInUse(); - - /** - * Set whether calling Atomics.wait (a function that may block) is allowed in - * this isolate. This can also be configured via - * CreateParams::allow_atomics_wait. - */ - void SetAllowAtomicsWait(bool allow); - - /** - * Time zone redetection indicator for - * DateTimeConfigurationChangeNotification. - * - * kSkip indicates V8 that the notification should not trigger redetecting - * host time zone. kRedetect indicates V8 that host time zone should be - * redetected, and used to set the default time zone. - * - * The host time zone detection may require file system access or similar - * operations unlikely to be available inside a sandbox. If v8 is run inside a - * sandbox, the host time zone has to be detected outside the sandbox before - * calling DateTimeConfigurationChangeNotification function. - */ - enum class TimeZoneDetection { kSkip, kRedetect }; - - /** - * Notification that the embedder has changed the time zone, daylight savings - * time or other date / time configuration parameters. V8 keeps a cache of - * various values used for date / time computation. This notification will - * reset those cached values for the current context so that date / time - * configuration changes would be reflected. - * - * This API should not be called more than needed as it will negatively impact - * the performance of date operations. - */ - void DateTimeConfigurationChangeNotification( - TimeZoneDetection time_zone_detection = TimeZoneDetection::kSkip); - - /** - * Notification that the embedder has changed the locale. V8 keeps a cache of - * various values used for locale computation. This notification will reset - * those cached values for the current context so that locale configuration - * changes would be reflected. - * - * This API should not be called more than needed as it will negatively impact - * the performance of locale operations. - */ - void LocaleConfigurationChangeNotification(); - - Isolate() = delete; - ~Isolate() = delete; - Isolate(const Isolate&) = delete; - Isolate& operator=(const Isolate&) = delete; - // Deleting operator new and delete here is allowed as ctor and dtor is also - // deleted. - void* operator new(size_t size) = delete; - void* operator new[](size_t size) = delete; - void operator delete(void*, size_t) = delete; - void operator delete[](void*, size_t) = delete; - - private: - template - friend class PersistentValueMapBase; - - internal::Address* GetDataFromSnapshotOnce(size_t index); - void ReportExternalAllocationLimitReached(); -}; - -void Isolate::SetData(uint32_t slot, void* data) { - using I = internal::Internals; - I::SetEmbedderData(this, slot, data); -} - -void* Isolate::GetData(uint32_t slot) { - using I = internal::Internals; - return I::GetEmbedderData(this, slot); -} - -uint32_t Isolate::GetNumberOfDataSlots() { - using I = internal::Internals; - return I::kNumIsolateDataSlots; -} - -template -MaybeLocal Isolate::GetDataFromSnapshotOnce(size_t index) { - T* data = reinterpret_cast(GetDataFromSnapshotOnce(index)); - if (data) internal::PerformCastCheck(data); - return Local(data); -} - -} // namespace v8 - -#endif // INCLUDE_V8_ISOLATE_H_ diff --git a/NativeScript/include/v8-json.h b/NativeScript/include/v8-json.h deleted file mode 100644 index 23d918fc..00000000 --- a/NativeScript/include/v8-json.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_JSON_H_ -#define INCLUDE_V8_JSON_H_ - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; -class Value; -class String; - -/** - * A JSON Parser and Stringifier. - */ -class V8_EXPORT JSON { - public: - /** - * Tries to parse the string |json_string| and returns it as value if - * successful. - * - * \param the context in which to parse and create the value. - * \param json_string The string to parse. - * \return The corresponding value if successfully parsed. - */ - static V8_WARN_UNUSED_RESULT MaybeLocal Parse( - Local context, Local json_string); - - /** - * Tries to stringify the JSON-serializable object |json_object| and returns - * it as string if successful. - * - * \param json_object The JSON-serializable object to stringify. - * \return The corresponding string if successfully stringified. - */ - static V8_WARN_UNUSED_RESULT MaybeLocal Stringify( - Local context, Local json_object, - Local gap = Local()); -}; - -} // namespace v8 - -#endif // INCLUDE_V8_JSON_H_ diff --git a/NativeScript/include/v8-local-handle.h b/NativeScript/include/v8-local-handle.h deleted file mode 100644 index 5ae97408..00000000 --- a/NativeScript/include/v8-local-handle.h +++ /dev/null @@ -1,455 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_LOCAL_HANDLE_H_ -#define INCLUDE_V8_LOCAL_HANDLE_H_ - -#include - -#include - -#include "v8-internal.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Boolean; -template -class BasicTracedReference; -class Context; -class EscapableHandleScope; -template -class Eternal; -template -class FunctionCallbackInfo; -class Isolate; -template -class MaybeLocal; -template -class NonCopyablePersistentTraits; -class Object; -template > -class Persistent; -template -class PersistentBase; -template -class PersistentValueMapBase; -template -class PersistentValueVector; -class Primitive; -class Private; -template -class PropertyCallbackInfo; -template -class ReturnValue; -class String; -template -class Traced; -template -class TracedReference; -class TracedReferenceBase; -class Utils; - -namespace internal { -template -class CustomArguments; -} // namespace internal - -namespace api_internal { -// Called when ToLocalChecked is called on an empty Local. -V8_EXPORT void ToLocalEmpty(); -} // namespace api_internal - -/** - * A stack-allocated class that governs a number of local handles. - * After a handle scope has been created, all local handles will be - * allocated within that handle scope until either the handle scope is - * deleted or another handle scope is created. If there is already a - * handle scope and a new one is created, all allocations will take - * place in the new handle scope until it is deleted. After that, - * new handles will again be allocated in the original handle scope. - * - * After the handle scope of a local handle has been deleted the - * garbage collector will no longer track the object stored in the - * handle and may deallocate it. The behavior of accessing a handle - * for which the handle scope has been deleted is undefined. - */ -class V8_EXPORT V8_NODISCARD HandleScope { - public: - explicit HandleScope(Isolate* isolate); - - ~HandleScope(); - - /** - * Counts the number of allocated handles. - */ - static int NumberOfHandles(Isolate* isolate); - - V8_INLINE Isolate* GetIsolate() const { - return reinterpret_cast(isolate_); - } - - HandleScope(const HandleScope&) = delete; - void operator=(const HandleScope&) = delete; - - protected: - V8_INLINE HandleScope() = default; - - void Initialize(Isolate* isolate); - - static internal::Address* CreateHandle(internal::Isolate* isolate, - internal::Address value); - - private: - // Declaring operator new and delete as deleted is not spec compliant. - // Therefore declare them private instead to disable dynamic alloc - void* operator new(size_t size); - void* operator new[](size_t size); - void operator delete(void*, size_t); - void operator delete[](void*, size_t); - - internal::Isolate* isolate_; - internal::Address* prev_next_; - internal::Address* prev_limit_; - - // Local::New uses CreateHandle with an Isolate* parameter. - template - friend class Local; - - // Object::GetInternalField and Context::GetEmbedderData use CreateHandle with - // a HeapObject in their shortcuts. - friend class Object; - friend class Context; -}; - -/** - * An object reference managed by the v8 garbage collector. - * - * All objects returned from v8 have to be tracked by the garbage collector so - * that it knows that the objects are still alive. Also, because the garbage - * collector may move objects, it is unsafe to point directly to an object. - * Instead, all objects are stored in handles which are known by the garbage - * collector and updated whenever an object moves. Handles should always be - * passed by value (except in cases like out-parameters) and they should never - * be allocated on the heap. - * - * There are two types of handles: local and persistent handles. - * - * Local handles are light-weight and transient and typically used in local - * operations. They are managed by HandleScopes. That means that a HandleScope - * must exist on the stack when they are created and that they are only valid - * inside of the HandleScope active during their creation. For passing a local - * handle to an outer HandleScope, an EscapableHandleScope and its Escape() - * method must be used. - * - * Persistent handles can be used when storing objects across several - * independent operations and have to be explicitly deallocated when they're no - * longer used. - * - * It is safe to extract the object stored in the handle by dereferencing the - * handle (for instance, to extract the Object* from a Local); the value - * will still be governed by a handle behind the scenes and the same rules apply - * to these values as to their handles. - */ -template -class Local { - public: - V8_INLINE Local() : val_(nullptr) {} - template - V8_INLINE Local(Local that) : val_(reinterpret_cast(*that)) { - /** - * This check fails when trying to convert between incompatible - * handles. For example, converting from a Local to a - * Local. - */ - static_assert(std::is_base_of::value, "type check"); - } - - /** - * Returns true if the handle is empty. - */ - V8_INLINE bool IsEmpty() const { return val_ == nullptr; } - - /** - * Sets the handle to be empty. IsEmpty() will then return true. - */ - V8_INLINE void Clear() { val_ = nullptr; } - - V8_INLINE T* operator->() const { return val_; } - - V8_INLINE T* operator*() const { return val_; } - - /** - * Checks whether two handles are the same. - * Returns true if both are empty, or if the objects to which they refer - * are identical. - * - * If both handles refer to JS objects, this is the same as strict equality. - * For primitives, such as numbers or strings, a `false` return value does not - * indicate that the values aren't equal in the JavaScript sense. - * Use `Value::StrictEquals()` to check primitives for equality. - */ - template - V8_INLINE bool operator==(const Local& that) const { - internal::Address* a = reinterpret_cast(this->val_); - internal::Address* b = reinterpret_cast(that.val_); - if (a == nullptr) return b == nullptr; - if (b == nullptr) return false; - return *a == *b; - } - - template - V8_INLINE bool operator==(const PersistentBase& that) const { - internal::Address* a = reinterpret_cast(this->val_); - internal::Address* b = reinterpret_cast(that.val_); - if (a == nullptr) return b == nullptr; - if (b == nullptr) return false; - return *a == *b; - } - - /** - * Checks whether two handles are different. - * Returns true if only one of the handles is empty, or if - * the objects to which they refer are different. - * - * If both handles refer to JS objects, this is the same as strict - * non-equality. For primitives, such as numbers or strings, a `true` return - * value does not indicate that the values aren't equal in the JavaScript - * sense. Use `Value::StrictEquals()` to check primitives for equality. - */ - template - V8_INLINE bool operator!=(const Local& that) const { - return !operator==(that); - } - - template - V8_INLINE bool operator!=(const Persistent& that) const { - return !operator==(that); - } - - /** - * Cast a handle to a subclass, e.g. Local to Local. - * This is only valid if the handle actually refers to a value of the - * target type. - */ - template - V8_INLINE static Local Cast(Local that) { -#ifdef V8_ENABLE_CHECKS - // If we're going to perform the type check then we have to check - // that the handle isn't empty before doing the checked cast. - if (that.IsEmpty()) return Local(); -#endif - return Local(T::Cast(*that)); - } - - /** - * Calling this is equivalent to Local::Cast(). - * In particular, this is only valid if the handle actually refers to a value - * of the target type. - */ - template - V8_INLINE Local As() const { - return Local::Cast(*this); - } - - /** - * Create a local handle for the content of another handle. - * The referee is kept alive by the local handle even when - * the original handle is destroyed/disposed. - */ - V8_INLINE static Local New(Isolate* isolate, Local that) { - return New(isolate, that.val_); - } - - V8_INLINE static Local New(Isolate* isolate, - const PersistentBase& that) { - return New(isolate, that.val_); - } - - V8_INLINE static Local New(Isolate* isolate, - const BasicTracedReference& that) { - return New(isolate, *that); - } - - private: - friend class TracedReferenceBase; - friend class Utils; - template - friend class Eternal; - template - friend class PersistentBase; - template - friend class Persistent; - template - friend class Local; - template - friend class MaybeLocal; - template - friend class FunctionCallbackInfo; - template - friend class PropertyCallbackInfo; - friend class String; - friend class Object; - friend class Context; - friend class Isolate; - friend class Private; - template - friend class internal::CustomArguments; - friend Local Undefined(Isolate* isolate); - friend Local Null(Isolate* isolate); - friend Local True(Isolate* isolate); - friend Local False(Isolate* isolate); - friend class HandleScope; - friend class EscapableHandleScope; - template - friend class PersistentValueMapBase; - template - friend class PersistentValueVector; - template - friend class ReturnValue; - template - friend class Traced; - template - friend class BasicTracedReference; - template - friend class TracedReference; - - explicit V8_INLINE Local(T* that) : val_(that) {} - V8_INLINE static Local New(Isolate* isolate, T* that) { - if (that == nullptr) return Local(); - T* that_ptr = that; - internal::Address* p = reinterpret_cast(that_ptr); - return Local(reinterpret_cast(HandleScope::CreateHandle( - reinterpret_cast(isolate), *p))); - } - T* val_; -}; - -#if !defined(V8_IMMINENT_DEPRECATION_WARNINGS) -// Handle is an alias for Local for historical reasons. -template -using Handle = Local; -#endif - -/** - * A MaybeLocal<> is a wrapper around Local<> that enforces a check whether - * the Local<> is empty before it can be used. - * - * If an API method returns a MaybeLocal<>, the API method can potentially fail - * either because an exception is thrown, or because an exception is pending, - * e.g. because a previous API call threw an exception that hasn't been caught - * yet, or because a TerminateExecution exception was thrown. In that case, an - * empty MaybeLocal is returned. - */ -template -class MaybeLocal { - public: - V8_INLINE MaybeLocal() : val_(nullptr) {} - template - V8_INLINE MaybeLocal(Local that) : val_(reinterpret_cast(*that)) { - static_assert(std::is_base_of::value, "type check"); - } - - V8_INLINE bool IsEmpty() const { return val_ == nullptr; } - - /** - * Converts this MaybeLocal<> to a Local<>. If this MaybeLocal<> is empty, - * |false| is returned and |out| is left untouched. - */ - template - V8_WARN_UNUSED_RESULT V8_INLINE bool ToLocal(Local* out) const { - out->val_ = IsEmpty() ? nullptr : this->val_; - return !IsEmpty(); - } - - /** - * Converts this MaybeLocal<> to a Local<>. If this MaybeLocal<> is empty, - * V8 will crash the process. - */ - V8_INLINE Local ToLocalChecked() { - if (V8_UNLIKELY(val_ == nullptr)) api_internal::ToLocalEmpty(); - return Local(val_); - } - - /** - * Converts this MaybeLocal<> to a Local<>, using a default value if this - * MaybeLocal<> is empty. - */ - template - V8_INLINE Local FromMaybe(Local default_value) const { - return IsEmpty() ? default_value : Local(val_); - } - - private: - T* val_; -}; - -/** - * A HandleScope which first allocates a handle in the current scope - * which will be later filled with the escape value. - */ -class V8_EXPORT V8_NODISCARD EscapableHandleScope : public HandleScope { - public: - explicit EscapableHandleScope(Isolate* isolate); - V8_INLINE ~EscapableHandleScope() = default; - - /** - * Pushes the value into the previous scope and returns a handle to it. - * Cannot be called twice. - */ - template - V8_INLINE Local Escape(Local value) { - internal::Address* slot = - Escape(reinterpret_cast(*value)); - return Local(reinterpret_cast(slot)); - } - - template - V8_INLINE MaybeLocal EscapeMaybe(MaybeLocal value) { - return Escape(value.FromMaybe(Local())); - } - - EscapableHandleScope(const EscapableHandleScope&) = delete; - void operator=(const EscapableHandleScope&) = delete; - - private: - // Declaring operator new and delete as deleted is not spec compliant. - // Therefore declare them private instead to disable dynamic alloc - void* operator new(size_t size); - void* operator new[](size_t size); - void operator delete(void*, size_t); - void operator delete[](void*, size_t); - - internal::Address* Escape(internal::Address* escape_value); - internal::Address* escape_slot_; -}; - -/** - * A SealHandleScope acts like a handle scope in which no handle allocations - * are allowed. It can be useful for debugging handle leaks. - * Handles can be allocated within inner normal HandleScopes. - */ -class V8_EXPORT V8_NODISCARD SealHandleScope { - public: - explicit SealHandleScope(Isolate* isolate); - ~SealHandleScope(); - - SealHandleScope(const SealHandleScope&) = delete; - void operator=(const SealHandleScope&) = delete; - - private: - // Declaring operator new and delete as deleted is not spec compliant. - // Therefore declare them private instead to disable dynamic alloc - void* operator new(size_t size); - void* operator new[](size_t size); - void operator delete(void*, size_t); - void operator delete[](void*, size_t); - - internal::Isolate* const isolate_; - internal::Address* prev_limit_; - int prev_sealed_level_; -}; - -} // namespace v8 - -#endif // INCLUDE_V8_LOCAL_HANDLE_H_ diff --git a/NativeScript/include/v8-locker.h b/NativeScript/include/v8-locker.h deleted file mode 100644 index 7ca5bf6e..00000000 --- a/NativeScript/include/v8-locker.h +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_LOCKER_H_ -#define INCLUDE_V8_LOCKER_H_ - -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -namespace internal { -class Isolate; -} // namespace internal - -class Isolate; - -/** - * Multiple threads in V8 are allowed, but only one thread at a time is allowed - * to use any given V8 isolate, see the comments in the Isolate class. The - * definition of 'using a V8 isolate' includes accessing handles or holding onto - * object pointers obtained from V8 handles while in the particular V8 isolate. - * It is up to the user of V8 to ensure, perhaps with locking, that this - * constraint is not violated. In addition to any other synchronization - * mechanism that may be used, the v8::Locker and v8::Unlocker classes must be - * used to signal thread switches to V8. - * - * v8::Locker is a scoped lock object. While it's active, i.e. between its - * construction and destruction, the current thread is allowed to use the locked - * isolate. V8 guarantees that an isolate can be locked by at most one thread at - * any time. In other words, the scope of a v8::Locker is a critical section. - * - * Sample usage: - * \code - * ... - * { - * v8::Locker locker(isolate); - * v8::Isolate::Scope isolate_scope(isolate); - * ... - * // Code using V8 and isolate goes here. - * ... - * } // Destructor called here - * \endcode - * - * If you wish to stop using V8 in a thread A you can do this either by - * destroying the v8::Locker object as above or by constructing a v8::Unlocker - * object: - * - * \code - * { - * isolate->Exit(); - * v8::Unlocker unlocker(isolate); - * ... - * // Code not using V8 goes here while V8 can run in another thread. - * ... - * } // Destructor called here. - * isolate->Enter(); - * \endcode - * - * The Unlocker object is intended for use in a long-running callback from V8, - * where you want to release the V8 lock for other threads to use. - * - * The v8::Locker is a recursive lock, i.e. you can lock more than once in a - * given thread. This can be useful if you have code that can be called either - * from code that holds the lock or from code that does not. The Unlocker is - * not recursive so you can not have several Unlockers on the stack at once, and - * you cannot use an Unlocker in a thread that is not inside a Locker's scope. - * - * An unlocker will unlock several lockers if it has to and reinstate the - * correct depth of locking on its destruction, e.g.: - * - * \code - * // V8 not locked. - * { - * v8::Locker locker(isolate); - * Isolate::Scope isolate_scope(isolate); - * // V8 locked. - * { - * v8::Locker another_locker(isolate); - * // V8 still locked (2 levels). - * { - * isolate->Exit(); - * v8::Unlocker unlocker(isolate); - * // V8 not locked. - * } - * isolate->Enter(); - * // V8 locked again (2 levels). - * } - * // V8 still locked (1 level). - * } - * // V8 Now no longer locked. - * \endcode - */ -class V8_EXPORT Unlocker { - public: - /** - * Initialize Unlocker for a given Isolate. - */ - V8_INLINE explicit Unlocker(Isolate* isolate) { Initialize(isolate); } - - ~Unlocker(); - - private: - void Initialize(Isolate* isolate); - - internal::Isolate* isolate_; -}; - -class V8_EXPORT Locker { - public: - /** - * Initialize Locker for a given Isolate. - */ - V8_INLINE explicit Locker(Isolate* isolate) { Initialize(isolate); } - - ~Locker(); - - /** - * Returns whether or not the locker for a given isolate, is locked by the - * current thread. - */ - static bool IsLocked(Isolate* isolate); - - /** - * Returns whether any v8::Locker has ever been used in this process. - * TODO(cbruni, chromium:1240851): Fix locking checks on a per-thread basis. - * The current implementation is quite confusing and leads to unexpected - * results if anybody uses v8::Locker in the current process. - */ - V8_DEPRECATE_SOON("This method will be removed.") - static bool WasEverUsed(); - V8_DEPRECATED("Use WasEverUsed instead") - static bool IsActive(); - - // Disallow copying and assigning. - Locker(const Locker&) = delete; - void operator=(const Locker&) = delete; - - private: - void Initialize(Isolate* isolate); - - bool has_lock_; - bool top_level_; - internal::Isolate* isolate_; -}; - -} // namespace v8 - -#endif // INCLUDE_V8_LOCKER_H_ diff --git a/NativeScript/include/v8-maybe.h b/NativeScript/include/v8-maybe.h deleted file mode 100644 index 0532a510..00000000 --- a/NativeScript/include/v8-maybe.h +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_MAYBE_H_ -#define INCLUDE_V8_MAYBE_H_ - -#include "v8-internal.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -namespace api_internal { -// Called when ToChecked is called on an empty Maybe. -V8_EXPORT void FromJustIsNothing(); -} // namespace api_internal - -/** - * A simple Maybe type, representing an object which may or may not have a - * value, see https://hackage.haskell.org/package/base/docs/Data-Maybe.html. - * - * If an API method returns a Maybe<>, the API method can potentially fail - * either because an exception is thrown, or because an exception is pending, - * e.g. because a previous API call threw an exception that hasn't been caught - * yet, or because a TerminateExecution exception was thrown. In that case, a - * "Nothing" value is returned. - */ -template -class Maybe { - public: - V8_INLINE bool IsNothing() const { return !has_value_; } - V8_INLINE bool IsJust() const { return has_value_; } - - /** - * An alias for |FromJust|. Will crash if the Maybe<> is nothing. - */ - V8_INLINE T ToChecked() const { return FromJust(); } - - /** - * Short-hand for ToChecked(), which doesn't return a value. To be used, where - * the actual value of the Maybe is not needed like Object::Set. - */ - V8_INLINE void Check() const { - if (V8_UNLIKELY(!IsJust())) api_internal::FromJustIsNothing(); - } - - /** - * Converts this Maybe<> to a value of type T. If this Maybe<> is - * nothing (empty), |false| is returned and |out| is left untouched. - */ - V8_WARN_UNUSED_RESULT V8_INLINE bool To(T* out) const { - if (V8_LIKELY(IsJust())) *out = value_; - return IsJust(); - } - - /** - * Converts this Maybe<> to a value of type T. If this Maybe<> is - * nothing (empty), V8 will crash the process. - */ - V8_INLINE T FromJust() const { - if (V8_UNLIKELY(!IsJust())) api_internal::FromJustIsNothing(); - return value_; - } - - /** - * Converts this Maybe<> to a value of type T, using a default value if this - * Maybe<> is nothing (empty). - */ - V8_INLINE T FromMaybe(const T& default_value) const { - return has_value_ ? value_ : default_value; - } - - V8_INLINE bool operator==(const Maybe& other) const { - return (IsJust() == other.IsJust()) && - (!IsJust() || FromJust() == other.FromJust()); - } - - V8_INLINE bool operator!=(const Maybe& other) const { - return !operator==(other); - } - - private: - Maybe() : has_value_(false) {} - explicit Maybe(const T& t) : has_value_(true), value_(t) {} - - bool has_value_; - T value_; - - template - friend Maybe Nothing(); - template - friend Maybe Just(const U& u); -}; - -template -inline Maybe Nothing() { - return Maybe(); -} - -template -inline Maybe Just(const T& t) { - return Maybe(t); -} - -// A template specialization of Maybe for the case of T = void. -template <> -class Maybe { - public: - V8_INLINE bool IsNothing() const { return !is_valid_; } - V8_INLINE bool IsJust() const { return is_valid_; } - - V8_INLINE bool operator==(const Maybe& other) const { - return IsJust() == other.IsJust(); - } - - V8_INLINE bool operator!=(const Maybe& other) const { - return !operator==(other); - } - - private: - struct JustTag {}; - - Maybe() : is_valid_(false) {} - explicit Maybe(JustTag) : is_valid_(true) {} - - bool is_valid_; - - template - friend Maybe Nothing(); - friend Maybe JustVoid(); -}; - -inline Maybe JustVoid() { return Maybe(Maybe::JustTag()); } - -} // namespace v8 - -#endif // INCLUDE_V8_MAYBE_H_ diff --git a/NativeScript/include/v8-memory-span.h b/NativeScript/include/v8-memory-span.h deleted file mode 100644 index b26af4f7..00000000 --- a/NativeScript/include/v8-memory-span.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_MEMORY_SPAN_H_ -#define INCLUDE_V8_MEMORY_SPAN_H_ - -#include - -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -/** - * Points to an unowned continous buffer holding a known number of elements. - * - * This is similar to std::span (under consideration for C++20), but does not - * require advanced C++ support. In the (far) future, this may be replaced with - * or aliased to std::span. - * - * To facilitate future migration, this class exposes a subset of the interface - * implemented by std::span. - */ -template -class V8_EXPORT MemorySpan { - public: - /** The default constructor creates an empty span. */ - constexpr MemorySpan() = default; - - constexpr MemorySpan(T* data, size_t size) : data_(data), size_(size) {} - - /** Returns a pointer to the beginning of the buffer. */ - constexpr T* data() const { return data_; } - /** Returns the number of elements that the buffer holds. */ - constexpr size_t size() const { return size_; } - - private: - T* data_ = nullptr; - size_t size_ = 0; -}; - -} // namespace v8 -#endif // INCLUDE_V8_MEMORY_SPAN_H_ diff --git a/NativeScript/include/v8-message.h b/NativeScript/include/v8-message.h deleted file mode 100644 index a1327641..00000000 --- a/NativeScript/include/v8-message.h +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_MESSAGE_H_ -#define INCLUDE_V8_MESSAGE_H_ - -#include - -#include - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-maybe.h" // NOLINT(build/include_directory) -#include "v8-primitive.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Integer; -class PrimitiveArray; -class StackTrace; -class String; -class Value; - -/** - * The optional attributes of ScriptOrigin. - */ -class ScriptOriginOptions { - public: - V8_INLINE ScriptOriginOptions(bool is_shared_cross_origin = false, - bool is_opaque = false, bool is_wasm = false, - bool is_module = false) - : flags_((is_shared_cross_origin ? kIsSharedCrossOrigin : 0) | - (is_wasm ? kIsWasm : 0) | (is_opaque ? kIsOpaque : 0) | - (is_module ? kIsModule : 0)) {} - V8_INLINE ScriptOriginOptions(int flags) - : flags_(flags & - (kIsSharedCrossOrigin | kIsOpaque | kIsWasm | kIsModule)) {} - - bool IsSharedCrossOrigin() const { - return (flags_ & kIsSharedCrossOrigin) != 0; - } - bool IsOpaque() const { return (flags_ & kIsOpaque) != 0; } - bool IsWasm() const { return (flags_ & kIsWasm) != 0; } - bool IsModule() const { return (flags_ & kIsModule) != 0; } - - int Flags() const { return flags_; } - - private: - enum { - kIsSharedCrossOrigin = 1, - kIsOpaque = 1 << 1, - kIsWasm = 1 << 2, - kIsModule = 1 << 3 - }; - const int flags_; -}; - -/** - * The origin, within a file, of a script. - */ -class V8_EXPORT ScriptOrigin { - public: - V8_INLINE ScriptOrigin(Isolate* isolate, Local resource_name, - int resource_line_offset = 0, - int resource_column_offset = 0, - bool resource_is_shared_cross_origin = false, - int script_id = -1, - Local source_map_url = Local(), - bool resource_is_opaque = false, bool is_wasm = false, - bool is_module = false, - Local host_defined_options = Local()) - : isolate_(isolate), - resource_name_(resource_name), - resource_line_offset_(resource_line_offset), - resource_column_offset_(resource_column_offset), - options_(resource_is_shared_cross_origin, resource_is_opaque, is_wasm, - is_module), - script_id_(script_id), - source_map_url_(source_map_url), - host_defined_options_(host_defined_options) { - VerifyHostDefinedOptions(); - } - - V8_INLINE Local ResourceName() const; - V8_INLINE int LineOffset() const; - V8_INLINE int ColumnOffset() const; - V8_INLINE int ScriptId() const; - V8_INLINE Local SourceMapUrl() const; - V8_DEPRECATE_SOON("Use GetHostDefinedOptions") - Local HostDefinedOptions() const; - V8_INLINE Local GetHostDefinedOptions() const; - V8_INLINE ScriptOriginOptions Options() const { return options_; } - - private: - void VerifyHostDefinedOptions() const; - Isolate* isolate_; - Local resource_name_; - int resource_line_offset_; - int resource_column_offset_; - ScriptOriginOptions options_; - int script_id_; - Local source_map_url_; - Local host_defined_options_; -}; - -/** - * An error message. - */ -class V8_EXPORT Message { - public: - Local Get() const; - - /** - * Return the isolate to which the Message belongs. - */ - Isolate* GetIsolate() const; - - V8_WARN_UNUSED_RESULT MaybeLocal GetSource( - Local context) const; - V8_WARN_UNUSED_RESULT MaybeLocal GetSourceLine( - Local context) const; - - /** - * Returns the origin for the script from where the function causing the - * error originates. - */ - ScriptOrigin GetScriptOrigin() const; - - /** - * Returns the resource name for the script from where the function causing - * the error originates. - */ - Local GetScriptResourceName() const; - - /** - * Exception stack trace. By default stack traces are not captured for - * uncaught exceptions. SetCaptureStackTraceForUncaughtExceptions allows - * to change this option. - */ - Local GetStackTrace() const; - - /** - * Returns the number, 1-based, of the line where the error occurred. - */ - V8_WARN_UNUSED_RESULT Maybe GetLineNumber(Local context) const; - - /** - * Returns the index within the script of the first character where - * the error occurred. - */ - int GetStartPosition() const; - - /** - * Returns the index within the script of the last character where - * the error occurred. - */ - int GetEndPosition() const; - - /** - * Returns the Wasm function index where the error occurred. Returns -1 if - * message is not from a Wasm script. - */ - int GetWasmFunctionIndex() const; - - /** - * Returns the error level of the message. - */ - int ErrorLevel() const; - - /** - * Returns the index within the line of the first character where - * the error occurred. - */ - int GetStartColumn() const; - V8_WARN_UNUSED_RESULT Maybe GetStartColumn(Local context) const; - - /** - * Returns the index within the line of the last character where - * the error occurred. - */ - int GetEndColumn() const; - V8_WARN_UNUSED_RESULT Maybe GetEndColumn(Local context) const; - - /** - * Passes on the value set by the embedder when it fed the script from which - * this Message was generated to V8. - */ - bool IsSharedCrossOrigin() const; - bool IsOpaque() const; - - static void PrintCurrentStackTrace(Isolate* isolate, std::ostream& out); - - static const int kNoLineNumberInfo = 0; - static const int kNoColumnInfo = 0; - static const int kNoScriptIdInfo = 0; - static const int kNoWasmFunctionIndexInfo = -1; -}; - -Local ScriptOrigin::ResourceName() const { return resource_name_; } - -Local ScriptOrigin::GetHostDefinedOptions() const { - return host_defined_options_; -} - -int ScriptOrigin::LineOffset() const { return resource_line_offset_; } - -int ScriptOrigin::ColumnOffset() const { return resource_column_offset_; } - -int ScriptOrigin::ScriptId() const { return script_id_; } - -Local ScriptOrigin::SourceMapUrl() const { return source_map_url_; } - -} // namespace v8 - -#endif // INCLUDE_V8_MESSAGE_H_ diff --git a/NativeScript/include/v8-metrics.h b/NativeScript/include/v8-metrics.h deleted file mode 100644 index d8e8bd86..00000000 --- a/NativeScript/include/v8-metrics.h +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_METRICS_H_ -#define V8_METRICS_H_ - -#include -#include - -#include - -#include "v8-internal.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; -class Isolate; - -namespace metrics { - -struct GarbageCollectionPhases { - int64_t total_wall_clock_duration_in_us = -1; - int64_t compact_wall_clock_duration_in_us = -1; - int64_t mark_wall_clock_duration_in_us = -1; - int64_t sweep_wall_clock_duration_in_us = -1; - int64_t weak_wall_clock_duration_in_us = -1; -}; - -struct GarbageCollectionSizes { - int64_t bytes_before = -1; - int64_t bytes_after = -1; - int64_t bytes_freed = -1; -}; - -struct GarbageCollectionFullCycle { - int reason = -1; - GarbageCollectionPhases total; - GarbageCollectionPhases total_cpp; - GarbageCollectionPhases main_thread; - GarbageCollectionPhases main_thread_cpp; - GarbageCollectionPhases main_thread_atomic; - GarbageCollectionPhases main_thread_atomic_cpp; - GarbageCollectionPhases main_thread_incremental; - GarbageCollectionPhases main_thread_incremental_cpp; - GarbageCollectionSizes objects; - GarbageCollectionSizes objects_cpp; - GarbageCollectionSizes memory; - GarbageCollectionSizes memory_cpp; - double collection_rate_in_percent = -1.0; - double collection_rate_cpp_in_percent = -1.0; - double efficiency_in_bytes_per_us = -1.0; - double efficiency_cpp_in_bytes_per_us = -1.0; - double main_thread_efficiency_in_bytes_per_us = -1.0; - double main_thread_efficiency_cpp_in_bytes_per_us = -1.0; -}; - -struct GarbageCollectionFullMainThreadIncrementalMark { - int64_t wall_clock_duration_in_us = -1; - int64_t cpp_wall_clock_duration_in_us = -1; -}; - -struct GarbageCollectionFullMainThreadIncrementalSweep { - int64_t wall_clock_duration_in_us = -1; - int64_t cpp_wall_clock_duration_in_us = -1; -}; - -template -struct GarbageCollectionBatchedEvents { - std::vector events; -}; - -using GarbageCollectionFullMainThreadBatchedIncrementalMark = - GarbageCollectionBatchedEvents< - GarbageCollectionFullMainThreadIncrementalMark>; -using GarbageCollectionFullMainThreadBatchedIncrementalSweep = - GarbageCollectionBatchedEvents< - GarbageCollectionFullMainThreadIncrementalSweep>; - -struct GarbageCollectionYoungCycle { - int reason = -1; - int64_t total_wall_clock_duration_in_us = -1; - int64_t main_thread_wall_clock_duration_in_us = -1; - double collection_rate_in_percent = -1.0; - double efficiency_in_bytes_per_us = -1.0; - double main_thread_efficiency_in_bytes_per_us = -1.0; -#if defined(CPPGC_YOUNG_GENERATION) - GarbageCollectionPhases total_cpp; - GarbageCollectionSizes objects_cpp; - GarbageCollectionSizes memory_cpp; - double collection_rate_cpp_in_percent = -1.0; - double efficiency_cpp_in_bytes_per_us = -1.0; - double main_thread_efficiency_cpp_in_bytes_per_us = -1.0; -#endif // defined(CPPGC_YOUNG_GENERATION) -}; - -struct WasmModuleDecoded { - bool async = false; - bool streamed = false; - bool success = false; - size_t module_size_in_bytes = 0; - size_t function_count = 0; - int64_t wall_clock_duration_in_us = -1; - int64_t cpu_duration_in_us = -1; -}; - -struct WasmModuleCompiled { - bool async = false; - bool streamed = false; - bool cached = false; - bool deserialized = false; - bool lazy = false; - bool success = false; - size_t code_size_in_bytes = 0; - size_t liftoff_bailout_count = 0; - int64_t wall_clock_duration_in_us = -1; - int64_t cpu_duration_in_us = -1; -}; - -struct WasmModuleInstantiated { - bool async = false; - bool success = false; - size_t imported_function_count = 0; - int64_t wall_clock_duration_in_us = -1; -}; - -struct WasmModuleTieredUp { - bool lazy = false; - size_t code_size_in_bytes = 0; - int64_t wall_clock_duration_in_us = -1; - int64_t cpu_duration_in_us = -1; -}; - -struct WasmModulesPerIsolate { - size_t count = 0; -}; - -#define V8_MAIN_THREAD_METRICS_EVENTS(V) \ - V(GarbageCollectionFullCycle) \ - V(GarbageCollectionFullMainThreadIncrementalMark) \ - V(GarbageCollectionFullMainThreadBatchedIncrementalMark) \ - V(GarbageCollectionFullMainThreadIncrementalSweep) \ - V(GarbageCollectionFullMainThreadBatchedIncrementalSweep) \ - V(GarbageCollectionYoungCycle) \ - V(WasmModuleDecoded) \ - V(WasmModuleCompiled) \ - V(WasmModuleInstantiated) \ - V(WasmModuleTieredUp) - -#define V8_THREAD_SAFE_METRICS_EVENTS(V) V(WasmModulesPerIsolate) - -/** - * This class serves as a base class for recording event-based metrics in V8. - * There a two kinds of metrics, those which are expected to be thread-safe and - * whose implementation is required to fulfill this requirement and those whose - * implementation does not have that requirement and only needs to be - * executable on the main thread. If such an event is triggered from a - * background thread, it will be delayed and executed by the foreground task - * runner. - * - * The thread-safe events are listed in the V8_THREAD_SAFE_METRICS_EVENTS - * macro above while the main thread event are listed in - * V8_MAIN_THREAD_METRICS_EVENTS above. For the former, a virtual method - * AddMainThreadEvent(const E& event, v8::Context::Token token) will be - * generated and for the latter AddThreadSafeEvent(const E& event). - * - * Thread-safe events are not allowed to access the context and therefore do - * not carry a context ID with them. These IDs can be generated using - * Recorder::GetContextId() and the ID will be valid throughout the lifetime - * of the isolate. It is not guaranteed that the ID will still resolve to - * a valid context using Recorder::GetContext() at the time the metric is - * recorded. In this case, an empty handle will be returned. - * - * The embedder is expected to call v8::Isolate::SetMetricsRecorder() - * providing its implementation and have the virtual methods overwritten - * for the events it cares about. - */ -class V8_EXPORT Recorder { - public: - // A unique identifier for a context in this Isolate. - // It is guaranteed to not be reused throughout the lifetime of the Isolate. - class ContextId { - public: - ContextId() : id_(kEmptyId) {} - - bool IsEmpty() const { return id_ == kEmptyId; } - static const ContextId Empty() { return ContextId{kEmptyId}; } - - bool operator==(const ContextId& other) const { return id_ == other.id_; } - bool operator!=(const ContextId& other) const { return id_ != other.id_; } - - private: - friend class ::v8::Context; - friend class ::v8::internal::Isolate; - - explicit ContextId(uintptr_t id) : id_(id) {} - - static constexpr uintptr_t kEmptyId = 0; - uintptr_t id_; - }; - - virtual ~Recorder() = default; - -#define ADD_MAIN_THREAD_EVENT(E) \ - virtual void AddMainThreadEvent(const E& event, ContextId context_id) {} - V8_MAIN_THREAD_METRICS_EVENTS(ADD_MAIN_THREAD_EVENT) -#undef ADD_MAIN_THREAD_EVENT - -#define ADD_THREAD_SAFE_EVENT(E) \ - virtual void AddThreadSafeEvent(const E& event) {} - V8_THREAD_SAFE_METRICS_EVENTS(ADD_THREAD_SAFE_EVENT) -#undef ADD_THREAD_SAFE_EVENT - - virtual void NotifyIsolateDisposal() {} - - // Return the context with the given id or an empty handle if the context - // was already garbage collected. - static MaybeLocal GetContext(Isolate* isolate, ContextId id); - // Return the unique id corresponding to the given context. - static ContextId GetContextId(Local context); -}; - -/** - * Experimental API intended for the LongTasks UKM (crbug.com/1173527). - * The Reset() method should be called at the start of a potential - * long task. The Get() method returns durations of V8 work that - * happened during the task. - * - * This API is experimental and may be removed/changed in the future. - */ -struct V8_EXPORT LongTaskStats { - /** - * Resets durations of V8 work for the new task. - */ - V8_INLINE static void Reset(Isolate* isolate) { - v8::internal::Internals::IncrementLongTasksStatsCounter(isolate); - } - - /** - * Returns durations of V8 work that happened since the last Reset(). - */ - static LongTaskStats Get(Isolate* isolate); - - int64_t gc_full_atomic_wall_clock_duration_us = 0; - int64_t gc_full_incremental_wall_clock_duration_us = 0; - int64_t gc_young_wall_clock_duration_us = 0; - // Only collected with --slow-histograms - int64_t v8_execute_us = 0; -}; - -} // namespace metrics -} // namespace v8 - -#endif // V8_METRICS_H_ diff --git a/NativeScript/include/v8-microtask-queue.h b/NativeScript/include/v8-microtask-queue.h deleted file mode 100644 index af9caa54..00000000 --- a/NativeScript/include/v8-microtask-queue.h +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_MICROTASKS_QUEUE_H_ -#define INCLUDE_V8_MICROTASKS_QUEUE_H_ - -#include - -#include - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-microtask.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Function; - -namespace internal { -class Isolate; -class MicrotaskQueue; -} // namespace internal - -/** - * Represents the microtask queue, where microtasks are stored and processed. - * https://html.spec.whatwg.org/multipage/webappapis.html#microtask-queue - * https://html.spec.whatwg.org/multipage/webappapis.html#enqueuejob(queuename,-job,-arguments) - * https://html.spec.whatwg.org/multipage/webappapis.html#perform-a-microtask-checkpoint - * - * A MicrotaskQueue instance may be associated to multiple Contexts by passing - * it to Context::New(), and they can be detached by Context::DetachGlobal(). - * The embedder must keep the MicrotaskQueue instance alive until all associated - * Contexts are gone or detached. - * - * Use the same instance of MicrotaskQueue for all Contexts that may access each - * other synchronously. E.g. for Web embedding, use the same instance for all - * origins that share the same URL scheme and eTLD+1. - */ -class V8_EXPORT MicrotaskQueue { - public: - /** - * Creates an empty MicrotaskQueue instance. - */ - static std::unique_ptr New( - Isolate* isolate, MicrotasksPolicy policy = MicrotasksPolicy::kAuto); - - virtual ~MicrotaskQueue() = default; - - /** - * Enqueues the callback to the queue. - */ - virtual void EnqueueMicrotask(Isolate* isolate, - Local microtask) = 0; - - /** - * Enqueues the callback to the queue. - */ - virtual void EnqueueMicrotask(v8::Isolate* isolate, - MicrotaskCallback callback, - void* data = nullptr) = 0; - - /** - * Adds a callback to notify the embedder after microtasks were run. The - * callback is triggered by explicit RunMicrotasks call or automatic - * microtasks execution (see Isolate::SetMicrotasksPolicy). - * - * Callback will trigger even if microtasks were attempted to run, - * but the microtasks queue was empty and no single microtask was actually - * executed. - * - * Executing scripts inside the callback will not re-trigger microtasks and - * the callback. - */ - virtual void AddMicrotasksCompletedCallback( - MicrotasksCompletedCallbackWithData callback, void* data = nullptr) = 0; - - /** - * Removes callback that was installed by AddMicrotasksCompletedCallback. - */ - virtual void RemoveMicrotasksCompletedCallback( - MicrotasksCompletedCallbackWithData callback, void* data = nullptr) = 0; - - /** - * Runs microtasks if no microtask is running on this MicrotaskQueue instance. - */ - virtual void PerformCheckpoint(Isolate* isolate) = 0; - - /** - * Returns true if a microtask is running on this MicrotaskQueue instance. - */ - virtual bool IsRunningMicrotasks() const = 0; - - /** - * Returns the current depth of nested MicrotasksScope that has - * kRunMicrotasks. - */ - virtual int GetMicrotasksScopeDepth() const = 0; - - MicrotaskQueue(const MicrotaskQueue&) = delete; - MicrotaskQueue& operator=(const MicrotaskQueue&) = delete; - - private: - friend class internal::MicrotaskQueue; - MicrotaskQueue() = default; -}; - -/** - * This scope is used to control microtasks when MicrotasksPolicy::kScoped - * is used on Isolate. In this mode every non-primitive call to V8 should be - * done inside some MicrotasksScope. - * Microtasks are executed when topmost MicrotasksScope marked as kRunMicrotasks - * exits. - * kDoNotRunMicrotasks should be used to annotate calls not intended to trigger - * microtasks. - */ -class V8_EXPORT V8_NODISCARD MicrotasksScope { - public: - enum Type { kRunMicrotasks, kDoNotRunMicrotasks }; - - MicrotasksScope(Isolate* isolate, Type type); - MicrotasksScope(Isolate* isolate, MicrotaskQueue* microtask_queue, Type type); - ~MicrotasksScope(); - - /** - * Runs microtasks if no kRunMicrotasks scope is currently active. - */ - static void PerformCheckpoint(Isolate* isolate); - - /** - * Returns current depth of nested kRunMicrotasks scopes. - */ - static int GetCurrentDepth(Isolate* isolate); - - /** - * Returns true while microtasks are being executed. - */ - static bool IsRunningMicrotasks(Isolate* isolate); - - // Prevent copying. - MicrotasksScope(const MicrotasksScope&) = delete; - MicrotasksScope& operator=(const MicrotasksScope&) = delete; - - private: - internal::Isolate* const isolate_; - internal::MicrotaskQueue* const microtask_queue_; - bool run_; -}; - -} // namespace v8 - -#endif // INCLUDE_V8_MICROTASKS_QUEUE_H_ diff --git a/NativeScript/include/v8-microtask.h b/NativeScript/include/v8-microtask.h deleted file mode 100644 index c1592036..00000000 --- a/NativeScript/include/v8-microtask.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_MICROTASK_H_ -#define INCLUDE_V8_MICROTASK_H_ - -namespace v8 { - -class Isolate; - -// --- Microtasks Callbacks --- -using MicrotasksCompletedCallbackWithData = void (*)(Isolate*, void*); -using MicrotaskCallback = void (*)(void* data); - -/** - * Policy for running microtasks: - * - explicit: microtasks are invoked with the - * Isolate::PerformMicrotaskCheckpoint() method; - * - scoped: microtasks invocation is controlled by MicrotasksScope objects; - * - auto: microtasks are invoked when the script call depth decrements - * to zero. - */ -enum class MicrotasksPolicy { kExplicit, kScoped, kAuto }; - -} // namespace v8 - -#endif // INCLUDE_V8_MICROTASK_H_ diff --git a/NativeScript/include/v8-object.h b/NativeScript/include/v8-object.h deleted file mode 100644 index bad299fc..00000000 --- a/NativeScript/include/v8-object.h +++ /dev/null @@ -1,775 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_OBJECT_H_ -#define INCLUDE_V8_OBJECT_H_ - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-maybe.h" // NOLINT(build/include_directory) -#include "v8-persistent-handle.h" // NOLINT(build/include_directory) -#include "v8-primitive.h" // NOLINT(build/include_directory) -#include "v8-traced-handle.h" // NOLINT(build/include_directory) -#include "v8-value.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Array; -class Function; -class FunctionTemplate; -template -class PropertyCallbackInfo; - -/** - * A private symbol - * - * This is an experimental feature. Use at your own risk. - */ -class V8_EXPORT Private : public Data { - public: - /** - * Returns the print name string of the private symbol, or undefined if none. - */ - Local Name() const; - - /** - * Create a private symbol. If name is not empty, it will be the description. - */ - static Local New(Isolate* isolate, - Local name = Local()); - - /** - * Retrieve a global private symbol. If a symbol with this name has not - * been retrieved in the same isolate before, it is created. - * Note that private symbols created this way are never collected, so - * they should only be used for statically fixed properties. - * Also, there is only one global name space for the names used as keys. - * To minimize the potential for clashes, use qualified names as keys, - * e.g., "Class#property". - */ - static Local ForApi(Isolate* isolate, Local name); - - V8_INLINE static Private* Cast(Data* data); - - private: - Private(); - - static void CheckCast(Data* that); -}; - -/** - * An instance of a Property Descriptor, see Ecma-262 6.2.4. - * - * Properties in a descriptor are present or absent. If you do not set - * `enumerable`, `configurable`, and `writable`, they are absent. If `value`, - * `get`, or `set` are absent, but you must specify them in the constructor, use - * empty handles. - * - * Accessors `get` and `set` must be callable or undefined if they are present. - * - * \note Only query properties if they are present, i.e., call `x()` only if - * `has_x()` returns true. - * - * \code - * // var desc = {writable: false} - * v8::PropertyDescriptor d(Local()), false); - * d.value(); // error, value not set - * if (d.has_writable()) { - * d.writable(); // false - * } - * - * // var desc = {value: undefined} - * v8::PropertyDescriptor d(v8::Undefined(isolate)); - * - * // var desc = {get: undefined} - * v8::PropertyDescriptor d(v8::Undefined(isolate), Local())); - * \endcode - */ -class V8_EXPORT PropertyDescriptor { - public: - // GenericDescriptor - PropertyDescriptor(); - - // DataDescriptor - explicit PropertyDescriptor(Local value); - - // DataDescriptor with writable property - PropertyDescriptor(Local value, bool writable); - - // AccessorDescriptor - PropertyDescriptor(Local get, Local set); - - ~PropertyDescriptor(); - - Local value() const; - bool has_value() const; - - Local get() const; - bool has_get() const; - Local set() const; - bool has_set() const; - - void set_enumerable(bool enumerable); - bool enumerable() const; - bool has_enumerable() const; - - void set_configurable(bool configurable); - bool configurable() const; - bool has_configurable() const; - - bool writable() const; - bool has_writable() const; - - struct PrivateData; - PrivateData* get_private() const { return private_; } - - PropertyDescriptor(const PropertyDescriptor&) = delete; - void operator=(const PropertyDescriptor&) = delete; - - private: - PrivateData* private_; -}; - -/** - * PropertyAttribute. - */ -enum PropertyAttribute { - /** None. **/ - None = 0, - /** ReadOnly, i.e., not writable. **/ - ReadOnly = 1 << 0, - /** DontEnum, i.e., not enumerable. **/ - DontEnum = 1 << 1, - /** DontDelete, i.e., not configurable. **/ - DontDelete = 1 << 2 -}; - -/** - * Accessor[Getter|Setter] are used as callback functions when - * setting|getting a particular property. See Object and ObjectTemplate's - * method SetAccessor. - */ -using AccessorGetterCallback = - void (*)(Local property, const PropertyCallbackInfo& info); -using AccessorNameGetterCallback = - void (*)(Local property, const PropertyCallbackInfo& info); - -using AccessorSetterCallback = void (*)(Local property, - Local value, - const PropertyCallbackInfo& info); -using AccessorNameSetterCallback = - void (*)(Local property, Local value, - const PropertyCallbackInfo& info); - -/** - * Access control specifications. - * - * Some accessors should be accessible across contexts. These - * accessors have an explicit access control parameter which specifies - * the kind of cross-context access that should be allowed. - * - * TODO(dcarney): Remove PROHIBITS_OVERWRITING as it is now unused. - */ -enum AccessControl { - DEFAULT = 0, - ALL_CAN_READ = 1, - ALL_CAN_WRITE = 1 << 1, - PROHIBITS_OVERWRITING = 1 << 2 -}; - -/** - * Property filter bits. They can be or'ed to build a composite filter. - */ -enum PropertyFilter { - ALL_PROPERTIES = 0, - ONLY_WRITABLE = 1, - ONLY_ENUMERABLE = 2, - ONLY_CONFIGURABLE = 4, - SKIP_STRINGS = 8, - SKIP_SYMBOLS = 16 -}; - -/** - * Options for marking whether callbacks may trigger JS-observable side effects. - * Side-effect-free callbacks are allowlisted during debug evaluation with - * throwOnSideEffect. It applies when calling a Function, FunctionTemplate, - * or an Accessor callback. For Interceptors, please see - * PropertyHandlerFlags's kHasNoSideEffect. - * Callbacks that only cause side effects to the receiver are allowlisted if - * invoked on receiver objects that are created within the same debug-evaluate - * call, as these objects are temporary and the side effect does not escape. - */ -enum class SideEffectType { - kHasSideEffect, - kHasNoSideEffect, - kHasSideEffectToReceiver -}; - -/** - * Keys/Properties filter enums: - * - * KeyCollectionMode limits the range of collected properties. kOwnOnly limits - * the collected properties to the given Object only. kIncludesPrototypes will - * include all keys of the objects's prototype chain as well. - */ -enum class KeyCollectionMode { kOwnOnly, kIncludePrototypes }; - -/** - * kIncludesIndices allows for integer indices to be collected, while - * kSkipIndices will exclude integer indices from being collected. - */ -enum class IndexFilter { kIncludeIndices, kSkipIndices }; - -/** - * kConvertToString will convert integer indices to strings. - * kKeepNumbers will return numbers for integer indices. - */ -enum class KeyConversionMode { kConvertToString, kKeepNumbers, kNoNumbers }; - -/** - * Integrity level for objects. - */ -enum class IntegrityLevel { kFrozen, kSealed }; - -/** - * A JavaScript object (ECMA-262, 4.3.3) - */ -class V8_EXPORT Object : public Value { - public: - /** - * Set only return Just(true) or Empty(), so if it should never fail, use - * result.Check(). - */ - V8_WARN_UNUSED_RESULT Maybe Set(Local context, - Local key, Local value); - - V8_WARN_UNUSED_RESULT Maybe Set(Local context, uint32_t index, - Local value); - - // Implements CreateDataProperty (ECMA-262, 7.3.4). - // - // Defines a configurable, writable, enumerable property with the given value - // on the object unless the property already exists and is not configurable - // or the object is not extensible. - // - // Returns true on success. - V8_WARN_UNUSED_RESULT Maybe CreateDataProperty(Local context, - Local key, - Local value); - V8_WARN_UNUSED_RESULT Maybe CreateDataProperty(Local context, - uint32_t index, - Local value); - - // Implements DefineOwnProperty. - // - // In general, CreateDataProperty will be faster, however, does not allow - // for specifying attributes. - // - // Returns true on success. - V8_WARN_UNUSED_RESULT Maybe DefineOwnProperty( - Local context, Local key, Local value, - PropertyAttribute attributes = None); - - // Implements Object.DefineProperty(O, P, Attributes), see Ecma-262 19.1.2.4. - // - // The defineProperty function is used to add an own property or - // update the attributes of an existing own property of an object. - // - // Both data and accessor descriptors can be used. - // - // In general, CreateDataProperty is faster, however, does not allow - // for specifying attributes or an accessor descriptor. - // - // The PropertyDescriptor can change when redefining a property. - // - // Returns true on success. - V8_WARN_UNUSED_RESULT Maybe DefineProperty( - Local context, Local key, PropertyDescriptor& descriptor); - - V8_WARN_UNUSED_RESULT MaybeLocal Get(Local context, - Local key); - - V8_WARN_UNUSED_RESULT MaybeLocal Get(Local context, - uint32_t index); - - /** - * Gets the property attributes of a property which can be None or - * any combination of ReadOnly, DontEnum and DontDelete. Returns - * None when the property doesn't exist. - */ - V8_WARN_UNUSED_RESULT Maybe GetPropertyAttributes( - Local context, Local key); - - /** - * Returns Object.getOwnPropertyDescriptor as per ES2016 section 19.1.2.6. - */ - V8_WARN_UNUSED_RESULT MaybeLocal GetOwnPropertyDescriptor( - Local context, Local key); - - /** - * Object::Has() calls the abstract operation HasProperty(O, P) described - * in ECMA-262, 7.3.10. Has() returns - * true, if the object has the property, either own or on the prototype chain. - * Interceptors, i.e., PropertyQueryCallbacks, are called if present. - * - * Has() has the same side effects as JavaScript's `variable in object`. - * For example, calling Has() on a revoked proxy will throw an exception. - * - * \note Has() converts the key to a name, which possibly calls back into - * JavaScript. - * - * See also v8::Object::HasOwnProperty() and - * v8::Object::HasRealNamedProperty(). - */ - V8_WARN_UNUSED_RESULT Maybe Has(Local context, - Local key); - - V8_WARN_UNUSED_RESULT Maybe Delete(Local context, - Local key); - - V8_WARN_UNUSED_RESULT Maybe Has(Local context, uint32_t index); - - V8_WARN_UNUSED_RESULT Maybe Delete(Local context, - uint32_t index); - - /** - * Note: SideEffectType affects the getter only, not the setter. - */ - V8_WARN_UNUSED_RESULT Maybe SetAccessor( - Local context, Local name, - AccessorNameGetterCallback getter, - AccessorNameSetterCallback setter = nullptr, - MaybeLocal data = MaybeLocal(), - AccessControl settings = DEFAULT, PropertyAttribute attribute = None, - SideEffectType getter_side_effect_type = SideEffectType::kHasSideEffect, - SideEffectType setter_side_effect_type = SideEffectType::kHasSideEffect); - - void SetAccessorProperty(Local name, Local getter, - Local setter = Local(), - PropertyAttribute attribute = None, - AccessControl settings = DEFAULT); - - /** - * Sets a native data property like Template::SetNativeDataProperty, but - * this method sets on this object directly. - */ - V8_WARN_UNUSED_RESULT Maybe SetNativeDataProperty( - Local context, Local name, - AccessorNameGetterCallback getter, - AccessorNameSetterCallback setter = nullptr, - Local data = Local(), PropertyAttribute attributes = None, - SideEffectType getter_side_effect_type = SideEffectType::kHasSideEffect, - SideEffectType setter_side_effect_type = SideEffectType::kHasSideEffect); - - /** - * Attempts to create a property with the given name which behaves like a data - * property, except that the provided getter is invoked (and provided with the - * data value) to supply its value the first time it is read. After the - * property is accessed once, it is replaced with an ordinary data property. - * - * Analogous to Template::SetLazyDataProperty. - */ - V8_WARN_UNUSED_RESULT Maybe SetLazyDataProperty( - Local context, Local name, - AccessorNameGetterCallback getter, Local data = Local(), - PropertyAttribute attributes = None, - SideEffectType getter_side_effect_type = SideEffectType::kHasSideEffect, - SideEffectType setter_side_effect_type = SideEffectType::kHasSideEffect); - - /** - * Functionality for private properties. - * This is an experimental feature, use at your own risk. - * Note: Private properties are not inherited. Do not rely on this, since it - * may change. - */ - Maybe HasPrivate(Local context, Local key); - Maybe SetPrivate(Local context, Local key, - Local value); - Maybe DeletePrivate(Local context, Local key); - MaybeLocal GetPrivate(Local context, Local key); - - /** - * Returns an array containing the names of the enumerable properties - * of this object, including properties from prototype objects. The - * array returned by this method contains the same values as would - * be enumerated by a for-in statement over this object. - */ - V8_WARN_UNUSED_RESULT MaybeLocal GetPropertyNames( - Local context); - V8_WARN_UNUSED_RESULT MaybeLocal GetPropertyNames( - Local context, KeyCollectionMode mode, - PropertyFilter property_filter, IndexFilter index_filter, - KeyConversionMode key_conversion = KeyConversionMode::kKeepNumbers); - - /** - * This function has the same functionality as GetPropertyNames but - * the returned array doesn't contain the names of properties from - * prototype objects. - */ - V8_WARN_UNUSED_RESULT MaybeLocal GetOwnPropertyNames( - Local context); - - /** - * Returns an array containing the names of the filtered properties - * of this object, including properties from prototype objects. The - * array returned by this method contains the same values as would - * be enumerated by a for-in statement over this object. - */ - V8_WARN_UNUSED_RESULT MaybeLocal GetOwnPropertyNames( - Local context, PropertyFilter filter, - KeyConversionMode key_conversion = KeyConversionMode::kKeepNumbers); - - /** - * Get the prototype object. This does not skip objects marked to - * be skipped by __proto__ and it does not consult the security - * handler. - */ - Local GetPrototype(); - - /** - * Set the prototype object. This does not skip objects marked to - * be skipped by __proto__ and it does not consult the security - * handler. - */ - V8_WARN_UNUSED_RESULT Maybe SetPrototype(Local context, - Local prototype); - - /** - * Finds an instance of the given function template in the prototype - * chain. - */ - Local FindInstanceInPrototypeChain(Local tmpl); - - /** - * Call builtin Object.prototype.toString on this object. - * This is different from Value::ToString() that may call - * user-defined toString function. This one does not. - */ - V8_WARN_UNUSED_RESULT MaybeLocal ObjectProtoToString( - Local context); - - /** - * Returns the name of the function invoked as a constructor for this object. - */ - Local GetConstructorName(); - - /** - * Sets the integrity level of the object. - */ - Maybe SetIntegrityLevel(Local context, IntegrityLevel level); - - /** Gets the number of internal fields for this Object. */ - int InternalFieldCount() const; - - /** Same as above, but works for PersistentBase. */ - V8_INLINE static int InternalFieldCount( - const PersistentBase& object) { - return object.val_->InternalFieldCount(); - } - - /** Same as above, but works for BasicTracedReference. */ - V8_INLINE static int InternalFieldCount( - const BasicTracedReference& object) { - return object->InternalFieldCount(); - } - - /** Gets the value from an internal field. */ - V8_INLINE Local GetInternalField(int index); - - /** Sets the value in an internal field. */ - void SetInternalField(int index, Local value); - - /** - * Gets a 2-byte-aligned native pointer from an internal field. This field - * must have been set by SetAlignedPointerInInternalField, everything else - * leads to undefined behavior. - */ - V8_INLINE void* GetAlignedPointerFromInternalField(int index); - - /** Same as above, but works for PersistentBase. */ - V8_INLINE static void* GetAlignedPointerFromInternalField( - const PersistentBase& object, int index) { - return object.val_->GetAlignedPointerFromInternalField(index); - } - - /** Same as above, but works for TracedReference. */ - V8_INLINE static void* GetAlignedPointerFromInternalField( - const BasicTracedReference& object, int index) { - return object->GetAlignedPointerFromInternalField(index); - } - - /** - * Sets a 2-byte-aligned native pointer in an internal field. To retrieve such - * a field, GetAlignedPointerFromInternalField must be used, everything else - * leads to undefined behavior. - */ - void SetAlignedPointerInInternalField(int index, void* value); - void SetAlignedPointerInInternalFields(int argc, int indices[], - void* values[]); - - /** - * HasOwnProperty() is like JavaScript's Object.prototype.hasOwnProperty(). - * - * See also v8::Object::Has() and v8::Object::HasRealNamedProperty(). - */ - V8_WARN_UNUSED_RESULT Maybe HasOwnProperty(Local context, - Local key); - V8_WARN_UNUSED_RESULT Maybe HasOwnProperty(Local context, - uint32_t index); - /** - * Use HasRealNamedProperty() if you want to check if an object has an own - * property without causing side effects, i.e., without calling interceptors. - * - * This function is similar to v8::Object::HasOwnProperty(), but it does not - * call interceptors. - * - * \note Consider using non-masking interceptors, i.e., the interceptors are - * not called if the receiver has the real named property. See - * `v8::PropertyHandlerFlags::kNonMasking`. - * - * See also v8::Object::Has(). - */ - V8_WARN_UNUSED_RESULT Maybe HasRealNamedProperty(Local context, - Local key); - V8_WARN_UNUSED_RESULT Maybe HasRealIndexedProperty( - Local context, uint32_t index); - V8_WARN_UNUSED_RESULT Maybe HasRealNamedCallbackProperty( - Local context, Local key); - - /** - * If result.IsEmpty() no real property was located in the prototype chain. - * This means interceptors in the prototype chain are not called. - */ - V8_WARN_UNUSED_RESULT MaybeLocal GetRealNamedPropertyInPrototypeChain( - Local context, Local key); - - /** - * Gets the property attributes of a real property in the prototype chain, - * which can be None or any combination of ReadOnly, DontEnum and DontDelete. - * Interceptors in the prototype chain are not called. - */ - V8_WARN_UNUSED_RESULT Maybe - GetRealNamedPropertyAttributesInPrototypeChain(Local context, - Local key); - - /** - * If result.IsEmpty() no real property was located on the object or - * in the prototype chain. - * This means interceptors in the prototype chain are not called. - */ - V8_WARN_UNUSED_RESULT MaybeLocal GetRealNamedProperty( - Local context, Local key); - - /** - * Gets the property attributes of a real property which can be - * None or any combination of ReadOnly, DontEnum and DontDelete. - * Interceptors in the prototype chain are not called. - */ - V8_WARN_UNUSED_RESULT Maybe GetRealNamedPropertyAttributes( - Local context, Local key); - - /** Tests for a named lookup interceptor.*/ - bool HasNamedLookupInterceptor() const; - - /** Tests for an index lookup interceptor.*/ - bool HasIndexedLookupInterceptor() const; - - /** - * Returns the identity hash for this object. The current implementation - * uses a hidden property on the object to store the identity hash. - * - * The return value will never be 0. Also, it is not guaranteed to be - * unique. - */ - int GetIdentityHash(); - - /** - * Clone this object with a fast but shallow copy. Values will point - * to the same values as the original object. - */ - // TODO(dcarney): take an isolate and optionally bail out? - Local Clone(); - - /** - * Returns the context in which the object was created. - */ - V8_DEPRECATED("Use MaybeLocal GetCreationContext()") - Local CreationContext(); - MaybeLocal GetCreationContext(); - - /** - * Shortcut for GetCreationContext().ToLocalChecked(). - **/ - Local GetCreationContextChecked(); - - /** Same as above, but works for Persistents */ - V8_DEPRECATED( - "Use MaybeLocal GetCreationContext(const " - "PersistentBase& object)") - static Local CreationContext(const PersistentBase& object); - V8_INLINE static MaybeLocal GetCreationContext( - const PersistentBase& object) { - return object.val_->GetCreationContext(); - } - - /** - * Checks whether a callback is set by the - * ObjectTemplate::SetCallAsFunctionHandler method. - * When an Object is callable this method returns true. - */ - bool IsCallable() const; - - /** - * True if this object is a constructor. - */ - bool IsConstructor() const; - - /** - * True if this object can carry information relevant to the embedder in its - * embedder fields, false otherwise. This is generally true for objects - * constructed through function templates but also holds for other types where - * V8 automatically adds internal fields at compile time, such as e.g. - * v8::ArrayBuffer. - */ - bool IsApiWrapper() const; - - /** - * True if this object was created from an object template which was marked - * as undetectable. See v8::ObjectTemplate::MarkAsUndetectable for more - * information. - */ - bool IsUndetectable() const; - - /** - * Call an Object as a function if a callback is set by the - * ObjectTemplate::SetCallAsFunctionHandler method. - */ - V8_WARN_UNUSED_RESULT MaybeLocal CallAsFunction(Local context, - Local recv, - int argc, - Local argv[]); - - /** - * Call an Object as a constructor if a callback is set by the - * ObjectTemplate::SetCallAsFunctionHandler method. - * Note: This method behaves like the Function::NewInstance method. - */ - V8_WARN_UNUSED_RESULT MaybeLocal CallAsConstructor( - Local context, int argc, Local argv[]); - - /** - * Return the isolate to which the Object belongs to. - */ - Isolate* GetIsolate(); - - /** - * If this object is a Set, Map, WeakSet or WeakMap, this returns a - * representation of the elements of this object as an array. - * If this object is a SetIterator or MapIterator, this returns all - * elements of the underlying collection, starting at the iterator's current - * position. - * For other types, this will return an empty MaybeLocal (without - * scheduling an exception). - */ - MaybeLocal PreviewEntries(bool* is_key_value); - - static Local New(Isolate* isolate); - - /** - * Creates a JavaScript object with the given properties, and - * a the given prototype_or_null (which can be any JavaScript - * value, and if it's null, the newly created object won't have - * a prototype at all). This is similar to Object.create(). - * All properties will be created as enumerable, configurable - * and writable properties. - */ - static Local New(Isolate* isolate, Local prototype_or_null, - Local* names, Local* values, - size_t length); - - V8_INLINE static Object* Cast(Value* obj); - - /** - * Support for TC39 "dynamic code brand checks" proposal. - * - * This API allows to query whether an object was constructed from a - * "code like" ObjectTemplate. - * - * See also: v8::ObjectTemplate::SetCodeLike - */ - bool IsCodeLike(Isolate* isolate) const; - - private: - Object(); - static void CheckCast(Value* obj); - Local SlowGetInternalField(int index); - void* SlowGetAlignedPointerFromInternalField(int index); -}; - -// --- Implementation --- - -Local Object::GetInternalField(int index) { -#ifndef V8_ENABLE_CHECKS - using A = internal::Address; - using I = internal::Internals; - A obj = *reinterpret_cast(this); - // Fast path: If the object is a plain JSObject, which is the common case, we - // know where to find the internal fields and can return the value directly. - int instance_type = I::GetInstanceType(obj); - if (v8::internal::CanHaveInternalField(instance_type)) { - int offset = I::kJSObjectHeaderSize + (I::kEmbedderDataSlotSize * index); - A value = I::ReadRawField(obj, offset); -#ifdef V8_COMPRESS_POINTERS - // We read the full pointer value and then decompress it in order to avoid - // dealing with potential endiannes issues. - value = I::DecompressTaggedAnyField(obj, static_cast(value)); -#endif - internal::Isolate* isolate = - internal::IsolateFromNeverReadOnlySpaceObject(obj); - A* result = HandleScope::CreateHandle(isolate, value); - return Local(reinterpret_cast(result)); - } -#endif - return SlowGetInternalField(index); -} - -void* Object::GetAlignedPointerFromInternalField(int index) { -#if !defined(V8_ENABLE_CHECKS) - using A = internal::Address; - using I = internal::Internals; - A obj = *reinterpret_cast(this); - // Fast path: If the object is a plain JSObject, which is the common case, we - // know where to find the internal fields and can return the value directly. - auto instance_type = I::GetInstanceType(obj); - if (v8::internal::CanHaveInternalField(instance_type)) { - int offset = I::kJSObjectHeaderSize + (I::kEmbedderDataSlotSize * index); -#ifdef V8_SANDBOXED_EXTERNAL_POINTERS - offset += I::kEmbedderDataSlotRawPayloadOffset; -#endif - internal::Isolate* isolate = I::GetIsolateForSandbox(obj); - A value = I::ReadExternalPointerField( - isolate, obj, offset, internal::kEmbedderDataSlotPayloadTag); - return reinterpret_cast(value); - } -#endif - return SlowGetAlignedPointerFromInternalField(index); -} - -Private* Private::Cast(Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return reinterpret_cast(data); -} - -Object* Object::Cast(v8::Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); -} - -} // namespace v8 - -#endif // INCLUDE_V8_OBJECT_H_ diff --git a/NativeScript/include/v8-persistent-handle.h b/NativeScript/include/v8-persistent-handle.h deleted file mode 100644 index a6c21268..00000000 --- a/NativeScript/include/v8-persistent-handle.h +++ /dev/null @@ -1,590 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_PERSISTENT_HANDLE_H_ -#define INCLUDE_V8_PERSISTENT_HANDLE_H_ - -#include "v8-internal.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-weak-callback-info.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Isolate; -template -class PersistentValueMapBase; -template -class PersistentValueVector; -template -class Global; -template -class PersistentBase; -template -class PersistentValueMap; -class Value; - -namespace api_internal { -V8_EXPORT Value* Eternalize(v8::Isolate* isolate, Value* handle); -V8_EXPORT internal::Address* CopyGlobalReference(internal::Address* from); -V8_EXPORT void DisposeGlobal(internal::Address* global_handle); -V8_EXPORT void MakeWeak(internal::Address** location_addr); -V8_EXPORT void* ClearWeak(internal::Address* location); -V8_EXPORT void AnnotateStrongRetainer(internal::Address* location, - const char* label); -V8_EXPORT internal::Address* GlobalizeReference(internal::Isolate* isolate, - internal::Address* handle); -V8_EXPORT void MoveGlobalReference(internal::Address** from, - internal::Address** to); -} // namespace api_internal - -/** - * Eternal handles are set-once handles that live for the lifetime of the - * isolate. - */ -template -class Eternal { - public: - V8_INLINE Eternal() : val_(nullptr) {} - template - V8_INLINE Eternal(Isolate* isolate, Local handle) : val_(nullptr) { - Set(isolate, handle); - } - // Can only be safely called if already set. - V8_INLINE Local Get(Isolate* isolate) const { - // The eternal handle will never go away, so as with the roots, we don't - // even need to open a handle. - return Local(val_); - } - - V8_INLINE bool IsEmpty() const { return val_ == nullptr; } - - template - void Set(Isolate* isolate, Local handle) { - static_assert(std::is_base_of::value, "type check"); - val_ = reinterpret_cast( - api_internal::Eternalize(isolate, reinterpret_cast(*handle))); - } - - private: - T* val_; -}; - -namespace api_internal { -V8_EXPORT void MakeWeak(internal::Address* location, void* data, - WeakCallbackInfo::Callback weak_callback, - WeakCallbackType type); -} // namespace api_internal - -/** - * An object reference that is independent of any handle scope. Where - * a Local handle only lives as long as the HandleScope in which it was - * allocated, a PersistentBase handle remains valid until it is explicitly - * disposed using Reset(). - * - * A persistent handle contains a reference to a storage cell within - * the V8 engine which holds an object value and which is updated by - * the garbage collector whenever the object is moved. A new storage - * cell can be created using the constructor or PersistentBase::Reset and - * existing handles can be disposed using PersistentBase::Reset. - * - */ -template -class PersistentBase { - public: - /** - * If non-empty, destroy the underlying storage cell - * IsEmpty() will return true after this call. - */ - V8_INLINE void Reset(); - - /** - * If non-empty, destroy the underlying storage cell - * and create a new one with the contents of other if other is non empty - */ - template - V8_INLINE void Reset(Isolate* isolate, const Local& other); - - /** - * If non-empty, destroy the underlying storage cell - * and create a new one with the contents of other if other is non empty - */ - template - V8_INLINE void Reset(Isolate* isolate, const PersistentBase& other); - - V8_INLINE bool IsEmpty() const { return val_ == nullptr; } - V8_INLINE void Empty() { val_ = 0; } - - V8_INLINE Local Get(Isolate* isolate) const { - return Local::New(isolate, *this); - } - - template - V8_INLINE bool operator==(const PersistentBase& that) const { - internal::Address* a = reinterpret_cast(this->val_); - internal::Address* b = reinterpret_cast(that.val_); - if (a == nullptr) return b == nullptr; - if (b == nullptr) return false; - return *a == *b; - } - - template - V8_INLINE bool operator==(const Local& that) const { - internal::Address* a = reinterpret_cast(this->val_); - internal::Address* b = reinterpret_cast(that.val_); - if (a == nullptr) return b == nullptr; - if (b == nullptr) return false; - return *a == *b; - } - - template - V8_INLINE bool operator!=(const PersistentBase& that) const { - return !operator==(that); - } - - template - V8_INLINE bool operator!=(const Local& that) const { - return !operator==(that); - } - - /** - * Install a finalization callback on this object. - * NOTE: There is no guarantee as to *when* or even *if* the callback is - * invoked. The invocation is performed solely on a best effort basis. - * As always, GC-based finalization should *not* be relied upon for any - * critical form of resource management! - * - * The callback is supposed to reset the handle. No further V8 API may be - * called in this callback. In case additional work involving V8 needs to be - * done, a second callback can be scheduled using - * WeakCallbackInfo::SetSecondPassCallback. - */ - template - V8_INLINE void SetWeak(P* parameter, - typename WeakCallbackInfo

::Callback callback, - WeakCallbackType type); - - /** - * Turns this handle into a weak phantom handle without finalization callback. - * The handle will be reset automatically when the garbage collector detects - * that the object is no longer reachable. - * A related function Isolate::NumberOfPhantomHandleResetsSinceLastCall - * returns how many phantom handles were reset by the garbage collector. - */ - V8_INLINE void SetWeak(); - - template - V8_INLINE P* ClearWeak(); - - // TODO(dcarney): remove this. - V8_INLINE void ClearWeak() { ClearWeak(); } - - /** - * Annotates the strong handle with the given label, which is then used by the - * heap snapshot generator as a name of the edge from the root to the handle. - * The function does not take ownership of the label and assumes that the - * label is valid as long as the handle is valid. - */ - V8_INLINE void AnnotateStrongRetainer(const char* label); - - /** Returns true if the handle's reference is weak. */ - V8_INLINE bool IsWeak() const; - - /** - * Assigns a wrapper class ID to the handle. - */ - V8_INLINE void SetWrapperClassId(uint16_t class_id); - - /** - * Returns the class ID previously assigned to this handle or 0 if no class ID - * was previously assigned. - */ - V8_INLINE uint16_t WrapperClassId() const; - - PersistentBase(const PersistentBase& other) = delete; - void operator=(const PersistentBase&) = delete; - - private: - friend class Isolate; - friend class Utils; - template - friend class Local; - template - friend class Persistent; - template - friend class Global; - template - friend class PersistentBase; - template - friend class ReturnValue; - template - friend class PersistentValueMapBase; - template - friend class PersistentValueVector; - friend class Object; - - explicit V8_INLINE PersistentBase(T* val) : val_(val) {} - V8_INLINE static T* New(Isolate* isolate, T* that); - - T* val_; -}; - -/** - * Default traits for Persistent. This class does not allow - * use of the copy constructor or assignment operator. - * At present kResetInDestructor is not set, but that will change in a future - * version. - */ -template -class NonCopyablePersistentTraits { - public: - using NonCopyablePersistent = Persistent>; - static const bool kResetInDestructor = false; - template - V8_INLINE static void Copy(const Persistent& source, - NonCopyablePersistent* dest) { - static_assert(sizeof(S) < 0, - "NonCopyablePersistentTraits::Copy is not instantiable"); - } -}; - -/** - * Helper class traits to allow copying and assignment of Persistent. - * This will clone the contents of storage cell, but not any of the flags, etc. - */ -template -struct CopyablePersistentTraits { - using CopyablePersistent = Persistent>; - static const bool kResetInDestructor = true; - template - static V8_INLINE void Copy(const Persistent& source, - CopyablePersistent* dest) { - // do nothing, just allow copy - } -}; - -/** - * A PersistentBase which allows copy and assignment. - * - * Copy, assignment and destructor behavior is controlled by the traits - * class M. - * - * Note: Persistent class hierarchy is subject to future changes. - */ -template -class Persistent : public PersistentBase { - public: - /** - * A Persistent with no storage cell. - */ - V8_INLINE Persistent() : PersistentBase(nullptr) {} - /** - * Construct a Persistent from a Local. - * When the Local is non-empty, a new storage cell is created - * pointing to the same object, and no flags are set. - */ - template - V8_INLINE Persistent(Isolate* isolate, Local that) - : PersistentBase(PersistentBase::New(isolate, *that)) { - static_assert(std::is_base_of::value, "type check"); - } - /** - * Construct a Persistent from a Persistent. - * When the Persistent is non-empty, a new storage cell is created - * pointing to the same object, and no flags are set. - */ - template - V8_INLINE Persistent(Isolate* isolate, const Persistent& that) - : PersistentBase(PersistentBase::New(isolate, *that)) { - static_assert(std::is_base_of::value, "type check"); - } - /** - * The copy constructors and assignment operator create a Persistent - * exactly as the Persistent constructor, but the Copy function from the - * traits class is called, allowing the setting of flags based on the - * copied Persistent. - */ - V8_INLINE Persistent(const Persistent& that) : PersistentBase(nullptr) { - Copy(that); - } - template - V8_INLINE Persistent(const Persistent& that) : PersistentBase(0) { - Copy(that); - } - V8_INLINE Persistent& operator=(const Persistent& that) { - Copy(that); - return *this; - } - template - V8_INLINE Persistent& operator=(const Persistent& that) { - Copy(that); - return *this; - } - /** - * The destructor will dispose the Persistent based on the - * kResetInDestructor flags in the traits class. Since not calling dispose - * can result in a memory leak, it is recommended to always set this flag. - */ - V8_INLINE ~Persistent() { - if (M::kResetInDestructor) this->Reset(); - } - - // TODO(dcarney): this is pretty useless, fix or remove - template - V8_INLINE static Persistent& Cast(const Persistent& that) { -#ifdef V8_ENABLE_CHECKS - // If we're going to perform the type check then we have to check - // that the handle isn't empty before doing the checked cast. - if (!that.IsEmpty()) T::Cast(*that); -#endif - return reinterpret_cast&>(const_cast&>(that)); - } - - // TODO(dcarney): this is pretty useless, fix or remove - template - V8_INLINE Persistent& As() const { - return Persistent::Cast(*this); - } - - private: - friend class Isolate; - friend class Utils; - template - friend class Local; - template - friend class Persistent; - template - friend class ReturnValue; - - explicit V8_INLINE Persistent(T* that) : PersistentBase(that) {} - V8_INLINE T* operator*() const { return this->val_; } - template - V8_INLINE void Copy(const Persistent& that); -}; - -/** - * A PersistentBase which has move semantics. - * - * Note: Persistent class hierarchy is subject to future changes. - */ -template -class Global : public PersistentBase { - public: - /** - * A Global with no storage cell. - */ - V8_INLINE Global() : PersistentBase(nullptr) {} - - /** - * Construct a Global from a Local. - * When the Local is non-empty, a new storage cell is created - * pointing to the same object, and no flags are set. - */ - template - V8_INLINE Global(Isolate* isolate, Local that) - : PersistentBase(PersistentBase::New(isolate, *that)) { - static_assert(std::is_base_of::value, "type check"); - } - - /** - * Construct a Global from a PersistentBase. - * When the Persistent is non-empty, a new storage cell is created - * pointing to the same object, and no flags are set. - */ - template - V8_INLINE Global(Isolate* isolate, const PersistentBase& that) - : PersistentBase(PersistentBase::New(isolate, that.val_)) { - static_assert(std::is_base_of::value, "type check"); - } - - /** - * Move constructor. - */ - V8_INLINE Global(Global&& other); - - V8_INLINE ~Global() { this->Reset(); } - - /** - * Move via assignment. - */ - template - V8_INLINE Global& operator=(Global&& rhs); - - /** - * Pass allows returning uniques from functions, etc. - */ - Global Pass() { return static_cast(*this); } - - /* - * For compatibility with Chromium's base::Bind (base::Passed). - */ - using MoveOnlyTypeForCPP03 = void; - - Global(const Global&) = delete; - void operator=(const Global&) = delete; - - private: - template - friend class ReturnValue; - V8_INLINE T* operator*() const { return this->val_; } -}; - -// UniquePersistent is an alias for Global for historical reason. -template -using UniquePersistent = Global; - -/** - * Interface for iterating through all the persistent handles in the heap. - */ -class V8_EXPORT PersistentHandleVisitor { - public: - virtual ~PersistentHandleVisitor() = default; - virtual void VisitPersistentHandle(Persistent* value, - uint16_t class_id) {} -}; - -template -T* PersistentBase::New(Isolate* isolate, T* that) { - if (that == nullptr) return nullptr; - internal::Address* p = reinterpret_cast(that); - return reinterpret_cast(api_internal::GlobalizeReference( - reinterpret_cast(isolate), p)); -} - -template -template -void Persistent::Copy(const Persistent& that) { - static_assert(std::is_base_of::value, "type check"); - this->Reset(); - if (that.IsEmpty()) return; - internal::Address* p = reinterpret_cast(that.val_); - this->val_ = reinterpret_cast(api_internal::CopyGlobalReference(p)); - M::Copy(that, this); -} - -template -bool PersistentBase::IsWeak() const { - using I = internal::Internals; - if (this->IsEmpty()) return false; - return I::GetNodeState(reinterpret_cast(this->val_)) == - I::kNodeStateIsWeakValue; -} - -template -void PersistentBase::Reset() { - if (this->IsEmpty()) return; - api_internal::DisposeGlobal(reinterpret_cast(this->val_)); - val_ = nullptr; -} - -/** - * If non-empty, destroy the underlying storage cell - * and create a new one with the contents of other if other is non empty - */ -template -template -void PersistentBase::Reset(Isolate* isolate, const Local& other) { - static_assert(std::is_base_of::value, "type check"); - Reset(); - if (other.IsEmpty()) return; - this->val_ = New(isolate, other.val_); -} - -/** - * If non-empty, destroy the underlying storage cell - * and create a new one with the contents of other if other is non empty - */ -template -template -void PersistentBase::Reset(Isolate* isolate, - const PersistentBase& other) { - static_assert(std::is_base_of::value, "type check"); - Reset(); - if (other.IsEmpty()) return; - this->val_ = New(isolate, other.val_); -} - -template -template -V8_INLINE void PersistentBase::SetWeak( - P* parameter, typename WeakCallbackInfo

::Callback callback, - WeakCallbackType type) { - using Callback = WeakCallbackInfo::Callback; -#if (__GNUC__ >= 8) && !defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-function-type" -#endif - api_internal::MakeWeak(reinterpret_cast(this->val_), - parameter, reinterpret_cast(callback), type); -#if (__GNUC__ >= 8) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif -} - -template -void PersistentBase::SetWeak() { - api_internal::MakeWeak(reinterpret_cast(&this->val_)); -} - -template -template -P* PersistentBase::ClearWeak() { - return reinterpret_cast(api_internal::ClearWeak( - reinterpret_cast(this->val_))); -} - -template -void PersistentBase::AnnotateStrongRetainer(const char* label) { - api_internal::AnnotateStrongRetainer( - reinterpret_cast(this->val_), label); -} - -template -void PersistentBase::SetWrapperClassId(uint16_t class_id) { - using I = internal::Internals; - if (this->IsEmpty()) return; - internal::Address* obj = reinterpret_cast(this->val_); - uint8_t* addr = reinterpret_cast(obj) + I::kNodeClassIdOffset; - *reinterpret_cast(addr) = class_id; -} - -template -uint16_t PersistentBase::WrapperClassId() const { - using I = internal::Internals; - if (this->IsEmpty()) return 0; - internal::Address* obj = reinterpret_cast(this->val_); - uint8_t* addr = reinterpret_cast(obj) + I::kNodeClassIdOffset; - return *reinterpret_cast(addr); -} - -template -Global::Global(Global&& other) : PersistentBase(other.val_) { - if (other.val_ != nullptr) { - api_internal::MoveGlobalReference( - reinterpret_cast(&other.val_), - reinterpret_cast(&this->val_)); - other.val_ = nullptr; - } -} - -template -template -Global& Global::operator=(Global&& rhs) { - static_assert(std::is_base_of::value, "type check"); - if (this != &rhs) { - this->Reset(); - if (rhs.val_ != nullptr) { - this->val_ = rhs.val_; - api_internal::MoveGlobalReference( - reinterpret_cast(&rhs.val_), - reinterpret_cast(&this->val_)); - rhs.val_ = nullptr; - } - } - return *this; -} - -} // namespace v8 - -#endif // INCLUDE_V8_PERSISTENT_HANDLE_H_ diff --git a/NativeScript/include/v8-platform.h b/NativeScript/include/v8-platform.h deleted file mode 100644 index 91b3fd9c..00000000 --- a/NativeScript/include/v8-platform.h +++ /dev/null @@ -1,1092 +0,0 @@ -// Copyright 2013 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_V8_PLATFORM_H_ -#define V8_V8_PLATFORM_H_ - -#include -#include -#include // For abort. -#include -#include - -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Isolate; - -// Valid priorities supported by the task scheduling infrastructure. -enum class TaskPriority : uint8_t { - /** - * Best effort tasks are not critical for performance of the application. The - * platform implementation should preempt such tasks if higher priority tasks - * arrive. - */ - kBestEffort, - /** - * User visible tasks are long running background tasks that will - * improve performance and memory usage of the application upon completion. - * Example: background compilation and garbage collection. - */ - kUserVisible, - /** - * User blocking tasks are highest priority tasks that block the execution - * thread (e.g. major garbage collection). They must be finished as soon as - * possible. - */ - kUserBlocking, -}; - -/** - * A Task represents a unit of work. - */ -class Task { - public: - virtual ~Task() = default; - - virtual void Run() = 0; -}; - -/** - * An IdleTask represents a unit of work to be performed in idle time. - * The Run method is invoked with an argument that specifies the deadline in - * seconds returned by MonotonicallyIncreasingTime(). - * The idle task is expected to complete by this deadline. - */ -class IdleTask { - public: - virtual ~IdleTask() = default; - virtual void Run(double deadline_in_seconds) = 0; -}; - -/** - * A TaskRunner allows scheduling of tasks. The TaskRunner may still be used to - * post tasks after the isolate gets destructed, but these tasks may not get - * executed anymore. All tasks posted to a given TaskRunner will be invoked in - * sequence. Tasks can be posted from any thread. - */ -class TaskRunner { - public: - /** - * Schedules a task to be invoked by this TaskRunner. The TaskRunner - * implementation takes ownership of |task|. - */ - virtual void PostTask(std::unique_ptr task) = 0; - - /** - * Schedules a task to be invoked by this TaskRunner. The TaskRunner - * implementation takes ownership of |task|. The |task| cannot be nested - * within other task executions. - * - * Tasks which shouldn't be interleaved with JS execution must be posted with - * |PostNonNestableTask| or |PostNonNestableDelayedTask|. This is because the - * embedder may process tasks in a callback which is called during JS - * execution. - * - * In particular, tasks which execute JS must be non-nestable, since JS - * execution is not allowed to nest. - * - * Requires that |TaskRunner::NonNestableTasksEnabled()| is true. - */ - virtual void PostNonNestableTask(std::unique_ptr task) {} - - /** - * Schedules a task to be invoked by this TaskRunner. The task is scheduled - * after the given number of seconds |delay_in_seconds|. The TaskRunner - * implementation takes ownership of |task|. - */ - virtual void PostDelayedTask(std::unique_ptr task, - double delay_in_seconds) = 0; - - /** - * Schedules a task to be invoked by this TaskRunner. The task is scheduled - * after the given number of seconds |delay_in_seconds|. The TaskRunner - * implementation takes ownership of |task|. The |task| cannot be nested - * within other task executions. - * - * Tasks which shouldn't be interleaved with JS execution must be posted with - * |PostNonNestableTask| or |PostNonNestableDelayedTask|. This is because the - * embedder may process tasks in a callback which is called during JS - * execution. - * - * In particular, tasks which execute JS must be non-nestable, since JS - * execution is not allowed to nest. - * - * Requires that |TaskRunner::NonNestableDelayedTasksEnabled()| is true. - */ - virtual void PostNonNestableDelayedTask(std::unique_ptr task, - double delay_in_seconds) {} - - /** - * Schedules an idle task to be invoked by this TaskRunner. The task is - * scheduled when the embedder is idle. Requires that - * |TaskRunner::IdleTasksEnabled()| is true. Idle tasks may be reordered - * relative to other task types and may be starved for an arbitrarily long - * time if no idle time is available. The TaskRunner implementation takes - * ownership of |task|. - */ - virtual void PostIdleTask(std::unique_ptr task) = 0; - - /** - * Returns true if idle tasks are enabled for this TaskRunner. - */ - virtual bool IdleTasksEnabled() = 0; - - /** - * Returns true if non-nestable tasks are enabled for this TaskRunner. - */ - virtual bool NonNestableTasksEnabled() const { return false; } - - /** - * Returns true if non-nestable delayed tasks are enabled for this TaskRunner. - */ - virtual bool NonNestableDelayedTasksEnabled() const { return false; } - - TaskRunner() = default; - virtual ~TaskRunner() = default; - - TaskRunner(const TaskRunner&) = delete; - TaskRunner& operator=(const TaskRunner&) = delete; -}; - -/** - * Delegate that's passed to Job's worker task, providing an entry point to - * communicate with the scheduler. - */ -class JobDelegate { - public: - /** - * Returns true if this thread should return from the worker task on the - * current thread ASAP. Workers should periodically invoke ShouldYield (or - * YieldIfNeeded()) as often as is reasonable. - */ - virtual bool ShouldYield() = 0; - - /** - * Notifies the scheduler that max concurrency was increased, and the number - * of worker should be adjusted accordingly. See Platform::PostJob() for more - * details. - */ - virtual void NotifyConcurrencyIncrease() = 0; - - /** - * Returns a task_id unique among threads currently running this job, such - * that GetTaskId() < worker count. To achieve this, the same task_id may be - * reused by a different thread after a worker_task returns. - */ - virtual uint8_t GetTaskId() = 0; - - /** - * Returns true if the current task is called from the thread currently - * running JobHandle::Join(). - */ - virtual bool IsJoiningThread() const = 0; -}; - -/** - * Handle returned when posting a Job. Provides methods to control execution of - * the posted Job. - */ -class JobHandle { - public: - virtual ~JobHandle() = default; - - /** - * Notifies the scheduler that max concurrency was increased, and the number - * of worker should be adjusted accordingly. See Platform::PostJob() for more - * details. - */ - virtual void NotifyConcurrencyIncrease() = 0; - - /** - * Contributes to the job on this thread. Doesn't return until all tasks have - * completed and max concurrency becomes 0. When Join() is called and max - * concurrency reaches 0, it should not increase again. This also promotes - * this Job's priority to be at least as high as the calling thread's - * priority. - */ - virtual void Join() = 0; - - /** - * Forces all existing workers to yield ASAP. Waits until they have all - * returned from the Job's callback before returning. - */ - virtual void Cancel() = 0; - - /* - * Forces all existing workers to yield ASAP but doesn’t wait for them. - * Warning, this is dangerous if the Job's callback is bound to or has access - * to state which may be deleted after this call. - */ - virtual void CancelAndDetach() = 0; - - /** - * Returns true if there's any work pending or any worker running. - */ - virtual bool IsActive() = 0; - - /** - * Returns true if associated with a Job and other methods may be called. - * Returns false after Join() or Cancel() was called. This may return true - * even if no workers are running and IsCompleted() returns true - */ - virtual bool IsValid() = 0; - - /** - * Returns true if job priority can be changed. - */ - virtual bool UpdatePriorityEnabled() const { return false; } - - /** - * Update this Job's priority. - */ - virtual void UpdatePriority(TaskPriority new_priority) {} -}; - -/** - * A JobTask represents work to run in parallel from Platform::PostJob(). - */ -class JobTask { - public: - virtual ~JobTask() = default; - - virtual void Run(JobDelegate* delegate) = 0; - - /** - * Controls the maximum number of threads calling Run() concurrently, given - * the number of threads currently assigned to this job and executing Run(). - * Run() is only invoked if the number of threads previously running Run() was - * less than the value returned. Since GetMaxConcurrency() is a leaf function, - * it must not call back any JobHandle methods. - */ - virtual size_t GetMaxConcurrency(size_t worker_count) const = 0; -}; - -/** - * The interface represents complex arguments to trace events. - */ -class ConvertableToTraceFormat { - public: - virtual ~ConvertableToTraceFormat() = default; - - /** - * Append the class info to the provided |out| string. The appended - * data must be a valid JSON object. Strings must be properly quoted, and - * escaped. There is no processing applied to the content after it is - * appended. - */ - virtual void AppendAsTraceFormat(std::string* out) const = 0; -}; - -/** - * V8 Tracing controller. - * - * Can be implemented by an embedder to record trace events from V8. - */ -class TracingController { - public: - virtual ~TracingController() = default; - - // In Perfetto mode, trace events are written using Perfetto's Track Event - // API directly without going through the embedder. However, it is still - // possible to observe tracing being enabled and disabled. -#if !defined(V8_USE_PERFETTO) - /** - * Called by TRACE_EVENT* macros, don't call this directly. - * The name parameter is a category group for example: - * TRACE_EVENT0("v8,parse", "V8.Parse") - * The pointer returned points to a value with zero or more of the bits - * defined in CategoryGroupEnabledFlags. - **/ - virtual const uint8_t* GetCategoryGroupEnabled(const char* name) { - static uint8_t no = 0; - return &no; - } - - /** - * Adds a trace event to the platform tracing system. These function calls are - * usually the result of a TRACE_* macro from trace_event_common.h when - * tracing and the category of the particular trace are enabled. It is not - * advisable to call these functions on their own; they are really only meant - * to be used by the trace macros. The returned handle can be used by - * UpdateTraceEventDuration to update the duration of COMPLETE events. - */ - virtual uint64_t AddTraceEvent( - char phase, const uint8_t* category_enabled_flag, const char* name, - const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args, - const char** arg_names, const uint8_t* arg_types, - const uint64_t* arg_values, - std::unique_ptr* arg_convertables, - unsigned int flags) { - return 0; - } - virtual uint64_t AddTraceEventWithTimestamp( - char phase, const uint8_t* category_enabled_flag, const char* name, - const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args, - const char** arg_names, const uint8_t* arg_types, - const uint64_t* arg_values, - std::unique_ptr* arg_convertables, - unsigned int flags, int64_t timestamp) { - return 0; - } - - /** - * Sets the duration field of a COMPLETE trace event. It must be called with - * the handle returned from AddTraceEvent(). - **/ - virtual void UpdateTraceEventDuration(const uint8_t* category_enabled_flag, - const char* name, uint64_t handle) {} -#endif // !defined(V8_USE_PERFETTO) - - class TraceStateObserver { - public: - virtual ~TraceStateObserver() = default; - virtual void OnTraceEnabled() = 0; - virtual void OnTraceDisabled() = 0; - }; - - /** Adds tracing state change observer. */ - virtual void AddTraceStateObserver(TraceStateObserver*) {} - - /** Removes tracing state change observer. */ - virtual void RemoveTraceStateObserver(TraceStateObserver*) {} -}; - -/** - * A V8 memory page allocator. - * - * Can be implemented by an embedder to manage large host OS allocations. - */ -class PageAllocator { - public: - virtual ~PageAllocator() = default; - - /** - * Gets the page granularity for AllocatePages and FreePages. Addresses and - * lengths for those calls should be multiples of AllocatePageSize(). - */ - virtual size_t AllocatePageSize() = 0; - - /** - * Gets the page granularity for SetPermissions and ReleasePages. Addresses - * and lengths for those calls should be multiples of CommitPageSize(). - */ - virtual size_t CommitPageSize() = 0; - - /** - * Sets the random seed so that GetRandomMmapAddr() will generate repeatable - * sequences of random mmap addresses. - */ - virtual void SetRandomMmapSeed(int64_t seed) = 0; - - /** - * Returns a randomized address, suitable for memory allocation under ASLR. - * The address will be aligned to AllocatePageSize. - */ - virtual void* GetRandomMmapAddr() = 0; - - /** - * Memory permissions. - */ - enum Permission { - kNoAccess, - kRead, - kReadWrite, - kReadWriteExecute, - kReadExecute, - // Set this when reserving memory that will later require kReadWriteExecute - // permissions. The resulting behavior is platform-specific, currently - // this is used to set the MAP_JIT flag on Apple Silicon. - // TODO(jkummerow): Remove this when Wasm has a platform-independent - // w^x implementation. - // TODO(saelo): Remove this once all JIT pages are allocated through the - // VirtualAddressSpace API. - kNoAccessWillJitLater - }; - - /** - * Allocates memory in range with the given alignment and permission. - */ - virtual void* AllocatePages(void* address, size_t length, size_t alignment, - Permission permissions) = 0; - - /** - * Frees memory in a range that was allocated by a call to AllocatePages. - */ - virtual bool FreePages(void* address, size_t length) = 0; - - /** - * Releases memory in a range that was allocated by a call to AllocatePages. - */ - virtual bool ReleasePages(void* address, size_t length, - size_t new_length) = 0; - - /** - * Sets permissions on pages in an allocated range. - */ - virtual bool SetPermissions(void* address, size_t length, - Permission permissions) = 0; - - /** - * Frees memory in the given [address, address + size) range. address and size - * should be operating system page-aligned. The next write to this - * memory area brings the memory transparently back. This should be treated as - * a hint to the OS that the pages are no longer needed. It does not guarantee - * that the pages will be discarded immediately or at all. - */ - virtual bool DiscardSystemPages(void* address, size_t size) { return true; } - - /** - * Decommits any wired memory pages in the given range, allowing the OS to - * reclaim them, and marks the region as inacessible (kNoAccess). The address - * range stays reserved and can be accessed again later by changing its - * permissions. However, in that case the memory content is guaranteed to be - * zero-initialized again. The memory must have been previously allocated by a - * call to AllocatePages. Returns true on success, false otherwise. - */ - virtual bool DecommitPages(void* address, size_t size) = 0; - - /** - * INTERNAL ONLY: This interface has not been stabilised and may change - * without notice from one release to another without being deprecated first. - */ - class SharedMemoryMapping { - public: - // Implementations are expected to free the shared memory mapping in the - // destructor. - virtual ~SharedMemoryMapping() = default; - virtual void* GetMemory() const = 0; - }; - - /** - * INTERNAL ONLY: This interface has not been stabilised and may change - * without notice from one release to another without being deprecated first. - */ - class SharedMemory { - public: - // Implementations are expected to free the shared memory in the destructor. - virtual ~SharedMemory() = default; - virtual std::unique_ptr RemapTo( - void* new_address) const = 0; - virtual void* GetMemory() const = 0; - virtual size_t GetSize() const = 0; - }; - - /** - * INTERNAL ONLY: This interface has not been stabilised and may change - * without notice from one release to another without being deprecated first. - * - * Reserve pages at a fixed address returning whether the reservation is - * possible. The reserved memory is detached from the PageAllocator and so - * should not be freed by it. It's intended for use with - * SharedMemory::RemapTo, where ~SharedMemoryMapping would free the memory. - */ - virtual bool ReserveForSharedMemoryMapping(void* address, size_t size) { - return false; - } - - /** - * INTERNAL ONLY: This interface has not been stabilised and may change - * without notice from one release to another without being deprecated first. - * - * Allocates shared memory pages. Not all PageAllocators need support this and - * so this method need not be overridden. - * Allocates a new read-only shared memory region of size |length| and copies - * the memory at |original_address| into it. - */ - virtual std::unique_ptr AllocateSharedPages( - size_t length, const void* original_address) { - return {}; - } - - /** - * INTERNAL ONLY: This interface has not been stabilised and may change - * without notice from one release to another without being deprecated first. - * - * If not overridden and changed to return true, V8 will not attempt to call - * AllocateSharedPages or RemapSharedPages. If overridden, AllocateSharedPages - * and RemapSharedPages must also be overridden. - */ - virtual bool CanAllocateSharedPages() { return false; } -}; - -// Opaque type representing a handle to a shared memory region. -using PlatformSharedMemoryHandle = intptr_t; -static constexpr PlatformSharedMemoryHandle kInvalidSharedMemoryHandle = -1; - -// Conversion routines from the platform-dependent shared memory identifiers -// into the opaque PlatformSharedMemoryHandle type. These use the underlying -// types (e.g. unsigned int) instead of the typedef'd ones (e.g. mach_port_t) -// to avoid pulling in large OS header files into this header file. Instead, -// the users of these routines are expected to include the respecitve OS -// headers in addition to this one. -#if V8_OS_MACOS -// Convert between a shared memory handle and a mach_port_t referencing a memory -// entry object. -inline PlatformSharedMemoryHandle SharedMemoryHandleFromMachMemoryEntry( - unsigned int port) { - return static_cast(port); -} -inline unsigned int MachMemoryEntryFromSharedMemoryHandle( - PlatformSharedMemoryHandle handle) { - return static_cast(handle); -} -#elif V8_OS_FUCHSIA -// Convert between a shared memory handle and a zx_handle_t to a VMO. -inline PlatformSharedMemoryHandle SharedMemoryHandleFromVMO(uint32_t handle) { - return static_cast(handle); -} -inline uint32_t VMOFromSharedMemoryHandle(PlatformSharedMemoryHandle handle) { - return static_cast(handle); -} -#elif V8_OS_WIN -// Convert between a shared memory handle and a Windows HANDLE to a file mapping -// object. -inline PlatformSharedMemoryHandle SharedMemoryHandleFromFileMapping( - void* handle) { - return reinterpret_cast(handle); -} -inline void* FileMappingFromSharedMemoryHandle( - PlatformSharedMemoryHandle handle) { - return reinterpret_cast(handle); -} -#else -// Convert between a shared memory handle and a file descriptor. -inline PlatformSharedMemoryHandle SharedMemoryHandleFromFileDescriptor(int fd) { - return static_cast(fd); -} -inline int FileDescriptorFromSharedMemoryHandle( - PlatformSharedMemoryHandle handle) { - return static_cast(handle); -} -#endif - -/** - * Possible permissions for memory pages. - */ -enum class PagePermissions { - kNoAccess, - kRead, - kReadWrite, - kReadWriteExecute, - kReadExecute, -}; - -/** - * Class to manage a virtual memory address space. - * - * This class represents a contiguous region of virtual address space in which - * sub-spaces and (private or shared) memory pages can be allocated, freed, and - * modified. This interface is meant to eventually replace the PageAllocator - * interface, and can be used as an alternative in the meantime. - * - * This API is not yet stable and may change without notice! - */ -class VirtualAddressSpace { - public: - using Address = uintptr_t; - - VirtualAddressSpace(size_t page_size, size_t allocation_granularity, - Address base, size_t size, - PagePermissions max_page_permissions) - : page_size_(page_size), - allocation_granularity_(allocation_granularity), - base_(base), - size_(size), - max_page_permissions_(max_page_permissions) {} - - virtual ~VirtualAddressSpace() = default; - - /** - * The page size used inside this space. Guaranteed to be a power of two. - * Used as granularity for all page-related operations except for allocation, - * which use the allocation_granularity(), see below. - * - * \returns the page size in bytes. - */ - size_t page_size() const { return page_size_; } - - /** - * The granularity of page allocations and, by extension, of subspace - * allocations. This is guaranteed to be a power of two and a multiple of the - * page_size(). In practice, this is equal to the page size on most OSes, but - * on Windows it is usually 64KB, while the page size is 4KB. - * - * \returns the allocation granularity in bytes. - */ - size_t allocation_granularity() const { return allocation_granularity_; } - - /** - * The base address of the address space managed by this instance. - * - * \returns the base address of this address space. - */ - Address base() const { return base_; } - - /** - * The size of the address space managed by this instance. - * - * \returns the size of this address space in bytes. - */ - size_t size() const { return size_; } - - /** - * The maximum page permissions that pages allocated inside this space can - * obtain. - * - * \returns the maximum page permissions. - */ - PagePermissions max_page_permissions() const { return max_page_permissions_; } - - /** - * Sets the random seed so that GetRandomPageAddress() will generate - * repeatable sequences of random addresses. - * - * \param The seed for the PRNG. - */ - virtual void SetRandomSeed(int64_t seed) = 0; - - /** - * Returns a random address inside this address space, suitable for page - * allocations hints. - * - * \returns a random address aligned to allocation_granularity(). - */ - virtual Address RandomPageAddress() = 0; - - /** - * Allocates private memory pages with the given alignment and permissions. - * - * \param hint If nonzero, the allocation is attempted to be placed at the - * given address first. If that fails, the allocation is attempted to be - * placed elsewhere, possibly nearby, but that is not guaranteed. Specifying - * zero for the hint always causes this function to choose a random address. - * The hint, if specified, must be aligned to the specified alignment. - * - * \param size The size of the allocation in bytes. Must be a multiple of the - * allocation_granularity(). - * - * \param alignment The alignment of the allocation in bytes. Must be a - * multiple of the allocation_granularity() and should be a power of two. - * - * \param permissions The page permissions of the newly allocated pages. - * - * \returns the start address of the allocated pages on success, zero on - * failure. - */ - static constexpr Address kNoHint = 0; - virtual V8_WARN_UNUSED_RESULT Address - AllocatePages(Address hint, size_t size, size_t alignment, - PagePermissions permissions) = 0; - - /** - * Frees previously allocated pages. - * - * This function will terminate the process on failure as this implies a bug - * in the client. As such, there is no return value. - * - * \param address The start address of the pages to free. This address must - * have been obtained through a call to AllocatePages. - * - * \param size The size in bytes of the region to free. This must match the - * size passed to AllocatePages when the pages were allocated. - */ - virtual void FreePages(Address address, size_t size) = 0; - - /** - * Sets permissions of all allocated pages in the given range. - * - * \param address The start address of the range. Must be aligned to - * page_size(). - * - * \param size The size in bytes of the range. Must be a multiple - * of page_size(). - * - * \param permissions The new permissions for the range. - * - * \returns true on success, false otherwise. - */ - virtual V8_WARN_UNUSED_RESULT bool SetPagePermissions( - Address address, size_t size, PagePermissions permissions) = 0; - - /** - * Creates a guard region at the specified address. - * - * Guard regions are guaranteed to cause a fault when accessed and generally - * do not count towards any memory consumption limits. Further, allocating - * guard regions can usually not fail in subspaces if the region does not - * overlap with another region, subspace, or page allocation. - * - * \param address The start address of the guard region. Must be aligned to - * the allocation_granularity(). - * - * \param size The size of the guard region in bytes. Must be a multiple of - * the allocation_granularity(). - * - * \returns true on success, false otherwise. - */ - virtual V8_WARN_UNUSED_RESULT bool AllocateGuardRegion(Address address, - size_t size) = 0; - - /** - * Frees an existing guard region. - * - * This function will terminate the process on failure as this implies a bug - * in the client. As such, there is no return value. - * - * \param address The start address of the guard region to free. This address - * must have previously been used as address parameter in a successful - * invocation of AllocateGuardRegion. - * - * \param size The size in bytes of the guard region to free. This must match - * the size passed to AllocateGuardRegion when the region was created. - */ - virtual void FreeGuardRegion(Address address, size_t size) = 0; - - /** - * Allocates shared memory pages with the given permissions. - * - * \param hint Placement hint. See AllocatePages. - * - * \param size The size of the allocation in bytes. Must be a multiple of the - * allocation_granularity(). - * - * \param permissions The page permissions of the newly allocated pages. - * - * \param handle A platform-specific handle to a shared memory object. See - * the SharedMemoryHandleFromX routines above for ways to obtain these. - * - * \param offset The offset in the shared memory object at which the mapping - * should start. Must be a multiple of the allocation_granularity(). - * - * \returns the start address of the allocated pages on success, zero on - * failure. - */ - virtual V8_WARN_UNUSED_RESULT Address - AllocateSharedPages(Address hint, size_t size, PagePermissions permissions, - PlatformSharedMemoryHandle handle, uint64_t offset) = 0; - - /** - * Frees previously allocated shared pages. - * - * This function will terminate the process on failure as this implies a bug - * in the client. As such, there is no return value. - * - * \param address The start address of the pages to free. This address must - * have been obtained through a call to AllocateSharedPages. - * - * \param size The size in bytes of the region to free. This must match the - * size passed to AllocateSharedPages when the pages were allocated. - */ - virtual void FreeSharedPages(Address address, size_t size) = 0; - - /** - * Whether this instance can allocate subspaces or not. - * - * \returns true if subspaces can be allocated, false if not. - */ - virtual bool CanAllocateSubspaces() = 0; - - /* - * Allocate a subspace. - * - * The address space of a subspace stays reserved in the parent space for the - * lifetime of the subspace. As such, it is guaranteed that page allocations - * on the parent space cannot end up inside a subspace. - * - * \param hint Hints where the subspace should be allocated. See - * AllocatePages() for more details. - * - * \param size The size in bytes of the subspace. Must be a multiple of the - * allocation_granularity(). - * - * \param alignment The alignment of the subspace in bytes. Must be a multiple - * of the allocation_granularity() and should be a power of two. - * - * \param max_page_permissions The maximum permissions that pages allocated in - * the subspace can obtain. - * - * \returns a new subspace or nullptr on failure. - */ - virtual std::unique_ptr AllocateSubspace( - Address hint, size_t size, size_t alignment, - PagePermissions max_page_permissions) = 0; - - // - // TODO(v8) maybe refactor the methods below before stabilizing the API. For - // example by combining them into some form of page operation method that - // takes a command enum as parameter. - // - - /** - * Frees memory in the given [address, address + size) range. address and - * size should be aligned to the page_size(). The next write to this memory - * area brings the memory transparently back. This should be treated as a - * hint to the OS that the pages are no longer needed. It does not guarantee - * that the pages will be discarded immediately or at all. - * - * \returns true on success, false otherwise. Since this method is only a - * hint, a successful invocation does not imply that pages have been removed. - */ - virtual V8_WARN_UNUSED_RESULT bool DiscardSystemPages(Address address, - size_t size) { - return true; - } - /** - * Decommits any wired memory pages in the given range, allowing the OS to - * reclaim them, and marks the region as inacessible (kNoAccess). The address - * range stays reserved and can be accessed again later by changing its - * permissions. However, in that case the memory content is guaranteed to be - * zero-initialized again. The memory must have been previously allocated by a - * call to AllocatePages. - * - * \returns true on success, false otherwise. - */ - virtual V8_WARN_UNUSED_RESULT bool DecommitPages(Address address, - size_t size) = 0; - - private: - const size_t page_size_; - const size_t allocation_granularity_; - const Address base_; - const size_t size_; - const PagePermissions max_page_permissions_; -}; - -/** - * V8 Allocator used for allocating zone backings. - */ -class ZoneBackingAllocator { - public: - using MallocFn = void* (*)(size_t); - using FreeFn = void (*)(void*); - - virtual MallocFn GetMallocFn() const { return ::malloc; } - virtual FreeFn GetFreeFn() const { return ::free; } -}; - -/** - * Observer used by V8 to notify the embedder about entering/leaving sections - * with high throughput of malloc/free operations. - */ -class HighAllocationThroughputObserver { - public: - virtual void EnterSection() {} - virtual void LeaveSection() {} -}; - -/** - * V8 Platform abstraction layer. - * - * The embedder has to provide an implementation of this interface before - * initializing the rest of V8. - */ -class Platform { - public: - virtual ~Platform() = default; - - /** - * Allows the embedder to manage memory page allocations. - */ - virtual PageAllocator* GetPageAllocator() { - // TODO(bbudge) Make this abstract after all embedders implement this. - return nullptr; - } - - /** - * Allows the embedder to specify a custom allocator used for zones. - */ - virtual ZoneBackingAllocator* GetZoneBackingAllocator() { - static ZoneBackingAllocator default_allocator; - return &default_allocator; - } - - /** - * Enables the embedder to respond in cases where V8 can't allocate large - * blocks of memory. V8 retries the failed allocation once after calling this - * method. On success, execution continues; otherwise V8 exits with a fatal - * error. - * Embedder overrides of this function must NOT call back into V8. - */ - virtual void OnCriticalMemoryPressure() { - // TODO(bbudge) Remove this when embedders override the following method. - // See crbug.com/634547. - } - - /** - * Enables the embedder to respond in cases where V8 can't allocate large - * memory regions. The |length| parameter is the amount of memory needed. - * Returns true if memory is now available. Returns false if no memory could - * be made available. V8 will retry allocations until this method returns - * false. - * - * Embedder overrides of this function must NOT call back into V8. - */ - virtual bool OnCriticalMemoryPressure(size_t length) { return false; } - - /** - * Gets the number of worker threads used by - * Call(BlockingTask)OnWorkerThread(). This can be used to estimate the number - * of tasks a work package should be split into. A return value of 0 means - * that there are no worker threads available. Note that a value of 0 won't - * prohibit V8 from posting tasks using |CallOnWorkerThread|. - */ - virtual int NumberOfWorkerThreads() = 0; - - /** - * Returns a TaskRunner which can be used to post a task on the foreground. - * The TaskRunner's NonNestableTasksEnabled() must be true. This function - * should only be called from a foreground thread. - */ - virtual std::shared_ptr GetForegroundTaskRunner( - Isolate* isolate) = 0; - - /** - * Schedules a task to be invoked on a worker thread. - */ - virtual void CallOnWorkerThread(std::unique_ptr task) = 0; - - /** - * Schedules a task that blocks the main thread to be invoked with - * high-priority on a worker thread. - */ - virtual void CallBlockingTaskOnWorkerThread(std::unique_ptr task) { - // Embedders may optionally override this to process these tasks in a high - // priority pool. - CallOnWorkerThread(std::move(task)); - } - - /** - * Schedules a task to be invoked with low-priority on a worker thread. - */ - virtual void CallLowPriorityTaskOnWorkerThread(std::unique_ptr task) { - // Embedders may optionally override this to process these tasks in a low - // priority pool. - CallOnWorkerThread(std::move(task)); - } - - /** - * Schedules a task to be invoked on a worker thread after |delay_in_seconds| - * expires. - */ - virtual void CallDelayedOnWorkerThread(std::unique_ptr task, - double delay_in_seconds) = 0; - - /** - * Returns true if idle tasks are enabled for the given |isolate|. - */ - virtual bool IdleTasksEnabled(Isolate* isolate) { return false; } - - /** - * Posts |job_task| to run in parallel. Returns a JobHandle associated with - * the Job, which can be joined or canceled. - * This avoids degenerate cases: - * - Calling CallOnWorkerThread() for each work item, causing significant - * overhead. - * - Fixed number of CallOnWorkerThread() calls that split the work and might - * run for a long time. This is problematic when many components post - * "num cores" tasks and all expect to use all the cores. In these cases, - * the scheduler lacks context to be fair to multiple same-priority requests - * and/or ability to request lower priority work to yield when high priority - * work comes in. - * A canonical implementation of |job_task| looks like: - * class MyJobTask : public JobTask { - * public: - * MyJobTask(...) : worker_queue_(...) {} - * // JobTask: - * void Run(JobDelegate* delegate) override { - * while (!delegate->ShouldYield()) { - * // Smallest unit of work. - * auto work_item = worker_queue_.TakeWorkItem(); // Thread safe. - * if (!work_item) return; - * ProcessWork(work_item); - * } - * } - * - * size_t GetMaxConcurrency() const override { - * return worker_queue_.GetSize(); // Thread safe. - * } - * }; - * auto handle = PostJob(TaskPriority::kUserVisible, - * std::make_unique(...)); - * handle->Join(); - * - * PostJob() and methods of the returned JobHandle/JobDelegate, must never be - * called while holding a lock that could be acquired by JobTask::Run or - * JobTask::GetMaxConcurrency -- that could result in a deadlock. This is - * because [1] JobTask::GetMaxConcurrency may be invoked while holding - * internal lock (A), hence JobTask::GetMaxConcurrency can only use a lock (B) - * if that lock is *never* held while calling back into JobHandle from any - * thread (A=>B/B=>A deadlock) and [2] JobTask::Run or - * JobTask::GetMaxConcurrency may be invoked synchronously from JobHandle - * (B=>JobHandle::foo=>B deadlock). - * - * A sufficient PostJob() implementation that uses the default Job provided in - * libplatform looks like: - * std::unique_ptr PostJob( - * TaskPriority priority, std::unique_ptr job_task) override { - * return v8::platform::NewDefaultJobHandle( - * this, priority, std::move(job_task), NumberOfWorkerThreads()); - * } - */ - virtual std::unique_ptr PostJob( - TaskPriority priority, std::unique_ptr job_task) = 0; - - /** - * Monotonically increasing time in seconds from an arbitrary fixed point in - * the past. This function is expected to return at least - * millisecond-precision values. For this reason, - * it is recommended that the fixed point be no further in the past than - * the epoch. - **/ - virtual double MonotonicallyIncreasingTime() = 0; - - /** - * Current wall-clock time in milliseconds since epoch. - * This function is expected to return at least millisecond-precision values. - */ - virtual double CurrentClockTimeMillis() = 0; - - typedef void (*StackTracePrinter)(); - - /** - * Returns a function pointer that print a stack trace of the current stack - * on invocation. Disables printing of the stack trace if nullptr. - */ - virtual StackTracePrinter GetStackTracePrinter() { return nullptr; } - - /** - * Returns an instance of a v8::TracingController. This must be non-nullptr. - */ - virtual TracingController* GetTracingController() = 0; - - /** - * Tells the embedder to generate and upload a crashdump during an unexpected - * but non-critical scenario. - */ - virtual void DumpWithoutCrashing() {} - - /** - * Allows the embedder to observe sections with high throughput allocation - * operations. - */ - virtual HighAllocationThroughputObserver* - GetHighAllocationThroughputObserver() { - static HighAllocationThroughputObserver default_observer; - return &default_observer; - } - - protected: - /** - * Default implementation of current wall-clock time in milliseconds - * since epoch. Useful for implementing |CurrentClockTimeMillis| if - * nothing special needed. - */ - V8_EXPORT static double SystemClockTimeMillis(); -}; - -} // namespace v8 - -#endif // V8_V8_PLATFORM_H_ diff --git a/NativeScript/include/v8-primitive-object.h b/NativeScript/include/v8-primitive-object.h deleted file mode 100644 index 573932d0..00000000 --- a/NativeScript/include/v8-primitive-object.h +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_PRIMITIVE_OBJECT_H_ -#define INCLUDE_V8_PRIMITIVE_OBJECT_H_ - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-object.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Isolate; - -/** - * A Number object (ECMA-262, 4.3.21). - */ -class V8_EXPORT NumberObject : public Object { - public: - static Local New(Isolate* isolate, double value); - - double ValueOf() const; - - V8_INLINE static NumberObject* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - static void CheckCast(Value* obj); -}; - -/** - * A BigInt object (https://tc39.github.io/proposal-bigint) - */ -class V8_EXPORT BigIntObject : public Object { - public: - static Local New(Isolate* isolate, int64_t value); - - Local ValueOf() const; - - V8_INLINE static BigIntObject* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - static void CheckCast(Value* obj); -}; - -/** - * A Boolean object (ECMA-262, 4.3.15). - */ -class V8_EXPORT BooleanObject : public Object { - public: - static Local New(Isolate* isolate, bool value); - - bool ValueOf() const; - - V8_INLINE static BooleanObject* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - static void CheckCast(Value* obj); -}; - -/** - * A String object (ECMA-262, 4.3.18). - */ -class V8_EXPORT StringObject : public Object { - public: - static Local New(Isolate* isolate, Local value); - - Local ValueOf() const; - - V8_INLINE static StringObject* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - static void CheckCast(Value* obj); -}; - -/** - * A Symbol object (ECMA-262 edition 6). - */ -class V8_EXPORT SymbolObject : public Object { - public: - static Local New(Isolate* isolate, Local value); - - Local ValueOf() const; - - V8_INLINE static SymbolObject* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - static void CheckCast(Value* obj); -}; - -} // namespace v8 - -#endif // INCLUDE_V8_PRIMITIVE_OBJECT_H_ diff --git a/NativeScript/include/v8-primitive.h b/NativeScript/include/v8-primitive.h deleted file mode 100644 index 1b6de166..00000000 --- a/NativeScript/include/v8-primitive.h +++ /dev/null @@ -1,866 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_PRIMITIVE_H_ -#define INCLUDE_V8_PRIMITIVE_H_ - -#include "v8-data.h" // NOLINT(build/include_directory) -#include "v8-internal.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-value.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; -class Isolate; -class String; - -namespace internal { -class ExternalString; -class ScopedExternalStringLock; -} // namespace internal - -/** - * The superclass of primitive values. See ECMA-262 4.3.2. - */ -class V8_EXPORT Primitive : public Value {}; - -/** - * A primitive boolean value (ECMA-262, 4.3.14). Either the true - * or false value. - */ -class V8_EXPORT Boolean : public Primitive { - public: - bool Value() const; - V8_INLINE static Boolean* Cast(v8::Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return static_cast(data); - } - - V8_INLINE static Local New(Isolate* isolate, bool value); - - private: - static void CheckCast(v8::Data* that); -}; - -/** - * An array to hold Primitive values. This is used by the embedder to - * pass host defined options to the ScriptOptions during compilation. - * - * This is passed back to the embedder as part of - * HostImportModuleDynamicallyCallback for module loading. - */ -class V8_EXPORT PrimitiveArray : public Data { - public: - static Local New(Isolate* isolate, int length); - int Length() const; - void Set(Isolate* isolate, int index, Local item); - Local Get(Isolate* isolate, int index); - - V8_INLINE static PrimitiveArray* Cast(Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return reinterpret_cast(data); - } - - private: - static void CheckCast(Data* obj); -}; - -/** - * A superclass for symbols and strings. - */ -class V8_EXPORT Name : public Primitive { - public: - /** - * Returns the identity hash for this object. The current implementation - * uses an inline property on the object to store the identity hash. - * - * The return value will never be 0. Also, it is not guaranteed to be - * unique. - */ - int GetIdentityHash(); - - V8_INLINE static Name* Cast(Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return static_cast(data); - } - - private: - static void CheckCast(Data* that); -}; - -/** - * A flag describing different modes of string creation. - * - * Aside from performance implications there are no differences between the two - * creation modes. - */ -enum class NewStringType { - /** - * Create a new string, always allocating new storage memory. - */ - kNormal, - - /** - * Acts as a hint that the string should be created in the - * old generation heap space and be deduplicated if an identical string - * already exists. - */ - kInternalized -}; - -/** - * A JavaScript string value (ECMA-262, 4.3.17). - */ -class V8_EXPORT String : public Name { - public: - static constexpr int kMaxLength = - internal::kApiSystemPointerSize == 4 ? (1 << 28) - 16 : (1 << 29) - 24; - - enum Encoding { - UNKNOWN_ENCODING = 0x1, - TWO_BYTE_ENCODING = 0x0, - ONE_BYTE_ENCODING = 0x8 - }; - /** - * Returns the number of characters (UTF-16 code units) in this string. - */ - int Length() const; - - /** - * Returns the number of bytes in the UTF-8 encoded - * representation of this string. - */ - int Utf8Length(Isolate* isolate) const; - - /** - * Returns whether this string is known to contain only one byte data, - * i.e. ISO-8859-1 code points. - * Does not read the string. - * False negatives are possible. - */ - bool IsOneByte() const; - - /** - * Returns whether this string contain only one byte data, - * i.e. ISO-8859-1 code points. - * Will read the entire string in some cases. - */ - bool ContainsOnlyOneByte() const; - - /** - * Write the contents of the string to an external buffer. - * If no arguments are given, expects the buffer to be large - * enough to hold the entire string and NULL terminator. Copies - * the contents of the string and the NULL terminator into the - * buffer. - * - * WriteUtf8 will not write partial UTF-8 sequences, preferring to stop - * before the end of the buffer. - * - * Copies up to length characters into the output buffer. - * Only null-terminates if there is enough space in the buffer. - * - * \param buffer The buffer into which the string will be copied. - * \param start The starting position within the string at which - * copying begins. - * \param length The number of characters to copy from the string. For - * WriteUtf8 the number of bytes in the buffer. - * \param nchars_ref The number of characters written, can be NULL. - * \param options Various options that might affect performance of this or - * subsequent operations. - * \return The number of characters copied to the buffer excluding the null - * terminator. For WriteUtf8: The number of bytes copied to the buffer - * including the null terminator (if written). - */ - enum WriteOptions { - NO_OPTIONS = 0, - HINT_MANY_WRITES_EXPECTED = 1, - NO_NULL_TERMINATION = 2, - PRESERVE_ONE_BYTE_NULL = 4, - // Used by WriteUtf8 to replace orphan surrogate code units with the - // unicode replacement character. Needs to be set to guarantee valid UTF-8 - // output. - REPLACE_INVALID_UTF8 = 8 - }; - - // 16-bit character codes. - int Write(Isolate* isolate, uint16_t* buffer, int start = 0, int length = -1, - int options = NO_OPTIONS) const; - // One byte characters. - int WriteOneByte(Isolate* isolate, uint8_t* buffer, int start = 0, - int length = -1, int options = NO_OPTIONS) const; - // UTF-8 encoded characters. - int WriteUtf8(Isolate* isolate, char* buffer, int length = -1, - int* nchars_ref = nullptr, int options = NO_OPTIONS) const; - - /** - * A zero length string. - */ - V8_INLINE static Local Empty(Isolate* isolate); - - /** - * Returns true if the string is external. - */ - bool IsExternal() const; - - /** - * Returns true if the string is both external and two-byte. - */ - bool IsExternalTwoByte() const; - - /** - * Returns true if the string is both external and one-byte. - */ - bool IsExternalOneByte() const; - - class V8_EXPORT ExternalStringResourceBase { - public: - virtual ~ExternalStringResourceBase() = default; - - /** - * If a string is cacheable, the value returned by - * ExternalStringResource::data() may be cached, otherwise it is not - * expected to be stable beyond the current top-level task. - */ - virtual bool IsCacheable() const { return true; } - - // Disallow copying and assigning. - ExternalStringResourceBase(const ExternalStringResourceBase&) = delete; - void operator=(const ExternalStringResourceBase&) = delete; - - protected: - ExternalStringResourceBase() = default; - - /** - * Internally V8 will call this Dispose method when the external string - * resource is no longer needed. The default implementation will use the - * delete operator. This method can be overridden in subclasses to - * control how allocated external string resources are disposed. - */ - virtual void Dispose() { delete this; } - - /** - * For a non-cacheable string, the value returned by - * |ExternalStringResource::data()| has to be stable between |Lock()| and - * |Unlock()|, that is the string must behave as is |IsCacheable()| returned - * true. - * - * These two functions must be thread-safe, and can be called from anywhere. - * They also must handle lock depth, in the sense that each can be called - * several times, from different threads, and unlocking should only happen - * when the balance of Lock() and Unlock() calls is 0. - */ - virtual void Lock() const {} - - /** - * Unlocks the string. - */ - virtual void Unlock() const {} - - private: - friend class internal::ExternalString; - friend class v8::String; - friend class internal::ScopedExternalStringLock; - }; - - /** - * An ExternalStringResource is a wrapper around a two-byte string - * buffer that resides outside V8's heap. Implement an - * ExternalStringResource to manage the life cycle of the underlying - * buffer. Note that the string data must be immutable. - */ - class V8_EXPORT ExternalStringResource : public ExternalStringResourceBase { - public: - /** - * Override the destructor to manage the life cycle of the underlying - * buffer. - */ - ~ExternalStringResource() override = default; - - /** - * The string data from the underlying buffer. If the resource is cacheable - * then data() must return the same value for all invocations. - */ - virtual const uint16_t* data() const = 0; - - /** - * The length of the string. That is, the number of two-byte characters. - */ - virtual size_t length() const = 0; - - /** - * Returns the cached data from the underlying buffer. This method can be - * called only for cacheable resources (i.e. IsCacheable() == true) and only - * after UpdateDataCache() was called. - */ - const uint16_t* cached_data() const { - CheckCachedDataInvariants(); - return cached_data_; - } - - /** - * Update {cached_data_} with the data from the underlying buffer. This can - * be called only for cacheable resources. - */ - void UpdateDataCache(); - - protected: - ExternalStringResource() = default; - - private: - void CheckCachedDataInvariants() const; - - const uint16_t* cached_data_ = nullptr; - }; - - /** - * An ExternalOneByteStringResource is a wrapper around an one-byte - * string buffer that resides outside V8's heap. Implement an - * ExternalOneByteStringResource to manage the life cycle of the - * underlying buffer. Note that the string data must be immutable - * and that the data must be Latin-1 and not UTF-8, which would require - * special treatment internally in the engine and do not allow efficient - * indexing. Use String::New or convert to 16 bit data for non-Latin1. - */ - - class V8_EXPORT ExternalOneByteStringResource - : public ExternalStringResourceBase { - public: - /** - * Override the destructor to manage the life cycle of the underlying - * buffer. - */ - ~ExternalOneByteStringResource() override = default; - - /** - * The string data from the underlying buffer. If the resource is cacheable - * then data() must return the same value for all invocations. - */ - virtual const char* data() const = 0; - - /** The number of Latin-1 characters in the string.*/ - virtual size_t length() const = 0; - - /** - * Returns the cached data from the underlying buffer. If the resource is - * uncacheable or if UpdateDataCache() was not called before, it has - * undefined behaviour. - */ - const char* cached_data() const { - CheckCachedDataInvariants(); - return cached_data_; - } - - /** - * Update {cached_data_} with the data from the underlying buffer. This can - * be called only for cacheable resources. - */ - void UpdateDataCache(); - - protected: - ExternalOneByteStringResource() = default; - - private: - void CheckCachedDataInvariants() const; - - const char* cached_data_ = nullptr; - }; - - /** - * If the string is an external string, return the ExternalStringResourceBase - * regardless of the encoding, otherwise return NULL. The encoding of the - * string is returned in encoding_out. - */ - V8_INLINE ExternalStringResourceBase* GetExternalStringResourceBase( - Encoding* encoding_out) const; - - /** - * Get the ExternalStringResource for an external string. Returns - * NULL if IsExternal() doesn't return true. - */ - V8_INLINE ExternalStringResource* GetExternalStringResource() const; - - /** - * Get the ExternalOneByteStringResource for an external one-byte string. - * Returns NULL if IsExternalOneByte() doesn't return true. - */ - const ExternalOneByteStringResource* GetExternalOneByteStringResource() const; - - V8_INLINE static String* Cast(v8::Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return static_cast(data); - } - - /** - * Allocates a new string from a UTF-8 literal. This is equivalent to calling - * String::NewFromUtf(isolate, "...").ToLocalChecked(), but without the check - * overhead. - * - * When called on a string literal containing '\0', the inferred length is the - * length of the input array minus 1 (for the final '\0') and not the value - * returned by strlen. - **/ - template - static V8_WARN_UNUSED_RESULT Local NewFromUtf8Literal( - Isolate* isolate, const char (&literal)[N], - NewStringType type = NewStringType::kNormal) { - static_assert(N <= kMaxLength, "String is too long"); - return NewFromUtf8Literal(isolate, literal, type, N - 1); - } - - /** Allocates a new string from UTF-8 data. Only returns an empty value when - * length > kMaxLength. **/ - static V8_WARN_UNUSED_RESULT MaybeLocal NewFromUtf8( - Isolate* isolate, const char* data, - NewStringType type = NewStringType::kNormal, int length = -1); - - /** Allocates a new string from Latin-1 data. Only returns an empty value - * when length > kMaxLength. **/ - static V8_WARN_UNUSED_RESULT MaybeLocal NewFromOneByte( - Isolate* isolate, const uint8_t* data, - NewStringType type = NewStringType::kNormal, int length = -1); - - /** Allocates a new string from UTF-16 data. Only returns an empty value when - * length > kMaxLength. **/ - static V8_WARN_UNUSED_RESULT MaybeLocal NewFromTwoByte( - Isolate* isolate, const uint16_t* data, - NewStringType type = NewStringType::kNormal, int length = -1); - - /** - * Creates a new string by concatenating the left and the right strings - * passed in as parameters. - */ - static Local Concat(Isolate* isolate, Local left, - Local right); - - /** - * Creates a new external string using the data defined in the given - * resource. When the external string is no longer live on V8's heap the - * resource will be disposed by calling its Dispose method. The caller of - * this function should not otherwise delete or modify the resource. Neither - * should the underlying buffer be deallocated or modified except through the - * destructor of the external string resource. - */ - static V8_WARN_UNUSED_RESULT MaybeLocal NewExternalTwoByte( - Isolate* isolate, ExternalStringResource* resource); - - /** - * Associate an external string resource with this string by transforming it - * in place so that existing references to this string in the JavaScript heap - * will use the external string resource. The external string resource's - * character contents need to be equivalent to this string. - * Returns true if the string has been changed to be an external string. - * The string is not modified if the operation fails. See NewExternal for - * information on the lifetime of the resource. - */ - bool MakeExternal(ExternalStringResource* resource); - - /** - * Creates a new external string using the one-byte data defined in the given - * resource. When the external string is no longer live on V8's heap the - * resource will be disposed by calling its Dispose method. The caller of - * this function should not otherwise delete or modify the resource. Neither - * should the underlying buffer be deallocated or modified except through the - * destructor of the external string resource. - */ - static V8_WARN_UNUSED_RESULT MaybeLocal NewExternalOneByte( - Isolate* isolate, ExternalOneByteStringResource* resource); - - /** - * Associate an external string resource with this string by transforming it - * in place so that existing references to this string in the JavaScript heap - * will use the external string resource. The external string resource's - * character contents need to be equivalent to this string. - * Returns true if the string has been changed to be an external string. - * The string is not modified if the operation fails. See NewExternal for - * information on the lifetime of the resource. - */ - bool MakeExternal(ExternalOneByteStringResource* resource); - - /** - * Returns true if this string can be made external. - */ - bool CanMakeExternal() const; - - /** - * Returns true if the strings values are equal. Same as JS ==/===. - */ - bool StringEquals(Local str) const; - - /** - * Converts an object to a UTF-8-encoded character array. Useful if - * you want to print the object. If conversion to a string fails - * (e.g. due to an exception in the toString() method of the object) - * then the length() method returns 0 and the * operator returns - * NULL. - */ - class V8_EXPORT Utf8Value { - public: - Utf8Value(Isolate* isolate, Local obj); - ~Utf8Value(); - char* operator*() { return str_; } - const char* operator*() const { return str_; } - int length() const { return length_; } - - // Disallow copying and assigning. - Utf8Value(const Utf8Value&) = delete; - void operator=(const Utf8Value&) = delete; - - private: - char* str_; - int length_; - }; - - /** - * Converts an object to a two-byte (UTF-16-encoded) string. - * If conversion to a string fails (eg. due to an exception in the toString() - * method of the object) then the length() method returns 0 and the * operator - * returns NULL. - */ - class V8_EXPORT Value { - public: - Value(Isolate* isolate, Local obj); - ~Value(); - uint16_t* operator*() { return str_; } - const uint16_t* operator*() const { return str_; } - int length() const { return length_; } - - // Disallow copying and assigning. - Value(const Value&) = delete; - void operator=(const Value&) = delete; - - private: - uint16_t* str_; - int length_; - }; - - private: - void VerifyExternalStringResourceBase(ExternalStringResourceBase* v, - Encoding encoding) const; - void VerifyExternalStringResource(ExternalStringResource* val) const; - ExternalStringResource* GetExternalStringResourceSlow() const; - ExternalStringResourceBase* GetExternalStringResourceBaseSlow( - String::Encoding* encoding_out) const; - - static Local NewFromUtf8Literal(Isolate* isolate, - const char* literal, - NewStringType type, int length); - - static void CheckCast(v8::Data* that); -}; - -// Zero-length string specialization (templated string size includes -// terminator). -template <> -inline V8_WARN_UNUSED_RESULT Local String::NewFromUtf8Literal( - Isolate* isolate, const char (&literal)[1], NewStringType type) { - return String::Empty(isolate); -} - -/** - * Interface for iterating through all external resources in the heap. - */ -class V8_EXPORT ExternalResourceVisitor { - public: - virtual ~ExternalResourceVisitor() = default; - virtual void VisitExternalString(Local string) {} -}; - -/** - * A JavaScript symbol (ECMA-262 edition 6) - */ -class V8_EXPORT Symbol : public Name { - public: - /** - * Returns the description string of the symbol, or undefined if none. - */ - Local Description(Isolate* isolate) const; - - /** - * Create a symbol. If description is not empty, it will be used as the - * description. - */ - static Local New(Isolate* isolate, - Local description = Local()); - - /** - * Access global symbol registry. - * Note that symbols created this way are never collected, so - * they should only be used for statically fixed properties. - * Also, there is only one global name space for the descriptions used as - * keys. - * To minimize the potential for clashes, use qualified names as keys. - */ - static Local For(Isolate* isolate, Local description); - - /** - * Retrieve a global symbol. Similar to |For|, but using a separate - * registry that is not accessible by (and cannot clash with) JavaScript code. - */ - static Local ForApi(Isolate* isolate, Local description); - - // Well-known symbols - static Local GetAsyncIterator(Isolate* isolate); - static Local GetHasInstance(Isolate* isolate); - static Local GetIsConcatSpreadable(Isolate* isolate); - static Local GetIterator(Isolate* isolate); - static Local GetMatch(Isolate* isolate); - static Local GetReplace(Isolate* isolate); - static Local GetSearch(Isolate* isolate); - static Local GetSplit(Isolate* isolate); - static Local GetToPrimitive(Isolate* isolate); - static Local GetToStringTag(Isolate* isolate); - static Local GetUnscopables(Isolate* isolate); - - V8_INLINE static Symbol* Cast(Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return static_cast(data); - } - - private: - Symbol(); - static void CheckCast(Data* that); -}; - -/** - * A JavaScript number value (ECMA-262, 4.3.20) - */ -class V8_EXPORT Number : public Primitive { - public: - double Value() const; - static Local New(Isolate* isolate, double value); - V8_INLINE static Number* Cast(v8::Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return static_cast(data); - } - - private: - Number(); - static void CheckCast(v8::Data* that); -}; - -/** - * A JavaScript value representing a signed integer. - */ -class V8_EXPORT Integer : public Number { - public: - static Local New(Isolate* isolate, int32_t value); - static Local NewFromUnsigned(Isolate* isolate, uint32_t value); - int64_t Value() const; - V8_INLINE static Integer* Cast(v8::Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return static_cast(data); - } - - private: - Integer(); - static void CheckCast(v8::Data* that); -}; - -/** - * A JavaScript value representing a 32-bit signed integer. - */ -class V8_EXPORT Int32 : public Integer { - public: - int32_t Value() const; - V8_INLINE static Int32* Cast(v8::Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return static_cast(data); - } - - private: - Int32(); - static void CheckCast(v8::Data* that); -}; - -/** - * A JavaScript value representing a 32-bit unsigned integer. - */ -class V8_EXPORT Uint32 : public Integer { - public: - uint32_t Value() const; - V8_INLINE static Uint32* Cast(v8::Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return static_cast(data); - } - - private: - Uint32(); - static void CheckCast(v8::Data* that); -}; - -/** - * A JavaScript BigInt value (https://tc39.github.io/proposal-bigint) - */ -class V8_EXPORT BigInt : public Primitive { - public: - static Local New(Isolate* isolate, int64_t value); - static Local NewFromUnsigned(Isolate* isolate, uint64_t value); - /** - * Creates a new BigInt object using a specified sign bit and a - * specified list of digits/words. - * The resulting number is calculated as: - * - * (-1)^sign_bit * (words[0] * (2^64)^0 + words[1] * (2^64)^1 + ...) - */ - static MaybeLocal NewFromWords(Local context, int sign_bit, - int word_count, const uint64_t* words); - - /** - * Returns the value of this BigInt as an unsigned 64-bit integer. - * If `lossless` is provided, it will reflect whether the return value was - * truncated or wrapped around. In particular, it is set to `false` if this - * BigInt is negative. - */ - uint64_t Uint64Value(bool* lossless = nullptr) const; - - /** - * Returns the value of this BigInt as a signed 64-bit integer. - * If `lossless` is provided, it will reflect whether this BigInt was - * truncated or not. - */ - int64_t Int64Value(bool* lossless = nullptr) const; - - /** - * Returns the number of 64-bit words needed to store the result of - * ToWordsArray(). - */ - int WordCount() const; - - /** - * Writes the contents of this BigInt to a specified memory location. - * `sign_bit` must be provided and will be set to 1 if this BigInt is - * negative. - * `*word_count` has to be initialized to the length of the `words` array. - * Upon return, it will be set to the actual number of words that would - * be needed to store this BigInt (i.e. the return value of `WordCount()`). - */ - void ToWordsArray(int* sign_bit, int* word_count, uint64_t* words) const; - - V8_INLINE static BigInt* Cast(v8::Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return static_cast(data); - } - - private: - BigInt(); - static void CheckCast(v8::Data* that); -}; - -Local String::Empty(Isolate* isolate) { - using S = internal::Address; - using I = internal::Internals; - I::CheckInitialized(isolate); - S* slot = I::GetRoot(isolate, I::kEmptyStringRootIndex); - return Local(reinterpret_cast(slot)); -} - -String::ExternalStringResource* String::GetExternalStringResource() const { - using A = internal::Address; - using I = internal::Internals; - A obj = *reinterpret_cast(this); - - ExternalStringResource* result; - if (I::IsExternalTwoByteString(I::GetInstanceType(obj))) { - internal::Isolate* isolate = I::GetIsolateForSandbox(obj); - A value = - I::ReadExternalPointerField(isolate, obj, I::kStringResourceOffset, - internal::kExternalStringResourceTag); - result = reinterpret_cast(value); - } else { - result = GetExternalStringResourceSlow(); - } -#ifdef V8_ENABLE_CHECKS - VerifyExternalStringResource(result); -#endif - return result; -} - -String::ExternalStringResourceBase* String::GetExternalStringResourceBase( - String::Encoding* encoding_out) const { - using A = internal::Address; - using I = internal::Internals; - A obj = *reinterpret_cast(this); - int type = I::GetInstanceType(obj) & I::kStringRepresentationAndEncodingMask; - *encoding_out = static_cast(type & I::kStringEncodingMask); - ExternalStringResourceBase* resource; - if (type == I::kExternalOneByteRepresentationTag || - type == I::kExternalTwoByteRepresentationTag) { - internal::Isolate* isolate = I::GetIsolateForSandbox(obj); - A value = - I::ReadExternalPointerField(isolate, obj, I::kStringResourceOffset, - internal::kExternalStringResourceTag); - resource = reinterpret_cast(value); - } else { - resource = GetExternalStringResourceBaseSlow(encoding_out); - } -#ifdef V8_ENABLE_CHECKS - VerifyExternalStringResourceBase(resource, *encoding_out); -#endif - return resource; -} - -// --- Statics --- - -V8_INLINE Local Undefined(Isolate* isolate) { - using S = internal::Address; - using I = internal::Internals; - I::CheckInitialized(isolate); - S* slot = I::GetRoot(isolate, I::kUndefinedValueRootIndex); - return Local(reinterpret_cast(slot)); -} - -V8_INLINE Local Null(Isolate* isolate) { - using S = internal::Address; - using I = internal::Internals; - I::CheckInitialized(isolate); - S* slot = I::GetRoot(isolate, I::kNullValueRootIndex); - return Local(reinterpret_cast(slot)); -} - -V8_INLINE Local True(Isolate* isolate) { - using S = internal::Address; - using I = internal::Internals; - I::CheckInitialized(isolate); - S* slot = I::GetRoot(isolate, I::kTrueValueRootIndex); - return Local(reinterpret_cast(slot)); -} - -V8_INLINE Local False(Isolate* isolate) { - using S = internal::Address; - using I = internal::Internals; - I::CheckInitialized(isolate); - S* slot = I::GetRoot(isolate, I::kFalseValueRootIndex); - return Local(reinterpret_cast(slot)); -} - -Local Boolean::New(Isolate* isolate, bool value) { - return value ? True(isolate) : False(isolate); -} - -} // namespace v8 - -#endif // INCLUDE_V8_PRIMITIVE_H_ diff --git a/NativeScript/include/v8-profiler.h b/NativeScript/include/v8-profiler.h deleted file mode 100644 index 26810407..00000000 --- a/NativeScript/include/v8-profiler.h +++ /dev/null @@ -1,1198 +0,0 @@ -// Copyright 2010 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_V8_PROFILER_H_ -#define V8_V8_PROFILER_H_ - -#include - -#include -#include -#include - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-message.h" // NOLINT(build/include_directory) -#include "v8-persistent-handle.h" // NOLINT(build/include_directory) - -/** - * Profiler support for the V8 JavaScript engine. - */ -namespace v8 { - -enum class EmbedderStateTag : uint8_t; -class HeapGraphNode; -struct HeapStatsUpdate; -class Object; -enum StateTag : int; - -using NativeObject = void*; -using SnapshotObjectId = uint32_t; -using ProfilerId = uint32_t; - -struct CpuProfileDeoptFrame { - int script_id; - size_t position; -}; - -namespace internal { -class CpuProfile; -} // namespace internal - -} // namespace v8 - -#ifdef V8_OS_WIN -template class V8_EXPORT std::vector; -#endif - -namespace v8 { - -struct V8_EXPORT CpuProfileDeoptInfo { - /** A pointer to a static string owned by v8. */ - const char* deopt_reason; - std::vector stack; -}; - -} // namespace v8 - -#ifdef V8_OS_WIN -template class V8_EXPORT std::vector; -#endif - -namespace v8 { - -/** - * CpuProfileNode represents a node in a call graph. - */ -class V8_EXPORT CpuProfileNode { - public: - struct LineTick { - /** The 1-based number of the source line where the function originates. */ - int line; - - /** The count of samples associated with the source line. */ - unsigned int hit_count; - }; - - // An annotation hinting at the source of a CpuProfileNode. - enum SourceType { - // User-supplied script with associated resource information. - kScript = 0, - // Native scripts and provided builtins. - kBuiltin = 1, - // Callbacks into native code. - kCallback = 2, - // VM-internal functions or state. - kInternal = 3, - // A node that failed to symbolize. - kUnresolved = 4, - }; - - /** Returns function name (empty string for anonymous functions.) */ - Local GetFunctionName() const; - - /** - * Returns function name (empty string for anonymous functions.) - * The string ownership is *not* passed to the caller. It stays valid until - * profile is deleted. The function is thread safe. - */ - const char* GetFunctionNameStr() const; - - /** Returns id of the script where function is located. */ - int GetScriptId() const; - - /** Returns resource name for script from where the function originates. */ - Local GetScriptResourceName() const; - - /** - * Returns resource name for script from where the function originates. - * The string ownership is *not* passed to the caller. It stays valid until - * profile is deleted. The function is thread safe. - */ - const char* GetScriptResourceNameStr() const; - - /** - * Return true if the script from where the function originates is flagged as - * being shared cross-origin. - */ - bool IsScriptSharedCrossOrigin() const; - - /** - * Returns the number, 1-based, of the line where the function originates. - * kNoLineNumberInfo if no line number information is available. - */ - int GetLineNumber() const; - - /** - * Returns 1-based number of the column where the function originates. - * kNoColumnNumberInfo if no column number information is available. - */ - int GetColumnNumber() const; - - /** - * Returns the number of the function's source lines that collect the samples. - */ - unsigned int GetHitLineCount() const; - - /** Returns the set of source lines that collect the samples. - * The caller allocates buffer and responsible for releasing it. - * True if all available entries are copied, otherwise false. - * The function copies nothing if buffer is not large enough. - */ - bool GetLineTicks(LineTick* entries, unsigned int length) const; - - /** Returns bailout reason for the function - * if the optimization was disabled for it. - */ - const char* GetBailoutReason() const; - - /** - * Returns the count of samples where the function was currently executing. - */ - unsigned GetHitCount() const; - - /** Returns id of the node. The id is unique within the tree */ - unsigned GetNodeId() const; - - /** - * Gets the type of the source which the node was captured from. - */ - SourceType GetSourceType() const; - - /** Returns child nodes count of the node. */ - int GetChildrenCount() const; - - /** Retrieves a child node by index. */ - const CpuProfileNode* GetChild(int index) const; - - /** Retrieves the ancestor node, or null if the root. */ - const CpuProfileNode* GetParent() const; - - /** Retrieves deopt infos for the node. */ - const std::vector& GetDeoptInfos() const; - - static const int kNoLineNumberInfo = Message::kNoLineNumberInfo; - static const int kNoColumnNumberInfo = Message::kNoColumnInfo; -}; - - -/** - * CpuProfile contains a CPU profile in a form of top-down call tree - * (from main() down to functions that do all the work). - */ -class V8_EXPORT CpuProfile { - public: - /** Returns CPU profile title. */ - Local GetTitle() const; - - /** Returns the root node of the top down call tree. */ - const CpuProfileNode* GetTopDownRoot() const; - - /** - * Returns number of samples recorded. The samples are not recorded unless - * |record_samples| parameter of CpuProfiler::StartCpuProfiling is true. - */ - int GetSamplesCount() const; - - /** - * Returns profile node corresponding to the top frame the sample at - * the given index. - */ - const CpuProfileNode* GetSample(int index) const; - - /** - * Returns the timestamp of the sample. The timestamp is the number of - * microseconds since some unspecified starting point. - * The point is equal to the starting point used by GetStartTime. - */ - int64_t GetSampleTimestamp(int index) const; - - /** - * Returns time when the profile recording was started (in microseconds) - * since some unspecified starting point. - */ - int64_t GetStartTime() const; - - /** - * Returns state of the vm when sample was captured. - */ - StateTag GetSampleState(int index) const; - - /** - * Returns state of the embedder when sample was captured. - */ - EmbedderStateTag GetSampleEmbedderState(int index) const; - - /** - * Returns time when the profile recording was stopped (in microseconds) - * since some unspecified starting point. - * The point is equal to the starting point used by GetStartTime. - */ - int64_t GetEndTime() const; - - /** - * Deletes the profile and removes it from CpuProfiler's list. - * All pointers to nodes previously returned become invalid. - */ - void Delete(); -}; - -enum CpuProfilingMode { - // In the resulting CpuProfile tree, intermediate nodes in a stack trace - // (from the root to a leaf) will have line numbers that point to the start - // line of the function, rather than the line of the callsite of the child. - kLeafNodeLineNumbers, - // In the resulting CpuProfile tree, nodes are separated based on the line - // number of their callsite in their parent. - kCallerLineNumbers, -}; - -// Determines how names are derived for functions sampled. -enum CpuProfilingNamingMode { - // Use the immediate name of functions at compilation time. - kStandardNaming, - // Use more verbose naming for functions without names, inferred from scope - // where possible. - kDebugNaming, -}; - -enum CpuProfilingLoggingMode { - // Enables logging when a profile is active, and disables logging when all - // profiles are detached. - kLazyLogging, - // Enables logging for the lifetime of the CpuProfiler. Calls to - // StartRecording are faster, at the expense of runtime overhead. - kEagerLogging, -}; - -// Enum for returning profiling status. Once StartProfiling is called, -// we want to return to clients whether the profiling was able to start -// correctly, or return a descriptive error. -enum class CpuProfilingStatus { - kStarted, - kAlreadyStarted, - kErrorTooManyProfilers -}; - -/** - * Result from StartProfiling returning the Profiling Status, and - * id of the started profiler, or 0 if profiler is not started - */ -struct CpuProfilingResult { - const ProfilerId id; - const CpuProfilingStatus status; -}; - -/** - * Delegate for when max samples reached and samples are discarded. - */ -class V8_EXPORT DiscardedSamplesDelegate { - public: - DiscardedSamplesDelegate() = default; - - virtual ~DiscardedSamplesDelegate() = default; - virtual void Notify() = 0; - - ProfilerId GetId() const { return profiler_id_; } - - private: - friend internal::CpuProfile; - - void SetId(ProfilerId id) { profiler_id_ = id; } - - ProfilerId profiler_id_; -}; - -/** - * Optional profiling attributes. - */ -class V8_EXPORT CpuProfilingOptions { - public: - // Indicates that the sample buffer size should not be explicitly limited. - static const unsigned kNoSampleLimit = UINT_MAX; - - /** - * \param mode Type of computation of stack frame line numbers. - * \param max_samples The maximum number of samples that should be recorded by - * the profiler. Samples obtained after this limit will be - * discarded. - * \param sampling_interval_us controls the profile-specific target - * sampling interval. The provided sampling - * interval will be snapped to the next lowest - * non-zero multiple of the profiler's sampling - * interval, set via SetSamplingInterval(). If - * zero, the sampling interval will be equal to - * the profiler's sampling interval. - * \param filter_context If specified, profiles will only contain frames - * using this context. Other frames will be elided. - */ - CpuProfilingOptions( - CpuProfilingMode mode = kLeafNodeLineNumbers, - unsigned max_samples = kNoSampleLimit, int sampling_interval_us = 0, - MaybeLocal filter_context = MaybeLocal()); - - CpuProfilingMode mode() const { return mode_; } - unsigned max_samples() const { return max_samples_; } - int sampling_interval_us() const { return sampling_interval_us_; } - - private: - friend class internal::CpuProfile; - - bool has_filter_context() const { return !filter_context_.IsEmpty(); } - void* raw_filter_context() const; - - CpuProfilingMode mode_; - unsigned max_samples_; - int sampling_interval_us_; - CopyablePersistentTraits::CopyablePersistent filter_context_; -}; - -/** - * Interface for controlling CPU profiling. Instance of the - * profiler can be created using v8::CpuProfiler::New method. - */ -class V8_EXPORT CpuProfiler { - public: - /** - * Creates a new CPU profiler for the |isolate|. The isolate must be - * initialized. The profiler object must be disposed after use by calling - * |Dispose| method. - */ - static CpuProfiler* New(Isolate* isolate, - CpuProfilingNamingMode = kDebugNaming, - CpuProfilingLoggingMode = kLazyLogging); - - /** - * Synchronously collect current stack sample in all profilers attached to - * the |isolate|. The call does not affect number of ticks recorded for - * the current top node. - */ - static void CollectSample(Isolate* isolate); - - /** - * Disposes the CPU profiler object. - */ - void Dispose(); - - /** - * Changes default CPU profiler sampling interval to the specified number - * of microseconds. Default interval is 1000us. This method must be called - * when there are no profiles being recorded. - */ - void SetSamplingInterval(int us); - - /** - * Sets whether or not the profiler should prioritize consistency of sample - * periodicity on Windows. Disabling this can greatly reduce CPU usage, but - * may result in greater variance in sample timings from the platform's - * scheduler. Defaults to enabled. This method must be called when there are - * no profiles being recorded. - */ - void SetUsePreciseSampling(bool); - - /** - * Starts collecting a CPU profile. Several profiles may be collected at once. - * Generates an anonymous profiler, without a String identifier. - */ - CpuProfilingResult Start( - CpuProfilingOptions options, - std::unique_ptr delegate = nullptr); - - /** - * Starts collecting a CPU profile. Title may be an empty string. Several - * profiles may be collected at once. Attempts to start collecting several - * profiles with the same title are silently ignored. - */ - CpuProfilingResult Start( - Local title, CpuProfilingOptions options, - std::unique_ptr delegate = nullptr); - - /** - * Starts profiling with the same semantics as above, except with expanded - * parameters. - * - * |record_samples| parameter controls whether individual samples should - * be recorded in addition to the aggregated tree. - * - * |max_samples| controls the maximum number of samples that should be - * recorded by the profiler. Samples obtained after this limit will be - * discarded. - */ - CpuProfilingResult Start( - Local title, CpuProfilingMode mode, bool record_samples = false, - unsigned max_samples = CpuProfilingOptions::kNoSampleLimit); - - /** - * The same as StartProfiling above, but the CpuProfilingMode defaults to - * kLeafNodeLineNumbers mode, which was the previous default behavior of the - * profiler. - */ - CpuProfilingResult Start(Local title, bool record_samples = false); - - /** - * Starts collecting a CPU profile. Title may be an empty string. Several - * profiles may be collected at once. Attempts to start collecting several - * profiles with the same title are silently ignored. - */ - CpuProfilingStatus StartProfiling( - Local title, CpuProfilingOptions options, - std::unique_ptr delegate = nullptr); - - /** - * Starts profiling with the same semantics as above, except with expanded - * parameters. - * - * |record_samples| parameter controls whether individual samples should - * be recorded in addition to the aggregated tree. - * - * |max_samples| controls the maximum number of samples that should be - * recorded by the profiler. Samples obtained after this limit will be - * discarded. - */ - CpuProfilingStatus StartProfiling( - Local title, CpuProfilingMode mode, bool record_samples = false, - unsigned max_samples = CpuProfilingOptions::kNoSampleLimit); - - /** - * The same as StartProfiling above, but the CpuProfilingMode defaults to - * kLeafNodeLineNumbers mode, which was the previous default behavior of the - * profiler. - */ - CpuProfilingStatus StartProfiling(Local title, - bool record_samples = false); - - /** - * Stops collecting CPU profile with a given id and returns it. - */ - CpuProfile* Stop(ProfilerId id); - - /** - * Stops collecting CPU profile with a given title and returns it. - * If the title given is empty, finishes the last profile started. - */ - CpuProfile* StopProfiling(Local title); - - /** - * Generate more detailed source positions to code objects. This results in - * better results when mapping profiling samples to script source. - */ - static void UseDetailedSourcePositionsForProfiling(Isolate* isolate); - - private: - CpuProfiler(); - ~CpuProfiler(); - CpuProfiler(const CpuProfiler&); - CpuProfiler& operator=(const CpuProfiler&); -}; - -/** - * HeapSnapshotEdge represents a directed connection between heap - * graph nodes: from retainers to retained nodes. - */ -class V8_EXPORT HeapGraphEdge { - public: - enum Type { - kContextVariable = 0, // A variable from a function context. - kElement = 1, // An element of an array. - kProperty = 2, // A named object property. - kInternal = 3, // A link that can't be accessed from JS, - // thus, its name isn't a real property name - // (e.g. parts of a ConsString). - kHidden = 4, // A link that is needed for proper sizes - // calculation, but may be hidden from user. - kShortcut = 5, // A link that must not be followed during - // sizes calculation. - kWeak = 6 // A weak reference (ignored by the GC). - }; - - /** Returns edge type (see HeapGraphEdge::Type). */ - Type GetType() const; - - /** - * Returns edge name. This can be a variable name, an element index, or - * a property name. - */ - Local GetName() const; - - /** Returns origin node. */ - const HeapGraphNode* GetFromNode() const; - - /** Returns destination node. */ - const HeapGraphNode* GetToNode() const; -}; - - -/** - * HeapGraphNode represents a node in a heap graph. - */ -class V8_EXPORT HeapGraphNode { - public: - enum Type { - kHidden = 0, // Hidden node, may be filtered when shown to user. - kArray = 1, // An array of elements. - kString = 2, // A string. - kObject = 3, // A JS object (except for arrays and strings). - kCode = 4, // Compiled code. - kClosure = 5, // Function closure. - kRegExp = 6, // RegExp. - kHeapNumber = 7, // Number stored in the heap. - kNative = 8, // Native object (not from V8 heap). - kSynthetic = 9, // Synthetic object, usually used for grouping - // snapshot items together. - kConsString = 10, // Concatenated string. A pair of pointers to strings. - kSlicedString = 11, // Sliced string. A fragment of another string. - kSymbol = 12, // A Symbol (ES6). - kBigInt = 13 // BigInt. - }; - - /** Returns node type (see HeapGraphNode::Type). */ - Type GetType() const; - - /** - * Returns node name. Depending on node's type this can be the name - * of the constructor (for objects), the name of the function (for - * closures), string value, or an empty string (for compiled code). - */ - Local GetName() const; - - /** - * Returns node id. For the same heap object, the id remains the same - * across all snapshots. - */ - SnapshotObjectId GetId() const; - - /** Returns node's own size, in bytes. */ - size_t GetShallowSize() const; - - /** Returns child nodes count of the node. */ - int GetChildrenCount() const; - - /** Retrieves a child by index. */ - const HeapGraphEdge* GetChild(int index) const; -}; - - -/** - * An interface for exporting data from V8, using "push" model. - */ -class V8_EXPORT OutputStream { - public: - enum WriteResult { - kContinue = 0, - kAbort = 1 - }; - virtual ~OutputStream() = default; - /** Notify about the end of stream. */ - virtual void EndOfStream() = 0; - /** Get preferred output chunk size. Called only once. */ - virtual int GetChunkSize() { return 1024; } - /** - * Writes the next chunk of snapshot data into the stream. Writing - * can be stopped by returning kAbort as function result. EndOfStream - * will not be called in case writing was aborted. - */ - virtual WriteResult WriteAsciiChunk(char* data, int size) = 0; - /** - * Writes the next chunk of heap stats data into the stream. Writing - * can be stopped by returning kAbort as function result. EndOfStream - * will not be called in case writing was aborted. - */ - virtual WriteResult WriteHeapStatsChunk(HeapStatsUpdate* data, int count) { - return kAbort; - } -}; - -/** - * HeapSnapshots record the state of the JS heap at some moment. - */ -class V8_EXPORT HeapSnapshot { - public: - enum SerializationFormat { - kJSON = 0 // See format description near 'Serialize' method. - }; - - /** Returns the root node of the heap graph. */ - const HeapGraphNode* GetRoot() const; - - /** Returns a node by its id. */ - const HeapGraphNode* GetNodeById(SnapshotObjectId id) const; - - /** Returns total nodes count in the snapshot. */ - int GetNodesCount() const; - - /** Returns a node by index. */ - const HeapGraphNode* GetNode(int index) const; - - /** Returns a max seen JS object Id. */ - SnapshotObjectId GetMaxSnapshotJSObjectId() const; - - /** - * Deletes the snapshot and removes it from HeapProfiler's list. - * All pointers to nodes, edges and paths previously returned become - * invalid. - */ - void Delete(); - - /** - * Prepare a serialized representation of the snapshot. The result - * is written into the stream provided in chunks of specified size. - * The total length of the serialized snapshot is unknown in - * advance, it can be roughly equal to JS heap size (that means, - * it can be really big - tens of megabytes). - * - * For the JSON format, heap contents are represented as an object - * with the following structure: - * - * { - * snapshot: { - * title: "...", - * uid: nnn, - * meta: { meta-info }, - * node_count: nnn, - * edge_count: nnn - * }, - * nodes: [nodes array], - * edges: [edges array], - * strings: [strings array] - * } - * - * Nodes reference strings, other nodes, and edges by their indexes - * in corresponding arrays. - */ - void Serialize(OutputStream* stream, - SerializationFormat format = kJSON) const; -}; - - -/** - * An interface for reporting progress and controlling long-running - * activities. - */ -class V8_EXPORT ActivityControl { - public: - enum ControlOption { - kContinue = 0, - kAbort = 1 - }; - virtual ~ActivityControl() = default; - /** - * Notify about current progress. The activity can be stopped by - * returning kAbort as the callback result. - */ - virtual ControlOption ReportProgressValue(uint32_t done, uint32_t total) = 0; -}; - -/** - * AllocationProfile is a sampled profile of allocations done by the program. - * This is structured as a call-graph. - */ -class V8_EXPORT AllocationProfile { - public: - struct Allocation { - /** - * Size of the sampled allocation object. - */ - size_t size; - - /** - * The number of objects of such size that were sampled. - */ - unsigned int count; - }; - - /** - * Represents a node in the call-graph. - */ - struct Node { - /** - * Name of the function. May be empty for anonymous functions or if the - * script corresponding to this function has been unloaded. - */ - Local name; - - /** - * Name of the script containing the function. May be empty if the script - * name is not available, or if the script has been unloaded. - */ - Local script_name; - - /** - * id of the script where the function is located. May be equal to - * v8::UnboundScript::kNoScriptId in cases where the script doesn't exist. - */ - int script_id; - - /** - * Start position of the function in the script. - */ - int start_position; - - /** - * 1-indexed line number where the function starts. May be - * kNoLineNumberInfo if no line number information is available. - */ - int line_number; - - /** - * 1-indexed column number where the function starts. May be - * kNoColumnNumberInfo if no line number information is available. - */ - int column_number; - - /** - * Unique id of the node. - */ - uint32_t node_id; - - /** - * List of callees called from this node for which we have sampled - * allocations. The lifetime of the children is scoped to the containing - * AllocationProfile. - */ - std::vector children; - - /** - * List of self allocations done by this node in the call-graph. - */ - std::vector allocations; - }; - - /** - * Represent a single sample recorded for an allocation. - */ - struct Sample { - /** - * id of the node in the profile tree. - */ - uint32_t node_id; - - /** - * Size of the sampled allocation object. - */ - size_t size; - - /** - * The number of objects of such size that were sampled. - */ - unsigned int count; - - /** - * Unique time-ordered id of the allocation sample. Can be used to track - * what samples were added or removed between two snapshots. - */ - uint64_t sample_id; - }; - - /** - * Returns the root node of the call-graph. The root node corresponds to an - * empty JS call-stack. The lifetime of the returned Node* is scoped to the - * containing AllocationProfile. - */ - virtual Node* GetRootNode() = 0; - virtual const std::vector& GetSamples() = 0; - - virtual ~AllocationProfile() = default; - - static const int kNoLineNumberInfo = Message::kNoLineNumberInfo; - static const int kNoColumnNumberInfo = Message::kNoColumnInfo; -}; - -/** - * An object graph consisting of embedder objects and V8 objects. - * Edges of the graph are strong references between the objects. - * The embedder can build this graph during heap snapshot generation - * to include the embedder objects in the heap snapshot. - * Usage: - * 1) Define derived class of EmbedderGraph::Node for embedder objects. - * 2) Set the build embedder graph callback on the heap profiler using - * HeapProfiler::AddBuildEmbedderGraphCallback. - * 3) In the callback use graph->AddEdge(node1, node2) to add an edge from - * node1 to node2. - * 4) To represent references from/to V8 object, construct V8 nodes using - * graph->V8Node(value). - */ -class V8_EXPORT EmbedderGraph { - public: - class Node { - public: - /** - * Detachedness specifies whether an object is attached or detached from the - * main application state. While unkown in general, there may be objects - * that specifically know their state. V8 passes this information along in - * the snapshot. Users of the snapshot may use it to annotate the object - * graph. - */ - enum class Detachedness : uint8_t { - kUnknown = 0, - kAttached = 1, - kDetached = 2, - }; - - Node() = default; - virtual ~Node() = default; - virtual const char* Name() = 0; - virtual size_t SizeInBytes() = 0; - /** - * The corresponding V8 wrapper node if not null. - * During heap snapshot generation the embedder node and the V8 wrapper - * node will be merged into one node to simplify retaining paths. - */ - virtual Node* WrapperNode() { return nullptr; } - virtual bool IsRootNode() { return false; } - /** Must return true for non-V8 nodes. */ - virtual bool IsEmbedderNode() { return true; } - /** - * Optional name prefix. It is used in Chrome for tagging detached nodes. - */ - virtual const char* NamePrefix() { return nullptr; } - - /** - * Returns the NativeObject that can be used for querying the - * |HeapSnapshot|. - */ - virtual NativeObject GetNativeObject() { return nullptr; } - - /** - * Detachedness state of a given object. While unkown in general, there may - * be objects that specifically know their state. V8 passes this information - * along in the snapshot. Users of the snapshot may use it to annotate the - * object graph. - */ - virtual Detachedness GetDetachedness() { return Detachedness::kUnknown; } - - Node(const Node&) = delete; - Node& operator=(const Node&) = delete; - }; - - /** - * Returns a node corresponding to the given V8 value. Ownership is not - * transferred. The result pointer is valid while the graph is alive. - */ - virtual Node* V8Node(const v8::Local& value) = 0; - - /** - * Adds the given node to the graph and takes ownership of the node. - * Returns a raw pointer to the node that is valid while the graph is alive. - */ - virtual Node* AddNode(std::unique_ptr node) = 0; - - /** - * Adds an edge that represents a strong reference from the given - * node |from| to the given node |to|. The nodes must be added to the graph - * before calling this function. - * - * If name is nullptr, the edge will have auto-increment indexes, otherwise - * it will be named accordingly. - */ - virtual void AddEdge(Node* from, Node* to, const char* name = nullptr) = 0; - - virtual ~EmbedderGraph() = default; -}; - -/** - * Interface for controlling heap profiling. Instance of the - * profiler can be retrieved using v8::Isolate::GetHeapProfiler. - */ -class V8_EXPORT HeapProfiler { - public: - enum SamplingFlags { - kSamplingNoFlags = 0, - kSamplingForceGC = 1 << 0, - }; - - /** - * Callback function invoked during heap snapshot generation to retrieve - * the embedder object graph. The callback should use graph->AddEdge(..) to - * add references between the objects. - * The callback must not trigger garbage collection in V8. - */ - typedef void (*BuildEmbedderGraphCallback)(v8::Isolate* isolate, - v8::EmbedderGraph* graph, - void* data); - - /** - * Callback function invoked during heap snapshot generation to retrieve - * the detachedness state of an object referenced by a TracedReference. - * - * The callback takes Local as parameter to allow the embedder to - * unpack the TracedReference into a Local and reuse that Local for different - * purposes. - */ - using GetDetachednessCallback = EmbedderGraph::Node::Detachedness (*)( - v8::Isolate* isolate, const v8::Local& v8_value, - uint16_t class_id, void* data); - - /** Returns the number of snapshots taken. */ - int GetSnapshotCount(); - - /** Returns a snapshot by index. */ - const HeapSnapshot* GetHeapSnapshot(int index); - - /** - * Returns SnapshotObjectId for a heap object referenced by |value| if - * it has been seen by the heap profiler, kUnknownObjectId otherwise. - */ - SnapshotObjectId GetObjectId(Local value); - - /** - * Returns SnapshotObjectId for a native object referenced by |value| if it - * has been seen by the heap profiler, kUnknownObjectId otherwise. - */ - SnapshotObjectId GetObjectId(NativeObject value); - - /** - * Returns heap object with given SnapshotObjectId if the object is alive, - * otherwise empty handle is returned. - */ - Local FindObjectById(SnapshotObjectId id); - - /** - * Clears internal map from SnapshotObjectId to heap object. The new objects - * will not be added into it unless a heap snapshot is taken or heap object - * tracking is kicked off. - */ - void ClearObjectIds(); - - /** - * A constant for invalid SnapshotObjectId. GetSnapshotObjectId will return - * it in case heap profiler cannot find id for the object passed as - * parameter. HeapSnapshot::GetNodeById will always return NULL for such id. - */ - static const SnapshotObjectId kUnknownObjectId = 0; - - /** - * Callback interface for retrieving user friendly names of global objects. - */ - class ObjectNameResolver { - public: - /** - * Returns name to be used in the heap snapshot for given node. Returned - * string must stay alive until snapshot collection is completed. - */ - virtual const char* GetName(Local object) = 0; - - protected: - virtual ~ObjectNameResolver() = default; - }; - - /** - * Takes a heap snapshot and returns it. - */ - const HeapSnapshot* TakeHeapSnapshot( - ActivityControl* control = nullptr, - ObjectNameResolver* global_object_name_resolver = nullptr, - bool treat_global_objects_as_roots = true, - bool capture_numeric_value = false); - - /** - * Starts tracking of heap objects population statistics. After calling - * this method, all heap objects relocations done by the garbage collector - * are being registered. - * - * |track_allocations| parameter controls whether stack trace of each - * allocation in the heap will be recorded and reported as part of - * HeapSnapshot. - */ - void StartTrackingHeapObjects(bool track_allocations = false); - - /** - * Adds a new time interval entry to the aggregated statistics array. The - * time interval entry contains information on the current heap objects - * population size. The method also updates aggregated statistics and - * reports updates for all previous time intervals via the OutputStream - * object. Updates on each time interval are provided as a stream of the - * HeapStatsUpdate structure instances. - * If |timestamp_us| is supplied, timestamp of the new entry will be written - * into it. The return value of the function is the last seen heap object Id. - * - * StartTrackingHeapObjects must be called before the first call to this - * method. - */ - SnapshotObjectId GetHeapStats(OutputStream* stream, - int64_t* timestamp_us = nullptr); - - /** - * Stops tracking of heap objects population statistics, cleans up all - * collected data. StartHeapObjectsTracking must be called again prior to - * calling GetHeapStats next time. - */ - void StopTrackingHeapObjects(); - - /** - * Starts gathering a sampling heap profile. A sampling heap profile is - * similar to tcmalloc's heap profiler and Go's mprof. It samples object - * allocations and builds an online 'sampling' heap profile. At any point in - * time, this profile is expected to be a representative sample of objects - * currently live in the system. Each sampled allocation includes the stack - * trace at the time of allocation, which makes this really useful for memory - * leak detection. - * - * This mechanism is intended to be cheap enough that it can be used in - * production with minimal performance overhead. - * - * Allocations are sampled using a randomized Poisson process. On average, one - * allocation will be sampled every |sample_interval| bytes allocated. The - * |stack_depth| parameter controls the maximum number of stack frames to be - * captured on each allocation. - * - * NOTE: This is a proof-of-concept at this point. Right now we only sample - * newspace allocations. Support for paged space allocation (e.g. pre-tenured - * objects, large objects, code objects, etc.) and native allocations - * doesn't exist yet, but is anticipated in the future. - * - * Objects allocated before the sampling is started will not be included in - * the profile. - * - * Returns false if a sampling heap profiler is already running. - */ - bool StartSamplingHeapProfiler(uint64_t sample_interval = 512 * 1024, - int stack_depth = 16, - SamplingFlags flags = kSamplingNoFlags); - - /** - * Stops the sampling heap profile and discards the current profile. - */ - void StopSamplingHeapProfiler(); - - /** - * Returns the sampled profile of allocations allocated (and still live) since - * StartSamplingHeapProfiler was called. The ownership of the pointer is - * transferred to the caller. Returns nullptr if sampling heap profiler is not - * active. - */ - AllocationProfile* GetAllocationProfile(); - - /** - * Deletes all snapshots taken. All previously returned pointers to - * snapshots and their contents become invalid after this call. - */ - void DeleteAllHeapSnapshots(); - - void AddBuildEmbedderGraphCallback(BuildEmbedderGraphCallback callback, - void* data); - void RemoveBuildEmbedderGraphCallback(BuildEmbedderGraphCallback callback, - void* data); - - void SetGetDetachednessCallback(GetDetachednessCallback callback, void* data); - - /** - * Default value of persistent handle class ID. Must not be used to - * define a class. Can be used to reset a class of a persistent - * handle. - */ - static const uint16_t kPersistentHandleNoClassId = 0; - - private: - HeapProfiler(); - ~HeapProfiler(); - HeapProfiler(const HeapProfiler&); - HeapProfiler& operator=(const HeapProfiler&); -}; - -/** - * A struct for exporting HeapStats data from V8, using "push" model. - * See HeapProfiler::GetHeapStats. - */ -struct HeapStatsUpdate { - HeapStatsUpdate(uint32_t index, uint32_t count, uint32_t size) - : index(index), count(count), size(size) { } - uint32_t index; // Index of the time interval that was changed. - uint32_t count; // New value of count field for the interval with this index. - uint32_t size; // New value of size field for the interval with this index. -}; - -#define CODE_EVENTS_LIST(V) \ - V(Builtin) \ - V(Callback) \ - V(Eval) \ - V(Function) \ - V(InterpretedFunction) \ - V(Handler) \ - V(BytecodeHandler) \ - V(LazyCompile) \ - V(RegExp) \ - V(Script) \ - V(Stub) \ - V(Relocation) - -/** - * Note that this enum may be extended in the future. Please include a default - * case if this enum is used in a switch statement. - */ -enum CodeEventType { - kUnknownType = 0 -#define V(Name) , k##Name##Type - CODE_EVENTS_LIST(V) -#undef V -}; - -/** - * Representation of a code creation event - */ -class V8_EXPORT CodeEvent { - public: - uintptr_t GetCodeStartAddress(); - size_t GetCodeSize(); - Local GetFunctionName(); - Local GetScriptName(); - int GetScriptLine(); - int GetScriptColumn(); - /** - * NOTE (mmarchini): We can't allocate objects in the heap when we collect - * existing code, and both the code type and the comment are not stored in the - * heap, so we return those as const char*. - */ - CodeEventType GetCodeType(); - const char* GetComment(); - - static const char* GetCodeEventTypeName(CodeEventType code_event_type); - - uintptr_t GetPreviousCodeStartAddress(); -}; - -/** - * Interface to listen to code creation and code relocation events. - */ -class V8_EXPORT CodeEventHandler { - public: - /** - * Creates a new listener for the |isolate|. The isolate must be initialized. - * The listener object must be disposed after use by calling |Dispose| method. - * Multiple listeners can be created for the same isolate. - */ - explicit CodeEventHandler(Isolate* isolate); - virtual ~CodeEventHandler(); - - /** - * Handle is called every time a code object is created or moved. Information - * about each code event will be available through the `code_event` - * parameter. - * - * When the CodeEventType is kRelocationType, the code for this CodeEvent has - * moved from `GetPreviousCodeStartAddress()` to `GetCodeStartAddress()`. - */ - virtual void Handle(CodeEvent* code_event) = 0; - - /** - * Call `Enable()` to starts listening to code creation and code relocation - * events. These events will be handled by `Handle()`. - */ - void Enable(); - - /** - * Call `Disable()` to stop listening to code creation and code relocation - * events. - */ - void Disable(); - - private: - CodeEventHandler(); - CodeEventHandler(const CodeEventHandler&); - CodeEventHandler& operator=(const CodeEventHandler&); - void* internal_listener_; -}; - -} // namespace v8 - - -#endif // V8_V8_PROFILER_H_ diff --git a/NativeScript/include/v8-promise.h b/NativeScript/include/v8-promise.h deleted file mode 100644 index 9da8e4b4..00000000 --- a/NativeScript/include/v8-promise.h +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_PROMISE_H_ -#define INCLUDE_V8_PROMISE_H_ - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-object.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; - -#ifndef V8_PROMISE_INTERNAL_FIELD_COUNT -// The number of required internal fields can be defined by embedder. -#define V8_PROMISE_INTERNAL_FIELD_COUNT 0 -#endif - -/** - * An instance of the built-in Promise constructor (ES6 draft). - */ -class V8_EXPORT Promise : public Object { - public: - /** - * State of the promise. Each value corresponds to one of the possible values - * of the [[PromiseState]] field. - */ - enum PromiseState { kPending, kFulfilled, kRejected }; - - class V8_EXPORT Resolver : public Object { - public: - /** - * Create a new resolver, along with an associated promise in pending state. - */ - static V8_WARN_UNUSED_RESULT MaybeLocal New( - Local context); - - /** - * Extract the associated promise. - */ - Local GetPromise(); - - /** - * Resolve/reject the associated promise with a given value. - * Ignored if the promise is no longer pending. - */ - V8_WARN_UNUSED_RESULT Maybe Resolve(Local context, - Local value); - - V8_WARN_UNUSED_RESULT Maybe Reject(Local context, - Local value); - - V8_INLINE static Resolver* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - Resolver(); - static void CheckCast(Value* obj); - }; - - /** - * Register a resolution/rejection handler with a promise. - * The handler is given the respective resolution/rejection value as - * an argument. If the promise is already resolved/rejected, the handler is - * invoked at the end of turn. - */ - V8_WARN_UNUSED_RESULT MaybeLocal Catch(Local context, - Local handler); - - V8_WARN_UNUSED_RESULT MaybeLocal Then(Local context, - Local handler); - - V8_WARN_UNUSED_RESULT MaybeLocal Then(Local context, - Local on_fulfilled, - Local on_rejected); - - /** - * Returns true if the promise has at least one derived promise, and - * therefore resolve/reject handlers (including default handler). - */ - bool HasHandler() const; - - /** - * Returns the content of the [[PromiseResult]] field. The Promise must not - * be pending. - */ - Local Result(); - - /** - * Returns the value of the [[PromiseState]] field. - */ - PromiseState State(); - - /** - * Marks this promise as handled to avoid reporting unhandled rejections. - */ - void MarkAsHandled(); - - /** - * Marks this promise as silent to prevent pausing the debugger when the - * promise is rejected. - */ - void MarkAsSilent(); - - V8_INLINE static Promise* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - static const int kEmbedderFieldCount = V8_PROMISE_INTERNAL_FIELD_COUNT; - - private: - Promise(); - static void CheckCast(Value* obj); -}; - -/** - * PromiseHook with type kInit is called when a new promise is - * created. When a new promise is created as part of the chain in the - * case of Promise.then or in the intermediate promises created by - * Promise.{race, all}/AsyncFunctionAwait, we pass the parent promise - * otherwise we pass undefined. - * - * PromiseHook with type kResolve is called at the beginning of - * resolve or reject function defined by CreateResolvingFunctions. - * - * PromiseHook with type kBefore is called at the beginning of the - * PromiseReactionJob. - * - * PromiseHook with type kAfter is called right at the end of the - * PromiseReactionJob. - */ -enum class PromiseHookType { kInit, kResolve, kBefore, kAfter }; - -using PromiseHook = void (*)(PromiseHookType type, Local promise, - Local parent); - -// --- Promise Reject Callback --- -enum PromiseRejectEvent { - kPromiseRejectWithNoHandler = 0, - kPromiseHandlerAddedAfterReject = 1, - kPromiseRejectAfterResolved = 2, - kPromiseResolveAfterResolved = 3, -}; - -class PromiseRejectMessage { - public: - PromiseRejectMessage(Local promise, PromiseRejectEvent event, - Local value) - : promise_(promise), event_(event), value_(value) {} - - V8_INLINE Local GetPromise() const { return promise_; } - V8_INLINE PromiseRejectEvent GetEvent() const { return event_; } - V8_INLINE Local GetValue() const { return value_; } - - private: - Local promise_; - PromiseRejectEvent event_; - Local value_; -}; - -using PromiseRejectCallback = void (*)(PromiseRejectMessage message); - -} // namespace v8 - -#endif // INCLUDE_V8_PROMISE_H_ diff --git a/NativeScript/include/v8-proxy.h b/NativeScript/include/v8-proxy.h deleted file mode 100644 index a08db880..00000000 --- a/NativeScript/include/v8-proxy.h +++ /dev/null @@ -1,50 +0,0 @@ - -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_PROXY_H_ -#define INCLUDE_V8_PROXY_H_ - -#include "v8-context.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-object.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; - -/** - * An instance of the built-in Proxy constructor (ECMA-262, 6th Edition, - * 26.2.1). - */ -class V8_EXPORT Proxy : public Object { - public: - Local GetTarget(); - Local GetHandler(); - bool IsRevoked() const; - void Revoke(); - - /** - * Creates a new Proxy for the target object. - */ - static MaybeLocal New(Local context, - Local local_target, - Local local_handler); - - V8_INLINE static Proxy* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - Proxy(); - static void CheckCast(Value* obj); -}; - -} // namespace v8 - -#endif // INCLUDE_V8_PROXY_H_ diff --git a/NativeScript/include/v8-regexp.h b/NativeScript/include/v8-regexp.h deleted file mode 100644 index 3791bc03..00000000 --- a/NativeScript/include/v8-regexp.h +++ /dev/null @@ -1,105 +0,0 @@ - -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_REGEXP_H_ -#define INCLUDE_V8_REGEXP_H_ - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-object.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; - -/** - * An instance of the built-in RegExp constructor (ECMA-262, 15.10). - */ -class V8_EXPORT RegExp : public Object { - public: - /** - * Regular expression flag bits. They can be or'ed to enable a set - * of flags. - * The kLinear value ('l') is experimental and can only be used with - * --enable-experimental-regexp-engine. RegExps with kLinear flag are - * guaranteed to be executed in asymptotic linear time wrt. the length of - * the subject string. - */ - enum Flags { - kNone = 0, - kGlobal = 1 << 0, - kIgnoreCase = 1 << 1, - kMultiline = 1 << 2, - kSticky = 1 << 3, - kUnicode = 1 << 4, - kDotAll = 1 << 5, - kLinear = 1 << 6, - kHasIndices = 1 << 7, - }; - - static constexpr int kFlagCount = 8; - - /** - * Creates a regular expression from the given pattern string and - * the flags bit field. May throw a JavaScript exception as - * described in ECMA-262, 15.10.4.1. - * - * For example, - * RegExp::New(v8::String::New("foo"), - * static_cast(kGlobal | kMultiline)) - * is equivalent to evaluating "/foo/gm". - */ - static V8_WARN_UNUSED_RESULT MaybeLocal New(Local context, - Local pattern, - Flags flags); - - /** - * Like New, but additionally specifies a backtrack limit. If the number of - * backtracks done in one Exec call hits the limit, a match failure is - * immediately returned. - */ - static V8_WARN_UNUSED_RESULT MaybeLocal NewWithBacktrackLimit( - Local context, Local pattern, Flags flags, - uint32_t backtrack_limit); - - /** - * Executes the current RegExp instance on the given subject string. - * Equivalent to RegExp.prototype.exec as described in - * - * https://tc39.es/ecma262/#sec-regexp.prototype.exec - * - * On success, an Array containing the matched strings is returned. On - * failure, returns Null. - * - * Note: modifies global context state, accessible e.g. through RegExp.input. - */ - V8_WARN_UNUSED_RESULT MaybeLocal Exec(Local context, - Local subject); - - /** - * Returns the value of the source property: a string representing - * the regular expression. - */ - Local GetSource() const; - - /** - * Returns the flags bit field. - */ - Flags GetFlags() const; - - V8_INLINE static RegExp* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - static void CheckCast(Value* obj); -}; - -} // namespace v8 - -#endif // INCLUDE_V8_REGEXP_H_ diff --git a/NativeScript/include/v8-script.h b/NativeScript/include/v8-script.h deleted file mode 100644 index 88252ac1..00000000 --- a/NativeScript/include/v8-script.h +++ /dev/null @@ -1,748 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_SCRIPT_H_ -#define INCLUDE_V8_SCRIPT_H_ - -#include -#include - -#include -#include - -#include "v8-data.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-maybe.h" // NOLINT(build/include_directory) -#include "v8-message.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Function; -class Object; -class PrimitiveArray; -class Script; - -namespace internal { -class BackgroundDeserializeTask; -struct ScriptStreamingData; -} // namespace internal - -/** - * A container type that holds relevant metadata for module loading. - * - * This is passed back to the embedder as part of - * HostImportModuleDynamicallyCallback for module loading. - */ -class V8_EXPORT ScriptOrModule { - public: - /** - * The name that was passed by the embedder as ResourceName to the - * ScriptOrigin. This can be either a v8::String or v8::Undefined. - */ - Local GetResourceName(); - - /** - * The options that were passed by the embedder as HostDefinedOptions to - * the ScriptOrigin. - */ - V8_DEPRECATED("Use HostDefinedOptions") - Local GetHostDefinedOptions(); - Local HostDefinedOptions(); -}; - -/** - * A compiled JavaScript script, not yet tied to a Context. - */ -class V8_EXPORT UnboundScript { - public: - /** - * Binds the script to the currently entered context. - */ - Local