diff --git a/.cargo/config.toml b/.cargo/config.toml index 549ae022..35049cbc 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,6 +1,2 @@ [alias] xtask = "run --package xtask --" - -[env] -# See: https://github.com/rust-lang/cargo/issues/3946#issuecomment-973132993 -CARGO_WORKSPACE_DIR = { value = "", relative = true } diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 1466f049..c75a67e6 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,6 +4,8 @@ updates: directory: "/" schedule: interval: "weekly" + cooldown: + default-days: 3 commit-message: prefix: "build(deps)" labels: @@ -12,10 +14,16 @@ updates: groups: cargo: patterns: ["*"] + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major", "version-update:semver-minor"] + - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" + cooldown: + default-days: 3 commit-message: prefix: "ci" labels: @@ -24,13 +32,17 @@ updates: groups: actions: patterns: ["*"] + - package-ecosystem: "npm" + versioning-strategy: increase directories: - "/crates/npm" - "/crates/eslint" - "/lib/binding_web" schedule: interval: "weekly" + cooldown: + default-days: 3 commit-message: prefix: "build(deps)" labels: diff --git a/.github/scripts/wasm_stdlib.js b/.github/scripts/wasm_stdlib.js new file mode 100644 index 00000000..e1350094 --- /dev/null +++ b/.github/scripts/wasm_stdlib.js @@ -0,0 +1,25 @@ +module.exports = async ({ github, context, core }) => { + if (context.eventName !== 'pull_request') return; + + const prNumber = context.payload.pull_request.number; + const owner = context.repo.owner; + const repo = context.repo.repo; + + const { data: files } = await github.rest.pulls.listFiles({ + owner, + repo, + pull_number: prNumber + }); + + const changedFiles = files.map(file => file.filename); + + const wasmStdLibSrc = 'crates/language/wasm/'; + const dirChanged = changedFiles.some(file => file.startsWith(wasmStdLibSrc)); + + if (!dirChanged) return; + + const wasmStdLibHeader = 'lib/src/wasm/wasm-stdlib.h'; + const requiredChanged = changedFiles.includes(wasmStdLibHeader); + + if (!requiredChanged) core.setFailed(`Changes detected in ${wasmStdLibSrc} but ${wasmStdLibHeader} was not modified.`); +}; diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 83992a3f..7caffa14 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Create app token uses: actions/create-github-app-token@v2 @@ -24,7 +24,7 @@ jobs: private-key: ${{ secrets.BACKPORT_KEY }} - name: Create backport PR - uses: korthout/backport-action@v3 + uses: korthout/backport-action@v4 with: pull_title: "${pull_title}" label_pattern: "^ci:backport ([^ ]+)$" diff --git a/.github/workflows/bindgen.yml b/.github/workflows/bindgen.yml index deee3757..1b0d20af 100644 --- a/.github/workflows/bindgen.yml +++ b/.github/workflows/bindgen.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up stable Rust toolchain uses: actions-rust-lang/setup-rust-toolchain@v1 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 62b45485..5cde3db9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -41,7 +41,7 @@ jobs: - { platform: windows-x64 , target: x86_64-pc-windows-msvc , os: windows-2025 } - { platform: windows-x86 , target: i686-pc-windows-msvc , os: windows-2025 } - { platform: macos-arm64 , target: aarch64-apple-darwin , os: macos-15 } - - { platform: macos-x64 , target: x86_64-apple-darwin , os: macos-13 } + - { platform: macos-x64 , target: x86_64-apple-darwin , os: macos-15-intel } - { platform: wasm32 , target: wasm32-unknown-unknown , os: ubuntu-24.04 } # Extra features @@ -68,27 +68,25 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - - name: Set up environment + - name: Set up cross-compilation + if: matrix.cross run: | - printf 'EMSCRIPTEN_VERSION=%s\n' "$(> $GITHUB_ENV + for target in armv7-unknown-linux-gnueabihf i686-unknown-linux-gnu powerpc64-unknown-linux-gnu; do + camel_target=${target//-/_}; target_cc=${target/-unknown/} + printf 'CC_%s=%s\n' "$camel_target" "${target_cc/v7/}-gcc" + printf 'AR_%s=%s\n' "$camel_target" "${target_cc/v7/}-ar" + printf 'CARGO_TARGET_%s_LINKER=%s\n' "${camel_target^^}" "${target_cc/v7/}-gcc" + done >> $GITHUB_ENV + { + printf 'CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm -L /usr/arm-linux-gnueabihf\n' + printf 'CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64 -L /usr/powerpc64-linux-gnu\n' + } >> $GITHUB_ENV - if [[ '${{ matrix.platform }}' =~ ^windows ]]; then - # Prevent race condition (see #2041) - printf 'RUST_TEST_THREADS=1\n' >> $GITHUB_ENV - elif [[ '${{ matrix.cross }}' == true ]]; then - for target in armv7-unknown-linux-gnueabihf i686-unknown-linux-gnu powerpc64-unknown-linux-gnu; do - camel_target=${target//-/_}; target_cc=${target/-unknown/} - printf 'CC_%s=%s\n' "$camel_target" "${target_cc/v7/}-gcc" - printf 'AR_%s=%s\n' "$camel_target" "${target_cc/v7/}-ar" - printf 'CARGO_TARGET_%s_LINKER=%s\n' "${camel_target^^}" "${target_cc/v7/}-gcc" - done >> $GITHUB_ENV - { - printf 'CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm -L /usr/arm-linux-gnueabihf\n' - printf 'CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64 -L /usr/powerpc64-linux-gnu\n' - } >> $GITHUB_ENV - fi + - name: Get emscripten version + if: contains(matrix.features, 'wasm') + run: printf 'EMSCRIPTEN_VERSION=%s\n' "$(> $GITHUB_ENV - name: Install Emscripten if: contains(matrix.features, 'wasm') @@ -280,7 +278,7 @@ jobs: - name: Upload CLI artifact if: "!matrix.no-run" - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: tree-sitter.${{ matrix.platform }} path: target/${{ matrix.target }}/release/tree-sitter${{ contains(matrix.target, 'windows') && '.exe' || '' }} @@ -289,7 +287,7 @@ jobs: - name: Upload Wasm artifacts if: matrix.platform == 'linux-x64' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: tree-sitter.wasm path: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f10394b2..a60c93f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up stable Rust toolchain uses: actions-rust-lang/setup-rust-toolchain@v1 @@ -44,3 +44,6 @@ jobs: build: uses: ./.github/workflows/build.yml + + check-wasm-stdlib: + uses: ./.github/workflows/wasm_stdlib.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 30fe914e..0e4baebf 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -3,6 +3,7 @@ on: push: branches: [master] paths: [docs/**] + workflow_dispatch: jobs: deploy-docs: @@ -15,7 +16,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up Rust uses: actions-rust-lang/setup-rust-toolchain@v1 @@ -25,7 +26,7 @@ jobs: GH_TOKEN: ${{ github.token }} run: | jq_expr='.assets[] | select(.name | contains("x86_64-unknown-linux-gnu")) | .browser_download_url' - url=$(gh api repos/rust-lang/mdbook/releases/latest --jq "$jq_expr") + url=$(gh api repos/rust-lang/mdbook/releases/tags/v0.4.52 --jq "$jq_expr") mkdir mdbook curl -sSL "$url" | tar -xz -C mdbook printf '%s/mdbook\n' "$PWD" >> "$GITHUB_PATH" diff --git a/.github/workflows/nvim_ts.yml b/.github/workflows/nvim_ts.yml index 9dea5304..88e3371f 100644 --- a/.github/workflows/nvim_ts.yml +++ b/.github/workflows/nvim_ts.yml @@ -28,9 +28,9 @@ jobs: NVIM: ${{ matrix.os == 'windows-latest' && 'nvim-win64\\bin\\nvim.exe' || 'nvim' }} NVIM_TS_DIR: nvim-treesitter steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: repository: nvim-treesitter/nvim-treesitter path: ${{ env.NVIM_TS_DIR }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 803a69ec..4f6f9d47 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,13 +17,15 @@ jobs: runs-on: ubuntu-latest needs: build permissions: + id-token: write + attestations: write contents: write steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Download build artifacts - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v7 with: path: artifacts @@ -47,9 +49,16 @@ jobs: rm -rf artifacts ls -l target/ + - name: Generate attestations + uses: actions/attest-build-provenance@v3 + with: + subject-path: | + target/tree-sitter-*.gz + target/web-tree-sitter.tar.gz + - name: Create release run: |- - gh release create ${{ github.ref_name }} \ + gh release create $GITHUB_REF_NAME \ target/tree-sitter-*.gz \ target/web-tree-sitter.tar.gz env: @@ -58,35 +67,47 @@ jobs: crates_io: name: Publish packages to Crates.io runs-on: ubuntu-latest + environment: crates + permissions: + id-token: write + contents: read needs: release steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up Rust uses: actions-rust-lang/setup-rust-toolchain@v1 + - name: Set up registry token + id: auth + uses: rust-lang/crates-io-auth-action@v1 + - name: Publish crates to Crates.io uses: katyo/publish-crates@v2 with: - registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }} + registry-token: ${{ steps.auth.outputs.token }} npm: name: Publish packages to npmjs.com runs-on: ubuntu-latest + environment: npm + permissions: + id-token: write + contents: read needs: release strategy: fail-fast: false matrix: - directory: [cli/npm, lib/binding_web] + directory: [crates/cli/npm, lib/binding_web] steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up Node - uses: actions/setup-node@v5 + uses: actions/setup-node@v6 with: - node-version: 20 + node-version: 24 registry-url: https://registry.npmjs.org - name: Set up Rust @@ -106,5 +127,3 @@ jobs: - name: Publish to npmjs.com working-directory: ${{ matrix.directory }} run: npm publish - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/response.yml b/.github/workflows/response.yml index 31e039c8..54dd2021 100644 --- a/.github/workflows/response.yml +++ b/.github/workflows/response.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout script - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: sparse-checkout: .github/scripts/close_unresponsive.js sparse-checkout-cone-mode: false @@ -35,7 +35,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout script - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: sparse-checkout: .github/scripts/remove_response_label.js sparse-checkout-cone-mode: false diff --git a/.github/workflows/reviewers_remove.yml b/.github/workflows/reviewers_remove.yml index 94e8c058..3a389ed4 100644 --- a/.github/workflows/reviewers_remove.yml +++ b/.github/workflows/reviewers_remove.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout script - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: sparse-checkout: .github/scripts/reviewers_remove.js sparse-checkout-cone-mode: false diff --git a/.github/workflows/sanitize.yml b/.github/workflows/sanitize.yml index 2239c673..2f8851dc 100644 --- a/.github/workflows/sanitize.yml +++ b/.github/workflows/sanitize.yml @@ -15,7 +15,7 @@ jobs: TREE_SITTER: ${{ github.workspace }}/target/release/tree-sitter steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Install UBSAN library run: sudo apt-get update -y && sudo apt-get install -y libubsan1 diff --git a/.github/workflows/spam.yml b/.github/workflows/spam.yml index ce3d5e1d..eb1d4a46 100644 --- a/.github/workflows/spam.yml +++ b/.github/workflows/spam.yml @@ -16,7 +16,7 @@ jobs: if: github.event.label.name == 'spam' steps: - name: Checkout script - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: sparse-checkout: .github/scripts/close_spam.js sparse-checkout-cone-mode: false diff --git a/.github/workflows/wasm_exports.yml b/.github/workflows/wasm_exports.yml index d04e1052..af48cf8a 100644 --- a/.github/workflows/wasm_exports.yml +++ b/.github/workflows/wasm_exports.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up stable Rust toolchain uses: actions-rust-lang/setup-rust-toolchain@v1 diff --git a/.github/workflows/wasm_stdlib.yml b/.github/workflows/wasm_stdlib.yml new file mode 100644 index 00000000..adec8411 --- /dev/null +++ b/.github/workflows/wasm_stdlib.yml @@ -0,0 +1,19 @@ +name: Check Wasm Stdlib build + +on: + workflow_call: + +jobs: + check: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Check directory changes + uses: actions/github-script@v8 + with: + script: | + const scriptPath = `${process.env.GITHUB_WORKSPACE}/.github/scripts/wasm_stdlib.js`; + const script = require(scriptPath); + return script({ github, context, core }); diff --git a/CMakeLists.txt b/CMakeLists.txt index bc8bf049..f11895c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.13) project(tree-sitter - VERSION "0.26.0" + VERSION "0.27.0" DESCRIPTION "An incremental parsing system for programming tools" HOMEPAGE_URL "https://tree-sitter.github.io/tree-sitter/" LANGUAGES C) @@ -81,7 +81,7 @@ set_target_properties(tree-sitter SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}" DEFINE_SYMBOL "") -target_compile_definitions(tree-sitter PRIVATE _POSIX_C_SOURCE=200112L _DEFAULT_SOURCE) +target_compile_definitions(tree-sitter PRIVATE _POSIX_C_SOURCE=200112L _DEFAULT_SOURCE _BSD_SOURCE _DARWIN_C_SOURCE) include(GNUInstallDirs) diff --git a/Cargo.lock b/Cargo.lock index 63d88dcf..ae7803c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -37,9 +37,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.20" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -52,9 +52,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" @@ -67,29 +67,38 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.10" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "anyhow" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "ar_archive_writer" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c269894b6fe5e9d7ada0cf69b5bf847ff35bc25fc271f08e1d080fce80339a" +dependencies = [ + "object 0.32.2", +] [[package]] name = "arbitrary" @@ -103,36 +112,13 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" -[[package]] -name = "bindgen" -version = "0.69.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" -dependencies = [ - "bitflags 2.9.4", - "cexpr", - "clang-sys", - "itertools 0.12.1", - "lazy_static", - "lazycell", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash 1.1.0", - "shlex", - "syn", - "which", -] - [[package]] name = "bindgen" version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cexpr", "clang-sys", "itertools 0.13.0", @@ -141,7 +127,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash 2.1.1", + "rustc-hash", "shlex", "syn", ] @@ -154,15 +140,24 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] [[package]] name = "bstr" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" dependencies = [ "memchr", "regex-automata", @@ -171,30 +166,30 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" dependencies = [ "allocator-api2", ] [[package]] name = "bytemuck" -version = "1.23.2" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "cc" -version = "1.2.37" +version = "1.2.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65193589c6404eb80b450d618eaf9a2cafaaafd57ecce47370519ef674a7bd44" +checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932" dependencies = [ "find-msvc-tools", "shlex", @@ -217,9 +212,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -241,14 +236,14 @@ checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", - "libloading", + "libloading 0.8.9", ] [[package]] name = "clap" -version = "4.5.47" +version = "4.5.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931" +checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" dependencies = [ "clap_builder", "clap_derive", @@ -256,9 +251,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.47" +version = "4.5.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6" +checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" dependencies = [ "anstream", "anstyle", @@ -268,18 +263,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.57" +version = "4.5.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d9501bd3f5f09f7bbee01da9a511073ed30a80cd7a509f1214bb74eadea71ad" +checksum = "430b4dc2b5e3861848de79627b2bedc9f3342c7da5173a14eaa5d0f8dc18ae5d" dependencies = [ "clap", ] [[package]] name = "clap_complete_nushell" -version = "4.5.8" +version = "4.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a0c951694691e65bf9d421d597d68416c22de9632e884c28412cb8cd8b73dce" +checksum = "685bc86fd34b7467e0532a4f8435ab107960d69a243785ef0275e571b35b641a" dependencies = [ "clap", "clap_complete", @@ -287,9 +282,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.47" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck", "proc-macro2", @@ -299,9 +294,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "cobs" @@ -309,7 +304,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" dependencies = [ - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -343,9 +338,9 @@ dependencies = [ [[package]] name = "convert_case" -version = "0.6.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" dependencies = [ "unicode-segmentation", ] @@ -419,11 +414,11 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "gimli", - "hashbrown", + "hashbrown 0.15.5", "log", "pulley-interpreter", "regalloc2", - "rustc-hash 2.1.1", + "rustc-hash", "serde", "smallvec", "target-lexicon", @@ -523,13 +518,13 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.5.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881c5d0a13b2f1498e2306e82cbada78390e152d4b1378fb28a84f4dcd0dc4f3" +checksum = "73736a89c4aff73035ba2ed2e565061954da00d4970fc9ac25dcc85a2a20d790" dependencies = [ - "dispatch", + "dispatch2", "nix", - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -553,10 +548,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] -name = "dispatch" -version = "0.2.0" +name = "dispatch2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags 2.10.0", + "block2", + "libc", + "objc2", +] [[package]] name = "displaydoc" @@ -575,6 +576,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + [[package]] name = "either" version = "1.15.0" @@ -616,23 +623,22 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "etcetera" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c7b13d0780cb82722fd59f6f57f925e143427e4a75313a6c77243bf5326ae6" +checksum = "de48cc4d1c1d97a20fd819def54b890cadde72ed3ad0c614822a0a433361be96" dependencies = [ "cfg-if", - "home", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -658,9 +664,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.1" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" +checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" [[package]] name = "fnv" @@ -674,6 +680,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -719,19 +731,19 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.3+wasi-0.2.4", + "wasip2", ] [[package]] @@ -757,25 +769,27 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "foldhash", + "foldhash 0.1.5", "serde", ] +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] + [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "home" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" -dependencies = [ - "windows-sys 0.59.0", -] - [[package]] name = "html-escape" version = "0.2.13" @@ -793,9 +807,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -806,9 +820,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -819,11 +833,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -834,42 +847,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -906,20 +915,24 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.1" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206a8042aec68fa4a62e8d3f7aa4ceb508177d9324faf261e1959e495b7a1921" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.16.1", "serde", + "serde_core", ] [[package]] name = "indoc" -version = "2.0.6" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] [[package]] name = "inotify" @@ -927,7 +940,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "inotify-sys", "libc", ] @@ -943,18 +956,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" @@ -976,9 +980,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "jni" @@ -1004,9 +1008,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" dependencies = [ "once_cell", "wasm-bindgen", @@ -1032,18 +1036,6 @@ dependencies = [ "libc", ] -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "leb128fmt" version = "0.1.0" @@ -1052,18 +1044,28 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.175" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libloading" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-targets 0.53.3", + "windows-link", +] + +[[package]] +name = "libloading" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60" +dependencies = [ + "cfg-if", + "windows-link", ] [[package]] @@ -1080,21 +1082,21 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.9.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "log" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "mach2" @@ -1107,9 +1109,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memfd" @@ -1117,7 +1119,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad38eb12aea514a0466ea40a80fd8cc83637065948eb4a426e4aa46261175227" dependencies = [ - "rustix 1.0.8", + "rustix 1.1.3", ] [[package]] @@ -1128,14 +1130,14 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "mio" -version = "1.0.4" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", "log", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", + "wasi", + "windows-sys 0.61.2", ] [[package]] @@ -1150,7 +1152,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cfg-if", "cfg_aliases", "libc", @@ -1172,7 +1174,7 @@ version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "fsevent-sys", "inotify", "kqueue", @@ -1205,9 +1207,9 @@ checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d" [[package]] name = "objc2" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561f357ba7f3a2a61563a186a163d0a3a5247e1089524a3981d49adb775078bc" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" dependencies = [ "objc2-encode", ] @@ -1220,14 +1222,23 @@ checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" [[package]] name = "objc2-foundation" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "objc2", ] +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + [[package]] name = "object" version = "0.36.7" @@ -1235,7 +1246,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "crc32fast", - "hashbrown", + "hashbrown 0.15.5", "indexmap", "memchr", ] @@ -1248,9 +1259,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "pathdiff" @@ -1266,28 +1277,29 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "phf" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ "phf_shared", + "serde", ] [[package]] name = "phf_generator" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" dependencies = [ + "fastrand", "phf_shared", - "rand", ] [[package]] name = "phf_shared" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" dependencies = [ "siphasher", ] @@ -1312,9 +1324,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -1350,28 +1362,29 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "9695f8df41bb4f3d222c95a67532365f569318332d03d5f3f67f37b20e6ebdf0" dependencies = [ "unicode-ident", ] [[package]] name = "psm" -version = "0.1.26" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e944464ec8536cd1beb0bbfd96987eb5e3b72f2ecdafdc5c769a37f1fa2ae1f" +checksum = "d11f2fedc3b7dafdc2851bc52f277377c5473d378859be234bc7ebb593144d01" dependencies = [ + "ar_archive_writer", "cc", ] @@ -1388,9 +1401,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -1431,6 +1444,26 @@ dependencies = [ "getrandom 0.2.16", ] +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "regalloc2" version = "0.12.2" @@ -1439,17 +1472,17 @@ checksum = "5216b1837de2149f8bc8e6d5f88a9326b63b8c836ed58ce4a0a29ec736a59734" dependencies = [ "allocator-api2", "bumpalo", - "hashbrown", + "hashbrown 0.15.5", "log", - "rustc-hash 2.1.1", + "rustc-hash", "smallvec", ] [[package]] name = "regex" -version = "1.11.2" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -1459,9 +1492,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.10" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -1470,15 +1503,18 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "relative-path" -version = "1.9.3" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" +checksum = "bca40a312222d8ba74837cb474edef44b37f561da5f773981007a10bbaa992b0" +dependencies = [ + "serde", +] [[package]] name = "rgb" @@ -1491,9 +1527,9 @@ dependencies = [ [[package]] name = "rquickjs" -version = "0.9.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5227859c4dfc83f428e58f9569bf439e628c8d139020e7faff437e6f5abaa0" +checksum = "c50dc6d6c587c339edb4769cf705867497a2baf0eca8b4645fa6ecd22f02c77a" dependencies = [ "rquickjs-core", "rquickjs-macro", @@ -1501,10 +1537,11 @@ dependencies = [ [[package]] name = "rquickjs-core" -version = "0.9.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e82e0ca83028ad5b533b53b96c395bbaab905a5774de4aaf1004eeacafa3d85d" +checksum = "b8bf7840285c321c3ab20e752a9afb95548c75cd7f4632a0627cea3507e310c1" dependencies = [ + "hashbrown 0.16.1", "phf", "relative-path", "rquickjs-sys", @@ -1512,9 +1549,9 @@ dependencies = [ [[package]] name = "rquickjs-macro" -version = "0.9.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4d2eccd988a924a470a76fbd81a191b22d1f5f4f4619cf5662a8c1ab4ca1db7" +checksum = "7106215ff41a5677b104906a13e1a440b880f4b6362b5dc4f3978c267fad2b80" dependencies = [ "convert_case", "fnv", @@ -1531,20 +1568,14 @@ dependencies = [ [[package]] name = "rquickjs-sys" -version = "0.9.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fed0097b0b4fbb2a87f6dd3b995a7c64ca56de30007eb7e867dfdfc78324ba5" +checksum = "27344601ef27460e82d6a4e1ecb9e7e99f518122095f3c51296da8e9be2b9d83" dependencies = [ - "bindgen 0.69.5", + "bindgen", "cc", ] -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc-hash" version = "2.1.1" @@ -1557,7 +1588,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys 0.4.15", @@ -1566,22 +1597,22 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.8" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "errno", "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.60.2", + "linux-raw-sys 0.11.0", + "windows-sys 0.61.2", ] [[package]] -name = "ryu" -version = "1.0.20" +name = "rustversion" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "same-file" @@ -1592,6 +1623,31 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schemars" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54e910108742c57a770f492731f99be216a52fadd361b06c8fb59d74ccc267d2" +dependencies = [ + "dyn-clone", + "ref-cast", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4908ad288c5035a8eb12cfdf0d49270def0a268ee162b75eeee0f85d155a7c45" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn", +] + [[package]] name = "semver" version = "1.0.27" @@ -1604,9 +1660,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.224" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aaeb1e94f53b16384af593c71e20b095e958dab1d26939c1b70645c5cfbcc0b" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", @@ -1614,18 +1670,29 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.224" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f39390fa6346e24defbcdd3d9544ba8a19985d0af74df8501fbfe9a64341ab" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.224" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ff78ab5e8561c9a675bfc1785cb07ae721f0ee53329a595cefd8c04c2ac4e0" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", @@ -1634,23 +1701,23 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.145" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "indexmap", "itoa", "memchr", - "ryu", "serde", "serde_core", + "zmij", ] [[package]] name = "shell-words" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" [[package]] name = "shlex" @@ -1693,9 +1760,9 @@ checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "streaming-iterator" @@ -1711,9 +1778,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.106" +version = "2.0.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "21f182278bf2d2bcb3c88b1b08a37df029d71ce3d3ae26168e3c653b213b99d4" dependencies = [ "proc-macro2", "quote", @@ -1733,21 +1800,21 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.13.2" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" +checksum = "b1dd07eb858a2067e2f3c7155d54e929265c264e6f37efe3ee7a8d1b5a1dd0ba" [[package]] name = "tempfile" -version = "3.22.0" +version = "3.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84fa4d11fadde498443cca10fd3ac23c951f0dc59e080e9f4b93d4df4e4eea53" +checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" dependencies = [ "fastrand", - "getrandom 0.3.3", + "getrandom 0.3.4", "once_cell", - "rustix 1.0.8", - "windows-sys 0.61.0", + "rustix 1.1.3", + "windows-sys 0.61.2", ] [[package]] @@ -1770,11 +1837,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.16", + "thiserror-impl 2.0.17", ] [[package]] @@ -1790,9 +1857,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -1822,9 +1889,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -1832,18 +1899,31 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.11" +version = "0.7.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] [[package]] name = "toml_edit" -version = "0.22.27" +version = "0.23.10+spec-1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" dependencies = [ "indexmap", "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +dependencies = [ "winnow", ] @@ -1855,9 +1935,9 @@ checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -1866,9 +1946,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", @@ -1877,9 +1957,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", ] @@ -1888,7 +1968,7 @@ dependencies = [ name = "tree-sitter" version = "0.27.0" dependencies = [ - "bindgen 0.72.1", + "bindgen", "cc", "regex", "regex-syntax", @@ -1909,6 +1989,7 @@ dependencies = [ "clap", "clap_complete", "clap_complete_nushell", + "crc32fast", "ctor", "ctrlc", "dialoguer", @@ -1922,12 +2003,14 @@ dependencies = [ "pretty_assertions", "rand", "regex", + "schemars", "semver", "serde", "serde_json", "similar", "streaming-iterator", "tempfile", + "thiserror 2.0.17", "tiny_http", "tree-sitter", "tree-sitter-config", @@ -1938,7 +2021,7 @@ dependencies = [ "tree-sitter-tests-proc-macro", "unindent", "walkdir", - "wasmparser", + "wasmparser 0.243.0", "webbrowser", "widestring", ] @@ -1947,18 +2030,18 @@ dependencies = [ name = "tree-sitter-config" version = "0.27.0" dependencies = [ - "anyhow", "etcetera", "log", "serde", "serde_json", + "thiserror 2.0.17", ] [[package]] name = "tree-sitter-generate" version = "0.27.0" dependencies = [ - "anyhow", + "bitflags 2.10.0", "dunce", "indexmap", "indoc", @@ -1967,13 +2050,13 @@ dependencies = [ "regex", "regex-syntax", "rquickjs", - "rustc-hash 2.1.1", + "rustc-hash", "semver", "serde", "serde_json", "smallbitvec", "tempfile", - "thiserror 2.0.16", + "thiserror 2.0.17", "topological-sort", ] @@ -1983,24 +2066,23 @@ version = "0.27.0" dependencies = [ "regex", "streaming-iterator", - "thiserror 2.0.16", + "thiserror 2.0.17", "tree-sitter", ] [[package]] name = "tree-sitter-language" -version = "0.1.4" +version = "0.1.7" [[package]] name = "tree-sitter-loader" version = "0.27.0" dependencies = [ - "anyhow", "cc", "etcetera", "fs4", "indoc", - "libloading", + "libloading 0.9.0", "log", "once_cell", "regex", @@ -2008,6 +2090,7 @@ dependencies = [ "serde", "serde_json", "tempfile", + "thiserror 2.0.17", "tree-sitter", "tree-sitter-highlight", "tree-sitter-tags", @@ -2020,7 +2103,7 @@ dependencies = [ "memchr", "regex", "streaming-iterator", - "thiserror 2.0.16", + "thiserror 2.0.17", "tree-sitter", ] @@ -2035,9 +2118,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-segmentation" @@ -2047,9 +2130,9 @@ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "unindent" @@ -2071,9 +2154,9 @@ dependencies = [ [[package]] name = "utf8-width" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" +checksum = "1292c0d970b54115d14f2492fe0170adf21d68a1de108eebc51c1df4f346a091" [[package]] name = "utf8_iter" @@ -2104,44 +2187,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasi" -version = "0.14.3+wasi-0.2.4" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2149,22 +2220,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" dependencies = [ "unicode-ident", ] @@ -2176,7 +2247,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38ba1d491ecacb085a2552025c10a675a6fddcbd03b1fc9b36c536010ce265d2" dependencies = [ "leb128fmt", - "wasmparser", + "wasmparser 0.229.0", ] [[package]] @@ -2185,8 +2256,21 @@ version = "0.229.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc3b1f053f5d41aa55640a1fa9b6d1b8a9e4418d118ce308d20e24ff3575a8c" dependencies = [ - "bitflags 2.9.4", - "hashbrown", + "bitflags 2.10.0", + "hashbrown 0.15.5", + "indexmap", + "semver", + "serde", +] + +[[package]] +name = "wasmparser" +version = "0.243.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6d8db401b0528ec316dfbe579e6ab4152d61739cfe076706d2009127970159d" +dependencies = [ + "bitflags 2.10.0", + "hashbrown 0.15.5", "indexmap", "semver", "serde", @@ -2200,7 +2284,7 @@ checksum = "d25dac01892684a99b8fbfaf670eb6b56edea8a096438c75392daeb83156ae2e" dependencies = [ "anyhow", "termcolor", - "wasmparser", + "wasmparser 0.229.0", ] [[package]] @@ -2211,28 +2295,28 @@ checksum = "57373e1d8699662fb791270ac5dfac9da5c14f618ecf940cdb29dc3ad9472a3c" dependencies = [ "addr2line", "anyhow", - "bitflags 2.9.4", + "bitflags 2.10.0", "bumpalo", "cc", "cfg-if", - "hashbrown", + "hashbrown 0.15.5", "indexmap", "libc", "log", "mach2", "memfd", - "object", + "object 0.36.7", "once_cell", "postcard", "psm", "pulley-interpreter", - "rustix 1.0.8", + "rustix 1.1.3", "serde", "serde_derive", "smallvec", "sptr", "target-lexicon", - "wasmparser", + "wasmparser 0.229.0", "wasmtime-asm-macros", "wasmtime-cranelift", "wasmtime-environ", @@ -2293,12 +2377,12 @@ dependencies = [ "gimli", "itertools 0.14.0", "log", - "object", + "object 0.36.7", "pulley-interpreter", "smallvec", "target-lexicon", - "thiserror 2.0.16", - "wasmparser", + "thiserror 2.0.17", + "wasmparser 0.229.0", "wasmtime-environ", "wasmtime-versioned-export-macros", ] @@ -2315,14 +2399,14 @@ dependencies = [ "gimli", "indexmap", "log", - "object", + "object 0.36.7", "postcard", "serde", "serde_derive", "smallvec", "target-lexicon", "wasm-encoder", - "wasmparser", + "wasmparser 0.229.0", "wasmprinter", ] @@ -2335,7 +2419,7 @@ dependencies = [ "anyhow", "cc", "cfg-if", - "rustix 1.0.8", + "rustix 1.1.3", "wasmtime-asm-macros", "wasmtime-versioned-export-macros", "windows-sys 0.59.0", @@ -2388,9 +2472,9 @@ dependencies = [ "anyhow", "cranelift-codegen", "gimli", - "object", + "object 0.36.7", "target-lexicon", - "wasmparser", + "wasmparser 0.229.0", "wasmtime-cranelift", "wasmtime-environ", "winch-codegen", @@ -2398,9 +2482,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" dependencies = [ "js-sys", "wasm-bindgen", @@ -2408,9 +2492,9 @@ dependencies = [ [[package]] name = "webbrowser" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf4f3c0ba838e82b4e5ccc4157003fb8c324ee24c058470ffb82820becbde98" +checksum = "00f1243ef785213e3a32fa0396093424a3a6ea566f9948497e5a2309261a4c97" dependencies = [ "core-foundation", "jni", @@ -2422,31 +2506,19 @@ dependencies = [ "web-sys", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.44", -] - [[package]] name = "widestring" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" +checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" [[package]] name = "winapi-util" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2462,23 +2534,17 @@ dependencies = [ "regalloc2", "smallvec", "target-lexicon", - "thiserror 2.0.16", - "wasmparser", + "thiserror 2.0.17", + "wasmparser 0.229.0", "wasmtime-cranelift", "wasmtime-environ", ] [[package]] name = "windows-link" -version = "0.1.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-link" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-sys" @@ -2513,16 +2579,16 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.3", + "windows-targets 0.53.5", ] [[package]] name = "windows-sys" -version = "0.61.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link 0.2.0", + "windows-link", ] [[package]] @@ -2558,19 +2624,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.3" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link 0.1.3", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -2587,9 +2653,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -2605,9 +2671,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -2623,9 +2689,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -2635,9 +2701,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -2653,9 +2719,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -2671,9 +2737,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -2689,9 +2755,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -2707,30 +2773,30 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] [[package]] name = "wit-bindgen" -version = "0.45.0" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "xtask" @@ -2738,14 +2804,18 @@ version = "0.1.0" dependencies = [ "anstyle", "anyhow", - "bindgen 0.72.1", + "bindgen", "clap", + "etcetera", "indoc", "notify", "notify-debouncer-full", "regex", + "schemars", "semver", "serde_json", + "tree-sitter-cli", + "tree-sitter-loader", ] [[package]] @@ -2756,11 +2826,10 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -2768,9 +2837,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", @@ -2780,18 +2849,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" dependencies = [ "proc-macro2", "quote", @@ -2821,15 +2890,15 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -2838,9 +2907,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -2849,11 +2918,17 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9747e91771f56fd7893e1164abd78febd14a670ceec257caad15e051de35f06" diff --git a/Cargo.toml b/Cargo.toml index b2bf25ca..ca0d644a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ authors = [ "Amaan Qureshi ", ] edition = "2021" -rust-version = "1.84" +rust-version = "1.85" homepage = "https://tree-sitter.github.io/tree-sitter" repository = "https://github.com/tree-sitter/tree-sitter" license = "MIT" @@ -103,11 +103,11 @@ codegen-units = 256 [workspace.dependencies] ansi_colours = "1.2.3" -anstyle = "1.0.11" -anyhow = "1.0.99" +anstyle = "1.0.13" +anyhow = "1.0.100" bstr = "1.12.0" -cc = "1.2.37" -clap = { version = "4.5.45", features = [ +cc = "1.2.53" +clap = { version = "4.5.54", features = [ "cargo", "derive", "env", @@ -115,46 +115,49 @@ clap = { version = "4.5.45", features = [ "string", "unstable-styles", ] } -clap_complete = "4.5.57" -clap_complete_nushell = "4.5.8" +clap_complete = "4.5.65" +clap_complete_nushell = "4.5.10" +crc32fast = "1.5.0" ctor = "0.2.9" ctrlc = { version = "3.5.0", features = ["termination"] } dialoguer = { version = "0.11.0", features = ["fuzzy-select"] } -etcetera = "0.10.0" +etcetera = "0.11.0" fs4 = "0.12.0" glob = "0.3.3" heck = "0.5.0" html-escape = "0.2.13" -indexmap = "2.11.1" +indexmap = "2.12.1" indoc = "2.0.6" -libloading = "0.8.8" +libloading = "0.9.0" log = { version = "0.4.28", features = ["std"] } -memchr = "2.7.5" +memchr = "2.7.6" once_cell = "1.21.3" pretty_assertions = "1.4.1" rand = "0.8.5" -regex = "1.11.2" +regex = "1.11.3" regex-syntax = "0.8.6" rustc-hash = "2.1.1" +schemars = "1.0.5" semver = { version = "1.0.27", features = ["serde"] } serde = { version = "1.0.219", features = ["derive"] } -serde_json = { version = "1.0.145", features = ["preserve_order"] } +serde_json = { version = "1.0.149", features = ["preserve_order"] } similar = "2.7.0" smallbitvec = "2.6.0" streaming-iterator = "0.1.9" -tempfile = "3.22.0" -thiserror = "2.0.16" +tempfile = "3.23.0" +thiserror = "2.0.17" tiny_http = "0.12.0" topological-sort = "0.2.2" unindent = "0.2.4" walkdir = "2.5.0" -wasmparser = "0.229.0" +wasmparser = "0.243.0" webbrowser = "1.0.5" tree-sitter = { version = "0.27.0", path = "./lib" } tree-sitter-generate = { version = "0.27.0", path = "./crates/generate" } -tree-sitter-language = { path = "./crates/language" } tree-sitter-loader = { version = "0.27.0", path = "./crates/loader" } tree-sitter-config = { version = "0.27.0", path = "./crates/config" } tree-sitter-highlight = { version = "0.27.0", path = "./crates/highlight" } tree-sitter-tags = { version = "0.27.0", path = "./crates/tags" } + +tree-sitter-language = { version = "0.1", path = "./crates/language" } diff --git a/Makefile b/Makefile index abd765b1..2098d275 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -VERSION := 0.26.0 +VERSION := 0.27.0 DESCRIPTION := An incremental parsing system for programming tools HOMEPAGE_URL := https://tree-sitter.github.io/tree-sitter/ @@ -24,7 +24,7 @@ OBJ := $(SRC:.c=.o) ARFLAGS := rcs CFLAGS ?= -O3 -Wall -Wextra -Wshadow -Wpedantic -Werror=incompatible-pointer-types override CFLAGS += -std=c11 -fPIC -fvisibility=hidden -override CFLAGS += -D_POSIX_C_SOURCE=200112L -D_DEFAULT_SOURCE +override CFLAGS += -D_POSIX_C_SOURCE=200112L -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_DARWIN_C_SOURCE override CFLAGS += -Ilib/src -Ilib/src/wasm -Ilib/include # ABI versioning diff --git a/Package.swift b/Package.swift index 572ba684..fb6c6e95 100644 --- a/Package.swift +++ b/Package.swift @@ -27,6 +27,8 @@ let package = Package( .headerSearchPath("src"), .define("_POSIX_C_SOURCE", to: "200112L"), .define("_DEFAULT_SOURCE"), + .define("_BSD_SOURCE"), + .define("_DARWIN_C_SOURCE"), ]), ], cLanguageStandard: .c11 diff --git a/build.zig b/build.zig index 66a448cb..9bb1e818 100644 --- a/build.zig +++ b/build.zig @@ -40,6 +40,8 @@ pub fn build(b: *std.Build) !void { lib.root_module.addCMacro("_POSIX_C_SOURCE", "200112L"); lib.root_module.addCMacro("_DEFAULT_SOURCE", ""); + lib.root_module.addCMacro("_BSD_SOURCE", ""); + lib.root_module.addCMacro("_DARWIN_C_SOURCE", ""); if (wasm) { if (b.lazyDependency(wasmtimeDep(target.result), .{})) |wasmtime| { diff --git a/build.zig.zon b/build.zig.zon index 48e52686..4ef5de16 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,7 +1,7 @@ .{ .name = .tree_sitter, .fingerprint = 0x841224b447ac0d4f, - .version = "0.26.0", + .version = "0.27.0", .minimum_zig_version = "0.14.1", .paths = .{ "build.zig", diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index b8ac8222..c10b4652 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -42,6 +42,7 @@ bstr.workspace = true clap.workspace = true clap_complete.workspace = true clap_complete_nushell.workspace = true +crc32fast.workspace = true ctor.workspace = true ctrlc.workspace = true dialoguer.workspace = true @@ -53,11 +54,13 @@ log.workspace = true memchr.workspace = true rand.workspace = true regex.workspace = true +schemars.workspace = true semver.workspace = true serde.workspace = true serde_json.workspace = true similar.workspace = true streaming-iterator.workspace = true +thiserror.workspace = true tiny_http.workspace = true walkdir.workspace = true wasmparser.workspace = true @@ -72,7 +75,7 @@ tree-sitter-tags.workspace = true [dev-dependencies] encoding_rs = "0.8.35" -widestring = "1.2.0" +widestring = "1.2.1" tree_sitter_proc_macro = { path = "src/tests/proc_macro", package = "tree-sitter-tests-proc-macro" } tempfile.workspace = true diff --git a/crates/cli/README.md b/crates/cli/README.md index 5a399f08..e3ef899e 100644 --- a/crates/cli/README.md +++ b/crates/cli/README.md @@ -7,7 +7,8 @@ [npmjs.com]: https://www.npmjs.org/package/tree-sitter-cli [npmjs.com badge]: https://img.shields.io/npm/v/tree-sitter-cli.svg?color=%23BF4A4A -The Tree-sitter CLI allows you to develop, test, and use Tree-sitter grammars from the command line. It works on `MacOS`, `Linux`, and `Windows`. +The Tree-sitter CLI allows you to develop, test, and use Tree-sitter grammars from the command line. It works on `MacOS`, +`Linux`, and `Windows`. ### Installation @@ -34,9 +35,11 @@ The `tree-sitter` binary itself has no dependencies, but specific commands have ### Commands -* `generate` - The `tree-sitter generate` command will generate a Tree-sitter parser based on the grammar in the current working directory. See [the documentation] for more information. +* `generate` - The `tree-sitter generate` command will generate a Tree-sitter parser based on the grammar in the current + working directory. See [the documentation] for more information. -* `test` - The `tree-sitter test` command will run the unit tests for the Tree-sitter parser in the current working directory. See [the documentation] for more information. +* `test` - The `tree-sitter test` command will run the unit tests for the Tree-sitter parser in the current working directory. + See [the documentation] for more information. * `parse` - The `tree-sitter parse` command will parse a file (or list of files) using Tree-sitter parsers. diff --git a/crates/cli/eslint/package-lock.json b/crates/cli/eslint/package-lock.json index 585a4f99..60559b10 100644 --- a/crates/cli/eslint/package-lock.json +++ b/crates/cli/eslint/package-lock.json @@ -805,9 +805,9 @@ "peer": true }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "license": "MIT", "peer": true, "dependencies": { diff --git a/crates/cli/npm/dsl.d.ts b/crates/cli/npm/dsl.d.ts index 3ad9ea2a..accdb95f 100644 --- a/crates/cli/npm/dsl.d.ts +++ b/crates/cli/npm/dsl.d.ts @@ -29,6 +29,7 @@ type Rule = | PrecRule | Repeat1Rule | RepeatRule + | ReservedRule | SeqRule | StringRule | SymbolRule diff --git a/crates/cli/npm/package-lock.json b/crates/cli/npm/package-lock.json index ae8bddb6..739e69f1 100644 --- a/crates/cli/npm/package-lock.json +++ b/crates/cli/npm/package-lock.json @@ -1,12 +1,12 @@ { "name": "tree-sitter-cli", - "version": "0.26.0", + "version": "0.27.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "tree-sitter-cli", - "version": "0.26.0", + "version": "0.27.0", "hasInstallScript": true, "license": "MIT", "bin": { diff --git a/crates/cli/npm/package.json b/crates/cli/npm/package.json index 23835503..d49abd46 100644 --- a/crates/cli/npm/package.json +++ b/crates/cli/npm/package.json @@ -1,6 +1,6 @@ { "name": "tree-sitter-cli", - "version": "0.26.0", + "version": "0.27.0", "author": { "name": "Max Brunsfeld", "email": "maxbrunsfeld@gmail.com" diff --git a/crates/cli/src/fuzz.rs b/crates/cli/src/fuzz.rs index 24806fca..39ad7691 100644 --- a/crates/cli/src/fuzz.rs +++ b/crates/cli/src/fuzz.rs @@ -25,7 +25,7 @@ use crate::{ random::Rand, }, parse::perform_edit, - test::{parse_tests, print_diff, print_diff_key, strip_sexp_fields, TestEntry}, + test::{parse_tests, strip_sexp_fields, DiffKey, TestDiff, TestEntry}, }; pub static LOG_ENABLED: LazyLock = LazyLock::new(|| env::var("TREE_SITTER_LOG").is_ok()); @@ -183,8 +183,8 @@ pub fn fuzz_language_corpus( if actual_output != test.output { println!("Incorrect initial parse for {test_name}"); - print_diff_key(); - print_diff(&actual_output, &test.output, true); + DiffKey::print(); + println!("{}", TestDiff::new(&actual_output, &test.output)); println!(); return false; } @@ -276,8 +276,8 @@ pub fn fuzz_language_corpus( if actual_output != test.output && !test.error { println!("Incorrect parse for {test_name} - seed {seed}"); - print_diff_key(); - print_diff(&actual_output, &test.output, true); + DiffKey::print(); + println!("{}", TestDiff::new(&actual_output, &test.output)); println!(); return false; } diff --git a/crates/cli/src/init.rs b/crates/cli/src/init.rs index 3af16c6e..70ca25af 100644 --- a/crates/cli/src/init.rs +++ b/crates/cli/src/init.rs @@ -5,14 +5,20 @@ use std::{ }; use anyhow::{anyhow, Context, Result}; +use crc32fast::hash as crc32; use heck::{ToKebabCase, ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase}; use indoc::{formatdoc, indoc}; -use log::warn; +use log::info; +use rand::{thread_rng, Rng}; use semver::Version; use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; use tree_sitter_generate::write_file; -use tree_sitter_loader::{Author, Bindings, Grammar, Links, Metadata, PathsJSON, TreeSitterJSON}; +use tree_sitter_loader::{ + Author, Bindings, Grammar, Links, Metadata, PathsJSON, TreeSitterJSON, + DEFAULT_HIGHLIGHTS_QUERY_FILE_NAME, DEFAULT_INJECTIONS_QUERY_FILE_NAME, + DEFAULT_LOCALS_QUERY_FILE_NAME, DEFAULT_TAGS_QUERY_FILE_NAME, +}; const CLI_VERSION: &str = env!("CARGO_PKG_VERSION"); const CLI_VERSION_PLACEHOLDER: &str = "CLI_VERSION"; @@ -30,9 +36,12 @@ const PARSER_CLASS_NAME_PLACEHOLDER: &str = "PARSER_CLASS_NAME"; const PARSER_DESCRIPTION_PLACEHOLDER: &str = "PARSER_DESCRIPTION"; const PARSER_LICENSE_PLACEHOLDER: &str = "PARSER_LICENSE"; +const PARSER_NS_PLACEHOLDER: &str = "PARSER_NS"; +const PARSER_NS_CLEANED_PLACEHOLDER: &str = "PARSER_NS_CLEANED"; const PARSER_URL_PLACEHOLDER: &str = "PARSER_URL"; const PARSER_URL_STRIPPED_PLACEHOLDER: &str = "PARSER_URL_STRIPPED"; const PARSER_VERSION_PLACEHOLDER: &str = "PARSER_VERSION"; +const PARSER_FINGERPRINT_PLACEHOLDER: &str = "PARSER_FINGERPRINT"; const AUTHOR_NAME_PLACEHOLDER: &str = "PARSER_AUTHOR_NAME"; const AUTHOR_EMAIL_PLACEHOLDER: &str = "PARSER_AUTHOR_EMAIL"; @@ -51,12 +60,22 @@ const AUTHOR_BLOCK_RS: &str = "\nauthors = ["; const AUTHOR_NAME_PLACEHOLDER_RS: &str = "PARSER_AUTHOR_NAME"; const AUTHOR_EMAIL_PLACEHOLDER_RS: &str = " PARSER_AUTHOR_EMAIL"; +const AUTHOR_BLOCK_JAVA: &str = "\n "; +const AUTHOR_NAME_PLACEHOLDER_JAVA: &str = "\n PARSER_AUTHOR_NAME"; +const AUTHOR_EMAIL_PLACEHOLDER_JAVA: &str = "\n PARSER_AUTHOR_EMAIL"; +const AUTHOR_URL_PLACEHOLDER_JAVA: &str = "\n PARSER_AUTHOR_URL"; + const AUTHOR_BLOCK_GRAMMAR: &str = "\n * @author "; const AUTHOR_NAME_PLACEHOLDER_GRAMMAR: &str = "PARSER_AUTHOR_NAME"; const AUTHOR_EMAIL_PLACEHOLDER_GRAMMAR: &str = " PARSER_AUTHOR_EMAIL"; const FUNDING_URL_PLACEHOLDER: &str = "FUNDING_URL"; +const HIGHLIGHTS_QUERY_PATH_PLACEHOLDER: &str = "HIGHLIGHTS_QUERY_PATH"; +const INJECTIONS_QUERY_PATH_PLACEHOLDER: &str = "INJECTIONS_QUERY_PATH"; +const LOCALS_QUERY_PATH_PLACEHOLDER: &str = "LOCALS_QUERY_PATH"; +const TAGS_QUERY_PATH_PLACEHOLDER: &str = "TAGS_QUERY_PATH"; + const GRAMMAR_JS_TEMPLATE: &str = include_str!("./templates/grammar.js"); const PACKAGE_JSON_TEMPLATE: &str = include_str!("./templates/package.json"); const GITIGNORE_TEMPLATE: &str = include_str!("./templates/gitignore"); @@ -95,12 +114,16 @@ const TEST_BINDING_PY_TEMPLATE: &str = include_str!("./templates/test_binding.py const PACKAGE_SWIFT_TEMPLATE: &str = include_str!("./templates/package.swift"); const TESTS_SWIFT_TEMPLATE: &str = include_str!("./templates/tests.swift"); +const POM_XML_TEMPLATE: &str = include_str!("./templates/pom.xml"); +const BINDING_JAVA_TEMPLATE: &str = include_str!("./templates/binding.java"); +const TEST_JAVA_TEMPLATE: &str = include_str!("./templates/test.java"); + const BUILD_ZIG_TEMPLATE: &str = include_str!("./templates/build.zig"); const BUILD_ZIG_ZON_TEMPLATE: &str = include_str!("./templates/build.zig.zon"); const ROOT_ZIG_TEMPLATE: &str = include_str!("./templates/root.zig"); const TEST_ZIG_TEMPLATE: &str = include_str!("./templates/test.zig"); -const TREE_SITTER_JSON_SCHEMA: &str = +pub const TREE_SITTER_JSON_SCHEMA: &str = "https://tree-sitter.github.io/tree-sitter/assets/schemas/config.schema.json"; #[derive(Serialize, Deserialize, Clone)] @@ -122,6 +145,7 @@ pub struct JsonConfigOpts { pub email: Option, #[serde(skip_serializing_if = "Option::is_none")] pub url: Option, + pub namespace: Option, pub bindings: Bindings, } @@ -154,7 +178,7 @@ impl JsonConfigOpts { authors: Some(vec![Author { name: self.author, email: self.email, - url: self.url.map(|url| url.to_string()), + url: self.url, }]), links: Some(Links { repository: self.repository.unwrap_or_else(|| { @@ -162,7 +186,7 @@ impl JsonConfigOpts { }), funding: self.funding, }), - namespace: None, + namespace: self.namespace, }, bindings: self.bindings, } @@ -185,6 +209,7 @@ impl Default for JsonConfigOpts { author: String::new(), email: None, url: None, + namespace: None, bindings: Bindings::default(), } } @@ -202,6 +227,11 @@ struct GenerateOpts<'a> { camel_parser_name: &'a str, title_parser_name: &'a str, class_name: &'a str, + highlights_query_path: &'a str, + injections_query_path: &'a str, + locals_query_path: &'a str, + tags_query_path: &'a str, + namespace: Option<&'a str>, } pub fn generate_grammar_files( @@ -252,6 +282,11 @@ pub fn generate_grammar_files( .clone() .unwrap_or_else(|| format!("TreeSitter{}", language_name.to_upper_camel_case())); + let default_highlights_path = Path::new("queries").join(DEFAULT_HIGHLIGHTS_QUERY_FILE_NAME); + let default_injections_path = Path::new("queries").join(DEFAULT_INJECTIONS_QUERY_FILE_NAME); + let default_locals_path = Path::new("queries").join(DEFAULT_LOCALS_QUERY_FILE_NAME); + let default_tags_path = Path::new("queries").join(DEFAULT_TAGS_QUERY_FILE_NAME); + let generate_opts = GenerateOpts { author_name: authors .map(|a| a.first().map(|a| a.name.as_str())) @@ -278,6 +313,19 @@ pub fn generate_grammar_files( camel_parser_name: &camel_name, title_parser_name: &title_name, class_name: &class_name, + highlights_query_path: tree_sitter_config.grammars[0] + .highlights + .to_variable_value(&default_highlights_path), + injections_query_path: tree_sitter_config.grammars[0] + .injections + .to_variable_value(&default_injections_path), + locals_query_path: tree_sitter_config.grammars[0] + .locals + .to_variable_value(&default_locals_path), + tags_query_path: tree_sitter_config.grammars[0] + .tags + .to_variable_value(&default_tags_path), + namespace: tree_sitter_config.metadata.namespace.as_deref(), }; // Create package.json @@ -304,11 +352,11 @@ pub fn generate_grammar_files( "tree-sitter-cli":"#}, indoc! {r#" "prebuildify": "^6.0.1", - "tree-sitter": "^0.22.4", + "tree-sitter": "^0.25.0", "tree-sitter-cli":"#}, ); if !contents.contains("module") { - warn!("Updating package.json"); + info!("Migrating package.json to ESM"); contents = contents.replace( r#""repository":"#, indoc! {r#" @@ -330,6 +378,7 @@ pub fn generate_grammar_files( |path| { let mut contents = fs::read_to_string(path)?; if contents.contains("module.exports") { + info!("Migrating grammars.js to ESM"); contents = contents.replace("module.exports =", "export default"); write_file(path, contents)?; } @@ -345,10 +394,16 @@ pub fn generate_grammar_files( allow_update, |path| generate_file(path, GITIGNORE_TEMPLATE, language_name, &generate_opts), |path| { - let contents = fs::read_to_string(path)?; + let mut contents = fs::read_to_string(path)?; if !contents.contains("Zig artifacts") { - warn!("Replacing .gitignore"); - generate_file(path, GITIGNORE_TEMPLATE, language_name, &generate_opts)?; + info!("Adding zig entries to .gitignore"); + contents.push('\n'); + contents.push_str(indoc! {" + # Zig artifacts + .zig-cache/ + zig-cache/ + zig-out/ + "}); } Ok(()) }, @@ -361,8 +416,13 @@ pub fn generate_grammar_files( |path| generate_file(path, GITATTRIBUTES_TEMPLATE, language_name, &generate_opts), |path| { let mut contents = fs::read_to_string(path)?; - contents = contents.replace("bindings/c/* ", "bindings/c/** "); + let c_bindings_entry = "bindings/c/* "; + if contents.contains(c_bindings_entry) { + info!("Updating c bindings entry in .gitattributes"); + contents = contents.replace(c_bindings_entry, "bindings/c/** "); + } if !contents.contains("Zig bindings") { + info!("Adding zig entries to .gitattributes"); contents.push('\n'); contents.push_str(indoc! {" # Zig bindings @@ -385,8 +445,48 @@ pub fn generate_grammar_files( // Generate Rust bindings if tree_sitter_config.bindings.rust { missing_path(bindings_dir.join("rust"), create_dir)?.apply(|path| { - missing_path(path.join("lib.rs"), |path| { + missing_path_else(path.join("lib.rs"), allow_update, |path| { generate_file(path, LIB_RS_TEMPLATE, language_name, &generate_opts) + }, |path| { + let mut contents = fs::read_to_string(path)?; + if !contents.contains("#[cfg(with_highlights_query)]") { + info!("Updating query constants in bindings/rust/lib.rs"); + let replacement = indoc! {r#" + #[cfg(with_highlights_query)] + /// The syntax highlighting query for this grammar. + pub const HIGHLIGHTS_QUERY: &str = include_str!("../../HIGHLIGHTS_QUERY_PATH"); + + #[cfg(with_injections_query)] + /// The language injection query for this grammar. + pub const INJECTIONS_QUERY: &str = include_str!("../../INJECTIONS_QUERY_PATH"); + + #[cfg(with_locals_query)] + /// The local variable query for this grammar. + pub const LOCALS_QUERY: &str = include_str!("../../LOCALS_QUERY_PATH"); + + #[cfg(with_tags_query)] + /// The symbol tagging query for this grammar. + pub const TAGS_QUERY: &str = include_str!("../../TAGS_QUERY_PATH"); + "#} + .replace("HIGHLIGHTS_QUERY_PATH", generate_opts.highlights_query_path) + .replace("INJECTIONS_QUERY_PATH", generate_opts.injections_query_path) + .replace("LOCALS_QUERY_PATH", generate_opts.locals_query_path) + .replace("TAGS_QUERY_PATH", generate_opts.tags_query_path); + contents = contents + .replace( + indoc! {r#" + // NOTE: uncomment these to include any queries that this grammar contains: + + // pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm"); + // pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injections.scm"); + // pub const LOCALS_QUERY: &str = include_str!("../../queries/locals.scm"); + // pub const TAGS_QUERY: &str = include_str!("../../queries/tags.scm"); + "#}, + &replacement, + ); + } + write_file(path, contents)?; + Ok(()) })?; missing_path_else( @@ -394,37 +494,76 @@ pub fn generate_grammar_files( allow_update, |path| generate_file(path, BUILD_RS_TEMPLATE, language_name, &generate_opts), |path| { - let replacement = indoc!{r#" - c_config.flag("-utf-8"); - - if std::env::var("TARGET").unwrap() == "wasm32-unknown-unknown" { - let Ok(wasm_headers) = std::env::var("DEP_TREE_SITTER_LANGUAGE_WASM_HEADERS") else { - panic!("Environment variable DEP_TREE_SITTER_LANGUAGE_WASM_HEADERS must be set by the language crate"); - }; - let Ok(wasm_src) = - std::env::var("DEP_TREE_SITTER_LANGUAGE_WASM_SRC").map(std::path::PathBuf::from) - else { - panic!("Environment variable DEP_TREE_SITTER_LANGUAGE_WASM_SRC must be set by the language crate"); - }; - - c_config.include(&wasm_headers); - c_config.files([ - wasm_src.join("stdio.c"), - wasm_src.join("stdlib.c"), - wasm_src.join("string.c"), - ]); - } - "#}; - - let indented_replacement = replacement - .lines() - .map(|line| if line.is_empty() { line.to_string() } else { format!(" {line}") }) - .collect::>() - .join("\n"); - let mut contents = fs::read_to_string(path)?; if !contents.contains("wasm32-unknown-unknown") { - contents = contents.replace(r#" c_config.flag("-utf-8");"#, &indented_replacement); + info!("Adding wasm32-unknown-unknown target to bindings/rust/build.rs"); + let replacement = indoc!{r#" + c_config.flag("-utf-8"); + + if std::env::var("TARGET").unwrap() == "wasm32-unknown-unknown" { + let Ok(wasm_headers) = std::env::var("DEP_TREE_SITTER_LANGUAGE_WASM_HEADERS") else { + panic!("Environment variable DEP_TREE_SITTER_LANGUAGE_WASM_HEADERS must be set by the language crate"); + }; + let Ok(wasm_src) = + std::env::var("DEP_TREE_SITTER_LANGUAGE_WASM_SRC").map(std::path::PathBuf::from) + else { + panic!("Environment variable DEP_TREE_SITTER_LANGUAGE_WASM_SRC must be set by the language crate"); + }; + + c_config.include(&wasm_headers); + c_config.files([ + wasm_src.join("stdio.c"), + wasm_src.join("stdlib.c"), + wasm_src.join("string.c"), + ]); + } + "#} + .lines() + .map(|line| if line.is_empty() { line.to_string() } else { format!(" {line}") }) + .collect::>() + .join("\n"); + + contents = contents.replace(r#" c_config.flag("-utf-8");"#, &replacement); + } + + // Introduce configuration variables for dynamic query inclusion + if !contents.contains("with_highlights_query") { + info!("Adding support for dynamic query inclusion to bindings/rust/build.rs"); + let replaced = indoc! {r#" + c_config.compile("tree-sitter-KEBAB_PARSER_NAME"); + }"#} + .replace("KEBAB_PARSER_NAME", &language_name.to_kebab_case()); + + let replacement = indoc! {r#" + c_config.compile("tree-sitter-KEBAB_PARSER_NAME"); + + println!("cargo:rustc-check-cfg=cfg(with_highlights_query)"); + if !"HIGHLIGHTS_QUERY_PATH".is_empty() && std::path::Path::new("HIGHLIGHTS_QUERY_PATH").exists() { + println!("cargo:rustc-cfg=with_highlights_query"); + } + println!("cargo:rustc-check-cfg=cfg(with_injections_query)"); + if !"INJECTIONS_QUERY_PATH".is_empty() && std::path::Path::new("INJECTIONS_QUERY_PATH").exists() { + println!("cargo:rustc-cfg=with_injections_query"); + } + println!("cargo:rustc-check-cfg=cfg(with_locals_query)"); + if !"LOCALS_QUERY_PATH".is_empty() && std::path::Path::new("LOCALS_QUERY_PATH").exists() { + println!("cargo:rustc-cfg=with_locals_query"); + } + println!("cargo:rustc-check-cfg=cfg(with_tags_query)"); + if !"TAGS_QUERY_PATH".is_empty() && std::path::Path::new("TAGS_QUERY_PATH").exists() { + println!("cargo:rustc-cfg=with_tags_query"); + } + }"#} + .replace("KEBAB_PARSER_NAME", &language_name.to_kebab_case()) + .replace("HIGHLIGHTS_QUERY_PATH", generate_opts.highlights_query_path) + .replace("INJECTIONS_QUERY_PATH", generate_opts.injections_query_path) + .replace("LOCALS_QUERY_PATH", generate_opts.locals_query_path) + .replace("TAGS_QUERY_PATH", generate_opts.tags_query_path); + + contents = contents.replace( + &replaced, + &replacement, + ); } write_file(path, contents)?; @@ -446,6 +585,7 @@ pub fn generate_grammar_files( |path| { let contents = fs::read_to_string(path)?; if contents.contains("\"LICENSE\"") { + info!("Adding LICENSE entry to bindings/rust/Cargo.toml"); write_file(path, contents.replace("\"LICENSE\"", "\"/LICENSE\""))?; } Ok(()) @@ -465,17 +605,27 @@ pub fn generate_grammar_files( |path| generate_file(path, INDEX_JS_TEMPLATE, language_name, &generate_opts), |path| { let contents = fs::read_to_string(path)?; - if !contents.contains("new URL") { - warn!("Replacing index.js"); + if !contents.contains("Object.defineProperty") { + info!("Replacing index.js"); generate_file(path, INDEX_JS_TEMPLATE, language_name, &generate_opts)?; } Ok(()) }, )?; - missing_path(path.join("index.d.ts"), |path| { - generate_file(path, INDEX_D_TS_TEMPLATE, language_name, &generate_opts) - })?; + missing_path_else( + path.join("index.d.ts"), + allow_update, + |path| generate_file(path, INDEX_D_TS_TEMPLATE, language_name, &generate_opts), + |path| { + let contents = fs::read_to_string(path)?; + if !contents.contains("export default binding") { + info!("Replacing index.d.ts"); + generate_file(path, INDEX_D_TS_TEMPLATE, language_name, &generate_opts)?; + } + Ok(()) + }, + )?; missing_path_else( path.join("binding_test.js"), @@ -491,7 +641,7 @@ pub fn generate_grammar_files( |path| { let contents = fs::read_to_string(path)?; if !contents.contains("import") { - warn!("Replacing binding_test.js"); + info!("Replacing binding_test.js"); generate_file( path, BINDING_TEST_JS_TEMPLATE, @@ -514,6 +664,7 @@ pub fn generate_grammar_files( |path| { let contents = fs::read_to_string(path)?; if contents.contains("fs.exists(") { + info!("Replacing `fs.exists` calls in binding.gyp"); write_file(path, contents.replace("fs.exists(", "fs.existsSync("))?; } Ok(()) @@ -526,14 +677,17 @@ pub fn generate_grammar_files( // Generate C bindings if tree_sitter_config.bindings.c { + let kebab_case_name = language_name.to_kebab_case(); missing_path(bindings_dir.join("c"), create_dir)?.apply(|path| { - let old_file = &path.join(format!("tree-sitter-{}.h", language_name.to_kebab_case())); + let header_name = format!("tree-sitter-{kebab_case_name}.h"); + let old_file = &path.join(&header_name); if allow_update && fs::exists(old_file).unwrap_or(false) { + info!("Removing bindings/c/{header_name}"); fs::remove_file(old_file)?; } missing_path(path.join("tree_sitter"), create_dir)?.apply(|include_path| { missing_path( - include_path.join(format!("tree-sitter-{}.h", language_name.to_kebab_case())), + include_path.join(&header_name), |path| { generate_file(path, PARSER_NAME_H_TEMPLATE, language_name, &generate_opts) }, @@ -542,7 +696,7 @@ pub fn generate_grammar_files( })?; missing_path( - path.join(format!("tree-sitter-{}.pc.in", language_name.to_kebab_case())), + path.join(format!("tree-sitter-{kebab_case_name}.pc.in")), |path| { generate_file( path, @@ -562,23 +716,27 @@ pub fn generate_grammar_files( |path| { let mut contents = fs::read_to_string(path)?; if !contents.contains("cd '$(DESTDIR)$(LIBDIR)' && ln -sf") { - warn!("Replacing Makefile"); + info!("Replacing Makefile"); generate_file(path, MAKEFILE_TEMPLATE, language_name, &generate_opts)?; } else { - contents = contents - .replace( - indoc! {r" - $(PARSER): $(SRC_DIR)/grammar.json - $(TS) generate $^ - "}, - indoc! {r" - $(SRC_DIR)/grammar.json: grammar.js - $(TS) generate --emit=json $^ + let replaced = indoc! {r" + $(PARSER): $(SRC_DIR)/grammar.json + $(TS) generate $^ + "}; + if contents.contains(replaced) { + info!("Adding --no-parser target to Makefile"); + contents = contents + .replace( + replaced, + indoc! {r" + $(SRC_DIR)/grammar.json: grammar.js + $(TS) generate --no-parser $^ - $(PARSER): $(SRC_DIR)/grammar.json - $(TS) generate --emit=parser $^ - "} - ); + $(PARSER): $(SRC_DIR)/grammar.json + $(TS) generate $^ + "} + ); + } write_file(path, contents)?; } Ok(()) @@ -590,8 +748,8 @@ pub fn generate_grammar_files( allow_update, |path| generate_file(path, CMAKELISTS_TXT_TEMPLATE, language_name, &generate_opts), |path| { - let mut contents = fs::read_to_string(path)?; - contents = contents + let contents = fs::read_to_string(path)?; + let replaced_contents = contents .replace("add_custom_target(test", "add_custom_target(ts-test") .replace( &formatdoc! {r#" @@ -622,21 +780,27 @@ pub fn generate_grammar_files( "#}, indoc! {r#" add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/grammar.json" + "${CMAKE_CURRENT_SOURCE_DIR}/src/node-types.json" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/grammar.js" - COMMAND "${TREE_SITTER_CLI}" generate grammar.js - --emit=json + COMMAND "${TREE_SITTER_CLI}" generate grammar.js --no-parser WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMENT "Generating grammar.json") add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/parser.c" + BYPRODUCTS "${CMAKE_CURRENT_SOURCE_DIR}/src/tree_sitter/parser.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/tree_sitter/alloc.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/tree_sitter/array.h" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/grammar.json" COMMAND "${TREE_SITTER_CLI}" generate src/grammar.json - --emit=parser --abi=${TREE_SITTER_ABI_VERSION} + --abi=${TREE_SITTER_ABI_VERSION} WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMENT "Generating parser.c") "#} ); - write_file(path, contents)?; + if !replaced_contents.eq(&contents) { + info!("Updating CMakeLists.txt"); + write_file(path, replaced_contents)?; + } Ok(()) }, )?; @@ -672,7 +836,8 @@ pub fn generate_grammar_files( // Generate Python bindings if tree_sitter_config.bindings.python { missing_path(bindings_dir.join("python"), create_dir)?.apply(|path| { - let lang_path = path.join(format!("tree_sitter_{}", language_name.to_snake_case())); + let snake_case_grammar_name = format!("tree_sitter_{}", language_name.to_snake_case()); + let lang_path = path.join(&snake_case_grammar_name); missing_path(&lang_path, create_dir)?; missing_path_else( @@ -682,6 +847,7 @@ pub fn generate_grammar_files( |path| { let mut contents = fs::read_to_string(path)?; if !contents.contains("PyModuleDef_Init") { + info!("Updating bindings/python/{snake_case_grammar_name}/binding.c"); contents = contents .replace("PyModule_Create", "PyModuleDef_Init") .replace( @@ -714,9 +880,21 @@ pub fn generate_grammar_files( }, )?; - missing_path(lang_path.join("__init__.py"), |path| { - generate_file(path, INIT_PY_TEMPLATE, language_name, &generate_opts) - })?; + missing_path_else( + lang_path.join("__init__.py"), + allow_update, + |path| { + generate_file(path, INIT_PY_TEMPLATE, language_name, &generate_opts) + }, + |path| { + let contents = fs::read_to_string(path)?; + if !contents.contains("uncomment these to include any queries") { + info!("Replacing __init__.py"); + generate_file(path, INIT_PY_TEMPLATE, language_name, &generate_opts)?; + } + Ok(()) + }, + )?; missing_path_else( lang_path.join("__init__.pyi"), @@ -724,7 +902,11 @@ pub fn generate_grammar_files( |path| generate_file(path, INIT_PYI_TEMPLATE, language_name, &generate_opts), |path| { let mut contents = fs::read_to_string(path)?; - if !contents.contains("CapsuleType") { + if contents.contains("uncomment these to include any queries") { + info!("Replacing __init__.pyi"); + generate_file(path, INIT_PYI_TEMPLATE, language_name, &generate_opts)?; + } else if !contents.contains("CapsuleType") { + info!("Updating __init__.pyi"); contents = contents .replace( "from typing import Final", @@ -756,6 +938,7 @@ pub fn generate_grammar_files( |path| { let mut contents = fs::read_to_string(path)?; if !contents.contains("Parser(Language(") { + info!("Updating Language function in bindings/python/tests/test_binding.py"); contents = contents .replace("tree_sitter.Language(", "Parser(Language(") .replace(".language())\n", ".language()))\n") @@ -776,11 +959,19 @@ pub fn generate_grammar_files( allow_update, |path| generate_file(path, SETUP_PY_TEMPLATE, language_name, &generate_opts), |path| { - let contents = fs::read_to_string(path)?; + let mut contents = fs::read_to_string(path)?; if !contents.contains("build_ext") { - warn!("Replacing setup.py"); + info!("Replacing setup.py"); generate_file(path, SETUP_PY_TEMPLATE, language_name, &generate_opts)?; } + if !contents.contains(" and not get_config_var") { + info!("Updating Python free-threading support in setup.py"); + contents = contents.replace( + r#"startswith("cp"):"#, + r#"startswith("cp") and not get_config_var("Py_GIL_DISABLED"):"# + ); + write_file(path, contents)?; + } Ok(()) }, )?; @@ -799,6 +990,7 @@ pub fn generate_grammar_files( |path| { let mut contents = fs::read_to_string(path)?; if !contents.contains("cp310-*") { + info!("Updating dependencies in pyproject.toml"); contents = contents .replace(r#"build = "cp39-*""#, r#"build = "cp310-*""#) .replace(r#"python = ">=3.9""#, r#"python = ">=3.10""#) @@ -836,15 +1028,18 @@ pub fn generate_grammar_files( allow_update, |path| generate_file(path, PACKAGE_SWIFT_TEMPLATE, language_name, &generate_opts), |path| { - let mut contents = fs::read_to_string(path)?; - contents = contents + let contents = fs::read_to_string(path)?; + let replaced_contents = contents .replace( "https://github.com/ChimeHQ/SwiftTreeSitter", "https://github.com/tree-sitter/swift-tree-sitter", ) .replace("version: \"0.8.0\")", "version: \"0.9.0\")") .replace("(url:", "(name: \"SwiftTreeSitter\", url:"); - write_file(path, contents)?; + if !replaced_contents.eq(&contents) { + info!("Updating tree-sitter dependency in Package.swift"); + write_file(path, contents)?; + } Ok(()) }, )?; @@ -862,7 +1057,7 @@ pub fn generate_grammar_files( |path| { let contents = fs::read_to_string(path)?; if !contents.contains("b.pkg_hash.len") { - warn!("Replacing build.zig"); + info!("Replacing build.zig"); generate_file(path, BUILD_ZIG_TEMPLATE, language_name, &generate_opts) } else { Ok(()) @@ -877,7 +1072,7 @@ pub fn generate_grammar_files( |path| { let contents = fs::read_to_string(path)?; if !contents.contains(".name = .tree_sitter_") { - warn!("Replacing build.zig.zon"); + info!("Replacing build.zig.zon"); generate_file(path, BUILD_ZIG_ZON_TEMPLATE, language_name, &generate_opts) } else { Ok(()) @@ -893,7 +1088,7 @@ pub fn generate_grammar_files( |path| { let contents = fs::read_to_string(path)?; if contents.contains("ts.Language") { - warn!("Replacing root.zig"); + info!("Replacing root.zig"); generate_file(path, ROOT_ZIG_TEMPLATE, language_name, &generate_opts) } else { Ok(()) @@ -909,6 +1104,45 @@ pub fn generate_grammar_files( })?; } + // Generate Java bindings + if tree_sitter_config.bindings.java { + missing_path(repo_path.join("pom.xml"), |path| { + generate_file(path, POM_XML_TEMPLATE, language_name, &generate_opts) + })?; + + missing_path(bindings_dir.join("java"), create_dir)?.apply(|path| { + missing_path(path.join("main"), create_dir)?.apply(|path| { + let package_path = generate_opts + .namespace + .unwrap_or("io.github.treesitter") + .replace(['-', '_'], "") + .split('.') + .fold(path.to_path_buf(), |path, dir| path.join(dir)) + .join("jtreesitter") + .join(language_name.to_lowercase().replace('_', "")); + missing_path(package_path, create_dir)?.apply(|path| { + missing_path(path.join(format!("{class_name}.java")), |path| { + generate_file(path, BINDING_JAVA_TEMPLATE, language_name, &generate_opts) + })?; + + Ok(()) + })?; + + Ok(()) + })?; + + missing_path(path.join("test"), create_dir)?.apply(|path| { + missing_path(path.join(format!("{class_name}Test.java")), |path| { + generate_file(path, TEST_JAVA_TEMPLATE, language_name, &generate_opts) + })?; + + Ok(()) + })?; + + Ok(()) + })?; + } + Ok(()) } @@ -958,6 +1192,15 @@ fn generate_file( ) -> Result<()> { let filename = path.file_name().unwrap().to_str().unwrap(); + let lower_parser_name = if path + .extension() + .is_some_and(|e| e.eq_ignore_ascii_case("java")) + { + language_name.to_snake_case().replace('_', "") + } else { + language_name.to_snake_case() + }; + let mut replacement = template .replace( CAMEL_PARSER_NAME_PLACEHOLDER, @@ -971,14 +1214,11 @@ fn generate_file( UPPER_PARSER_NAME_PLACEHOLDER, &language_name.to_shouty_snake_case(), ) - .replace( - LOWER_PARSER_NAME_PLACEHOLDER, - &language_name.to_snake_case(), - ) .replace( KEBAB_PARSER_NAME_PLACEHOLDER, &language_name.to_kebab_case(), ) + .replace(LOWER_PARSER_NAME_PLACEHOLDER, &lower_parser_name) .replace(PARSER_NAME_PLACEHOLDER, language_name) .replace(CLI_VERSION_PLACEHOLDER, CLI_VERSION) .replace(RUST_BINDING_VERSION_PLACEHOLDER, RUST_BINDING_VERSION) @@ -987,7 +1227,20 @@ fn generate_file( PARSER_VERSION_PLACEHOLDER, &generate_opts.version.to_string(), ) - .replace(PARSER_CLASS_NAME_PLACEHOLDER, generate_opts.class_name); + .replace(PARSER_CLASS_NAME_PLACEHOLDER, generate_opts.class_name) + .replace( + HIGHLIGHTS_QUERY_PATH_PLACEHOLDER, + generate_opts.highlights_query_path, + ) + .replace( + INJECTIONS_QUERY_PATH_PLACEHOLDER, + generate_opts.injections_query_path, + ) + .replace( + LOCALS_QUERY_PATH_PLACEHOLDER, + generate_opts.locals_query_path, + ) + .replace(TAGS_QUERY_PATH_PLACEHOLDER, generate_opts.tags_query_path); if let Some(name) = generate_opts.author_name { replacement = replacement.replace(AUTHOR_NAME_PLACEHOLDER, name); @@ -1005,6 +1258,9 @@ fn generate_file( "Cargo.toml" => { replacement = replacement.replace(AUTHOR_NAME_PLACEHOLDER_RS, ""); } + "pom.xml" => { + replacement = replacement.replace(AUTHOR_NAME_PLACEHOLDER_JAVA, ""); + } _ => {} } } @@ -1030,30 +1286,52 @@ fn generate_file( "Cargo.toml" => { replacement = replacement.replace(AUTHOR_EMAIL_PLACEHOLDER_RS, ""); } + "pom.xml" => { + replacement = replacement.replace(AUTHOR_EMAIL_PLACEHOLDER_JAVA, ""); + } _ => {} } } - if filename == "package.json" { - if let Some(url) = generate_opts.author_url { + match (generate_opts.author_url, filename) { + (Some(url), "package.json" | "pom.xml") => { replacement = replacement.replace(AUTHOR_URL_PLACEHOLDER, url); - } else { + } + (None, "package.json") => { replacement = replacement.replace(AUTHOR_URL_PLACEHOLDER_JS, ""); } + (None, "pom.xml") => { + replacement = replacement.replace(AUTHOR_URL_PLACEHOLDER_JAVA, ""); + } + _ => {} } if generate_opts.author_name.is_none() && generate_opts.author_email.is_none() && generate_opts.author_url.is_none() - && filename == "package.json" { - if let Some(start_idx) = replacement.find(AUTHOR_BLOCK_JS) { - if let Some(end_idx) = replacement[start_idx..] - .find("},") - .map(|i| i + start_idx + 2) - { - replacement.replace_range(start_idx..end_idx, ""); + match filename { + "package.json" => { + if let Some(start_idx) = replacement.find(AUTHOR_BLOCK_JS) { + if let Some(end_idx) = replacement[start_idx..] + .find("},") + .map(|i| i + start_idx + 2) + { + replacement.replace_range(start_idx..end_idx, ""); + } + } } + "pom.xml" => { + if let Some(start_idx) = replacement.find(AUTHOR_BLOCK_JAVA) { + if let Some(end_idx) = replacement[start_idx..] + .find("") + .map(|i| i + start_idx + 12) + { + replacement.replace_range(start_idx..end_idx, ""); + } + } + } + _ => {} } } else if generate_opts.author_name.is_none() && generate_opts.author_email.is_none() { match filename { @@ -1134,6 +1412,19 @@ fn generate_file( ); } + if let Some(namespace) = generate_opts.namespace { + replacement = replacement + .replace( + PARSER_NS_CLEANED_PLACEHOLDER, + &namespace.replace(['-', '_'], ""), + ) + .replace(PARSER_NS_PLACEHOLDER, namespace); + } else { + replacement = replacement + .replace(PARSER_NS_CLEANED_PLACEHOLDER, "io.github.treesitter") + .replace(PARSER_NS_PLACEHOLDER, "io.github.tree-sitter"); + } + if let Some(funding_url) = generate_opts.funding { match filename { "pyproject.toml" | "package.json" => { @@ -1153,6 +1444,18 @@ fn generate_file( } } + if filename == "build.zig.zon" { + let id = thread_rng().gen_range(1u32..0xFFFF_FFFFu32); + let checksum = crc32(format!("tree_sitter_{language_name}").as_bytes()); + replacement = replacement.replace( + PARSER_FINGERPRINT_PLACEHOLDER, + #[cfg(target_endian = "little")] + &format!("0x{checksum:x}{id:x}"), + #[cfg(target_endian = "big")] + &format!("0x{id:x}{checksum:x}"), + ); + } + write_file(path, replacement)?; Ok(()) } diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 6a6a202f..fbf75b8e 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -20,18 +20,20 @@ use tree_sitter_cli::{ LOG_GRAPH_ENABLED, START_SEED, }, highlight::{self, HighlightOptions}, - init::{generate_grammar_files, JsonConfigOpts}, + init::{generate_grammar_files, JsonConfigOpts, TREE_SITTER_JSON_SCHEMA}, input::{get_input, get_tmp_source_file, CliInput}, logger, parse::{self, ParseDebugType, ParseFileOptions, ParseOutput, ParseTheme}, - playground, query, + playground, + query::{self, QueryFileOptions}, tags::{self, TagsOptions}, - test::{self, TestOptions, TestStats}, - test_highlight, test_tags, util, version, - version::BumpLevel, + test::{self, TestOptions, TestStats, TestSummary}, + test_highlight, test_tags, util, + version::{self, BumpLevel}, wasm, }; use tree_sitter_config::Config; +use tree_sitter_generate::OptLevel; use tree_sitter_highlight::Highlighter; use tree_sitter_loader::{self as loader, Bindings, TreeSitterJSON}; use tree_sitter_tags::TagsContext; @@ -87,17 +89,6 @@ struct Init { pub grammar_path: Option, } -#[derive(Clone, Debug, Default, ValueEnum, PartialEq, Eq)] -enum GenerationEmit { - /// Generate `grammar.json` and `node-types.json` - Json, - /// Generate `parser.c` and related files - #[default] - Parser, - /// Compile to a library - Lib, -} - #[derive(Args)] #[command(alias = "gen", alias = "g")] struct Generate { @@ -120,28 +111,38 @@ struct Generate { ) )] pub abi_version: Option, - /// What generated files to emit + /// Only generate `grammar.json` and `node-types.json` #[arg(long)] - #[clap(value_enum, default_value_t=GenerationEmit::Parser)] - pub emit: GenerationEmit, - /// Deprecated: use --emit=lib. - #[arg(long, short = 'b', conflicts_with = "emit")] + pub no_parser: bool, + /// Deprecated: use the `build` command + #[arg(long, short = 'b')] pub build: bool, - /// Compile a parser in debug mode + /// Deprecated: use the `build` command #[arg(long, short = '0')] pub debug_build: bool, - /// The path to the directory containing the parser library + /// Deprecated: use the `build` command #[arg(long, value_name = "PATH")] pub libdir: Option, /// The path to output the generated source files #[arg(long, short, value_name = "DIRECTORY")] pub output: Option, /// Produce a report of the states for the given rule, use `-` to report every rule - #[arg(long)] + #[arg(long, conflicts_with = "json", conflicts_with = "json_summary")] pub report_states_for_rule: Option, - /// Report conflicts in a JSON format - #[arg(long)] + /// Deprecated: use --json-summary + #[arg( + long, + conflicts_with = "json_summary", + conflicts_with = "report_states_for_rule" + )] pub json: bool, + /// Report conflicts in a JSON format + #[arg( + long, + conflicts_with = "json", + conflicts_with = "report_states_for_rule" + )] + pub json_summary: bool, /// The name or path of the JavaScript runtime to use for generating parsers #[cfg(not(feature = "qjs-rt"))] #[arg( @@ -162,6 +163,11 @@ struct Generate { /// The name or path of the JavaScript runtime to use for generating parsers, specify `native` /// to use the native `QuickJS` runtime pub js_runtime: Option, + + /// Disable optimizations when generating the parser. Currently, this only affects + /// the merging of compatible parse states. + #[arg(long)] + pub disable_optimizations: bool, } #[derive(Args)] @@ -217,7 +223,7 @@ struct Parse { #[arg(long, short = 'D')] pub debug_graph: bool, /// Compile parsers to Wasm instead of native dynamic libraries - #[arg(long)] + #[arg(long, hide = cfg!(not(feature = "wasm")))] pub wasm: bool, /// Output the parse data with graphviz dot #[arg(long = "dot")] @@ -229,7 +235,7 @@ struct Parse { #[arg(long = "cst", short = 'c')] pub output_cst: bool, /// Show parsing statistic - #[arg(long, short)] + #[arg(long, short, conflicts_with = "json", conflicts_with = "json_summary")] pub stat: bool, /// Interrupt the parsing process by timeout (µs) #[arg(long)] @@ -254,9 +260,12 @@ struct Parse { /// Open `log.html` in the default browser, if `--debug-graph` is supplied #[arg(long)] pub open_log: bool, - /// Output parsing results in a JSON format - #[arg(long, short = 'j')] + /// Deprecated: use --json-summary + #[arg(long, conflicts_with = "json_summary", conflicts_with = "stat")] pub json: bool, + /// Output parsing results in a JSON format + #[arg(long, short = 'j', conflicts_with = "json", conflicts_with = "stat")] + pub json_summary: bool, /// The path to an alternative config.json file #[arg(long)] pub config_path: Option, @@ -314,7 +323,7 @@ struct Test { #[arg(long, short = 'D')] pub debug_graph: bool, /// Compile parsers to Wasm instead of native dynamic libraries - #[arg(long)] + #[arg(long, hide = cfg!(not(feature = "wasm")))] pub wasm: bool, /// Open `log.html` in the default browser, if `--debug-graph` is supplied #[arg(long)] @@ -334,6 +343,9 @@ struct Test { /// Show only the pass-fail overview tree #[arg(long)] pub overview_only: bool, + /// Output the test summary in a JSON format + #[arg(long)] + pub json_summary: bool, } #[derive(Args)] @@ -436,6 +448,14 @@ struct Query { /// The range of rows in which the query will be executed #[arg(long)] pub row_range: Option, + /// The range of byte offsets in which the query will be executed. Only the matches that are fully contained within the provided + /// byte range will be returned. + #[arg(long)] + pub containing_byte_range: Option, + /// The range of rows in which the query will be executed. Only the matches that are fully contained within the provided row range + /// will be returned. + #[arg(long)] + pub containing_row_range: Option, /// Select a language by the scope instead of a file extension #[arg(long)] pub scope: Option, @@ -577,6 +597,20 @@ pub enum Shell { Nushell, } +/// Complete `action` if the wasm feature is enabled, otherwise return an error +macro_rules! checked_wasm { + ($action:block) => { + #[cfg(feature = "wasm")] + { + $action + } + #[cfg(not(feature = "wasm"))] + { + Err(anyhow!("--wasm flag specified, but this build of tree-sitter-cli does not include the wasm feature"))?; + } + }; +} + impl InitConfig { fn run() -> Result<()> { if let Ok(Some(config_path)) = Config::find_config_file() { @@ -738,6 +772,14 @@ impl Init { .map(|e| Some(e.trim().to_string())) }; + let namespace = || { + Input::::with_theme(&ColorfulTheme::default()) + .with_prompt("Package namespace") + .default("io.github.tree-sitter".to_string()) + .allow_empty(true) + .interact() + }; + let bindings = || { let languages = Bindings::default().languages(); @@ -767,6 +809,7 @@ impl Init { "author", "email", "url", + "namespace", "bindings", "exit", ]; @@ -787,6 +830,7 @@ impl Init { "author" => opts.author = author()?, "email" => opts.email = email()?, "url" => opts.url = url()?, + "namespace" => opts.namespace = Some(namespace()?), "bindings" => opts.bindings = bindings()?, "exit" => break, _ => unreachable!(), @@ -823,10 +867,26 @@ impl Init { (opts.name.clone(), Some(opts)) } else { - let mut json = serde_json::from_str::( - &fs::read_to_string(current_dir.join("tree-sitter.json")) - .with_context(|| "Failed to read tree-sitter.json")?, - )?; + let old_config = fs::read_to_string(current_dir.join("tree-sitter.json")) + .with_context(|| "Failed to read tree-sitter.json")?; + + let mut json = serde_json::from_str::(&old_config)?; + if json.schema.is_none() { + json.schema = Some(TREE_SITTER_JSON_SCHEMA.to_string()); + } + + let new_config = format!("{}\n", serde_json::to_string_pretty(&json)?); + // Write the re-serialized config back, as newly added optional boolean fields + // will be included with explicit `false`s rather than implict `null`s + if self.update && !old_config.trim().eq(new_config.trim()) { + info!("Updating tree-sitter.json"); + fs::write( + current_dir.join("tree-sitter.json"), + serde_json::to_string_pretty(&json)?, + ) + .with_context(|| "Failed to write tree-sitter.json")?; + } + (json.grammars.swap_remove(0).name, None) }; @@ -856,9 +916,13 @@ impl Generate { version.parse().expect("invalid abi version flag") } }); - if self.build { - warn!("--build is deprecated, use --emit=lib instead"); - } + + let json_summary = if self.json { + warn!("--json is deprecated, use --json-summary instead"); + true + } else { + self.json_summary + }; if let Err(err) = tree_sitter_generate::generate_parser_in_directory( current_dir, @@ -867,9 +931,14 @@ impl Generate { abi_version, self.report_states_for_rule.as_deref(), self.js_runtime.as_deref(), - self.emit != GenerationEmit::Json, + !self.no_parser, + if self.disable_optimizations { + OptLevel::empty() + } else { + OptLevel::default() + }, ) { - if self.json { + if json_summary { eprintln!("{}", serde_json::to_string_pretty(&err)?); // Exit early to prevent errors from being printed a second time in the caller std::process::exit(1); @@ -878,7 +947,8 @@ impl Generate { Err(anyhow!(err.to_string())).with_context(|| "Error when generating parser")?; } } - if self.emit == GenerationEmit::Lib || self.build { + if self.build { + warn!("--build is deprecated, use the `build` command"); if let Some(path) = self.libdir { loader = loader::Loader::with_parser_lib_path(path); } @@ -901,11 +971,21 @@ impl Build { } else { let output_path = if let Some(ref path) = self.output { let path = Path::new(path); - if path.is_absolute() { + let full_path = if path.is_absolute() { path.to_path_buf() } else { current_dir.join(path) - } + }; + let parent_path = full_path + .parent() + .context("Output path must have a parent")?; + let name = full_path + .file_name() + .context("Ouput path must have a filename")?; + fs::create_dir_all(parent_path).context("Failed to create output path")?; + let mut canon_path = parent_path.canonicalize().context("Invalid output path")?; + canon_path.push(name); + canon_path } else { let file_name = grammar_path .file_stem() @@ -928,12 +1008,9 @@ impl Build { loader.force_rebuild(true); - let config = Config::load(None)?; - let loader_config = config.get()?; - loader.find_all_languages(&loader_config).unwrap(); loader .compile_parser_at_path(&grammar_path, output_path, flags) - .unwrap(); + .context("Failed to compile parser")?; } Ok(()) } @@ -943,13 +1020,19 @@ impl Parse { fn run(self, mut loader: loader::Loader, current_dir: &Path) -> Result<()> { let config = Config::load(self.config_path)?; let color = env::var("NO_COLOR").map_or(true, |v| v != "1"); + let json_summary = if self.json { + warn!("--json is deprecated, use --json-summary instead"); + true + } else { + self.json_summary + }; let output = if self.output_dot { ParseOutput::Dot } else if self.output_xml { ParseOutput::Xml } else if self.output_cst { ParseOutput::Cst - } else if self.quiet || self.json { + } else if self.quiet || json_summary { ParseOutput::Quiet } else { ParseOutput::Normal @@ -980,13 +1063,14 @@ impl Parse { loader.debug_build(self.debug_build); loader.force_rebuild(self.rebuild || self.grammar_path.is_some()); - #[cfg(feature = "wasm")] if self.wasm { - let engine = tree_sitter::wasmtime::Engine::default(); - parser - .set_wasm_store(tree_sitter::WasmStore::new(&engine).unwrap()) - .unwrap(); - loader.use_wasm(&engine); + checked_wasm!({ + let engine = tree_sitter::wasmtime::Engine::default(); + parser + .set_wasm_store(tree_sitter::WasmStore::new(&engine).unwrap()) + .unwrap(); + loader.use_wasm(&engine); + }); } let timeout = self.timeout.unwrap_or_default(); @@ -1023,7 +1107,7 @@ impl Parse { let mut update_stats = |stats: &mut parse::ParseStats| { let parse_result = stats.parse_summaries.last().unwrap(); - if should_track_stats { + if should_track_stats || json_summary { stats.cumulative_stats.total_parses += 1; if parse_result.successful { stats.cumulative_stats.successful_parses += 1; @@ -1055,18 +1139,19 @@ impl Parse { .map(|p| p.to_string_lossy().chars().count()) .max() .unwrap_or(0); + options.stats.source_count = paths.len(); for path in &paths { let path = Path::new(&path); let language = loader .select_language( - path, + Some(path), current_dir, self.scope.as_deref(), lib_info.as_ref(), ) .with_context(|| { - anyhow!("Failed to load langauge for path \"{}\"", path.display()) + anyhow!("Failed to load language for path \"{}\"", path.display()) })?; parse::parse_file_at_path( @@ -1091,7 +1176,12 @@ impl Parse { let language = if let Some(ref lib_path) = self.lib_path { &loader - .select_language(lib_path, current_dir, None, lib_info.as_ref()) + .select_language( + None, + current_dir, + self.scope.as_deref(), + lib_info.as_ref(), + ) .with_context(|| { anyhow!( "Failed to load language for path \"{}\"", @@ -1125,8 +1215,12 @@ impl Parse { let path = get_tmp_source_file(&contents)?; let name = "stdin"; - let language = - loader.select_language(&path, current_dir, None, lib_info.as_ref())?; + let language = loader.select_language( + None, + current_dir, + self.scope.as_deref(), + lib_info.as_ref(), + )?; parse::parse_file_at_path( &mut parser, @@ -1144,7 +1238,7 @@ impl Parse { if should_track_stats { println!("\n{}", stats.cumulative_stats); } - if self.json { + if json_summary { println!("{}", serde_json::to_string_pretty(&stats)?); } @@ -1156,6 +1250,28 @@ impl Parse { } } +/// In case an error is encountered, prints out the contents of `test_summary` and +/// propagates the error +fn check_test( + test_result: Result<()>, + test_summary: &TestSummary, + json_summary: bool, +) -> Result<()> { + if let Err(e) = test_result { + if json_summary { + let json_summary = serde_json::to_string_pretty(test_summary) + .expect("Failed to encode summary to JSON"); + println!("{json_summary}"); + } else { + println!("{test_summary}"); + } + + Err(e)?; + } + + Ok(()) +} + impl Test { fn run(self, mut loader: loader::Loader, current_dir: &Path) -> Result<()> { let config = Config::load(self.config_path)?; @@ -1167,13 +1283,14 @@ impl Test { let mut parser = Parser::new(); - #[cfg(feature = "wasm")] if self.wasm { - let engine = tree_sitter::wasmtime::Engine::default(); - parser - .set_wasm_store(tree_sitter::WasmStore::new(&engine).unwrap()) - .unwrap(); - loader.use_wasm(&engine); + checked_wasm!({ + let engine = tree_sitter::wasmtime::Engine::default(); + parser + .set_wasm_store(tree_sitter::WasmStore::new(&engine).unwrap()) + .unwrap(); + loader.use_wasm(&engine); + }); } if self.lib_path.is_none() && self.lang_name.is_some() { @@ -1184,7 +1301,7 @@ impl Test { let lib_info = get_lib_info(self.lib_path.as_ref(), self.lang_name.as_ref(), current_dir); &loader - .select_language(lib_path, current_dir, None, lib_info.as_ref()) + .select_language(None, current_dir, None, lib_info.as_ref()) .with_context(|| { anyhow!( "Failed to load language for path \"{}\"", @@ -1200,15 +1317,18 @@ impl Test { parser.set_language(language)?; let test_dir = current_dir.join("test"); - let mut stats = parse::Stats::default(); + let mut test_summary = TestSummary::new( + color, + stat, + self.update, + self.overview_only, + self.json_summary, + ); // Run the corpus tests. Look for them in `test/corpus`. let test_corpus_dir = test_dir.join("corpus"); if test_corpus_dir.is_dir() { - let mut output = String::new(); - let mut rates = Vec::new(); - let mut opts = TestOptions { - output: &mut output, + let opts = TestOptions { path: test_corpus_dir, debug: self.debug, debug_graph: self.debug_graph, @@ -1219,51 +1339,67 @@ impl Test { open_log: self.open_log, languages: languages.iter().map(|(l, n)| (n.as_str(), l)).collect(), color, - test_num: 1, - parse_rates: &mut rates, - stat_display: stat, - stats: &mut stats, show_fields: self.show_fields, overview_only: self.overview_only, }; - test::run_tests_at_path(&mut parser, &mut opts)?; - println!("\n{stats}"); + check_test( + test::run_tests_at_path(&mut parser, &opts, &mut test_summary), + &test_summary, + self.json_summary, + )?; + test_summary.test_num = 1; } // Check that all of the queries are valid. - test::check_queries_at_path(language, ¤t_dir.join("queries"))?; + let query_dir = current_dir.join("queries"); + check_test( + test::check_queries_at_path(language, &query_dir), + &test_summary, + self.json_summary, + )?; + test_summary.test_num = 1; // Run the syntax highlighting tests. let test_highlight_dir = test_dir.join("highlight"); if test_highlight_dir.is_dir() { let mut highlighter = Highlighter::new(); highlighter.parser = parser; - test_highlight::test_highlights( - &loader, - &config.get()?, - &mut highlighter, - &test_highlight_dir, - color, + check_test( + test_highlight::test_highlights( + &loader, + &config.get()?, + &mut highlighter, + &test_highlight_dir, + &mut test_summary, + ), + &test_summary, + self.json_summary, )?; parser = highlighter.parser; + test_summary.test_num = 1; } let test_tag_dir = test_dir.join("tags"); if test_tag_dir.is_dir() { let mut tags_context = TagsContext::new(); tags_context.parser = parser; - test_tags::test_tags( - &loader, - &config.get()?, - &mut tags_context, - &test_tag_dir, - color, + check_test( + test_tags::test_tags( + &loader, + &config.get()?, + &mut tags_context, + &test_tag_dir, + &mut test_summary, + ), + &test_summary, + self.json_summary, )?; + test_summary.test_num = 1; } // For the rest of the queries, find their tests and run them - for entry in walkdir::WalkDir::new(current_dir.join("queries")) + for entry in walkdir::WalkDir::new(&query_dir) .into_iter() .filter_map(|e| e.ok()) .filter(|e| e.file_type().is_file()) @@ -1286,34 +1422,48 @@ impl Test { }) .collect::>(); if !entries.is_empty() { - println!("{stem}:"); + test_summary.query_results.add_group(stem); } - for entry in entries { + test_summary.test_num = 1; + let opts = QueryFileOptions::default(); + for entry in &entries { let path = entry.path(); - query::query_file_at_path( - language, - path, - &path.display().to_string(), - path, - false, - None, - None, - true, - false, - false, - false, + check_test( + query::query_file_at_path( + language, + path, + &path.display().to_string(), + path, + &opts, + Some(&mut test_summary), + ), + &test_summary, + self.json_summary, )?; } + if !entries.is_empty() { + test_summary.query_results.pop_traversal(); + } } } + test_summary.test_num = 1; + + if self.json_summary { + let json_summary = serde_json::to_string_pretty(&test_summary) + .expect("Failed to encode test summary to JSON"); + println!("{json_summary}"); + } else { + println!("{test_summary}"); + } + Ok(()) } } impl Version { fn run(self, current_dir: PathBuf) -> Result<()> { - version::Version::new(self.version, current_dir, self.bump).run() + Ok(version::Version::new(self.version, current_dir, self.bump).run()?) } } @@ -1332,7 +1482,7 @@ impl Fuzz { let lang_name = lib_info.1.to_string(); &( loader - .select_language(lib_path, current_dir, None, Some(&lib_info)) + .select_language(None, current_dir, None, Some(&lib_info)) .with_context(|| { anyhow!( "Failed to load language for path \"{}\"", @@ -1377,18 +1527,11 @@ impl Query { loader.find_all_languages(&loader_config)?; let query_path = Path::new(&self.query_path); - let byte_range = self.byte_range.as_ref().and_then(|range| { - let mut parts = range.split(':'); - let start = parts.next()?.parse().ok()?; - let end = parts.next().unwrap().parse().ok()?; - Some(start..end) - }); - let point_range = self.row_range.as_ref().and_then(|range| { - let mut parts = range.split(':'); - let start = parts.next()?.parse().ok()?; - let end = parts.next().unwrap().parse().ok()?; - Some(Point::new(start, 0)..Point::new(end, 0)) - }); + let byte_range = parse_range(&self.byte_range, |x| x)?; + let point_range = parse_range(&self.row_range, |row| Point::new(row, 0))?; + let containing_byte_range = parse_range(&self.containing_byte_range, |x| x)?; + let containing_point_range = + parse_range(&self.containing_row_range, |row| Point::new(row, 0))?; let cancellation_flag = util::cancel_on_signal(); @@ -1407,25 +1550,30 @@ impl Query { match input { CliInput::Paths(paths) => { let language = loader.select_language( - Path::new(&paths[0]), + Some(Path::new(&paths[0])), current_dir, self.scope.as_deref(), lib_info.as_ref(), )?; + let opts = QueryFileOptions { + ordered_captures: self.captures, + byte_range, + point_range, + containing_byte_range, + containing_point_range, + quiet: self.quiet, + print_time: self.time, + stdin: false, + }; for path in paths { query::query_file_at_path( &language, &path, &path.display().to_string(), query_path, - self.captures, - byte_range.clone(), - point_range.clone(), - self.test, - self.quiet, - self.time, - false, + &opts, + None, )?; } } @@ -1438,7 +1586,7 @@ impl Query { let languages = loader.languages_at_path(current_dir)?; let language = if let Some(ref lib_path) = self.lib_path { &loader - .select_language(lib_path, current_dir, None, lib_info.as_ref()) + .select_language(None, current_dir, None, lib_info.as_ref()) .with_context(|| { anyhow!( "Failed to load language for path \"{}\"", @@ -1453,19 +1601,17 @@ impl Query { .map(|(l, _)| l.clone()) .ok_or_else(|| anyhow!("No language found"))? }; - query::query_file_at_path( - language, - &path, - &name, - query_path, - self.captures, + let opts = QueryFileOptions { + ordered_captures: self.captures, byte_range, point_range, - self.test, - self.quiet, - self.time, - true, - )?; + containing_byte_range, + containing_point_range, + quiet: self.quiet, + print_time: self.time, + stdin: true, + }; + query::query_file_at_path(language, &path, &name, query_path, &opts, None)?; fs::remove_file(path)?; } CliInput::Stdin(contents) => { @@ -1474,20 +1620,18 @@ impl Query { let path = get_tmp_source_file(&contents)?; let language = - loader.select_language(&path, current_dir, None, lib_info.as_ref())?; - query::query_file_at_path( - &language, - &path, - "stdin", - query_path, - self.captures, + loader.select_language(None, current_dir, None, lib_info.as_ref())?; + let opts = QueryFileOptions { + ordered_captures: self.captures, byte_range, point_range, - self.test, - self.quiet, - self.time, - true, - )?; + containing_byte_range, + containing_point_range, + quiet: self.quiet, + print_time: self.time, + stdin: true, + }; + query::query_file_at_path(&language, &path, "stdin", query_path, &opts, None)?; fs::remove_file(path)?; } } @@ -1504,6 +1648,7 @@ impl Highlight { let loader_config = config.get()?; loader.find_all_languages(&loader_config)?; loader.force_rebuild(self.rebuild || self.grammar_path.is_some()); + let languages = loader.languages_at_path(current_dir)?; let cancellation_flag = util::cancel_on_signal(); @@ -1584,7 +1729,6 @@ impl Highlight { } => { let path = get_tmp_source_file(&contents)?; - let languages = loader.languages_at_path(current_dir)?; let language = languages .iter() .find(|(_, n)| language_names.contains(&Box::from(n.as_str()))) @@ -1615,7 +1759,6 @@ impl Highlight { if let (Some(l), Some(lc)) = (language.clone(), language_configuration) { (l, lc) } else { - let languages = loader.languages_at_path(current_dir)?; let language = languages .first() .map(|(l, _)| l.clone()) @@ -1988,3 +2131,32 @@ fn get_lib_info<'a>( None } } + +/// Parse a range string of the form "start:end" into an optional Range. +fn parse_range( + range_str: &Option, + make: impl Fn(usize) -> T, +) -> Result>> { + if let Some(range) = range_str.as_ref() { + let err_msg = format!("Invalid range '{range}', expected 'start:end'"); + let mut parts = range.split(':'); + + let Some(part) = parts.next() else { + Err(anyhow!(err_msg))? + }; + let Ok(start) = part.parse::() else { + Err(anyhow!(err_msg))? + }; + + let Some(part) = parts.next() else { + Err(anyhow!(err_msg))? + }; + let Ok(end) = part.parse::() else { + Err(anyhow!(err_msg))? + }; + + Ok(Some(make(start)..make(end))) + } else { + Ok(None) + } +} diff --git a/crates/cli/src/parse.rs b/crates/cli/src/parse.rs index e1ee20c4..3551f556 100644 --- a/crates/cli/src/parse.rs +++ b/crates/cli/src/parse.rs @@ -11,6 +11,7 @@ use anstyle::{AnsiColor, Color, RgbColor}; use anyhow::{anyhow, Context, Result}; use clap::ValueEnum; use log::info; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use tree_sitter::{ ffi, InputEdit, Language, LogType, ParseOptions, ParseState, Parser, Point, Range, Tree, @@ -19,7 +20,7 @@ use tree_sitter::{ use crate::{fuzz::edits::Edit, logger::paint, util}; -#[derive(Debug, Default, Serialize)] +#[derive(Debug, Default, Serialize, JsonSchema)] pub struct Stats { pub successful_parses: usize, pub total_parses: usize, @@ -230,10 +231,21 @@ impl ParseSummary { } } -#[derive(Serialize, Debug, Default)] +#[derive(Serialize, Debug)] pub struct ParseStats { pub parse_summaries: Vec, pub cumulative_stats: Stats, + pub source_count: usize, +} + +impl Default for ParseStats { + fn default() -> Self { + Self { + parse_summaries: Vec::new(), + cumulative_stats: Stats::default(), + source_count: 1, + } + } } #[derive(Serialize, ValueEnum, Debug, Copy, Clone, Default, Eq, PartialEq)] @@ -503,16 +515,22 @@ pub fn parse_file_at_path( if opts.output == ParseOutput::Cst { render_cst(&source_code, &tree, &mut cursor, opts, &mut stdout)?; - println!(); } if opts.output == ParseOutput::Xml { let mut needs_newline = false; - let mut indent_level = 0; + let mut indent_level = 2; let mut did_visit_children = false; let mut had_named_children = false; let mut tags = Vec::<&str>::new(); - writeln!(&mut stdout, "")?; + + // If we're parsing the first file, write the header + if opts.stats.parse_summaries.is_empty() { + writeln!(&mut stdout, "")?; + writeln!(&mut stdout, "")?; + } + writeln!(&mut stdout, " ", path.display())?; + loop { let node = cursor.node(); let is_named = node.is_named(); @@ -591,8 +609,14 @@ pub fn parse_file_at_path( } } } + writeln!(&mut stdout)?; + writeln!(&mut stdout, " ")?; + + // If we parsed the last file, write the closing tag for the `sources` header + if opts.stats.parse_summaries.len() == opts.stats.source_count - 1 { + writeln!(&mut stdout, "")?; + } cursor.reset(tree.root_node()); - println!(); } if opts.output == ParseOutput::Dot { @@ -650,10 +674,9 @@ pub fn parse_file_at_path( width = max_path_length )?; if let Some(node) = first_error { - let start = node.start_position(); - let end = node.end_position(); - let mut node_text = String::new(); - for c in node.kind().chars() { + let node_kind = node.kind(); + let mut node_text = String::with_capacity(node_kind.len()); + for c in node_kind.chars() { if let Some(escaped) = escape_invisible(c) { node_text += escaped; } else { @@ -670,6 +693,9 @@ pub fn parse_file_at_path( } else { write!(&mut stdout, "{node_text}")?; } + + let start = node.start_position(); + let end = node.end_position(); write!( &mut stdout, " [{}, {}] - [{}, {}])", @@ -758,7 +784,7 @@ pub fn render_cst<'a, 'b: 'a>( .map(|(row, col)| (row as f64).log10() as usize + (col.len() as f64).log10() as usize + 1) .max() .unwrap_or(1); - let mut indent_level = 1; + let mut indent_level = usize::from(!opts.no_ranges); let mut did_visit_children = false; let mut in_error = false; loop { @@ -856,35 +882,24 @@ fn write_node_text( 0 }; let formatted_line = render_line_feed(line, opts); - if !opts.no_ranges { - write!( - out, - "{}{}{}{}{}{}", - if multiline { "\n" } else { "" }, - if multiline { - render_node_range(opts, cursor, is_named, true, total_width, node_range) - } else { - String::new() - }, - if multiline { - " ".repeat(indent_level + 1) - } else { - String::new() - }, - paint(quote_color, &String::from(quote)), - &paint(color, &render_node_text(&formatted_line)), - paint(quote_color, &String::from(quote)), - )?; - } else { - write!( - out, - "\n{}{}{}{}", - " ".repeat(indent_level + 1), - paint(quote_color, &String::from(quote)), - &paint(color, &render_node_text(&formatted_line)), - paint(quote_color, &String::from(quote)), - )?; - } + write!( + out, + "{}{}{}{}{}{}", + if multiline { "\n" } else { " " }, + if multiline && !opts.no_ranges { + render_node_range(opts, cursor, is_named, true, total_width, node_range) + } else { + String::new() + }, + if multiline { + " ".repeat(indent_level + 1) + } else { + String::new() + }, + paint(quote_color, &String::from(quote)), + paint(color, &render_node_text(&formatted_line)), + paint(quote_color, &String::from(quote)), + )?; } } @@ -938,7 +953,7 @@ fn render_node_range( fn cst_render_node( opts: &ParseFileOptions, - cursor: &mut TreeCursor, + cursor: &TreeCursor, source_code: &[u8], out: &mut impl Write, total_width: usize, @@ -984,10 +999,9 @@ fn cst_render_node( } else { opts.parse_theme.node_kind }; - write!(out, "{}", paint(kind_color, node.kind()),)?; + write!(out, "{}", paint(kind_color, node.kind()))?; if node.child_count() == 0 { - write!(out, " ")?; // Node text from a pattern or external scanner write_node_text( opts, diff --git a/crates/cli/src/playground.html b/crates/cli/src/playground.html index 6f90e030..147516ac 100644 --- a/crates/cli/src/playground.html +++ b/crates/cli/src/playground.html @@ -19,7 +19,8 @@ --light-scrollbar-track: #f1f1f1; --light-scrollbar-thumb: #c1c1c1; --light-scrollbar-thumb-hover: #a8a8a8; - + --light-tree-row-bg: #e3f2fd; + --dark-bg: #1d1f21; --dark-border: #2d2d2d; --dark-text: #c5c8c6; @@ -28,6 +29,7 @@ --dark-scrollbar-track: #25282c; --dark-scrollbar-thumb: #4a4d51; --dark-scrollbar-thumb-hover: #5a5d61; + --dark-tree-row-bg: #373737; --primary-color: #0550ae; --primary-color-alpha: rgba(5, 80, 174, 0.1); @@ -42,6 +44,7 @@ --text-color: var(--dark-text); --panel-bg: var(--dark-panel-bg); --code-bg: var(--dark-code-bg); + --tree-row-bg: var(--dark-tree-row-bg); } [data-theme="light"] { @@ -50,6 +53,7 @@ --text-color: var(--light-text); --panel-bg: white; --code-bg: white; + --tree-row-bg: var(--light-tree-row-bg); } /* Base Styles */ @@ -275,7 +279,7 @@ } #output-container a.highlighted { - background-color: #d9d9d9; + background-color: #cae2ff; color: red; border-radius: 3px; text-decoration: underline; @@ -346,7 +350,7 @@ } & #output-container a.highlighted { - background-color: #373b41; + background-color: #656669; color: red; } @@ -373,6 +377,9 @@ color: var(--dark-text); } } + .tree-row:has(.highlighted) { + background-color: var(--tree-row-bg); + } diff --git a/crates/cli/src/query.rs b/crates/cli/src/query.rs index ea074b75..54674115 100644 --- a/crates/cli/src/query.rs +++ b/crates/cli/src/query.rs @@ -6,30 +6,35 @@ use std::{ time::Instant, }; -use anstyle::AnsiColor; use anyhow::{Context, Result}; use log::warn; use streaming_iterator::StreamingIterator; use tree_sitter::{Language, Parser, Point, Query, QueryCursor}; use crate::{ - logger::paint, query_testing::{self, to_utf8_point}, + test::{TestInfo, TestOutcome, TestResult, TestSummary}, }; -#[allow(clippy::too_many_arguments)] +#[derive(Default)] +pub struct QueryFileOptions { + pub ordered_captures: bool, + pub byte_range: Option>, + pub point_range: Option>, + pub containing_byte_range: Option>, + pub containing_point_range: Option>, + pub quiet: bool, + pub print_time: bool, + pub stdin: bool, +} + pub fn query_file_at_path( language: &Language, path: &Path, name: &str, query_path: &Path, - ordered_captures: bool, - byte_range: Option>, - point_range: Option>, - should_test: bool, - quiet: bool, - print_time: bool, - stdin: bool, + opts: &QueryFileOptions, + test_summary: Option<&mut TestSummary>, ) -> Result<()> { let stdout = io::stdout(); let mut stdout = stdout.lock(); @@ -39,19 +44,26 @@ pub fn query_file_at_path( let query = Query::new(language, &query_source).with_context(|| "Query compilation failed")?; let mut query_cursor = QueryCursor::new(); - if let Some(range) = byte_range { - query_cursor.set_byte_range(range); + if let Some(ref range) = opts.byte_range { + query_cursor.set_byte_range(range.clone()); } - if let Some(range) = point_range { - query_cursor.set_point_range(range); + if let Some(ref range) = opts.point_range { + query_cursor.set_point_range(range.clone()); + } + if let Some(ref range) = opts.containing_byte_range { + query_cursor.set_containing_byte_range(range.clone()); + } + if let Some(ref range) = opts.containing_point_range { + query_cursor.set_containing_point_range(range.clone()); } let mut parser = Parser::new(); parser.set_language(language)?; let mut results = Vec::new(); + let should_test = test_summary.is_some(); - if !should_test && !stdin { + if !should_test && !opts.stdin { writeln!(&mut stdout, "{name}")?; } @@ -60,12 +72,12 @@ pub fn query_file_at_path( let tree = parser.parse(&source_code, None).unwrap(); let start = Instant::now(); - if ordered_captures { + if opts.ordered_captures { let mut captures = query_cursor.captures(&query, tree.root_node(), source_code.as_slice()); while let Some((mat, capture_index)) = captures.next() { let capture = mat.captures[*capture_index]; let capture_name = &query.capture_names()[capture.index as usize]; - if !quiet && !should_test { + if !opts.quiet && !should_test { writeln!( &mut stdout, " pattern: {:>2}, capture: {} - {capture_name}, start: {}, end: {}, text: `{}`", @@ -76,23 +88,25 @@ pub fn query_file_at_path( capture.node.utf8_text(&source_code).unwrap_or("") )?; } - results.push(query_testing::CaptureInfo { - name: (*capture_name).to_string(), - start: to_utf8_point(capture.node.start_position(), source_code.as_slice()), - end: to_utf8_point(capture.node.end_position(), source_code.as_slice()), - }); + if should_test { + results.push(query_testing::CaptureInfo { + name: (*capture_name).to_string(), + start: to_utf8_point(capture.node.start_position(), source_code.as_slice()), + end: to_utf8_point(capture.node.end_position(), source_code.as_slice()), + }); + } } } else { let mut matches = query_cursor.matches(&query, tree.root_node(), source_code.as_slice()); while let Some(m) = matches.next() { - if !quiet && !should_test { + if !opts.quiet && !should_test { writeln!(&mut stdout, " pattern: {}", m.pattern_index)?; } for capture in m.captures { let start = capture.node.start_position(); let end = capture.node.end_position(); let capture_name = &query.capture_names()[capture.index as usize]; - if !quiet && !should_test { + if !opts.quiet && !should_test { if end.row == start.row { writeln!( &mut stdout, @@ -107,38 +121,52 @@ pub fn query_file_at_path( )?; } } - results.push(query_testing::CaptureInfo { - name: (*capture_name).to_string(), - start: to_utf8_point(capture.node.start_position(), source_code.as_slice()), - end: to_utf8_point(capture.node.end_position(), source_code.as_slice()), - }); + if should_test { + results.push(query_testing::CaptureInfo { + name: (*capture_name).to_string(), + start: to_utf8_point(capture.node.start_position(), source_code.as_slice()), + end: to_utf8_point(capture.node.end_position(), source_code.as_slice()), + }); + } } } } - if !query_cursor.did_exceed_match_limit() { + if query_cursor.did_exceed_match_limit() { warn!("Query exceeded maximum number of in-progress captures!"); } if should_test { - let path_name = if stdin { + let path_name = if opts.stdin { "stdin" } else { Path::new(&path).file_name().unwrap().to_str().unwrap() }; + // Invariant: `test_summary` will always be `Some` when `should_test` is true + let test_summary = test_summary.unwrap(); match query_testing::assert_expected_captures(&results, path, &mut parser, language) { Ok(assertion_count) => { - println!( - " ✓ {} ({} assertions)", - paint(Some(AnsiColor::Green), path_name), - assertion_count - ); + test_summary.query_results.add_case(TestResult { + name: path_name.to_string(), + info: TestInfo::AssertionTest { + outcome: TestOutcome::AssertionPassed { assertion_count }, + test_num: test_summary.test_num, + }, + }); } Err(e) => { - println!(" ✗ {}", paint(Some(AnsiColor::Red), path_name)); + test_summary.query_results.add_case(TestResult { + name: path_name.to_string(), + info: TestInfo::AssertionTest { + outcome: TestOutcome::AssertionFailed { + error: e.to_string(), + }, + test_num: test_summary.test_num, + }, + }); return Err(e); } } } - if print_time { + if opts.print_time { writeln!(&mut stdout, "{:?}", start.elapsed())?; } diff --git a/crates/cli/src/templates/.editorconfig b/crates/cli/src/templates/.editorconfig index 65330c40..ff17b12f 100644 --- a/crates/cli/src/templates/.editorconfig +++ b/crates/cli/src/templates/.editorconfig @@ -3,11 +3,11 @@ root = true [*] charset = utf-8 -[*.{json,toml,yml,gyp}] +[*.{json,toml,yml,gyp,xml}] indent_style = space indent_size = 2 -[*.js] +[*.{js,ts}] indent_style = space indent_size = 2 @@ -31,6 +31,10 @@ indent_size = 4 indent_style = space indent_size = 4 +[*.java] +indent_style = space +indent_size = 4 + [*.go] indent_style = tab indent_size = 8 diff --git a/crates/cli/src/templates/__init__.py b/crates/cli/src/templates/__init__.py index fd137b0f..784887a7 100644 --- a/crates/cli/src/templates/__init__.py +++ b/crates/cli/src/templates/__init__.py @@ -6,32 +6,33 @@ from ._binding import language def _get_query(name, file): - query = _files(f"{__package__}.queries") / file - globals()[name] = query.read_text() + try: + query = _files(f"{__package__}") / file + globals()[name] = query.read_text() + except FileNotFoundError: + globals()[name] = None return globals()[name] def __getattr__(name): - # NOTE: uncomment these to include any queries that this grammar contains: - - # if name == "HIGHLIGHTS_QUERY": - # return _get_query("HIGHLIGHTS_QUERY", "highlights.scm") - # if name == "INJECTIONS_QUERY": - # return _get_query("INJECTIONS_QUERY", "injections.scm") - # if name == "LOCALS_QUERY": - # return _get_query("LOCALS_QUERY", "locals.scm") - # if name == "TAGS_QUERY": - # return _get_query("TAGS_QUERY", "tags.scm") + if name == "HIGHLIGHTS_QUERY": + return _get_query("HIGHLIGHTS_QUERY", "HIGHLIGHTS_QUERY_PATH") + if name == "INJECTIONS_QUERY": + return _get_query("INJECTIONS_QUERY", "INJECTIONS_QUERY_PATH") + if name == "LOCALS_QUERY": + return _get_query("LOCALS_QUERY", "LOCALS_QUERY_PATH") + if name == "TAGS_QUERY": + return _get_query("TAGS_QUERY", "TAGS_QUERY_PATH") raise AttributeError(f"module {__name__!r} has no attribute {name!r}") __all__ = [ "language", - # "HIGHLIGHTS_QUERY", - # "INJECTIONS_QUERY", - # "LOCALS_QUERY", - # "TAGS_QUERY", + "HIGHLIGHTS_QUERY", + "INJECTIONS_QUERY", + "LOCALS_QUERY", + "TAGS_QUERY", ] diff --git a/crates/cli/src/templates/__init__.pyi b/crates/cli/src/templates/__init__.pyi index 5c63215d..5c88ff6c 100644 --- a/crates/cli/src/templates/__init__.pyi +++ b/crates/cli/src/templates/__init__.pyi @@ -1,11 +1,17 @@ from typing import Final from typing_extensions import CapsuleType -# NOTE: uncomment these to include any queries that this grammar contains: +HIGHLIGHTS_QUERY: Final[str] | None +"""The syntax highlighting query for this grammar.""" -# HIGHLIGHTS_QUERY: Final[str] -# INJECTIONS_QUERY: Final[str] -# LOCALS_QUERY: Final[str] -# TAGS_QUERY: Final[str] +INJECTIONS_QUERY: Final[str] | None +"""The language injection query for this grammar.""" -def language() -> CapsuleType: ... +LOCALS_QUERY: Final[str] | None +"""The local variable query for this grammar.""" + +TAGS_QUERY: Final[str] | None +"""The symbol tagging query for this grammar.""" + +def language() -> CapsuleType: + """The tree-sitter language function for this grammar.""" diff --git a/crates/cli/src/templates/binding.java b/crates/cli/src/templates/binding.java new file mode 100644 index 00000000..704064a0 --- /dev/null +++ b/crates/cli/src/templates/binding.java @@ -0,0 +1,65 @@ +package PARSER_NS_CLEANED.jtreesitter.LOWER_PARSER_NAME; + +import java.lang.foreign.*; + +public final class PARSER_CLASS_NAME { + private static final ValueLayout VOID_PTR = + ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(Long.MAX_VALUE, ValueLayout.JAVA_BYTE)); + private static final FunctionDescriptor FUNC_DESC = FunctionDescriptor.of(VOID_PTR); + private static final Linker LINKER = Linker.nativeLinker(); + private static final PARSER_CLASS_NAME INSTANCE = new PARSER_CLASS_NAME(); + + private final Arena arena = Arena.ofAuto(); + private volatile SymbolLookup lookup = null; + + private PARSER_CLASS_NAME() {} + + /** + * Get the tree-sitter language for this grammar. + */ + public static MemorySegment language() { + if (INSTANCE.lookup == null) + INSTANCE.lookup = INSTANCE.findLibrary(); + return language(INSTANCE.lookup); + } + + /** + * Get the tree-sitter language for this grammar. + * + * The {@linkplain Arena} used in the {@code lookup} + * must not be closed while the language is being used. + */ + public static MemorySegment language(SymbolLookup lookup) { + return call(lookup, "tree_sitter_PARSER_NAME"); + } + + private SymbolLookup findLibrary() { + try { + var library = System.mapLibraryName("tree-sitter-KEBAB_PARSER_NAME"); + return SymbolLookup.libraryLookup(library, arena); + } catch (IllegalArgumentException ex1) { + try { + System.loadLibrary("tree-sitter-KEBAB_PARSER_NAME"); + return SymbolLookup.loaderLookup(); + } catch (UnsatisfiedLinkError ex2) { + ex1.addSuppressed(ex2); + throw ex1; + } + } + } + + private static UnsatisfiedLinkError unresolved(String name) { + return new UnsatisfiedLinkError("Unresolved symbol: %s".formatted(name)); + } + + @SuppressWarnings("SameParameterValue") + private static MemorySegment call(SymbolLookup lookup, String name) throws UnsatisfiedLinkError { + var address = lookup.find(name).orElseThrow(() -> unresolved(name)); + try { + var function = LINKER.downcallHandle(address, FUNC_DESC); + return (MemorySegment) function.invokeExact(); + } catch (Throwable e) { + throw new RuntimeException("Call to %s failed".formatted(name), e); + } + } +} diff --git a/crates/cli/src/templates/build.rs b/crates/cli/src/templates/build.rs index 272d8961..e3fffe4b 100644 --- a/crates/cli/src/templates/build.rs +++ b/crates/cli/src/templates/build.rs @@ -36,4 +36,21 @@ fn main() { } c_config.compile("tree-sitter-KEBAB_PARSER_NAME"); + + println!("cargo:rustc-check-cfg=cfg(with_highlights_query)"); + if !"HIGHLIGHTS_QUERY_PATH".is_empty() && std::path::Path::new("HIGHLIGHTS_QUERY_PATH").exists() { + println!("cargo:rustc-cfg=with_highlights_query"); + } + println!("cargo:rustc-check-cfg=cfg(with_injections_query)"); + if !"INJECTIONS_QUERY_PATH".is_empty() && std::path::Path::new("INJECTIONS_QUERY_PATH").exists() { + println!("cargo:rustc-cfg=with_injections_query"); + } + println!("cargo:rustc-check-cfg=cfg(with_locals_query)"); + if !"LOCALS_QUERY_PATH".is_empty() && std::path::Path::new("LOCALS_QUERY_PATH").exists() { + println!("cargo:rustc-cfg=with_locals_query"); + } + println!("cargo:rustc-check-cfg=cfg(with_tags_query)"); + if !"TAGS_QUERY_PATH".is_empty() && std::path::Path::new("TAGS_QUERY_PATH").exists() { + println!("cargo:rustc-cfg=with_tags_query"); + } } diff --git a/crates/cli/src/templates/build.zig.zon b/crates/cli/src/templates/build.zig.zon index ef084d23..0d542675 100644 --- a/crates/cli/src/templates/build.zig.zon +++ b/crates/cli/src/templates/build.zig.zon @@ -1,5 +1,6 @@ .{ .name = .tree_sitter_PARSER_NAME, + .fingerprint = PARSER_FINGERPRINT, .version = "PARSER_VERSION", .dependencies = .{ .tree_sitter = .{ diff --git a/crates/cli/src/templates/cmakelists.cmake b/crates/cli/src/templates/cmakelists.cmake index c2fd82fd..06acbc8f 100644 --- a/crates/cli/src/templates/cmakelists.cmake +++ b/crates/cli/src/templates/cmakelists.cmake @@ -20,16 +20,19 @@ include(GNUInstallDirs) find_program(TREE_SITTER_CLI tree-sitter DOC "Tree-sitter CLI") add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/grammar.json" + "${CMAKE_CURRENT_SOURCE_DIR}/src/node-types.json" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/grammar.js" - COMMAND "${TREE_SITTER_CLI}" generate grammar.js - --emit=json + COMMAND "${TREE_SITTER_CLI}" generate grammar.js --no-parser WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMENT "Generating grammar.json") add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/parser.c" + BYPRODUCTS "${CMAKE_CURRENT_SOURCE_DIR}/src/tree_sitter/parser.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/tree_sitter/alloc.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/tree_sitter/array.h" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/grammar.json" COMMAND "${TREE_SITTER_CLI}" generate src/grammar.json - --emit=parser --abi=${TREE_SITTER_ABI_VERSION} + --abi=${TREE_SITTER_ABI_VERSION} WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMENT "Generating parser.c") diff --git a/crates/cli/src/templates/gitattributes b/crates/cli/src/templates/gitattributes index 7772c942..027ac707 100644 --- a/crates/cli/src/templates/gitattributes +++ b/crates/cli/src/templates/gitattributes @@ -40,3 +40,7 @@ Package.resolved linguist-generated bindings/zig/* linguist-generated build.zig linguist-generated build.zig.zon linguist-generated + +# Java bindings +pom.xml linguist-generated +bindings/java/** linguist-generated diff --git a/crates/cli/src/templates/gitignore b/crates/cli/src/templates/gitignore index bc9e191a..7c0cb7f5 100644 --- a/crates/cli/src/templates/gitignore +++ b/crates/cli/src/templates/gitignore @@ -45,3 +45,4 @@ zig-out/ *.tar.gz *.tgz *.zip +*.jar diff --git a/crates/cli/src/templates/index.d.ts b/crates/cli/src/templates/index.d.ts index 528e060f..24576d32 100644 --- a/crates/cli/src/templates/index.d.ts +++ b/crates/cli/src/templates/index.d.ts @@ -18,10 +18,43 @@ type NodeInfo = children: ChildNode[]; }); -type Language = { +/** + * The tree-sitter language object for this grammar. + * + * @see {@linkcode https://tree-sitter.github.io/node-tree-sitter/interfaces/Parser.Language.html Parser.Language} + * + * @example + * import Parser from "tree-sitter"; + * import CAMEL_PARSER_NAME from "tree-sitter-KEBAB_PARSER_NAME"; + * + * const parser = new Parser(); + * parser.setLanguage(CAMEL_PARSER_NAME); + */ +declare const binding: { + /** + * The inner language object. + * @private + */ language: unknown; + + /** + * The content of the `node-types.json` file for this grammar. + * + * @see {@linkplain https://tree-sitter.github.io/tree-sitter/using-parsers/6-static-node-types Static Node Types} + */ nodeTypeInfo: NodeInfo[]; + + /** The syntax highlighting query for this grammar. */ + HIGHLIGHTS_QUERY?: string; + + /** The language injection query for this grammar. */ + INJECTIONS_QUERY?: string; + + /** The local variable query for this grammar. */ + LOCALS_QUERY?: string; + + /** The symbol tagging query for this grammar. */ + TAGS_QUERY?: string; }; -declare const language: Language; -export = language; +export default binding; diff --git a/crates/cli/src/templates/index.js b/crates/cli/src/templates/index.js index 233261d0..b3edc2e3 100644 --- a/crates/cli/src/templates/index.js +++ b/crates/cli/src/templates/index.js @@ -1,4 +1,7 @@ -const root = new URL("../..", import.meta.url).pathname; +import { readFileSync } from "node:fs"; +import { fileURLToPath } from "node:url"; + +const root = fileURLToPath(new URL("../..", import.meta.url)); const binding = typeof process.versions.bun === "string" // Support `bun build --compile` by being statically analyzable enough to find the .node file at build-time @@ -6,8 +9,29 @@ const binding = typeof process.versions.bun === "string" : (await import("node-gyp-build")).default(root); try { - const nodeTypes = await import(`${root}/src/node-types.json`, {with: {type: "json"}}); + const nodeTypes = await import(`${root}/src/node-types.json`, { with: { type: "json" } }); binding.nodeTypeInfo = nodeTypes.default; -} catch (_) {} +} catch { } + +const queries = [ + ["HIGHLIGHTS_QUERY", `${root}/HIGHLIGHTS_QUERY_PATH`], + ["INJECTIONS_QUERY", `${root}/INJECTIONS_QUERY_PATH`], + ["LOCALS_QUERY", `${root}/LOCALS_QUERY_PATH`], + ["TAGS_QUERY", `${root}/TAGS_QUERY_PATH`], +]; + +for (const [prop, path] of queries) { + Object.defineProperty(binding, prop, { + configurable: true, + enumerable: true, + get() { + delete binding[prop]; + try { + binding[prop] = readFileSync(path, "utf8"); + } catch { } + return binding[prop]; + } + }); +} export default binding; diff --git a/crates/cli/src/templates/lib.rs b/crates/cli/src/templates/lib.rs index 8478f488..1e8c9ca3 100644 --- a/crates/cli/src/templates/lib.rs +++ b/crates/cli/src/templates/lib.rs @@ -32,12 +32,21 @@ pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_PARSE /// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers/6-static-node-types pub const NODE_TYPES: &str = include_str!("../../src/node-types.json"); -// NOTE: uncomment these to include any queries that this grammar contains: +#[cfg(with_highlights_query)] +/// The syntax highlighting query for this grammar. +pub const HIGHLIGHTS_QUERY: &str = include_str!("../../HIGHLIGHTS_QUERY_PATH"); -// pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm"); -// pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injections.scm"); -// pub const LOCALS_QUERY: &str = include_str!("../../queries/locals.scm"); -// pub const TAGS_QUERY: &str = include_str!("../../queries/tags.scm"); +#[cfg(with_injections_query)] +/// The language injection query for this grammar. +pub const INJECTIONS_QUERY: &str = include_str!("../../INJECTIONS_QUERY_PATH"); + +#[cfg(with_locals_query)] +/// The local variable query for this grammar. +pub const LOCALS_QUERY: &str = include_str!("../../LOCALS_QUERY_PATH"); + +#[cfg(with_tags_query)] +/// The symbol tagging query for this grammar. +pub const TAGS_QUERY: &str = include_str!("../../TAGS_QUERY_PATH"); #[cfg(test)] mod tests { diff --git a/crates/cli/src/templates/makefile b/crates/cli/src/templates/makefile index 847381c5..b42dab97 100644 --- a/crates/cli/src/templates/makefile +++ b/crates/cli/src/templates/makefile @@ -73,10 +73,10 @@ $(LANGUAGE_NAME).pc: bindings/c/$(LANGUAGE_NAME).pc.in -e 's|@CMAKE_INSTALL_PREFIX@|$(PREFIX)|' $< > $@ $(SRC_DIR)/grammar.json: grammar.js - $(TS) generate --emit=json $^ + $(TS) generate --no-parser $^ $(PARSER): $(SRC_DIR)/grammar.json - $(TS) generate --emit=parser $^ + $(TS) generate $^ install: all install -d '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/KEBAB_PARSER_NAME '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter '$(DESTDIR)$(PCLIBDIR)' '$(DESTDIR)$(LIBDIR)' diff --git a/crates/cli/src/templates/package.json b/crates/cli/src/templates/package.json index 95f5b638..d9dbbd33 100644 --- a/crates/cli/src/templates/package.json +++ b/crates/cli/src/templates/package.json @@ -38,11 +38,11 @@ }, "devDependencies": { "prebuildify": "^6.0.1", - "tree-sitter": "^0.22.4", + "tree-sitter": "^0.25.0", "tree-sitter-cli": "^CLI_VERSION" }, "peerDependencies": { - "tree-sitter": "^0.22.4" + "tree-sitter": "^0.25.0" }, "peerDependenciesMeta": { "tree-sitter": { diff --git a/crates/cli/src/templates/pom.xml b/crates/cli/src/templates/pom.xml new file mode 100644 index 00000000..661fe42b --- /dev/null +++ b/crates/cli/src/templates/pom.xml @@ -0,0 +1,154 @@ + + + 4.0.0 + PARSER_NS + jtreesitter-KEBAB_PARSER_NAME + JTreeSitter CAMEL_PARSER_NAME + PARSER_VERSION + PARSER_DESCRIPTION + PARSER_URL + + + PARSER_LICENSE + https://spdx.org/licenses/PARSER_LICENSE.html + + + + + PARSER_AUTHOR_NAME + PARSER_AUTHOR_EMAIL + PARSER_AUTHOR_URL + + + + PARSER_URL + scm:git:git://PARSER_URL_STRIPPED.git + scm:git:ssh://PARSER_URL_STRIPPED.git + + + 23 + UTF-8 + true + true + false + true + + + + io.github.tree-sitter + jtreesitter + 0.26.0 + true + + + org.junit.jupiter + junit-jupiter-api + 6.0.1 + test + + + + bindings/java/main + bindings/java/test + + + maven-surefire-plugin + 3.5.4 + + + ${project.build.directory}/reports/surefire + + --enable-native-access=ALL-UNNAMED + + + + maven-javadoc-plugin + 3.12.0 + + + + jar + + + + + public + true + true + all,-missing + + + + maven-source-plugin + 3.3.1 + + + + jar-no-fork + + + + + + maven-gpg-plugin + 3.2.8 + + + verify + + sign + + + true + + --no-tty + --pinentry-mode + loopback + + + + + + + io.github.mavenplugins + central-publishing-maven-plugin + 1.1.1 + + + deploy + + publish + + + validated + ${publish.auto} + ${publish.skip} + ${project.artifactId}-${project.version}.zip + ${project.artifactId}-${project.version}.zip + + + + true + + + + + + ci + + + env.CI + true + + + + false + true + false + + + + diff --git a/crates/cli/src/templates/setup.py b/crates/cli/src/templates/setup.py index 7f92eaee..bcf184b7 100644 --- a/crates/cli/src/templates/setup.py +++ b/crates/cli/src/templates/setup.py @@ -32,7 +32,7 @@ class BuildExt(build_ext): class BdistWheel(bdist_wheel): def get_tag(self): python, abi, platform = super().get_tag() - if python.startswith("cp"): + if python.startswith("cp") and not get_config_var("Py_GIL_DISABLED"): python, abi = "cp310", "abi3" return python, abi, platform diff --git a/crates/cli/src/templates/test.java b/crates/cli/src/templates/test.java new file mode 100644 index 00000000..8bf81ea0 --- /dev/null +++ b/crates/cli/src/templates/test.java @@ -0,0 +1,12 @@ +import io.github.treesitter.jtreesitter.Language; +import PARSER_NS_CLEANED.jtreesitter.LOWER_PARSER_NAME.PARSER_CLASS_NAME; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +public class PARSER_CLASS_NAMETest { + @Test + public void testCanLoadLanguage() { + assertDoesNotThrow(() -> new Language(PARSER_CLASS_NAME.language())); + } +} diff --git a/crates/cli/src/test.rs b/crates/cli/src/test.rs index d3a120e3..b568e4a3 100644 --- a/crates/cli/src/test.rs +++ b/crates/cli/src/test.rs @@ -1,7 +1,7 @@ use std::{ collections::BTreeMap, ffi::OsStr, - fmt::Write as _, + fmt::Display as _, fs, io::{self, Write}, path::{Path, PathBuf}, @@ -18,6 +18,8 @@ use regex::{ bytes::{Regex as ByteRegex, RegexBuilder as ByteRegexBuilder}, Regex, }; +use schemars::{JsonSchema, Schema, SchemaGenerator}; +use serde::Serialize; use similar::{ChangeTag, TextDiff}; use tree_sitter::{format_sexp, Language, LogType, Parser, Query, Tree}; use walkdir::WalkDir; @@ -65,7 +67,7 @@ static POINT_REGEX: LazyLock = pub enum TestEntry { Group { name: String, - children: Vec, + children: Vec, file_path: Option, }, Example { @@ -114,7 +116,7 @@ impl Default for TestAttributes { } } -#[derive(ValueEnum, Default, Copy, Clone, PartialEq, Eq)] +#[derive(ValueEnum, Default, Debug, Copy, Clone, PartialEq, Eq, Serialize)] pub enum TestStats { All, #[default] @@ -123,7 +125,6 @@ pub enum TestStats { } pub struct TestOptions<'a> { - pub output: &'a mut String, pub path: PathBuf, pub debug: bool, pub debug_graph: bool, @@ -134,17 +135,477 @@ pub struct TestOptions<'a> { pub open_log: bool, pub languages: BTreeMap<&'a str, &'a Language>, pub color: bool, - pub test_num: usize, - /// Whether a test ran for the nth line in `output`, the true parse rate, and the adjusted - /// parse rate - pub parse_rates: &'a mut Vec<(bool, Option<(f64, f64)>)>, - pub stat_display: TestStats, - pub stats: &'a mut Stats, pub show_fields: bool, pub overview_only: bool, } -pub fn run_tests_at_path(parser: &mut Parser, opts: &mut TestOptions) -> Result<()> { +/// A stateful object used to collect results from running a grammar's test suite +#[derive(Debug, Default, Serialize, JsonSchema)] +pub struct TestSummary { + // Parse test results and associated data + #[schemars(schema_with = "schema_as_array")] + #[serde(serialize_with = "serialize_as_array")] + pub parse_results: TestResultHierarchy, + pub parse_failures: Vec, + pub parse_stats: Stats, + #[schemars(skip)] + #[serde(skip)] + pub has_parse_errors: bool, + #[schemars(skip)] + #[serde(skip)] + pub parse_stat_display: TestStats, + + // Other test results + #[schemars(schema_with = "schema_as_array")] + #[serde(serialize_with = "serialize_as_array")] + pub highlight_results: TestResultHierarchy, + #[schemars(schema_with = "schema_as_array")] + #[serde(serialize_with = "serialize_as_array")] + pub tag_results: TestResultHierarchy, + #[schemars(schema_with = "schema_as_array")] + #[serde(serialize_with = "serialize_as_array")] + pub query_results: TestResultHierarchy, + + // Data used during construction + #[schemars(skip)] + #[serde(skip)] + pub test_num: usize, + // Options passed in from the CLI which control how the summary is displayed + #[schemars(skip)] + #[serde(skip)] + pub color: bool, + #[schemars(skip)] + #[serde(skip)] + pub overview_only: bool, + #[schemars(skip)] + #[serde(skip)] + pub update: bool, + #[schemars(skip)] + #[serde(skip)] + pub json: bool, +} + +impl TestSummary { + #[must_use] + pub fn new( + color: bool, + stat_display: TestStats, + parse_update: bool, + overview_only: bool, + json_summary: bool, + ) -> Self { + Self { + color, + parse_stat_display: stat_display, + update: parse_update, + overview_only, + json: json_summary, + test_num: 1, + ..Default::default() + } + } +} + +#[derive(Debug, Default, JsonSchema)] +pub struct TestResultHierarchy { + root_group: Vec, + traversal_idxs: Vec, +} + +fn serialize_as_array(results: &TestResultHierarchy, serializer: S) -> Result +where + S: serde::Serializer, +{ + results.root_group.serialize(serializer) +} + +fn schema_as_array(gen: &mut SchemaGenerator) -> Schema { + gen.subschema_for::>() +} + +/// Stores arbitrarily nested parent test groups and child cases. Supports creation +/// in DFS traversal order +impl TestResultHierarchy { + /// Signifies the start of a new group's traversal during construction. + fn push_traversal(&mut self, idx: usize) { + self.traversal_idxs.push(idx); + } + + /// Signifies the end of the current group's traversal during construction. + /// Must be paired with a prior call to [`TestResultHierarchy::add_group`]. + pub fn pop_traversal(&mut self) { + self.traversal_idxs.pop(); + } + + /// Adds a new group as a child of the current group. Caller is responsible + /// for calling [`TestResultHierarchy::pop_traversal`] once the group is done + /// being traversed. + pub fn add_group(&mut self, group_name: &str) { + let new_group_idx = self.curr_group_len(); + self.push(TestResult { + name: group_name.to_string(), + info: TestInfo::Group { + children: Vec::new(), + }, + }); + self.push_traversal(new_group_idx); + } + + /// Adds a new test example as a child of the current group. + /// Asserts that `test_case.info` is not [`TestInfo::Group`]. + pub fn add_case(&mut self, test_case: TestResult) { + assert!(!matches!(test_case.info, TestInfo::Group { .. })); + self.push(test_case); + } + + /// Adds a new `TestResult` to the current group. + fn push(&mut self, result: TestResult) { + // If there are no traversal steps, we're adding to the root + if self.traversal_idxs.is_empty() { + self.root_group.push(result); + return; + } + + #[allow(clippy::manual_let_else)] + let mut curr_group = match self.root_group[self.traversal_idxs[0]].info { + TestInfo::Group { ref mut children } => children, + _ => unreachable!(), + }; + for idx in self.traversal_idxs.iter().skip(1) { + curr_group = match curr_group[*idx].info { + TestInfo::Group { ref mut children } => children, + _ => unreachable!(), + }; + } + + curr_group.push(result); + } + + fn curr_group_len(&self) -> usize { + if self.traversal_idxs.is_empty() { + return self.root_group.len(); + } + + #[allow(clippy::manual_let_else)] + let mut curr_group = match self.root_group[self.traversal_idxs[0]].info { + TestInfo::Group { ref children } => children, + _ => unreachable!(), + }; + for idx in self.traversal_idxs.iter().skip(1) { + curr_group = match curr_group[*idx].info { + TestInfo::Group { ref children } => children, + _ => unreachable!(), + }; + } + curr_group.len() + } + + #[allow(clippy::iter_without_into_iter)] + #[must_use] + pub fn iter(&self) -> TestResultIterWithDepth<'_> { + let mut stack = Vec::with_capacity(self.root_group.len()); + for child in self.root_group.iter().rev() { + stack.push((0, child)); + } + TestResultIterWithDepth { stack } + } +} + +pub struct TestResultIterWithDepth<'a> { + stack: Vec<(usize, &'a TestResult)>, +} + +impl<'a> Iterator for TestResultIterWithDepth<'a> { + type Item = (usize, &'a TestResult); + + fn next(&mut self) -> Option { + self.stack.pop().inspect(|(depth, result)| { + if let TestInfo::Group { children } = &result.info { + for child in children.iter().rev() { + self.stack.push((depth + 1, child)); + } + } + }) + } +} + +#[derive(Debug, Serialize, JsonSchema)] +pub struct TestResult { + pub name: String, + #[schemars(flatten)] + #[serde(flatten)] + pub info: TestInfo, +} + +#[derive(Debug, Serialize, JsonSchema)] +#[schemars(untagged)] +#[serde(untagged)] +pub enum TestInfo { + Group { + children: Vec, + }, + ParseTest { + outcome: TestOutcome, + // True parse rate, adjusted parse rate + #[schemars(schema_with = "parse_rate_schema")] + #[serde(serialize_with = "serialize_parse_rates")] + parse_rate: Option<(f64, f64)>, + test_num: usize, + }, + AssertionTest { + outcome: TestOutcome, + test_num: usize, + }, +} + +fn serialize_parse_rates( + parse_rate: &Option<(f64, f64)>, + serializer: S, +) -> Result +where + S: serde::Serializer, +{ + match parse_rate { + None => serializer.serialize_none(), + Some((first, _)) => serializer.serialize_some(first), + } +} + +fn parse_rate_schema(gen: &mut SchemaGenerator) -> Schema { + gen.subschema_for::>() +} + +#[derive(Debug, Clone, Eq, PartialEq, Serialize, JsonSchema)] +pub enum TestOutcome { + // Parse outcomes + Passed, + Failed, + Updated, + Skipped, + Platform, + + // Highlight/Tag/Query outcomes + AssertionPassed { assertion_count: usize }, + AssertionFailed { error: String }, +} + +impl TestSummary { + fn fmt_parse_results(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let (count, total_adj_parse_time) = self + .parse_results + .iter() + .filter_map(|(_, result)| match result.info { + TestInfo::Group { .. } => None, + TestInfo::ParseTest { parse_rate, .. } => parse_rate, + _ => unreachable!(), + }) + .fold((0usize, 0.0f64), |(count, rate_accum), (_, adj_rate)| { + (count + 1, rate_accum + adj_rate) + }); + + let avg = total_adj_parse_time / count as f64; + let std_dev = { + let variance = self + .parse_results + .iter() + .filter_map(|(_, result)| match result.info { + TestInfo::Group { .. } => None, + TestInfo::ParseTest { parse_rate, .. } => parse_rate, + _ => unreachable!(), + }) + .map(|(_, rate_i)| (rate_i - avg).powi(2)) + .sum::() + / count as f64; + variance.sqrt() + }; + + for (depth, entry) in self.parse_results.iter() { + write!(f, "{}", " ".repeat(depth + 1))?; + match &entry.info { + TestInfo::Group { .. } => writeln!(f, "{}:", entry.name)?, + TestInfo::ParseTest { + outcome, + parse_rate, + test_num, + } => { + let (color, result_char) = match outcome { + TestOutcome::Passed => (AnsiColor::Green, "✓"), + TestOutcome::Failed => (AnsiColor::Red, "✗"), + TestOutcome::Updated => (AnsiColor::Blue, "✓"), + TestOutcome::Skipped => (AnsiColor::Yellow, "⌀"), + TestOutcome::Platform => (AnsiColor::Magenta, "⌀"), + _ => unreachable!(), + }; + let stat_display = match (self.parse_stat_display, parse_rate) { + (TestStats::TotalOnly, _) | (_, None) => String::new(), + (display, Some((true_rate, adj_rate))) => { + let mut stats = if display == TestStats::All { + format!(" ({true_rate:.3} bytes/ms)") + } else { + String::new() + }; + // 3 standard deviations below the mean, aka the "Empirical Rule" + if *adj_rate < 3.0f64.mul_add(-std_dev, avg) { + stats += &paint( + self.color.then_some(AnsiColor::Yellow), + &format!( + " -- Warning: Slow parse rate ({true_rate:.3} bytes/ms)" + ), + ); + } + stats + } + }; + writeln!( + f, + "{test_num:>3}. {result_char} {}{stat_display}", + paint(self.color.then_some(color), &entry.name), + )?; + } + TestInfo::AssertionTest { .. } => unreachable!(), + } + } + + // Parse failure info + if !self.parse_failures.is_empty() && self.update && !self.has_parse_errors { + writeln!( + f, + "\n{} update{}:\n", + self.parse_failures.len(), + if self.parse_failures.len() == 1 { + "" + } else { + "s" + } + )?; + + for (i, TestFailure { name, .. }) in self.parse_failures.iter().enumerate() { + writeln!(f, " {}. {name}", i + 1)?; + } + } else if !self.parse_failures.is_empty() && !self.overview_only { + if !self.has_parse_errors { + writeln!( + f, + "\n{} failure{}:", + self.parse_failures.len(), + if self.parse_failures.len() == 1 { + "" + } else { + "s" + } + )?; + } + + if self.color { + DiffKey.fmt(f)?; + } + for ( + i, + TestFailure { + name, + actual, + expected, + is_cst, + }, + ) in self.parse_failures.iter().enumerate() + { + if expected == "NO ERROR" { + writeln!(f, "\n {}. {name}:\n", i + 1)?; + writeln!(f, " Expected an ERROR node, but got:")?; + let actual = if *is_cst { + actual + } else { + &format_sexp(actual, 2) + }; + writeln!( + f, + " {}", + paint(self.color.then_some(AnsiColor::Red), actual) + )?; + } else { + writeln!(f, "\n {}. {name}:", i + 1)?; + if *is_cst { + writeln!( + f, + "{}", + TestDiff::new(actual, expected).with_color(self.color) + )?; + } else { + writeln!( + f, + "{}", + TestDiff::new(&format_sexp(actual, 2), &format_sexp(expected, 2)) + .with_color(self.color,) + )?; + } + } + } + } else { + writeln!(f)?; + } + + Ok(()) + } +} + +impl std::fmt::Display for TestSummary { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.fmt_parse_results(f)?; + + let mut render_assertion_results = + |name: &str, results: &TestResultHierarchy| -> std::fmt::Result { + writeln!(f, "{name}:")?; + for (depth, entry) in results.iter() { + write!(f, "{}", " ".repeat(depth + 2))?; + match &entry.info { + TestInfo::Group { .. } => writeln!(f, "{}", entry.name)?, + TestInfo::AssertionTest { outcome, test_num } => match outcome { + TestOutcome::AssertionPassed { assertion_count } => writeln!( + f, + "{:>3}. ✓ {} ({assertion_count} assertions)", + test_num, + paint(self.color.then_some(AnsiColor::Green), &entry.name) + )?, + TestOutcome::AssertionFailed { error } => { + writeln!( + f, + "{:>3}. ✗ {}", + test_num, + paint(self.color.then_some(AnsiColor::Red), &entry.name) + )?; + writeln!(f, "{} {error}", " ".repeat(depth + 1))?; + } + _ => unreachable!(), + }, + TestInfo::ParseTest { .. } => unreachable!(), + } + } + Ok(()) + }; + + if !self.highlight_results.root_group.is_empty() { + render_assertion_results("syntax highlighting", &self.highlight_results)?; + } + + if !self.tag_results.root_group.is_empty() { + render_assertion_results("tags", &self.tag_results)?; + } + + if !self.query_results.root_group.is_empty() { + render_assertion_results("queries", &self.query_results)?; + } + + write!(f, "{}", self.parse_stats)?; + + Ok(()) + } +} + +pub fn run_tests_at_path( + parser: &mut Parser, + opts: &TestOptions, + test_summary: &mut TestSummary, +) -> Result<()> { let test_entry = parse_tests(&opts.path)?; let mut _log_session = None; @@ -159,140 +620,26 @@ pub fn run_tests_at_path(parser: &mut Parser, opts: &mut TestOptions) -> Result< }))); } - let mut failures = Vec::new(); let mut corrected_entries = Vec::new(); - let mut has_parse_errors = false; run_tests( parser, test_entry, opts, - 0, - &mut failures, + test_summary, &mut corrected_entries, - &mut has_parse_errors, + true, )?; - let (count, total_adj_parse_time) = opts - .parse_rates - .iter() - .flat_map(|(_, rates)| rates) - .fold((0usize, 0.0f64), |(count, rate_accum), (_, adj_rate)| { - (count + 1, rate_accum + adj_rate) - }); - - let avg = total_adj_parse_time / count as f64; - let std_dev = { - let variance = opts - .parse_rates - .iter() - .flat_map(|(_, rates)| rates) - .map(|(_, rate_i)| (rate_i - avg).powi(2)) - .sum::() - / count as f64; - variance.sqrt() - }; - - for ((is_test, rates), out_line) in opts.parse_rates.iter().zip(opts.output.lines()) { - let stat_display = if !is_test { - // Test group, no actual parsing took place - String::new() - } else { - match (opts.stat_display, rates) { - (TestStats::TotalOnly, _) | (_, None) => String::new(), - (display, Some((true_rate, adj_rate))) => { - let mut stats = if display == TestStats::All { - format!(" ({true_rate:.3} bytes/ms)") - } else { - String::new() - }; - // 3 standard deviations below the mean, aka the "Empirical Rule" - if *adj_rate < 3.0f64.mul_add(-std_dev, avg) { - stats += &paint( - opts.color.then_some(AnsiColor::Yellow), - &format!(" -- Warning: Slow parse rate ({true_rate:.3} bytes/ms)"), - ); - } - stats - } - } - }; - println!("{out_line}{stat_display}"); - } - parser.stop_printing_dot_graphs(); - if failures.is_empty() { + if test_summary.parse_failures.is_empty() || (opts.update && !test_summary.has_parse_errors) { Ok(()) - } else if opts.update && !has_parse_errors { - println!( - "\n{} update{}:\n", - failures.len(), - if failures.len() == 1 { "" } else { "s" } - ); - - for (i, TestFailure { name, .. }) in failures.iter().enumerate() { - println!(" {}. {name}", i + 1); - } - - Ok(()) - } else { - has_parse_errors = opts.update && has_parse_errors; - - if !opts.overview_only { - if !has_parse_errors { - println!( - "\n{} failure{}:", - failures.len(), - if failures.len() == 1 { "" } else { "s" } - ); - } - - if opts.color { - print_diff_key(); - } - for ( - i, - TestFailure { - name, - actual, - expected, - is_cst, - }, - ) in failures.iter().enumerate() - { - if expected == "NO ERROR" { - println!("\n {}. {name}:\n", i + 1); - println!(" Expected an ERROR node, but got:"); - let actual = if *is_cst { - actual - } else { - &format_sexp(actual, 2) - }; - println!(" {}", paint(opts.color.then_some(AnsiColor::Red), actual)); - } else { - println!("\n {}. {name}:", i + 1); - if *is_cst { - print_diff(actual, expected, opts.color); - } else { - print_diff( - &format_sexp(actual, 2), - &format_sexp(expected, 2), - opts.color, - ); - } - } - } - } else { - println!(); - } - - if has_parse_errors { - Err(anyhow!(indoc! {" + } else if opts.update && test_summary.has_parse_errors { + Err(anyhow!(indoc! {" Some tests failed to parse with unexpected `ERROR` or `MISSING` nodes, as shown above, and cannot be updated automatically. Either fix the grammar or manually update the tests if this is expected."})) - } else { - Err(anyhow!("")) - } + } else { + Err(anyhow!("")) } } @@ -317,52 +664,95 @@ pub fn check_queries_at_path(language: &Language, path: &Path) -> Result<()> { Ok(()) } -pub fn print_diff_key() { - println!( - "\ncorrect / {} / {}", - paint(Some(AnsiColor::Green), "expected"), - paint(Some(AnsiColor::Red), "unexpected") - ); +pub struct DiffKey; + +impl std::fmt::Display for DiffKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "\ncorrect / {} / {}", + paint(Some(AnsiColor::Green), "expected"), + paint(Some(AnsiColor::Red), "unexpected") + )?; + Ok(()) + } } -pub fn print_diff(actual: &str, expected: &str, use_color: bool) { - let diff = TextDiff::from_lines(actual, expected); - for diff in diff.iter_all_changes() { - match diff.tag() { - ChangeTag::Equal => { - if use_color { - print!("{diff}"); - } else { - print!(" {diff}"); - } - } - ChangeTag::Insert => { - if use_color { - print!("{}", paint(Some(AnsiColor::Green), diff.as_str().unwrap())); - } else { - print!("+{diff}"); - } - if diff.missing_newline() { - println!(); - } - } - ChangeTag::Delete => { - if use_color { - print!("{}", paint(Some(AnsiColor::Red), diff.as_str().unwrap())); - } else { - print!("-{diff}"); - } - if diff.missing_newline() { - println!(); - } - } +impl DiffKey { + /// Writes [`DiffKey`] to stdout + pub fn print() { + println!("{Self}"); + } +} + +pub struct TestDiff<'a> { + pub actual: &'a str, + pub expected: &'a str, + pub color: bool, +} + +impl<'a> TestDiff<'a> { + #[must_use] + pub const fn new(actual: &'a str, expected: &'a str) -> Self { + Self { + actual, + expected, + color: true, } } - println!(); + #[must_use] + pub const fn with_color(mut self, color: bool) -> Self { + self.color = color; + self + } } -struct TestFailure { +impl std::fmt::Display for TestDiff<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let diff = TextDiff::from_lines(self.actual, self.expected); + for diff in diff.iter_all_changes() { + match diff.tag() { + ChangeTag::Equal => { + if self.color { + write!(f, "{diff}")?; + } else { + write!(f, " {diff}")?; + } + } + ChangeTag::Insert => { + if self.color { + write!( + f, + "{}", + paint(Some(AnsiColor::Green), diff.as_str().unwrap()) + )?; + } else { + write!(f, "+{diff}")?; + } + if diff.missing_newline() { + writeln!(f)?; + } + } + ChangeTag::Delete => { + if self.color { + write!(f, "{}", paint(Some(AnsiColor::Red), diff.as_str().unwrap()))?; + } else { + write!(f, "-{diff}")?; + } + if diff.missing_newline() { + writeln!(f)?; + } + } + } + } + + Ok(()) + } +} + +#[derive(Debug, Serialize, JsonSchema)] +pub struct TestFailure { name: String, actual: String, expected: String, @@ -421,15 +811,13 @@ impl TestCorrection { } /// This will return false if we want to "fail fast". It will bail and not parse any more tests. -#[allow(clippy::too_many_arguments)] fn run_tests( parser: &mut Parser, test_entry: TestEntry, - opts: &mut TestOptions, - mut indent_level: u32, - failures: &mut Vec, + opts: &TestOptions, + test_summary: &mut TestSummary, corrected_entries: &mut Vec, - has_parse_errors: &mut bool, + is_root: bool, ) -> Result { match test_entry { TestEntry::Example { @@ -443,29 +831,29 @@ fn run_tests( attributes, .. } => { - write!(opts.output, "{}", " ".repeat(indent_level as usize))?; - if attributes.skip { - writeln!( - opts.output, - "{:>3}. ⌀ {}", - opts.test_num, - paint(opts.color.then_some(AnsiColor::Yellow), &name), - )?; - opts.parse_rates.push((true, None)); - opts.test_num += 1; + test_summary.parse_results.add_case(TestResult { + name: name.clone(), + info: TestInfo::ParseTest { + outcome: TestOutcome::Skipped, + parse_rate: None, + test_num: test_summary.test_num, + }, + }); + test_summary.test_num += 1; return Ok(true); } if !attributes.platform { - writeln!( - opts.output, - "{:>3}. ⌀ {}", - opts.test_num, - paint(opts.color.then_some(AnsiColor::Magenta), &name), - )?; - opts.parse_rates.push((true, None)); - opts.test_num += 1; + test_summary.parse_results.add_case(TestResult { + name: name.clone(), + info: TestInfo::ParseTest { + outcome: TestOutcome::Platform, + parse_rate: None, + test_num: test_summary.test_num, + }, + }); + test_summary.test_num += 1; return Ok(true); } @@ -479,28 +867,30 @@ fn run_tests( } let start = std::time::Instant::now(); let tree = parser.parse(&input, None).unwrap(); - { + let parse_rate = { let parse_time = start.elapsed(); let true_parse_rate = tree.root_node().byte_range().len() as f64 / (parse_time.as_nanos() as f64 / 1_000_000.0); let adj_parse_rate = adjusted_parse_rate(&tree, parse_time); - opts.parse_rates - .push((true, Some((true_parse_rate, adj_parse_rate)))); - opts.stats.total_parses += 1; - opts.stats.total_duration += parse_time; - opts.stats.total_bytes += tree.root_node().byte_range().len(); - } + test_summary.parse_stats.total_parses += 1; + test_summary.parse_stats.total_duration += parse_time; + test_summary.parse_stats.total_bytes += tree.root_node().byte_range().len(); + + Some((true_parse_rate, adj_parse_rate)) + }; if attributes.error { if tree.root_node().has_error() { - writeln!( - opts.output, - "{:>3}. ✓ {}", - opts.test_num, - paint(opts.color.then_some(AnsiColor::Green), &name), - )?; - opts.stats.successful_parses += 1; + test_summary.parse_results.add_case(TestResult { + name: name.clone(), + info: TestInfo::ParseTest { + outcome: TestOutcome::Passed, + parse_rate, + test_num: test_summary.test_num, + }, + }); + test_summary.parse_stats.successful_parses += 1; if opts.update { let input = String::from_utf8(input.clone()).unwrap(); let output = if attributes.cst { @@ -535,18 +925,25 @@ fn run_tests( divider_delim_len, )); } - writeln!( - opts.output, - "{:>3}. ✗ {}", - opts.test_num, - paint(opts.color.then_some(AnsiColor::Red), &name), - )?; + test_summary.parse_results.add_case(TestResult { + name: name.clone(), + info: TestInfo::ParseTest { + outcome: TestOutcome::Failed, + parse_rate, + test_num: test_summary.test_num, + }, + }); let actual = if attributes.cst { render_test_cst(&input, &tree)? } else { tree.root_node().to_sexp() }; - failures.push(TestFailure::new(&name, actual, "NO ERROR", attributes.cst)); + test_summary.parse_failures.push(TestFailure::new( + &name, + actual, + "NO ERROR", + attributes.cst, + )); } if attributes.fail_fast { @@ -563,13 +960,15 @@ fn run_tests( } if actual == output { - writeln!( - opts.output, - "{:>3}. ✓ {}", - opts.test_num, - paint(opts.color.then_some(AnsiColor::Green), &name), - )?; - opts.stats.successful_parses += 1; + test_summary.parse_results.add_case(TestResult { + name: name.clone(), + info: TestInfo::ParseTest { + outcome: TestOutcome::Passed, + parse_rate, + test_num: test_summary.test_num, + }, + }); + test_summary.parse_stats.successful_parses += 1; if opts.update { let input = String::from_utf8(input.clone()).unwrap(); let output = if attributes.cst { @@ -600,7 +999,7 @@ fn run_tests( // are intended to have errors, hence why this // check isn't shown above if actual.contains("ERROR") || actual.contains("MISSING") { - *has_parse_errors = true; + test_summary.has_parse_errors = true; // keep the original `expected` output if the actual output has an // error @@ -621,22 +1020,31 @@ fn run_tests( header_delim_len, divider_delim_len, )); - writeln!( - opts.output, - "{:>3}. ✓ {}", - opts.test_num, - paint(opts.color.then_some(AnsiColor::Blue), &name), - )?; + test_summary.parse_results.add_case(TestResult { + name: name.clone(), + info: TestInfo::ParseTest { + outcome: TestOutcome::Updated, + parse_rate, + test_num: test_summary.test_num, + }, + }); } } else { - writeln!( - opts.output, - "{:>3}. ✗ {}", - opts.test_num, - paint(opts.color.then_some(AnsiColor::Red), &name), - )?; + test_summary.parse_results.add_case(TestResult { + name: name.clone(), + info: TestInfo::ParseTest { + outcome: TestOutcome::Failed, + parse_rate, + test_num: test_summary.test_num, + }, + }); } - failures.push(TestFailure::new(&name, actual, &output, attributes.cst)); + test_summary.parse_failures.push(TestFailure::new( + &name, + actual, + &output, + attributes.cst, + )); if attributes.fail_fast { return Ok(false); @@ -649,7 +1057,7 @@ fn run_tests( parser.set_language(opts.languages.values().next().unwrap())?; } } - opts.test_num += 1; + test_summary.test_num += 1; } TestEntry::Group { name, @@ -660,9 +1068,7 @@ fn run_tests( return Ok(true); } - indent_level += 1; - let failure_count = failures.len(); - let mut has_printed = false; + let mut ran_test_in_group = false; let matches_filter = |name: &str, file_name: &Option, opts: &TestOptions| { if let (Some(test_file_path), Some(filter_file_name)) = (file_name, &opts.file_name) @@ -680,16 +1086,10 @@ fn run_tests( } }; - let should_skip = |entry: &TestEntry, opts: &TestOptions| match entry { - TestEntry::Example { - name, file_name, .. - } => !matches_filter(name, file_name, opts), - TestEntry::Group { .. } => false, - }; - for child in children { if let TestEntry::Example { ref name, + ref file_name, ref input, ref output, ref attributes_str, @@ -698,48 +1098,40 @@ fn run_tests( .. } = child { - if should_skip(&child, opts) { - let input = String::from_utf8(input.clone()).unwrap(); - let output = format_sexp(output, 0); - corrected_entries.push(TestCorrection::new( - name, - input, - output, - attributes_str, - header_delim_len, - divider_delim_len, - )); - - opts.test_num += 1; + if !matches_filter(name, file_name, opts) { + if opts.update { + let input = String::from_utf8(input.clone()).unwrap(); + let output = format_sexp(output, 0); + corrected_entries.push(TestCorrection::new( + name, + input, + output, + attributes_str, + header_delim_len, + divider_delim_len, + )); + } + test_summary.test_num += 1; continue; } } - if !has_printed && indent_level > 1 { - has_printed = true; - writeln!( - opts.output, - "{}{name}:", - " ".repeat((indent_level - 1) as usize) - )?; - opts.parse_rates.push((false, None)); + + if !ran_test_in_group && !is_root { + test_summary.parse_results.add_group(&name); + ran_test_in_group = true; } - if !run_tests( - parser, - child, - opts, - indent_level, - failures, - corrected_entries, - has_parse_errors, - )? { + if !run_tests(parser, child, opts, test_summary, corrected_entries, false)? { // fail fast return Ok(false); } } + // Now that we're done traversing the children of the current group, pop + // the index + test_summary.parse_results.pop_traversal(); if let Some(file_path) = file_path { - if opts.update && failures.len() - failure_count > 0 { + if opts.update { write_tests(&file_path, corrected_entries)?; } corrected_entries.clear(); @@ -1027,7 +1419,6 @@ fn parse_test_content(name: String, content: &str, file_path: Option) - // Remove trailing newline from the input. input.pop(); - #[cfg(target_os = "windows")] if input.last() == Some(&b'\r') { input.pop(); } @@ -1086,6 +1477,10 @@ fn parse_test_content(name: String, content: &str, file_path: Option) - #[cfg(test)] mod tests { + use serde_json::json; + + use crate::tests::get_language; + use super::*; #[test] @@ -1743,4 +2138,290 @@ Test with cst marker } ); } + + fn clear_parse_rate(result: &mut TestResult) { + let test_case_info = &mut result.info; + match test_case_info { + TestInfo::ParseTest { + ref mut parse_rate, .. + } => { + assert!(parse_rate.is_some()); + *parse_rate = None; + } + TestInfo::Group { .. } | TestInfo::AssertionTest { .. } => { + panic!("Unexpected test result") + } + } + } + + #[test] + fn run_tests_simple() { + let mut parser = Parser::new(); + let language = get_language("c"); + parser + .set_language(&language) + .expect("Failed to set language"); + let mut languages = BTreeMap::new(); + languages.insert("c", &language); + let opts = TestOptions { + path: PathBuf::from("foo"), + debug: true, + debug_graph: false, + include: None, + exclude: None, + file_name: None, + update: false, + open_log: false, + languages, + color: true, + show_fields: false, + overview_only: false, + }; + + // NOTE: The following test cases are combined to work around a race condition + // in the loader + { + let test_entry = TestEntry::Group { + name: "foo".to_string(), + file_path: None, + children: vec![TestEntry::Example { + name: "C Test 1".to_string(), + input: b"1;\n".to_vec(), + output: "(translation_unit (expression_statement (number_literal)))" + .to_string(), + header_delim_len: 25, + divider_delim_len: 3, + has_fields: false, + attributes_str: String::new(), + attributes: TestAttributes::default(), + file_name: None, + }], + }; + + let mut test_summary = TestSummary::new(true, TestStats::All, false, false, false); + let mut corrected_entries = Vec::new(); + run_tests( + &mut parser, + test_entry, + &opts, + &mut test_summary, + &mut corrected_entries, + true, + ) + .expect("Failed to run tests"); + + // parse rates will always be different, so we need to clear out these + // fields to reliably assert equality below + clear_parse_rate(&mut test_summary.parse_results.root_group[0]); + test_summary.parse_stats.total_duration = Duration::from_secs(0); + + let json_results = serde_json::to_string(&test_summary).unwrap(); + + assert_eq!( + json_results, + json!({ + "parse_results": [ + { + "name": "C Test 1", + "outcome": "Passed", + "parse_rate": null, + "test_num": 1 + } + ], + "parse_failures": [], + "parse_stats": { + "successful_parses": 1, + "total_parses": 1, + "total_bytes": 3, + "total_duration": { + "secs": 0, + "nanos": 0, + } + }, + "highlight_results": [], + "tag_results": [], + "query_results": [] + }) + .to_string() + ); + } + { + let test_entry = TestEntry::Group { + name: "corpus".to_string(), + file_path: None, + children: vec![ + TestEntry::Group { + name: "group1".to_string(), + // This test passes + children: vec![TestEntry::Example { + name: "C Test 1".to_string(), + input: b"1;\n".to_vec(), + output: "(translation_unit (expression_statement (number_literal)))" + .to_string(), + header_delim_len: 25, + divider_delim_len: 3, + has_fields: false, + attributes_str: String::new(), + attributes: TestAttributes::default(), + file_name: None, + }], + file_path: None, + }, + TestEntry::Group { + name: "group2".to_string(), + children: vec![ + // This test passes + TestEntry::Example { + name: "C Test 2".to_string(), + input: b"1;\n".to_vec(), + output: + "(translation_unit (expression_statement (number_literal)))" + .to_string(), + header_delim_len: 25, + divider_delim_len: 3, + has_fields: false, + attributes_str: String::new(), + attributes: TestAttributes::default(), + file_name: None, + }, + // This test fails, and is marked with fail-fast + TestEntry::Example { + name: "C Test 3".to_string(), + input: b"1;\n".to_vec(), + output: + "(translation_unit (expression_statement (string_literal)))" + .to_string(), + header_delim_len: 25, + divider_delim_len: 3, + has_fields: false, + attributes_str: String::new(), + attributes: TestAttributes { + fail_fast: true, + ..Default::default() + }, + file_name: None, + }, + ], + file_path: None, + }, + // This group never runs because of the previous failure + TestEntry::Group { + name: "group3".to_string(), + // This test fails, and is marked with fail-fast + children: vec![TestEntry::Example { + name: "C Test 4".to_string(), + input: b"1;\n".to_vec(), + output: "(translation_unit (expression_statement (number_literal)))" + .to_string(), + header_delim_len: 25, + divider_delim_len: 3, + has_fields: false, + attributes_str: String::new(), + attributes: TestAttributes::default(), + file_name: None, + }], + file_path: None, + }, + ], + }; + + let mut test_summary = TestSummary::new(true, TestStats::All, false, false, false); + let mut corrected_entries = Vec::new(); + run_tests( + &mut parser, + test_entry, + &opts, + &mut test_summary, + &mut corrected_entries, + true, + ) + .expect("Failed to run tests"); + + // parse rates will always be different, so we need to clear out these + // fields to reliably assert equality below + { + let test_group_1_info = &mut test_summary.parse_results.root_group[0].info; + match test_group_1_info { + TestInfo::Group { + ref mut children, .. + } => clear_parse_rate(&mut children[0]), + TestInfo::ParseTest { .. } | TestInfo::AssertionTest { .. } => { + panic!("Unexpected test result"); + } + } + let test_group_2_info = &mut test_summary.parse_results.root_group[1].info; + match test_group_2_info { + TestInfo::Group { + ref mut children, .. + } => { + clear_parse_rate(&mut children[0]); + clear_parse_rate(&mut children[1]); + } + TestInfo::ParseTest { .. } | TestInfo::AssertionTest { .. } => { + panic!("Unexpected test result"); + } + } + test_summary.parse_stats.total_duration = Duration::from_secs(0); + } + + let json_results = serde_json::to_string(&test_summary).unwrap(); + + assert_eq!( + json_results, + json!({ + "parse_results": [ + { + "name": "group1", + "children": [ + { + "name": "C Test 1", + "outcome": "Passed", + "parse_rate": null, + "test_num": 1 + } + ] + }, + { + "name": "group2", + "children": [ + { + "name": "C Test 2", + "outcome": "Passed", + "parse_rate": null, + "test_num": 2 + }, + { + "name": "C Test 3", + "outcome": "Failed", + "parse_rate": null, + "test_num": 3 + } + ] + } + ], + "parse_failures": [ + { + "name": "C Test 3", + "actual": "(translation_unit (expression_statement (number_literal)))", + "expected": "(translation_unit (expression_statement (string_literal)))", + "is_cst": false, + } + ], + "parse_stats": { + "successful_parses": 2, + "total_parses": 3, + "total_bytes": 9, + "total_duration": { + "secs": 0, + "nanos": 0, + } + }, + "highlight_results": [], + "tag_results": [], + "query_results": [] + }) + .to_string() + ); + } + } } diff --git a/crates/cli/src/test_highlight.rs b/crates/cli/src/test_highlight.rs index b03270c6..d96f90c2 100644 --- a/crates/cli/src/test_highlight.rs +++ b/crates/cli/src/test_highlight.rs @@ -1,14 +1,13 @@ use std::{fs, path::Path}; -use anstyle::AnsiColor; use anyhow::{anyhow, Result}; use tree_sitter::Point; use tree_sitter_highlight::{Highlight, HighlightConfiguration, HighlightEvent, Highlighter}; use tree_sitter_loader::{Config, Loader}; use crate::{ - logger::paint, query_testing::{parse_position_comments, to_utf8_point, Assertion, Utf8Point}, + test::{TestInfo, TestOutcome, TestResult, TestSummary}, util, }; @@ -48,19 +47,7 @@ pub fn test_highlights( loader_config: &Config, highlighter: &mut Highlighter, directory: &Path, - use_color: bool, -) -> Result<()> { - println!("syntax highlighting:"); - test_highlights_indented(loader, loader_config, highlighter, directory, use_color, 2) -} - -fn test_highlights_indented( - loader: &Loader, - loader_config: &Config, - highlighter: &mut Highlighter, - directory: &Path, - use_color: bool, - indent_level: usize, + test_summary: &mut TestSummary, ) -> Result<()> { let mut failed = false; @@ -68,25 +55,22 @@ fn test_highlights_indented( let highlight_test_file = highlight_test_file?; let test_file_path = highlight_test_file.path(); let test_file_name = highlight_test_file.file_name(); - print!( - "{indent:indent_level$}", - indent = "", - indent_level = indent_level * 2 - ); if test_file_path.is_dir() && test_file_path.read_dir()?.next().is_some() { - println!("{}:", test_file_name.to_string_lossy()); - if test_highlights_indented( + test_summary + .highlight_results + .add_group(test_file_name.to_string_lossy().as_ref()); + if test_highlights( loader, loader_config, highlighter, &test_file_path, - use_color, - indent_level + 1, + test_summary, ) .is_err() { failed = true; } + test_summary.highlight_results.pop_traversal(); } else { let (language, language_config) = loader .language_configuration_for_file_name(&test_file_path)? @@ -98,7 +82,12 @@ fn test_highlights_indented( })?; let highlight_config = language_config .highlight_config(language, None)? - .ok_or_else(|| anyhow!("No highlighting config found for {test_file_path:?}"))?; + .ok_or_else(|| { + anyhow!( + "No highlighting config found for {}", + test_file_path.display() + ) + })?; match test_highlight( loader, highlighter, @@ -106,30 +95,28 @@ fn test_highlights_indented( fs::read(&test_file_path)?.as_slice(), ) { Ok(assertion_count) => { - println!( - "✓ {} ({assertion_count} assertions)", - paint( - use_color.then_some(AnsiColor::Green), - test_file_name.to_string_lossy().as_ref() - ), - ); + test_summary.highlight_results.add_case(TestResult { + name: test_file_name.to_string_lossy().to_string(), + info: TestInfo::AssertionTest { + outcome: TestOutcome::AssertionPassed { assertion_count }, + test_num: test_summary.test_num, + }, + }); } Err(e) => { - println!( - "✗ {}", - paint( - use_color.then_some(AnsiColor::Red), - test_file_name.to_string_lossy().as_ref() - ) - ); - println!( - "{indent:indent_level$} {e}", - indent = "", - indent_level = indent_level * 2 - ); + test_summary.highlight_results.add_case(TestResult { + name: test_file_name.to_string_lossy().to_string(), + info: TestInfo::AssertionTest { + outcome: TestOutcome::AssertionFailed { + error: e.to_string(), + }, + test_num: test_summary.test_num, + }, + }); failed = true; } } + test_summary.test_num += 1; } } diff --git a/crates/cli/src/test_tags.rs b/crates/cli/src/test_tags.rs index e5a68443..882718e5 100644 --- a/crates/cli/src/test_tags.rs +++ b/crates/cli/src/test_tags.rs @@ -1,13 +1,12 @@ use std::{fs, path::Path}; -use anstyle::AnsiColor; use anyhow::{anyhow, Result}; use tree_sitter_loader::{Config, Loader}; use tree_sitter_tags::{TagsConfiguration, TagsContext}; use crate::{ - logger::paint, query_testing::{parse_position_comments, to_utf8_point, Assertion, Utf8Point}, + test::{TestInfo, TestOutcome, TestResult, TestSummary}, util, }; @@ -47,19 +46,7 @@ pub fn test_tags( loader_config: &Config, tags_context: &mut TagsContext, directory: &Path, - use_color: bool, -) -> Result<()> { - println!("tags:"); - test_tags_indented(loader, loader_config, tags_context, directory, use_color, 2) -} - -pub fn test_tags_indented( - loader: &Loader, - loader_config: &Config, - tags_context: &mut TagsContext, - directory: &Path, - use_color: bool, - indent_level: usize, + test_summary: &mut TestSummary, ) -> Result<()> { let mut failed = false; @@ -67,25 +54,22 @@ pub fn test_tags_indented( let tag_test_file = tag_test_file?; let test_file_path = tag_test_file.path(); let test_file_name = tag_test_file.file_name(); - print!( - "{indent:indent_level$}", - indent = "", - indent_level = indent_level * 2 - ); if test_file_path.is_dir() && test_file_path.read_dir()?.next().is_some() { - println!("{}:", test_file_name.to_string_lossy()); - if test_tags_indented( + test_summary + .tag_results + .add_group(test_file_name.to_string_lossy().as_ref()); + if test_tags( loader, loader_config, tags_context, &test_file_path, - use_color, - indent_level + 1, + test_summary, ) .is_err() { failed = true; } + test_summary.tag_results.pop_traversal(); } else { let (language, language_config) = loader .language_configuration_for_file_name(&test_file_path)? @@ -97,37 +81,35 @@ pub fn test_tags_indented( })?; let tags_config = language_config .tags_config(language)? - .ok_or_else(|| anyhow!("No tags config found for {test_file_path:?}"))?; + .ok_or_else(|| anyhow!("No tags config found for {}", test_file_path.display()))?; match test_tag( tags_context, tags_config, fs::read(&test_file_path)?.as_slice(), ) { Ok(assertion_count) => { - println!( - "✓ {} ({assertion_count} assertions)", - paint( - use_color.then_some(AnsiColor::Green), - test_file_name.to_string_lossy().as_ref() - ), - ); + test_summary.tag_results.add_case(TestResult { + name: test_file_name.to_string_lossy().to_string(), + info: TestInfo::AssertionTest { + outcome: TestOutcome::AssertionPassed { assertion_count }, + test_num: test_summary.test_num, + }, + }); } Err(e) => { - println!( - "✗ {}", - paint( - use_color.then_some(AnsiColor::Red), - test_file_name.to_string_lossy().as_ref() - ) - ); - println!( - "{indent:indent_level$} {e}", - indent = "", - indent_level = indent_level * 2 - ); + test_summary.tag_results.add_case(TestResult { + name: test_file_name.to_string_lossy().to_string(), + info: TestInfo::AssertionTest { + outcome: TestOutcome::AssertionFailed { + error: e.to_string(), + }, + test_num: test_summary.test_num, + }, + }); failed = true; } } + test_summary.test_num += 1; } } diff --git a/crates/cli/src/tests.rs b/crates/cli/src/tests.rs index c64744f8..2439be38 100644 --- a/crates/cli/src/tests.rs +++ b/crates/cli/src/tests.rs @@ -1,11 +1,10 @@ -mod async_context_test; +mod async_boundary_test; mod corpus_test; mod detect_language; mod helpers; mod highlight_test; mod language_test; mod node_test; -mod parser_hang_test; mod parser_test; mod pathological_test; mod query_test; @@ -27,6 +26,8 @@ pub use crate::fuzz::{ ITERATION_COUNT, }; +pub use helpers::fixtures::get_language; + /// This is a simple wrapper around [`tree_sitter_generate::generate_parser_for_grammar`], because /// our tests do not need to pass in a version number, only the grammar JSON. fn generate_parser(grammar_json: &str) -> GenerateResult<(String, String)> { diff --git a/crates/cli/src/tests/async_boundary_test.rs b/crates/cli/src/tests/async_boundary_test.rs new file mode 100644 index 00000000..254ed931 --- /dev/null +++ b/crates/cli/src/tests/async_boundary_test.rs @@ -0,0 +1,150 @@ +use std::{ + future::Future, + pin::Pin, + ptr, + task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, +}; + +use tree_sitter::Parser; + +use super::helpers::fixtures::get_language; + +#[test] +fn test_node_across_async_boundaries() { + let mut parser = Parser::new(); + let language = get_language("bash"); + parser.set_language(&language).unwrap(); + let tree = parser.parse("#", None).unwrap(); + let root = tree.root_node(); + + let (result, yields) = simple_async_executor(async { + let root_ref = &root; + + // Test node captured by value + let fut_by_value = async { + yield_once().await; + root.child(0).unwrap().kind() + }; + + // Test node captured by reference + let fut_by_ref = async { + yield_once().await; + root_ref.child(0).unwrap().kind() + }; + + let result1 = fut_by_value.await; + let result2 = fut_by_ref.await; + + assert_eq!(result1, result2); + result1 + }); + + assert_eq!(result, "comment"); + assert_eq!(yields, 2); +} + +#[test] +fn test_cursor_across_async_boundaries() { + let mut parser = Parser::new(); + let language = get_language("c"); + parser.set_language(&language).unwrap(); + let tree = parser.parse("#", None).unwrap(); + let mut cursor = tree.walk(); + + let ((), yields) = simple_async_executor(async { + cursor.goto_first_child(); + + // Test cursor usage across yield point + yield_once().await; + cursor.goto_first_child(); + + // Test cursor in async block + let cursor_ref = &mut cursor; + let fut = async { + yield_once().await; + cursor_ref.goto_first_child(); + }; + fut.await; + }); + + assert_eq!(yields, 2); +} + +#[test] +fn test_node_and_cursor_together() { + let mut parser = Parser::new(); + let language = get_language("javascript"); + parser.set_language(&language).unwrap(); + let tree = parser.parse("#", None).unwrap(); + let root = tree.root_node(); + let mut cursor = tree.walk(); + + let ((), yields) = simple_async_executor(async { + cursor.goto_first_child(); + + let fut = async { + yield_once().await; + let _ = root.to_sexp(); + cursor.goto_first_child(); + }; + + yield_once().await; + fut.await; + }); + + assert_eq!(yields, 2); +} + +fn simple_async_executor(future: F) -> (F::Output, u32) +where + F: Future, +{ + let waker = noop_waker(); + let mut cx = Context::from_waker(&waker); + let mut yields = 0; + let mut future = Box::pin(future); + + loop { + match future.as_mut().poll(&mut cx) { + Poll::Ready(result) => return (result, yields), + Poll::Pending => yields += 1, + } + } +} + +async fn yield_once() { + struct YieldOnce { + yielded: bool, + } + + impl Future for YieldOnce { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + if self.yielded { + Poll::Ready(()) + } else { + self.yielded = true; + cx.waker().wake_by_ref(); + Poll::Pending + } + } + } + + YieldOnce { yielded: false }.await; +} + +const fn noop_waker() -> Waker { + const VTABLE: RawWakerVTable = RawWakerVTable::new( + // Cloning just returns a new no-op raw waker + |_| RAW, + // `wake` does nothing + |_| {}, + // `wake_by_ref` does nothing + |_| {}, + // Dropping does nothing as we don't allocate anything + |_| {}, + ); + const RAW: RawWaker = RawWaker::new(ptr::null(), &VTABLE); + unsafe { Waker::from_raw(RAW) } +} diff --git a/crates/cli/src/tests/async_context_test.rs b/crates/cli/src/tests/async_context_test.rs deleted file mode 100644 index 48849bd2..00000000 --- a/crates/cli/src/tests/async_context_test.rs +++ /dev/null @@ -1,278 +0,0 @@ -use std::{ - future::Future, - pin::{pin, Pin}, - ptr, - task::{self, Context, Poll, RawWaker, RawWakerVTable, Waker}, -}; - -use tree_sitter::Parser; - -use super::helpers::fixtures::get_language; - -#[test] -fn test_node_in_fut() { - let (ret, pended) = tokio_like_spawn(async { - let mut parser = Parser::new(); - let language = get_language("bash"); - parser.set_language(&language).unwrap(); - - let tree = parser.parse("#", None).unwrap(); - - let root = tree.root_node(); - let root_ref = &root; - - let fut_val_fn = || async { - yield_now().await; - root.child(0).unwrap().kind() - }; - - yield_now().await; - - let fut_ref_fn = || async { - yield_now().await; - root_ref.child(0).unwrap().kind() - }; - - let f1 = fut_val_fn().await; - let f2 = fut_ref_fn().await; - assert_eq!(f1, f2); - - let fut_val = async { - yield_now().await; - root.child(0).unwrap().kind() - }; - - let fut_ref = async { - yield_now().await; - root_ref.child(0).unwrap().kind() - }; - - let f1 = fut_val.await; - let f2 = fut_ref.await; - assert_eq!(f1, f2); - - f1 - }) - .join(); - assert_eq!(ret, "comment"); - assert_eq!(pended, 5); -} - -#[test] -fn test_node_and_cursor_ref_in_fut() { - let ((), pended) = tokio_like_spawn(async { - let mut parser = Parser::new(); - let language = get_language("c"); - parser.set_language(&language).unwrap(); - - let tree = parser.parse("#", None).unwrap(); - - let root = tree.root_node(); - let root_ref = &root; - - let mut cursor = tree.walk(); - let cursor_ref = &mut cursor; - - cursor_ref.goto_first_child(); - - let fut_val = async { - yield_now().await; - let _ = root.to_sexp(); - }; - - yield_now().await; - - let fut_ref = async { - yield_now().await; - let _ = root_ref.to_sexp(); - cursor_ref.goto_first_child(); - }; - - fut_val.await; - fut_ref.await; - - cursor_ref.goto_first_child(); - }) - .join(); - assert_eq!(pended, 3); -} - -#[test] -fn test_node_and_cursor_ref_in_fut_with_fut_fabrics() { - let ((), pended) = tokio_like_spawn(async { - let mut parser = Parser::new(); - let language = get_language("javascript"); - parser.set_language(&language).unwrap(); - - let tree = parser.parse("#", None).unwrap(); - - let root = tree.root_node(); - let root_ref = &root; - - let mut cursor = tree.walk(); - let cursor_ref = &mut cursor; - - cursor_ref.goto_first_child(); - - let fut_val = || async { - yield_now().await; - let _ = root.to_sexp(); - }; - - yield_now().await; - - let fut_ref = || async move { - yield_now().await; - let _ = root_ref.to_sexp(); - cursor_ref.goto_first_child(); - }; - - fut_val().await; - fut_val().await; - fut_ref().await; - }) - .join(); - assert_eq!(pended, 4); -} - -#[test] -fn test_node_and_cursor_ref_in_fut_with_inner_spawns() { - let (ret, pended) = tokio_like_spawn(async { - let mut parser = Parser::new(); - let language = get_language("rust"); - parser.set_language(&language).unwrap(); - - let tree = parser.parse("#", None).unwrap(); - - let mut cursor = tree.walk(); - let cursor_ref = &mut cursor; - - cursor_ref.goto_first_child(); - - let fut_val = || { - let tree = tree.clone(); - async move { - let root = tree.root_node(); - let mut cursor = tree.walk(); - let cursor_ref = &mut cursor; - yield_now().await; - let _ = root.to_sexp(); - cursor_ref.goto_first_child(); - } - }; - - yield_now().await; - - let fut_ref = || { - let tree = tree.clone(); - async move { - let root = tree.root_node(); - let root_ref = &root; - let mut cursor = tree.walk(); - let cursor_ref = &mut cursor; - yield_now().await; - let _ = root_ref.to_sexp(); - cursor_ref.goto_first_child(); - } - }; - - let ((), p1) = tokio_like_spawn(fut_val()).await.unwrap(); - let ((), p2) = tokio_like_spawn(fut_ref()).await.unwrap(); - - cursor_ref.goto_first_child(); - - fut_val().await; - fut_val().await; - fut_ref().await; - - cursor_ref.goto_first_child(); - - p1 + p2 - }) - .join(); - assert_eq!(pended, 4); - assert_eq!(ret, 2); -} - -fn tokio_like_spawn(future: T) -> JoinHandle<(T::Output, usize)> -where - T: Future + Send + 'static, - T::Output: Send + 'static, -{ - // No runtime, just noop waker - - let waker = noop_waker(); - let mut cx = task::Context::from_waker(&waker); - - let mut pending = 0; - let mut future = pin!(future); - let ret = loop { - match future.as_mut().poll(&mut cx) { - Poll::Pending => pending += 1, - Poll::Ready(r) => { - break r; - } - } - }; - JoinHandle::new((ret, pending)) -} - -async fn yield_now() { - struct SimpleYieldNow { - yielded: bool, - } - - impl Future for SimpleYieldNow { - type Output = (); - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { - cx.waker().wake_by_ref(); - if self.yielded { - return Poll::Ready(()); - } - self.yielded = true; - Poll::Pending - } - } - - SimpleYieldNow { yielded: false }.await; -} - -pub const fn noop_waker() -> Waker { - const VTABLE: RawWakerVTable = RawWakerVTable::new( - // Cloning just returns a new no-op raw waker - |_| RAW, - // `wake` does nothing - |_| {}, - // `wake_by_ref` does nothing - |_| {}, - // Dropping does nothing as we don't allocate anything - |_| {}, - ); - const RAW: RawWaker = RawWaker::new(ptr::null(), &VTABLE); - unsafe { Waker::from_raw(RAW) } -} - -struct JoinHandle { - data: Option, -} - -impl JoinHandle { - #[must_use] - const fn new(data: T) -> Self { - Self { data: Some(data) } - } - - const fn join(&mut self) -> T { - self.data.take().unwrap() - } -} - -impl Future for JoinHandle { - type Output = std::result::Result; - - fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { - let data = self.get_mut().data.take().unwrap(); - Poll::Ready(Ok(data)) - } -} diff --git a/crates/cli/src/tests/corpus_test.rs b/crates/cli/src/tests/corpus_test.rs index fe2e2943..ba3fd68e 100644 --- a/crates/cli/src/tests/corpus_test.rs +++ b/crates/cli/src/tests/corpus_test.rs @@ -16,7 +16,7 @@ use crate::{ LOG_GRAPH_ENABLED, START_SEED, }, parse::perform_edit, - test::{parse_tests, print_diff, print_diff_key, strip_sexp_fields}, + test::{parse_tests, strip_sexp_fields, DiffKey, TestDiff}, tests::{ allocations, helpers::fixtures::{fixtures_dir, get_language, get_test_language, SCRATCH_BASE_DIR}, @@ -209,8 +209,8 @@ pub fn test_language_corpus( if actual_output != test.output { println!("Incorrect initial parse for {test_name}"); - print_diff_key(); - print_diff(&actual_output, &test.output, true); + DiffKey::print(); + println!("{}", TestDiff::new(&actual_output, &test.output)); println!(); return false; } @@ -297,8 +297,8 @@ pub fn test_language_corpus( if actual_output != test.output { println!("Incorrect parse for {test_name} - seed {seed}"); - print_diff_key(); - print_diff(&actual_output, &test.output, true); + DiffKey::print(); + println!("{}", TestDiff::new(&actual_output, &test.output)); println!(); return false; } @@ -428,8 +428,8 @@ fn test_feature_corpus_files() { if actual_output == test.output { true } else { - print_diff_key(); - print_diff(&actual_output, &test.output, true); + DiffKey::print(); + print!("{}", TestDiff::new(&actual_output, &test.output)); println!(); false } diff --git a/crates/cli/src/tests/detect_language.rs b/crates/cli/src/tests/detect_language.rs index c94b30b4..c543c31e 100644 --- a/crates/cli/src/tests/detect_language.rs +++ b/crates/cli/src/tests/detect_language.rs @@ -90,7 +90,7 @@ fn detect_language_by_first_line_regex() { } #[test] -fn detect_langauge_by_double_barrel_file_extension() { +fn detect_language_by_double_barrel_file_extension() { let blade_dir = tree_sitter_dir( r#"{ "grammars": [ diff --git a/crates/cli/src/tests/helpers/query_helpers.rs b/crates/cli/src/tests/helpers/query_helpers.rs index bc5617e8..e2c68f17 100644 --- a/crates/cli/src/tests/helpers/query_helpers.rs +++ b/crates/cli/src/tests/helpers/query_helpers.rs @@ -12,7 +12,7 @@ pub struct Pattern { named: bool, field: Option<&'static str>, capture: Option, - children: Vec, + children: Vec, } #[derive(Clone, Debug, PartialEq, Eq)] @@ -225,7 +225,7 @@ impl Pattern { } // Find every matching combination of child patterns and child nodes. - let mut finished_matches = Vec::::new(); + let mut finished_matches = Vec::>::new(); if cursor.goto_first_child() { let mut match_states = vec![(0, mat)]; loop { diff --git a/crates/cli/src/tests/highlight_test.rs b/crates/cli/src/tests/highlight_test.rs index 76c43f43..88209bfe 100644 --- a/crates/cli/src/tests/highlight_test.rs +++ b/crates/cli/src/tests/highlight_test.rs @@ -481,7 +481,7 @@ fn test_highlighting_cancellation() { // The initial `highlight` call, which eagerly parses the outer document, should not fail. let mut highlighter = Highlighter::new(); - let events = highlighter + let mut events = highlighter .highlight( &HTML_HIGHLIGHT, source.as_bytes(), @@ -492,14 +492,18 @@ fn test_highlighting_cancellation() { // Iterating the scopes should not panic. It should return an error once the // cancellation is detected. - for event in events { - if let Err(e) = event { - assert_eq!(e, Error::Cancelled); - return; + let found_cancellation_error = events.any(|event| match event { + Ok(_) => false, + Err(Error::Cancelled) => true, + Err(Error::InvalidLanguage | Error::Unknown) => { + unreachable!("Unexpected error type while iterating events") } - } + }); - panic!("Expected an error while iterating highlighter"); + assert!( + found_cancellation_error, + "Expected a cancellation error while iterating events" + ); } #[test] diff --git a/crates/cli/src/tests/parser_hang_test.rs b/crates/cli/src/tests/parser_hang_test.rs deleted file mode 100644 index 1ff9d17e..00000000 --- a/crates/cli/src/tests/parser_hang_test.rs +++ /dev/null @@ -1,104 +0,0 @@ -// For some reasons `Command::spawn` doesn't work in CI env for many exotic arches. -#![cfg(all(any(target_arch = "x86_64", target_arch = "x86"), not(sanitizing)))] - -use std::{ - env::VarError, - process::{Command, Stdio}, -}; - -use tree_sitter::Parser; -use tree_sitter_generate::load_grammar_file; - -use super::generate_parser; -use crate::tests::helpers::fixtures::{fixtures_dir, get_test_language}; - -// The `sanitizing` cfg is required to don't run tests under specific sunitizer -// because they don't work well with subprocesses _(it's an assumption)_. -// -// Below are two alternative examples of how to disable tests for some arches -// if a way with excluding the whole mod from compilation wouldn't work well. -// -// XXX: Also may be it makes sense to keep such tests as ignored by default -// to omit surprises and enable them on CI by passing an extra option explicitly: -// -// > cargo test -- --include-ignored -// -// #[cfg(all(any(target_arch = "x86_64", target_arch = "x86"), not(sanitizing)))] -// #[cfg_attr(not(all(any(target_arch = "x86_64", target_arch = "x86"), not(sanitizing))), ignore)] -// -#[test] -fn test_grammar_that_should_hang_and_not_segfault() { - let parent_sleep_millis = 1000; - let test_name = "test_grammar_that_should_hang_and_not_segfault"; - let test_var = "CARGO_HANG_TEST"; - - eprintln!(" {test_name}"); - - let tests_exec_path = std::env::args() - .next() - .expect("Failed to get tests executable path"); - - match std::env::var(test_var) { - Ok(v) if v == test_name => { - eprintln!(" child process id {}", std::process::id()); - hang_test(); - } - - Err(VarError::NotPresent) => { - eprintln!(" parent process id {}", std::process::id()); - let mut command = Command::new(tests_exec_path); - command.arg(test_name).env(test_var, test_name); - - if std::env::args().any(|x| x == "--nocapture") { - command.arg("--nocapture"); - } else { - command.stdout(Stdio::null()).stderr(Stdio::null()); - } - - match command.spawn() { - Ok(mut child) => { - std::thread::sleep(std::time::Duration::from_millis(parent_sleep_millis)); - match child.try_wait() { - Ok(Some(status)) if status.success() => { - panic!("Child didn't hang and exited successfully") - } - Ok(Some(status)) => panic!( - "Child didn't hang and exited with status code: {:?}", - status.code() - ), - _ => (), - } - if let Err(e) = child.kill() { - eprintln!( - "Failed to kill hang test's process id: {}, error: {e}", - child.id() - ); - } - } - Err(e) => panic!("{e}"), - } - } - - Err(e) => panic!("Env var error: {e}"), - - _ => unreachable!(), - } -} - -fn hang_test() { - let test_grammar_dir = fixtures_dir() - .join("test_grammars") - .join("get_col_should_hang_not_crash"); - - let grammar_json = load_grammar_file(&test_grammar_dir.join("grammar.js"), None).unwrap(); - let (parser_name, parser_code) = generate_parser(grammar_json.as_str()).unwrap(); - - let language = get_test_language(&parser_name, &parser_code, Some(test_grammar_dir.as_path())); - - let mut parser = Parser::new(); - parser.set_language(&language).unwrap(); - - let code_that_should_hang = "\nHello"; - - parser.parse(code_that_should_hang, None).unwrap(); -} diff --git a/crates/cli/src/tests/parser_test.rs b/crates/cli/src/tests/parser_test.rs index 72f917b3..f1d50319 100644 --- a/crates/cli/src/tests/parser_test.rs +++ b/crates/cli/src/tests/parser_test.rs @@ -1,12 +1,17 @@ use std::{ ops::ControlFlow, - sync::atomic::{AtomicUsize, Ordering}, - thread, time, + sync::{ + atomic::{AtomicUsize, Ordering}, + mpsc, + }, + thread, + time::{self, Duration}, }; use tree_sitter::{ Decode, IncludedRangesError, InputEdit, LogType, ParseOptions, ParseState, Parser, Point, Range, }; +use tree_sitter_generate::load_grammar_file; use tree_sitter_proc_macro::retry; use super::helpers::{ @@ -17,7 +22,11 @@ use super::helpers::{ use crate::{ fuzz::edits::Edit, parse::perform_edit, - tests::{generate_parser, helpers::fixtures::get_test_fixture_language, invert_edit}, + tests::{ + generate_parser, + helpers::fixtures::{fixtures_dir, get_test_fixture_language}, + invert_edit, + }, }; #[test] @@ -88,7 +97,6 @@ fn test_parsing_with_logging() { } #[test] -#[cfg(unix)] fn test_parsing_with_debug_graph_enabled() { use std::io::{BufRead, BufReader, Seek}; @@ -2126,3 +2134,46 @@ fn test_parse_options_reborrow() { assert!(parse_count.load(Ordering::SeqCst) > 0); } + +#[test] +fn test_grammar_that_should_hang_and_not_segfault() { + fn hang_test() { + let test_grammar_dir = fixtures_dir() + .join("test_grammars") + .join("get_col_should_hang_not_crash"); + + let grammar_json = load_grammar_file(&test_grammar_dir.join("grammar.js"), None) + .expect("Failed to load grammar file"); + + let (parser_name, parser_code) = + generate_parser(grammar_json.as_str()).expect("Failed to generate parser"); + + let language = + get_test_language(&parser_name, &parser_code, Some(test_grammar_dir.as_path())); + + let mut parser = Parser::new(); + parser + .set_language(&language) + .expect("Failed to set parser language"); + + let code_that_should_hang = "\nHello"; + + parser + .parse(code_that_should_hang, None) + .expect("Parse operation completed unexpectedly"); + } + + let timeout = Duration::from_millis(500); + let (tx, rx) = mpsc::channel(); + + thread::spawn(move || tx.send(std::panic::catch_unwind(hang_test))); + + match rx.recv_timeout(timeout) { + Ok(Ok(())) => panic!("The test completed rather than hanging"), + Ok(Err(panic_info)) => panic!("The test panicked unexpectedly: {panic_info:?}"), + Err(mpsc::RecvTimeoutError::Timeout) => {} // Expected + Err(mpsc::RecvTimeoutError::Disconnected) => { + panic!("The test thread disconnected unexpectedly") + } + } +} diff --git a/crates/cli/src/tests/query_test.rs b/crates/cli/src/tests/query_test.rs index 835138ce..3f1467e5 100644 --- a/crates/cli/src/tests/query_test.rs +++ b/crates/cli/src/tests/query_test.rs @@ -8,6 +8,7 @@ use tree_sitter::{ QueryCursorOptions, QueryError, QueryErrorKind, QueryPredicate, QueryPredicateArg, QueryProperty, Range, }; +use tree_sitter_generate::load_grammar_file; use unindent::Unindent; use super::helpers::{ @@ -237,6 +238,20 @@ fn test_query_errors_on_invalid_syntax() { ] .join("\n") ); + assert_eq!( + Query::new(&language, "(statement / export_statement)").unwrap_err(), + QueryError { + row: 0, + offset: 11, + column: 11, + kind: QueryErrorKind::Syntax, + message: [ + "(statement / export_statement)", // + " ^" + ] + .join("\n") + } + ); }); } @@ -415,11 +430,11 @@ fn test_query_errors_on_impossible_patterns() { Err(QueryError { kind: QueryErrorKind::Structure, row: 0, - offset: 51, - column: 51, + offset: 37, + column: 37, message: [ "(binary_expression left: (expression (identifier)) left: (expression (identifier)))", - " ^", + " ^", ] .join("\n"), }) @@ -2654,6 +2669,64 @@ fn test_query_matches_within_range_of_long_repetition() { }); } +#[test] +fn test_query_matches_contained_within_range() { + allocations::record(|| { + let language = get_language("json"); + let query = Query::new( + &language, + r#" + ("[" @l_bracket "]" @r_bracket) + ("{" @l_brace "}" @r_brace) + "#, + ) + .unwrap(); + + let source = r#" + [ + {"key1": "value1"}, + {"key2": "value2"}, + {"key3": "value3"}, + {"key4": "value4"}, + {"key5": "value5"}, + {"key6": "value6"}, + {"key7": "value7"}, + {"key8": "value8"}, + {"key9": "value9"}, + {"key10": "value10"}, + {"key11": "value11"}, + {"key12": "value12"}, + ] + "# + .unindent(); + + let mut parser = Parser::new(); + parser.set_language(&language).unwrap(); + let tree = parser.parse(&source, None).unwrap(); + + let expected_matches = [ + (1, vec![("l_brace", "{"), ("r_brace", "}")]), + (1, vec![("l_brace", "{"), ("r_brace", "}")]), + ]; + { + let mut cursor = QueryCursor::new(); + let matches = cursor + .set_containing_point_range(Point::new(5, 0)..Point::new(7, 0)) + .matches(&query, tree.root_node(), source.as_bytes()); + assert_eq!(collect_matches(matches, &query, &source), &expected_matches); + } + { + let mut cursor = QueryCursor::new(); + let matches = cursor.set_containing_byte_range(78..120).matches( + &query, + tree.root_node(), + source.as_bytes(), + ); + assert_eq!(collect_matches(matches, &query, &source), &expected_matches); + } + }); +} + #[test] fn test_query_matches_different_queries_same_cursor() { allocations::record(|| { @@ -4186,12 +4259,9 @@ fn test_query_random() { let pattern = pattern_ast.to_string(); let expected_matches = pattern_ast.matches_in_tree(&test_tree); - let query = match Query::new(&language, &pattern) { - Ok(query) => query, - Err(e) => { - panic!("failed to build query for pattern {pattern} - {e}. seed: {seed}"); - } - }; + let query = Query::new(&language, &pattern).unwrap_or_else(|e| { + panic!("failed to build query for pattern {pattern}. seed: {seed}\n{e}") + }); let mut actual_matches = Vec::new(); let mut match_iter = cursor.matches( &query, @@ -5020,6 +5090,26 @@ fn test_query_quantified_captures() { ("comment.documentation", "// quuz"), ], }, + Row { + description: "multiple quantifiers should not hang query parsing", + language: get_language("c"), + code: indoc! {" + // foo + // bar + // baz + "}, + pattern: r" + ((comment) ?+ @comment) + ", + // This should be identical to the `*` quantifier. + captures: &[ + ("comment", "// foo"), + ("comment", "// foo"), + ("comment", "// foo"), + ("comment", "// bar"), + ("comment", "// baz"), + ], + }, ]; allocations::record(|| { @@ -5765,3 +5855,109 @@ fn test_query_allows_error_nodes_with_children() { assert_eq!(matches, &[(0, vec![("error", ".bar")])]); }); } + +#[test] +fn test_query_assertion_on_unreachable_node_with_child() { + // The `await_binding` rule is unreachable because it has a lower precedence than + // `identifier`, so we'll always reduce to an expression of type `identifier` + // instead whenever we see the token `await` followed by an identifier. + // + // A query that tries to capture the `await` token in the `await_binding` rule + // should not cause an assertion failure during query analysis. + let grammar = r#" +export default grammar({ + name: "query_assertion_crash", + + rules: { + source_file: $ => repeat($.expression), + + expression: $ => choice( + $.await_binding, + $.await_expr, + $.equal_expr, + prec(3, $.identifier), + ), + + await_binding: $ => prec(1, seq('await', $.identifier, '=', $.expression)), + + await_expr: $ => prec(1, seq('await', $.expression)), + + equal_expr: $ => prec.right(2, seq($.expression, '=', $.expression)), + + identifier: _ => /[a-z]+/, + } +}); + "#; + + let file = tempfile::NamedTempFile::with_suffix(".js").unwrap(); + std::fs::write(file.path(), grammar).unwrap(); + + let grammar_json = load_grammar_file(file.path(), None).unwrap(); + + let (parser_name, parser_code) = generate_parser(&grammar_json).unwrap(); + + let language = get_test_language(&parser_name, &parser_code, None); + + let query_result = Query::new(&language, r#"(await_binding "await")"#); + + assert!(query_result.is_err()); + assert_eq!( + query_result.unwrap_err(), + QueryError { + kind: QueryErrorKind::Structure, + row: 0, + offset: 0, + column: 0, + message: ["(await_binding \"await\")", "^"].join("\n"), + } + ); +} + +#[test] +fn test_query_supertype_with_anonymous_node() { + let grammar = r#" +export default grammar({ + name: "supertype_anonymous_test", + + extras: $ => [/\s/, $.comment], + + supertypes: $ => [$.expression], + + word: $ => $.identifier, + + rules: { + source_file: $ => repeat($.expression), + + expression: $ => choice( + $.function_call, + '()' // an empty tuple, which should be queryable with the supertype syntax + ), + + function_call: $ => seq($.identifier, '()'), + + identifier: _ => /[a-zA-Z_][a-zA-Z0-9_]*/, + + comment: _ => token(seq('//', /.*/)), + } +}); + "#; + + let file = tempfile::NamedTempFile::with_suffix(".js").unwrap(); + std::fs::write(file.path(), grammar).unwrap(); + + let grammar_json = load_grammar_file(file.path(), None).unwrap(); + + let (parser_name, parser_code) = generate_parser(&grammar_json).unwrap(); + + let language = get_test_language(&parser_name, &parser_code, None); + + let query_result = Query::new(&language, r#"(expression/"()") @tuple"#); + + assert!(query_result.is_ok()); + + let query = query_result.unwrap(); + + let source = "foo()\n()"; + + assert_query_matches(&language, &query, source, &[(0, vec![("tuple", "()")])]); +} diff --git a/crates/cli/src/tests/tags_test.rs b/crates/cli/src/tests/tags_test.rs index 232a01dc..0c9f7111 100644 --- a/crates/cli/src/tests/tags_test.rs +++ b/crates/cli/src/tests/tags_test.rs @@ -1,6 +1,7 @@ use std::{ ffi::{CStr, CString}, fs, ptr, slice, str, + sync::atomic::{AtomicUsize, Ordering}, }; use tree_sitter::Point; @@ -262,34 +263,34 @@ fn test_tags_ruby() { #[test] fn test_tags_cancellation() { - use std::sync::atomic::{AtomicUsize, Ordering}; - allocations::record(|| { // Large javascript document - let source = (0..500) - .map(|_| "/* hi */ class A { /* ok */ b() {} }\n") - .collect::(); - + let source = "/* hi */ class A { /* ok */ b() {} }\n".repeat(500); let cancellation_flag = AtomicUsize::new(0); let language = get_language("javascript"); let tags_config = TagsConfiguration::new(language, JS_TAG_QUERY, "").unwrap(); - let mut tag_context = TagsContext::new(); let tags = tag_context .generate_tags(&tags_config, source.as_bytes(), Some(&cancellation_flag)) .unwrap(); - for (i, tag) in tags.0.enumerate() { + let found_cancellation_error = tags.0.enumerate().any(|(i, tag)| { if i == 150 { cancellation_flag.store(1, Ordering::SeqCst); } - if let Err(e) = tag { - assert_eq!(e, Error::Cancelled); - return; + match tag { + Ok(_) => false, + Err(Error::Cancelled) => true, + Err(e) => { + unreachable!("Unexpected error type while iterating tags: {e}") + } } - } + }); - panic!("Expected to halt tagging with an error"); + assert!( + found_cancellation_error, + "Expected to halt tagging with a cancellation error" + ); }); } diff --git a/crates/cli/src/version.rs b/crates/cli/src/version.rs index 39cd5481..757306c7 100644 --- a/crates/cli/src/version.rs +++ b/crates/cli/src/version.rs @@ -1,6 +1,5 @@ use std::{fs, path::PathBuf, process::Command}; -use anyhow::{anyhow, Context, Result}; use clap::ValueEnum; use log::{info, warn}; use regex::Regex; @@ -22,6 +21,36 @@ pub struct Version { pub bump: Option, } +#[derive(thiserror::Error, Debug)] +pub enum VersionError { + #[error(transparent)] + Json(#[from] serde_json::Error), + #[error(transparent)] + Io(#[from] std::io::Error), + #[error("Failed to update one or more files:\n\n{0}")] + Update(UpdateErrors), +} + +#[derive(thiserror::Error, Debug)] +pub struct UpdateErrors(Vec); + +impl std::fmt::Display for UpdateErrors { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for error in &self.0 { + writeln!(f, "{error}\n")?; + } + Ok(()) + } +} + +#[derive(thiserror::Error, Debug)] +pub enum UpdateError { + #[error("Failed to update {1}:\n{0}")] + Io(std::io::Error, PathBuf), + #[error("Failed to run `{0}`:\n{1}")] + Command(&'static str, String), +} + impl Version { #[must_use] pub const fn new( @@ -36,7 +65,7 @@ impl Version { } } - pub fn run(mut self) -> Result<()> { + pub fn run(mut self) -> Result<(), VersionError> { let tree_sitter_json = self.current_dir.join("tree-sitter.json"); let tree_sitter_json = @@ -84,98 +113,101 @@ impl Version { let is_multigrammar = tree_sitter_json.grammars.len() > 1; - self.update_treesitter_json().with_context(|| { - format!( - "Failed to update tree-sitter.json at {}", - self.current_dir.display() - ) - })?; - self.update_cargo_toml().with_context(|| { - format!( - "Failed to update Cargo.toml at {}", - self.current_dir.display() - ) - })?; - self.update_package_json().with_context(|| { - format!( - "Failed to update package.json at {}", - self.current_dir.display() - ) - })?; - self.update_makefile(is_multigrammar).with_context(|| { - format!( - "Failed to update Makefile at {}", - self.current_dir.display() - ) - })?; - self.update_cmakelists_txt().with_context(|| { - format!( - "Failed to update CMakeLists.txt at {}", - self.current_dir.display() - ) - })?; - self.update_pyproject_toml().with_context(|| { - format!( - "Failed to update pyproject.toml at {}", - self.current_dir.display() - ) - })?; + let mut errors = Vec::new(); - Ok(()) + // Helper to push errors into the errors vector, returns true if an error was pushed + let mut push_err = |result: Result<(), UpdateError>| -> bool { + if let Err(e) = result { + errors.push(e); + return true; + } + false + }; + + push_err(self.update_treesitter_json()); + + // Only update Cargo.lock if Cargo.toml was updated + push_err(self.update_cargo_toml()).then(|| push_err(self.update_cargo_lock())); + + // Only update package-lock.json if package.json was updated + push_err(self.update_package_json()).then(|| push_err(self.update_package_lock_json())); + + push_err(self.update_makefile(is_multigrammar)); + push_err(self.update_cmakelists_txt()); + push_err(self.update_pyproject_toml()); + push_err(self.update_zig_zon()); + + if errors.is_empty() { + Ok(()) + } else { + Err(VersionError::Update(UpdateErrors(errors))) + } } - fn update_treesitter_json(&self) -> Result<()> { - let tree_sitter_json = &fs::read_to_string(self.current_dir.join("tree-sitter.json"))?; - - let tree_sitter_json = tree_sitter_json - .lines() - .map(|line| { - if line.contains("\"version\":") { - let prefix_index = line.find("\"version\":").unwrap() + "\"version\":".len(); - let start_quote = line[prefix_index..].find('"').unwrap() + prefix_index + 1; - let end_quote = line[start_quote + 1..].find('"').unwrap() + start_quote + 1; - - format!( - "{}{}{}", - &line[..start_quote], - self.version.as_ref().unwrap(), - &line[end_quote..] - ) - } else { - line.to_string() - } - }) - .collect::>() - .join("\n") - + "\n"; - - fs::write(self.current_dir.join("tree-sitter.json"), tree_sitter_json)?; - - Ok(()) + fn update_file_with(&self, path: &PathBuf, update_fn: F) -> Result<(), UpdateError> + where + F: Fn(&str) -> String, + { + let content = fs::read_to_string(path).map_err(|e| UpdateError::Io(e, path.clone()))?; + let updated_content = update_fn(&content); + fs::write(path, updated_content).map_err(|e| UpdateError::Io(e, path.clone())) } - fn update_cargo_toml(&self) -> Result<()> { - if !self.current_dir.join("Cargo.toml").exists() { + fn update_treesitter_json(&self) -> Result<(), UpdateError> { + let json_path = self.current_dir.join("tree-sitter.json"); + self.update_file_with(&json_path, |content| { + content + .lines() + .map(|line| { + if line.contains("\"version\":") { + let prefix_index = + line.find("\"version\":").unwrap() + "\"version\":".len(); + let start_quote = + line[prefix_index..].find('"').unwrap() + prefix_index + 1; + let end_quote = + line[start_quote + 1..].find('"').unwrap() + start_quote + 1; + + format!( + "{}{}{}", + &line[..start_quote], + self.version.as_ref().unwrap(), + &line[end_quote..] + ) + } else { + line.to_string() + } + }) + .collect::>() + .join("\n") + + "\n" + }) + } + + fn update_cargo_toml(&self) -> Result<(), UpdateError> { + let cargo_toml_path = self.current_dir.join("Cargo.toml"); + if !cargo_toml_path.exists() { return Ok(()); } - let cargo_toml = fs::read_to_string(self.current_dir.join("Cargo.toml"))?; + self.update_file_with(&cargo_toml_path, |content| { + content + .lines() + .map(|line| { + if line.starts_with("version =") { + format!("version = \"{}\"", self.version.as_ref().unwrap()) + } else { + line.to_string() + } + }) + .collect::>() + .join("\n") + + "\n" + })?; - let cargo_toml = cargo_toml - .lines() - .map(|line| { - if line.starts_with("version =") { - format!("version = \"{}\"", self.version.as_ref().unwrap()) - } else { - line.to_string() - } - }) - .collect::>() - .join("\n") - + "\n"; - - fs::write(self.current_dir.join("Cargo.toml"), cargo_toml)?; + Ok(()) + } + fn update_cargo_lock(&self) -> Result<(), UpdateError> { if self.current_dir.join("Cargo.lock").exists() { let Ok(cmd) = Command::new("cargo") .arg("generate-lockfile") @@ -188,8 +220,9 @@ impl Version { if !cmd.status.success() { let stderr = String::from_utf8_lossy(&cmd.stderr); - return Err(anyhow!( - "Failed to run `cargo generate-lockfile`:\n{stderr}" + return Err(UpdateError::Command( + "cargo generate-lockfile", + stderr.to_string(), )); } } @@ -197,37 +230,43 @@ impl Version { Ok(()) } - fn update_package_json(&self) -> Result<()> { - if !self.current_dir.join("package.json").exists() { + fn update_package_json(&self) -> Result<(), UpdateError> { + let package_json_path = self.current_dir.join("package.json"); + if !package_json_path.exists() { return Ok(()); } - let package_json = &fs::read_to_string(self.current_dir.join("package.json"))?; + self.update_file_with(&package_json_path, |content| { + content + .lines() + .map(|line| { + if line.contains("\"version\":") { + let prefix_index = + line.find("\"version\":").unwrap() + "\"version\":".len(); + let start_quote = + line[prefix_index..].find('"').unwrap() + prefix_index + 1; + let end_quote = + line[start_quote + 1..].find('"').unwrap() + start_quote + 1; - let package_json = package_json - .lines() - .map(|line| { - if line.contains("\"version\":") { - let prefix_index = line.find("\"version\":").unwrap() + "\"version\":".len(); - let start_quote = line[prefix_index..].find('"').unwrap() + prefix_index + 1; - let end_quote = line[start_quote + 1..].find('"').unwrap() + start_quote + 1; + format!( + "{}{}{}", + &line[..start_quote], + self.version.as_ref().unwrap(), + &line[end_quote..] + ) + } else { + line.to_string() + } + }) + .collect::>() + .join("\n") + + "\n" + })?; - format!( - "{}{}{}", - &line[..start_quote], - self.version.as_ref().unwrap(), - &line[end_quote..] - ) - } else { - line.to_string() - } - }) - .collect::>() - .join("\n") - + "\n"; - - fs::write(self.current_dir.join("package.json"), package_json)?; + Ok(()) + } + fn update_package_lock_json(&self) -> Result<(), UpdateError> { if self.current_dir.join("package-lock.json").exists() { let Ok(cmd) = Command::new("npm") .arg("install") @@ -240,82 +279,117 @@ impl Version { if !cmd.status.success() { let stderr = String::from_utf8_lossy(&cmd.stderr); - return Err(anyhow!("Failed to run `npm install`:\n{stderr}")); + return Err(UpdateError::Command("npm install", stderr.to_string())); } } Ok(()) } - fn update_makefile(&self, is_multigrammar: bool) -> Result<()> { - let makefile = if is_multigrammar { - if !self.current_dir.join("common").join("common.mak").exists() { - return Ok(()); - } - - fs::read_to_string(self.current_dir.join("Makefile"))? + fn update_makefile(&self, is_multigrammar: bool) -> Result<(), UpdateError> { + let makefile_path = if is_multigrammar { + self.current_dir.join("common").join("common.mak") } else { - if !self.current_dir.join("Makefile").exists() { - return Ok(()); - } - - fs::read_to_string(self.current_dir.join("Makefile"))? + self.current_dir.join("Makefile") }; - let makefile = makefile - .lines() - .map(|line| { - if line.starts_with("VERSION") { - format!("VERSION := {}", self.version.as_ref().unwrap()) - } else { - line.to_string() - } - }) - .collect::>() - .join("\n") - + "\n"; - - fs::write(self.current_dir.join("Makefile"), makefile)?; + self.update_file_with(&makefile_path, |content| { + content + .lines() + .map(|line| { + if line.starts_with("VERSION") { + format!("VERSION := {}", self.version.as_ref().unwrap()) + } else { + line.to_string() + } + }) + .collect::>() + .join("\n") + + "\n" + })?; Ok(()) } - fn update_cmakelists_txt(&self) -> Result<()> { - if !self.current_dir.join("CMakeLists.txt").exists() { + fn update_cmakelists_txt(&self) -> Result<(), UpdateError> { + let cmake_lists_path = self.current_dir.join("CMakeLists.txt"); + if !cmake_lists_path.exists() { return Ok(()); } - let cmake = fs::read_to_string(self.current_dir.join("CMakeLists.txt"))?; - - let re = Regex::new(r#"(\s*VERSION\s+)"[0-9]+\.[0-9]+\.[0-9]+""#)?; - let cmake = re.replace(&cmake, format!(r#"$1"{}""#, self.version.as_ref().unwrap())); - - fs::write(self.current_dir.join("CMakeLists.txt"), cmake.as_bytes())?; + self.update_file_with(&cmake_lists_path, |content| { + let re = Regex::new(r#"(\s*VERSION\s+)"[0-9]+\.[0-9]+\.[0-9]+""#) + .expect("Failed to compile regex"); + re.replace( + content, + format!(r#"$1"{}""#, self.version.as_ref().unwrap()), + ) + .to_string() + })?; Ok(()) } - fn update_pyproject_toml(&self) -> Result<()> { - if !self.current_dir.join("pyproject.toml").exists() { + fn update_pyproject_toml(&self) -> Result<(), UpdateError> { + let pyproject_toml_path = self.current_dir.join("pyproject.toml"); + if !pyproject_toml_path.exists() { return Ok(()); } - let pyproject_toml = fs::read_to_string(self.current_dir.join("pyproject.toml"))?; + self.update_file_with(&pyproject_toml_path, |content| { + content + .lines() + .map(|line| { + if line.starts_with("version =") { + format!("version = \"{}\"", self.version.as_ref().unwrap()) + } else { + line.to_string() + } + }) + .collect::>() + .join("\n") + + "\n" + })?; - let pyproject_toml = pyproject_toml - .lines() - .map(|line| { - if line.starts_with("version =") { - format!("version = \"{}\"", self.version.as_ref().unwrap()) - } else { - line.to_string() - } - }) - .collect::>() - .join("\n") - + "\n"; + Ok(()) + } - fs::write(self.current_dir.join("pyproject.toml"), pyproject_toml)?; + fn update_zig_zon(&self) -> Result<(), UpdateError> { + let zig_zon_path = self.current_dir.join("build.zig.zon"); + if !zig_zon_path.exists() { + return Ok(()); + } + + self.update_file_with(&zig_zon_path, |content| { + let zig_version_prefix = ".version ="; + content + .lines() + .map(|line| { + if line + .trim_start_matches(|c: char| c.is_ascii_whitespace()) + .starts_with(zig_version_prefix) + { + let prefix_index = + line.find(zig_version_prefix).unwrap() + zig_version_prefix.len(); + let start_quote = + line[prefix_index..].find('"').unwrap() + prefix_index + 1; + let end_quote = + line[start_quote + 1..].find('"').unwrap() + start_quote + 1; + + format!( + "{}{}{}", + &line[..start_quote], + self.version.as_ref().unwrap(), + &line[end_quote..] + ) + } else { + line.to_string() + } + }) + .collect::>() + .join("\n") + + "\n" + })?; Ok(()) } diff --git a/crates/config/Cargo.toml b/crates/config/Cargo.toml index b9bc239e..641b434b 100644 --- a/crates/config/Cargo.toml +++ b/crates/config/Cargo.toml @@ -20,8 +20,8 @@ path = "src/tree_sitter_config.rs" workspace = true [dependencies] -anyhow.workspace = true etcetera.workspace = true log.workspace = true serde.workspace = true serde_json.workspace = true +thiserror.workspace = true diff --git a/crates/config/src/tree_sitter_config.rs b/crates/config/src/tree_sitter_config.rs index 85dc003d..17b1d384 100644 --- a/crates/config/src/tree_sitter_config.rs +++ b/crates/config/src/tree_sitter_config.rs @@ -1,12 +1,54 @@ #![cfg_attr(not(any(test, doctest)), doc = include_str!("../README.md"))] -use std::{env, fs, path::PathBuf}; +use std::{ + env, fs, + path::{Path, PathBuf}, +}; -use anyhow::{Context, Result}; use etcetera::BaseStrategy as _; use log::warn; use serde::{Deserialize, Serialize}; use serde_json::Value; +use thiserror::Error; + +pub type ConfigResult = Result; + +#[derive(Debug, Error)] +pub enum ConfigError { + #[error("Bad JSON config {0} -- {1}")] + ConfigRead(String, serde_json::Error), + #[error(transparent)] + HomeDir(#[from] etcetera::HomeDirError), + #[error(transparent)] + IO(IoError), + #[error(transparent)] + Serialization(#[from] serde_json::Error), +} + +#[derive(Debug, Error)] +pub struct IoError { + pub error: std::io::Error, + pub path: Option, +} + +impl IoError { + fn new(error: std::io::Error, path: Option<&Path>) -> Self { + Self { + error, + path: path.map(|p| p.to_string_lossy().to_string()), + } + } +} + +impl std::fmt::Display for IoError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.error)?; + if let Some(ref path) = self.path { + write!(f, " ({path})")?; + } + Ok(()) + } +} /// Holds the contents of tree-sitter's configuration file. /// @@ -23,7 +65,7 @@ pub struct Config { } impl Config { - pub fn find_config_file() -> Result> { + pub fn find_config_file() -> ConfigResult> { if let Ok(path) = env::var("TREE_SITTER_DIR") { let mut path = PathBuf::from(path); path.push("config.json"); @@ -46,8 +88,12 @@ impl Config { .join("tree-sitter") .join("config.json"); if legacy_apple_path.is_file() { - fs::create_dir_all(xdg_path.parent().unwrap())?; - fs::rename(&legacy_apple_path, &xdg_path)?; + let xdg_dir = xdg_path.parent().unwrap(); + fs::create_dir_all(xdg_dir) + .map_err(|e| ConfigError::IO(IoError::new(e, Some(xdg_dir))))?; + fs::rename(&legacy_apple_path, &xdg_path).map_err(|e| { + ConfigError::IO(IoError::new(e, Some(legacy_apple_path.as_path()))) + })?; warn!( "Your config.json file has been automatically migrated from \"{}\" to \"{}\"", legacy_apple_path.display(), @@ -67,7 +113,7 @@ impl Config { Ok(None) } - fn xdg_config_file() -> Result { + fn xdg_config_file() -> ConfigResult { let xdg_path = etcetera::choose_base_strategy()? .config_dir() .join("tree-sitter") @@ -84,7 +130,7 @@ impl Config { /// [`etcetera::choose_base_strategy`](https://docs.rs/etcetera/*/etcetera/#basestrategy) /// - `$HOME/.tree-sitter/config.json` as a fallback from where tree-sitter _used_ to store /// its configuration - pub fn load(path: Option) -> Result { + pub fn load(path: Option) -> ConfigResult { let location = if let Some(path) = path { path } else if let Some(path) = Self::find_config_file()? { @@ -94,9 +140,9 @@ impl Config { }; let content = fs::read_to_string(&location) - .with_context(|| format!("Failed to read {}", location.to_string_lossy()))?; + .map_err(|e| ConfigError::IO(IoError::new(e, Some(location.as_path()))))?; let config = serde_json::from_str(&content) - .with_context(|| format!("Bad JSON config {}", location.to_string_lossy()))?; + .map_err(|e| ConfigError::ConfigRead(location.to_string_lossy().to_string(), e))?; Ok(Self { location, config }) } @@ -106,7 +152,7 @@ impl Config { /// disk. /// /// (Note that this is typically only done by the `tree-sitter init-config` command.) - pub fn initial() -> Result { + pub fn initial() -> ConfigResult { let location = if let Ok(path) = env::var("TREE_SITTER_DIR") { let mut path = PathBuf::from(path); path.push("config.json"); @@ -119,17 +165,20 @@ impl Config { } /// Saves this configuration to the file that it was originally loaded from. - pub fn save(&self) -> Result<()> { + pub fn save(&self) -> ConfigResult<()> { let json = serde_json::to_string_pretty(&self.config)?; - fs::create_dir_all(self.location.parent().unwrap())?; - fs::write(&self.location, json)?; + let config_dir = self.location.parent().unwrap(); + fs::create_dir_all(config_dir) + .map_err(|e| ConfigError::IO(IoError::new(e, Some(config_dir))))?; + fs::write(&self.location, json) + .map_err(|e| ConfigError::IO(IoError::new(e, Some(self.location.as_path()))))?; Ok(()) } /// Parses a component-specific configuration from the configuration file. The type `C` must /// be [deserializable](https://docs.rs/serde/*/serde/trait.Deserialize.html) from a JSON /// object, and must only include the fields relevant to that component. - pub fn get(&self) -> Result + pub fn get(&self) -> ConfigResult where C: for<'de> Deserialize<'de>, { @@ -140,7 +189,7 @@ impl Config { /// Adds a component-specific configuration to the configuration file. The type `C` must be /// [serializable](https://docs.rs/serde/*/serde/trait.Serialize.html) into a JSON object, and /// must only include the fields relevant to that component. - pub fn add(&mut self, config: C) -> Result<()> + pub fn add(&mut self, config: C) -> ConfigResult<()> where C: Serialize, { diff --git a/crates/generate/Cargo.toml b/crates/generate/Cargo.toml index 61b1686a..e55be890 100644 --- a/crates/generate/Cargo.toml +++ b/crates/generate/Cargo.toml @@ -25,7 +25,7 @@ load = ["dep:semver"] qjs-rt = ["load", "rquickjs", "pathdiff"] [dependencies] -anyhow.workspace = true +bitflags = "2.9.4" dunce = "1.0.5" indexmap.workspace = true indoc.workspace = true @@ -33,7 +33,7 @@ log.workspace = true pathdiff = { version = "0.2.3", optional = true } regex.workspace = true regex-syntax.workspace = true -rquickjs = { version = "0.9.0", optional = true, features = [ +rquickjs = { version = "0.11.0", optional = true, features = [ "bindgen", "loader", "macro", diff --git a/crates/generate/src/build_tables.rs b/crates/generate/src/build_tables.rs index c6020cd2..8c6ef2a4 100644 --- a/crates/generate/src/build_tables.rs +++ b/crates/generate/src/build_tables.rs @@ -27,6 +27,7 @@ use crate::{ node_types::VariableInfo, rules::{AliasMap, Symbol, SymbolType, TokenSet}, tables::{LexTable, ParseAction, ParseTable, ParseTableEntry}, + OptLevel, }; pub struct Tables { @@ -43,6 +44,7 @@ pub fn build_tables( variable_info: &[VariableInfo], inlines: &InlinedProductionMap, report_symbol_name: Option<&str>, + optimizations: OptLevel, ) -> BuildTableResult { let item_set_builder = ParseItemSetBuilder::new(syntax_grammar, lexical_grammar, inlines); let following_tokens = @@ -78,6 +80,7 @@ pub fn build_tables( simple_aliases, &token_conflict_map, &keywords, + optimizations, ); let lex_tables = build_lex_table( &mut parse_table, @@ -100,6 +103,10 @@ pub fn build_tables( ); } + if parse_table.states.len() > u16::MAX as usize { + Err(ParseTableBuilderError::StateCount(parse_table.states.len()))?; + } + Ok(Tables { parse_table, main_lex_table: lex_tables.main_lex_table, diff --git a/crates/generate/src/build_tables/build_parse_table.rs b/crates/generate/src/build_tables/build_parse_table.rs index f292542d..66f29609 100644 --- a/crates/generate/src/build_tables/build_parse_table.rs +++ b/crates/generate/src/build_tables/build_parse_table.rs @@ -77,9 +77,11 @@ pub enum ParseTableBuilderError { "The non-terminal rule `{0}` is used in a non-terminal `extra` rule, which is not allowed." )] ImproperNonTerminalExtra(String), + #[error("State count `{0}` exceeds the max value {max}.", max=u16::MAX)] + StateCount(usize), } -#[derive(Default, Debug, Serialize)] +#[derive(Default, Debug, Serialize, Error)] pub struct ConflictError { pub symbol_sequence: Vec, pub conflicting_lookahead: String, @@ -87,7 +89,7 @@ pub struct ConflictError { pub possible_resolutions: Vec, } -#[derive(Default, Debug, Serialize)] +#[derive(Default, Debug, Serialize, Error)] pub struct Interpretation { pub preceding_symbols: Vec, pub variable_name: String, @@ -106,7 +108,7 @@ pub enum Resolution { AddConflict { symbols: Vec }, } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Error)] pub struct AmbiguousExtraError { pub parent_symbols: Vec, } @@ -236,9 +238,6 @@ impl std::fmt::Display for AmbiguousExtraError { } } -impl std::error::Error for ConflictError {} -impl std::error::Error for AmbiguousExtraError {} - impl<'a> ParseTableBuilder<'a> { fn new( syntax_grammar: &'a SyntaxGrammar, diff --git a/crates/generate/src/build_tables/item.rs b/crates/generate/src/build_tables/item.rs index 0beb3e3c..cd70ce74 100644 --- a/crates/generate/src/build_tables/item.rs +++ b/crates/generate/src/build_tables/item.rs @@ -204,7 +204,7 @@ impl fmt::Display for ParseItemDisplay<'_> { || step.reserved_word_set_id != ReservedWordSetId::default() { write!(f, " (")?; - if step.precedence.is_none() { + if !step.precedence.is_none() { write!(f, " {}", step.precedence)?; } if let Some(associativity) = step.associativity { diff --git a/crates/generate/src/build_tables/minimize_parse_table.rs b/crates/generate/src/build_tables/minimize_parse_table.rs index 9655cb88..6c26f1c4 100644 --- a/crates/generate/src/build_tables/minimize_parse_table.rs +++ b/crates/generate/src/build_tables/minimize_parse_table.rs @@ -11,6 +11,7 @@ use crate::{ grammars::{LexicalGrammar, SyntaxGrammar, VariableType}, rules::{AliasMap, Symbol, TokenSet}, tables::{GotoAction, ParseAction, ParseState, ParseStateId, ParseTable, ParseTableEntry}, + OptLevel, }; pub fn minimize_parse_table( @@ -20,6 +21,7 @@ pub fn minimize_parse_table( simple_aliases: &AliasMap, token_conflict_map: &TokenConflictMap, keywords: &TokenSet, + optimizations: OptLevel, ) { let mut minimizer = Minimizer { parse_table, @@ -29,7 +31,9 @@ pub fn minimize_parse_table( keywords, simple_aliases, }; - minimizer.merge_compatible_states(); + if optimizations.contains(OptLevel::MergeStates) { + minimizer.merge_compatible_states(); + } minimizer.remove_unit_reductions(); minimizer.remove_unused_states(); minimizer.reorder_states_by_descending_size(); @@ -302,9 +306,7 @@ impl Minimizer<'_> { return true; } - for (i, action1) in actions1.iter().enumerate() { - let action2 = &actions2[i]; - + for (action1, action2) in actions1.iter().zip(actions2.iter()) { // Two shift actions are equivalent if their destinations are in the same group. if let ( ParseAction::Shift { diff --git a/crates/generate/src/build_tables/token_conflicts.rs b/crates/generate/src/build_tables/token_conflicts.rs index bacac1b4..d72effd4 100644 --- a/crates/generate/src/build_tables/token_conflicts.rs +++ b/crates/generate/src/build_tables/token_conflicts.rs @@ -28,7 +28,7 @@ pub struct TokenConflictMap<'a> { impl<'a> TokenConflictMap<'a> { /// Create a token conflict map based on a lexical grammar, which describes the structure - /// each token, and a `following_token` map, which indicates which tokens may be appear + /// of each token, and a `following_token` map, which indicates which tokens may be appear /// immediately after each other token. /// /// This analyzes the possible kinds of overlap between each pair of tokens and stores diff --git a/crates/generate/src/generate.rs b/crates/generate/src/generate.rs index 0551bb1d..6a005637 100644 --- a/crates/generate/src/generate.rs +++ b/crates/generate/src/generate.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, sync::LazyLock}; +use std::{collections::BTreeMap, sync::LazyLock}; #[cfg(feature = "load")] use std::{ env, fs, @@ -7,7 +7,7 @@ use std::{ process::{Command, Stdio}, }; -use anyhow::Result; +use bitflags::bitflags; use log::warn; use node_types::VariableInfo; use regex::{Regex, RegexBuilder}; @@ -56,7 +56,7 @@ struct JSONOutput { syntax_grammar: SyntaxGrammar, lexical_grammar: LexicalGrammar, inlines: InlinedProductionMap, - simple_aliases: HashMap, + simple_aliases: BTreeMap, variable_info: Vec, } @@ -80,8 +80,8 @@ pub type GenerateResult = Result; pub enum GenerateError { #[error("Error with specified path -- {0}")] GrammarPath(String), - #[error("{0}")] - IO(String), + #[error(transparent)] + IO(IoError), #[cfg(feature = "load")] #[error(transparent)] LoadGrammarFile(#[from] LoadGrammarError), @@ -100,9 +100,28 @@ pub enum GenerateError { SuperTypeCycle(#[from] SuperTypeCycleError), } -impl From for GenerateError { - fn from(value: std::io::Error) -> Self { - Self::IO(value.to_string()) +#[derive(Debug, Error, Serialize)] +pub struct IoError { + pub error: String, + pub path: Option, +} + +impl IoError { + fn new(error: &std::io::Error, path: Option<&Path>) -> Self { + Self { + error: error.to_string(), + path: path.map(|p| p.to_string_lossy().to_string()), + } + } +} + +impl std::fmt::Display for IoError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.error)?; + if let Some(ref path) = self.path { + write!(f, " ({path})")?; + } + Ok(()) } } @@ -117,18 +136,11 @@ pub enum LoadGrammarError { #[error("Failed to load grammar.js -- {0}")] LoadJSGrammarFile(#[from] JSError), #[error("Failed to load grammar.json -- {0}")] - IO(String), + IO(IoError), #[error("Unknown grammar file extension: {0:?}")] FileExtension(PathBuf), } -#[cfg(feature = "load")] -impl From for LoadGrammarError { - fn from(value: std::io::Error) -> Self { - Self::IO(value.to_string()) - } -} - #[cfg(feature = "load")] #[derive(Debug, Error, Serialize)] pub enum ParseVersionError { @@ -136,8 +148,8 @@ pub enum ParseVersionError { Version(String), #[error("{0}")] JSON(String), - #[error("{0}")] - IO(String), + #[error(transparent)] + IO(IoError), } #[cfg(feature = "load")] @@ -152,8 +164,21 @@ pub enum JSError { JSRuntimeUtf8 { runtime: String, error: String }, #[error("`{runtime}` process exited with status {code}")] JSRuntimeExit { runtime: String, code: i32 }, - #[error("{0}")] - IO(String), + #[error("Failed to open stdin for `{runtime}`")] + JSRuntimeStdin { runtime: String }, + #[error("Failed to write {item} to `{runtime}`'s stdin -- {error}")] + JSRuntimeWrite { + runtime: String, + item: String, + error: String, + }, + #[error("Failed to read output from `{runtime}` -- {error}")] + JSRuntimeRead { runtime: String, error: String }, + #[error(transparent)] + IO(IoError), + #[cfg(feature = "qjs-rt")] + #[error("Failed to get relative path")] + RelativePath, #[error("Could not parse this package's version as semver -- {0}")] Semver(String), #[error("Failed to serialze grammar JSON -- {0}")] @@ -163,13 +188,6 @@ pub enum JSError { QuickJS(String), } -#[cfg(feature = "load")] -impl From for JSError { - fn from(value: std::io::Error) -> Self { - Self::IO(value.to_string()) - } -} - #[cfg(feature = "load")] impl From for JSError { fn from(value: serde_json::Error) -> Self { @@ -191,6 +209,19 @@ impl From for JSError { } } +bitflags! { + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub struct OptLevel: u32 { + const MergeStates = 1 << 0; + } +} + +impl Default for OptLevel { + fn default() -> Self { + Self::MergeStates + } +} + #[cfg(feature = "load")] #[allow(clippy::too_many_arguments)] pub fn generate_parser_in_directory( @@ -201,6 +232,7 @@ pub fn generate_parser_in_directory( report_symbol_name: Option<&str>, js_runtime: Option<&str>, generate_parser: bool, + optimizations: OptLevel, ) -> GenerateResult<()> where T: Into, @@ -216,7 +248,8 @@ where .try_exists() .map_err(|e| GenerateError::GrammarPath(e.to_string()))? { - fs::create_dir_all(&path_buf)?; + fs::create_dir_all(&path_buf) + .map_err(|e| GenerateError::IO(IoError::new(&e, Some(path_buf.as_path()))))?; repo_path = path_buf; repo_path.join("grammar.js") } else { @@ -233,15 +266,12 @@ where let header_path = src_path.join("tree_sitter"); // Ensure that the output directory exists - fs::create_dir_all(&src_path)?; + fs::create_dir_all(&src_path) + .map_err(|e| GenerateError::IO(IoError::new(&e, Some(src_path.as_path()))))?; if grammar_path.file_name().unwrap() != "grammar.json" { - fs::write(src_path.join("grammar.json"), &grammar_json).map_err(|e| { - GenerateError::IO(format!( - "Failed to write grammar.json to {} -- {e}", - src_path.display() - )) - })?; + fs::write(src_path.join("grammar.json"), &grammar_json) + .map_err(|e| GenerateError::IO(IoError::new(&e, Some(src_path.as_path()))))?; } // If our job is only to generate `grammar.json` and not `parser.c`, stop here. @@ -278,11 +308,13 @@ where abi_version, semantic_version.map(|v| (v.major as u8, v.minor as u8, v.patch as u8)), report_symbol_name, + optimizations, )?; write_file(&src_path.join("parser.c"), c_code)?; write_file(&src_path.join("node-types.json"), node_types_json)?; - fs::create_dir_all(&header_path)?; + fs::create_dir_all(&header_path) + .map_err(|e| GenerateError::IO(IoError::new(&e, Some(header_path.as_path()))))?; write_file(&header_path.join("alloc.h"), ALLOC_HEADER)?; write_file(&header_path.join("array.h"), ARRAY_HEADER)?; write_file(&header_path.join("parser.h"), PARSER_HEADER)?; @@ -301,6 +333,7 @@ pub fn generate_parser_for_grammar( LANGUAGE_VERSION, semantic_version, None, + OptLevel::empty(), )?; Ok((input_grammar.name, parser.c_code)) } @@ -334,6 +367,7 @@ fn generate_parser_for_grammar_with_opts( abi_version: usize, semantic_version: Option<(u8, u8, u8)>, report_symbol_name: Option<&str>, + optimizations: OptLevel, ) -> GenerateResult { let JSONOutput { syntax_grammar, @@ -353,6 +387,7 @@ fn generate_parser_for_grammar_with_opts( &variable_info, &inlines, report_symbol_name, + optimizations, )?; let c_code = render_c_code( &input_grammar.name, @@ -395,9 +430,8 @@ fn read_grammar_version(repo_path: &Path) -> Result, ParseVersio let json = path .exists() .then(|| { - let contents = fs::read_to_string(path.as_path()).map_err(|e| { - ParseVersionError::IO(format!("Failed to read `{}` -- {e}", path.display())) - })?; + let contents = fs::read_to_string(path.as_path()) + .map_err(|e| ParseVersionError::IO(IoError::new(&e, Some(path.as_path()))))?; serde_json::from_str::(&contents).map_err(|e| { ParseVersionError::JSON(format!("Failed to parse `{}` -- {e}", path.display())) }) @@ -431,14 +465,16 @@ pub fn load_grammar_file( } match grammar_path.extension().and_then(|e| e.to_str()) { Some("js") => Ok(load_js_grammar_file(grammar_path, js_runtime)?), - Some("json") => Ok(fs::read_to_string(grammar_path)?), + Some("json") => Ok(fs::read_to_string(grammar_path) + .map_err(|e| LoadGrammarError::IO(IoError::new(&e, Some(grammar_path))))?), _ => Err(LoadGrammarError::FileExtension(grammar_path.to_owned()))?, } } #[cfg(feature = "load")] fn load_js_grammar_file(grammar_path: &Path, js_runtime: Option<&str>) -> JSResult { - let grammar_path = dunce::canonicalize(grammar_path)?; + let grammar_path = dunce::canonicalize(grammar_path) + .map_err(|e| JSError::IO(IoError::new(&e, Some(grammar_path))))?; #[cfg(feature = "qjs-rt")] if js_runtime == Some("native") { @@ -479,7 +515,9 @@ fn load_js_grammar_file(grammar_path: &Path, js_runtime: Option<&str>) -> JSResu let mut js_stdin = js_process .stdin .take() - .ok_or_else(|| JSError::IO(format!("Failed to open stdin for `{js_runtime}`")))?; + .ok_or_else(|| JSError::JSRuntimeStdin { + runtime: js_runtime.to_string(), + })?; let cli_version = Version::parse(env!("CARGO_PKG_VERSION"))?; write!( @@ -489,23 +527,27 @@ fn load_js_grammar_file(grammar_path: &Path, js_runtime: Option<&str>) -> JSResu globalThis.TREE_SITTER_CLI_VERSION_PATCH = {};", cli_version.major, cli_version.minor, cli_version.patch, ) - .map_err(|e| { - JSError::IO(format!( - "Failed to write tree-sitter version to `{js_runtime}`'s stdin -- {e}" - )) - })?; - js_stdin.write(include_bytes!("./dsl.js")).map_err(|e| { - JSError::IO(format!( - "Failed to write grammar dsl to `{js_runtime}`'s stdin -- {e}" - )) + .map_err(|e| JSError::JSRuntimeWrite { + runtime: js_runtime.to_string(), + item: "tree-sitter version".to_string(), + error: e.to_string(), })?; + js_stdin + .write(include_bytes!("./dsl.js")) + .map_err(|e| JSError::JSRuntimeWrite { + runtime: js_runtime.to_string(), + item: "grammar dsl".to_string(), + error: e.to_string(), + })?; drop(js_stdin); let output = js_process .wait_with_output() - .map_err(|e| JSError::IO(format!("Failed to read output from `{js_runtime}` -- {e}")))?; + .map_err(|e| JSError::JSRuntimeRead { + runtime: js_runtime.to_string(), + error: e.to_string(), + })?; match output.status.code() { - None => panic!("`{js_runtime}` process was killed"), Some(0) => { let stdout = String::from_utf8(output.stdout).map_err(|e| JSError::JSRuntimeUtf8 { runtime: js_runtime.to_string(), @@ -520,9 +562,15 @@ fn load_js_grammar_file(grammar_path: &Path, js_runtime: Option<&str>) -> JSResu grammar_json = &stdout[pos + 1..]; let mut stdout = std::io::stdout().lock(); - stdout.write_all(node_output.as_bytes())?; - stdout.write_all(b"\n")?; - stdout.flush()?; + stdout + .write_all(node_output.as_bytes()) + .map_err(|e| JSError::IO(IoError::new(&e, None)))?; + stdout + .write_all(b"\n") + .map_err(|e| JSError::IO(IoError::new(&e, None)))?; + stdout + .flush() + .map_err(|e| JSError::IO(IoError::new(&e, None)))?; } Ok(serde_json::to_string_pretty(&serde_json::from_str::< @@ -533,13 +581,16 @@ fn load_js_grammar_file(grammar_path: &Path, js_runtime: Option<&str>) -> JSResu runtime: js_runtime.to_string(), code, }), + None => Err(JSError::JSRuntimeExit { + runtime: js_runtime.to_string(), + code: -1, + }), } } #[cfg(feature = "load")] pub fn write_file(path: &Path, body: impl AsRef<[u8]>) -> GenerateResult<()> { - fs::write(path, body) - .map_err(|e| GenerateError::IO(format!("Failed to write {:?} -- {e}", path.file_name()))) + fs::write(path, body).map_err(|e| GenerateError::IO(IoError::new(&e, Some(path)))) } #[cfg(test)] diff --git a/crates/generate/src/node_types.rs b/crates/generate/src/node_types.rs index 748a3d58..2dde0c49 100644 --- a/crates/generate/src/node_types.rs +++ b/crates/generate/src/node_types.rs @@ -1,6 +1,5 @@ -use std::collections::{BTreeMap, HashMap, HashSet}; +use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; -use anyhow::Result; use serde::Serialize; use thiserror::Error; @@ -378,11 +377,11 @@ pub fn get_variable_info( fn get_aliases_by_symbol( syntax_grammar: &SyntaxGrammar, default_aliases: &AliasMap, -) -> HashMap>> { +) -> HashMap>> { let mut aliases_by_symbol = HashMap::new(); for (symbol, alias) in default_aliases { aliases_by_symbol.insert(*symbol, { - let mut aliases = HashSet::new(); + let mut aliases = BTreeSet::new(); aliases.insert(Some(alias.clone())); aliases }); @@ -391,7 +390,7 @@ fn get_aliases_by_symbol( if !default_aliases.contains_key(extra_symbol) { aliases_by_symbol .entry(*extra_symbol) - .or_insert_with(HashSet::new) + .or_insert_with(BTreeSet::new) .insert(None); } } @@ -400,7 +399,7 @@ fn get_aliases_by_symbol( for step in &production.steps { aliases_by_symbol .entry(step.symbol) - .or_insert_with(HashSet::new) + .or_insert_with(BTreeSet::new) .insert( step.alias .as_ref() @@ -531,7 +530,7 @@ pub fn generate_node_types_json( let aliases_by_symbol = get_aliases_by_symbol(syntax_grammar, default_aliases); - let empty = HashSet::new(); + let empty = BTreeSet::new(); let extra_names = syntax_grammar .extra_symbols .iter() @@ -590,7 +589,7 @@ pub fn generate_node_types_json( } else if !syntax_grammar.variables_to_inline.contains(&symbol) { // If a rule is aliased under multiple names, then its information // contributes to multiple entries in the final JSON. - for alias in aliases_by_symbol.get(&symbol).unwrap_or(&HashSet::new()) { + for alias in aliases_by_symbol.get(&symbol).unwrap_or(&BTreeSet::new()) { let kind; let is_named; if let Some(alias) = alias { @@ -784,6 +783,9 @@ pub fn generate_node_types_json( a_is_leaf.cmp(&b_is_leaf) }) .then_with(|| a.kind.cmp(&b.kind)) + .then_with(|| a.named.cmp(&b.named)) + .then_with(|| a.root.cmp(&b.root)) + .then_with(|| a.extra.cmp(&b.extra)) }); result.dedup(); Ok(result) @@ -826,12 +828,12 @@ fn extend_sorted<'a, T>(vec: &mut Vec, values: impl IntoIterator, + content: Box, named: bool, value: String, }, @@ -34,46 +33,46 @@ enum RuleJSON { name: String, }, CHOICE { - members: Vec, + members: Vec, }, FIELD { name: String, - content: Box, + content: Box, }, SEQ { - members: Vec, + members: Vec, }, REPEAT { - content: Box, + content: Box, }, REPEAT1 { - content: Box, + content: Box, }, PREC_DYNAMIC { value: i32, - content: Box, + content: Box, }, PREC_LEFT { value: PrecedenceValueJSON, - content: Box, + content: Box, }, PREC_RIGHT { value: PrecedenceValueJSON, - content: Box, + content: Box, }, PREC { value: PrecedenceValueJSON, - content: Box, + content: Box, }, TOKEN { - content: Box, + content: Box, }, IMMEDIATE_TOKEN { - content: Box, + content: Box, }, RESERVED { context_name: String, - content: Box, + content: Box, }, } diff --git a/crates/generate/src/prepare_grammar.rs b/crates/generate/src/prepare_grammar.rs index 8c35c741..58e0869c 100644 --- a/crates/generate/src/prepare_grammar.rs +++ b/crates/generate/src/prepare_grammar.rs @@ -12,7 +12,6 @@ use std::{ mem, }; -use anyhow::Result; pub use expand_tokens::ExpandTokensError; pub use extract_tokens::ExtractTokensError; pub use flatten_grammar::FlattenGrammarError; diff --git a/crates/generate/src/prepare_grammar/expand_tokens.rs b/crates/generate/src/prepare_grammar/expand_tokens.rs index 2762b41c..acfb9ba3 100644 --- a/crates/generate/src/prepare_grammar/expand_tokens.rs +++ b/crates/generate/src/prepare_grammar/expand_tokens.rs @@ -1,4 +1,3 @@ -use anyhow::Result; use regex_syntax::{ hir::{Class, Hir, HirKind}, ParserBuilder, @@ -27,7 +26,7 @@ pub enum ExpandTokensError { "The rule `{0}` matches the empty string. Tree-sitter does not support syntactic rules that match the empty string unless they are used only as the grammar's start rule. - " +" )] EmptyString(String), #[error(transparent)] @@ -189,7 +188,7 @@ impl NfaBuilder { } Rule::String(s) => { for c in s.chars().rev() { - self.push_advance(CharacterSet::empty().add_char(c), next_state_id); + self.push_advance(CharacterSet::from_char(c), next_state_id); next_state_id = self.nfa.last_state_id(); } Ok(!s.is_empty()) diff --git a/crates/generate/src/prepare_grammar/extract_default_aliases.rs b/crates/generate/src/prepare_grammar/extract_default_aliases.rs index 68ea1e48..cc977362 100644 --- a/crates/generate/src/prepare_grammar/extract_default_aliases.rs +++ b/crates/generate/src/prepare_grammar/extract_default_aliases.rs @@ -69,9 +69,7 @@ pub(super) fn extract_default_aliases( SymbolType::External => &mut external_status_list[symbol.index], SymbolType::NonTerminal => &mut non_terminal_status_list[symbol.index], SymbolType::Terminal => &mut terminal_status_list[symbol.index], - SymbolType::End | SymbolType::EndOfNonTerminalExtra => { - panic!("Unexpected end token") - } + SymbolType::End | SymbolType::EndOfNonTerminalExtra => panic!("Unexpected end token"), }; status.appears_unaliased = true; } diff --git a/crates/generate/src/prepare_grammar/extract_tokens.rs b/crates/generate/src/prepare_grammar/extract_tokens.rs index cb40ce5a..a7b4f227 100644 --- a/crates/generate/src/prepare_grammar/extract_tokens.rs +++ b/crates/generate/src/prepare_grammar/extract_tokens.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; -use anyhow::Result; use serde::Serialize; use thiserror::Error; @@ -153,7 +152,7 @@ pub(super) fn extract_tokens( } } - let mut external_tokens = Vec::new(); + let mut external_tokens = Vec::with_capacity(grammar.external_tokens.len()); for external_token in grammar.external_tokens { let rule = symbol_replacer.replace_symbols_in_rule(&external_token.rule); if let Rule::Symbol(symbol) = rule { @@ -591,14 +590,13 @@ mod test { ]); grammar.external_tokens = vec![Variable::named("rule_1", Rule::non_terminal(1))]; - match extract_tokens(grammar) { - Err(e) => { - assert_eq!(e.to_string(), "Rule 'rule_1' cannot be used as both an external token and a non-terminal rule"); - } - _ => { - panic!("Expected an error but got no error"); - } - } + let result = extract_tokens(grammar); + assert!(result.is_err(), "Expected an error but got no error"); + let err = result.err().unwrap(); + assert_eq!( + err.to_string(), + "Rule 'rule_1' cannot be used as both an external token and a non-terminal rule" + ); } #[test] diff --git a/crates/generate/src/prepare_grammar/flatten_grammar.rs b/crates/generate/src/prepare_grammar/flatten_grammar.rs index cb0f1dae..3bec17bf 100644 --- a/crates/generate/src/prepare_grammar/flatten_grammar.rs +++ b/crates/generate/src/prepare_grammar/flatten_grammar.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; -use anyhow::Result; use serde::Serialize; use thiserror::Error; diff --git a/crates/generate/src/prepare_grammar/intern_symbols.rs b/crates/generate/src/prepare_grammar/intern_symbols.rs index 010967b8..92f0f095 100644 --- a/crates/generate/src/prepare_grammar/intern_symbols.rs +++ b/crates/generate/src/prepare_grammar/intern_symbols.rs @@ -1,4 +1,3 @@ -use anyhow::Result; use log::warn; use serde::Serialize; use thiserror::Error; @@ -279,10 +278,9 @@ mod tests { fn test_grammar_with_undefined_symbols() { let result = intern_symbols(&build_grammar(vec![Variable::named("x", Rule::named("y"))])); - match result { - Err(e) => assert_eq!(e.to_string(), "Undefined symbol `y`"), - _ => panic!("Expected an error but got none"), - } + assert!(result.is_err(), "Expected an error but got none"); + let e = result.err().unwrap(); + assert_eq!(e.to_string(), "Undefined symbol `y`"); } fn build_grammar(variables: Vec) -> InputGrammar { diff --git a/crates/generate/src/prepare_grammar/process_inlines.rs b/crates/generate/src/prepare_grammar/process_inlines.rs index 085e6732..460d2359 100644 --- a/crates/generate/src/prepare_grammar/process_inlines.rs +++ b/crates/generate/src/prepare_grammar/process_inlines.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; -use anyhow::Result; use serde::Serialize; use thiserror::Error; @@ -71,12 +70,13 @@ impl InlinedProductionMapBuilder { let production_map = production_indices_by_step_id .into_iter() .map(|(step_id, production_indices)| { - let production = step_id.variable_index.map_or_else( - || &productions[step_id.production_index], - |variable_index| { - &grammar.variables[variable_index].productions[step_id.production_index] - }, - ) as *const Production; + let production = + core::ptr::from_ref::(step_id.variable_index.map_or_else( + || &productions[step_id.production_index], + |variable_index| { + &grammar.variables[variable_index].productions[step_id.production_index] + }, + )); ((production, step_id.step_index as u32), production_indices) }) .collect(); @@ -549,10 +549,9 @@ mod tests { ..Default::default() }; - if let Err(error) = process_inlines(&grammar, &lexical_grammar) { - assert_eq!(error.to_string(), "Token `something` cannot be inlined"); - } else { - panic!("expected an error, but got none"); - } + let result = process_inlines(&grammar, &lexical_grammar); + assert!(result.is_err(), "expected an error, but got none"); + let err = result.err().unwrap(); + assert_eq!(err.to_string(), "Token `something` cannot be inlined",); } } diff --git a/crates/generate/src/quickjs.rs b/crates/generate/src/quickjs.rs index 689615fc..d8c71cfe 100644 --- a/crates/generate/src/quickjs.rs +++ b/crates/generate/src/quickjs.rs @@ -10,7 +10,7 @@ use rquickjs::{ Context, Ctx, Function, Module, Object, Runtime, Type, Value, }; -use super::{JSError, JSResult}; +use super::{IoError, JSError, JSResult}; const DSL: &[u8] = include_bytes!("dsl.js"); @@ -95,9 +95,27 @@ impl Console { Type::Module => "module".to_string(), Type::BigInt => v.get::().unwrap_or_else(|_| "BigInt".to_string()), Type::Unknown => "unknown".to_string(), + Type::Array => { + let js_vals = v + .as_array() + .unwrap() + .iter::>() + .filter_map(|x| x.ok()) + .map(|x| { + if x.is_string() { + format!("'{}'", Self::format_args(&[x])) + } else { + Self::format_args(&[x]) + } + }) + .collect::>() + .join(", "); + + format!("[ {js_vals} ]") + } Type::Symbol | Type::Object - | Type::Array + | Type::Proxy | Type::Function | Type::Constructor | Type::Promise @@ -197,11 +215,11 @@ fn try_resolve_path(path: &Path) -> rquickjs::Result { } #[allow(clippy::needless_pass_by_value)] -fn require_from_module<'a>( - ctx: Ctx<'a>, +fn require_from_module<'js>( + ctx: Ctx<'js>, module_path: String, from_module: &str, -) -> rquickjs::Result> { +) -> rquickjs::Result> { let current_module = PathBuf::from(from_module); let current_dir = if current_module.is_file() { current_module.parent().unwrap_or(Path::new(".")) @@ -216,13 +234,13 @@ fn require_from_module<'a>( load_module_from_content(&ctx, &resolved_path, &contents) } -fn load_module_from_content<'a>( - ctx: &Ctx<'a>, +fn load_module_from_content<'js>( + ctx: &Ctx<'js>, path: &Path, contents: &str, -) -> rquickjs::Result> { +) -> rquickjs::Result> { if path.extension().is_some_and(|ext| ext == "json") { - return ctx.eval::(format!("JSON.parse({contents:?})")); + return ctx.eval::, _>(format!("JSON.parse({contents:?})")); } let exports = Object::new(ctx.clone())?; @@ -238,7 +256,7 @@ fn load_module_from_content<'a>( let module_path = filename.clone(); let require = Function::new( ctx.clone(), - move |ctx_inner: Ctx<'a>, target_path: String| -> rquickjs::Result> { + move |ctx_inner: Ctx<'js>, target_path: String| -> rquickjs::Result> { require_from_module(ctx_inner, target_path, &module_path) }, )?; @@ -246,8 +264,8 @@ fn load_module_from_content<'a>( let wrapper = format!("(function(exports, require, module, __filename, __dirname) {{ {contents} }})"); - let module_func = ctx.eval::(wrapper)?; - module_func.call::<_, Value>((exports, require, module_obj.clone(), filename, dirname))?; + let module_func = ctx.eval::, _>(wrapper)?; + module_func.call::<_, Value<'js>>((exports, require, module_obj.clone(), filename, dirname))?; module_obj.get("exports") } @@ -261,15 +279,16 @@ pub fn execute_native_runtime(grammar_path: &Path) -> JSResult { let context = Context::full(&runtime)?; let resolver = FileResolver::default() + .with_path("./node_modules") .with_path("./") .with_pattern("{}.mjs"); let loader = ScriptLoader::default().with_extension("mjs"); runtime.set_loader(resolver, loader); - let cwd = std::env::current_dir()?; + let cwd = std::env::current_dir().map_err(|e| JSError::IO(IoError::new(&e, None)))?; let relative_path = pathdiff::diff_paths(grammar_path, &cwd) .map(|p| p.to_string_lossy().to_string()) - .ok_or_else(|| JSError::IO("Failed to get relative path".to_string()))?; + .ok_or(JSError::RelativePath)?; context.with(|ctx| -> JSResult { let globals = ctx.globals(); diff --git a/crates/generate/src/render.rs b/crates/generate/src/render.rs index e4aea008..bcfc832e 100644 --- a/crates/generate/src/render.rs +++ b/crates/generate/src/render.rs @@ -34,6 +34,8 @@ macro_rules! add { macro_rules! add_whitespace { ($this:tt) => {{ + // 4 bytes per char, 2 spaces per indent level + $this.buffer.reserve(4 * 2 * $this.indent_level); for _ in 0..$this.indent_level { write!(&mut $this.buffer, " ").unwrap(); } @@ -688,13 +690,14 @@ impl Generator { flat_field_map.push((field_name.clone(), *location)); } } + let field_map_len = flat_field_map.len(); field_map_ids.push(( self.get_field_map_id( - flat_field_map.clone(), + flat_field_map, &mut flat_field_maps, &mut next_flat_field_map_index, ), - flat_field_map.len(), + field_map_len, )); } } @@ -962,10 +965,7 @@ impl Generator { large_char_set_ix = Some(char_set_ix); } - let mut line_break = "\n".to_string(); - for _ in 0..self.indent_level + 2 { - line_break.push_str(" "); - } + let line_break = format!("\n{}", " ".repeat(self.indent_level + 2)); let has_positive_condition = large_char_set_ix.is_some() || !asserted_chars.is_empty(); let has_negative_condition = !negated_chars.is_empty(); diff --git a/crates/generate/src/rules.rs b/crates/generate/src/rules.rs index cd4aa482..05a0c426 100644 --- a/crates/generate/src/rules.rs +++ b/crates/generate/src/rules.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, fmt}; +use std::{collections::BTreeMap, fmt}; use serde::Serialize; use smallbitvec::SmallBitVec; @@ -34,7 +34,7 @@ pub enum Precedence { Name(String), } -pub type AliasMap = HashMap; +pub type AliasMap = BTreeMap; #[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Serialize)] pub struct MetadataParams { @@ -60,15 +60,15 @@ pub enum Rule { Pattern(String, String), NamedSymbol(String), Symbol(Symbol), - Choice(Vec), + Choice(Vec), Metadata { params: MetadataParams, - rule: Box, + rule: Box, }, - Repeat(Box), - Seq(Vec), + Repeat(Box), + Seq(Vec), Reserved { - rule: Box, + rule: Box, context_name: String, }, } diff --git a/crates/highlight/src/highlight.rs b/crates/highlight/src/highlight.rs index bb81fc08..d38351f6 100644 --- a/crates/highlight/src/highlight.rs +++ b/crates/highlight/src/highlight.rs @@ -189,7 +189,7 @@ struct HighlightIterLayer<'a> { depth: usize, } -pub struct _QueryCaptures<'query, 'tree: 'query, T: TextProvider, I: AsRef<[u8]>> { +pub struct _QueryCaptures<'query, 'tree, T: TextProvider, I: AsRef<[u8]>> { ptr: *mut ffi::TSQueryCursor, query: &'query Query, text_provider: T, @@ -225,7 +225,7 @@ impl<'tree> _QueryMatch<'_, 'tree> { } } -impl<'query, 'tree: 'query, T: TextProvider, I: AsRef<[u8]>> Iterator +impl<'query, 'tree, T: TextProvider, I: AsRef<[u8]>> Iterator for _QueryCaptures<'query, 'tree, T, I> { type Item = (QueryMatch<'query, 'tree>, usize); @@ -344,11 +344,13 @@ impl HighlightConfiguration { locals_query: &str, ) -> Result { // Concatenate the query strings, keeping track of the start offset of each section. - let mut query_source = String::new(); + let mut query_source = String::with_capacity( + injection_query.len() + locals_query.len() + highlights_query.len(), + ); query_source.push_str(injection_query); - let locals_query_offset = query_source.len(); + let locals_query_offset = injection_query.len(); query_source.push_str(locals_query); - let highlights_query_offset = query_source.len(); + let highlights_query_offset = injection_query.len() + locals_query.len(); query_source.push_str(highlights_query); // Construct a single query by concatenating the three query strings, but record the @@ -592,6 +594,7 @@ impl<'a> HighlightIterLayer<'a> { } } + // SAFETY: // The `captures` iterator borrows the `Tree` and the `QueryCursor`, which // prevents them from being moved. But both of these values are really just // pointers, so it's actually ok to move them. diff --git a/crates/language/Cargo.toml b/crates/language/Cargo.toml index 5b974117..b6f5cdf8 100644 --- a/crates/language/Cargo.toml +++ b/crates/language/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "tree-sitter-language" description = "The tree-sitter Language type, used by the library and by language implementations" -version = "0.1.4" +version = "0.1.7" authors.workspace = true edition.workspace = true rust-version = "1.77" diff --git a/crates/language/wasm/include/stdint.h b/crates/language/wasm/include/stdint.h index 5f7cb264..10cc35dc 100644 --- a/crates/language/wasm/include/stdint.h +++ b/crates/language/wasm/include/stdint.h @@ -23,9 +23,15 @@ typedef long unsigned int size_t; typedef long unsigned int uintptr_t; -#define UINT16_MAX 65535 +#define INT8_MAX 127 +#define INT16_MAX 32767 +#define INT32_MAX 2147483647L +#define INT64_MAX 9223372036854775807LL +#define UINT8_MAX 255 +#define UINT16_MAX 65535 #define UINT32_MAX 4294967295U +#define UINT64_MAX 18446744073709551615ULL #if defined(__wasm32__) diff --git a/crates/language/wasm/include/string.h b/crates/language/wasm/include/string.h index 2d576f08..10f11958 100644 --- a/crates/language/wasm/include/string.h +++ b/crates/language/wasm/include/string.h @@ -13,4 +13,6 @@ void *memset(void *dst, int value, size_t count); int strncmp(const char *left, const char *right, size_t n); +size_t strlen(const char *str); + #endif // TREE_SITTER_WASM_STRING_H_ diff --git a/crates/language/wasm/src/stdio.c b/crates/language/wasm/src/stdio.c index 3432699a..470c1ecc 100644 --- a/crates/language/wasm/src/stdio.c +++ b/crates/language/wasm/src/stdio.c @@ -1,4 +1,5 @@ #include +#include typedef struct { bool left_justify; // - @@ -105,12 +106,6 @@ static int ptr_to_str(void *ptr, char *buffer) { return 2 + len; } -size_t strlen(const char *str) { - const char *s = str; - while (*s) s++; - return s - str; -} - char *strncpy(char *dest, const char *src, size_t n) { char *d = dest; const char *s = src; diff --git a/crates/language/wasm/src/string.c b/crates/language/wasm/src/string.c index 0fcf4b85..2d0d9096 100644 --- a/crates/language/wasm/src/string.c +++ b/crates/language/wasm/src/string.c @@ -58,3 +58,9 @@ int strncmp(const char *left, const char *right, size_t n) { } return 0; } + +size_t strlen(const char *str) { + const char *s = str; + while (*s) s++; + return s - str; +} diff --git a/crates/loader/Cargo.toml b/crates/loader/Cargo.toml index ba6aa0f4..cecae218 100644 --- a/crates/loader/Cargo.toml +++ b/crates/loader/Cargo.toml @@ -28,7 +28,6 @@ wasm = ["tree-sitter/wasm"] default = ["tree-sitter-highlight", "tree-sitter-tags"] [dependencies] -anyhow.workspace = true cc.workspace = true etcetera.workspace = true fs4.workspace = true @@ -41,6 +40,7 @@ semver.workspace = true serde.workspace = true serde_json.workspace = true tempfile.workspace = true +thiserror.workspace = true tree-sitter = { workspace = true } tree-sitter-highlight = { workspace = true, optional = true } diff --git a/crates/loader/emscripten-version b/crates/loader/emscripten-version index 4c05e4ef..af253c16 100644 --- a/crates/loader/emscripten-version +++ b/crates/loader/emscripten-version @@ -1 +1 @@ -4.0.12 +4.0.15 diff --git a/crates/loader/src/loader.rs b/crates/loader/src/loader.rs index a004c0d9..e7584378 100644 --- a/crates/loader/src/loader.rs +++ b/crates/loader/src/loader.rs @@ -8,17 +8,16 @@ use std::sync::Mutex; use std::{ collections::HashMap, env, fs, + hash::{Hash as _, Hasher as _}, io::{BufRead, BufReader}, marker::PhantomData, mem, path::{Path, PathBuf}, process::Command, sync::LazyLock, - time::SystemTime, + time::{SystemTime, SystemTimeError}, }; -use anyhow::Error; -use anyhow::{anyhow, Context, Result}; use etcetera::BaseStrategy as _; use fs4::fs_std::FileExt; use libloading::{Library, Symbol}; @@ -27,11 +26,14 @@ use once_cell::unsync::OnceCell; use regex::{Regex, RegexBuilder}; use semver::Version; use serde::{Deserialize, Deserializer, Serialize}; +use thiserror::Error; use tree_sitter::Language; #[cfg(any(feature = "tree-sitter-highlight", feature = "tree-sitter-tags"))] use tree_sitter::QueryError; #[cfg(feature = "tree-sitter-highlight")] use tree_sitter::QueryErrorKind; +#[cfg(feature = "wasm")] +use tree_sitter::WasmError; #[cfg(feature = "tree-sitter-highlight")] use tree_sitter_highlight::HighlightConfiguration; #[cfg(feature = "tree-sitter-tags")] @@ -40,6 +42,220 @@ use tree_sitter_tags::{Error as TagsError, TagsConfiguration}; static GRAMMAR_NAME_REGEX: LazyLock = LazyLock::new(|| Regex::new(r#""name":\s*"(.*?)""#).unwrap()); +const WASI_SDK_VERSION: &str = include_str!("../wasi-sdk-version").trim_ascii(); + +pub type LoaderResult = Result; + +#[derive(Debug, Error)] +pub enum LoaderError { + #[error(transparent)] + Compiler(CompilerError), + #[error("Parser compilation failed.\nStdout: {0}\nStderr: {1}")] + Compilation(String, String), + #[error("Failed to execute curl for {0} -- {1}")] + Curl(String, std::io::Error), + #[error("Failed to load language in current directory:\n{0}")] + CurrentDirectoryLoad(Box), + #[error("External file path {0} is outside of parser directory {1}")] + ExternalFile(String, String), + #[error("Failed to extract archive {0} to {1}")] + Extraction(String, String), + #[error("Failed to load language for file name {0}:\n{1}")] + FileNameLoad(String, Box), + #[error("Failed to parse the language name from grammar.json at {0}")] + GrammarJSON(String), + #[error(transparent)] + HomeDir(#[from] etcetera::HomeDirError), + #[error(transparent)] + IO(IoError), + #[error(transparent)] + Library(LibraryError), + #[error("Failed to compare binary and source timestamps:\n{0}")] + ModifiedTime(Box), + #[error("No language found")] + NoLanguage, + #[error(transparent)] + Query(LoaderQueryError), + #[error(transparent)] + ScannerSymbols(ScannerSymbolError), + #[error("Failed to load language for scope '{0}':\n{1}")] + ScopeLoad(String, Box), + #[error(transparent)] + Serialization(#[from] serde_json::Error), + #[error(transparent)] + Symbol(SymbolError), + #[error(transparent)] + Tags(#[from] TagsError), + #[error("Failed to execute tar for {0} -- {1}")] + Tar(String, std::io::Error), + #[error(transparent)] + Time(#[from] SystemTimeError), + #[error("Unknown scope '{0}'")] + UnknownScope(String), + #[error("Failed to download wasi-sdk from {0}")] + WasiSDKDownload(String), + #[error(transparent)] + WasiSDKClang(#[from] WasiSDKClangError), + #[error("Unsupported platform for wasi-sdk")] + WasiSDKPlatform, + #[cfg(feature = "wasm")] + #[error(transparent)] + Wasm(#[from] WasmError), + #[error("Failed to run wasi-sdk clang -- {0}")] + WasmCompiler(std::io::Error), + #[error("wasi-sdk clang command failed: {0}")] + WasmCompilation(String), +} + +#[derive(Debug, Error)] +pub struct CompilerError { + pub error: std::io::Error, + pub command: Box, +} + +impl std::fmt::Display for CompilerError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "Failed to execute the C compiler with the following command:\n{:?}\nError: {}", + *self.command, self.error + )?; + Ok(()) + } +} + +#[derive(Debug, Error)] +pub struct IoError { + pub error: std::io::Error, + pub path: Option, +} + +impl IoError { + fn new(error: std::io::Error, path: Option<&Path>) -> Self { + Self { + error, + path: path.map(|p| p.to_string_lossy().to_string()), + } + } +} + +impl std::fmt::Display for IoError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.error)?; + if let Some(ref path) = self.path { + write!(f, " ({path})")?; + } + Ok(()) + } +} + +#[derive(Debug, Error)] +pub struct LibraryError { + pub error: libloading::Error, + pub path: String, +} + +impl std::fmt::Display for LibraryError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "Error opening dynamic library {} -- {}", + self.path, self.error + )?; + Ok(()) + } +} + +#[derive(Debug, Error)] +pub struct LoaderQueryError { + pub error: QueryError, + pub file: Option, +} + +impl std::fmt::Display for LoaderQueryError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if let Some(ref path) = self.file { + writeln!(f, "Error in query file {path}:")?; + } + write!(f, "{}", self.error)?; + Ok(()) + } +} + +#[derive(Debug, Error)] +pub struct SymbolError { + pub error: libloading::Error, + pub symbol_name: String, + pub path: String, +} + +impl std::fmt::Display for SymbolError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "Failed to load symbol {} from {} -- {}", + self.symbol_name, self.path, self.error + )?; + Ok(()) + } +} + +#[derive(Debug, Error)] +pub struct ScannerSymbolError { + pub missing: Vec, +} + +impl std::fmt::Display for ScannerSymbolError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!( + f, + "Missing required functions in the external scanner, parsing won't work without these!\n" + )?; + for symbol in &self.missing { + writeln!(f, " `{symbol}`")?; + } + writeln!( + f, + "You can read more about this at https://tree-sitter.github.io/tree-sitter/creating-parsers/4-external-scanners\n" + )?; + Ok(()) + } +} + +#[derive(Debug, Error)] +pub struct WasiSDKClangError { + pub wasi_sdk_dir: String, + pub possible_executables: Vec<&'static str>, + pub download: bool, +} + +impl std::fmt::Display for WasiSDKClangError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.download { + write!( + f, + "Failed to find clang executable in downloaded wasi-sdk at '{}'.", + self.wasi_sdk_dir + )?; + } else { + write!(f, "TREE_SITTER_WASI_SDK_PATH is set to '{}', but no clang executable found in 'bin/' directory.", self.wasi_sdk_dir)?; + } + + let possible_exes = self.possible_executables.join(", "); + write!(f, " Looked for: {possible_exes}.")?; + + Ok(()) + } +} + +pub const DEFAULT_HIGHLIGHTS_QUERY_FILE_NAME: &str = "highlights.scm"; + +pub const DEFAULT_INJECTIONS_QUERY_FILE_NAME: &str = "injections.scm"; + +pub const DEFAULT_LOCALS_QUERY_FILE_NAME: &str = "locals.scm"; + +pub const DEFAULT_TAGS_QUERY_FILE_NAME: &str = "tags.scm"; + #[derive(Default, Deserialize, Serialize)] pub struct Config { #[serde(default)] @@ -71,6 +287,17 @@ impl PathsJSON { const fn is_empty(&self) -> bool { matches!(self, Self::Empty) } + + /// Represent this set of paths as a string that can be included in templates + #[must_use] + pub fn to_variable_value<'a>(&'a self, default: &'a PathBuf) -> &'a str { + match self { + Self::Empty => Some(default), + Self::Single(path_buf) => Some(path_buf), + Self::Multiple(paths) => paths.first(), + } + .map_or("", |path| path.as_os_str().to_str().unwrap_or("")) + } } #[derive(Serialize, Deserialize, Clone)] @@ -143,9 +370,10 @@ pub struct TreeSitterJSON { } impl TreeSitterJSON { - pub fn from_file(path: &Path) -> Result { - Ok(serde_json::from_str(&fs::read_to_string( - path.join("tree-sitter.json"), + pub fn from_file(path: &Path) -> LoaderResult { + let path = path.join("tree-sitter.json"); + Ok(serde_json::from_str(&fs::read_to_string(&path).map_err( + |e| LoaderError::IO(IoError::new(e, Some(path.as_path()))), )?)?) } @@ -223,7 +451,6 @@ pub struct Links { pub struct Bindings { pub c: bool, pub go: bool, - #[serde(skip)] pub java: bool, #[serde(skip)] pub kotlin: bool, @@ -237,12 +464,12 @@ pub struct Bindings { impl Bindings { /// return available languages and its default enabled state. #[must_use] - pub const fn languages(&self) -> [(&'static str, bool); 7] { + pub const fn languages(&self) -> [(&'static str, bool); 8] { [ ("c", true), ("go", true), - // Comment out Java and Kotlin until the bindings are actually available. - // ("java", false), + ("java", false), + // Comment out Kotlin until the bindings are actually available. // ("kotlin", false), ("node", true), ("python", true), @@ -273,8 +500,8 @@ impl Bindings { match v { "c" => out.c = true, "go" => out.go = true, - // Comment out Java and Kotlin until the bindings are actually available. - // "java" => out.java = true, + "java" => out.java = true, + // Comment out Kotlin until the bindings are actually available. // "kotlin" => out.kotlin = true, "node" => out.node = true, "python" => out.python = true, @@ -351,7 +578,6 @@ impl Config { } const BUILD_TARGET: &str = env!("BUILD_TARGET"); -const BUILD_HOST: &str = env!("BUILD_HOST"); pub struct LanguageConfiguration<'a> { pub scope: Option, @@ -432,7 +658,7 @@ impl<'a> CompileConfig<'a> { unsafe impl Sync for Loader {} impl Loader { - pub fn new() -> Result { + pub fn new() -> LoaderResult { let parser_lib_path = if let Ok(path) = env::var("TREE_SITTER_LIBDIR") { PathBuf::from(path) } else { @@ -441,7 +667,9 @@ impl Loader { .cache_dir() // `$HOME/Library/Caches/` .join("tree-sitter"); if legacy_apple_path.exists() && legacy_apple_path.is_dir() { - std::fs::remove_dir_all(legacy_apple_path)?; + std::fs::remove_dir_all(&legacy_apple_path).map_err(|e| { + LoaderError::IO(IoError::new(e, Some(legacy_apple_path.as_path()))) + })?; } } @@ -491,7 +719,7 @@ impl Loader { self.highlight_names.lock().unwrap().clone() } - pub fn find_all_languages(&mut self, config: &Config) -> Result<()> { + pub fn find_all_languages(&mut self, config: &Config) -> LoaderResult<()> { if config.parser_directories.is_empty() { warn!(concat!( "You have not configured any parser directories!\n", @@ -503,7 +731,7 @@ impl Loader { for parser_container_dir in &config.parser_directories { if let Ok(entries) = fs::read_dir(parser_container_dir) { for entry in entries { - let entry = entry?; + let entry = entry.map_err(|e| LoaderError::IO(IoError::new(e, None)))?; if let Some(parser_dir_name) = entry.file_name().to_str() { if parser_dir_name.starts_with("tree-sitter-") { self.find_language_configurations_at_path( @@ -519,7 +747,7 @@ impl Loader { Ok(()) } - pub fn languages_at_path(&mut self, path: &Path) -> Result> { + pub fn languages_at_path(&mut self, path: &Path) -> LoaderResult> { if let Ok(configurations) = self.find_language_configurations_at_path(path, true) { let mut language_ids = configurations .iter() @@ -530,14 +758,14 @@ impl Loader { language_ids .into_iter() .map(|(id, name)| Ok((self.language_for_id(id)?, name))) - .collect::>>() + .collect::>>() } else { Ok(Vec::new()) } } #[must_use] - pub fn get_all_language_configurations(&self) -> Vec<(&LanguageConfiguration, &Path)> { + pub fn get_all_language_configurations(&self) -> Vec<(&LanguageConfiguration<'static>, &Path)> { self.language_configurations .iter() .map(|c| (c, self.languages_by_id[c.language_id].0.as_ref())) @@ -547,7 +775,7 @@ impl Loader { pub fn language_configuration_for_scope( &self, scope: &str, - ) -> Result> { + ) -> LoaderResult)>> { for configuration in &self.language_configurations { if configuration.scope.as_ref().is_some_and(|s| s == scope) { let language = self.language_for_id(configuration.language_id)?; @@ -560,14 +788,19 @@ impl Loader { pub fn language_configuration_for_first_line_regex( &self, path: &Path, - ) -> Result> { + ) -> LoaderResult)>> { self.language_configuration_ids_by_first_line_regex .iter() .try_fold(None, |_, (regex, ids)| { if let Some(regex) = Self::regex(Some(regex)) { - let file = fs::File::open(path)?; + let file = fs::File::open(path) + .map_err(|e| LoaderError::IO(IoError::new(e, Some(path))))?; let reader = BufReader::new(file); - let first_line = reader.lines().next().transpose()?; + let first_line = reader + .lines() + .next() + .transpose() + .map_err(|e| LoaderError::IO(IoError::new(e, Some(path))))?; if let Some(first_line) = first_line { if regex.is_match(&first_line) && !ids.is_empty() { let configuration = &self.language_configurations[ids[0]]; @@ -584,7 +817,7 @@ impl Loader { pub fn language_configuration_for_file_name( &self, path: &Path, - ) -> Result> { + ) -> LoaderResult)>> { // Find all the language configurations that match this file name // or a suffix of the file name. let configuration_ids = path @@ -611,8 +844,8 @@ impl Loader { // If multiple language configurations match, then determine which // one to use by applying the configurations' content regexes. else { - let file_contents = fs::read(path) - .with_context(|| format!("Failed to read path {}", path.display()))?; + let file_contents = + fs::read(path).map_err(|e| LoaderError::IO(IoError::new(e, Some(path))))?; let file_contents = String::from_utf8_lossy(&file_contents); let mut best_score = -2isize; let mut best_configuration_id = None; @@ -656,7 +889,7 @@ impl Loader { pub fn language_configuration_for_injection_string( &self, string: &str, - ) -> Result> { + ) -> LoaderResult)>> { let mut best_match_length = 0; let mut best_match_position = None; for (i, configuration) in self.language_configurations.iter().enumerate() { @@ -683,11 +916,11 @@ impl Loader { pub fn language_for_configuration( &self, configuration: &LanguageConfiguration, - ) -> Result { + ) -> LoaderResult { self.language_for_id(configuration.language_id) } - fn language_for_id(&self, id: usize) -> Result { + fn language_for_id(&self, id: usize) -> LoaderResult { let (path, language, externals) = &self.languages_by_id[id]; language .get_or_try_init(|| { @@ -706,20 +939,23 @@ impl Loader { grammar_path: &Path, output_path: PathBuf, flags: &[&str], - ) -> Result<()> { + ) -> LoaderResult<()> { let src_path = grammar_path.join("src"); let mut config = CompileConfig::new(&src_path, None, Some(output_path)); config.flags = flags; self.load_language_at_path(config).map(|_| ()) } - pub fn load_language_at_path(&self, mut config: CompileConfig) -> Result { + pub fn load_language_at_path(&self, mut config: CompileConfig) -> LoaderResult { let grammar_path = config.src_path.join("grammar.json"); config.name = Self::grammar_json_name(&grammar_path)?; self.load_language_at_path_with_name(config) } - pub fn load_language_at_path_with_name(&self, mut config: CompileConfig) -> Result { + pub fn load_language_at_path_with_name( + &self, + mut config: CompileConfig, + ) -> LoaderResult { let mut lib_name = config.name.clone(); let language_fn_name = format!("tree_sitter_{}", config.name.replace('-', "_")); if self.debug_build { @@ -732,7 +968,9 @@ impl Loader { } if config.output_path.is_none() { - fs::create_dir_all(&self.parser_lib_path)?; + fs::create_dir_all(&self.parser_lib_path).map_err(|e| { + LoaderError::IO(IoError::new(e, Some(self.parser_lib_path.as_path()))) + })?; } let mut recompile = self.force_rebuild || config.output_path.is_some(); // if specified, always recompile @@ -766,8 +1004,7 @@ impl Loader { ); if !recompile { - recompile = needs_recompile(&output_path, &paths_to_check) - .with_context(|| "Failed to compare source and binary timestamps")?; + recompile = needs_recompile(&output_path, &paths_to_check)?; } #[cfg(feature = "wasm")] @@ -784,57 +1021,73 @@ impl Loader { )?; } - let wasm_bytes = fs::read(&output_path)?; + let wasm_bytes = fs::read(&output_path) + .map_err(|e| LoaderError::IO(IoError::new(e, Some(output_path.as_path()))))?; return Ok(wasm_store.load_language(&config.name, &wasm_bytes)?); } + // Create a unique lock path based on the output path hash to prevent + // interference when multiple processes build the same grammar (by name) + // to different output locations + let lock_hash = { + let mut hasher = std::hash::DefaultHasher::new(); + output_path.hash(&mut hasher); + format!("{:x}", hasher.finish()) + }; + let lock_path = if env::var("CROSS_RUNNER").is_ok() { tempfile::tempdir() - .unwrap() + .expect("create a temp dir") .path() - .join("tree-sitter") - .join("lock") - .join(format!("{}.lock", config.name)) + .to_path_buf() } else { - etcetera::choose_base_strategy()? - .cache_dir() - .join("tree-sitter") - .join("lock") - .join(format!("{}.lock", config.name)) - }; + etcetera::choose_base_strategy()?.cache_dir() + } + .join("tree-sitter") + .join("lock") + .join(format!("{}-{lock_hash}.lock", config.name)); if let Ok(lock_file) = fs::OpenOptions::new().write(true).open(&lock_path) { recompile = false; if lock_file.try_lock_exclusive().is_err() { // if we can't acquire the lock, another process is compiling the parser, wait for // it and don't recompile - lock_file.lock_exclusive()?; + lock_file + .lock_exclusive() + .map_err(|e| LoaderError::IO(IoError::new(e, Some(lock_path.as_path()))))?; recompile = false; } else { // if we can acquire the lock, check if the lock file is older than 30 seconds, a // run that was interrupted and left the lock file behind should not block // subsequent runs - let time = lock_file.metadata()?.modified()?.elapsed()?.as_secs(); + let time = lock_file + .metadata() + .map_err(|e| LoaderError::IO(IoError::new(e, Some(lock_path.as_path()))))? + .modified() + .map_err(|e| LoaderError::IO(IoError::new(e, Some(lock_path.as_path()))))? + .elapsed()? + .as_secs(); if time > 30 { - fs::remove_file(&lock_path)?; + fs::remove_file(&lock_path) + .map_err(|e| LoaderError::IO(IoError::new(e, Some(lock_path.as_path()))))?; recompile = true; } } } if recompile { - fs::create_dir_all(lock_path.parent().unwrap()).with_context(|| { - format!( - "Failed to create directory {}", - lock_path.parent().unwrap().display() - ) - })?; + let parent_path = lock_path.parent().unwrap(); + fs::create_dir_all(parent_path) + .map_err(|e| LoaderError::IO(IoError::new(e, Some(parent_path))))?; let lock_file = fs::OpenOptions::new() .create(true) .truncate(true) .write(true) - .open(&lock_path)?; - lock_file.lock_exclusive()?; + .open(&lock_path) + .map_err(|e| LoaderError::IO(IoError::new(e, Some(lock_path.as_path()))))?; + lock_file + .lock_exclusive() + .map_err(|e| LoaderError::IO(IoError::new(e, Some(lock_path.as_path()))))?; self.compile_parser_to_dylib(&config, &lock_file, &lock_path)?; @@ -843,20 +1096,45 @@ impl Loader { } } + // Ensure the dynamic library exists before trying to load it. This can + // happen in race conditions where we couldn't acquire the lock because + // another process was compiling but it still hasn't finished by the + // time we reach this point, so the output file still doesn't exist. + // + // Instead of allowing the `load_language` call below to fail, return a + // clearer error to the user here. + if !output_path.exists() { + let msg = format!( + "Dynamic library `{}` not found after build attempt. \ + Are you running multiple processes building to the same output location?", + output_path.display() + ); + + Err(LoaderError::IO(IoError::new( + std::io::Error::new(std::io::ErrorKind::NotFound, msg), + Some(output_path.as_path()), + )))?; + } + Self::load_language(&output_path, &language_fn_name) } - pub fn load_language(path: &Path, function_name: &str) -> Result { - let library = unsafe { Library::new(path) } - .with_context(|| format!("Error opening dynamic library {}", path.display()))?; + pub fn load_language(path: &Path, function_name: &str) -> LoaderResult { + let library = unsafe { Library::new(path) }.map_err(|e| { + LoaderError::Library(LibraryError { + error: e, + path: path.to_string_lossy().to_string(), + }) + })?; let language = unsafe { let language_fn = library .get:: Language>>(function_name.as_bytes()) - .with_context(|| { - format!( - "Failed to load symbol {function_name} from {}", - path.display() - ) + .map_err(|e| { + LoaderError::Symbol(SymbolError { + error: e, + symbol_name: function_name.to_string(), + path: path.to_string_lossy().to_string(), + }) })?; language_fn() }; @@ -869,13 +1147,16 @@ impl Loader { config: &CompileConfig, lock_file: &fs::File, lock_path: &Path, - ) -> Result<(), Error> { + ) -> LoaderResult<()> { let mut cc_config = cc::Build::new(); cc_config .cargo_metadata(false) .cargo_warnings(false) .target(BUILD_TARGET) - .host(BUILD_HOST) + // BUILD_TARGET from the build environment becomes a runtime host for cc. + // Otherwise, when cross compiled, cc will keep looking for a cross-compiler + // on the target system instead of the native compiler. + .host(BUILD_TARGET) .debug(self.debug_build) .file(&config.parser_path) .includes(&config.header_paths) @@ -904,12 +1185,27 @@ impl Loader { let output_path = config.output_path.as_ref().unwrap(); - if compiler.is_like_msvc() { + let temp_dir = if compiler.is_like_msvc() { let out = format!("-out:{}", output_path.to_str().unwrap()); command.arg(if self.debug_build { "-LDd" } else { "-LD" }); command.arg("-utf-8"); + + // Windows creates intermediate files when compiling (.exp, .lib, .obj), which causes + // issues when multiple processes are compiling in the same directory. This creates a + // temporary directory for those files to go into, which is deleted after compilation. + let temp_dir = output_path.parent().unwrap().join(format!( + "tmp_{}_{:?}", + std::process::id(), + std::thread::current().id() + )); + std::fs::create_dir_all(&temp_dir).unwrap(); + + command.arg(format!("/Fo{}\\", temp_dir.display())); command.args(cc_config.get_files()); command.arg("-link").arg(out); + command.arg(format!("/IMPLIB:{}.lib", temp_dir.join("temp").display())); + + Some(temp_dir) } else { command.arg("-Werror=implicit-function-declaration"); if cfg!(any(target_os = "macos", target_os = "ios")) { @@ -921,28 +1217,38 @@ impl Loader { } command.args(cc_config.get_files()); command.arg("-o").arg(output_path); - } - let output = command.output().with_context(|| { - format!("Failed to execute the C compiler with the following command:\n{command:?}") + None + }; + + let output = command.output().map_err(|e| { + LoaderError::Compiler(CompilerError { + error: e, + command: Box::new(command), + }) })?; - FileExt::unlock(lock_file)?; - fs::remove_file(lock_path)?; + if let Some(temp_dir) = temp_dir { + let _ = fs::remove_dir_all(temp_dir); + } + + FileExt::unlock(lock_file) + .map_err(|e| LoaderError::IO(IoError::new(e, Some(lock_path))))?; + fs::remove_file(lock_path) + .map_err(|e| LoaderError::IO(IoError::new(e, Some(lock_path))))?; if output.status.success() { Ok(()) } else { - Err(anyhow!( - "Parser compilation failed.\nStdout: {}\nStderr: {}", - String::from_utf8_lossy(&output.stdout), - String::from_utf8_lossy(&output.stderr) + Err(LoaderError::Compilation( + String::from_utf8_lossy(&output.stdout).to_string(), + String::from_utf8_lossy(&output.stderr).to_string(), )) } } #[cfg(unix)] - fn check_external_scanner(&self, name: &str, library_path: &Path) -> Result<()> { + fn check_external_scanner(&self, name: &str, library_path: &Path) -> LoaderResult<()> { let prefix = if cfg!(any(target_os = "macos", target_os = "ios")) { "_" } else { @@ -994,31 +1300,23 @@ impl Loader { } if !must_have.is_empty() { - let missing = must_have - .iter() - .map(|f| format!(" `{f}`")) - .collect::>() - .join("\n"); - - return Err(anyhow!(format!( - indoc::indoc! {" - Missing required functions in the external scanner, parsing won't work without these! - - {} - - You can read more about this at https://tree-sitter.github.io/tree-sitter/creating-parsers/4-external-scanners - "}, - missing, - ))); + return Err(LoaderError::ScannerSymbols(ScannerSymbolError { + missing: must_have, + })); } } + } else { + warn!( + "Failed to run `nm` to verify symbols in {}", + library_path.display() + ); } Ok(()) } #[cfg(windows)] - fn check_external_scanner(&self, _name: &str, _library_path: &Path) -> Result<()> { + fn check_external_scanner(&self, _name: &str, _library_path: &Path) -> LoaderResult<()> { // TODO: there's no nm command on windows, whoever wants to implement this can and should :) // let mut must_have = vec![ @@ -1038,14 +1336,13 @@ impl Loader { src_path: &Path, scanner_filename: Option<&Path>, output_path: &Path, - ) -> Result<(), Error> { + ) -> LoaderResult<()> { let clang_executable = self.ensure_wasi_sdk_exists()?; - let output_name = "output.wasm"; let mut command = Command::new(&clang_executable); command.current_dir(src_path).args([ "-o", - output_name, + output_path.to_str().unwrap(), "-fPIC", "-shared", if self.debug_build { "-g" } else { "-Os" }, @@ -1064,18 +1361,14 @@ impl Loader { command.arg(scanner_filename); } - let output = command.output().context("Failed to run wasi-sdk clang")?; + let output = command.output().map_err(LoaderError::WasmCompiler)?; if !output.status.success() { - return Err(anyhow!( - "wasi-sdk clang command failed: {}", - String::from_utf8_lossy(&output.stderr) + return Err(LoaderError::WasmCompilation( + String::from_utf8_lossy(&output.stderr).to_string(), )); } - fs::rename(src_path.join(output_name), output_path) - .context("failed to rename Wasm output file")?; - Ok(()) } @@ -1084,7 +1377,7 @@ impl Loader { &self, archive_path: &Path, destination: &Path, - ) -> Result<(), Error> { + ) -> LoaderResult<()> { let status = Command::new("tar") .arg("-xzf") .arg(archive_path) @@ -1092,13 +1385,12 @@ impl Loader { .arg("-C") .arg(destination) .status() - .with_context(|| format!("Failed to execute tar for {}", archive_path.display()))?; + .map_err(|e| LoaderError::Tar(archive_path.to_string_lossy().to_string(), e))?; if !status.success() { - return Err(anyhow!( - "Failed to extract archive {} to {}", - archive_path.display(), - destination.display() + return Err(LoaderError::Extraction( + archive_path.to_string_lossy().to_string(), + destination.to_string_lossy().to_string(), )); } @@ -1109,7 +1401,7 @@ impl Loader { /// and returns the path to the `clang` executable. /// /// If `TREE_SITTER_WASI_SDK_PATH` is set, it will use that path to look for the clang executable. - fn ensure_wasi_sdk_exists(&self) -> Result { + fn ensure_wasi_sdk_exists(&self) -> LoaderResult { let possible_executables = if cfg!(windows) { vec![ "clang.exe", @@ -1130,18 +1422,18 @@ impl Loader { } } - return Err(anyhow!( - "TREE_SITTER_WASI_SDK_PATH is set to '{}', but no clang executable found in 'bin/' directory. \ - Looked for: {}", - wasi_sdk_dir.display(), - possible_executables.join(", ") - )); + return Err(LoaderError::WasiSDKClang(WasiSDKClangError { + wasi_sdk_dir: wasi_sdk_dir.to_string_lossy().to_string(), + possible_executables, + download: false, + })); } let cache_dir = etcetera::choose_base_strategy()? .cache_dir() .join("tree-sitter"); - fs::create_dir_all(&cache_dir)?; + fs::create_dir_all(&cache_dir) + .map_err(|e| LoaderError::IO(IoError::new(e, Some(cache_dir.as_path()))))?; let wasi_sdk_dir = cache_dir.join("wasi-sdk"); @@ -1152,7 +1444,8 @@ impl Loader { } } - fs::create_dir_all(&wasi_sdk_dir)?; + fs::create_dir_all(&wasi_sdk_dir) + .map_err(|e| LoaderError::IO(IoError::new(e, Some(wasi_sdk_dir.as_path()))))?; let arch_os = if cfg!(target_os = "macos") { if cfg!(target_arch = "aarch64") { @@ -1173,12 +1466,15 @@ impl Loader { "x86_64-linux" } } else { - return Err(anyhow!("Unsupported platform for wasi-sdk")); + return Err(LoaderError::WasiSDKPlatform); }; - let sdk_filename = format!("wasi-sdk-25.0-{arch_os}.tar.gz"); + let sdk_filename = format!("wasi-sdk-{WASI_SDK_VERSION}-{arch_os}.tar.gz"); + let wasi_sdk_major_version = WASI_SDK_VERSION + .trim_end_matches(char::is_numeric) // trim minor version... + .trim_end_matches('.'); // ...and '.' separator let sdk_url = format!( - "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/{sdk_filename}", + "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-{wasi_sdk_major_version}/{sdk_filename}", ); info!("Downloading wasi-sdk from {sdk_url}..."); @@ -1191,15 +1487,14 @@ impl Loader { .arg(&temp_tar_path) .arg(&sdk_url) .status() - .with_context(|| format!("Failed to execute curl for {sdk_url}"))?; + .map_err(|e| LoaderError::Curl(sdk_url.clone(), e))?; if !status.success() { - return Err(anyhow!("Failed to download wasi-sdk from {sdk_url}",)); + return Err(LoaderError::WasiSDKDownload(sdk_url)); } info!("Extracting wasi-sdk to {}...", wasi_sdk_dir.display()); - self.extract_tar_gz_with_strip(&temp_tar_path, &wasi_sdk_dir) - .context("Failed to extract wasi-sdk archive")?; + self.extract_tar_gz_with_strip(&temp_tar_path, &wasi_sdk_dir)?; fs::remove_file(temp_tar_path).ok(); for exe in &possible_executables { @@ -1209,11 +1504,11 @@ impl Loader { } } - Err(anyhow!( - "Failed to find clang executable in downloaded wasi-sdk at '{}'. Looked for: {}", - wasi_sdk_dir.display(), - possible_executables.join(", ") - )) + Err(LoaderError::WasiSDKClang(WasiSDKClangError { + wasi_sdk_dir: wasi_sdk_dir.to_string_lossy().to_string(), + possible_executables, + download: true, + })) } #[must_use] @@ -1244,7 +1539,9 @@ impl Loader { } #[must_use] - pub fn get_language_configuration_in_current_path(&self) -> Option<&LanguageConfiguration> { + pub fn get_language_configuration_in_current_path( + &self, + ) -> Option<&LanguageConfiguration<'static>> { self.language_configuration_in_current_path .map(|i| &self.language_configurations[i]) } @@ -1253,113 +1550,121 @@ impl Loader { &mut self, parser_path: &Path, set_current_path_config: bool, - ) -> Result<&[LanguageConfiguration]> { + ) -> LoaderResult<&[LanguageConfiguration<'static>]> { let initial_language_configuration_count = self.language_configurations.len(); - let ts_json = TreeSitterJSON::from_file(parser_path); - if let Ok(config) = ts_json { - let language_count = self.languages_by_id.len(); - for grammar in config.grammars { - // Determine the path to the parser directory. This can be specified in - // the tree-sitter.json, but defaults to the directory containing the - // tree-sitter.json. - let language_path = parser_path.join(grammar.path.unwrap_or(PathBuf::from("."))); + match TreeSitterJSON::from_file(parser_path) { + Ok(config) => { + let language_count = self.languages_by_id.len(); + for grammar in config.grammars { + // Determine the path to the parser directory. This can be specified in + // the tree-sitter.json, but defaults to the directory containing the + // tree-sitter.json. + let language_path = + parser_path.join(grammar.path.unwrap_or(PathBuf::from("."))); - // Determine if a previous language configuration in this package.json file - // already uses the same language. - let mut language_id = None; - for (id, (path, _, _)) in - self.languages_by_id.iter().enumerate().skip(language_count) - { - if language_path == *path { - language_id = Some(id); + // Determine if a previous language configuration in this package.json file + // already uses the same language. + let mut language_id = None; + for (id, (path, _, _)) in + self.languages_by_id.iter().enumerate().skip(language_count) + { + if language_path == *path { + language_id = Some(id); + } } - } - // If not, add a new language path to the list. - let language_id = if let Some(language_id) = language_id { - language_id - } else { - self.languages_by_id.push(( + // If not, add a new language path to the list. + let language_id = if let Some(language_id) = language_id { + language_id + } else { + self.languages_by_id.push(( language_path, OnceCell::new(), - grammar.external_files.clone().into_vec().map(|files| { - files.into_iter() - .map(|path| { - let path = parser_path.join(path); - // prevent p being above/outside of parser_path - if path.starts_with(parser_path) { - Ok(path) - } else { - Err(anyhow!("External file path {path:?} is outside of parser directory {parser_path:?}")) - } - }) - .collect::>>() - }).transpose()?, + grammar + .external_files + .clone() + .into_vec() + .map(|files| { + files + .into_iter() + .map(|path| { + let path = parser_path.join(path); + // prevent p being above/outside of parser_path + if path.starts_with(parser_path) { + Ok(path) + } else { + Err(LoaderError::ExternalFile( + path.to_string_lossy().to_string(), + parser_path.to_string_lossy().to_string(), + )) + } + }) + .collect::>>() + }) + .transpose()?, )); - self.languages_by_id.len() - 1 - }; + self.languages_by_id.len() - 1 + }; - let configuration = LanguageConfiguration { - root_path: parser_path.to_path_buf(), - language_name: grammar.name, - scope: Some(grammar.scope), - language_id, - file_types: grammar.file_types.unwrap_or_default(), - content_regex: Self::regex(grammar.content_regex.as_deref()), - first_line_regex: Self::regex(grammar.first_line_regex.as_deref()), - injection_regex: Self::regex(grammar.injection_regex.as_deref()), - injections_filenames: grammar.injections.into_vec(), - locals_filenames: grammar.locals.into_vec(), - tags_filenames: grammar.tags.into_vec(), - highlights_filenames: grammar.highlights.into_vec(), - #[cfg(feature = "tree-sitter-highlight")] - highlight_config: OnceCell::new(), - #[cfg(feature = "tree-sitter-tags")] - tags_config: OnceCell::new(), - #[cfg(feature = "tree-sitter-highlight")] - highlight_names: &self.highlight_names, - #[cfg(feature = "tree-sitter-highlight")] - use_all_highlight_names: self.use_all_highlight_names, - _phantom: PhantomData, - }; + let configuration = LanguageConfiguration { + root_path: parser_path.to_path_buf(), + language_name: grammar.name, + scope: Some(grammar.scope), + language_id, + file_types: grammar.file_types.unwrap_or_default(), + content_regex: Self::regex(grammar.content_regex.as_deref()), + first_line_regex: Self::regex(grammar.first_line_regex.as_deref()), + injection_regex: Self::regex(grammar.injection_regex.as_deref()), + injections_filenames: grammar.injections.into_vec(), + locals_filenames: grammar.locals.into_vec(), + tags_filenames: grammar.tags.into_vec(), + highlights_filenames: grammar.highlights.into_vec(), + #[cfg(feature = "tree-sitter-highlight")] + highlight_config: OnceCell::new(), + #[cfg(feature = "tree-sitter-tags")] + tags_config: OnceCell::new(), + #[cfg(feature = "tree-sitter-highlight")] + highlight_names: &self.highlight_names, + #[cfg(feature = "tree-sitter-highlight")] + use_all_highlight_names: self.use_all_highlight_names, + _phantom: PhantomData, + }; - for file_type in &configuration.file_types { - self.language_configuration_ids_by_file_type - .entry(file_type.clone()) - .or_default() - .push(self.language_configurations.len()); - } - if let Some(first_line_regex) = &configuration.first_line_regex { - self.language_configuration_ids_by_first_line_regex - .entry(first_line_regex.to_string()) - .or_default() - .push(self.language_configurations.len()); - } + for file_type in &configuration.file_types { + self.language_configuration_ids_by_file_type + .entry(file_type.clone()) + .or_default() + .push(self.language_configurations.len()); + } + if let Some(first_line_regex) = &configuration.first_line_regex { + self.language_configuration_ids_by_first_line_regex + .entry(first_line_regex.to_string()) + .or_default() + .push(self.language_configurations.len()); + } - self.language_configurations.push(unsafe { - mem::transmute::, LanguageConfiguration<'static>>( - configuration, - ) - }); + self.language_configurations.push(unsafe { + mem::transmute::, LanguageConfiguration<'static>>( + configuration, + ) + }); - if set_current_path_config && self.language_configuration_in_current_path.is_none() - { - self.language_configuration_in_current_path = - Some(self.language_configurations.len() - 1); + if set_current_path_config + && self.language_configuration_in_current_path.is_none() + { + self.language_configuration_in_current_path = + Some(self.language_configurations.len() - 1); + } } } - } else if let Err(e) = ts_json { - match e.downcast_ref::() { - // This is noisy, and not really an issue. - Some(e) if e.kind() == std::io::ErrorKind::NotFound => {} - _ => { - warn!( - "Failed to parse {} -- {e}", - parser_path.join("tree-sitter.json").display() - ); - } + Err(LoaderError::Serialization(e)) => { + warn!( + "Failed to parse {} -- {e}", + parser_path.join("tree-sitter.json").display() + ); } + _ => {} } // If we didn't find any language configurations in the tree-sitter.json file, @@ -1409,79 +1714,74 @@ impl Loader { pattern.and_then(|r| RegexBuilder::new(r).multi_line(true).build().ok()) } - fn grammar_json_name(grammar_path: &Path) -> Result { - let file = fs::File::open(grammar_path).with_context(|| { - format!("Failed to open grammar.json at {}", grammar_path.display()) - })?; + fn grammar_json_name(grammar_path: &Path) -> LoaderResult { + let file = fs::File::open(grammar_path) + .map_err(|e| LoaderError::IO(IoError::new(e, Some(grammar_path))))?; let first_three_lines = BufReader::new(file) .lines() .take(3) - .collect::, _>>() - .with_context(|| { - format!( - "Failed to read the first three lines of grammar.json at {}", - grammar_path.display() - ) - })? + .collect::, std::io::Error>>() + .map_err(|_| LoaderError::GrammarJSON(grammar_path.to_string_lossy().to_string()))? .join("\n"); let name = GRAMMAR_NAME_REGEX .captures(&first_three_lines) .and_then(|c| c.get(1)) - .ok_or_else(|| { - anyhow!( - "Failed to parse the language name from grammar.json at {}", - grammar_path.display() - ) - })?; + .ok_or_else(|| LoaderError::GrammarJSON(grammar_path.to_string_lossy().to_string()))?; Ok(name.as_str().to_string()) } pub fn select_language( &mut self, - path: &Path, + path: Option<&Path>, current_dir: &Path, scope: Option<&str>, // path to dynamic library, name of language lib_info: Option<&(PathBuf, &str)>, - ) -> Result { + ) -> LoaderResult { if let Some((ref lib_path, language_name)) = lib_info { let language_fn_name = format!("tree_sitter_{}", language_name.replace('-', "_")); Self::load_language(lib_path, &language_fn_name) } else if let Some(scope) = scope { if let Some(config) = self .language_configuration_for_scope(scope) - .with_context(|| format!("Failed to load language for scope '{scope}'"))? + .map_err(|e| LoaderError::ScopeLoad(scope.to_string(), Box::new(e)))? { Ok(config.0) } else { - Err(anyhow!("Unknown scope '{scope}'")) + Err(LoaderError::UnknownScope(scope.to_string())) } - } else if let Some((lang, _)) = self - .language_configuration_for_file_name(path) - .with_context(|| { - format!( - "Failed to load language for file name {}", - path.file_name().unwrap().to_string_lossy() - ) - })? - { + } else if let Some((lang, _)) = if let Some(path) = path { + self.language_configuration_for_file_name(path) + .map_err(|e| { + LoaderError::FileNameLoad( + path.file_name().unwrap().to_string_lossy().to_string(), + Box::new(e), + ) + })? + } else { + None + } { Ok(lang) } else if let Some(id) = self.language_configuration_in_current_path { Ok(self.language_for_id(self.language_configurations[id].language_id)?) } else if let Some(lang) = self .languages_at_path(current_dir) - .with_context(|| "Failed to load language in current directory")? + .map_err(|e| LoaderError::CurrentDirectoryLoad(Box::new(e)))? .first() .cloned() { Ok(lang.0) - } else if let Some(lang) = self.language_configuration_for_first_line_regex(path)? { + } else if let Some(lang) = if let Some(path) = path { + self.language_configuration_for_first_line_regex(path)? + } else { + None + } { Ok(lang.0) } else { - Err(anyhow!("No language found")) + Err(LoaderError::NoLanguage) } } @@ -1516,27 +1816,27 @@ impl LanguageConfiguration<'_> { &self, language: Language, paths: Option<&[PathBuf]>, - ) -> Result> { + ) -> LoaderResult> { let (highlights_filenames, injections_filenames, locals_filenames) = match paths { Some(paths) => ( Some( paths .iter() - .filter(|p| p.ends_with("highlights.scm")) + .filter(|p| p.ends_with(DEFAULT_HIGHLIGHTS_QUERY_FILE_NAME)) .cloned() .collect::>(), ), Some( paths .iter() - .filter(|p| p.ends_with("tags.scm")) + .filter(|p| p.ends_with(DEFAULT_TAGS_QUERY_FILE_NAME)) .cloned() .collect::>(), ), Some( paths .iter() - .filter(|p| p.ends_with("locals.scm")) + .filter(|p| p.ends_with(DEFAULT_LOCALS_QUERY_FILE_NAME)) .cloned() .collect::>(), ), @@ -1551,7 +1851,7 @@ impl LanguageConfiguration<'_> { } else { self.highlights_filenames.as_deref() }, - "highlights.scm", + DEFAULT_HIGHLIGHTS_QUERY_FILE_NAME, )?; let (injections_query, injection_ranges) = self.read_queries( if injections_filenames.is_some() { @@ -1559,7 +1859,7 @@ impl LanguageConfiguration<'_> { } else { self.injections_filenames.as_deref() }, - "injections.scm", + DEFAULT_INJECTIONS_QUERY_FILE_NAME, )?; let (locals_query, locals_ranges) = self.read_queries( if locals_filenames.is_some() { @@ -1567,7 +1867,7 @@ impl LanguageConfiguration<'_> { } else { self.locals_filenames.as_deref() }, - "locals.scm", + DEFAULT_LOCALS_QUERY_FILE_NAME, )?; if highlights_query.is_empty() { @@ -1581,7 +1881,9 @@ impl LanguageConfiguration<'_> { &locals_query, ) .map_err(|error| match error.kind { - QueryErrorKind::Language => Error::from(error), + QueryErrorKind::Language => { + LoaderError::Query(LoaderQueryError { error, file: None }) + } _ => { if error.offset < injections_query.len() { Self::include_path_in_query_error( @@ -1624,13 +1926,15 @@ impl LanguageConfiguration<'_> { } #[cfg(feature = "tree-sitter-tags")] - pub fn tags_config(&self, language: Language) -> Result> { + pub fn tags_config(&self, language: Language) -> LoaderResult> { self.tags_config .get_or_try_init(|| { - let (tags_query, tags_ranges) = - self.read_queries(self.tags_filenames.as_deref(), "tags.scm")?; - let (locals_query, locals_ranges) = - self.read_queries(self.locals_filenames.as_deref(), "locals.scm")?; + let (tags_query, tags_ranges) = self + .read_queries(self.tags_filenames.as_deref(), DEFAULT_TAGS_QUERY_FILE_NAME)?; + let (locals_query, locals_ranges) = self.read_queries( + self.locals_filenames.as_deref(), + DEFAULT_LOCALS_QUERY_FILE_NAME, + )?; if tags_query.is_empty() { Ok(None) } else { @@ -1668,7 +1972,7 @@ impl LanguageConfiguration<'_> { ranges: &[(PathBuf, Range)], source: &str, start_offset: usize, - ) -> Error { + ) -> LoaderError { let offset_within_section = error.offset - start_offset; let (path, range) = ranges .iter() @@ -1678,7 +1982,10 @@ impl LanguageConfiguration<'_> { error.row = source[range.start..offset_within_section] .matches('\n') .count(); - Error::from(error).context(format!("Error in query file {}", path.display())) + LoaderError::Query(LoaderQueryError { + error, + file: Some(path.to_string_lossy().to_string()), + }) } #[allow(clippy::type_complexity)] @@ -1687,7 +1994,7 @@ impl LanguageConfiguration<'_> { &self, paths: Option<&[PathBuf]>, default_path: &str, - ) -> Result<(String, Vec<(PathBuf, Range)>)> { + ) -> LoaderResult<(String, Vec<(PathBuf, Range)>)> { let mut query = String::new(); let mut path_ranges = Vec::new(); if let Some(paths) = paths { @@ -1695,12 +2002,14 @@ impl LanguageConfiguration<'_> { let abs_path = self.root_path.join(path); let prev_query_len = query.len(); query += &fs::read_to_string(&abs_path) - .with_context(|| format!("Failed to read query file {}", path.display()))?; + .map_err(|e| LoaderError::IO(IoError::new(e, Some(abs_path.as_path()))))?; path_ranges.push((path.clone(), prev_query_len..query.len())); } } else { // highlights.scm is needed to test highlights, and tags.scm to test tags - if default_path == "highlights.scm" || default_path == "tags.scm" { + if default_path == DEFAULT_HIGHLIGHTS_QUERY_FILE_NAME + || default_path == DEFAULT_TAGS_QUERY_FILE_NAME + { warn!( concat!( "You should add a `{}` entry pointing to the {} path in the `tree-sitter` ", @@ -1715,7 +2024,7 @@ impl LanguageConfiguration<'_> { let path = queries_path.join(default_path); if path.exists() { query = fs::read_to_string(&path) - .with_context(|| format!("Failed to read query file {}", path.display()))?; + .map_err(|e| LoaderError::IO(IoError::new(e, Some(path.as_path()))))?; path_ranges.push((PathBuf::from(default_path), 0..query.len())); } } @@ -1724,20 +2033,22 @@ impl LanguageConfiguration<'_> { } } -fn needs_recompile(lib_path: &Path, paths_to_check: &[PathBuf]) -> Result { +fn needs_recompile(lib_path: &Path, paths_to_check: &[PathBuf]) -> LoaderResult { if !lib_path.exists() { return Ok(true); } - let lib_mtime = mtime(lib_path) - .with_context(|| format!("Failed to read mtime of {}", lib_path.display()))?; + let lib_mtime = mtime(lib_path).map_err(|e| LoaderError::ModifiedTime(Box::new(e)))?; for path in paths_to_check { - if mtime(path)? > lib_mtime { + if mtime(path).map_err(|e| LoaderError::ModifiedTime(Box::new(e)))? > lib_mtime { return Ok(true); } } Ok(false) } -fn mtime(path: &Path) -> Result { - Ok(fs::metadata(path)?.modified()?) +fn mtime(path: &Path) -> LoaderResult { + fs::metadata(path) + .map_err(|e| LoaderError::IO(IoError::new(e, Some(path))))? + .modified() + .map_err(|e| LoaderError::IO(IoError::new(e, Some(path)))) } diff --git a/crates/loader/wasi-sdk-version b/crates/loader/wasi-sdk-version new file mode 100644 index 00000000..231f5c77 --- /dev/null +++ b/crates/loader/wasi-sdk-version @@ -0,0 +1 @@ +29.0 diff --git a/crates/tags/src/tags.rs b/crates/tags/src/tags.rs index 16270b0a..c6654876 100644 --- a/crates/tags/src/tags.rs +++ b/crates/tags/src/tags.rs @@ -313,6 +313,7 @@ impl TagsContext { ) .ok_or(Error::Cancelled)?; + // SAFETY: // The `matches` iterator borrows the `Tree`, which prevents it from being // moved. But the tree is really just a pointer, so it's actually ok to // move it. diff --git a/crates/xtask/Cargo.toml b/crates/xtask/Cargo.toml index 607d64ad..17972317 100644 --- a/crates/xtask/Cargo.toml +++ b/crates/xtask/Cargo.toml @@ -19,9 +19,13 @@ anstyle.workspace = true anyhow.workspace = true bindgen = { version = "0.72.0" } clap.workspace = true +etcetera.workspace = true indoc.workspace = true regex.workspace = true +schemars.workspace = true semver.workspace = true serde_json.workspace = true +tree-sitter-cli = { path = "../cli/" } +tree-sitter-loader = { path = "../loader/" } notify = "8.2.0" notify-debouncer-full = "0.6.0" diff --git a/crates/xtask/src/build_wasm.rs b/crates/xtask/src/build_wasm.rs index 67ca59d6..fbb231ce 100644 --- a/crates/xtask/src/build_wasm.rs +++ b/crates/xtask/src/build_wasm.rs @@ -8,13 +8,15 @@ use std::{ time::Duration, }; -use anyhow::{anyhow, Error, Result}; +use anyhow::{anyhow, Result}; +use etcetera::BaseStrategy as _; use indoc::indoc; use notify::{ event::{AccessKind, AccessMode}, EventKind, RecursiveMode, }; use notify_debouncer_full::new_debouncer; +use tree_sitter_loader::{IoError, LoaderError, WasiSDKClangError}; use crate::{ bail_on_err, embed_sources::embed_sources_in_map, watch_wasm, BuildWasm, EMSCRIPTEN_TAG, @@ -50,6 +52,8 @@ const EXPORTED_RUNTIME_METHODS: [&str; 20] = [ "LE_HEAP_STORE_I64", ]; +const WASI_SDK_VERSION: &str = include_str!("../../loader/wasi-sdk-version").trim_ascii(); + pub fn run_wasm(args: &BuildWasm) -> Result<()> { let mut emscripten_flags = if args.debug { vec!["-O0", "--minify", "0"] @@ -195,6 +199,8 @@ pub fn run_wasm(args: &BuildWasm) -> Result<()> { "-D", "NDEBUG=", "-D", "_POSIX_C_SOURCE=200112L", "-D", "_DEFAULT_SOURCE=", + "-D", "_BSD_SOURCE=", + "-D", "_DARWIN_C_SOURCE=", "-I", "lib/src", "-I", "lib/include", "--js-library", "lib/binding_web/lib/imports.js", @@ -308,9 +314,17 @@ fn build_wasm(cmd: &mut Command, edit_tsd: bool) -> Result<()> { Ok(()) } -/// This gets the path to the `clang` binary in the WASI SDK specified by the -/// `TREE_SITTER_WASI_SDK_PATH` environment variable. -fn get_wasi_binary() -> Result { +/// This ensures that the wasi-sdk is available, downloading and extracting it if necessary, +/// and returns the path to the `clang` executable. +/// +/// If `TREE_SITTER_WASI_SDK_PATH` is set, it will use that path to look for the clang executable. +/// +/// Note that this is just a minimially modified version of +/// `tree_sitter_loader::ensure_wasi_sdk_exists`. In the loader, this functionality is implemented +/// as a private method of `Loader`. Rather than add this to the public API, we just +/// re-implement it. Any fixes and/or modifications made to the loader's copy should be reflected +/// here. +pub fn ensure_wasi_sdk_exists() -> Result { let possible_executables = if cfg!(windows) { vec![ "clang.exe", @@ -331,19 +345,122 @@ fn get_wasi_binary() -> Result { } } - return Err(anyhow!( - "TREE_SITTER_WASI_SDK_PATH is set to '{}', but no clang executable found in 'bin/' directory. \ - Looked for: {}", - wasi_sdk_dir.display(), - possible_executables.join(", ") - )); + Err(LoaderError::WasiSDKClang(WasiSDKClangError { + wasi_sdk_dir: wasi_sdk_dir.to_string_lossy().to_string(), + possible_executables: possible_executables.clone(), + download: false, + }))?; } - Err(anyhow!( - "TREE_SITTER_WASI_SDK_PATH environment variable is not set. \ - Please install the WASI SDK from https://github.com/WebAssembly/wasi-sdk/releases \ - and set TREE_SITTER_WASI_SDK_PATH to the installation directory." - )) + let cache_dir = etcetera::choose_base_strategy()? + .cache_dir() + .join("tree-sitter"); + fs::create_dir_all(&cache_dir).map_err(|error| { + LoaderError::IO(IoError { + error, + path: Some(cache_dir.to_string_lossy().to_string()), + }) + })?; + + let wasi_sdk_dir = cache_dir.join("wasi-sdk"); + + for exe in &possible_executables { + let clang_exe = wasi_sdk_dir.join("bin").join(exe); + if clang_exe.exists() { + return Ok(clang_exe); + } + } + + fs::create_dir_all(&wasi_sdk_dir).map_err(|error| { + LoaderError::IO(IoError { + error, + path: Some(wasi_sdk_dir.to_string_lossy().to_string()), + }) + })?; + + let arch_os = if cfg!(target_os = "macos") { + if cfg!(target_arch = "aarch64") { + "arm64-macos" + } else { + "x86_64-macos" + } + } else if cfg!(target_os = "windows") { + if cfg!(target_arch = "aarch64") { + "arm64-windows" + } else { + "x86_64-windows" + } + } else if cfg!(target_os = "linux") { + if cfg!(target_arch = "aarch64") { + "arm64-linux" + } else { + "x86_64-linux" + } + } else { + Err(LoaderError::WasiSDKPlatform)? + }; + + let sdk_filename = format!("wasi-sdk-{WASI_SDK_VERSION}-{arch_os}.tar.gz"); + let wasi_sdk_major_version = WASI_SDK_VERSION + .trim_end_matches(char::is_numeric) // trim minor version... + .trim_end_matches('.'); // ...and '.' separator + let sdk_url = format!( + "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-{wasi_sdk_major_version}/{sdk_filename}", + ); + + eprintln!("Downloading wasi-sdk from {sdk_url}..."); + let temp_tar_path = cache_dir.join(sdk_filename); + + let status = Command::new("curl") + .arg("-f") + .arg("-L") + .arg("-o") + .arg(&temp_tar_path) + .arg(&sdk_url) + .status() + .map_err(|e| LoaderError::Curl(sdk_url.clone(), e))?; + + if !status.success() { + Err(LoaderError::WasiSDKDownload(sdk_url))?; + } + + eprintln!("Extracting wasi-sdk to {}...", wasi_sdk_dir.display()); + extract_tar_gz_with_strip(&temp_tar_path, &wasi_sdk_dir)?; + + fs::remove_file(temp_tar_path).ok(); + for exe in &possible_executables { + let clang_exe = wasi_sdk_dir.join("bin").join(exe); + if clang_exe.exists() { + return Ok(clang_exe); + } + } + + Err(LoaderError::WasiSDKClang(WasiSDKClangError { + wasi_sdk_dir: wasi_sdk_dir.to_string_lossy().to_string(), + possible_executables, + download: true, + }))? +} + +/// Extracts a tar.gz archive with `tar`, stripping the first path component. +fn extract_tar_gz_with_strip(archive_path: &Path, destination: &Path) -> Result<()> { + let status = Command::new("tar") + .arg("-xzf") + .arg(archive_path) + .arg("--strip-components=1") + .arg("-C") + .arg(destination) + .status() + .map_err(|e| LoaderError::Tar(archive_path.to_string_lossy().to_string(), e))?; + + if !status.success() { + Err(LoaderError::Extraction( + archive_path.to_string_lossy().to_string(), + destination.to_string_lossy().to_string(), + ))?; + } + + Ok(()) } pub fn run_wasm_stdlib() -> Result<()> { @@ -352,7 +469,7 @@ pub fn run_wasm_stdlib() -> Result<()> { .map(|line| format!("-Wl,--export={}", &line[1..line.len() - 2])) .collect::>(); - let clang_exe = get_wasi_binary()?; + let clang_exe = ensure_wasi_sdk_exists()?; let output = Command::new(&clang_exe) .args([ diff --git a/crates/xtask/src/bump.rs b/crates/xtask/src/bump.rs index 7e5f5dcd..02254274 100644 --- a/crates/xtask/src/bump.rs +++ b/crates/xtask/src/bump.rs @@ -2,7 +2,7 @@ use std::{cmp::Ordering, path::Path}; use anyhow::{anyhow, Context, Result}; use indoc::indoc; -use semver::{BuildMetadata, Prerelease, Version}; +use semver::{Prerelease, Version}; use crate::{create_commit, BumpVersion}; @@ -48,7 +48,6 @@ pub fn run(args: BumpVersion) -> Result<()> { String::from_utf8_lossy(&output.stderr) ); } - let latest_tag_sha = String::from_utf8(output.stdout)?.trim().to_string(); let workspace_toml_version = Version::parse(&fetch_workspace_version()?)?; @@ -65,102 +64,7 @@ pub fn run(args: BumpVersion) -> Result<()> { return Ok(()); } - let output = std::process::Command::new("git") - .args(["rev-list", &format!("{latest_tag_sha}..HEAD")]) - .output()?; - if !output.status.success() { - anyhow::bail!( - "Failed to get commits: {}", - String::from_utf8_lossy(&output.stderr) - ); - } - let commits = String::from_utf8(output.stdout)? - .lines() - .map(|s| s.to_string()) - .collect::>(); - - let mut should_increment_patch = false; - let mut should_increment_minor = false; - - for commit_sha in commits { - let output = std::process::Command::new("git") - .args(["log", "-1", "--format=%s", &commit_sha]) - .output()?; - if !output.status.success() { - continue; - } - let message = String::from_utf8(output.stdout)?.trim().to_string(); - - let output = std::process::Command::new("git") - .args([ - "diff-tree", - "--no-commit-id", - "--name-only", - "-r", - &commit_sha, - ]) - .output()?; - if !output.status.success() { - continue; - } - - let mut source_code_changed = false; - for path in String::from_utf8(output.stdout)?.lines() { - let path = Path::new(path); - if path.extension().is_some_and(|ext| { - ext.eq_ignore_ascii_case("rs") - || ext.eq_ignore_ascii_case("js") - || ext.eq_ignore_ascii_case("c") - }) { - source_code_changed = true; - break; - } - } - - if source_code_changed { - should_increment_patch = true; - - let Some((prefix, _)) = message.split_once(':') else { - continue; - }; - - let convention = if prefix.contains('(') { - prefix.split_once('(').unwrap().0 - } else { - prefix - }; - - if ["feat", "feat!"].contains(&convention) || prefix.ends_with('!') { - should_increment_minor = true; - } - } - } - - let next_version = if let Some(version) = args.version { - version - } else { - let mut next_version = current_version.clone(); - if should_increment_minor { - next_version.minor += 1; - next_version.patch = 0; - next_version.pre = Prerelease::EMPTY; - next_version.build = BuildMetadata::EMPTY; - } else if should_increment_patch { - next_version.patch += 1; - next_version.pre = Prerelease::EMPTY; - next_version.build = BuildMetadata::EMPTY; - } else { - return Err(anyhow!(format!( - "No source code changed since {current_version}" - ))); - } - next_version - }; - if next_version <= current_version { - return Err(anyhow!(format!( - "Next version {next_version} must be greater than current version {current_version}" - ))); - } + let next_version = args.version; println!("Bumping from {current_version} to {next_version}"); update_crates(¤t_version, &next_version)?; diff --git a/crates/xtask/src/check_wasm_exports.rs b/crates/xtask/src/check_wasm_exports.rs index 124725b7..c93f7cd3 100644 --- a/crates/xtask/src/check_wasm_exports.rs +++ b/crates/xtask/src/check_wasm_exports.rs @@ -16,7 +16,7 @@ use notify_debouncer_full::new_debouncer; use crate::{bail_on_err, watch_wasm, CheckWasmExports}; -const EXCLUDES: [&str; 23] = [ +const EXCLUDES: [&str; 25] = [ // Unneeded because the JS side has its own way of implementing it "ts_node_child_by_field_name", "ts_node_edit", @@ -44,6 +44,8 @@ const EXCLUDES: [&str; 23] = [ "ts_query_cursor_delete", "ts_query_cursor_match_limit", "ts_query_cursor_remove_match", + "ts_query_cursor_set_point_range", + "ts_query_cursor_set_containing_byte_range", ]; pub fn run(args: &CheckWasmExports) -> Result<()> { diff --git a/crates/xtask/src/main.rs b/crates/xtask/src/main.rs index 57f81dae..3814cf66 100644 --- a/crates/xtask/src/main.rs +++ b/crates/xtask/src/main.rs @@ -7,6 +7,7 @@ mod embed_sources; mod fetch; mod generate; mod test; +mod test_schema; mod upgrade_wasmtime; use std::{path::Path, process::Command}; @@ -40,6 +41,8 @@ enum Commands { GenerateBindings, /// Generates the fixtures for testing tree-sitter. GenerateFixtures(GenerateFixtures), + /// Generates the JSON schema for the test runner summary. + GenerateTestSchema, /// Generate the list of exports from Tree-sitter Wasm files. GenerateWasmExports, /// Run the test suite @@ -94,8 +97,8 @@ struct BuildWasm { #[derive(Args)] struct BumpVersion { /// The version to bump to. - #[arg(long, short)] - version: Option, + #[arg(index = 1, required = true)] + version: Version, } #[derive(Args)] @@ -236,6 +239,7 @@ fn run() -> Result<()> { Commands::GenerateFixtures(generate_fixtures_options) => { generate::run_fixtures(&generate_fixtures_options)?; } + Commands::GenerateTestSchema => test_schema::run_test_schema()?, Commands::GenerateWasmExports => generate::run_wasm_exports()?, Commands::Test(test_options) => test::run(&test_options)?, Commands::TestWasm => test::run_wasm()?, diff --git a/crates/xtask/src/test.rs b/crates/xtask/src/test.rs index 467245dc..6b8d8243 100644 --- a/crates/xtask/src/test.rs +++ b/crates/xtask/src/test.rs @@ -73,9 +73,6 @@ pub fn run(args: &Test) -> Result<()> { .arg("--no-run") .arg("--message-format=json"); - #[cfg(target_os = "windows")] - cargo_cmd.arg("--").arg("--test-threads=1"); - let cargo_cmd = cargo_cmd.stdout(Stdio::piped()).spawn()?; let jq_cmd = Command::new("jq") @@ -103,9 +100,6 @@ pub fn run(args: &Test) -> Result<()> { } cargo_cmd.args(&args.args); - #[cfg(target_os = "windows")] - cargo_cmd.arg("--").arg("--test-threads=1"); - if args.nocapture { #[cfg(not(target_os = "windows"))] cargo_cmd.arg("--"); diff --git a/crates/xtask/src/test_schema.rs b/crates/xtask/src/test_schema.rs new file mode 100644 index 00000000..a2f65ed2 --- /dev/null +++ b/crates/xtask/src/test_schema.rs @@ -0,0 +1,25 @@ +use std::path::PathBuf; + +use anyhow::Result; +use serde_json::to_writer_pretty; + +use tree_sitter_cli::test::TestSummary; + +pub fn run_test_schema() -> Result<()> { + let schema = schemars::schema_for!(TestSummary); + + let xtask_path: PathBuf = env!("CARGO_MANIFEST_DIR").into(); + let schema_path = xtask_path + .parent() + .unwrap() + .parent() + .unwrap() + .join("docs") + .join("src") + .join("assets") + .join("schemas") + .join("test-summary.schema.json"); + let mut file = std::fs::File::create(schema_path)?; + + Ok(to_writer_pretty(&mut file, &schema)?) +} diff --git a/docs/book.toml b/docs/book.toml index 664a1f24..0894c988 100644 --- a/docs/book.toml +++ b/docs/book.toml @@ -4,7 +4,6 @@ authors = [ "Amaan Qureshi ", ] language = "en" -multilingual = false src = "src" title = "Tree-sitter" diff --git a/docs/src/3-syntax-highlighting.md b/docs/src/3-syntax-highlighting.md index ca42c047..c6356fbb 100644 --- a/docs/src/3-syntax-highlighting.md +++ b/docs/src/3-syntax-highlighting.md @@ -73,9 +73,8 @@ The behaviors of these three files are described in the next section. ## Queries -Tree-sitter's syntax highlighting system is based on *tree queries*, which are a general system for pattern-matching on Tree-sitter's -syntax trees. See [this section][pattern matching] of the documentation for more information -about tree queries. +Tree-sitter's syntax highlighting system is based on *tree queries*, which are a general system for pattern-matching on +Tree-sitter's syntax trees. See [this section][pattern matching] of the documentation for more information about tree queries. Syntax highlighting is controlled by *three* different types of query files that are usually included in the `queries` folder. The default names for the query files use the `.scm` file. We chose this extension because it commonly used for files written @@ -433,7 +432,7 @@ not the `keyword` class. ``` [erb]: https://en.wikipedia.org/wiki/ERuby -[highlight crate]: https://github.com/tree-sitter/tree-sitter/tree/master/highlight +[highlight crate]: https://github.com/tree-sitter/tree-sitter/tree/master/crates/highlight [init-config]: ./cli/init-config.md [init]: ./cli/init.md#structure-of-tree-sitterjson [js grammar]: https://github.com/tree-sitter/tree-sitter-javascript diff --git a/docs/src/4-code-navigation.md b/docs/src/4-code-navigation.md index 46d60307..02a9fa4d 100644 --- a/docs/src/4-code-navigation.md +++ b/docs/src/4-code-navigation.md @@ -3,7 +3,8 @@ Tree-sitter can be used in conjunction with its [query language][query language] as a part of code navigation systems. An example of such a system can be seen in the `tree-sitter tags` command, which emits a textual dump of the interesting syntactic nodes in its file argument. A notable application of this is GitHub's support for [search-based code navigation][gh search]. -This document exists to describe how to integrate with such systems, and how to extend this functionality to any language with a Tree-sitter grammar. +This document exists to describe how to integrate with such systems, and how to extend this functionality to any language +with a Tree-sitter grammar. ## Tagging and captures @@ -12,9 +13,9 @@ entities. Having found them, you use a syntax capture to label the entity and it The essence of a given tag lies in two pieces of data: the _role_ of the entity that is matched (i.e. whether it is a definition or a reference) and the _kind_ of that entity, which describes how the entity is used -(i.e. whether it's a class definition, function call, variable reference, and so on). Our convention is to use a syntax capture -following the `@role.kind` capture name format, and another inner capture, always called `@name`, that pulls out the name -of a given identifier. +(i.e. whether it's a class definition, function call, variable reference, and so on). Our convention is to use a syntax +capture following the `@role.kind` capture name format, and another inner capture, always called `@name`, that pulls out +the name of a given identifier. You may optionally include a capture named `@doc` to bind a docstring. For convenience purposes, the tagging system provides two built-in functions, `#select-adjacent!` and `#strip!` that are convenient for removing comment syntax from a docstring. diff --git a/docs/src/5-implementation.md b/docs/src/5-implementation.md index 987a91ff..36963d8e 100644 --- a/docs/src/5-implementation.md +++ b/docs/src/5-implementation.md @@ -51,10 +51,10 @@ WIP [crates]: https://crates.io [npm]: https://npmjs.com [gh]: https://github.com/tree-sitter/tree-sitter/releases/latest -[src]: https://github.com/tree-sitter/tree-sitter/tree/master/cli/src +[src]: https://github.com/tree-sitter/tree-sitter/tree/master/crates/cli/src [schema]: https://tree-sitter.github.io/tree-sitter/assets/schemas/grammar.schema.json -[parse grammar]: https://github.com/tree-sitter/tree-sitter/blob/master/cli/generate/src/parse_grammar.rs +[parse grammar]: https://github.com/tree-sitter/tree-sitter/blob/master/crates/generate/src/parse_grammar.rs [enum]: https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html -[rules.rs]: https://github.com/tree-sitter/tree-sitter/blob/master/cli/generate/src/rules.rs -[prepare grammar]: https://github.com/tree-sitter/tree-sitter/tree/master/cli/generate/src/prepare_grammar +[rules.rs]: https://github.com/tree-sitter/tree-sitter/blob/master/crates/generate/src/rules.rs +[prepare grammar]: https://github.com/tree-sitter/tree-sitter/tree/master/crates/generate/src/prepare_grammar [symbols]: https://en.wikipedia.org/wiki/Terminal_and_nonterminal_symbols diff --git a/docs/src/6-contributing.md b/docs/src/6-contributing.md index 001d6337..0fad6581 100644 --- a/docs/src/6-contributing.md +++ b/docs/src/6-contributing.md @@ -51,7 +51,7 @@ cargo install --path crates/cli If you're going to be in a fast iteration cycle and would like the CLI to build faster, you can use the `release-dev` profile: ```sh -cargo build --release --profile release-dev +cargo build --profile release-dev # or cargo install --path crates/cli --profile release-dev ``` @@ -83,6 +83,19 @@ cargo xtask generate-fixtures --wasm cargo xtask test-wasm ``` +#### Wasm Stdlib + +The tree-sitter Wasm stdlib can be built via xtask: + +```sh +cargo xtask build-wasm-stdlib +``` + +This command looks for the [Wasi SDK][wasi_sdk] indicated by the `TREE_SITTER_WASI_SDK_PATH` +environment variable. If you don't have the binary, it can be downloaded from wasi-sdk's [releases][wasi-sdk-releases] +page. Note that any changes to `crates/language/wasm/**` requires rebuilding the tree-sitter Wasm stdlib via +`cargo xtask build-wasm-stdlib`. + ### Debugging The test script has a number of useful flags. You can list them all by running `cargo xtask test -h`. @@ -220,4 +233,6 @@ and the tree-sitter module is fetched from [here][js url]. This, along with the [pypi]: https://pypi.org [rust]: https://rustup.rs [ts repo]: https://github.com/tree-sitter/tree-sitter +[wasi_sdk]: https://github.com/WebAssembly/wasi-sdk +[wasi-sdk-releases]: https://github.com/WebAssembly/wasi-sdk/releases [web-ts]: https://www.npmjs.com/package/web-tree-sitter diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 6e6eed94..231085ae 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -15,6 +15,7 @@ - [Predicates and Directives](./using-parsers/queries/3-predicates-and-directives.md) - [API](./using-parsers/queries/4-api.md) - [Static Node Types](./using-parsers/6-static-node-types.md) + - [ABI versions](./using-parsers/7-abi-versions.md) - [Creating Parsers](./creating-parsers/index.md) - [Getting Started](./creating-parsers/1-getting-started.md) - [The Grammar DSL](./creating-parsers/2-the-grammar-dsl.md) diff --git a/docs/src/assets/js/playground.js b/docs/src/assets/js/playground.js index 595fe565..ef65c371 100644 --- a/docs/src/assets/js/playground.js +++ b/docs/src/assets/js/playground.js @@ -61,7 +61,7 @@ function initializeCustomSelect({ initialValue = null, addListeners = false }) { } window.initializePlayground = async (opts) => { - const { Parser, Language } = window.TreeSitter; + const { Parser, Language, Query } = window.TreeSitter; const { local } = opts; if (local) { @@ -146,8 +146,9 @@ window.initializePlayground = async (opts) => { }); queryEditor.on('keydown', (_, event) => { - if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') { - event.stopPropagation(); // Prevent mdBook from going back/forward + const key = event.key; + if (key === 'ArrowLeft' || key === 'ArrowRight' || key === '?') { + event.stopPropagation(); // Prevent mdBook from going back/forward, or showing help } }); @@ -356,11 +357,10 @@ window.initializePlayground = async (opts) => { marks.forEach((m) => m.clear()); if (tree && query) { - const captures = query.captures( - tree.rootNode, - { row: startRow, column: 0 }, - { row: endRow, column: 0 }, - ); + const captures = query.captures(tree.rootNode, { + startPosition: { row: startRow, column: 0 }, + endPosition: { row: endRow, column: 0 }, + }); let lastNodeId; for (const { name, node } of captures) { if (node.id === lastNodeId) continue; @@ -409,7 +409,7 @@ window.initializePlayground = async (opts) => { const queryText = queryEditor.getValue(); try { - query = parser.language.query(queryText); + query = new Query(parser.language, queryText); let match; let row = 0; diff --git a/docs/src/assets/schemas/node-types.schema.json b/docs/src/assets/schemas/node-types.schema.json new file mode 100644 index 00000000..7ea8a5af --- /dev/null +++ b/docs/src/assets/schemas/node-types.schema.json @@ -0,0 +1,108 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Tree-sitter node types specification", + "type": "array", + "items": { + "$ref": "#/definitions/NodeInfo" + }, + "definitions": { + "NodeInfo": { + "type": "object", + "required": [ + "type", + "named" + ], + "properties": { + "type": { + "type": "string" + }, + "named": { + "type": "boolean" + }, + "root": { + "type": "boolean", + "default": false + }, + "extra": { + "type": "boolean", + "default": false + }, + "fields": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/FieldInfo" + } + }, + "children": { + "$ref": "#/definitions/FieldInfo" + }, + "subtypes": { + "type": "array", + "items": { + "$ref": "#/definitions/NodeType" + } + } + }, + "oneOf": [ + { + "description": "Regular node", + "properties": { + "subtypes": false + } + }, + { + "description": "Supertype node", + "required": [ + "subtypes" + ], + "properties": { + "children": false, + "fields": false + } + } + ] + }, + "NodeType": { + "type": "object", + "required": [ + "type", + "named" + ], + "properties": { + "type": { + "type": "string", + "description": "The kind of node type" + }, + "named": { + "type": "boolean", + "description": "Whether the node type is named" + } + } + }, + "FieldInfo": { + "type": "object", + "required": [ + "multiple", + "required", + "types" + ], + "properties": { + "multiple": { + "type": "boolean", + "default": false + }, + "required": { + "type": "boolean", + "default": true + }, + "types": { + "type": "array", + "default": [], + "items": { + "$ref": "#/definitions/NodeType" + } + } + } + } + } +} diff --git a/docs/src/assets/schemas/test-summary.schema.json b/docs/src/assets/schemas/test-summary.schema.json new file mode 100644 index 00000000..6211d60c --- /dev/null +++ b/docs/src/assets/schemas/test-summary.schema.json @@ -0,0 +1,247 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "TestSummary", + "description": "A stateful object used to collect results from running a grammar's test suite", + "type": "object", + "properties": { + "parse_results": { + "type": "array", + "items": { + "$ref": "#/$defs/TestResult" + } + }, + "parse_failures": { + "type": "array", + "items": { + "$ref": "#/$defs/TestFailure" + } + }, + "parse_stats": { + "$ref": "#/$defs/Stats" + }, + "highlight_results": { + "type": "array", + "items": { + "$ref": "#/$defs/TestResult" + } + }, + "tag_results": { + "type": "array", + "items": { + "$ref": "#/$defs/TestResult" + } + }, + "query_results": { + "type": "array", + "items": { + "$ref": "#/$defs/TestResult" + } + } + }, + "required": [ + "parse_results", + "parse_failures", + "parse_stats", + "highlight_results", + "tag_results", + "query_results" + ], + "$defs": { + "TestResult": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "type": "object", + "properties": { + "children": { + "type": "array", + "items": { + "$ref": "#/$defs/TestResult" + } + } + }, + "required": [ + "children" + ] + }, + { + "type": "object", + "properties": { + "outcome": { + "$ref": "#/$defs/TestOutcome" + }, + "parse_rate": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "test_num": { + "type": "integer", + "format": "uint", + "minimum": 0 + } + }, + "required": [ + "outcome", + "parse_rate", + "test_num" + ] + }, + { + "type": "object", + "properties": { + "outcome": { + "$ref": "#/$defs/TestOutcome" + }, + "test_num": { + "type": "integer", + "format": "uint", + "minimum": 0 + } + }, + "required": [ + "outcome", + "test_num" + ] + } + ] + }, + "TestOutcome": { + "oneOf": [ + { + "type": "string", + "enum": [ + "Passed", + "Failed", + "Updated", + "Skipped", + "Platform" + ] + }, + { + "type": "object", + "properties": { + "AssertionPassed": { + "type": "object", + "properties": { + "assertion_count": { + "type": "integer", + "format": "uint", + "minimum": 0 + } + }, + "required": [ + "assertion_count" + ] + } + }, + "required": [ + "AssertionPassed" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "AssertionFailed": { + "type": "object", + "properties": { + "error": { + "type": "string" + } + }, + "required": [ + "error" + ] + } + }, + "required": [ + "AssertionFailed" + ], + "additionalProperties": false + } + ] + }, + "TestFailure": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "actual": { + "type": "string" + }, + "expected": { + "type": "string" + }, + "is_cst": { + "type": "boolean" + } + }, + "required": [ + "name", + "actual", + "expected", + "is_cst" + ] + }, + "Stats": { + "type": "object", + "properties": { + "successful_parses": { + "type": "integer", + "format": "uint", + "minimum": 0 + }, + "total_parses": { + "type": "integer", + "format": "uint", + "minimum": 0 + }, + "total_bytes": { + "type": "integer", + "format": "uint", + "minimum": 0 + }, + "total_duration": { + "$ref": "#/$defs/Duration" + } + }, + "required": [ + "successful_parses", + "total_parses", + "total_bytes", + "total_duration" + ] + }, + "Duration": { + "type": "object", + "properties": { + "secs": { + "type": "integer", + "format": "uint64", + "minimum": 0 + }, + "nanos": { + "type": "integer", + "format": "uint32", + "minimum": 0 + } + }, + "required": [ + "secs", + "nanos" + ] + } + } +} \ No newline at end of file diff --git a/docs/src/cli/build.md b/docs/src/cli/build.md index 0ad4a922..44ee8271 100644 --- a/docs/src/cli/build.md +++ b/docs/src/cli/build.md @@ -18,7 +18,9 @@ will attempt to build the parser in the current working directory. ### `-w/--wasm` -Compile the parser as a Wasm module. +Compile the parser as a Wasm module. This command looks for the [Wasi SDK][wasi_sdk] indicated by the `TREE_SITTER_WASI_SDK_PATH` +environment variable. If you don't have the binary, the CLI will attempt to download it for you to `/tree-sitter/wasi-sdk/`, +where `` is resolved according to the [XDG base directory][XDG] or Window's [Known_Folder_Locations][Known_Folder]. ### `-o/--output` @@ -35,4 +37,9 @@ in the external scanner does so using their allocator. ### `-0/--debug` -Compile the parser with debug flags enabled. This is useful when debugging issues that require a debugger like `gdb` or `lldb`. +Compile the parser with debug flags enabled. This is useful when debugging issues that require a debugger like `gdb` or +`lldb`. + +[Known_Folder]: https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid +[wasi_sdk]: https://github.com/WebAssembly/wasi-sdk +[XDG]: https://specifications.freedesktop.org/basedir/latest/ diff --git a/docs/src/cli/dump-languages.md b/docs/src/cli/dump-languages.md index 1d1a6aaa..f29daa57 100644 --- a/docs/src/cli/dump-languages.md +++ b/docs/src/cli/dump-languages.md @@ -1,6 +1,8 @@ # `tree-sitter dump-languages` -The `dump-languages` command prints out a list of all the languages that the CLI knows about. This can be useful for debugging purposes, or for scripting. The paths to search comes from the config file's [`parser-directories`][parser-directories] object. +The `dump-languages` command prints out a list of all the languages that the CLI knows about. This can be useful for debugging +purposes, or for scripting. The paths to search comes from the config file's [`parser-directories`][parser-directories] +object. ```bash tree-sitter dump-languages [OPTIONS] # Aliases: langs @@ -10,6 +12,7 @@ tree-sitter dump-languages [OPTIONS] # Aliases: langs ### `--config-path` -The path to the configuration file. Ordinarily, the CLI will use the default location as explained in the [init-config](./init-config.md) command. This flag allows you to explicitly override that default, and use a config defined elsewhere. +The path to the configuration file. Ordinarily, the CLI will use the default location as explained in the [init-config](./init-config.md) +command. This flag allows you to explicitly override that default, and use a config defined elsewhere. [parser-directories]: ./init-config.md#parser-directories diff --git a/docs/src/cli/fuzz.md b/docs/src/cli/fuzz.md index 1f79bc00..7f97f9ba 100644 --- a/docs/src/cli/fuzz.md +++ b/docs/src/cli/fuzz.md @@ -17,6 +17,18 @@ A list of test names to skip fuzzing. The directory containing the parser. This is primarily useful in multi-language repositories. +### `-p/--grammar-path` + +The path to the directory containing the grammar. + +### `--lib-path` + +The path to the parser's dynamic library. This is used instead of the cached or automatically generated dynamic library. + +### `--lang-name` + +If `--lib-path` is used, the name of the language used to extract the library's language function + ### `--edits ` The maximum number of edits to perform. The default is 3. diff --git a/docs/src/cli/generate.md b/docs/src/cli/generate.md index 956d5629..df9111f0 100644 --- a/docs/src/cli/generate.md +++ b/docs/src/cli/generate.md @@ -1,53 +1,47 @@ # `tree-sitter generate` -The most important command you'll use is `tree-sitter generate`. This command reads the `grammar.js` file in your current -working directory and creates a file called `src/parser.c`, which implements the parser. After making changes to your grammar, -just run `tree-sitter generate` again. +The most important command for grammar development is `tree-sitter generate`, which reads the grammar in structured form +and outputs C files that can be compiled into a shared or static library (e.g., using the [`build`](./build.md) command). ```bash tree-sitter generate [OPTIONS] [GRAMMAR_PATH] # Aliases: gen, g ``` -The grammar path argument allows you to specify a path to a `grammar.js` JavaScript file, or `grammar.json` JSON file. -In case your `grammar.js` file is in a non-standard path, you can specify it yourself. But, if you are using a parser -where `grammar.json` was already generated, or it was hand-written, you can tell the CLI to generate the parser *based* -on this JSON file. This avoids relying on a JavaScript file and avoids the dependency on a JavaScript runtime. +The optional `GRAMMAR_PATH` argument should point to the structured grammar, in one of two forms: +- `grammar.js` a (ESM or CJS) JavaScript file; if the argument is omitted, it defaults to `./grammar.js`. +- `grammar.json` a structured representation of the grammar that is created as a byproduct of `generate`; this can be used +to regenerate a missing `parser.c` without requiring a JavaScript runtime (useful when distributing parsers to consumers). If there is an ambiguity or *local ambiguity* in your grammar, Tree-sitter will detect it during parser generation, and -it will exit with a `Unresolved conflict` error message. To learn more about conflicts and how to handle them, check out +it will exit with a `Unresolved conflict` error message. To learn more about conflicts and how to handle them, see the section on [`Structuring Rules Well`](../creating-parsers/3-writing-the-grammar.md#structuring-rules-well) in the user guide. +## Generated files + +- `src/parser.c` implements the parser logic specified in the grammar. +- `src/tree_sitter/parser.h` provides basic C definitions that are used in the generated `parser.c` file. +- `src/tree_sitter/alloc.h` provides memory allocation macros that can be used in an external scanner. +- `src/tree_sitter/array.h` provides array macros that can be used in an external scanner. +- `src/grammar.json` contains a structured representation of the grammar; can be used to regenerate the parser without having +to re-evaluate the `grammar.js`. +- `src/node-types.json` provides type information about individual syntax nodes; see the section on [`Static Node Types`](../using-parsers/6-static-node-types.md). + + ## Options ### `-l/--log` -Print the log of the parser generation process. This is really only useful if you know what you're doing, or are investigating -a bug in the CLI itself. It logs info such as what tokens are included in the error recovery state, -what keywords were extracted, what states were split and why, and the entry point state. +Print the log of the parser generation process. This includes information such as what tokens are included in the error +recovery state, what keywords were extracted, what states were split and why, and the entry point state. ### `--abi ` The ABI to use for parser generation. The default is ABI 15, with ABI 14 being a supported target. -### `--stage` +### `--no-parser` -What generated files to emit. Possible values: - -- `json`: Generate `grammar.json` and `node-types.json` -- `parser` (default): Generate `parser.c` and related files. -- `lib`: Compile to a library (equivalent of the deprecated `--build` option) - -### `-0/--debug-build` - -Compile the parser with debug flags enabled. This is useful when debugging issues that require a debugger like `gdb` or `lldb`. - -### `--libdir ` - -The directory to place the compiled parser(s) in. -On Unix systems, the default path is `$XDG_CACHE_HOME/tree-sitter` if `$XDG_CACHE_HOME` is set, -otherwise `$HOME/.config/tree-sitter` is used. On Windows, the default path is `%LOCALAPPDATA%\tree-sitter` if available, -otherwise `$HOME\AppData\Local\tree-sitter` is used. +Only generate `grammar.json` and `node-types.json` ### `-o/--output` @@ -59,13 +53,19 @@ Print the overview of states from the given rule. This is useful for debugging a item sets for all given states in a given rule. To solely view state count numbers for rules, pass in `-` for the rule argument. To view the overview of states for every rule, pass in `*` for the rule argument. -### `--json` +### `--json-summary` Report conflicts in a JSON format. ### `--js-runtime ` The path to the JavaScript runtime executable to use when generating the parser. The default is `node`. -Note that you can also set this with `TREE_SITTER_JS_RUNTIME`. Starting from version 0.26.0, you can -also pass in `native` to use the native QuickJS runtime that comes bundled with the CLI. This avoids -the dependency on a JavaScript runtime entirely. +Note that you can also set this with `TREE_SITTER_JS_RUNTIME`. Starting from version 0.26, you can +also pass in `native` to use the experimental native QuickJS runtime that comes bundled with the CLI. +This avoids the dependency on a JavaScript runtime entirely. The native QuickJS runtime is compatible +with ESM as well as with CommonJS in strict mode. If your grammar depends on `npm` to install dependencies such as base +grammars, the native runtime can be used *after* running `npm install`. + +### `--disable-optimization` + +Disable optimizations when generating the parser. Currently, this only affects the merging of compatible parse states. diff --git a/docs/src/cli/highlight.md b/docs/src/cli/highlight.md index 1378e0f6..1a4ed1f6 100644 --- a/docs/src/cli/highlight.md +++ b/docs/src/cli/highlight.md @@ -52,8 +52,13 @@ The path to the directory containing the grammar. ### `--config-path ` -The path to an alternative configuration (`config.json`) file. See [the init-config command](./init-config.md) for more information. +The path to an alternative configuration (`config.json`) file. See [the init-config command](./init-config.md) for more +information. ### `-n/--test-number ` Highlight the contents of a specific test. + +### `-r/--rebuild` + +Force a rebuild of the parser before running the fuzzer. diff --git a/docs/src/cli/index.md b/docs/src/cli/index.md index 7c982b40..042c0196 100644 --- a/docs/src/cli/index.md +++ b/docs/src/cli/index.md @@ -1,4 +1,8 @@ # CLI Overview -Let's go over all of the functionality of the `tree-sitter` command line interface. -Once you feel that you have enough of a grasp on the CLI, you can move onto the grammar authoring section to learn more about writing your own parser. +The `tree-sitter` command-line interface is used to create, manage, test, and build tree-sitter parsers. It is controlled +by + +- a personal `tree-sitter/config.json` config file generated by [`tree-sitter init-config`](./init-config.md) +- a parser `tree-sitter.json` config file generated by [`tree-sitter init`](./init.md). + diff --git a/docs/src/cli/init.md b/docs/src/cli/init.md index 2d7d6847..568bc98f 100644 --- a/docs/src/cli/init.md +++ b/docs/src/cli/init.md @@ -8,30 +8,94 @@ we recommend using git for version control of your grammar. tree-sitter init [OPTIONS] # Aliases: i ``` -## Options +## Generated files -### `--update` +### Required files -Update outdated generated files, if needed. +The following required files are always created if missing: -### `-p/--grammar-path ` +- `tree-sitter.json` - The main configuration file that determines how `tree-sitter` interacts with the grammar. If missing, +the `init` command will prompt the user for the required fields. See [below](./init.md#structure-of-tree-sitterjson) for +the full documentation of the structure of this file. +- `package.json` - The `npm` manifest for the parser. This file is required for some `tree-sitter` subcommands, and if the +grammar has dependencies (e.g., another published base grammar that this grammar extends). +- `grammar.js` - An empty template for the main grammar file; see [the section on creating parsers](../2-creating-parser). -The path to the directory containing the grammar. +### Language bindings + +Language bindings are files that allow your parser to be directly used by projects written in the respective language. +The following bindings are created if enabled in `tree-sitter.json`: + +#### C/C++ + +- `Makefile` — This file tells [`make`][make] how to compile your language. +- `CMakeLists.txt` — This file tells [`cmake`][cmake] how to compile your language. +- `bindings/c/tree_sitter/tree-sitter-language.h` — This file provides the C interface of your language. +- `bindings/c/tree-sitter-language.pc` — This file provides [pkg-config][pkg-config] metadata about your language's C library. + +#### Go + +- `go.mod` — This file is the manifest of the Go module. +- `bindings/go/binding.go` — This file wraps your language in a Go module. +- `bindings/go/binding_test.go` — This file contains a test for the Go package. + +#### Node + +- `binding.gyp` — This file tells Node.js how to compile your language. +- `bindings/node/binding.cc` — This file wraps your language in a JavaScript module for Node.js. +- `bindings/node/index.js` — This is the file that Node.js initially loads when using your language. +- `bindings/node/index.d.ts` — This file provides type hints for your parser when used in TypeScript. +- `bindings/node/binding_test.js` — This file contains a test for the Node.js package. + +#### Java + +- `pom.xml` - This file is the manifest of the Maven package. +- `bindings/java/main/namespace/language/TreeSitterLanguage.java` - This file wraps your language in a Java class. +- `bindings/java/test/TreeSitterLanguageTest.java` - This file contains a test for the Java package. + +#### Python + +- `pyproject.toml` — This file is the manifest of the Python package. +- `setup.py` — This file tells Python how to compile your language. +- `bindings/python/tree_sitter_language/binding.c` — This file wraps your language in a Python module. +- `bindings/python/tree_sitter_language/__init__.py` — This file tells Python how to load your language. +- `bindings/python/tree_sitter_language/__init__.pyi` — This file provides type hints for your parser when used in Python. +- `bindings/python/tree_sitter_language/py.typed` — This file provides type hints for your parser when used in Python. +- `bindings/python/tests/test_binding.py` — This file contains a test for the Python package. + +#### Rust + +- `Cargo.toml` — This file is the manifest of the Rust package. +- `bindings/rust/build.rs` — This file tells Rust how to compile your language. +- `bindings/rust/lib.rs` — This file wraps your language in a Rust crate when used in Rust. + +#### Swift + +- `Package.swift` — This file tells Swift how to compile your language. +- `bindings/swift/TreeSitterLanguage/language.h` — This file wraps your language in a Swift module when used in Swift. +- `bindings/swift/TreeSitterLanguageTests/TreeSitterLanguageTests.swift` — This file contains a test for the Swift package. + +#### Zig + +- `build.zig` - This file tells Zig how to compile your language. +- `build.zig.zon` - This file is the manifest of the Zig package. +- `bindings/zig/root.zig` - This file wraps your language in a Zig module. +- `bindings/zig/test.zig` - This file contains a test for the Zig package. + +### Additional files + +In addition, the following files are created that aim to improve the development experience: + +- `.editorconfig` — This file tells your editor how to format your code. More information about this file can be found [here][editorconfig]. +- `.gitattributes` — This file tells Git how to handle line endings and tells GitHub which files are generated. +- `.gitignore` — This file tells Git which files to ignore when committing changes. ## Structure of `tree-sitter.json` -The main file of interest for users to configure is `tree-sitter.json`, which tells the CLI information about your grammar, -such as the location of queries. - ### The `grammars` field This field is an array of objects, though you typically only need one object in this array unless your repo has -multiple grammars (for example, `Typescript` and `TSX`). - -### Example - -Typically, the objects in the `"tree-sitter"` array only needs to specify a few keys: - +multiple grammars (for example, `Typescript` and `TSX`), e.g., ```json { "tree-sitter": [ @@ -49,7 +113,7 @@ Typically, the objects in the `"tree-sitter"` array only needs to specify a few } ``` -#### Basic Fields +#### Basic fields These keys specify basic information about the parser: @@ -65,12 +129,12 @@ parser to files that should be checked for modifications during recompilation. This is useful during development to have changes to other files besides scanner.c be picked up by the cli. -#### Language Detection +#### Language detection These keys help to decide whether the language applies to a given file: -- `file-types` — An array of filename suffix strings. The grammar will be used for files whose names end with one of -these suffixes. Note that the suffix may match an *entire* filename. +- `file-types` — An array of filename suffix strings (not including the dot). The grammar will be used for files whose names +end with one of these suffixes. Note that the suffix may match an *entire* filename. - `first-line-regex` — A regex pattern that will be tested against the first line of a file to determine whether this language applies to the file. If present, this regex will be used for any file whose @@ -85,14 +149,14 @@ no `content-regex` will be preferred over this one. should be used for a potential *language injection* site. Language injection is described in more detail in [the relevant section](../3-syntax-highlighting.md#language-injection). -#### Query Paths +#### Query paths These keys specify relative paths from the directory containing `tree-sitter.json` to the files that control syntax highlighting: - `highlights` — Path to a *highlight query*. Default: `queries/highlights.scm` - `locals` — Path to a *local variable query*. Default: `queries/locals.scm`. - `injections` — Path to an *injection query*. Default: `queries/injections.scm`. -- `tags` — Path to an *tag query*. Default: `queries/tags.scm`. +- `tags` — Path to a *tag query*. Default: `queries/tags.scm`. ### The `metadata` field @@ -115,74 +179,25 @@ Each key is a language name, and the value is a boolean. - `c` (default: `true`) - `go` (default: `true`) - `java` (default: `false`) -- `kotlin` (default: `false`) - `node` (default: `true`) - `python` (default: `true`) - `rust` (default: `true`) - `swift` (default: `false`) +- `zig` (default: `false`) -## Binding Files +## Options -When you run `tree-sitter init`, the CLI will also generate a number of files in your repository that allow for your parser -to be used from different language. Here is a list of these bindings files that are generated, and what their purpose is: +### `-u/--update` -### C/C++ +Update outdated generated files, if possible. -- `Makefile` — This file tells [`make`][make] how to compile your language. -- `CMakeLists.txt` — This file tells [`cmake`][cmake] how to compile your language. -- `bindings/c/tree_sitter/tree-sitter-language.h` — This file provides the C interface of your language. -- `bindings/c/tree-sitter-language.pc` — This file provides [pkg-config][pkg-config] metadata about your language's C library. -- `src/tree_sitter/parser.h` — This file provides some basic C definitions that are used in your generated `parser.c` file. -- `src/tree_sitter/alloc.h` — This file provides some memory allocation macros that are to be used in your external scanner, -if you have one. -- `src/tree_sitter/array.h` — This file provides some array macros that are to be used in your external scanner, -if you have one. +**Note:** Existing files that may have been edited manually are _not_ updated in general. To force an update to such files, +remove them and call `tree-sitter init -u` again. -### Go +### `-p/--grammar-path ` -- `go.mod` — This file is the manifest of the Go module. -- `bindings/go/binding.go` — This file wraps your language in a Go module. -- `bindings/go/binding_test.go` — This file contains a test for the Go package. +The path to the directory containing the grammar. -### Node - -- `binding.gyp` — This file tells Node.js how to compile your language. -- `package.json` — This file is the manifest of the Node.js package. -- `bindings/node/binding.cc` — This file wraps your language in a JavaScript module for Node.js. -- `bindings/node/index.js` — This is the file that Node.js initially loads when using your language. -- `bindings/node/index.d.ts` — This file provides type hints for your parser when used in TypeScript. -- `bindings/node/binding_test.js` — This file contains a test for the Node.js package. - -### Python - -- `pyproject.toml` — This file is the manifest of the Python package. -- `setup.py` — This file tells Python how to compile your language. -- `bindings/python/tree_sitter_language/binding.c` — This file wraps your language in a Python module. -- `bindings/python/tree_sitter_language/__init__.py` — This file tells Python how to load your language. - `bindings/python/tree_sitter_language/__init__.pyi` — This file provides type hints for your parser when used in Python. -- `bindings/python/tree_sitter_language/py.typed` — This file provides type hints for your parser when used in Python. -- `bindings/python/tests/test_binding.py` — This file contains a test for the Python package. - -### Rust - -- `Cargo.toml` — This file is the manifest of the Rust package. -- `bindings/rust/lib.rs` — This file wraps your language in a Rust crate when used in Rust. -- `bindings/rust/build.rs` — This file wraps the building process for the Rust crate. - -### Swift - -- `Package.swift` — This file tells Swift how to compile your language. -- `bindings/swift/TreeSitterLanguage/language.h` — This file wraps your language in a Swift module when used in Swift. -- `bindings/swift/TreeSitterLanguageTests/TreeSitterLanguageTests.swift` — This file contains a test for the Swift package. - -### Additional Files - -Additionally, there's a few other files that are generated when you run `tree-sitter init`, -that aim to improve the development experience: - -- `.editorconfig` — This file tells your editor how to format your code. More information about this file can be found [here][editorconfig] -- `.gitattributes` — This file tells Git how to handle line endings, and tells GitHub what files are generated. -- `.gitignore` — This file tells Git what files to ignore when committing changes. [cmake]: https://cmake.org/cmake/help/latest [editorconfig]: https://editorconfig.org diff --git a/docs/src/cli/parse.md b/docs/src/cli/parse.md index 9f76b550..2e9bc835 100644 --- a/docs/src/cli/parse.md +++ b/docs/src/cli/parse.md @@ -1,8 +1,8 @@ # `tree-sitter parse` The `parse` command parses source files using a Tree-sitter parser. You can pass any number of file paths and glob patterns -to `tree-sitter parse`, and it will parse all the given files. The command will exit with a non-zero status code if any -parse errors occurred. +to `tree-sitter parse`, and it will parse all the given files. If no paths are provided, input will be parsed from stdin. +The command will exit with a non-zero status code if any parse errors occurred. ```bash tree-sitter parse [OPTIONS] [PATHS]... # Aliases: p @@ -18,6 +18,14 @@ The path to a file that contains paths to source files to parse. The path to the directory containing the grammar. +### `-l/--lib-path` + +The path to the parser's dynamic library. This is used instead of the cached or automatically generated dynamic library. + +### `--lang-name` + +If `--lib-path` is used, the name of the language used to extract the library's language function + ### `--scope ` The language scope to use for parsing. This is useful when the language is ambiguous. @@ -37,7 +45,7 @@ The graphs are constructed with [graphviz dot][dot], and the output is written t ### `--wasm` -Compile and run the parser as a Wasm module. +Compile and run the parser as a Wasm module (only if the tree-sitter CLI was built with `--features=wasm`). ### `--dot` @@ -70,7 +78,8 @@ Suppress main output. ### `--edits ...` -Apply edits after parsing the file. Edits are in the form of `row,col|position delcount insert_text` where row and col, or position are 0-indexed. +Apply edits after parsing the file. Edits are in the form of `row,col|position delcount insert_text` where row and col, +or position are 0-indexed. ### `--encoding ` @@ -81,13 +90,14 @@ in `UTF-16BE` or `UTF-16LE`. If no `BOM` is present, `UTF-8` is the default. One When using the `--debug-graph` option, open the log file in the default browser. -### `-j/--json` +### `-j/--json-summary` Output parsing results in a JSON format. ### `--config-path ` -The path to an alternative configuration (`config.json`) file. See [the init-config command](./init-config.md) for more information. +The path to an alternative configuration (`config.json`) file. See [the init-config command](./init-config.md) for more +information. ### `-n/--test-number ` diff --git a/docs/src/cli/playground.md b/docs/src/cli/playground.md index 0dbff469..c0bfb495 100644 --- a/docs/src/cli/playground.md +++ b/docs/src/cli/playground.md @@ -7,16 +7,12 @@ tree-sitter playground [OPTIONS] # Aliases: play, pg, web-ui ``` ```admonish note -For this to work, you must have already built the parser as a Wasm module. This can be done with the [`build`](./build.md) subcommand -(`tree-sitter build --wasm`). +For this to work, you must have already built the parser as a Wasm module. This can be done with the [`build`](./build.md) +subcommand (`tree-sitter build --wasm`). ``` ## Options -### `-e/--export ` - -Export static playground files to the specified directory instead of serving them. - ### `-q/--quiet` Don't automatically open the playground in the default browser. @@ -24,3 +20,7 @@ Don't automatically open the playground in the default browser. ### `--grammar-path ` The path to the directory containing the grammar and wasm files. + +### `-e/--export ` + +Export static playground files to the specified directory instead of serving them. diff --git a/docs/src/cli/query.md b/docs/src/cli/query.md index ed96aa51..fbd6dafd 100644 --- a/docs/src/cli/query.md +++ b/docs/src/cli/query.md @@ -12,6 +12,14 @@ tree-sitter query [OPTIONS] [PATHS]... # Aliases: q The path to the directory containing the grammar. +### `--lib-path` + +The path to the parser's dynamic library. This is used instead of the cached or automatically generated dynamic library. + +### `--lang-name` + +If `--lib-path` is used, the name of the language used to extract the library's language function + ### `-t/--time` Print the time taken to execute the query on the file. @@ -28,10 +36,20 @@ The path to a file that contains paths to source files in which the query will b The range of byte offsets in which the query will be executed. The format is `start_byte:end_byte`. +### `--containing-byte-range ` + +The range of byte offsets in which the query will be executed. Only the matches that are fully contained within the provided +byte range will be returned. + ### `--row-range ` The range of rows in which the query will be executed. The format is `start_row:end_row`. +### `--containing-row-range ` + +The range of rows in which the query will be executed. Only the matches that are fully contained within the provided row +range will be returned. + ### `--scope ` The language scope to use for parsing and querying. This is useful when the language is ambiguous. @@ -46,8 +64,13 @@ Whether to run query tests or not. ### `--config-path ` -The path to an alternative configuration (`config.json`) file. See [the init-config command](./init-config.md) for more information. +The path to an alternative configuration (`config.json`) file. See [the init-config command](./init-config.md) for more +information. ### `-n/--test-number ` Query the contents of a specific test. + +### `-r/--rebuild` + +Force a rebuild of the parser before executing the query. diff --git a/docs/src/cli/tags.md b/docs/src/cli/tags.md index 80ee1baa..8275237e 100644 --- a/docs/src/cli/tags.md +++ b/docs/src/cli/tags.md @@ -31,8 +31,13 @@ The path to the directory containing the grammar. ### `--config-path ` -The path to an alternative configuration (`config.json`) file. See [the init-config command](./init-config.md) for more information. +The path to an alternative configuration (`config.json`) file. See [the init-config command](./init-config.md) for more +information. ### `-n/--test-number ` Generate tags from the contents of a specific test. + +### `-r/--rebuild` + +Force a rebuild of the parser before running the tags. diff --git a/docs/src/cli/test.md b/docs/src/cli/test.md index c1724745..7e662f60 100644 --- a/docs/src/cli/test.md +++ b/docs/src/cli/test.md @@ -24,6 +24,14 @@ Only run tests from the given filename in the corpus. The path to the directory containing the grammar. +### `--lib-path` + +The path to the parser's dynamic library. This is used instead of the cached or automatically generated dynamic library. + +### `--lang-name` + +If `--lib-path` is used, the name of the language used to extract the library's language function + ### `-u/--update` Update the expected output of tests. @@ -47,7 +55,7 @@ The graphs are constructed with [graphviz dot][dot], and the output is written t ### `--wasm` -Compile and run the parser as a Wasm module. +Compile and run the parser as a Wasm module (only if the tree-sitter CLI was built with `--features=wasm`). ### `--open-log` @@ -55,7 +63,8 @@ When using the `--debug-graph` option, open the log file in the default browser. ### `--config-path ` -The path to an alternative configuration (`config.json`) file. See [the init-config command](./init-config.md) for more information. +The path to an alternative configuration (`config.json`) file. See [the init-config command](./init-config.md) for more +information. ### `--show-fields` @@ -78,3 +87,7 @@ Force a rebuild of the parser before running tests. ### `--overview-only` Only show the overview of the test results, and not the diff. + +### `--json-summary` + +Output the test summary in a JSON format. diff --git a/docs/src/cli/version.md b/docs/src/cli/version.md index e8f7a840..39cda84a 100644 --- a/docs/src/cli/version.md +++ b/docs/src/cli/version.md @@ -25,11 +25,9 @@ tree-sitter version --bump minor # minor bump tree-sitter version --bump major # major bump ``` -As a grammar author, you should keep the version of your grammar in sync across -different bindings. However, doing so manually is error-prone and tedious, so -this command takes care of the burden. If you are using a version control system, -it is recommended to commit the changes made by this command, and to tag the -commit with the new version. +As a grammar author, you should keep the version of your grammar in sync across different bindings. However, doing so manually +is error-prone and tedious, so this command takes care of the burden. If you are using a version control system, it is recommended +to commit the changes made by this command, and to tag the commit with the new version. To print the current version without bumping it, use: @@ -37,8 +35,21 @@ To print the current version without bumping it, use: tree-sitter version ``` +Note that some of the binding updates require access to external tooling: + +* Updating Cargo.toml and Cargo.lock bindings requires that `cargo` is installed. +* Updating package-lock.json requires that `npm` is installed. + ## Options ### `-p/--grammar-path ` The path to the directory containing the grammar. + +### `--bump` + +Automatically bump the version. Possible values are: + +- `patch`: Bump the patch version. +- `minor`: Bump the minor version. +- `major`: Bump the major version. diff --git a/docs/src/creating-parsers/1-getting-started.md b/docs/src/creating-parsers/1-getting-started.md index 92159f4a..5095eb75 100644 --- a/docs/src/creating-parsers/1-getting-started.md +++ b/docs/src/creating-parsers/1-getting-started.md @@ -131,6 +131,6 @@ To learn more about this command, check the [reference page](../cli/generate.md) [npm]: https://docs.npmjs.com [path-env]: https://en.wikipedia.org/wiki/PATH_(variable) [releases]: https://github.com/tree-sitter/tree-sitter/releases/latest -[tree-sitter-cli]: https://github.com/tree-sitter/tree-sitter/tree/master/cli +[tree-sitter-cli]: https://github.com/tree-sitter/tree-sitter/tree/master/crates/cli [triple-slash]: https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html [ts-check]: https://www.typescriptlang.org/docs/handbook/intro-to-js-ts.html diff --git a/docs/src/creating-parsers/2-the-grammar-dsl.md b/docs/src/creating-parsers/2-the-grammar-dsl.md index d210619b..0592c6bd 100644 --- a/docs/src/creating-parsers/2-the-grammar-dsl.md +++ b/docs/src/creating-parsers/2-the-grammar-dsl.md @@ -17,8 +17,8 @@ DSL through the `RustRegex` class. Simply pass your regex pattern as a string: ``` Unlike JavaScript's builtin `RegExp` class, which takes a pattern and flags as separate arguments, `RustRegex` only - accepts a single pattern string. While it doesn't support separate flags, you can use inline flags within the pattern itself. - For more details about Rust's regex syntax and capabilities, check out the [Rust regex documentation][rust regex]. + accepts a single pattern string. While it doesn't support separate flags, you can use inline flags within the pattern + itself. For more details about Rust's regex syntax and capabilities, check out the [Rust regex documentation][rust regex]. ```admonish note Only a subset of the Regex engine is actually supported. This is due to certain features like lookahead and lookaround @@ -50,10 +50,10 @@ The previous `repeat` rule is implemented in `repeat1` but is included because i - **Options : `optional(rule)`** — This function creates a rule that matches *zero or one* occurrence of a given rule. It is analogous to the `[x]` (square bracket) syntax in EBNF notation. -- **Precedence : `prec(number, rule)`** — This function marks the given rule with a numerical precedence, which will be used -to resolve [*LR(1) Conflicts*][lr-conflict] at parser-generation time. When two rules overlap in a way that represents either -a true ambiguity or a *local* ambiguity given one token of lookahead, Tree-sitter will try to resolve the conflict by matching -the rule with the higher precedence. The default precedence of all rules is zero. This works similarly to the +- **Precedence : `prec(number, rule)`** — This function marks the given rule with a numerical precedence, which will be +used to resolve [*LR(1) Conflicts*][lr-conflict] at parser-generation time. When two rules overlap in a way that represents +either a true ambiguity or a *local* ambiguity given one token of lookahead, Tree-sitter will try to resolve the conflict +by matching the rule with the higher precedence. The default precedence of all rules is zero. This works similarly to the [precedence directives][yacc-prec] in Yacc grammars. This function can also be used to assign lexical precedence to a given @@ -115,8 +115,8 @@ want to create syntax tree nodes at runtime. - **`conflicts`** — an array of arrays of rule names. Each inner array represents a set of rules that's involved in an *LR(1) conflict* that is *intended to exist* in the grammar. When these conflicts occur at runtime, Tree-sitter will use -the GLR algorithm to explore all the possible interpretations. If *multiple* parses end up succeeding, Tree-sitter will pick -the subtree whose corresponding rule has the highest total *dynamic precedence*. +the GLR algorithm to explore all the possible interpretations. If *multiple* parses end up succeeding, Tree-sitter will +pick the subtree whose corresponding rule has the highest total *dynamic precedence*. - **`externals`** — an array of token names which can be returned by an [*external scanner*][external-scanners]. External scanners allow you to write custom C code which runs during the lexing @@ -139,10 +139,10 @@ for more details. array of reserved rules. The reserved rule in the array must be a terminal token meaning it must be a string, regex, token, or terminal rule. The reserved rule must also exist and be used in the grammar, specifying arbitrary tokens will not work. The *first* reserved word set in the object is the global word set, meaning it applies to every rule in every parse state. -However, certain keywords are contextual, depending on the rule. For example, in JavaScript, keywords are typically not allowed -as ordinary variables, however, they *can* be used as a property name. In this situation, the `reserved` function would be used, -and the word set to pass in would be the name of the word set that is declared in the `reserved` object that corresponds to an -empty array, signifying *no* keywords are reserved. +However, certain keywords are contextual, depending on the rule. For example, in JavaScript, keywords are typically not +allowed as ordinary variables, however, they *can* be used as a property name. In this situation, the `reserved` function +would be used, and the word set to pass in would be the name of the word set that is declared in the `reserved` object that +corresponds to an empty array, signifying *no* keywords are reserved. [bison-dprec]: https://www.gnu.org/software/bison/manual/html_node/Generalized-LR-Parsing.html [ebnf]: https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form diff --git a/docs/src/creating-parsers/3-writing-the-grammar.md b/docs/src/creating-parsers/3-writing-the-grammar.md index ebd2f5a4..5048ff5b 100644 --- a/docs/src/creating-parsers/3-writing-the-grammar.md +++ b/docs/src/creating-parsers/3-writing-the-grammar.md @@ -1,7 +1,7 @@ # Writing the Grammar -Writing a grammar requires creativity. There are an infinite number of CFGs (context-free grammars) that can be used to describe -any given language. To produce a good Tree-sitter parser, you need to create a grammar with two important properties: +Writing a grammar requires creativity. There are an infinite number of CFGs (context-free grammars) that can be used to +describe any given language. To produce a good Tree-sitter parser, you need to create a grammar with two important properties: 1. **An intuitive structure** — Tree-sitter's output is a [concrete syntax tree][cst]; each node in the tree corresponds directly to a [terminal or non-terminal symbol][non-terminal] in the grammar. So to produce an easy-to-analyze tree, there @@ -139,8 +139,8 @@ instead. It's often useful to check your progress by trying to parse some real c ## Structuring Rules Well Imagine that you were just starting work on the [Tree-sitter JavaScript parser][tree-sitter-javascript]. Naively, you might -try to directly mirror the structure of the [ECMAScript Language Spec][ecmascript-spec]. To illustrate the problem with this -approach, consider the following line of code: +try to directly mirror the structure of the [ECMAScript Language Spec][ecmascript-spec]. To illustrate the problem with +this approach, consider the following line of code: ```js return x + y; @@ -181,16 +181,17 @@ which are unrelated to the actual code. ## Standard Rule Names -Tree-sitter places no restrictions on how to name the rules of your grammar. It can be helpful, however, to follow certain conventions -used by many other established grammars in the ecosystem. Some of these well-established patterns are listed below: +Tree-sitter places no restrictions on how to name the rules of your grammar. It can be helpful, however, to follow certain +conventions used by many other established grammars in the ecosystem. Some of these well-established patterns are listed +below: - `source_file`: Represents an entire source file, this rule is commonly used as the root node for a grammar, -- `expression`/`statement`: Used to represent statements and expressions for a given language. Commonly defined as a choice between several -more specific sub-expression/sub-statement rules. +- `expression`/`statement`: Used to represent statements and expressions for a given language. Commonly defined as a choice +between several more specific sub-expression/sub-statement rules. - `block`: Used as the parent node for block scopes, with its children representing the block's contents. - `type`: Represents the types of a language such as `int`, `char`, and `void`. -- `identifier`: Used for constructs like variable names, function arguments, and object fields; this rule is commonly used as the `word` -token in grammars. +- `identifier`: Used for constructs like variable names, function arguments, and object fields; this rule is commonly used +as the `word` token in grammars. - `string`: Used to represent `"string literals"`. - `comment`: Used to represent comments, this rule is commonly used as an `extra`. @@ -308,9 +309,9 @@ This is where `prec.left` and `prec.right` come into use. We want to select the ## Using Conflicts -Sometimes, conflicts are actually desirable. In our JavaScript grammar, expressions and patterns can create intentional ambiguity. -A construct like `[x, y]` could be legitimately parsed as both an array literal (like in `let a = [x, y]`) or as a destructuring -pattern (like in `let [x, y] = arr`). +Sometimes, conflicts are actually desirable. In our JavaScript grammar, expressions and patterns can create intentional +ambiguity. A construct like `[x, y]` could be legitimately parsed as both an array literal (like in `let a = [x, y]`) or +as a destructuring pattern (like in `let [x, y] = arr`). ```js export default grammar({ @@ -564,8 +565,8 @@ as mentioned in the previous page, is `token(prec(N, ...))`. ## Keywords Many languages have a set of _keyword_ tokens (e.g. `if`, `for`, `return`), as well as a more general token (e.g. `identifier`) -that matches any word, including many of the keyword strings. For example, JavaScript has a keyword `instanceof`, which is -used as a binary operator, like this: +that matches any word, including many of the keyword strings. For example, JavaScript has a keyword `instanceof`, which +is used as a binary operator, like this: ```js if (a instanceof Something) b(); diff --git a/docs/src/creating-parsers/4-external-scanners.md b/docs/src/creating-parsers/4-external-scanners.md index 7d63d04b..6c89e221 100644 --- a/docs/src/creating-parsers/4-external-scanners.md +++ b/docs/src/creating-parsers/4-external-scanners.md @@ -23,10 +23,7 @@ grammar({ }); ``` -Then, add another C source file to your project. Its path must be src/scanner.c for the CLI to recognize it. Be sure to add -this file to the sources section of your `binding.gyp` file so that it will be included when your project is compiled by -Node.js and uncomment the appropriate block in your bindings/rust/build.rs file so that it will be included in your Rust -crate. +Then, add another C source file to your project. Its path must be src/scanner.c for the CLI to recognize it. In this new source file, define an [`enum`][enum] type containing the names of all of your external tokens. The ordering of this enum must match the order in your grammar's `externals` array; the actual names do not matter. @@ -146,10 +143,10 @@ the second argument, the current character will be treated as whitespace; whites associated with tokens emitted by the external scanner. - **`void (*mark_end)(TSLexer *)`** — A function for marking the end of the recognized token. This allows matching tokens -that require multiple characters of lookahead. By default, (if you don't call `mark_end`), any character that you moved past -using the `advance` function will be included in the size of the token. But once you call `mark_end`, then any later calls -to `advance` will _not_ increase the size of the returned token. You can call `mark_end` multiple times to increase the size -of the token. +that require multiple characters of lookahead. By default, (if you don't call `mark_end`), any character that you moved +past using the `advance` function will be included in the size of the token. But once you call `mark_end`, then any later +calls to `advance` will _not_ increase the size of the returned token. You can call `mark_end` multiple times to increase +the size of the token. - **`uint32_t (*get_column)(TSLexer *)`** — A function for querying the current column position of the lexer. It returns the number of codepoints since the start of the current line. The codepoint position is recalculated on every call to this @@ -188,9 +185,9 @@ if (valid_symbols[INDENT] || valid_symbols[DEDENT]) { ### Allocator -Instead of using libc's `malloc`, `calloc`, `realloc`, and `free`, you should use the versions prefixed with `ts_` from `tree_sitter/alloc.h`. -These macros can allow a potential consumer to override the default allocator with their own implementation, but by default -will use the libc functions. +Instead of using libc's `malloc`, `calloc`, `realloc`, and `free`, you should use the versions prefixed with `ts_` from +`tree_sitter/alloc.h`. These macros can allow a potential consumer to override the default allocator with their own implementation, +but by default will use the libc functions. As a consumer of the tree-sitter core library as well as any parser libraries that might use allocations, you can enable overriding the default allocator and have it use the same one as the library allocator, of which you can set with `ts_set_allocator`. @@ -198,7 +195,8 @@ To enable this overriding in scanners, you must compile them with the `TREE_SITT the library must be linked into your final app dynamically, since it needs to resolve the internal functions at runtime. If you are compiling an executable binary that uses the core library, but want to load parsers dynamically at runtime, then you will have to use a special linker flag on Unix. For non-Darwin systems, that would be `--dynamic-list` and for Darwin -systems, that would be `-exported_symbols_list`. The CLI does exactly this, so you can use it as a reference (check out `cli/build.rs`). +systems, that would be `-exported_symbols_list`. The CLI does exactly this, so you can use it as a reference (check out +`cli/build.rs`). For example, assuming you wanted to allocate 100 bytes for your scanner, you'd do so like the following example: @@ -296,9 +294,10 @@ bool tree_sitter_my_language_external_scanner_scan( ## Other External Scanner Details -External scanners have priority over Tree-sitter's normal lexing process. When a token listed in the externals array is valid -at a given position, the external scanner is called first. This makes external scanners a powerful way to override Tree-sitter's -default lexing behavior, especially for cases that can't be handled with regular lexical rules, parsing, or dynamic precedence. +External scanners have priority over Tree-sitter's normal lexing process. When a token listed in the externals array is +valid at a given position, the external scanner is called first. This makes external scanners a powerful way to override +Tree-sitter's default lexing behavior, especially for cases that can't be handled with regular lexical rules, parsing, or +dynamic precedence. During error recovery, Tree-sitter's first step is to call the external scanner's scan function with all tokens marked as valid. Your scanner should detect and handle this case appropriately. One simple approach is to add an unused "sentinel" diff --git a/docs/src/creating-parsers/5-writing-tests.md b/docs/src/creating-parsers/5-writing-tests.md index 0d0aeb60..33155cca 100644 --- a/docs/src/creating-parsers/5-writing-tests.md +++ b/docs/src/creating-parsers/5-writing-tests.md @@ -39,8 +39,8 @@ It only shows the *named* nodes, as described in [this section][named-vs-anonymo ``` The expected output section can also *optionally* show the [*field names*][node-field-names] associated with each child - node. To include field names in your tests, you write a node's field name followed by a colon, before the node itself in - the S-expression: + node. To include field names in your tests, you write a node's field name followed by a colon, before the node itself + in the S-expression: ```query (source_file @@ -87,6 +87,11 @@ The recommendation is to be comprehensive in adding tests. If it's a visible nod directory. It's typically a good idea to test all the permutations of each language construct. This increases test coverage, but doubly acquaints readers with a way to examine expected outputs and understand the "edges" of a language. +```admonish tip +After modifying the grammar, you can run `tree-sitter test -u` +to update all syntax trees in corpus files with current parser output. +``` + ## Attributes Tests can be annotated with a few `attributes`. Attributes must be put in the header, below the test name, and start with @@ -99,8 +104,8 @@ you can repeat the attribute on a new line. The following attributes are available: -* `:cst` - This attribute specifies that the expected output should be in the form of a CST instead of the normal S-expression. This -CST matches the format given by `parse --cst`. +* `:cst` - This attribute specifies that the expected output should be in the form of a CST instead of the normal S-expression. +This CST matches the format given by `parse --cst`. * `:error` — This attribute will assert that the parse tree contains an error. It's useful to just validate that a certain input is invalid without displaying the whole parse tree, as such you should omit the parse tree below the `---` line. * `:fail-fast` — This attribute will stop the testing of additional cases if the test marked with this attribute fails. diff --git a/docs/src/creating-parsers/index.md b/docs/src/creating-parsers/index.md index 478cbeeb..4fb2c112 100644 --- a/docs/src/creating-parsers/index.md +++ b/docs/src/creating-parsers/index.md @@ -1,4 +1,4 @@ # Creating parsers -Developing Tree-sitter grammars can have a difficult learning curve, but once you get the hang of it, it can be fun and even -zen-like. This document will help you to get started and to develop a useful mental model. +Developing Tree-sitter grammars can have a difficult learning curve, but once you get the hang of it, it can be fun and +even zen-like. This document will help you to get started and to develop a useful mental model. diff --git a/docs/src/index.md b/docs/src/index.md index 5f9140a7..ee92966a 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -10,7 +10,8 @@ file and efficiently update the syntax tree as the source file is edited. Tree-s - **General** enough to parse any programming language - **Fast** enough to parse on every keystroke in a text editor - **Robust** enough to provide useful results even in the presence of syntax errors -- **Dependency-free** so that the runtime library (which is written in pure [C11](https://github.com/tree-sitter/tree-sitter/tree/master/lib)) can be embedded in any application +- **Dependency-free** so that the runtime library (which is written in pure [C11](https://github.com/tree-sitter/tree-sitter/tree/master/lib)) +can be embedded in any application ## Language Bindings diff --git a/docs/src/using-parsers/2-basic-parsing.md b/docs/src/using-parsers/2-basic-parsing.md index 77f6fb7a..8c425d6b 100644 --- a/docs/src/using-parsers/2-basic-parsing.md +++ b/docs/src/using-parsers/2-basic-parsing.md @@ -2,7 +2,8 @@ ## Providing the Code -In the example on the previous page, we parsed source code stored in a simple string using the `ts_parser_parse_string` function: +In the example on the previous page, we parsed source code stored in a simple string using the `ts_parser_parse_string` +function: ```c TSTree *ts_parser_parse_string( @@ -135,10 +136,10 @@ Consider a grammar rule like this: if_statement: $ => seq("if", "(", $._expression, ")", $._statement); ``` -A syntax node representing an `if_statement` in this language would have 5 children: the condition expression, the body statement, -as well as the `if`, `(`, and `)` tokens. The expression and the statement would be marked as _named_ nodes, because they -have been given explicit names in the grammar. But the `if`, `(`, and `)` nodes would _not_ be named nodes, because they -are represented in the grammar as simple strings. +A syntax node representing an `if_statement` in this language would have 5 children: the condition expression, the body +statement, as well as the `if`, `(`, and `)` tokens. The expression and the statement would be marked as _named_ nodes, +because they have been given explicit names in the grammar. But the `if`, `(`, and `)` nodes would _not_ be named nodes, +because they are represented in the grammar as simple strings. You can check whether any given node is named: diff --git a/docs/src/using-parsers/3-advanced-parsing.md b/docs/src/using-parsers/3-advanced-parsing.md index bffd35ea..c1c92e24 100644 --- a/docs/src/using-parsers/3-advanced-parsing.md +++ b/docs/src/using-parsers/3-advanced-parsing.md @@ -19,8 +19,8 @@ typedef struct { void ts_tree_edit(TSTree *, const TSInputEdit *); ``` -Then, you can call `ts_parser_parse` again, passing in the old tree. This will create a new tree that internally shares structure -with the old tree. +Then, you can call `ts_parser_parse` again, passing in the old tree. This will create a new tree that internally shares +structure with the old tree. When you edit a syntax tree, the positions of its nodes will change. If you have stored any `TSNode` instances outside of the `TSTree`, you must update their positions separately, using the same `TSInputEdit` value, in order to update their diff --git a/docs/src/using-parsers/6-static-node-types.md b/docs/src/using-parsers/6-static-node-types.md index 5976d0bc..171f4314 100644 --- a/docs/src/using-parsers/6-static-node-types.md +++ b/docs/src/using-parsers/6-static-node-types.md @@ -108,9 +108,9 @@ In Tree-sitter grammars, there are usually certain rules that represent abstract "type", "declaration"). In the `grammar.js` file, these are often written as [hidden rules][hidden rules] whose definition is a simple [`choice`][grammar dsl] where each member is just a single symbol. -Normally, hidden rules are not mentioned in the node types file, since they don't appear in the syntax tree. But if you add -a hidden rule to the grammar's [`supertypes` list][grammar dsl], then it _will_ show up in the node -types file, with the following special entry: +Normally, hidden rules are not mentioned in the node types file, since they don't appear in the syntax tree. But if you +add a hidden rule to the grammar's [`supertypes` list][grammar dsl], then it _will_ show up in the node types file, with +the following special entry: - `"subtypes"` — An array of objects that specify the _types_ of nodes that this 'supertype' node can wrap. diff --git a/docs/src/using-parsers/7-abi-versions.md b/docs/src/using-parsers/7-abi-versions.md new file mode 100644 index 00000000..1db42a5d --- /dev/null +++ b/docs/src/using-parsers/7-abi-versions.md @@ -0,0 +1,25 @@ +# ABI versions + +Parsers generated with tree-sitter have an associated ABI version, which establishes hard compatibility boundaries +between the generated parser and the tree-sitter library. + +A given version of the tree-sitter library is only able to load parsers generated with supported ABI versions: + +| tree-sitter version | Min parser ABI version | Max parser ABI version | +|---------------------|------------------------|------------------------| +| 0.14 | 9 | 9 | +| >=0.15.0, <=0.15.7 | 9 | 10 | +| >=0.15.8, <=0.16 | 9 | 11 | +| 0.17, 0.18 | 9 | 12 | +| >=0.19, <=0.20.2 | 13 | 13 | +| >=0.20.3, <=0.24 | 13 | 14 | +| >=0.25 | 13 | 15 | + +By default, the tree-sitter CLI will generate parsers using the latest available ABI for that version, but an older ABI +(supported by the CLI) can be selected by passing the [`--abi` option][abi_option] to the `generate` command. + +Note that the ABI version range supported by the CLI can be smaller than for the library: When a new ABI version is released, +older versions will be phased out over a deprecation period, which starts with no longer being able to generate parsers +with the oldest ABI version. + +[abi_option]: ../cli/generate.md#--abi-version diff --git a/docs/src/using-parsers/index.md b/docs/src/using-parsers/index.md index 48d61599..5b2c146d 100644 --- a/docs/src/using-parsers/index.md +++ b/docs/src/using-parsers/index.md @@ -6,8 +6,8 @@ the core concepts remain the same. Tree-sitter's parsing functionality is implemented through its C API, with all functions documented in the [tree_sitter/api.h][api.h] header file, but if you're working in another language, you can use one of the following bindings found [here](../index.md#language-bindings), -each providing idiomatic access to Tree-sitter's functionality. Of these bindings, the official ones have their own API docs -hosted online at the following pages: +each providing idiomatic access to Tree-sitter's functionality. Of these bindings, the official ones have their own API +doc hosted online at the following pages: - [Go][go] - [Java] diff --git a/docs/src/using-parsers/queries/1-syntax.md b/docs/src/using-parsers/queries/1-syntax.md index a12cec70..2e0a8853 100644 --- a/docs/src/using-parsers/queries/1-syntax.md +++ b/docs/src/using-parsers/queries/1-syntax.md @@ -1,9 +1,9 @@ # Query Syntax -A _query_ consists of one or more _patterns_, where each pattern is an [S-expression][s-exp] that matches a certain set of -nodes in a syntax tree. The expression to match a given node consists of a pair of parentheses containing two things: the -node's type, and optionally, a series of other S-expressions that match the node's children. For example, this pattern would -match any `binary_expression` node whose children are both `number_literal` nodes: +A _query_ consists of one or more _patterns_, where each pattern is an [S-expression][s-exp] that matches a certain set +of nodes in a syntax tree. The expression to match a given node consists of a pair of parentheses containing two things: +the node's type, and optionally, a series of other S-expressions that match the node's children. For example, this pattern +would match any `binary_expression` node whose children are both `number_literal` nodes: ```query (binary_expression (number_literal) (number_literal)) @@ -99,10 +99,10 @@ by `(ERROR)` queries. Specific missing node types can also be queried: ### Supertype Nodes Some node types are marked as _supertypes_ in a grammar. A supertype is a node type that contains multiple -subtypes. For example, in the [JavaScript grammar example][grammar], `expression` is a supertype that can represent any kind -of expression, such as a `binary_expression`, `call_expression`, or `identifier`. You can use supertypes in queries to match -any of their subtypes, rather than having to list out each subtype individually. For example, this pattern would match any -kind of expression, even though it's not a visible node in the syntax tree: +subtypes. For example, in the [JavaScript grammar example][grammar], `expression` is a supertype that can represent any +kind of expression, such as a `binary_expression`, `call_expression`, or `identifier`. You can use supertypes in queries +to match any of their subtypes, rather than having to list out each subtype individually. For example, this pattern would +match any kind of expression, even though it's not a visible node in the syntax tree: ```query (expression) @any-expression @@ -115,6 +115,12 @@ match a `binary_expression` only if it is a child of `expression`: (expression/binary_expression) @binary-expression ``` +This also applies to anonymous nodes. For example, this pattern would match `"()"` only if it is a child of `expression`: + +```query +(expression/"()") @empty-expression +``` + [grammar]: ../../creating-parsers/3-writing-the-grammar.md#structuring-rules-well [node-field-names]: ../2-basic-parsing.md#node-field-names [named-vs-anonymous-nodes]: ../2-basic-parsing.md#named-vs-anonymous-nodes diff --git a/docs/src/using-parsers/queries/3-predicates-and-directives.md b/docs/src/using-parsers/queries/3-predicates-and-directives.md index a059a3ba..1f9aeada 100644 --- a/docs/src/using-parsers/queries/3-predicates-and-directives.md +++ b/docs/src/using-parsers/queries/3-predicates-and-directives.md @@ -128,19 +128,19 @@ This pattern would match any builtin variable that is not a local variable, beca # Directives -Similar to predicates, directives are a way to associate arbitrary metadata with a pattern. The only difference between predicates -and directives is that directives end in a `!` character instead of `?` character. +Similar to predicates, directives are a way to associate arbitrary metadata with a pattern. The only difference between +predicates and directives is that directives end in a `!` character instead of `?` character. Tree-sitter's CLI supports the following directives by default: ## The `set!` directive -This directive allows you to associate key-value pairs with a pattern. The key and value can be any arbitrary text that you -see fit. +This directive allows you to associate key-value pairs with a pattern. The key and value can be any arbitrary text that +you see fit. ```query ((comment) @injection.content - (#lua-match? @injection.content "/[*\/][!*\/] bool; } +extern "C" { + #[doc = " Set the byte range within which all matches must be fully contained.\n\n Set the range of bytes in which matches will be searched for. In contrast to\n `ts_query_cursor_set_byte_range`, this will restrict the query cursor to only return\n matches where _all_ nodes are _fully_ contained within the given range. Both functions\n can be used together, e.g. to search for any matches that intersect line 5000, as\n long as they are fully contained within lines 4500-5500"] + pub fn ts_query_cursor_set_containing_byte_range( + self_: *mut TSQueryCursor, + start_byte: u32, + end_byte: u32, + ) -> bool; +} +extern "C" { + #[doc = " Set the point range within which all matches must be fully contained.\n\n Set the range of bytes in which matches will be searched for. In contrast to\n `ts_query_cursor_set_point_range`, this will restrict the query cursor to only return\n matches where _all_ nodes are _fully_ contained within the given range. Both functions\n can be used together, e.g. to search for any matches that intersect line 5000, as\n long as they are fully contained within lines 4500-5500"] + pub fn ts_query_cursor_set_containing_point_range( + self_: *mut TSQueryCursor, + start_point: TSPoint, + end_point: TSPoint, + ) -> bool; +} extern "C" { #[doc = " Advance to the next match of the currently running query.\n\n If there is a match, write it to `*match` and return `true`.\n Otherwise, return `false`."] pub fn ts_query_cursor_next_match(self_: *mut TSQueryCursor, match_: *mut TSQueryMatch) diff --git a/lib/binding_rust/build.rs b/lib/binding_rust/build.rs index 7268d615..57c5bc94 100644 --- a/lib/binding_rust/build.rs +++ b/lib/binding_rust/build.rs @@ -49,6 +49,8 @@ fn main() { .include(&include_path) .define("_POSIX_C_SOURCE", "200112L") .define("_DEFAULT_SOURCE", None) + .define("_BSD_SOURCE", None) + .define("_DARWIN_C_SOURCE", None) .warnings(false) .file(src_path.join("lib.c")) .compile("tree-sitter"); diff --git a/lib/binding_rust/lib.rs b/lib/binding_rust/lib.rs index 6938c1db..51fd7f25 100644 --- a/lib/binding_rust/lib.rs +++ b/lib/binding_rust/lib.rs @@ -1,4 +1,4 @@ -#![cfg_attr(not(any(test, doctest)), doc = include_str!("../README.md"))] +#![cfg_attr(not(any(test, doctest)), doc = include_str!("./README.md"))] #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(docsrs, feature(doc_cfg))] @@ -317,7 +317,7 @@ pub trait Decode { /// A stateful object for walking a syntax [`Tree`] efficiently. #[doc(alias = "TSTreeCursor")] -pub struct TreeCursor<'cursor>(ffi::TSTreeCursor, PhantomData<&'cursor ()>); +pub struct TreeCursor<'tree>(ffi::TSTreeCursor, PhantomData<&'tree ()>); /// A set of patterns that match nodes in a syntax tree. #[doc(alias = "TSQuery")] @@ -351,7 +351,7 @@ impl From for CaptureQuantifier { ffi::TSQuantifierZeroOrMore => Self::ZeroOrMore, ffi::TSQuantifierOne => Self::One, ffi::TSQuantifierOneOrMore => Self::OneOrMore, - _ => panic!("Unrecognized quantifier: {value}"), + _ => unreachable!(), } } } @@ -392,7 +392,7 @@ pub struct QueryMatch<'cursor, 'tree> { } /// A sequence of [`QueryMatch`]es associated with a given [`QueryCursor`]. -pub struct QueryMatches<'query, 'tree: 'query, T: TextProvider, I: AsRef<[u8]>> { +pub struct QueryMatches<'query, 'tree, T: TextProvider, I: AsRef<[u8]>> { ptr: *mut ffi::TSQueryCursor, query: &'query Query, text_provider: T, @@ -407,7 +407,7 @@ pub struct QueryMatches<'query, 'tree: 'query, T: TextProvider, I: AsRef<[u8] /// /// During iteration, each element contains a [`QueryMatch`] and index. The index can /// be used to access the new capture inside of the [`QueryMatch::captures`]'s [`captures`]. -pub struct QueryCaptures<'query, 'tree: 'query, T: TextProvider, I: AsRef<[u8]>> { +pub struct QueryCaptures<'query, 'tree, T: TextProvider, I: AsRef<[u8]>> { ptr: *mut ffi::TSQueryCursor, query: &'query Query, text_provider: T, @@ -1386,6 +1386,11 @@ impl Drop for Parser { } } +#[cfg(windows)] +extern "C" { + fn _open_osfhandle(osfhandle: isize, flags: core::ffi::c_int) -> core::ffi::c_int; +} + impl Tree { /// Get the root node of the syntax tree. #[doc(alias = "ts_tree_root_node")] @@ -1495,7 +1500,8 @@ impl Tree { #[cfg(windows)] { let handle = file.as_raw_handle(); - unsafe { ffi::ts_tree_print_dot_graph(self.0.as_ptr(), handle as i32) } + let fd = unsafe { _open_osfhandle(handle as isize, 0) }; + unsafe { ffi::ts_tree_print_dot_graph(self.0.as_ptr(), fd) } } } } @@ -1575,7 +1581,7 @@ impl<'tree> Node<'tree> { /// Get the [`Language`] that was used to parse this node's syntax tree. #[doc(alias = "ts_node_language")] #[must_use] - pub fn language(&self) -> LanguageRef { + pub fn language(&self) -> LanguageRef<'tree> { LanguageRef(unsafe { ffi::ts_node_language(self.0) }, PhantomData) } @@ -2076,11 +2082,11 @@ impl fmt::Display for Node<'_> { } } -impl<'cursor> TreeCursor<'cursor> { +impl<'tree> TreeCursor<'tree> { /// Get the tree cursor's current [`Node`]. #[doc(alias = "ts_tree_cursor_current_node")] #[must_use] - pub fn node(&self) -> Node<'cursor> { + pub fn node(&self) -> Node<'tree> { Node( unsafe { ffi::ts_tree_cursor_current_node(&self.0) }, PhantomData, @@ -2221,7 +2227,7 @@ impl<'cursor> TreeCursor<'cursor> { /// Re-initialize this tree cursor to start at the original node that the /// cursor was constructed with. #[doc(alias = "ts_tree_cursor_reset")] - pub fn reset(&mut self, node: Node<'cursor>) { + pub fn reset(&mut self, node: Node<'tree>) { unsafe { ffi::ts_tree_cursor_reset(&mut self.0, node.0) }; } @@ -2337,6 +2343,16 @@ impl Query { /// on syntax nodes parsed with that language. References to Queries can be /// shared between multiple threads. pub fn new(language: &Language, source: &str) -> Result { + let ptr = Self::new_raw(language, source)?; + unsafe { Self::from_raw_parts(ptr, source) } + } + + /// Constructs a raw [`TSQuery`](ffi::TSQuery) pointer without performing extra checks specific to the rust + /// bindings, such as predicate validation. A [`Query`] object can be constructed from the + /// returned pointer using [`from_raw_parts`](Query::from_raw_parts). The caller is + /// responsible for ensuring that the returned pointer is eventually freed by calling + /// [`ts_query_delete`](ffi::ts_query_delete). + pub fn new_raw(language: &Language, source: &str) -> Result<*mut ffi::TSQuery, QueryError> { let mut error_offset = 0u32; let mut error_type: ffi::TSQueryError = 0; let bytes = source.as_bytes(); @@ -2352,90 +2368,90 @@ impl Query { ) }; + if !ptr.is_null() { + return Ok(ptr); + } + // On failure, build an error based on the error code and offset. - if ptr.is_null() { - if error_type == ffi::TSQueryErrorLanguage { - return Err(QueryError { - row: 0, - column: 0, - offset: 0, - message: LanguageError::Version(language.abi_version()).to_string(), - kind: QueryErrorKind::Language, - }); - } - - let offset = error_offset as usize; - let mut line_start = 0; - let mut row = 0; - let mut line_containing_error = None; - for line in source.lines() { - let line_end = line_start + line.len() + 1; - if line_end > offset { - line_containing_error = Some(line); - break; - } - line_start = line_end; - row += 1; - } - let column = offset - line_start; - - let kind; - let message; - match error_type { - // Error types that report names - ffi::TSQueryErrorNodeType | ffi::TSQueryErrorField | ffi::TSQueryErrorCapture => { - let suffix = source.split_at(offset).1; - let in_quotes = offset > 0 && source.as_bytes()[offset - 1] == b'"'; - let mut backslashes = 0; - let end_offset = suffix - .find(|c| { - if in_quotes { - if c == '"' && backslashes % 2 == 0 { - true - } else if c == '\\' { - backslashes += 1; - false - } else { - backslashes = 0; - false - } - } else { - !char::is_alphanumeric(c) && c != '_' && c != '-' - } - }) - .unwrap_or(suffix.len()); - message = format!("\"{}\"", suffix.split_at(end_offset).0); - kind = match error_type { - ffi::TSQueryErrorNodeType => QueryErrorKind::NodeType, - ffi::TSQueryErrorField => QueryErrorKind::Field, - ffi::TSQueryErrorCapture => QueryErrorKind::Capture, - _ => unreachable!(), - }; - } - - // Error types that report positions - _ => { - message = line_containing_error.map_or_else( - || "Unexpected EOF".to_string(), - |line| line.to_string() + "\n" + &" ".repeat(offset - line_start) + "^", - ); - kind = match error_type { - ffi::TSQueryErrorStructure => QueryErrorKind::Structure, - _ => QueryErrorKind::Syntax, - }; - } - } - + if error_type == ffi::TSQueryErrorLanguage { return Err(QueryError { - row, - column, - offset, - message, - kind, + row: 0, + column: 0, + offset: 0, + message: LanguageError::Version(language.abi_version()).to_string(), + kind: QueryErrorKind::Language, }); } - unsafe { Self::from_raw_parts(ptr, source) } + let offset = error_offset as usize; + let mut line_start = 0; + let mut row = 0; + let mut line_containing_error = None; + for line in source.lines() { + let line_end = line_start + line.len() + 1; + if line_end > offset { + line_containing_error = Some(line); + break; + } + line_start = line_end; + row += 1; + } + let column = offset - line_start; + + let kind; + let message; + match error_type { + // Error types that report names + ffi::TSQueryErrorNodeType | ffi::TSQueryErrorField | ffi::TSQueryErrorCapture => { + let suffix = source.split_at(offset).1; + let in_quotes = offset > 0 && source.as_bytes()[offset - 1] == b'"'; + let mut backslashes = 0; + let end_offset = suffix + .find(|c| { + if in_quotes { + if c == '"' && backslashes % 2 == 0 { + true + } else if c == '\\' { + backslashes += 1; + false + } else { + backslashes = 0; + false + } + } else { + !char::is_alphanumeric(c) && c != '_' && c != '-' + } + }) + .unwrap_or(suffix.len()); + message = format!("\"{}\"", suffix.split_at(end_offset).0); + kind = match error_type { + ffi::TSQueryErrorNodeType => QueryErrorKind::NodeType, + ffi::TSQueryErrorField => QueryErrorKind::Field, + ffi::TSQueryErrorCapture => QueryErrorKind::Capture, + _ => unreachable!(), + }; + } + + // Error types that report positions + _ => { + message = line_containing_error.map_or_else( + || "Unexpected EOF".to_string(), + |line| line.to_string() + "\n" + &" ".repeat(offset - line_start) + "^", + ); + kind = match error_type { + ffi::TSQueryErrorStructure => QueryErrorKind::Structure, + _ => QueryErrorKind::Syntax, + }; + } + } + + Err(QueryError { + row, + column, + offset, + message, + kind, + }) } #[doc(hidden)] @@ -3165,6 +3181,44 @@ impl QueryCursor { self } + /// Set the byte range within which all matches must be fully contained. + /// + /// Set the range of bytes in which matches will be searched for. In contrast to + /// `ts_query_cursor_set_byte_range`, this will restrict the query cursor to only return + /// matches where _all_ nodes are _fully_ contained within the given range. Both functions + /// can be used together, e.g. to search for any matches that intersect line 5000, as + /// long as they are fully contained within lines 4500-5500 + #[doc(alias = "ts_query_cursor_set_containing_byte_range")] + pub fn set_containing_byte_range(&mut self, range: ops::Range) -> &mut Self { + unsafe { + ffi::ts_query_cursor_set_containing_byte_range( + self.ptr.as_ptr(), + range.start as u32, + range.end as u32, + ); + } + self + } + + /// Set the point range within which all matches must be fully contained. + /// + /// Set the range of bytes in which matches will be searched for. In contrast to + /// `ts_query_cursor_set_point_range`, this will restrict the query cursor to only return + /// matches where _all_ nodes are _fully_ contained within the given range. Both functions + /// can be used together, e.g. to search for any matches that intersect line 5000, as + /// long as they are fully contained within lines 4500-5500 + #[doc(alias = "ts_query_cursor_set_containing_point_range")] + pub fn set_containing_point_range(&mut self, range: ops::Range) -> &mut Self { + unsafe { + ffi::ts_query_cursor_set_containing_point_range( + self.ptr.as_ptr(), + range.start.into(), + range.end.into(), + ); + } + self + } + /// Set the maximum start depth for a query cursor. /// /// This prevents cursors from exploring children nodes at a certain depth. @@ -3174,9 +3228,9 @@ impl QueryCursor { /// The zero max start depth value can be used as a special behavior and /// it helps to destructure a subtree by staying on a node and using /// captures for interested parts. Note that the zero max start depth - /// only limit a search depth for a pattern's root node but other nodes - /// that are parts of the pattern may be searched at any depth what - /// defined by the pattern structure. + /// only limits a search depth for a pattern's root node but other nodes + /// that are parts of the pattern may be searched at any depth depending on + /// what is defined by the pattern structure. /// /// Set to `None` to remove the maximum start depth. #[doc(alias = "ts_query_cursor_set_max_start_depth")] @@ -3350,7 +3404,7 @@ impl QueryProperty { /// Provide a `StreamingIterator` instead of the traditional `Iterator`, as the /// underlying object in the C library gets updated on each iteration. Copies would /// have their internal state overwritten, leading to Undefined Behavior -impl<'query, 'tree: 'query, T: TextProvider, I: AsRef<[u8]>> StreamingIterator +impl<'query, 'tree, T: TextProvider, I: AsRef<[u8]>> StreamingIterator for QueryMatches<'query, 'tree, T, I> { type Item = QueryMatch<'query, 'tree>; @@ -3381,15 +3435,13 @@ impl<'query, 'tree: 'query, T: TextProvider, I: AsRef<[u8]>> StreamingIterato } } -impl<'query, 'tree: 'query, T: TextProvider, I: AsRef<[u8]>> StreamingIteratorMut - for QueryMatches<'query, 'tree, T, I> -{ +impl, I: AsRef<[u8]>> StreamingIteratorMut for QueryMatches<'_, '_, T, I> { fn get_mut(&mut self) -> Option<&mut Self::Item> { self.current_match.as_mut() } } -impl<'query, 'tree: 'query, T: TextProvider, I: AsRef<[u8]>> StreamingIterator +impl<'query, 'tree, T: TextProvider, I: AsRef<[u8]>> StreamingIterator for QueryCaptures<'query, 'tree, T, I> { type Item = (QueryMatch<'query, 'tree>, usize); @@ -3426,9 +3478,7 @@ impl<'query, 'tree: 'query, T: TextProvider, I: AsRef<[u8]>> StreamingIterato } } -impl<'query, 'tree: 'query, T: TextProvider, I: AsRef<[u8]>> StreamingIteratorMut - for QueryCaptures<'query, 'tree, T, I> -{ +impl, I: AsRef<[u8]>> StreamingIteratorMut for QueryCaptures<'_, '_, T, I> { fn get_mut(&mut self) -> Option<&mut Self::Item> { self.current_match.as_mut() } @@ -3568,8 +3618,8 @@ impl From for Range { } } -impl From<&'_ InputEdit> for ffi::TSInputEdit { - fn from(val: &'_ InputEdit) -> Self { +impl From<&InputEdit> for ffi::TSInputEdit { + fn from(val: &InputEdit) -> Self { Self { start_byte: val.start_byte as u32, old_end_byte: val.old_end_byte as u32, diff --git a/lib/binding_web/lib/tree-sitter.c b/lib/binding_web/lib/tree-sitter.c index db6c108b..828132ac 100644 --- a/lib/binding_web/lib/tree-sitter.c +++ b/lib/binding_web/lib/tree-sitter.c @@ -874,6 +874,12 @@ void ts_query_matches_wasm( uint32_t end_column, uint32_t start_index, uint32_t end_index, + uint32_t start_containing_row, + uint32_t start_containing_column, + uint32_t end_containing_row, + uint32_t end_containing_column, + uint32_t start_containing_index, + uint32_t end_containing_index, uint32_t match_limit, uint32_t max_start_depth ) { @@ -889,8 +895,20 @@ void ts_query_matches_wasm( TSNode node = unmarshal_node(tree); TSPoint start_point = {start_row, code_unit_to_byte(start_column)}; TSPoint end_point = {end_row, code_unit_to_byte(end_column)}; + TSPoint start_containing_point = {start_containing_row, code_unit_to_byte(start_containing_column)}; + TSPoint end_containing_point = {end_containing_row, code_unit_to_byte(end_containing_column)}; ts_query_cursor_set_point_range(scratch_query_cursor, start_point, end_point); ts_query_cursor_set_byte_range(scratch_query_cursor, start_index, end_index); + ts_query_cursor_set_containing_point_range( + scratch_query_cursor, + start_containing_point, + end_containing_point + ); + ts_query_cursor_set_containing_byte_range( + scratch_query_cursor, + start_containing_index, + end_containing_index + ); ts_query_cursor_set_match_limit(scratch_query_cursor, match_limit); ts_query_cursor_set_max_start_depth(scratch_query_cursor, max_start_depth); @@ -932,6 +950,12 @@ void ts_query_captures_wasm( uint32_t end_column, uint32_t start_index, uint32_t end_index, + uint32_t start_containing_row, + uint32_t start_containing_column, + uint32_t end_containing_row, + uint32_t end_containing_column, + uint32_t start_containing_index, + uint32_t end_containing_index, uint32_t match_limit, uint32_t max_start_depth ) { @@ -944,8 +968,20 @@ void ts_query_captures_wasm( TSNode node = unmarshal_node(tree); TSPoint start_point = {start_row, code_unit_to_byte(start_column)}; TSPoint end_point = {end_row, code_unit_to_byte(end_column)}; + TSPoint start_containing_point = {start_containing_row, code_unit_to_byte(start_containing_column)}; + TSPoint end_containing_point = {end_containing_row, code_unit_to_byte(end_containing_column)}; ts_query_cursor_set_point_range(scratch_query_cursor, start_point, end_point); ts_query_cursor_set_byte_range(scratch_query_cursor, start_index, end_index); + ts_query_cursor_set_containing_point_range( + scratch_query_cursor, + start_containing_point, + end_containing_point + ); + ts_query_cursor_set_containing_byte_range( + scratch_query_cursor, + start_containing_index, + end_containing_index + ); ts_query_cursor_set_match_limit(scratch_query_cursor, match_limit); ts_query_cursor_set_max_start_depth(scratch_query_cursor, max_start_depth); ts_query_cursor_exec(scratch_query_cursor, self, node); diff --git a/lib/binding_web/lib/web-tree-sitter.d.ts b/lib/binding_web/lib/web-tree-sitter.d.ts index c19d7bf4..c1e0e0dd 100644 --- a/lib/binding_web/lib/web-tree-sitter.d.ts +++ b/lib/binding_web/lib/web-tree-sitter.d.ts @@ -175,8 +175,8 @@ interface WasmModule { _ts_node_is_extra_wasm(_0: number): number; _ts_node_parse_state_wasm(_0: number): number; _ts_node_next_parse_state_wasm(_0: number): number; - _ts_query_matches_wasm(_0: number, _1: number, _2: number, _3: number, _4: number, _5: number, _6: number, _7: number, _8: number, _9: number): void; - _ts_query_captures_wasm(_0: number, _1: number, _2: number, _3: number, _4: number, _5: number, _6: number, _7: number, _8: number, _9: number): void; + _ts_query_matches_wasm(_0: number, _1: number, _2: number, _3: number, _4: number, _5: number, _6: number, _7: number, _8: number, _9: number, _10: number, _11: number, _12: number, _13: number, _14: number, _15: number): void; + _ts_query_captures_wasm(_0: number, _1: number, _2: number, _3: number, _4: number, _5: number, _6: number, _7: number, _8: number, _9: number, _10: number, _11: number, _12: number, _13: number, _14: number, _15: number): void; _memset(_0: number, _1: number, _2: number): number; _memcpy(_0: number, _1: number, _2: number): number; _memmove(_0: number, _1: number, _2: number): number; diff --git a/lib/binding_web/package-lock.json b/lib/binding_web/package-lock.json index 49d63180..4ec07f7b 100644 --- a/lib/binding_web/package-lock.json +++ b/lib/binding_web/package-lock.json @@ -1,25 +1,25 @@ { "name": "web-tree-sitter", - "version": "0.26.0", + "version": "0.27.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "web-tree-sitter", - "version": "0.26.0", + "version": "0.27.0", "license": "MIT", "devDependencies": { - "@eslint/js": "^9.20.0", - "@types/emscripten": "^1.40.0", - "@types/node": "^24.3.0", + "@eslint/js": "^9.39.1", + "@types/emscripten": "^1.41.5", + "@types/node": "^24.10.1", "@vitest/coverage-v8": "^3.0.5", "dts-buddy": "^0.6.2", - "esbuild": "^0.25.0", - "eslint": "^9.20.0", + "esbuild": "^0.27.1", + "eslint": "^9.39.1", "source-map": "^0.7.4", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", - "typescript-eslint": "^8.23.0", + "typescript-eslint": "^8.48.1", "vitest": "^3.0.5" } }, @@ -98,9 +98,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", - "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.1.tgz", + "integrity": "sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA==", "cpu": [ "ppc64" ], @@ -115,9 +115,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", - "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.1.tgz", + "integrity": "sha512-kFqa6/UcaTbGm/NncN9kzVOODjhZW8e+FRdSeypWe6j33gzclHtwlANs26JrupOntlcWmB0u8+8HZo8s7thHvg==", "cpu": [ "arm" ], @@ -132,9 +132,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", - "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.1.tgz", + "integrity": "sha512-45fuKmAJpxnQWixOGCrS+ro4Uvb4Re9+UTieUY2f8AEc+t7d4AaZ6eUJ3Hva7dtrxAAWHtlEFsXFMAgNnGU9uQ==", "cpu": [ "arm64" ], @@ -149,9 +149,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", - "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.1.tgz", + "integrity": "sha512-LBEpOz0BsgMEeHgenf5aqmn/lLNTFXVfoWMUox8CtWWYK9X4jmQzWjoGoNb8lmAYml/tQ/Ysvm8q7szu7BoxRQ==", "cpu": [ "x64" ], @@ -166,9 +166,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", - "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.1.tgz", + "integrity": "sha512-veg7fL8eMSCVKL7IW4pxb54QERtedFDfY/ASrumK/SbFsXnRazxY4YykN/THYqFnFwJ0aVjiUrVG2PwcdAEqQQ==", "cpu": [ "arm64" ], @@ -183,9 +183,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", - "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.1.tgz", + "integrity": "sha512-+3ELd+nTzhfWb07Vol7EZ+5PTbJ/u74nC6iv4/lwIU99Ip5uuY6QoIf0Hn4m2HoV0qcnRivN3KSqc+FyCHjoVQ==", "cpu": [ "x64" ], @@ -200,9 +200,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", - "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.1.tgz", + "integrity": "sha512-/8Rfgns4XD9XOSXlzUDepG8PX+AVWHliYlUkFI3K3GB6tqbdjYqdhcb4BKRd7C0BhZSoaCxhv8kTcBrcZWP+xg==", "cpu": [ "arm64" ], @@ -217,9 +217,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", - "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.1.tgz", + "integrity": "sha512-GITpD8dK9C+r+5yRT/UKVT36h/DQLOHdwGVwwoHidlnA168oD3uxA878XloXebK4Ul3gDBBIvEdL7go9gCUFzQ==", "cpu": [ "x64" ], @@ -234,9 +234,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", - "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.1.tgz", + "integrity": "sha512-ieMID0JRZY/ZeCrsFQ3Y3NlHNCqIhTprJfDgSB3/lv5jJZ8FX3hqPyXWhe+gvS5ARMBJ242PM+VNz/ctNj//eA==", "cpu": [ "arm" ], @@ -251,9 +251,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", - "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.1.tgz", + "integrity": "sha512-W9//kCrh/6in9rWIBdKaMtuTTzNj6jSeG/haWBADqLLa9P8O5YSRDzgD5y9QBok4AYlzS6ARHifAb75V6G670Q==", "cpu": [ "arm64" ], @@ -268,9 +268,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", - "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.1.tgz", + "integrity": "sha512-VIUV4z8GD8rtSVMfAj1aXFahsi/+tcoXXNYmXgzISL+KB381vbSTNdeZHHHIYqFyXcoEhu9n5cT+05tRv13rlw==", "cpu": [ "ia32" ], @@ -285,9 +285,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", - "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.1.tgz", + "integrity": "sha512-l4rfiiJRN7sTNI//ff65zJ9z8U+k6zcCg0LALU5iEWzY+a1mVZ8iWC1k5EsNKThZ7XCQ6YWtsZ8EWYm7r1UEsg==", "cpu": [ "loong64" ], @@ -302,9 +302,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", - "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.1.tgz", + "integrity": "sha512-U0bEuAOLvO/DWFdygTHWY8C067FXz+UbzKgxYhXC0fDieFa0kDIra1FAhsAARRJbvEyso8aAqvPdNxzWuStBnA==", "cpu": [ "mips64el" ], @@ -319,9 +319,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", - "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.1.tgz", + "integrity": "sha512-NzdQ/Xwu6vPSf/GkdmRNsOfIeSGnh7muundsWItmBsVpMoNPVpM61qNzAVY3pZ1glzzAxLR40UyYM23eaDDbYQ==", "cpu": [ "ppc64" ], @@ -336,9 +336,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", - "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.1.tgz", + "integrity": "sha512-7zlw8p3IApcsN7mFw0O1Z1PyEk6PlKMu18roImfl3iQHTnr/yAfYv6s4hXPidbDoI2Q0pW+5xeoM4eTCC0UdrQ==", "cpu": [ "riscv64" ], @@ -353,9 +353,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", - "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.1.tgz", + "integrity": "sha512-cGj5wli+G+nkVQdZo3+7FDKC25Uh4ZVwOAK6A06Hsvgr8WqBBuOy/1s+PUEd/6Je+vjfm6stX0kmib5b/O2Ykw==", "cpu": [ "s390x" ], @@ -370,9 +370,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", - "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.1.tgz", + "integrity": "sha512-z3H/HYI9MM0HTv3hQZ81f+AKb+yEoCRlUby1F80vbQ5XdzEMyY/9iNlAmhqiBKw4MJXwfgsh7ERGEOhrM1niMA==", "cpu": [ "x64" ], @@ -387,9 +387,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", - "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.1.tgz", + "integrity": "sha512-wzC24DxAvk8Em01YmVXyjl96Mr+ecTPyOuADAvjGg+fyBpGmxmcr2E5ttf7Im8D0sXZihpxzO1isus8MdjMCXQ==", "cpu": [ "arm64" ], @@ -404,9 +404,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", - "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.1.tgz", + "integrity": "sha512-1YQ8ybGi2yIXswu6eNzJsrYIGFpnlzEWRl6iR5gMgmsrR0FcNoV1m9k9sc3PuP5rUBLshOZylc9nqSgymI+TYg==", "cpu": [ "x64" ], @@ -421,9 +421,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", - "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.1.tgz", + "integrity": "sha512-5Z+DzLCrq5wmU7RDaMDe2DVXMRm2tTDvX2KU14JJVBN2CT/qov7XVix85QoJqHltpvAOZUAc3ndU56HSMWrv8g==", "cpu": [ "arm64" ], @@ -438,9 +438,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", - "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.1.tgz", + "integrity": "sha512-Q73ENzIdPF5jap4wqLtsfh8YbYSZ8Q0wnxplOlZUOyZy7B4ZKW8DXGWgTCZmF8VWD7Tciwv5F4NsRf6vYlZtqg==", "cpu": [ "x64" ], @@ -455,9 +455,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", - "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.1.tgz", + "integrity": "sha512-ajbHrGM/XiK+sXM0JzEbJAen+0E+JMQZ2l4RR4VFwvV9JEERx+oxtgkpoKv1SevhjavK2z2ReHk32pjzktWbGg==", "cpu": [ "arm64" ], @@ -472,9 +472,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", - "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.1.tgz", + "integrity": "sha512-IPUW+y4VIjuDVn+OMzHc5FV4GubIwPnsz6ubkvN8cuhEqH81NovB53IUlrlBkPMEPxvNnf79MGBoz8rZ2iW8HA==", "cpu": [ "x64" ], @@ -489,9 +489,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", - "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.1.tgz", + "integrity": "sha512-RIVRWiljWA6CdVu8zkWcRmGP7iRRIIwvhDKem8UMBjPql2TXM5PkDVvvrzMtj1V+WFPB4K7zkIGM7VzRtFkjdg==", "cpu": [ "arm64" ], @@ -506,9 +506,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", - "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.1.tgz", + "integrity": "sha512-2BR5M8CPbptC1AK5JbJT1fWrHLvejwZidKx3UMSF0ecHMa+smhi16drIrCEggkgviBwLYd5nwrFLSl5Kho96RQ==", "cpu": [ "ia32" ], @@ -523,9 +523,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", - "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.1.tgz", + "integrity": "sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw==", "cpu": [ "x64" ], @@ -582,13 +582,13 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", - "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.6", + "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" }, @@ -597,19 +597,22 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", - "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", "dev": true, "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/core": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", - "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -644,9 +647,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.35.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.35.0.tgz", - "integrity": "sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw==", + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", + "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", "dev": true, "license": "MIT", "engines": { @@ -657,9 +660,9 @@ } }, "node_modules/@eslint/object-schema": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -667,13 +670,13 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", - "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.15.2", + "@eslint/core": "^0.17.0", "levn": "^0.4.1" }, "engines": { @@ -838,44 +841,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -1185,9 +1150,9 @@ "license": "MIT" }, "node_modules/@types/emscripten": { - "version": "1.41.2", - "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.41.2.tgz", - "integrity": "sha512-0EVXosRnffZuF+rsMM1ZVbfpwpvL2/hWycYQ/0GaH/VaoSJvcSmMl6fiPel9TZXHL3EhANxzqKOVFC6NFXyn8A==", + "version": "1.41.5", + "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.41.5.tgz", + "integrity": "sha512-cMQm7pxu6BxtHyqJ7mQZ2kXWV5SLmugybFdHCBbJ5eHzOo6VhBckEgAT3//rP5FwPHNPeEiq4SmQ5ucBwsOo4Q==", "dev": true, "license": "MIT" }, @@ -1206,27 +1171,28 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.5.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.5.0.tgz", - "integrity": "sha512-y1dMvuvJspJiPSDZUQ+WMBvF7dpnEqN4x9DDC9ie5Fs/HUZJA3wFp7EhHoVaKX/iI0cRoECV8X2jL8zi0xrHCg==", + "version": "24.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", + "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "undici-types": "~7.12.0" + "undici-types": "~7.16.0" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.44.0.tgz", - "integrity": "sha512-EGDAOGX+uwwekcS0iyxVDmRV9HX6FLSM5kzrAToLTsr9OWCIKG/y3lQheCq18yZ5Xh78rRKJiEpP0ZaCs4ryOQ==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.1.tgz", + "integrity": "sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.44.0", - "@typescript-eslint/type-utils": "8.44.0", - "@typescript-eslint/utils": "8.44.0", - "@typescript-eslint/visitor-keys": "8.44.0", + "@typescript-eslint/scope-manager": "8.48.1", + "@typescript-eslint/type-utils": "8.48.1", + "@typescript-eslint/utils": "8.48.1", + "@typescript-eslint/visitor-keys": "8.48.1", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -1240,7 +1206,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.44.0", + "@typescript-eslint/parser": "^8.48.1", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } @@ -1256,16 +1222,17 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.44.0.tgz", - "integrity": "sha512-VGMpFQGUQWYT9LfnPcX8ouFojyrZ/2w3K5BucvxL/spdNehccKhB4jUyB1yBCXpr2XFm0jkECxgrpXBW2ipoAw==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.1.tgz", + "integrity": "sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.44.0", - "@typescript-eslint/types": "8.44.0", - "@typescript-eslint/typescript-estree": "8.44.0", - "@typescript-eslint/visitor-keys": "8.44.0", + "@typescript-eslint/scope-manager": "8.48.1", + "@typescript-eslint/types": "8.48.1", + "@typescript-eslint/typescript-estree": "8.48.1", + "@typescript-eslint/visitor-keys": "8.48.1", "debug": "^4.3.4" }, "engines": { @@ -1281,14 +1248,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.44.0.tgz", - "integrity": "sha512-ZeaGNraRsq10GuEohKTo4295Z/SuGcSq2LzfGlqiuEvfArzo/VRrT0ZaJsVPuKZ55lVbNk8U6FcL+ZMH8CoyVA==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.48.1.tgz", + "integrity": "sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.44.0", - "@typescript-eslint/types": "^8.44.0", + "@typescript-eslint/tsconfig-utils": "^8.48.1", + "@typescript-eslint/types": "^8.48.1", "debug": "^4.3.4" }, "engines": { @@ -1303,14 +1270,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.44.0.tgz", - "integrity": "sha512-87Jv3E+al8wpD+rIdVJm/ItDBe/Im09zXIjFoipOjr5gHUhJmTzfFLuTJ/nPTMc2Srsroy4IBXwcTCHyRR7KzA==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.48.1.tgz", + "integrity": "sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.44.0", - "@typescript-eslint/visitor-keys": "8.44.0" + "@typescript-eslint/types": "8.48.1", + "@typescript-eslint/visitor-keys": "8.48.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1321,9 +1288,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.44.0.tgz", - "integrity": "sha512-x5Y0+AuEPqAInc6yd0n5DAcvtoQ/vyaGwuX5HE9n6qAefk1GaedqrLQF8kQGylLUb9pnZyLf+iEiL9fr8APDtQ==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.1.tgz", + "integrity": "sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==", "dev": true, "license": "MIT", "engines": { @@ -1338,15 +1305,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.44.0.tgz", - "integrity": "sha512-9cwsoSxJ8Sak67Be/hD2RNt/fsqmWnNE1iHohG8lxqLSNY8xNfyY7wloo5zpW3Nu9hxVgURevqfcH6vvKCt6yg==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.48.1.tgz", + "integrity": "sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.44.0", - "@typescript-eslint/typescript-estree": "8.44.0", - "@typescript-eslint/utils": "8.44.0", + "@typescript-eslint/types": "8.48.1", + "@typescript-eslint/typescript-estree": "8.48.1", + "@typescript-eslint/utils": "8.48.1", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -1363,9 +1330,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.44.0.tgz", - "integrity": "sha512-ZSl2efn44VsYM0MfDQe68RKzBz75NPgLQXuGypmym6QVOWL5kegTZuZ02xRAT9T+onqvM6T8CdQk0OwYMB6ZvA==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.1.tgz", + "integrity": "sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==", "dev": true, "license": "MIT", "engines": { @@ -1377,21 +1344,20 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.44.0.tgz", - "integrity": "sha512-lqNj6SgnGcQZwL4/SBJ3xdPEfcBuhCG8zdcwCPgYcmiPLgokiNDKlbPzCwEwu7m279J/lBYWtDYL+87OEfn8Jw==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.1.tgz", + "integrity": "sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.44.0", - "@typescript-eslint/tsconfig-utils": "8.44.0", - "@typescript-eslint/types": "8.44.0", - "@typescript-eslint/visitor-keys": "8.44.0", + "@typescript-eslint/project-service": "8.48.1", + "@typescript-eslint/tsconfig-utils": "8.48.1", + "@typescript-eslint/types": "8.48.1", + "@typescript-eslint/visitor-keys": "8.48.1", "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", + "tinyglobby": "^0.2.15", "ts-api-utils": "^2.1.0" }, "engines": { @@ -1432,16 +1398,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.44.0.tgz", - "integrity": "sha512-nktOlVcg3ALo0mYlV+L7sWUD58KG4CMj1rb2HUVOO4aL3K/6wcD+NERqd0rrA5Vg06b42YhF6cFxeixsp9Riqg==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.48.1.tgz", + "integrity": "sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.44.0", - "@typescript-eslint/types": "8.44.0", - "@typescript-eslint/typescript-estree": "8.44.0" + "@typescript-eslint/scope-manager": "8.48.1", + "@typescript-eslint/types": "8.48.1", + "@typescript-eslint/typescript-estree": "8.48.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1456,13 +1422,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.44.0.tgz", - "integrity": "sha512-zaz9u8EJ4GBmnehlrpoKvj/E3dNbuQ7q0ucyZImm3cLqJ8INTc970B1qEqDX/Rzq65r3TvVTN7kHWPBoyW7DWw==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.1.tgz", + "integrity": "sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.44.0", + "@typescript-eslint/types": "8.48.1", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -1628,6 +1594,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1738,19 +1705,6 @@ "concat-map": "0.0.1" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -1950,9 +1904,9 @@ "license": "MIT" }, "node_modules/esbuild": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", - "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.1.tgz", + "integrity": "sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1963,32 +1917,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.9", - "@esbuild/android-arm": "0.25.9", - "@esbuild/android-arm64": "0.25.9", - "@esbuild/android-x64": "0.25.9", - "@esbuild/darwin-arm64": "0.25.9", - "@esbuild/darwin-x64": "0.25.9", - "@esbuild/freebsd-arm64": "0.25.9", - "@esbuild/freebsd-x64": "0.25.9", - "@esbuild/linux-arm": "0.25.9", - "@esbuild/linux-arm64": "0.25.9", - "@esbuild/linux-ia32": "0.25.9", - "@esbuild/linux-loong64": "0.25.9", - "@esbuild/linux-mips64el": "0.25.9", - "@esbuild/linux-ppc64": "0.25.9", - "@esbuild/linux-riscv64": "0.25.9", - "@esbuild/linux-s390x": "0.25.9", - "@esbuild/linux-x64": "0.25.9", - "@esbuild/netbsd-arm64": "0.25.9", - "@esbuild/netbsd-x64": "0.25.9", - "@esbuild/openbsd-arm64": "0.25.9", - "@esbuild/openbsd-x64": "0.25.9", - "@esbuild/openharmony-arm64": "0.25.9", - "@esbuild/sunos-x64": "0.25.9", - "@esbuild/win32-arm64": "0.25.9", - "@esbuild/win32-ia32": "0.25.9", - "@esbuild/win32-x64": "0.25.9" + "@esbuild/aix-ppc64": "0.27.1", + "@esbuild/android-arm": "0.27.1", + "@esbuild/android-arm64": "0.27.1", + "@esbuild/android-x64": "0.27.1", + "@esbuild/darwin-arm64": "0.27.1", + "@esbuild/darwin-x64": "0.27.1", + "@esbuild/freebsd-arm64": "0.27.1", + "@esbuild/freebsd-x64": "0.27.1", + "@esbuild/linux-arm": "0.27.1", + "@esbuild/linux-arm64": "0.27.1", + "@esbuild/linux-ia32": "0.27.1", + "@esbuild/linux-loong64": "0.27.1", + "@esbuild/linux-mips64el": "0.27.1", + "@esbuild/linux-ppc64": "0.27.1", + "@esbuild/linux-riscv64": "0.27.1", + "@esbuild/linux-s390x": "0.27.1", + "@esbuild/linux-x64": "0.27.1", + "@esbuild/netbsd-arm64": "0.27.1", + "@esbuild/netbsd-x64": "0.27.1", + "@esbuild/openbsd-arm64": "0.27.1", + "@esbuild/openbsd-x64": "0.27.1", + "@esbuild/openharmony-arm64": "0.27.1", + "@esbuild/sunos-x64": "0.27.1", + "@esbuild/win32-arm64": "0.27.1", + "@esbuild/win32-ia32": "0.27.1", + "@esbuild/win32-x64": "0.27.1" } }, "node_modules/escape-string-regexp": { @@ -2005,25 +1959,25 @@ } }, "node_modules/eslint": { - "version": "9.35.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.35.0.tgz", - "integrity": "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==", + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", + "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.0", - "@eslint/config-helpers": "^0.3.1", - "@eslint/core": "^0.15.2", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.35.0", - "@eslint/plugin-kit": "^0.3.5", + "@eslint/js": "9.39.1", + "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", @@ -2186,36 +2140,6 @@ "dev": true, "license": "MIT" }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -2230,16 +2154,6 @@ "dev": true, "license": "MIT" }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -2253,19 +2167,6 @@ "node": ">=16.0.0" } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -2350,9 +2251,9 @@ } }, "node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dev": true, "license": "ISC", "dependencies": { @@ -2516,16 +2417,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2611,9 +2502,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -2760,30 +2651,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2981,19 +2848,6 @@ "dev": true, "license": "ISC" }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -3043,27 +2897,6 @@ "node": ">=6" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -3084,17 +2917,6 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, "node_modules/rollup": { "version": "4.49.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.49.0.tgz", @@ -3135,30 +2957,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, "node_modules/sade": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", @@ -3501,6 +3299,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -3538,19 +3337,6 @@ "node": ">=14.0.0" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, "node_modules/ts-api-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", @@ -3565,13 +3351,14 @@ } }, "node_modules/tsx": { - "version": "4.20.5", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.5.tgz", - "integrity": "sha512-+wKjMNU9w/EaQayHXb7WA7ZaHY6hN8WgfvHNQ3t1PnU91/7O8TcTnIhCDYTZwnt8JsO9IBqZ30Ln1r7pPF52Aw==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "esbuild": "~0.25.0", + "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" }, "bin": { @@ -3603,6 +3390,7 @@ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3612,16 +3400,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.44.0.tgz", - "integrity": "sha512-ib7mCkYuIzYonCq9XWF5XNw+fkj2zg629PSa9KNIQ47RXFF763S5BIX4wqz1+FLPogTZoiw8KmCiRPRa8bL3qw==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.48.1.tgz", + "integrity": "sha512-FbOKN1fqNoXp1hIl5KYpObVrp0mCn+CLgn479nmu2IsRMrx2vyv74MmsBLVlhg8qVwNFGbXSp8fh1zp8pEoC2A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.44.0", - "@typescript-eslint/parser": "8.44.0", - "@typescript-eslint/typescript-estree": "8.44.0", - "@typescript-eslint/utils": "8.44.0" + "@typescript-eslint/eslint-plugin": "8.48.1", + "@typescript-eslint/parser": "8.48.1", + "@typescript-eslint/typescript-estree": "8.48.1", + "@typescript-eslint/utils": "8.48.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3636,9 +3424,9 @@ } }, "node_modules/undici-types": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.12.0.tgz", - "integrity": "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "dev": true, "license": "MIT" }, @@ -3653,11 +3441,12 @@ } }, "node_modules/vite": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.5.tgz", - "integrity": "sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==", + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.6.tgz", + "integrity": "sha512-tI2l/nFHC5rLh7+5+o7QjKjSR04ivXDF4jcgV0f/bTQ+OJiITy5S6gaynVsEM+7RqzufMnVbIon6Sr5x1SDYaQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -3750,6 +3539,490 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, "node_modules/vite/node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -3774,6 +4047,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -3787,6 +4061,7 @@ "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", diff --git a/lib/binding_web/package.json b/lib/binding_web/package.json index 8faf9ecb..1bc53aad 100644 --- a/lib/binding_web/package.json +++ b/lib/binding_web/package.json @@ -1,6 +1,6 @@ { "name": "web-tree-sitter", - "version": "0.26.0", + "version": "0.27.0", "description": "Tree-sitter bindings for the web", "repository": { "type": "git", @@ -69,17 +69,17 @@ "web-tree-sitter.d.cts.map" ], "devDependencies": { - "@eslint/js": "^9.20.0", - "@types/emscripten": "^1.40.0", - "@types/node": "^24.3.0", + "@eslint/js": "^9.39.1", + "@types/emscripten": "^1.41.5", + "@types/node": "^24.10.1", "@vitest/coverage-v8": "^3.0.5", "dts-buddy": "^0.6.2", - "esbuild": "^0.25.0", - "eslint": "^9.20.0", + "esbuild": "^0.27.1", + "eslint": "^9.39.1", "source-map": "^0.7.4", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", - "typescript-eslint": "^8.23.0", + "typescript-eslint": "^8.48.1", "vitest": "^3.0.5" }, "scripts": { diff --git a/lib/binding_web/src/finalization_registry.ts b/lib/binding_web/src/finalization_registry.ts new file mode 100644 index 00000000..5f9c45cc --- /dev/null +++ b/lib/binding_web/src/finalization_registry.ts @@ -0,0 +1,8 @@ +export function newFinalizer(handler: (value: T) => void): FinalizationRegistry | undefined { + try { + return new FinalizationRegistry(handler); + } catch(e) { + console.error('Unsupported FinalizationRegistry:', e); + return; + } +} diff --git a/lib/binding_web/src/lookahead_iterator.ts b/lib/binding_web/src/lookahead_iterator.ts index 92b4d28f..4dd6b296 100644 --- a/lib/binding_web/src/lookahead_iterator.ts +++ b/lib/binding_web/src/lookahead_iterator.ts @@ -1,5 +1,10 @@ import { C, Internal, assertInternal } from './constants'; import { Language } from './language'; +import { newFinalizer } from './finalization_registry'; + +const finalizer = newFinalizer((address: number) => { + C._ts_lookahead_iterator_delete(address); +}); export class LookaheadIterator implements Iterable { /** @internal */ @@ -13,6 +18,7 @@ export class LookaheadIterator implements Iterable { assertInternal(internal); this[0] = address; this.language = language; + finalizer?.register(this, address, this); } /** Get the current symbol of the lookahead iterator. */ @@ -27,6 +33,7 @@ export class LookaheadIterator implements Iterable { /** Delete the lookahead iterator, freeing its resources. */ delete(): void { + finalizer?.unregister(this); C._ts_lookahead_iterator_delete(this[0]); this[0] = 0; } diff --git a/lib/binding_web/src/parser.ts b/lib/binding_web/src/parser.ts index efcadf05..7e3c3b4a 100644 --- a/lib/binding_web/src/parser.ts +++ b/lib/binding_web/src/parser.ts @@ -3,6 +3,7 @@ import { Language } from './language'; import { marshalRange, unmarshalRange } from './marshal'; import { checkModule, initializeBinding } from './bindings'; import { Tree } from './tree'; +import { newFinalizer } from './finalization_registry'; /** * Options for parsing @@ -82,6 +83,11 @@ export let LANGUAGE_VERSION: number; */ export let MIN_COMPATIBLE_VERSION: number; +const finalizer = newFinalizer((addresses: number[]) => { + C._ts_parser_delete(addresses[0]); + C._free(addresses[1]); +}); + /** * A stateful object that is used to produce a {@link Tree} based on some * source code. @@ -117,6 +123,7 @@ export class Parser { */ constructor() { this.initialize(); + finalizer?.register(this, [this[0], this[1]], this); } /** @internal */ @@ -131,6 +138,7 @@ export class Parser { /** Delete the parser, freeing its resources. */ delete() { + finalizer?.unregister(this); C._ts_parser_delete(this[0]); C._free(this[1]); this[0] = 0; diff --git a/lib/binding_web/src/query.ts b/lib/binding_web/src/query.ts index 6f3064a8..e2994b14 100644 --- a/lib/binding_web/src/query.ts +++ b/lib/binding_web/src/query.ts @@ -3,6 +3,7 @@ import { Node } from './node'; import { marshalNode, unmarshalCaptures } from './marshal'; import { TRANSFER_BUFFER } from './parser'; import { Language } from './language'; +import { newFinalizer } from './finalization_registry'; const PREDICATE_STEP_TYPE_CAPTURE = 1; @@ -20,12 +21,32 @@ export interface QueryOptions { /** The end position of the range to query */ endPosition?: Point; + /** The start position of the range to query Only the matches that are fully + * contained within provided range will be returned. + **/ + startContainingPosition?: Point; + + /** The end position of the range to query Only the matches that are fully + * contained within provided range will be returned. + **/ + endContainingPosition?: Point; + /** The start index of the range to query */ startIndex?: number; /** The end index of the range to query */ endIndex?: number; + /** The start index of the range to query Only the matches that are fully + * contained within provided range will be returned. + **/ + startContainingIndex?: number; + + /** The end index of the range to query Only the matches that are fully + * contained within provided range will be returned. + **/ + endContainingIndex?: number; + /** * The maximum number of in-progress matches for this query. * The limit must be > 0 and <= 65536. @@ -486,6 +507,10 @@ function parsePattern( } } +const finalizer = newFinalizer((address: number) => { + C._ts_query_delete(address); +}); + export class Query { /** @internal */ private [0] = 0; // Internal handle for Wasm @@ -667,10 +692,12 @@ export class Query { this.assertedProperties = assertedProperties; this.refutedProperties = refutedProperties; this.exceededMatchLimit = false; + finalizer?.register(this, address, this); } /** Delete the query, freeing its resources. */ delete(): void { + finalizer?.unregister(this); C._ts_query_delete(this[0]); this[0] = 0; } @@ -695,6 +722,10 @@ export class Query { const endPosition = options.endPosition ?? ZERO_POINT; const startIndex = options.startIndex ?? 0; const endIndex = options.endIndex ?? 0; + const startContainingPosition = options.startContainingPosition ?? ZERO_POINT; + const endContainingPosition = options.endContainingPosition ?? ZERO_POINT; + const startContainingIndex = options.startContainingIndex ?? 0; + const endContainingIndex = options.endContainingIndex ?? 0; const matchLimit = options.matchLimit ?? 0xFFFFFFFF; const maxStartDepth = options.maxStartDepth ?? 0xFFFFFFFF; const progressCallback = options.progressCallback; @@ -715,6 +746,18 @@ export class Query { throw new Error('`startPosition` cannot be greater than `endPosition`'); } + if (endContainingIndex !== 0 && startContainingIndex > endContainingIndex) { + throw new Error('`startContainingIndex` cannot be greater than `endContainingIndex`'); + } + + if (endContainingPosition !== ZERO_POINT && ( + startContainingPosition.row > endContainingPosition.row || + (startContainingPosition.row === endContainingPosition.row && + startContainingPosition.column > endContainingPosition.column) + )) { + throw new Error('`startContainingPosition` cannot be greater than `endContainingPosition`'); + } + if (progressCallback) { C.currentQueryProgressCallback = progressCallback; } @@ -730,6 +773,12 @@ export class Query { endPosition.column, startIndex, endIndex, + startContainingPosition.row, + startContainingPosition.column, + endContainingPosition.row, + endContainingPosition.column, + startContainingIndex, + endContainingIndex, matchLimit, maxStartDepth, ); @@ -788,6 +837,10 @@ export class Query { const endPosition = options.endPosition ?? ZERO_POINT; const startIndex = options.startIndex ?? 0; const endIndex = options.endIndex ?? 0; + const startContainingPosition = options.startContainingPosition ?? ZERO_POINT; + const endContainingPosition = options.endContainingPosition ?? ZERO_POINT; + const startContainingIndex = options.startContainingIndex ?? 0; + const endContainingIndex = options.endContainingIndex ?? 0; const matchLimit = options.matchLimit ?? 0xFFFFFFFF; const maxStartDepth = options.maxStartDepth ?? 0xFFFFFFFF; const progressCallback = options.progressCallback; @@ -808,6 +861,18 @@ export class Query { throw new Error('`startPosition` cannot be greater than `endPosition`'); } + if (endContainingIndex !== 0 && startContainingIndex > endContainingIndex) { + throw new Error('`startContainingIndex` cannot be greater than `endContainingIndex`'); + } + + if (endContainingPosition !== ZERO_POINT && ( + startContainingPosition.row > endContainingPosition.row || + (startContainingPosition.row === endContainingPosition.row && + startContainingPosition.column > endContainingPosition.column) + )) { + throw new Error('`startContainingPosition` cannot be greater than `endContainingPosition`'); + } + if (progressCallback) { C.currentQueryProgressCallback = progressCallback; } @@ -823,6 +888,12 @@ export class Query { endPosition.column, startIndex, endIndex, + startContainingPosition.row, + startContainingPosition.column, + endContainingPosition.row, + endContainingPosition.column, + startContainingIndex, + endContainingIndex, matchLimit, maxStartDepth, ); diff --git a/lib/binding_web/src/tree.ts b/lib/binding_web/src/tree.ts index 7a251440..f6a7aaf3 100644 --- a/lib/binding_web/src/tree.ts +++ b/lib/binding_web/src/tree.ts @@ -5,6 +5,7 @@ import { TreeCursor } from './tree_cursor'; import { marshalEdit, marshalPoint, unmarshalNode, unmarshalRange } from './marshal'; import { TRANSFER_BUFFER } from './parser'; import { Edit } from './edit'; +import { newFinalizer } from './finalization_registry'; /** @internal */ export function getText(tree: Tree, startIndex: number, endIndex: number, startPosition: Point): string { @@ -28,6 +29,10 @@ export function getText(tree: Tree, startIndex: number, endIndex: number, startP return result ?? ''; } +const finalizer = newFinalizer((address: number) => { + C._ts_tree_delete(address); +}); + /** A tree that represents the syntactic structure of a source code file. */ export class Tree { /** @internal */ @@ -45,6 +50,7 @@ export class Tree { this[0] = address; this.language = language; this.textCallback = textCallback; + finalizer?.register(this, address, this); } /** Create a shallow copy of the syntax tree. This is very fast. */ @@ -55,6 +61,7 @@ export class Tree { /** Delete the syntax tree, freeing its resources. */ delete(): void { + finalizer?.unregister(this); C._ts_tree_delete(this[0]); this[0] = 0; } diff --git a/lib/binding_web/src/tree_cursor.ts b/lib/binding_web/src/tree_cursor.ts index 7562bb7f..978a86dc 100644 --- a/lib/binding_web/src/tree_cursor.ts +++ b/lib/binding_web/src/tree_cursor.ts @@ -3,6 +3,11 @@ import { marshalNode, marshalPoint, marshalTreeCursor, unmarshalNode, unmarshalP import { Node } from './node'; import { TRANSFER_BUFFER } from './parser'; import { getText, Tree } from './tree'; +import { newFinalizer } from './finalization_registry'; + +const finalizer = newFinalizer((address: number) => { + C._ts_tree_cursor_delete_wasm(address); +}); /** A stateful object for walking a syntax {@link Tree} efficiently. */ export class TreeCursor { @@ -30,6 +35,7 @@ export class TreeCursor { assertInternal(internal); this.tree = tree; unmarshalTreeCursor(this); + finalizer?.register(this, this.tree[0], this); } /** Creates a deep copy of the tree cursor. This allocates new memory. */ @@ -42,6 +48,7 @@ export class TreeCursor { /** Delete the tree cursor, freeing its resources. */ delete(): void { + finalizer?.unregister(this); marshalTreeCursor(this); C._ts_tree_cursor_delete_wasm(this.tree[0]); this[0] = this[1] = this[2] = 0; diff --git a/lib/binding_web/test/memory.test.ts b/lib/binding_web/test/memory.test.ts new file mode 100644 index 00000000..46238934 --- /dev/null +++ b/lib/binding_web/test/memory.test.ts @@ -0,0 +1,74 @@ +import { describe, expect, it } from 'vitest'; +import { gc, event, Finalizer } from './memory'; + +// hijack finalization registry before import web-tree-sitter +globalThis.FinalizationRegistry = Finalizer; + +describe('Memory Management', () => { + describe('call .delete()', () => { + it('test free memory manually', async () => { + const timer = setInterval(() => { + gc(); + }, 100); + let done = 0; + event.on('gc', () => { + done++; + }); + await (async () => { + const { JavaScript } = await (await import('./helper')).default; + const { Parser, Query } = await import('../src'); + const parser = new Parser(); + parser.setLanguage(JavaScript); + const tree = parser.parse('1+1')!; + const copyTree = tree.copy(); + const cursor = tree.walk(); + const copyCursor = cursor.copy(); + const lookaheadIterator = JavaScript.lookaheadIterator(cursor.currentNode.nextParseState)!; + const query = new Query(JavaScript, '(identifier) @element'); + parser.delete(); + tree.delete(); + copyTree.delete(); + cursor.delete(); + copyCursor.delete(); + lookaheadIterator.delete(); + query.delete(); + })(); + // wait for gc + await new Promise((resolve) => setTimeout(resolve, 1000)); + clearInterval(timer); + // expect no gc event fired + expect(done).toBe(0); + }); + }); + + describe('do not call .delete()', () => { + it('test free memory automatically', async () => { + const timer = setInterval(() => { + gc(); + }, 100); + let done = 0; + const promise = new Promise((resolve) => { + event.on('gc', () => { + if (++done === 7) { + resolve(undefined); + clearInterval(timer); + } + console.log('free memory times: ', done); + }); + }); + await (async () => { + const { JavaScript } = await (await import('./helper')).default; + const { Parser, Query } = await import('../src'); + const parser = new Parser(); // 1 + parser.setLanguage(JavaScript); + const tree = parser.parse('1+1')!; // 2 + tree.copy(); // 3 + const cursor = tree.walk(); // 4 + cursor.copy(); // 5 + JavaScript.lookaheadIterator(cursor.currentNode.nextParseState)!; // 6 + new Query(JavaScript, '(identifier) @element'); // 7 + })(); + await promise; + }); + }); +}); diff --git a/lib/binding_web/test/memory.ts b/lib/binding_web/test/memory.ts new file mode 100644 index 00000000..62cb8b7d --- /dev/null +++ b/lib/binding_web/test/memory.ts @@ -0,0 +1,20 @@ +import { EventEmitter } from 'events'; +import { Session } from 'inspector'; + +const session = new Session(); +session.connect(); + +export function gc() { + session.post('HeapProfiler.collectGarbage'); +} + +export const event = new EventEmitter(); + +export class Finalizer extends FinalizationRegistry { + constructor(handler: (value: T) => void) { + super((value) => { + handler(value); + event.emit('gc'); + }); + } +} diff --git a/lib/binding_web/test/memory_unsupported.test.ts b/lib/binding_web/test/memory_unsupported.test.ts new file mode 100644 index 00000000..cc1f69bf --- /dev/null +++ b/lib/binding_web/test/memory_unsupported.test.ts @@ -0,0 +1,25 @@ +import { describe, it } from 'vitest'; + +describe('FinalizationRegistry is unsupported', () => { + it('test FinalizationRegistry is unsupported', async () => { + // @ts-expect-error: test FinalizationRegistry is not supported + globalThis.FinalizationRegistry = undefined; + const { JavaScript } = await (await import('./helper')).default; + const { Parser, Query } = await import('../src'); + const parser = new Parser(); + parser.setLanguage(JavaScript); + const tree = parser.parse('1+1')!; + const copyTree = tree.copy(); + const cursor = tree.walk(); + const copyCursor = cursor.copy(); + const lookaheadIterator = JavaScript.lookaheadIterator(cursor.currentNode.nextParseState)!; + const query = new Query(JavaScript, '(identifier) @element'); + parser.delete(); + tree.delete(); + copyTree.delete(); + cursor.delete(); + copyCursor.delete(); + lookaheadIterator.delete(); + query.delete(); + }); +}); diff --git a/lib/binding_web/test/query.test.ts b/lib/binding_web/test/query.test.ts index ad6a6660..f90e9464 100644 --- a/lib/binding_web/test/query.test.ts +++ b/lib/binding_web/test/query.test.ts @@ -96,6 +96,64 @@ describe('Query', () => { ]); }); + it('can search in contained within point ranges', () => { + tree = parser.parse(`[ + {"key1": "value1"}, + {"key2": "value2"}, + {"key3": "value3"}, + {"key4": "value4"}, + {"key5": "value5"}, + {"key6": "value6"}, + {"key7": "value7"}, + {"key8": "value8"}, + {"key9": "value9"}, + {"key10": "value10"}, + {"key11": "value11"}, + {"key12": "value12"}, +]`)!; + query = new Query(JavaScript, '("[" @l_bracket "]" @r_bracket) ("{" @l_brace "}" @r_brace)'); + const matches = query.matches( + tree.rootNode, + { + startContainingPosition: { row: 5, column: 0 }, + endContainingPosition: { row: 7, column: 0 }, + } + ); + expect(formatMatches(matches)).toEqual([ + { patternIndex: 1, captures: [{ patternIndex: 1, name: 'l_brace', text: '{' }, { patternIndex: 1, name: 'r_brace', text: '}' },] }, + { patternIndex: 1, captures: [{ patternIndex: 1, name: 'l_brace', text: '{' }, { patternIndex: 1, name: 'r_brace', text: '}' },] }, + ]); + }); + + it('can search in contained within byte ranges', () => { + tree = parser.parse(`[ + {"key1": "value1"}, + {"key2": "value2"}, + {"key3": "value3"}, + {"key4": "value4"}, + {"key5": "value5"}, + {"key6": "value6"}, + {"key7": "value7"}, + {"key8": "value8"}, + {"key9": "value9"}, + {"key10": "value10"}, + {"key11": "value11"}, + {"key12": "value12"}, +]`)!; + query = new Query(JavaScript, '("[" @l_bracket "]" @r_bracket) ("{" @l_brace "}" @r_brace)'); + const matches = query.matches( + tree.rootNode, + { + startContainingIndex: 290, + endContainingIndex: 432, + } + ); + expect(formatMatches(matches)).toEqual([ + { patternIndex: 1, captures: [{ patternIndex: 1, name: 'l_brace', text: '{' }, { patternIndex: 1, name: 'r_brace', text: '}' },] }, + { patternIndex: 1, captures: [{ patternIndex: 1, name: 'l_brace', text: '{' }, { patternIndex: 1, name: 'r_brace', text: '}' },] }, + ]); + }); + it('handles predicates that compare the text of capture to literal strings', () => { tree = parser.parse(` giraffe(1, 2, []); diff --git a/lib/include/tree_sitter/api.h b/lib/include/tree_sitter/api.h index 264d405d..22c85d48 100644 --- a/lib/include/tree_sitter/api.h +++ b/lib/include/tree_sitter/api.h @@ -1101,6 +1101,28 @@ bool ts_query_cursor_set_byte_range(TSQueryCursor *self, uint32_t start_byte, ui */ bool ts_query_cursor_set_point_range(TSQueryCursor *self, TSPoint start_point, TSPoint end_point); +/** + * Set the byte range within which all matches must be fully contained. + * + * Set the range of bytes in which matches will be searched for. In contrast to + * `ts_query_cursor_set_byte_range`, this will restrict the query cursor to only return + * matches where _all_ nodes are _fully_ contained within the given range. Both functions + * can be used together, e.g. to search for any matches that intersect line 5000, as + * long as they are fully contained within lines 4500-5500 + */ +bool ts_query_cursor_set_containing_byte_range(TSQueryCursor *self, uint32_t start_byte, uint32_t end_byte); + +/** + * Set the point range within which all matches must be fully contained. + * + * Set the range of bytes in which matches will be searched for. In contrast to + * `ts_query_cursor_set_point_range`, this will restrict the query cursor to only return + * matches where _all_ nodes are _fully_ contained within the given range. Both functions + * can be used together, e.g. to search for any matches that intersect line 5000, as + * long as they are fully contained within lines 4500-5500 + */ +bool ts_query_cursor_set_containing_point_range(TSQueryCursor *self, TSPoint start_point, TSPoint end_point); + /** * Advance to the next match of the currently running query. * diff --git a/lib/src/query.c b/lib/src/query.c index 90dd30b6..e378910a 100644 --- a/lib/src/query.c +++ b/lib/src/query.c @@ -318,10 +318,8 @@ struct TSQueryCursor { CaptureListPool capture_list_pool; uint32_t depth; uint32_t max_start_depth; - uint32_t start_byte; - uint32_t end_byte; - TSPoint start_point; - TSPoint end_point; + TSRange included_range; + TSRange containing_range; uint32_t next_state_id; const TSQueryCursorOptions *query_options; TSQueryCursorState query_state; @@ -1336,7 +1334,7 @@ static void ts_query__perform_analysis( // of the query pattern. bool does_match = false; - // ERROR nodes can appear anywhere, so if the step is + // ERROR nodes can appear anywhere, so if the step is // looking for an ERROR node, consider it potentially matchable. if (step->symbol == ts_builtin_sym_error) { does_match = true; @@ -1483,6 +1481,7 @@ static bool ts_query__analyze_patterns(TSQuery *self, unsigned *error_offset) { // basic information about each step. Mark all of the steps that contain // captures, and record the indices of all of the steps that have child steps. Array(uint32_t) parent_step_indices = array_new(); + bool all_patterns_are_valid = true; for (unsigned i = 0; i < self->steps.size; i++) { QueryStep *step = array_get(&self->steps, i); if (step->depth == PATTERN_DONE_MARKER) { @@ -1510,8 +1509,45 @@ static bool ts_query__analyze_patterns(TSQuery *self, unsigned *error_offset) { has_children = true; } - if (has_children && !is_wildcard) { - array_push(&parent_step_indices, i); + if (has_children) { + if (!is_wildcard) { + array_push(&parent_step_indices, i); + } else if (step->supertype_symbol && self->language->abi_version >= LANGUAGE_VERSION_WITH_RESERVED_WORDS) { + // Look at the child steps to see if any aren't valid subtypes for this supertype. + uint32_t subtype_length; + const TSSymbol *subtypes = ts_language_subtypes( + self->language, + step->supertype_symbol, + &subtype_length + ); + + for (unsigned j = i + 1; j < self->steps.size; j++) { + QueryStep *child_step = array_get(&self->steps, j); + if (child_step->depth == PATTERN_DONE_MARKER || child_step->depth <= step->depth) { + break; + } + if (child_step->depth == step->depth + 1 && child_step->symbol != WILDCARD_SYMBOL) { + bool is_valid_subtype = false; + for (uint32_t k = 0; k < subtype_length; k++) { + if (child_step->symbol == subtypes[k]) { + is_valid_subtype = true; + break; + } + } + + if (!is_valid_subtype) { + for (unsigned offset_idx = 0; offset_idx < self->step_offsets.size; offset_idx++) { + StepOffset *step_offset = array_get(&self->step_offsets, offset_idx); + if (step_offset->step_index >= j) { + *error_offset = step_offset->byte_offset; + all_patterns_are_valid = false; + goto supertype_cleanup; + } + } + } + } + } + } } } @@ -1684,7 +1720,6 @@ static bool ts_query__analyze_patterns(TSQuery *self, unsigned *error_offset) { // For each non-terminal pattern, determine if the pattern can successfully match, // and identify all of the possible children within the pattern where matching could fail. - bool all_patterns_are_valid = true; QueryAnalysis analysis = query_analysis__new(); for (unsigned i = 0; i < parent_step_indices.size; i++) { uint16_t parent_step_index = *array_get(&parent_step_indices, i); @@ -1759,8 +1794,13 @@ static bool ts_query__analyze_patterns(TSQuery *self, unsigned *error_offset) { // If this pattern cannot match, store the pattern index so that it can be // returned to the caller. if (analysis.finished_parent_symbols.size == 0) { - ts_assert(analysis.final_step_indices.size > 0); - uint16_t impossible_step_index = *array_back(&analysis.final_step_indices); + uint16_t impossible_step_index; + if (analysis.final_step_indices.size > 0) { + impossible_step_index = *array_back(&analysis.final_step_indices); + } else { + // If there isn't a final step, then that means the parent step itself is unreachable. + impossible_step_index = parent_step_index; + } uint32_t j, impossible_exists; array_search_sorted_by(&self->step_offsets, .step_index, impossible_step_index, &j, &impossible_exists); if (j >= self->step_offsets.size) j = self->step_offsets.size - 1; @@ -1957,11 +1997,13 @@ static bool ts_query__analyze_patterns(TSQuery *self, unsigned *error_offset) { array_delete(&subgraphs); query_analysis__delete(&analysis); array_delete(&next_nodes); - array_delete(&non_rooted_pattern_start_steps); - array_delete(&parent_step_indices); array_delete(&predicate_capture_ids); state_predecessor_map_delete(&predecessor_map); +supertype_cleanup: + array_delete(&non_rooted_pattern_start_steps); + array_delete(&parent_step_indices); + return all_patterns_are_valid; } @@ -2408,8 +2450,7 @@ static TSQueryError ts_query__parse_pattern( step->is_named = true; } - stream_skip_whitespace(stream); - + // Parse a supertype symbol if (stream->next == '/') { if (!step->supertype_symbol) { stream_reset(stream, node_name - 1); // reset to the start of the node @@ -2417,20 +2458,31 @@ static TSQueryError ts_query__parse_pattern( } stream_advance(stream); - if (!stream_is_ident_start(stream)) { + + const char *subtype_node_name = stream->input; + + if (stream_is_ident_start(stream)) { // Named node + stream_scan_identifier(stream); + uint32_t length = (uint32_t)(stream->input - subtype_node_name); + step->symbol = ts_language_symbol_for_name( + self->language, + subtype_node_name, + length, + true + ); + } else if (stream->next == '"') { // Anonymous leaf node + TSQueryError e = ts_query__parse_string_literal(self, stream); + if (e) return e; + step->symbol = ts_language_symbol_for_name( + self->language, + self->string_buffer.contents, + self->string_buffer.size, + false + ); + } else { return TSQueryErrorSyntax; } - const char *subtype_node_name = stream->input; - stream_scan_identifier(stream); - uint32_t length = (uint32_t)(stream->input - subtype_node_name); - - step->symbol = ts_language_symbol_for_name( - self->language, - subtype_node_name, - length, - true - ); if (!step->symbol) { stream_reset(stream, subtype_node_name); return TSQueryErrorNodeType; @@ -2460,10 +2512,10 @@ static TSQueryError ts_query__parse_pattern( return TSQueryErrorStructure; } } - - stream_skip_whitespace(stream); } + stream_skip_whitespace(stream); + // Parse the child patterns bool child_is_immediate = false; uint16_t last_child_step_index = 0; @@ -2682,12 +2734,6 @@ static TSQueryError ts_query__parse_pattern( stream_advance(stream); stream_skip_whitespace(stream); - - QueryStep repeat_step = query_step__new(WILDCARD_SYMBOL, depth, false); - repeat_step.alternative_index = starting_step_index; - repeat_step.is_pass_through = true; - repeat_step.alternative_is_immediate = true; - array_push(&self->steps, repeat_step); } // Parse the zero-or-more repetition operator. @@ -2696,21 +2742,6 @@ static TSQueryError ts_query__parse_pattern( stream_advance(stream); stream_skip_whitespace(stream); - - QueryStep repeat_step = query_step__new(WILDCARD_SYMBOL, depth, false); - repeat_step.alternative_index = starting_step_index; - repeat_step.is_pass_through = true; - repeat_step.alternative_is_immediate = true; - array_push(&self->steps, repeat_step); - - // Stop when `step->alternative_index` is `NONE` or it points to - // `repeat_step` or beyond. Note that having just been pushed, - // `repeat_step` occupies slot `self->steps.size - 1`. - QueryStep *step = array_get(&self->steps, starting_step_index); - while (step->alternative_index != NONE && step->alternative_index < self->steps.size - 1) { - step = array_get(&self->steps, step->alternative_index); - } - step->alternative_index = self->steps.size; } // Parse the optional operator. @@ -2719,12 +2750,6 @@ static TSQueryError ts_query__parse_pattern( stream_advance(stream); stream_skip_whitespace(stream); - - QueryStep *step = array_get(&self->steps, starting_step_index); - while (step->alternative_index != NONE && step->alternative_index < self->steps.size) { - step = array_get(&self->steps, step->alternative_index); - } - step->alternative_index = self->steps.size; } // Parse an '@'-prefixed capture pattern @@ -2768,6 +2793,43 @@ static TSQueryError ts_query__parse_pattern( } } + QueryStep repeat_step; + QueryStep *step; + switch (quantifier) { + case TSQuantifierOneOrMore: + repeat_step = query_step__new(WILDCARD_SYMBOL, depth, false); + repeat_step.alternative_index = starting_step_index; + repeat_step.is_pass_through = true; + repeat_step.alternative_is_immediate = true; + array_push(&self->steps, repeat_step); + break; + case TSQuantifierZeroOrMore: + repeat_step = query_step__new(WILDCARD_SYMBOL, depth, false); + repeat_step.alternative_index = starting_step_index; + repeat_step.is_pass_through = true; + repeat_step.alternative_is_immediate = true; + array_push(&self->steps, repeat_step); + + // Stop when `step->alternative_index` is `NONE` or it points to + // `repeat_step` or beyond. Note that having just been pushed, + // `repeat_step` occupies slot `self->steps.size - 1`. + step = array_get(&self->steps, starting_step_index); + while (step->alternative_index != NONE && step->alternative_index < self->steps.size - 1) { + step = array_get(&self->steps, step->alternative_index); + } + step->alternative_index = self->steps.size; + break; + case TSQuantifierZeroOrOne: + step = array_get(&self->steps, starting_step_index); + while (step->alternative_index != NONE && step->alternative_index < self->steps.size) { + step = array_get(&self->steps, step->alternative_index); + } + step->alternative_index = self->steps.size; + break; + default: + break; + } + capture_quantifiers_mul(capture_quantifiers, quantifier); return 0; @@ -3091,10 +3153,18 @@ TSQueryCursor *ts_query_cursor_new(void) { .states = array_new(), .finished_states = array_new(), .capture_list_pool = capture_list_pool_new(), - .start_byte = 0, - .end_byte = UINT32_MAX, - .start_point = {0, 0}, - .end_point = POINT_MAX, + .included_range = { + .start_point = {0, 0}, + .end_point = POINT_MAX, + .start_byte = 0, + .end_byte = UINT32_MAX, + }, + .containing_range = { + .start_point = {0, 0}, + .end_point = POINT_MAX, + .start_byte = 0, + .end_byte = UINT32_MAX, + }, .max_start_depth = UINT32_MAX, .operation_count = 0, }; @@ -3202,8 +3272,8 @@ bool ts_query_cursor_set_byte_range( if (start_byte > end_byte) { return false; } - self->start_byte = start_byte; - self->end_byte = end_byte; + self->included_range.start_byte = start_byte; + self->included_range.end_byte = end_byte; return true; } @@ -3218,8 +3288,40 @@ bool ts_query_cursor_set_point_range( if (point_gt(start_point, end_point)) { return false; } - self->start_point = start_point; - self->end_point = end_point; + self->included_range.start_point = start_point; + self->included_range.end_point = end_point; + return true; +} + +bool ts_query_cursor_set_containing_byte_range( + TSQueryCursor *self, + uint32_t start_byte, + uint32_t end_byte +) { + if (end_byte == 0) { + end_byte = UINT32_MAX; + } + if (start_byte > end_byte) { + return false; + } + self->containing_range.start_byte = start_byte; + self->containing_range.end_byte = end_byte; + return true; +} + +bool ts_query_cursor_set_containing_point_range( + TSQueryCursor *self, + TSPoint start_point, + TSPoint end_point +) { + if (end_point.row == 0 && end_point.column == 0) { + end_point = POINT_MAX; + } + if (point_gt(start_point, end_point)) { + return false; + } + self->containing_range.start_point = start_point; + self->containing_range.end_point = end_point; return true; } @@ -3250,8 +3352,8 @@ static bool ts_query_cursor__first_in_progress_capture( TSNode node = array_get(captures, state->consumed_capture_count)->node; if ( - ts_node_end_byte(node) <= self->start_byte || - point_lte(ts_node_end_point(node), self->start_point) + ts_node_end_byte(node) <= self->included_range.start_byte || + point_lte(ts_node_end_point(node), self->included_range.start_point) ) { state->consumed_capture_count++; i--; @@ -3576,6 +3678,31 @@ static inline bool ts_query_cursor__should_descend( return false; } +bool range_intersects(const TSRange *a, const TSRange *b) { + bool is_empty = a->start_byte == a->end_byte; + return ( + ( + a->end_byte > b->start_byte || + (is_empty && a->end_byte == b->start_byte) + ) && + ( + point_gt(a->end_point, b->start_point) || + (is_empty && point_eq(a->end_point, b->start_point)) + ) && + a->start_byte < b->end_byte && + point_lt(a->start_point, b->end_point) + ); +} + +bool range_within(const TSRange *a, const TSRange *b) { + return ( + a->start_byte >= b->start_byte && + point_gte(a->start_point, b->start_point) && + a->end_byte <= b->end_byte && + point_lte(a->end_point, b->end_point) + ); +} + // Walk the tree, processing patterns until at least one pattern finishes, // If one or more patterns finish, return `true` and store their states in the // `finished_states` array. Multiple patterns can finish on the same node. If @@ -3696,39 +3823,31 @@ static inline bool ts_query_cursor__advance( // Enter a new node. else { - // Get the properties of the current node. TSNode node = ts_tree_cursor_current_node(&self->cursor); TSNode parent_node = ts_tree_cursor_parent_node(&self->cursor); - uint32_t start_byte = ts_node_start_byte(node); - uint32_t end_byte = ts_node_end_byte(node); - TSPoint start_point = ts_node_start_point(node); - TSPoint end_point = ts_node_end_point(node); - bool is_empty = start_byte == end_byte; + bool parent_intersects_range = + ts_node_is_null(parent_node) || + range_intersects(&(TSRange) { + .start_point = ts_node_start_point(parent_node), + .end_point = ts_node_end_point(parent_node), + .start_byte = ts_node_start_byte(parent_node), + .end_byte = ts_node_end_byte(parent_node), + }, &self->included_range); + TSRange node_range = (TSRange) { + .start_point = ts_node_start_point(node), + .end_point = ts_node_end_point(node), + .start_byte = ts_node_start_byte(node), + .end_byte = ts_node_end_byte(node), + }; + bool node_intersects_range = + parent_intersects_range && range_intersects(&node_range, &self->included_range); + bool node_intersects_containing_range = + range_intersects(&node_range, &self->containing_range); + bool node_within_containing_range = + range_within(&node_range, &self->containing_range); - bool parent_precedes_range = !ts_node_is_null(parent_node) && ( - ts_node_end_byte(parent_node) <= self->start_byte || - point_lte(ts_node_end_point(parent_node), self->start_point) - ); - bool parent_follows_range = !ts_node_is_null(parent_node) && ( - ts_node_start_byte(parent_node) >= self->end_byte || - point_gte(ts_node_start_point(parent_node), self->end_point) - ); - bool node_precedes_range = - parent_precedes_range || - end_byte < self->start_byte || - point_lt(end_point, self->start_point) || - (!is_empty && end_byte == self->start_byte) || - (!is_empty && point_eq(end_point, self->start_point)); - - bool node_follows_range = parent_follows_range || ( - start_byte >= self->end_byte || - point_gte(start_point, self->end_point) - ); - bool parent_intersects_range = !parent_precedes_range && !parent_follows_range; - bool node_intersects_range = !node_precedes_range && !node_follows_range; - - if (self->on_visible_node) { + if (node_within_containing_range && self->on_visible_node) { TSSymbol symbol = ts_node_symbol(node); bool is_named = ts_node_is_named(node); bool is_missing = ts_node_is_missing(node); @@ -4118,7 +4237,7 @@ static inline bool ts_query_cursor__advance( } } - if (ts_query_cursor__should_descend(self, node_intersects_range)) { + if (node_intersects_containing_range && ts_query_cursor__should_descend(self, node_intersects_range)) { switch (ts_tree_cursor_goto_first_child_internal(&self->cursor)) { case TreeCursorStepVisible: self->depth++; @@ -4240,12 +4359,12 @@ bool ts_query_cursor_next_capture( TSNode node = array_get(captures, state->consumed_capture_count)->node; bool node_precedes_range = ( - ts_node_end_byte(node) <= self->start_byte || - point_lte(ts_node_end_point(node), self->start_point) + ts_node_end_byte(node) <= self->included_range.start_byte || + point_lte(ts_node_end_point(node), self->included_range.start_point) ); bool node_follows_range = ( - ts_node_start_byte(node) >= self->end_byte || - point_gte(ts_node_start_point(node), self->end_point) + ts_node_start_byte(node) >= self->included_range.end_byte || + point_gte(ts_node_start_point(node), self->included_range.end_point) ); bool node_outside_of_range = node_precedes_range || node_follows_range; diff --git a/lib/src/wasm/wasm-stdlib.h b/lib/src/wasm/wasm-stdlib.h index d7929f03..082ef4c2 100644 --- a/lib/src/wasm/wasm-stdlib.h +++ b/lib/src/wasm/wasm-stdlib.h @@ -1,999 +1,942 @@ unsigned char STDLIB_WASM[] = { - 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x1e, 0x06, 0x60, + 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x1a, 0x05, 0x60, + 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x03, 0x7f, 0x7f, 0x7f, 0x01, 0x7f, 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x60, 0x01, 0x7f, 0x00, 0x60, 0x00, 0x00, - 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x00, 0x01, 0x7f, 0x60, 0x03, 0x7f, - 0x7f, 0x7f, 0x01, 0x7f, 0x02, 0x9e, 0x01, 0x05, 0x03, 0x65, 0x6e, 0x76, - 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, 0x02, 0x03, 0x65, - 0x6e, 0x76, 0x19, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, - 0x74, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, - 0x61, 0x62, 0x6c, 0x65, 0x01, 0x70, 0x00, 0x01, 0x16, 0x77, 0x61, 0x73, - 0x69, 0x5f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x70, - 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x31, 0x08, 0x61, 0x72, 0x67, 0x73, - 0x5f, 0x67, 0x65, 0x74, 0x00, 0x00, 0x16, 0x77, 0x61, 0x73, 0x69, 0x5f, - 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x70, 0x72, 0x65, - 0x76, 0x69, 0x65, 0x77, 0x31, 0x0e, 0x61, 0x72, 0x67, 0x73, 0x5f, 0x73, - 0x69, 0x7a, 0x65, 0x73, 0x5f, 0x67, 0x65, 0x74, 0x00, 0x00, 0x16, 0x77, - 0x61, 0x73, 0x69, 0x5f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, - 0x5f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x31, 0x09, 0x70, 0x72, - 0x6f, 0x63, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x00, 0x01, 0x03, 0x2a, 0x29, - 0x02, 0x00, 0x02, 0x02, 0x01, 0x03, 0x01, 0x00, 0x00, 0x01, 0x04, 0x00, - 0x00, 0x01, 0x02, 0x02, 0x05, 0x05, 0x03, 0x03, 0x05, 0x05, 0x00, 0x03, - 0x00, 0x03, 0x05, 0x03, 0x05, 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x05, - 0x03, 0x03, 0x00, 0x03, 0x03, 0x06, 0x0d, 0x02, 0x7f, 0x01, 0x41, 0x80, - 0x80, 0x04, 0x0b, 0x7f, 0x00, 0x41, 0x00, 0x0b, 0x07, 0xad, 0x02, 0x1c, - 0x11, 0x5f, 0x5f, 0x77, 0x61, 0x73, 0x6d, 0x5f, 0x63, 0x61, 0x6c, 0x6c, - 0x5f, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x00, 0x03, 0x0f, 0x5f, 0x5f, 0x73, - 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x03, 0x00, 0x06, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x06, 0x0a, - 0x72, 0x65, 0x73, 0x65, 0x74, 0x5f, 0x68, 0x65, 0x61, 0x70, 0x00, 0x07, - 0x06, 0x6d, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x00, 0x08, 0x04, 0x66, 0x72, - 0x65, 0x65, 0x00, 0x09, 0x06, 0x63, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x00, - 0x0a, 0x06, 0x6d, 0x65, 0x6d, 0x73, 0x65, 0x74, 0x00, 0x14, 0x07, 0x72, - 0x65, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x00, 0x0b, 0x06, 0x6d, 0x65, 0x6d, - 0x63, 0x70, 0x79, 0x00, 0x13, 0x06, 0x73, 0x74, 0x72, 0x6c, 0x65, 0x6e, - 0x00, 0x15, 0x08, 0x69, 0x73, 0x77, 0x61, 0x6c, 0x6e, 0x75, 0x6d, 0x00, - 0x2b, 0x08, 0x69, 0x73, 0x77, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x00, 0x16, - 0x08, 0x69, 0x73, 0x77, 0x62, 0x6c, 0x61, 0x6e, 0x6b, 0x00, 0x22, 0x08, - 0x69, 0x73, 0x77, 0x64, 0x69, 0x67, 0x69, 0x74, 0x00, 0x23, 0x08, 0x69, - 0x73, 0x77, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x00, 0x20, 0x08, 0x69, 0x73, - 0x77, 0x73, 0x70, 0x61, 0x63, 0x65, 0x00, 0x2a, 0x08, 0x69, 0x73, 0x77, - 0x75, 0x70, 0x70, 0x65, 0x72, 0x00, 0x1e, 0x09, 0x69, 0x73, 0x77, 0x78, - 0x64, 0x69, 0x67, 0x69, 0x74, 0x00, 0x27, 0x08, 0x74, 0x6f, 0x77, 0x6c, - 0x6f, 0x77, 0x65, 0x72, 0x00, 0x1a, 0x08, 0x74, 0x6f, 0x77, 0x75, 0x70, - 0x70, 0x65, 0x72, 0x00, 0x1c, 0x06, 0x6d, 0x65, 0x6d, 0x63, 0x68, 0x72, - 0x00, 0x18, 0x06, 0x6d, 0x65, 0x6d, 0x63, 0x6d, 0x70, 0x00, 0x17, 0x07, - 0x6d, 0x65, 0x6d, 0x6d, 0x6f, 0x76, 0x65, 0x00, 0x1f, 0x06, 0x73, 0x74, - 0x72, 0x63, 0x6d, 0x70, 0x00, 0x19, 0x07, 0x73, 0x74, 0x72, 0x6e, 0x63, - 0x61, 0x74, 0x00, 0x24, 0x07, 0x73, 0x74, 0x72, 0x6e, 0x63, 0x6d, 0x70, - 0x00, 0x1d, 0x07, 0x73, 0x74, 0x72, 0x6e, 0x63, 0x70, 0x79, 0x00, 0x26, - 0x08, 0x01, 0x05, 0x0a, 0x8c, 0x2f, 0x29, 0x02, 0x00, 0x0b, 0x03, 0x00, - 0x00, 0x0b, 0x0d, 0x00, 0x41, 0xe8, 0xc2, 0x04, 0x41, 0x00, 0x41, 0x14, - 0xfc, 0x0b, 0x00, 0x0b, 0x51, 0x01, 0x01, 0x7f, 0x02, 0x40, 0x02, 0x40, - 0x23, 0x81, 0x80, 0x80, 0x80, 0x00, 0x41, 0xe8, 0xc2, 0x84, 0x80, 0x00, - 0x6a, 0x28, 0x02, 0x00, 0x0d, 0x00, 0x23, 0x81, 0x80, 0x80, 0x80, 0x00, - 0x41, 0xe8, 0xc2, 0x84, 0x80, 0x00, 0x6a, 0x41, 0x01, 0x36, 0x02, 0x00, - 0x10, 0x83, 0x80, 0x80, 0x80, 0x00, 0x10, 0x8d, 0x80, 0x80, 0x80, 0x00, - 0x21, 0x00, 0x10, 0x92, 0x80, 0x80, 0x80, 0x00, 0x20, 0x00, 0x0d, 0x01, - 0x0f, 0x0b, 0x00, 0x0b, 0x20, 0x00, 0x10, 0x90, 0x80, 0x80, 0x80, 0x00, - 0x00, 0x0b, 0x49, 0x01, 0x01, 0x7f, 0x23, 0x81, 0x80, 0x80, 0x80, 0x00, - 0x22, 0x01, 0x41, 0xf0, 0xc2, 0x84, 0x80, 0x00, 0x6a, 0x20, 0x00, 0x36, - 0x02, 0x00, 0x20, 0x01, 0x41, 0xec, 0xc2, 0x84, 0x80, 0x00, 0x6a, 0x20, - 0x00, 0x36, 0x02, 0x00, 0x3f, 0x00, 0x21, 0x00, 0x20, 0x01, 0x41, 0xf8, - 0xc2, 0x84, 0x80, 0x00, 0x6a, 0x41, 0x00, 0x36, 0x02, 0x00, 0x20, 0x01, - 0x41, 0xf4, 0xc2, 0x84, 0x80, 0x00, 0x6a, 0x20, 0x00, 0x41, 0x10, 0x74, - 0x36, 0x02, 0x00, 0x0b, 0xa8, 0x02, 0x01, 0x03, 0x7f, 0x02, 0x40, 0x23, - 0x81, 0x80, 0x80, 0x80, 0x00, 0x41, 0xf8, 0xc2, 0x84, 0x80, 0x00, 0x6a, - 0x28, 0x02, 0x00, 0x22, 0x01, 0x45, 0x0d, 0x00, 0x41, 0x00, 0x21, 0x02, - 0x02, 0x40, 0x02, 0x40, 0x20, 0x01, 0x28, 0x02, 0x00, 0x20, 0x00, 0x49, - 0x0d, 0x00, 0x20, 0x01, 0x21, 0x03, 0x0c, 0x01, 0x0b, 0x03, 0x40, 0x20, - 0x01, 0x28, 0x02, 0x04, 0x22, 0x03, 0x45, 0x0d, 0x02, 0x20, 0x01, 0x21, - 0x02, 0x20, 0x03, 0x21, 0x01, 0x20, 0x03, 0x28, 0x02, 0x00, 0x20, 0x00, - 0x49, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x02, 0x41, 0x04, 0x6a, 0x23, 0x81, - 0x80, 0x80, 0x80, 0x00, 0x41, 0xf8, 0xc2, 0x84, 0x80, 0x00, 0x6a, 0x20, - 0x02, 0x1b, 0x20, 0x03, 0x28, 0x02, 0x04, 0x36, 0x02, 0x00, 0x20, 0x03, - 0x41, 0x08, 0x6a, 0x0f, 0x0b, 0x02, 0x40, 0x02, 0x40, 0x23, 0x81, 0x80, - 0x80, 0x80, 0x00, 0x22, 0x01, 0x41, 0xf4, 0xc2, 0x84, 0x80, 0x00, 0x6a, - 0x28, 0x02, 0x00, 0x20, 0x01, 0x41, 0xf0, 0xc2, 0x84, 0x80, 0x00, 0x6a, - 0x28, 0x02, 0x00, 0x22, 0x01, 0x20, 0x00, 0x6a, 0x41, 0x0b, 0x6a, 0x41, - 0x7c, 0x71, 0x22, 0x03, 0x4f, 0x0d, 0x00, 0x41, 0x00, 0x21, 0x01, 0x20, - 0x03, 0x23, 0x81, 0x80, 0x80, 0x80, 0x00, 0x41, 0xec, 0xc2, 0x84, 0x80, - 0x00, 0x6a, 0x28, 0x02, 0x00, 0x6b, 0x41, 0x80, 0x80, 0x80, 0x02, 0x4a, - 0x0d, 0x01, 0x20, 0x00, 0x41, 0x7f, 0x6a, 0x41, 0x10, 0x76, 0x41, 0x01, - 0x6a, 0x40, 0x00, 0x41, 0x7f, 0x46, 0x0d, 0x01, 0x3f, 0x00, 0x21, 0x01, - 0x23, 0x81, 0x80, 0x80, 0x80, 0x00, 0x22, 0x02, 0x41, 0xf4, 0xc2, 0x84, - 0x80, 0x00, 0x6a, 0x20, 0x01, 0x41, 0x10, 0x74, 0x36, 0x02, 0x00, 0x20, - 0x02, 0x41, 0xf0, 0xc2, 0x84, 0x80, 0x00, 0x6a, 0x28, 0x02, 0x00, 0x21, - 0x01, 0x0b, 0x20, 0x01, 0x20, 0x00, 0x36, 0x02, 0x00, 0x23, 0x81, 0x80, - 0x80, 0x80, 0x00, 0x41, 0xf0, 0xc2, 0x84, 0x80, 0x00, 0x6a, 0x20, 0x03, - 0x36, 0x02, 0x00, 0x20, 0x01, 0x41, 0x08, 0x6a, 0x21, 0x01, 0x0b, 0x20, - 0x01, 0x0b, 0x5c, 0x01, 0x03, 0x7f, 0x02, 0x40, 0x20, 0x00, 0x45, 0x0d, - 0x00, 0x20, 0x00, 0x41, 0x78, 0x6a, 0x22, 0x01, 0x28, 0x02, 0x00, 0x21, - 0x02, 0x02, 0x40, 0x23, 0x81, 0x80, 0x80, 0x80, 0x00, 0x41, 0xf0, 0xc2, - 0x84, 0x80, 0x00, 0x6a, 0x22, 0x03, 0x28, 0x02, 0x00, 0x20, 0x00, 0x20, - 0x02, 0x6a, 0x41, 0x03, 0x6a, 0x41, 0x7c, 0x71, 0x46, 0x0d, 0x00, 0x20, - 0x00, 0x41, 0x7c, 0x6a, 0x23, 0x81, 0x80, 0x80, 0x80, 0x00, 0x41, 0xf8, - 0xc2, 0x84, 0x80, 0x00, 0x6a, 0x22, 0x03, 0x28, 0x02, 0x00, 0x36, 0x02, - 0x00, 0x0b, 0x20, 0x03, 0x20, 0x01, 0x36, 0x02, 0x00, 0x0b, 0x0b, 0x19, - 0x00, 0x20, 0x01, 0x20, 0x00, 0x6c, 0x22, 0x00, 0x10, 0x88, 0x80, 0x80, - 0x80, 0x00, 0x41, 0x00, 0x20, 0x00, 0x10, 0x94, 0x80, 0x80, 0x80, 0x00, - 0x0b, 0x6b, 0x01, 0x02, 0x7f, 0x02, 0x40, 0x20, 0x00, 0x45, 0x0d, 0x00, - 0x20, 0x00, 0x41, 0x78, 0x6a, 0x22, 0x02, 0x28, 0x02, 0x00, 0x21, 0x03, - 0x02, 0x40, 0x23, 0x81, 0x80, 0x80, 0x80, 0x00, 0x41, 0xf0, 0xc2, 0x84, - 0x80, 0x00, 0x6a, 0x28, 0x02, 0x00, 0x20, 0x00, 0x20, 0x03, 0x6a, 0x41, - 0x03, 0x6a, 0x41, 0x7c, 0x71, 0x47, 0x0d, 0x00, 0x23, 0x81, 0x80, 0x80, - 0x80, 0x00, 0x41, 0xf0, 0xc2, 0x84, 0x80, 0x00, 0x6a, 0x20, 0x02, 0x36, - 0x02, 0x00, 0x0c, 0x01, 0x0b, 0x20, 0x01, 0x10, 0x88, 0x80, 0x80, 0x80, - 0x00, 0x20, 0x00, 0x20, 0x02, 0x28, 0x02, 0x00, 0x10, 0x93, 0x80, 0x80, - 0x80, 0x00, 0x0f, 0x0b, 0x20, 0x01, 0x10, 0x88, 0x80, 0x80, 0x80, 0x00, - 0x0b, 0x0b, 0x00, 0x20, 0x00, 0x10, 0x90, 0x80, 0x80, 0x80, 0x00, 0x00, - 0x0b, 0xd5, 0x01, 0x01, 0x03, 0x7f, 0x23, 0x80, 0x80, 0x80, 0x80, 0x00, - 0x41, 0x10, 0x6b, 0x22, 0x00, 0x24, 0x80, 0x80, 0x80, 0x80, 0x00, 0x02, - 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x20, 0x00, 0x41, - 0x08, 0x6a, 0x20, 0x00, 0x41, 0x0c, 0x6a, 0x10, 0x8f, 0x80, 0x80, 0x80, - 0x00, 0x0d, 0x00, 0x20, 0x00, 0x28, 0x02, 0x08, 0x41, 0x01, 0x6a, 0x22, - 0x01, 0x45, 0x0d, 0x01, 0x20, 0x00, 0x28, 0x02, 0x0c, 0x10, 0x88, 0x80, - 0x80, 0x80, 0x00, 0x22, 0x02, 0x45, 0x0d, 0x02, 0x20, 0x01, 0x41, 0x04, - 0x10, 0x8a, 0x80, 0x80, 0x80, 0x00, 0x22, 0x01, 0x45, 0x0d, 0x03, 0x20, - 0x01, 0x20, 0x02, 0x10, 0x8e, 0x80, 0x80, 0x80, 0x00, 0x0d, 0x04, 0x20, - 0x00, 0x28, 0x02, 0x08, 0x20, 0x01, 0x10, 0x84, 0x80, 0x80, 0x80, 0x00, - 0x21, 0x01, 0x20, 0x00, 0x41, 0x10, 0x6a, 0x24, 0x80, 0x80, 0x80, 0x80, - 0x00, 0x20, 0x01, 0x0f, 0x0b, 0x41, 0xc7, 0x00, 0x10, 0x8c, 0x80, 0x80, - 0x80, 0x00, 0x00, 0x0b, 0x41, 0xc6, 0x00, 0x10, 0x8c, 0x80, 0x80, 0x80, - 0x00, 0x00, 0x0b, 0x41, 0xc6, 0x00, 0x10, 0x8c, 0x80, 0x80, 0x80, 0x00, - 0x00, 0x0b, 0x20, 0x02, 0x10, 0x89, 0x80, 0x80, 0x80, 0x00, 0x41, 0xc6, - 0x00, 0x10, 0x8c, 0x80, 0x80, 0x80, 0x00, 0x00, 0x0b, 0x20, 0x02, 0x10, - 0x89, 0x80, 0x80, 0x80, 0x00, 0x20, 0x01, 0x10, 0x89, 0x80, 0x80, 0x80, - 0x00, 0x41, 0xc7, 0x00, 0x10, 0x8c, 0x80, 0x80, 0x80, 0x00, 0x00, 0x0b, - 0x11, 0x00, 0x20, 0x00, 0x20, 0x01, 0x10, 0x80, 0x80, 0x80, 0x80, 0x00, - 0x41, 0xff, 0xff, 0x03, 0x71, 0x0b, 0x11, 0x00, 0x20, 0x00, 0x20, 0x01, - 0x10, 0x81, 0x80, 0x80, 0x80, 0x00, 0x41, 0xff, 0xff, 0x03, 0x71, 0x0b, - 0x0b, 0x00, 0x20, 0x00, 0x10, 0x82, 0x80, 0x80, 0x80, 0x00, 0x00, 0x0b, - 0x02, 0x00, 0x0b, 0x0e, 0x00, 0x10, 0x91, 0x80, 0x80, 0x80, 0x00, 0x10, - 0x91, 0x80, 0x80, 0x80, 0x00, 0x0b, 0xd4, 0x08, 0x01, 0x04, 0x7f, 0x02, - 0x40, 0x02, 0x40, 0x02, 0x40, 0x20, 0x02, 0x41, 0x20, 0x4b, 0x0d, 0x00, - 0x20, 0x01, 0x41, 0x03, 0x71, 0x45, 0x0d, 0x01, 0x20, 0x02, 0x45, 0x0d, - 0x01, 0x20, 0x00, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, - 0x02, 0x41, 0x7f, 0x6a, 0x21, 0x03, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x21, - 0x04, 0x20, 0x01, 0x41, 0x01, 0x6a, 0x22, 0x05, 0x41, 0x03, 0x71, 0x45, - 0x0d, 0x02, 0x20, 0x03, 0x45, 0x0d, 0x02, 0x20, 0x00, 0x41, 0x01, 0x6a, - 0x20, 0x01, 0x41, 0x01, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, - 0x02, 0x41, 0x7e, 0x6a, 0x21, 0x03, 0x20, 0x00, 0x41, 0x02, 0x6a, 0x21, - 0x04, 0x20, 0x01, 0x41, 0x02, 0x6a, 0x22, 0x05, 0x41, 0x03, 0x71, 0x45, - 0x0d, 0x02, 0x20, 0x03, 0x45, 0x0d, 0x02, 0x20, 0x00, 0x41, 0x02, 0x6a, - 0x20, 0x01, 0x41, 0x02, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, - 0x02, 0x41, 0x7d, 0x6a, 0x21, 0x03, 0x20, 0x00, 0x41, 0x03, 0x6a, 0x21, - 0x04, 0x20, 0x01, 0x41, 0x03, 0x6a, 0x22, 0x05, 0x41, 0x03, 0x71, 0x45, - 0x0d, 0x02, 0x20, 0x03, 0x45, 0x0d, 0x02, 0x20, 0x00, 0x41, 0x03, 0x6a, - 0x20, 0x01, 0x41, 0x03, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, - 0x02, 0x41, 0x7c, 0x6a, 0x21, 0x03, 0x20, 0x00, 0x41, 0x04, 0x6a, 0x21, - 0x04, 0x20, 0x01, 0x41, 0x04, 0x6a, 0x21, 0x05, 0x0c, 0x02, 0x0b, 0x20, - 0x00, 0x20, 0x01, 0x20, 0x02, 0xfc, 0x0a, 0x00, 0x00, 0x20, 0x00, 0x0f, - 0x0b, 0x20, 0x02, 0x21, 0x03, 0x20, 0x00, 0x21, 0x04, 0x20, 0x01, 0x21, - 0x05, 0x0b, 0x02, 0x40, 0x02, 0x40, 0x20, 0x04, 0x41, 0x03, 0x71, 0x22, - 0x02, 0x0d, 0x00, 0x02, 0x40, 0x02, 0x40, 0x20, 0x03, 0x41, 0x10, 0x4f, - 0x0d, 0x00, 0x20, 0x03, 0x21, 0x02, 0x0c, 0x01, 0x0b, 0x02, 0x40, 0x20, - 0x03, 0x41, 0x70, 0x6a, 0x22, 0x02, 0x41, 0x10, 0x71, 0x0d, 0x00, 0x20, - 0x04, 0x20, 0x05, 0x29, 0x02, 0x00, 0x37, 0x02, 0x00, 0x20, 0x04, 0x41, - 0x08, 0x6a, 0x20, 0x05, 0x41, 0x08, 0x6a, 0x29, 0x02, 0x00, 0x37, 0x02, - 0x00, 0x20, 0x04, 0x41, 0x10, 0x6a, 0x21, 0x04, 0x20, 0x05, 0x41, 0x10, - 0x6a, 0x21, 0x05, 0x20, 0x02, 0x21, 0x03, 0x0b, 0x20, 0x02, 0x41, 0x10, - 0x49, 0x0d, 0x00, 0x20, 0x03, 0x21, 0x02, 0x03, 0x40, 0x20, 0x04, 0x20, - 0x05, 0x29, 0x02, 0x00, 0x37, 0x02, 0x00, 0x20, 0x04, 0x41, 0x08, 0x6a, - 0x20, 0x05, 0x41, 0x08, 0x6a, 0x29, 0x02, 0x00, 0x37, 0x02, 0x00, 0x20, - 0x04, 0x41, 0x10, 0x6a, 0x20, 0x05, 0x41, 0x10, 0x6a, 0x29, 0x02, 0x00, - 0x37, 0x02, 0x00, 0x20, 0x04, 0x41, 0x18, 0x6a, 0x20, 0x05, 0x41, 0x18, - 0x6a, 0x29, 0x02, 0x00, 0x37, 0x02, 0x00, 0x20, 0x04, 0x41, 0x20, 0x6a, - 0x21, 0x04, 0x20, 0x05, 0x41, 0x20, 0x6a, 0x21, 0x05, 0x20, 0x02, 0x41, - 0x60, 0x6a, 0x22, 0x02, 0x41, 0x0f, 0x4b, 0x0d, 0x00, 0x0b, 0x0b, 0x02, - 0x40, 0x20, 0x02, 0x41, 0x08, 0x49, 0x0d, 0x00, 0x20, 0x04, 0x20, 0x05, - 0x29, 0x02, 0x00, 0x37, 0x02, 0x00, 0x20, 0x05, 0x41, 0x08, 0x6a, 0x21, - 0x05, 0x20, 0x04, 0x41, 0x08, 0x6a, 0x21, 0x04, 0x0b, 0x02, 0x40, 0x20, - 0x02, 0x41, 0x04, 0x71, 0x45, 0x0d, 0x00, 0x20, 0x04, 0x20, 0x05, 0x28, - 0x02, 0x00, 0x36, 0x02, 0x00, 0x20, 0x05, 0x41, 0x04, 0x6a, 0x21, 0x05, - 0x20, 0x04, 0x41, 0x04, 0x6a, 0x21, 0x04, 0x0b, 0x02, 0x40, 0x20, 0x02, - 0x41, 0x02, 0x71, 0x45, 0x0d, 0x00, 0x20, 0x04, 0x20, 0x05, 0x2f, 0x00, - 0x00, 0x3b, 0x00, 0x00, 0x20, 0x04, 0x41, 0x02, 0x6a, 0x21, 0x04, 0x20, - 0x05, 0x41, 0x02, 0x6a, 0x21, 0x05, 0x0b, 0x20, 0x02, 0x41, 0x01, 0x71, - 0x45, 0x0d, 0x01, 0x20, 0x04, 0x20, 0x05, 0x2d, 0x00, 0x00, 0x3a, 0x00, - 0x00, 0x20, 0x00, 0x0f, 0x0b, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, - 0x40, 0x02, 0x40, 0x20, 0x03, 0x41, 0x20, 0x49, 0x0d, 0x00, 0x20, 0x04, - 0x20, 0x05, 0x28, 0x02, 0x00, 0x22, 0x03, 0x3a, 0x00, 0x00, 0x02, 0x40, - 0x02, 0x40, 0x20, 0x02, 0x41, 0x7f, 0x6a, 0x0e, 0x03, 0x03, 0x00, 0x01, - 0x03, 0x0b, 0x20, 0x04, 0x41, 0x01, 0x6a, 0x20, 0x03, 0x41, 0x08, 0x76, - 0x3a, 0x00, 0x00, 0x20, 0x04, 0x41, 0x06, 0x6a, 0x20, 0x05, 0x41, 0x06, - 0x6a, 0x29, 0x01, 0x00, 0x37, 0x02, 0x00, 0x20, 0x04, 0x41, 0x02, 0x6a, - 0x20, 0x05, 0x41, 0x04, 0x6a, 0x28, 0x02, 0x00, 0x41, 0x10, 0x74, 0x20, - 0x03, 0x41, 0x10, 0x76, 0x72, 0x36, 0x02, 0x00, 0x20, 0x04, 0x41, 0x12, - 0x6a, 0x21, 0x02, 0x20, 0x05, 0x41, 0x12, 0x6a, 0x21, 0x01, 0x41, 0x0e, - 0x21, 0x06, 0x20, 0x05, 0x41, 0x0e, 0x6a, 0x28, 0x01, 0x00, 0x21, 0x05, - 0x41, 0x0e, 0x21, 0x03, 0x0c, 0x03, 0x0b, 0x20, 0x04, 0x41, 0x05, 0x6a, - 0x20, 0x05, 0x41, 0x05, 0x6a, 0x29, 0x00, 0x00, 0x37, 0x02, 0x00, 0x20, - 0x04, 0x41, 0x01, 0x6a, 0x20, 0x05, 0x41, 0x04, 0x6a, 0x28, 0x02, 0x00, - 0x41, 0x18, 0x74, 0x20, 0x03, 0x41, 0x08, 0x76, 0x72, 0x36, 0x02, 0x00, - 0x20, 0x04, 0x41, 0x11, 0x6a, 0x21, 0x02, 0x20, 0x05, 0x41, 0x11, 0x6a, - 0x21, 0x01, 0x41, 0x0d, 0x21, 0x06, 0x20, 0x05, 0x41, 0x0d, 0x6a, 0x28, - 0x00, 0x00, 0x21, 0x05, 0x41, 0x0f, 0x21, 0x03, 0x0c, 0x02, 0x0b, 0x02, - 0x40, 0x02, 0x40, 0x20, 0x03, 0x41, 0x10, 0x4f, 0x0d, 0x00, 0x20, 0x04, - 0x21, 0x02, 0x20, 0x05, 0x21, 0x01, 0x0c, 0x01, 0x0b, 0x20, 0x04, 0x20, - 0x05, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x04, 0x41, 0x01, 0x6a, - 0x20, 0x05, 0x41, 0x01, 0x6a, 0x28, 0x00, 0x00, 0x36, 0x00, 0x00, 0x20, - 0x04, 0x41, 0x05, 0x6a, 0x20, 0x05, 0x41, 0x05, 0x6a, 0x29, 0x00, 0x00, - 0x37, 0x00, 0x00, 0x20, 0x04, 0x41, 0x0d, 0x6a, 0x20, 0x05, 0x41, 0x0d, - 0x6a, 0x2f, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x20, 0x04, 0x41, 0x0f, 0x6a, - 0x20, 0x05, 0x41, 0x0f, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, - 0x04, 0x41, 0x10, 0x6a, 0x21, 0x02, 0x20, 0x05, 0x41, 0x10, 0x6a, 0x21, - 0x01, 0x0b, 0x20, 0x03, 0x41, 0x08, 0x71, 0x0d, 0x02, 0x0c, 0x03, 0x0b, - 0x20, 0x04, 0x41, 0x02, 0x6a, 0x20, 0x03, 0x41, 0x10, 0x76, 0x3a, 0x00, - 0x00, 0x20, 0x04, 0x41, 0x01, 0x6a, 0x20, 0x03, 0x41, 0x08, 0x76, 0x3a, - 0x00, 0x00, 0x20, 0x04, 0x41, 0x07, 0x6a, 0x20, 0x05, 0x41, 0x07, 0x6a, - 0x29, 0x00, 0x00, 0x37, 0x02, 0x00, 0x20, 0x04, 0x41, 0x03, 0x6a, 0x20, - 0x05, 0x41, 0x04, 0x6a, 0x28, 0x02, 0x00, 0x41, 0x08, 0x74, 0x20, 0x03, - 0x41, 0x18, 0x76, 0x72, 0x36, 0x02, 0x00, 0x20, 0x04, 0x41, 0x13, 0x6a, - 0x21, 0x02, 0x20, 0x05, 0x41, 0x13, 0x6a, 0x21, 0x01, 0x41, 0x0f, 0x21, - 0x06, 0x20, 0x05, 0x41, 0x0f, 0x6a, 0x28, 0x00, 0x00, 0x21, 0x05, 0x41, - 0x0d, 0x21, 0x03, 0x0b, 0x20, 0x04, 0x20, 0x06, 0x6a, 0x20, 0x05, 0x36, - 0x02, 0x00, 0x0b, 0x20, 0x02, 0x20, 0x01, 0x29, 0x00, 0x00, 0x37, 0x00, - 0x00, 0x20, 0x02, 0x41, 0x08, 0x6a, 0x21, 0x02, 0x20, 0x01, 0x41, 0x08, - 0x6a, 0x21, 0x01, 0x0b, 0x02, 0x40, 0x20, 0x03, 0x41, 0x04, 0x71, 0x45, - 0x0d, 0x00, 0x20, 0x02, 0x20, 0x01, 0x28, 0x00, 0x00, 0x36, 0x00, 0x00, - 0x20, 0x02, 0x41, 0x04, 0x6a, 0x21, 0x02, 0x20, 0x01, 0x41, 0x04, 0x6a, - 0x21, 0x01, 0x0b, 0x02, 0x40, 0x20, 0x03, 0x41, 0x02, 0x71, 0x45, 0x0d, - 0x00, 0x20, 0x02, 0x20, 0x01, 0x2f, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x20, - 0x02, 0x41, 0x02, 0x6a, 0x21, 0x02, 0x20, 0x01, 0x41, 0x02, 0x6a, 0x21, - 0x01, 0x0b, 0x20, 0x03, 0x41, 0x01, 0x71, 0x45, 0x0d, 0x00, 0x20, 0x02, - 0x20, 0x01, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x0b, 0x20, 0x00, 0x0b, - 0xac, 0x03, 0x02, 0x03, 0x7f, 0x01, 0x7e, 0x02, 0x40, 0x20, 0x02, 0x41, - 0x21, 0x49, 0x0d, 0x00, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0xfc, 0x0b, - 0x00, 0x20, 0x00, 0x0f, 0x0b, 0x02, 0x40, 0x20, 0x02, 0x45, 0x0d, 0x00, - 0x20, 0x00, 0x20, 0x01, 0x3a, 0x00, 0x00, 0x20, 0x00, 0x20, 0x02, 0x6a, - 0x22, 0x03, 0x41, 0x7f, 0x6a, 0x20, 0x01, 0x3a, 0x00, 0x00, 0x20, 0x02, - 0x41, 0x03, 0x49, 0x0d, 0x00, 0x20, 0x00, 0x41, 0x02, 0x6a, 0x20, 0x01, - 0x3a, 0x00, 0x00, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x20, 0x01, 0x3a, 0x00, - 0x00, 0x20, 0x03, 0x41, 0x7d, 0x6a, 0x20, 0x01, 0x3a, 0x00, 0x00, 0x20, - 0x03, 0x41, 0x7e, 0x6a, 0x20, 0x01, 0x3a, 0x00, 0x00, 0x20, 0x02, 0x41, - 0x07, 0x49, 0x0d, 0x00, 0x20, 0x00, 0x41, 0x03, 0x6a, 0x20, 0x01, 0x3a, - 0x00, 0x00, 0x20, 0x03, 0x41, 0x7c, 0x6a, 0x20, 0x01, 0x3a, 0x00, 0x00, - 0x20, 0x02, 0x41, 0x09, 0x49, 0x0d, 0x00, 0x20, 0x00, 0x41, 0x00, 0x20, - 0x00, 0x6b, 0x41, 0x03, 0x71, 0x22, 0x04, 0x6a, 0x22, 0x05, 0x20, 0x01, - 0x41, 0xff, 0x01, 0x71, 0x41, 0x81, 0x82, 0x84, 0x08, 0x6c, 0x22, 0x03, - 0x36, 0x02, 0x00, 0x20, 0x05, 0x20, 0x02, 0x20, 0x04, 0x6b, 0x41, 0x3c, - 0x71, 0x22, 0x01, 0x6a, 0x22, 0x02, 0x41, 0x7c, 0x6a, 0x20, 0x03, 0x36, - 0x02, 0x00, 0x20, 0x01, 0x41, 0x09, 0x49, 0x0d, 0x00, 0x20, 0x05, 0x41, - 0x08, 0x6a, 0x20, 0x03, 0x36, 0x02, 0x00, 0x20, 0x05, 0x41, 0x04, 0x6a, - 0x20, 0x03, 0x36, 0x02, 0x00, 0x20, 0x02, 0x41, 0x78, 0x6a, 0x20, 0x03, - 0x36, 0x02, 0x00, 0x20, 0x02, 0x41, 0x74, 0x6a, 0x20, 0x03, 0x36, 0x02, - 0x00, 0x20, 0x01, 0x41, 0x19, 0x49, 0x0d, 0x00, 0x20, 0x05, 0x41, 0x18, - 0x6a, 0x20, 0x03, 0x36, 0x02, 0x00, 0x20, 0x05, 0x41, 0x14, 0x6a, 0x20, - 0x03, 0x36, 0x02, 0x00, 0x20, 0x05, 0x41, 0x10, 0x6a, 0x20, 0x03, 0x36, - 0x02, 0x00, 0x20, 0x05, 0x41, 0x0c, 0x6a, 0x20, 0x03, 0x36, 0x02, 0x00, - 0x20, 0x02, 0x41, 0x70, 0x6a, 0x20, 0x03, 0x36, 0x02, 0x00, 0x20, 0x02, - 0x41, 0x6c, 0x6a, 0x20, 0x03, 0x36, 0x02, 0x00, 0x20, 0x02, 0x41, 0x68, - 0x6a, 0x20, 0x03, 0x36, 0x02, 0x00, 0x20, 0x02, 0x41, 0x64, 0x6a, 0x20, - 0x03, 0x36, 0x02, 0x00, 0x20, 0x01, 0x20, 0x05, 0x41, 0x04, 0x71, 0x41, - 0x18, 0x72, 0x22, 0x02, 0x6b, 0x22, 0x01, 0x41, 0x20, 0x49, 0x0d, 0x00, - 0x20, 0x03, 0xad, 0x42, 0x81, 0x80, 0x80, 0x80, 0x10, 0x7e, 0x21, 0x06, - 0x20, 0x05, 0x20, 0x02, 0x6a, 0x21, 0x02, 0x03, 0x40, 0x20, 0x02, 0x20, - 0x06, 0x37, 0x03, 0x00, 0x20, 0x02, 0x41, 0x18, 0x6a, 0x20, 0x06, 0x37, - 0x03, 0x00, 0x20, 0x02, 0x41, 0x10, 0x6a, 0x20, 0x06, 0x37, 0x03, 0x00, - 0x20, 0x02, 0x41, 0x08, 0x6a, 0x20, 0x06, 0x37, 0x03, 0x00, 0x20, 0x02, - 0x41, 0x20, 0x6a, 0x21, 0x02, 0x20, 0x01, 0x41, 0x60, 0x6a, 0x22, 0x01, - 0x41, 0x1f, 0x4b, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x00, 0x0b, 0xcf, 0x01, - 0x01, 0x03, 0x7f, 0x20, 0x00, 0x21, 0x01, 0x02, 0x40, 0x02, 0x40, 0x20, - 0x00, 0x41, 0x03, 0x71, 0x45, 0x0d, 0x00, 0x02, 0x40, 0x20, 0x00, 0x2d, - 0x00, 0x00, 0x0d, 0x00, 0x20, 0x00, 0x20, 0x00, 0x6b, 0x0f, 0x0b, 0x20, - 0x00, 0x41, 0x01, 0x6a, 0x22, 0x01, 0x41, 0x03, 0x71, 0x45, 0x0d, 0x00, - 0x20, 0x01, 0x2d, 0x00, 0x00, 0x45, 0x0d, 0x01, 0x20, 0x00, 0x41, 0x02, + 0x02, 0x7c, 0x04, 0x16, 0x77, 0x61, 0x73, 0x69, 0x5f, 0x73, 0x6e, 0x61, + 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, + 0x77, 0x31, 0x08, 0x61, 0x72, 0x67, 0x73, 0x5f, 0x67, 0x65, 0x74, 0x00, + 0x02, 0x16, 0x77, 0x61, 0x73, 0x69, 0x5f, 0x73, 0x6e, 0x61, 0x70, 0x73, + 0x68, 0x6f, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x31, + 0x0e, 0x61, 0x72, 0x67, 0x73, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x73, 0x5f, + 0x67, 0x65, 0x74, 0x00, 0x02, 0x16, 0x77, 0x61, 0x73, 0x69, 0x5f, 0x73, + 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x76, + 0x69, 0x65, 0x77, 0x31, 0x09, 0x70, 0x72, 0x6f, 0x63, 0x5f, 0x65, 0x78, + 0x69, 0x74, 0x00, 0x03, 0x03, 0x65, 0x6e, 0x76, 0x06, 0x6d, 0x65, 0x6d, + 0x6f, 0x72, 0x79, 0x02, 0x00, 0x02, 0x03, 0x1f, 0x1e, 0x04, 0x04, 0x04, + 0x03, 0x00, 0x03, 0x02, 0x02, 0x03, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x06, 0x08, 0x01, 0x7f, 0x01, 0x41, 0x80, 0x80, 0x04, + 0x0b, 0x07, 0xad, 0x02, 0x1c, 0x11, 0x5f, 0x5f, 0x77, 0x61, 0x73, 0x6d, + 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x5f, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x00, + 0x03, 0x0f, 0x5f, 0x5f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x03, 0x00, 0x06, 0x5f, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x00, 0x05, 0x0a, 0x72, 0x65, 0x73, 0x65, 0x74, 0x5f, 0x68, + 0x65, 0x61, 0x70, 0x00, 0x06, 0x06, 0x6d, 0x61, 0x6c, 0x6c, 0x6f, 0x63, + 0x00, 0x07, 0x04, 0x66, 0x72, 0x65, 0x65, 0x00, 0x08, 0x06, 0x63, 0x61, + 0x6c, 0x6c, 0x6f, 0x63, 0x00, 0x09, 0x07, 0x72, 0x65, 0x61, 0x6c, 0x6c, + 0x6f, 0x63, 0x00, 0x0a, 0x06, 0x73, 0x74, 0x72, 0x6c, 0x65, 0x6e, 0x00, + 0x0c, 0x08, 0x69, 0x73, 0x77, 0x61, 0x6c, 0x6e, 0x75, 0x6d, 0x00, 0x20, + 0x08, 0x69, 0x73, 0x77, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x00, 0x0d, 0x08, + 0x69, 0x73, 0x77, 0x62, 0x6c, 0x61, 0x6e, 0x6b, 0x00, 0x1a, 0x08, 0x69, + 0x73, 0x77, 0x64, 0x69, 0x67, 0x69, 0x74, 0x00, 0x1b, 0x08, 0x69, 0x73, + 0x77, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x00, 0x18, 0x08, 0x69, 0x73, 0x77, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x00, 0x1f, 0x08, 0x69, 0x73, 0x77, 0x75, + 0x70, 0x70, 0x65, 0x72, 0x00, 0x15, 0x09, 0x69, 0x73, 0x77, 0x78, 0x64, + 0x69, 0x67, 0x69, 0x74, 0x00, 0x1e, 0x08, 0x74, 0x6f, 0x77, 0x6c, 0x6f, + 0x77, 0x65, 0x72, 0x00, 0x11, 0x08, 0x74, 0x6f, 0x77, 0x75, 0x70, 0x70, + 0x65, 0x72, 0x00, 0x13, 0x06, 0x6d, 0x65, 0x6d, 0x63, 0x68, 0x72, 0x00, + 0x0f, 0x06, 0x6d, 0x65, 0x6d, 0x63, 0x6d, 0x70, 0x00, 0x0e, 0x06, 0x6d, + 0x65, 0x6d, 0x63, 0x70, 0x79, 0x00, 0x19, 0x07, 0x6d, 0x65, 0x6d, 0x6d, + 0x6f, 0x76, 0x65, 0x00, 0x16, 0x06, 0x6d, 0x65, 0x6d, 0x73, 0x65, 0x74, + 0x00, 0x17, 0x06, 0x73, 0x74, 0x72, 0x63, 0x6d, 0x70, 0x00, 0x10, 0x07, + 0x73, 0x74, 0x72, 0x6e, 0x63, 0x61, 0x74, 0x00, 0x1c, 0x07, 0x73, 0x74, + 0x72, 0x6e, 0x63, 0x6d, 0x70, 0x00, 0x14, 0x07, 0x73, 0x74, 0x72, 0x6e, + 0x63, 0x70, 0x79, 0x00, 0x1d, 0x08, 0x01, 0x04, 0x0c, 0x01, 0x02, 0x0a, + 0x8d, 0x2a, 0x1e, 0x02, 0x00, 0x0b, 0x0e, 0x00, 0x41, 0xec, 0xc2, 0x04, + 0x41, 0x00, 0x41, 0x84, 0x01, 0xfc, 0x0b, 0x00, 0x0b, 0xfd, 0x01, 0x01, + 0x03, 0x7f, 0x41, 0xec, 0xc2, 0x04, 0x28, 0x02, 0x00, 0x45, 0x04, 0x40, + 0x41, 0xec, 0xc2, 0x04, 0x41, 0x01, 0x36, 0x02, 0x00, 0x41, 0x84, 0xc3, + 0x04, 0x41, 0x84, 0xc3, 0x04, 0x36, 0x02, 0x00, 0x41, 0xbc, 0xc3, 0x04, + 0x41, 0x00, 0x36, 0x02, 0x00, 0x41, 0xb8, 0xc3, 0x04, 0x41, 0x80, 0x80, + 0x04, 0x36, 0x02, 0x00, 0x41, 0xb4, 0xc3, 0x04, 0x41, 0x80, 0x80, 0x04, + 0x36, 0x02, 0x00, 0x41, 0x8c, 0xc3, 0x04, 0x41, 0x84, 0xc3, 0x04, 0x36, + 0x02, 0x00, 0x41, 0x88, 0xc3, 0x04, 0x41, 0x84, 0xc3, 0x04, 0x36, 0x02, + 0x00, 0x41, 0x90, 0xc3, 0x04, 0x41, 0x80, 0xc3, 0x04, 0x28, 0x02, 0x00, + 0x36, 0x02, 0x00, 0x41, 0xe8, 0xc2, 0x04, 0x41, 0x80, 0x80, 0x04, 0x36, + 0x02, 0x00, 0x23, 0x00, 0x41, 0x10, 0x6b, 0x22, 0x00, 0x24, 0x00, 0x02, + 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x20, 0x00, 0x41, 0x08, 0x6a, + 0x20, 0x00, 0x41, 0x0c, 0x6a, 0x10, 0x01, 0x41, 0xff, 0xff, 0x03, 0x71, + 0x45, 0x04, 0x40, 0x20, 0x00, 0x28, 0x02, 0x08, 0x41, 0x01, 0x6a, 0x22, + 0x01, 0x45, 0x0d, 0x01, 0x20, 0x00, 0x28, 0x02, 0x0c, 0x10, 0x07, 0x22, + 0x02, 0x45, 0x0d, 0x02, 0x20, 0x01, 0x41, 0x04, 0x10, 0x09, 0x22, 0x01, + 0x45, 0x0d, 0x03, 0x20, 0x01, 0x20, 0x02, 0x10, 0x00, 0x41, 0xff, 0xff, + 0x03, 0x71, 0x0d, 0x04, 0x20, 0x00, 0x28, 0x02, 0x08, 0x00, 0x0b, 0x41, + 0xc7, 0x00, 0x10, 0x0b, 0x00, 0x0b, 0x41, 0xc6, 0x00, 0x10, 0x0b, 0x00, + 0x0b, 0x41, 0xc6, 0x00, 0x10, 0x0b, 0x00, 0x0b, 0x20, 0x02, 0x10, 0x08, + 0x41, 0xc6, 0x00, 0x10, 0x0b, 0x00, 0x0b, 0x20, 0x02, 0x10, 0x08, 0x20, + 0x01, 0x10, 0x08, 0x41, 0xc7, 0x00, 0x10, 0x0b, 0x00, 0x0b, 0x00, 0x0b, + 0x35, 0x01, 0x01, 0x7f, 0x41, 0xf4, 0xc2, 0x04, 0x20, 0x00, 0x36, 0x02, + 0x00, 0x41, 0xf0, 0xc2, 0x04, 0x20, 0x00, 0x36, 0x02, 0x00, 0x3f, 0x00, + 0x21, 0x00, 0x20, 0x01, 0x41, 0xfc, 0xc2, 0x04, 0x6a, 0x41, 0x00, 0x36, + 0x02, 0x00, 0x20, 0x01, 0x41, 0xf8, 0xc2, 0x04, 0x6a, 0x20, 0x00, 0x41, + 0x10, 0x74, 0x36, 0x02, 0x00, 0x0b, 0xde, 0x01, 0x01, 0x04, 0x7f, 0x02, + 0x40, 0x20, 0x00, 0x45, 0x0d, 0x00, 0x02, 0x40, 0x41, 0xfc, 0xc2, 0x04, + 0x28, 0x02, 0x00, 0x22, 0x01, 0x45, 0x0d, 0x00, 0x02, 0x40, 0x20, 0x00, + 0x20, 0x01, 0x28, 0x02, 0x00, 0x4d, 0x04, 0x40, 0x20, 0x01, 0x21, 0x02, + 0x0c, 0x01, 0x0b, 0x03, 0x40, 0x20, 0x01, 0x28, 0x02, 0x04, 0x22, 0x02, + 0x45, 0x0d, 0x02, 0x20, 0x01, 0x21, 0x03, 0x20, 0x02, 0x22, 0x01, 0x28, + 0x02, 0x00, 0x20, 0x00, 0x49, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x02, 0x28, + 0x02, 0x04, 0x21, 0x00, 0x02, 0x40, 0x20, 0x03, 0x45, 0x04, 0x40, 0x41, + 0xfc, 0xc2, 0x04, 0x20, 0x00, 0x36, 0x02, 0x00, 0x0c, 0x01, 0x0b, 0x20, + 0x03, 0x20, 0x00, 0x36, 0x02, 0x04, 0x0b, 0x20, 0x02, 0x41, 0x08, 0x6a, + 0x0f, 0x0b, 0x41, 0xf4, 0xc2, 0x04, 0x28, 0x02, 0x00, 0x22, 0x03, 0x41, + 0x08, 0x6a, 0x22, 0x01, 0x20, 0x00, 0x6a, 0x41, 0x03, 0x6a, 0x41, 0x7c, + 0x71, 0x22, 0x02, 0x41, 0xf8, 0xc2, 0x04, 0x28, 0x02, 0x00, 0x4b, 0x04, + 0x40, 0x20, 0x02, 0x41, 0xf0, 0xc2, 0x04, 0x28, 0x02, 0x00, 0x6b, 0x41, + 0x80, 0x80, 0x80, 0x02, 0x4a, 0x0d, 0x01, 0x20, 0x00, 0x41, 0x01, 0x6b, + 0x41, 0x10, 0x76, 0x41, 0x01, 0x6a, 0x40, 0x00, 0x41, 0x7f, 0x46, 0x0d, + 0x01, 0x41, 0xf8, 0xc2, 0x04, 0x3f, 0x00, 0x41, 0x10, 0x74, 0x36, 0x02, + 0x00, 0x0b, 0x20, 0x03, 0x20, 0x00, 0x36, 0x02, 0x00, 0x41, 0xf4, 0xc2, + 0x04, 0x20, 0x02, 0x36, 0x02, 0x00, 0x20, 0x01, 0x21, 0x04, 0x0b, 0x20, + 0x04, 0x0b, 0x41, 0x01, 0x02, 0x7f, 0x20, 0x00, 0x04, 0x40, 0x41, 0xf4, + 0xc2, 0x04, 0x22, 0x01, 0x28, 0x02, 0x00, 0x20, 0x00, 0x41, 0x08, 0x6b, + 0x22, 0x02, 0x28, 0x02, 0x00, 0x20, 0x00, 0x6a, 0x41, 0x03, 0x6a, 0x41, + 0x7c, 0x71, 0x47, 0x04, 0x40, 0x20, 0x00, 0x41, 0x04, 0x6b, 0x41, 0xfc, + 0xc2, 0x04, 0x22, 0x01, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00, 0x0b, 0x20, + 0x01, 0x20, 0x02, 0x36, 0x02, 0x00, 0x0b, 0x0b, 0x1d, 0x00, 0x20, 0x00, + 0x20, 0x01, 0x6c, 0x22, 0x00, 0x10, 0x07, 0x21, 0x01, 0x20, 0x00, 0x04, + 0x40, 0x20, 0x01, 0x41, 0x00, 0x20, 0x00, 0xfc, 0x0b, 0x00, 0x0b, 0x20, + 0x01, 0x0b, 0x56, 0x01, 0x01, 0x7f, 0x02, 0x40, 0x20, 0x00, 0x45, 0x0d, + 0x00, 0x41, 0xf4, 0xc2, 0x04, 0x28, 0x02, 0x00, 0x20, 0x00, 0x41, 0x08, + 0x6b, 0x22, 0x02, 0x28, 0x02, 0x00, 0x20, 0x00, 0x6a, 0x41, 0x03, 0x6a, + 0x41, 0x7c, 0x71, 0x46, 0x04, 0x40, 0x41, 0xf4, 0xc2, 0x04, 0x20, 0x02, + 0x36, 0x02, 0x00, 0x0c, 0x01, 0x0b, 0x20, 0x01, 0x10, 0x07, 0x21, 0x01, + 0x20, 0x02, 0x28, 0x02, 0x00, 0x22, 0x02, 0x04, 0x40, 0x20, 0x01, 0x20, + 0x00, 0x20, 0x02, 0xfc, 0x0a, 0x00, 0x00, 0x0b, 0x20, 0x01, 0x0f, 0x0b, + 0x20, 0x01, 0x10, 0x07, 0x0b, 0x07, 0x00, 0x20, 0x00, 0x10, 0x02, 0x00, + 0x0b, 0xc5, 0x01, 0x01, 0x03, 0x7f, 0x02, 0x40, 0x02, 0x40, 0x20, 0x00, + 0x22, 0x01, 0x41, 0x03, 0x71, 0x45, 0x0d, 0x00, 0x20, 0x01, 0x2d, 0x00, + 0x00, 0x45, 0x04, 0x40, 0x41, 0x00, 0x0f, 0x0b, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x22, 0x01, 0x41, 0x03, 0x71, 0x45, 0x0d, 0x00, 0x20, 0x01, 0x2d, - 0x00, 0x00, 0x45, 0x0d, 0x01, 0x20, 0x00, 0x41, 0x03, 0x6a, 0x22, 0x01, + 0x00, 0x00, 0x45, 0x0d, 0x01, 0x20, 0x00, 0x41, 0x02, 0x6a, 0x22, 0x01, 0x41, 0x03, 0x71, 0x45, 0x0d, 0x00, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x45, - 0x0d, 0x01, 0x20, 0x00, 0x41, 0x04, 0x6a, 0x22, 0x01, 0x41, 0x03, 0x71, - 0x0d, 0x01, 0x0b, 0x20, 0x01, 0x41, 0x7c, 0x6a, 0x21, 0x02, 0x20, 0x01, - 0x41, 0x7b, 0x6a, 0x21, 0x01, 0x03, 0x40, 0x20, 0x01, 0x41, 0x04, 0x6a, - 0x21, 0x01, 0x41, 0x80, 0x82, 0x84, 0x08, 0x20, 0x02, 0x41, 0x04, 0x6a, - 0x22, 0x02, 0x28, 0x02, 0x00, 0x22, 0x03, 0x6b, 0x20, 0x03, 0x72, 0x41, - 0x80, 0x81, 0x82, 0x84, 0x78, 0x71, 0x41, 0x80, 0x81, 0x82, 0x84, 0x78, - 0x46, 0x0d, 0x00, 0x0b, 0x03, 0x40, 0x20, 0x01, 0x41, 0x01, 0x6a, 0x21, - 0x01, 0x20, 0x02, 0x2d, 0x00, 0x00, 0x21, 0x03, 0x20, 0x02, 0x41, 0x01, - 0x6a, 0x21, 0x02, 0x20, 0x03, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x01, 0x20, - 0x00, 0x6b, 0x0b, 0x44, 0x00, 0x02, 0x40, 0x20, 0x00, 0x41, 0xff, 0xff, - 0x07, 0x4b, 0x0d, 0x00, 0x20, 0x00, 0x41, 0x08, 0x76, 0x41, 0x80, 0x80, - 0x84, 0x80, 0x00, 0x6a, 0x2d, 0x00, 0x00, 0x41, 0x05, 0x74, 0x20, 0x00, - 0x41, 0x03, 0x76, 0x41, 0x1f, 0x71, 0x72, 0x41, 0x80, 0x80, 0x84, 0x80, - 0x00, 0x6a, 0x2d, 0x00, 0x00, 0x20, 0x00, 0x41, 0x07, 0x71, 0x76, 0x41, - 0x01, 0x71, 0x0f, 0x0b, 0x20, 0x00, 0x41, 0xfe, 0xff, 0x0b, 0x49, 0x0b, - 0x49, 0x01, 0x03, 0x7f, 0x41, 0x00, 0x21, 0x03, 0x02, 0x40, 0x20, 0x02, - 0x45, 0x0d, 0x00, 0x02, 0x40, 0x03, 0x40, 0x20, 0x00, 0x2d, 0x00, 0x00, - 0x22, 0x04, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x22, 0x05, 0x47, 0x0d, 0x01, - 0x20, 0x01, 0x41, 0x01, 0x6a, 0x21, 0x01, 0x20, 0x00, 0x41, 0x01, 0x6a, - 0x21, 0x00, 0x20, 0x02, 0x41, 0x7f, 0x6a, 0x22, 0x02, 0x0d, 0x00, 0x0c, - 0x02, 0x0b, 0x0b, 0x20, 0x04, 0x20, 0x05, 0x6b, 0x21, 0x03, 0x0b, 0x20, - 0x03, 0x0b, 0xf6, 0x02, 0x01, 0x03, 0x7f, 0x20, 0x02, 0x41, 0x00, 0x47, - 0x21, 0x03, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x20, 0x00, - 0x41, 0x03, 0x71, 0x45, 0x0d, 0x00, 0x20, 0x02, 0x45, 0x0d, 0x00, 0x02, - 0x40, 0x20, 0x00, 0x2d, 0x00, 0x00, 0x20, 0x01, 0x41, 0xff, 0x01, 0x71, - 0x47, 0x0d, 0x00, 0x20, 0x00, 0x21, 0x04, 0x20, 0x02, 0x21, 0x05, 0x0c, - 0x03, 0x0b, 0x20, 0x02, 0x41, 0x7f, 0x6a, 0x22, 0x05, 0x41, 0x00, 0x47, - 0x21, 0x03, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x22, 0x04, 0x41, 0x03, 0x71, - 0x45, 0x0d, 0x01, 0x20, 0x05, 0x45, 0x0d, 0x01, 0x20, 0x04, 0x2d, 0x00, - 0x00, 0x20, 0x01, 0x41, 0xff, 0x01, 0x71, 0x46, 0x0d, 0x02, 0x20, 0x02, - 0x41, 0x7e, 0x6a, 0x22, 0x05, 0x41, 0x00, 0x47, 0x21, 0x03, 0x20, 0x00, - 0x41, 0x02, 0x6a, 0x22, 0x04, 0x41, 0x03, 0x71, 0x45, 0x0d, 0x01, 0x20, - 0x05, 0x45, 0x0d, 0x01, 0x20, 0x04, 0x2d, 0x00, 0x00, 0x20, 0x01, 0x41, - 0xff, 0x01, 0x71, 0x46, 0x0d, 0x02, 0x20, 0x02, 0x41, 0x7d, 0x6a, 0x22, - 0x05, 0x41, 0x00, 0x47, 0x21, 0x03, 0x20, 0x00, 0x41, 0x03, 0x6a, 0x22, - 0x04, 0x41, 0x03, 0x71, 0x45, 0x0d, 0x01, 0x20, 0x05, 0x45, 0x0d, 0x01, - 0x20, 0x04, 0x2d, 0x00, 0x00, 0x20, 0x01, 0x41, 0xff, 0x01, 0x71, 0x46, - 0x0d, 0x02, 0x20, 0x00, 0x41, 0x04, 0x6a, 0x21, 0x04, 0x20, 0x02, 0x41, - 0x7c, 0x6a, 0x22, 0x05, 0x41, 0x00, 0x47, 0x21, 0x03, 0x0c, 0x01, 0x0b, - 0x20, 0x02, 0x21, 0x05, 0x20, 0x00, 0x21, 0x04, 0x0b, 0x20, 0x03, 0x45, - 0x0d, 0x01, 0x02, 0x40, 0x20, 0x04, 0x2d, 0x00, 0x00, 0x20, 0x01, 0x41, - 0xff, 0x01, 0x71, 0x46, 0x0d, 0x00, 0x20, 0x05, 0x41, 0x04, 0x49, 0x0d, - 0x00, 0x20, 0x01, 0x41, 0xff, 0x01, 0x71, 0x41, 0x81, 0x82, 0x84, 0x08, - 0x6c, 0x21, 0x00, 0x03, 0x40, 0x41, 0x80, 0x82, 0x84, 0x08, 0x20, 0x04, + 0x0d, 0x01, 0x20, 0x00, 0x41, 0x03, 0x6a, 0x22, 0x01, 0x41, 0x03, 0x71, + 0x45, 0x0d, 0x00, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x45, 0x0d, 0x01, 0x20, + 0x00, 0x41, 0x04, 0x6a, 0x22, 0x01, 0x41, 0x03, 0x71, 0x0d, 0x01, 0x0b, + 0x20, 0x01, 0x41, 0x04, 0x6b, 0x21, 0x02, 0x20, 0x01, 0x41, 0x05, 0x6b, + 0x21, 0x01, 0x03, 0x40, 0x20, 0x01, 0x41, 0x04, 0x6a, 0x21, 0x01, 0x41, + 0x80, 0x82, 0x84, 0x08, 0x20, 0x02, 0x41, 0x04, 0x6a, 0x22, 0x02, 0x28, + 0x02, 0x00, 0x22, 0x03, 0x6b, 0x20, 0x03, 0x72, 0x41, 0x80, 0x81, 0x82, + 0x84, 0x78, 0x71, 0x41, 0x80, 0x81, 0x82, 0x84, 0x78, 0x46, 0x0d, 0x00, + 0x0b, 0x03, 0x40, 0x20, 0x01, 0x41, 0x01, 0x6a, 0x21, 0x01, 0x20, 0x02, + 0x2d, 0x00, 0x00, 0x20, 0x02, 0x41, 0x01, 0x6a, 0x21, 0x02, 0x0d, 0x00, + 0x0b, 0x0b, 0x20, 0x01, 0x20, 0x00, 0x6b, 0x0b, 0x38, 0x00, 0x20, 0x00, + 0x41, 0xff, 0xff, 0x07, 0x4d, 0x04, 0x40, 0x20, 0x00, 0x41, 0x03, 0x76, + 0x41, 0x1f, 0x71, 0x20, 0x00, 0x41, 0x08, 0x76, 0x2d, 0x00, 0x80, 0x80, + 0x04, 0x41, 0x05, 0x74, 0x72, 0x2d, 0x00, 0x80, 0x80, 0x04, 0x20, 0x00, + 0x41, 0x07, 0x71, 0x76, 0x41, 0x01, 0x71, 0x0f, 0x0b, 0x20, 0x00, 0x41, + 0xfe, 0xff, 0x0b, 0x49, 0x0b, 0x43, 0x01, 0x03, 0x7f, 0x02, 0x40, 0x20, + 0x02, 0x45, 0x0d, 0x00, 0x03, 0x40, 0x20, 0x00, 0x2d, 0x00, 0x00, 0x22, + 0x04, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x22, 0x05, 0x46, 0x04, 0x40, 0x20, + 0x01, 0x41, 0x01, 0x6a, 0x21, 0x01, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x21, + 0x00, 0x20, 0x02, 0x41, 0x01, 0x6b, 0x22, 0x02, 0x0d, 0x01, 0x0c, 0x02, + 0x0b, 0x0b, 0x20, 0x04, 0x20, 0x05, 0x6b, 0x21, 0x03, 0x0b, 0x20, 0x03, + 0x0b, 0xe9, 0x02, 0x01, 0x03, 0x7f, 0x20, 0x02, 0x41, 0x00, 0x47, 0x21, + 0x05, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x20, 0x00, 0x41, 0x03, 0x71, + 0x45, 0x20, 0x02, 0x45, 0x72, 0x45, 0x04, 0x40, 0x20, 0x00, 0x2d, 0x00, + 0x00, 0x20, 0x01, 0x41, 0xff, 0x01, 0x71, 0x46, 0x04, 0x40, 0x20, 0x00, + 0x21, 0x03, 0x20, 0x02, 0x21, 0x04, 0x0c, 0x03, 0x0b, 0x20, 0x02, 0x41, + 0x01, 0x6b, 0x22, 0x04, 0x41, 0x00, 0x47, 0x21, 0x05, 0x20, 0x00, 0x41, + 0x01, 0x6a, 0x22, 0x03, 0x41, 0x03, 0x71, 0x45, 0x20, 0x04, 0x45, 0x72, + 0x0d, 0x01, 0x20, 0x03, 0x2d, 0x00, 0x00, 0x20, 0x01, 0x41, 0xff, 0x01, + 0x71, 0x46, 0x0d, 0x02, 0x20, 0x02, 0x41, 0x02, 0x6b, 0x22, 0x04, 0x41, + 0x00, 0x47, 0x21, 0x05, 0x20, 0x00, 0x41, 0x02, 0x6a, 0x22, 0x03, 0x41, + 0x03, 0x71, 0x45, 0x20, 0x04, 0x45, 0x72, 0x0d, 0x01, 0x20, 0x03, 0x2d, + 0x00, 0x00, 0x20, 0x01, 0x41, 0xff, 0x01, 0x71, 0x46, 0x0d, 0x02, 0x20, + 0x02, 0x41, 0x03, 0x6b, 0x22, 0x04, 0x41, 0x00, 0x47, 0x21, 0x05, 0x20, + 0x00, 0x41, 0x03, 0x6a, 0x22, 0x03, 0x41, 0x03, 0x71, 0x45, 0x20, 0x04, + 0x45, 0x72, 0x0d, 0x01, 0x20, 0x03, 0x2d, 0x00, 0x00, 0x20, 0x01, 0x41, + 0xff, 0x01, 0x71, 0x46, 0x0d, 0x02, 0x20, 0x00, 0x41, 0x04, 0x6a, 0x21, + 0x03, 0x20, 0x02, 0x41, 0x04, 0x6b, 0x22, 0x04, 0x41, 0x00, 0x47, 0x21, + 0x05, 0x0c, 0x01, 0x0b, 0x20, 0x02, 0x21, 0x04, 0x20, 0x00, 0x21, 0x03, + 0x0b, 0x20, 0x05, 0x45, 0x0d, 0x01, 0x20, 0x01, 0x41, 0xff, 0x01, 0x71, + 0x22, 0x00, 0x20, 0x03, 0x2d, 0x00, 0x00, 0x46, 0x20, 0x04, 0x41, 0x04, + 0x49, 0x72, 0x45, 0x04, 0x40, 0x20, 0x00, 0x41, 0x81, 0x82, 0x84, 0x08, + 0x6c, 0x21, 0x00, 0x03, 0x40, 0x41, 0x80, 0x82, 0x84, 0x08, 0x20, 0x03, 0x28, 0x02, 0x00, 0x20, 0x00, 0x73, 0x22, 0x02, 0x6b, 0x20, 0x02, 0x72, 0x41, 0x80, 0x81, 0x82, 0x84, 0x78, 0x71, 0x41, 0x80, 0x81, 0x82, 0x84, - 0x78, 0x47, 0x0d, 0x02, 0x20, 0x04, 0x41, 0x04, 0x6a, 0x21, 0x04, 0x20, - 0x05, 0x41, 0x7c, 0x6a, 0x22, 0x05, 0x41, 0x03, 0x4b, 0x0d, 0x00, 0x0b, - 0x0b, 0x20, 0x05, 0x45, 0x0d, 0x01, 0x0b, 0x20, 0x01, 0x41, 0xff, 0x01, - 0x71, 0x21, 0x02, 0x03, 0x40, 0x02, 0x40, 0x20, 0x04, 0x2d, 0x00, 0x00, - 0x20, 0x02, 0x47, 0x0d, 0x00, 0x20, 0x04, 0x0f, 0x0b, 0x20, 0x04, 0x41, - 0x01, 0x6a, 0x21, 0x04, 0x20, 0x05, 0x41, 0x7f, 0x6a, 0x22, 0x05, 0x0d, - 0x00, 0x0b, 0x0b, 0x41, 0x00, 0x0b, 0x67, 0x01, 0x02, 0x7f, 0x20, 0x01, - 0x2d, 0x00, 0x00, 0x21, 0x02, 0x02, 0x40, 0x20, 0x00, 0x2d, 0x00, 0x00, - 0x22, 0x03, 0x45, 0x0d, 0x00, 0x20, 0x03, 0x20, 0x02, 0x41, 0xff, 0x01, - 0x71, 0x47, 0x0d, 0x00, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x21, 0x00, 0x20, - 0x01, 0x41, 0x01, 0x6a, 0x21, 0x01, 0x03, 0x40, 0x20, 0x01, 0x2d, 0x00, - 0x00, 0x21, 0x02, 0x20, 0x00, 0x2d, 0x00, 0x00, 0x22, 0x03, 0x45, 0x0d, - 0x01, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x21, 0x00, 0x20, 0x01, 0x41, 0x01, - 0x6a, 0x21, 0x01, 0x20, 0x03, 0x20, 0x02, 0x41, 0xff, 0x01, 0x71, 0x46, - 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x03, 0x20, 0x02, 0x41, 0xff, 0x01, 0x71, - 0x6b, 0x0b, 0x0c, 0x00, 0x20, 0x00, 0x41, 0x00, 0x10, 0x9b, 0x80, 0x80, - 0x80, 0x00, 0x0b, 0xb7, 0x02, 0x01, 0x07, 0x7f, 0x02, 0x40, 0x20, 0x00, - 0x41, 0xff, 0xff, 0x07, 0x4b, 0x0d, 0x00, 0x20, 0x00, 0x20, 0x00, 0x41, - 0xff, 0x01, 0x71, 0x22, 0x02, 0x41, 0x03, 0x6e, 0x22, 0x03, 0x41, 0x03, - 0x6c, 0x6b, 0x41, 0xff, 0x01, 0x71, 0x41, 0x02, 0x74, 0x41, 0xc0, 0x9e, - 0x84, 0x80, 0x00, 0x6a, 0x28, 0x02, 0x00, 0x20, 0x00, 0x41, 0x08, 0x76, - 0x22, 0x04, 0x41, 0xa0, 0xa9, 0x84, 0x80, 0x00, 0x6a, 0x2d, 0x00, 0x00, - 0x41, 0xd6, 0x00, 0x6c, 0x20, 0x03, 0x6a, 0x41, 0xa0, 0xa9, 0x84, 0x80, - 0x00, 0x6a, 0x2d, 0x00, 0x00, 0x6c, 0x41, 0x0b, 0x76, 0x41, 0x06, 0x70, - 0x20, 0x04, 0x41, 0x90, 0xbe, 0x84, 0x80, 0x00, 0x6a, 0x2d, 0x00, 0x00, - 0x6a, 0x41, 0x02, 0x74, 0x41, 0xd0, 0x9e, 0x84, 0x80, 0x00, 0x6a, 0x28, - 0x02, 0x00, 0x22, 0x03, 0x41, 0x08, 0x75, 0x21, 0x04, 0x02, 0x40, 0x20, - 0x03, 0x41, 0xff, 0x01, 0x71, 0x22, 0x03, 0x41, 0x01, 0x4b, 0x0d, 0x00, - 0x20, 0x04, 0x41, 0x00, 0x20, 0x03, 0x20, 0x01, 0x73, 0x6b, 0x71, 0x20, - 0x00, 0x6a, 0x0f, 0x0b, 0x20, 0x04, 0x41, 0xff, 0x01, 0x71, 0x22, 0x03, - 0x45, 0x0d, 0x00, 0x20, 0x04, 0x41, 0x08, 0x76, 0x21, 0x04, 0x03, 0x40, - 0x02, 0x40, 0x20, 0x02, 0x20, 0x03, 0x41, 0x01, 0x76, 0x22, 0x05, 0x20, - 0x04, 0x6a, 0x22, 0x06, 0x41, 0x01, 0x74, 0x41, 0x90, 0xa6, 0x84, 0x80, - 0x00, 0x6a, 0x22, 0x07, 0x2d, 0x00, 0x00, 0x22, 0x08, 0x47, 0x0d, 0x00, - 0x02, 0x40, 0x20, 0x07, 0x41, 0x01, 0x6a, 0x2d, 0x00, 0x00, 0x41, 0x02, - 0x74, 0x41, 0xd0, 0x9e, 0x84, 0x80, 0x00, 0x6a, 0x28, 0x02, 0x00, 0x22, - 0x03, 0x41, 0xff, 0x01, 0x71, 0x22, 0x04, 0x41, 0x01, 0x4b, 0x0d, 0x00, - 0x20, 0x03, 0x41, 0x08, 0x75, 0x41, 0x00, 0x20, 0x04, 0x20, 0x01, 0x73, - 0x6b, 0x71, 0x20, 0x00, 0x6a, 0x0f, 0x0b, 0x41, 0x7f, 0x41, 0x01, 0x20, - 0x01, 0x1b, 0x20, 0x00, 0x6a, 0x0f, 0x0b, 0x20, 0x04, 0x20, 0x06, 0x20, - 0x02, 0x20, 0x08, 0x49, 0x22, 0x08, 0x1b, 0x21, 0x04, 0x20, 0x05, 0x20, - 0x03, 0x20, 0x05, 0x6b, 0x20, 0x08, 0x1b, 0x22, 0x03, 0x0d, 0x00, 0x0b, - 0x0b, 0x20, 0x00, 0x0b, 0x0c, 0x00, 0x20, 0x00, 0x41, 0x01, 0x10, 0x9b, - 0x80, 0x80, 0x80, 0x00, 0x0b, 0x87, 0x01, 0x01, 0x02, 0x7f, 0x02, 0x40, - 0x20, 0x02, 0x0d, 0x00, 0x41, 0x00, 0x0f, 0x0b, 0x02, 0x40, 0x02, 0x40, - 0x20, 0x00, 0x2d, 0x00, 0x00, 0x22, 0x03, 0x0d, 0x00, 0x41, 0x00, 0x21, - 0x03, 0x0c, 0x01, 0x0b, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x21, 0x00, 0x20, - 0x02, 0x41, 0x7f, 0x6a, 0x21, 0x02, 0x02, 0x40, 0x03, 0x40, 0x20, 0x03, - 0x41, 0xff, 0x01, 0x71, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x22, 0x04, 0x47, - 0x0d, 0x01, 0x20, 0x04, 0x45, 0x0d, 0x01, 0x20, 0x02, 0x41, 0x00, 0x46, - 0x0d, 0x01, 0x20, 0x02, 0x41, 0x7f, 0x6a, 0x21, 0x02, 0x20, 0x01, 0x41, - 0x01, 0x6a, 0x21, 0x01, 0x20, 0x00, 0x2d, 0x00, 0x00, 0x21, 0x03, 0x20, - 0x00, 0x41, 0x01, 0x6a, 0x21, 0x00, 0x20, 0x03, 0x0d, 0x00, 0x0b, 0x41, - 0x00, 0x21, 0x03, 0x0b, 0x20, 0x03, 0x41, 0xff, 0x01, 0x71, 0x21, 0x03, - 0x0b, 0x20, 0x03, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x6b, 0x0b, 0x0d, 0x00, - 0x20, 0x00, 0x10, 0x9a, 0x80, 0x80, 0x80, 0x00, 0x20, 0x00, 0x47, 0x0b, - 0xa5, 0x0a, 0x01, 0x04, 0x7f, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x20, - 0x02, 0x41, 0x21, 0x4f, 0x0d, 0x00, 0x20, 0x00, 0x20, 0x01, 0x46, 0x0d, - 0x02, 0x20, 0x01, 0x20, 0x00, 0x20, 0x02, 0x6a, 0x22, 0x03, 0x6b, 0x41, - 0x00, 0x20, 0x02, 0x41, 0x01, 0x74, 0x6b, 0x4b, 0x0d, 0x01, 0x0b, 0x20, - 0x00, 0x20, 0x01, 0x20, 0x02, 0xfc, 0x0a, 0x00, 0x00, 0x0c, 0x01, 0x0b, - 0x20, 0x01, 0x20, 0x00, 0x73, 0x41, 0x03, 0x71, 0x21, 0x04, 0x02, 0x40, - 0x02, 0x40, 0x02, 0x40, 0x20, 0x00, 0x20, 0x01, 0x4f, 0x0d, 0x00, 0x02, - 0x40, 0x20, 0x04, 0x45, 0x0d, 0x00, 0x20, 0x02, 0x21, 0x05, 0x20, 0x00, - 0x21, 0x03, 0x0c, 0x03, 0x0b, 0x02, 0x40, 0x20, 0x00, 0x41, 0x03, 0x71, - 0x0d, 0x00, 0x20, 0x02, 0x21, 0x05, 0x20, 0x00, 0x21, 0x03, 0x0c, 0x02, - 0x0b, 0x20, 0x02, 0x45, 0x0d, 0x03, 0x20, 0x00, 0x20, 0x01, 0x2d, 0x00, - 0x00, 0x3a, 0x00, 0x00, 0x20, 0x02, 0x41, 0x7f, 0x6a, 0x21, 0x05, 0x02, - 0x40, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x22, 0x03, 0x41, 0x03, 0x71, 0x0d, - 0x00, 0x20, 0x01, 0x41, 0x01, 0x6a, 0x21, 0x01, 0x0c, 0x02, 0x0b, 0x20, - 0x05, 0x45, 0x0d, 0x03, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x20, 0x01, 0x41, - 0x01, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x02, 0x41, 0x7e, - 0x6a, 0x21, 0x05, 0x02, 0x40, 0x20, 0x00, 0x41, 0x02, 0x6a, 0x22, 0x03, - 0x41, 0x03, 0x71, 0x0d, 0x00, 0x20, 0x01, 0x41, 0x02, 0x6a, 0x21, 0x01, - 0x0c, 0x02, 0x0b, 0x20, 0x05, 0x45, 0x0d, 0x03, 0x20, 0x00, 0x41, 0x02, - 0x6a, 0x20, 0x01, 0x41, 0x02, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, - 0x20, 0x02, 0x41, 0x7d, 0x6a, 0x21, 0x05, 0x02, 0x40, 0x20, 0x00, 0x41, - 0x03, 0x6a, 0x22, 0x03, 0x41, 0x03, 0x71, 0x0d, 0x00, 0x20, 0x01, 0x41, - 0x03, 0x6a, 0x21, 0x01, 0x0c, 0x02, 0x0b, 0x20, 0x05, 0x45, 0x0d, 0x03, - 0x20, 0x00, 0x41, 0x03, 0x6a, 0x20, 0x01, 0x41, 0x03, 0x6a, 0x2d, 0x00, - 0x00, 0x3a, 0x00, 0x00, 0x20, 0x00, 0x41, 0x04, 0x6a, 0x21, 0x03, 0x20, - 0x01, 0x41, 0x04, 0x6a, 0x21, 0x01, 0x20, 0x02, 0x41, 0x7c, 0x6a, 0x21, - 0x05, 0x0c, 0x01, 0x0b, 0x02, 0x40, 0x20, 0x04, 0x0d, 0x00, 0x02, 0x40, - 0x20, 0x03, 0x41, 0x03, 0x71, 0x45, 0x0d, 0x00, 0x20, 0x02, 0x45, 0x0d, - 0x04, 0x20, 0x00, 0x20, 0x02, 0x41, 0x7f, 0x6a, 0x22, 0x03, 0x6a, 0x22, - 0x04, 0x20, 0x01, 0x20, 0x03, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, - 0x02, 0x40, 0x20, 0x04, 0x41, 0x03, 0x71, 0x0d, 0x00, 0x20, 0x03, 0x21, + 0x78, 0x47, 0x0d, 0x02, 0x20, 0x03, 0x41, 0x04, 0x6a, 0x21, 0x03, 0x20, + 0x04, 0x41, 0x04, 0x6b, 0x22, 0x04, 0x41, 0x03, 0x4b, 0x0d, 0x00, 0x0b, + 0x0b, 0x20, 0x04, 0x45, 0x0d, 0x01, 0x0b, 0x20, 0x01, 0x41, 0xff, 0x01, + 0x71, 0x21, 0x00, 0x03, 0x40, 0x20, 0x00, 0x20, 0x03, 0x2d, 0x00, 0x00, + 0x46, 0x04, 0x40, 0x20, 0x03, 0x0f, 0x0b, 0x20, 0x03, 0x41, 0x01, 0x6a, + 0x21, 0x03, 0x20, 0x04, 0x41, 0x01, 0x6b, 0x22, 0x04, 0x0d, 0x00, 0x0b, + 0x0b, 0x41, 0x00, 0x0b, 0x58, 0x01, 0x02, 0x7f, 0x02, 0x40, 0x20, 0x00, + 0x2d, 0x00, 0x00, 0x22, 0x02, 0x45, 0x20, 0x02, 0x20, 0x01, 0x2d, 0x00, + 0x00, 0x22, 0x03, 0x47, 0x72, 0x0d, 0x00, 0x20, 0x00, 0x41, 0x01, 0x6a, + 0x21, 0x00, 0x20, 0x01, 0x41, 0x01, 0x6a, 0x21, 0x01, 0x03, 0x40, 0x20, + 0x01, 0x2d, 0x00, 0x00, 0x21, 0x03, 0x20, 0x00, 0x2d, 0x00, 0x00, 0x22, + 0x02, 0x45, 0x0d, 0x01, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x21, 0x00, 0x20, + 0x01, 0x41, 0x01, 0x6a, 0x21, 0x01, 0x20, 0x02, 0x20, 0x03, 0x46, 0x0d, + 0x00, 0x0b, 0x0b, 0x20, 0x02, 0x20, 0x03, 0x6b, 0x0b, 0x08, 0x00, 0x20, + 0x00, 0x41, 0x00, 0x10, 0x12, 0x0b, 0x90, 0x02, 0x01, 0x07, 0x7f, 0x02, + 0x40, 0x20, 0x00, 0x41, 0xff, 0xff, 0x07, 0x4b, 0x0d, 0x00, 0x20, 0x00, + 0x20, 0x00, 0x41, 0xff, 0x01, 0x71, 0x22, 0x05, 0x41, 0x03, 0x6e, 0x22, + 0x02, 0x41, 0x03, 0x6c, 0x6b, 0x41, 0xff, 0x01, 0x71, 0x41, 0x02, 0x74, + 0x28, 0x02, 0xc0, 0x9e, 0x04, 0x20, 0x02, 0x20, 0x00, 0x41, 0x08, 0x76, + 0x22, 0x02, 0x2d, 0x00, 0xa0, 0xa9, 0x04, 0x41, 0xd6, 0x00, 0x6c, 0x6a, + 0x2d, 0x00, 0xa0, 0xa9, 0x04, 0x6c, 0x41, 0x0b, 0x76, 0x41, 0x06, 0x70, + 0x20, 0x02, 0x2d, 0x00, 0x90, 0xbe, 0x04, 0x6a, 0x41, 0x02, 0x74, 0x28, + 0x02, 0xd0, 0x9e, 0x04, 0x22, 0x03, 0x41, 0x08, 0x75, 0x21, 0x02, 0x20, + 0x03, 0x41, 0xff, 0x01, 0x71, 0x22, 0x03, 0x41, 0x01, 0x4d, 0x04, 0x40, + 0x20, 0x02, 0x41, 0x00, 0x20, 0x01, 0x20, 0x03, 0x73, 0x6b, 0x71, 0x20, + 0x00, 0x6a, 0x0f, 0x0b, 0x20, 0x02, 0x41, 0xff, 0x01, 0x71, 0x22, 0x03, + 0x45, 0x0d, 0x00, 0x20, 0x02, 0x41, 0x08, 0x76, 0x21, 0x02, 0x03, 0x40, + 0x20, 0x03, 0x41, 0x01, 0x76, 0x22, 0x06, 0x20, 0x02, 0x6a, 0x22, 0x04, + 0x41, 0x01, 0x74, 0x22, 0x07, 0x2d, 0x00, 0x90, 0xa6, 0x04, 0x22, 0x08, + 0x20, 0x05, 0x46, 0x04, 0x40, 0x20, 0x07, 0x41, 0x90, 0xa6, 0x04, 0x6a, + 0x2d, 0x00, 0x01, 0x41, 0x02, 0x74, 0x28, 0x02, 0xd0, 0x9e, 0x04, 0x22, + 0x02, 0x41, 0xff, 0x01, 0x71, 0x22, 0x03, 0x41, 0x01, 0x4d, 0x04, 0x40, + 0x41, 0x00, 0x20, 0x01, 0x20, 0x03, 0x73, 0x6b, 0x20, 0x02, 0x41, 0x08, + 0x75, 0x71, 0x20, 0x00, 0x6a, 0x0f, 0x0b, 0x41, 0x7f, 0x41, 0x01, 0x20, + 0x01, 0x1b, 0x20, 0x00, 0x6a, 0x0f, 0x0b, 0x20, 0x02, 0x20, 0x04, 0x20, + 0x05, 0x20, 0x08, 0x49, 0x22, 0x04, 0x1b, 0x21, 0x02, 0x20, 0x06, 0x20, + 0x03, 0x20, 0x06, 0x6b, 0x20, 0x04, 0x1b, 0x22, 0x03, 0x0d, 0x00, 0x0b, + 0x0b, 0x20, 0x00, 0x0b, 0x08, 0x00, 0x20, 0x00, 0x41, 0x01, 0x10, 0x12, + 0x0b, 0x75, 0x01, 0x02, 0x7f, 0x20, 0x02, 0x45, 0x04, 0x40, 0x41, 0x00, + 0x0f, 0x0b, 0x02, 0x40, 0x20, 0x00, 0x2d, 0x00, 0x00, 0x22, 0x03, 0x45, + 0x04, 0x40, 0x41, 0x00, 0x21, 0x03, 0x0c, 0x01, 0x0b, 0x20, 0x00, 0x41, + 0x01, 0x6a, 0x21, 0x00, 0x20, 0x02, 0x41, 0x01, 0x6b, 0x21, 0x02, 0x02, + 0x40, 0x03, 0x40, 0x20, 0x02, 0x45, 0x20, 0x03, 0x20, 0x01, 0x2d, 0x00, + 0x00, 0x22, 0x04, 0x47, 0x20, 0x04, 0x45, 0x72, 0x72, 0x0d, 0x01, 0x20, + 0x02, 0x41, 0x01, 0x6b, 0x21, 0x02, 0x20, 0x01, 0x41, 0x01, 0x6a, 0x21, + 0x01, 0x20, 0x00, 0x2d, 0x00, 0x00, 0x21, 0x03, 0x20, 0x00, 0x41, 0x01, + 0x6a, 0x21, 0x00, 0x20, 0x03, 0x0d, 0x00, 0x0b, 0x41, 0x00, 0x21, 0x03, + 0x0b, 0x0b, 0x20, 0x03, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x6b, 0x0b, 0x09, + 0x00, 0x20, 0x00, 0x10, 0x11, 0x20, 0x00, 0x47, 0x0b, 0x93, 0x0a, 0x01, + 0x04, 0x7f, 0x02, 0x40, 0x02, 0x40, 0x20, 0x02, 0x41, 0x21, 0x4f, 0x04, + 0x40, 0x20, 0x02, 0x45, 0x0d, 0x01, 0x0c, 0x02, 0x0b, 0x20, 0x00, 0x20, + 0x01, 0x46, 0x0d, 0x00, 0x20, 0x01, 0x20, 0x00, 0x20, 0x02, 0x6a, 0x22, + 0x04, 0x6b, 0x41, 0x00, 0x20, 0x02, 0x41, 0x01, 0x74, 0x6b, 0x4d, 0x04, + 0x40, 0x20, 0x02, 0x45, 0x0d, 0x01, 0x0c, 0x02, 0x0b, 0x20, 0x00, 0x20, + 0x01, 0x73, 0x41, 0x03, 0x71, 0x21, 0x03, 0x02, 0x40, 0x02, 0x40, 0x20, + 0x00, 0x20, 0x01, 0x49, 0x04, 0x40, 0x20, 0x03, 0x04, 0x40, 0x20, 0x02, + 0x21, 0x04, 0x20, 0x00, 0x21, 0x03, 0x0c, 0x03, 0x0b, 0x20, 0x00, 0x41, + 0x03, 0x71, 0x45, 0x04, 0x40, 0x20, 0x02, 0x21, 0x04, 0x20, 0x00, 0x21, + 0x03, 0x0c, 0x02, 0x0b, 0x20, 0x02, 0x45, 0x0d, 0x03, 0x20, 0x00, 0x20, + 0x01, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x02, 0x41, 0x01, 0x6b, + 0x21, 0x04, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x22, 0x03, 0x41, 0x03, 0x71, + 0x45, 0x04, 0x40, 0x20, 0x01, 0x41, 0x01, 0x6a, 0x21, 0x01, 0x0c, 0x02, + 0x0b, 0x20, 0x04, 0x45, 0x0d, 0x03, 0x20, 0x00, 0x20, 0x01, 0x2d, 0x00, + 0x01, 0x3a, 0x00, 0x01, 0x20, 0x02, 0x41, 0x02, 0x6b, 0x21, 0x04, 0x20, + 0x00, 0x41, 0x02, 0x6a, 0x22, 0x03, 0x41, 0x03, 0x71, 0x45, 0x04, 0x40, + 0x20, 0x01, 0x41, 0x02, 0x6a, 0x21, 0x01, 0x0c, 0x02, 0x0b, 0x20, 0x04, + 0x45, 0x0d, 0x03, 0x20, 0x00, 0x20, 0x01, 0x2d, 0x00, 0x02, 0x3a, 0x00, + 0x02, 0x20, 0x02, 0x41, 0x03, 0x6b, 0x21, 0x04, 0x20, 0x00, 0x41, 0x03, + 0x6a, 0x22, 0x03, 0x41, 0x03, 0x71, 0x45, 0x04, 0x40, 0x20, 0x01, 0x41, + 0x03, 0x6a, 0x21, 0x01, 0x0c, 0x02, 0x0b, 0x20, 0x04, 0x45, 0x0d, 0x03, + 0x20, 0x00, 0x20, 0x01, 0x2d, 0x00, 0x03, 0x3a, 0x00, 0x03, 0x20, 0x00, + 0x41, 0x04, 0x6a, 0x21, 0x03, 0x20, 0x01, 0x41, 0x04, 0x6a, 0x21, 0x01, + 0x20, 0x02, 0x41, 0x04, 0x6b, 0x21, 0x04, 0x0c, 0x01, 0x0b, 0x02, 0x40, + 0x20, 0x03, 0x0d, 0x00, 0x02, 0x40, 0x20, 0x04, 0x41, 0x03, 0x71, 0x45, + 0x0d, 0x00, 0x20, 0x02, 0x45, 0x0d, 0x04, 0x20, 0x00, 0x20, 0x02, 0x41, + 0x01, 0x6b, 0x22, 0x03, 0x6a, 0x22, 0x04, 0x20, 0x01, 0x20, 0x03, 0x6a, + 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x04, 0x41, 0x03, 0x71, 0x45, + 0x04, 0x40, 0x20, 0x03, 0x21, 0x02, 0x0c, 0x01, 0x0b, 0x20, 0x03, 0x45, + 0x0d, 0x04, 0x20, 0x00, 0x20, 0x02, 0x41, 0x02, 0x6b, 0x22, 0x03, 0x6a, + 0x22, 0x04, 0x20, 0x01, 0x20, 0x03, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, + 0x00, 0x20, 0x04, 0x41, 0x03, 0x71, 0x45, 0x04, 0x40, 0x20, 0x03, 0x21, 0x02, 0x0c, 0x01, 0x0b, 0x20, 0x03, 0x45, 0x0d, 0x04, 0x20, 0x00, 0x20, - 0x02, 0x41, 0x7e, 0x6a, 0x22, 0x03, 0x6a, 0x22, 0x04, 0x20, 0x01, 0x20, - 0x03, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x02, 0x40, 0x20, 0x04, - 0x41, 0x03, 0x71, 0x0d, 0x00, 0x20, 0x03, 0x21, 0x02, 0x0c, 0x01, 0x0b, - 0x20, 0x03, 0x45, 0x0d, 0x04, 0x20, 0x00, 0x20, 0x02, 0x41, 0x7d, 0x6a, - 0x22, 0x03, 0x6a, 0x22, 0x04, 0x20, 0x01, 0x20, 0x03, 0x6a, 0x2d, 0x00, - 0x00, 0x3a, 0x00, 0x00, 0x02, 0x40, 0x20, 0x04, 0x41, 0x03, 0x71, 0x0d, - 0x00, 0x20, 0x03, 0x21, 0x02, 0x0c, 0x01, 0x0b, 0x20, 0x03, 0x45, 0x0d, - 0x04, 0x20, 0x00, 0x20, 0x02, 0x41, 0x7c, 0x6a, 0x22, 0x02, 0x6a, 0x20, - 0x01, 0x20, 0x02, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x0b, 0x20, - 0x02, 0x41, 0x04, 0x49, 0x0d, 0x00, 0x02, 0x40, 0x20, 0x02, 0x41, 0x7c, - 0x6a, 0x22, 0x06, 0x41, 0x02, 0x76, 0x41, 0x01, 0x6a, 0x41, 0x03, 0x71, - 0x22, 0x03, 0x45, 0x0d, 0x00, 0x20, 0x01, 0x41, 0x7c, 0x6a, 0x21, 0x04, - 0x20, 0x00, 0x41, 0x7c, 0x6a, 0x21, 0x05, 0x03, 0x40, 0x20, 0x05, 0x20, - 0x02, 0x6a, 0x20, 0x04, 0x20, 0x02, 0x6a, 0x28, 0x02, 0x00, 0x36, 0x02, - 0x00, 0x20, 0x02, 0x41, 0x7c, 0x6a, 0x21, 0x02, 0x20, 0x03, 0x41, 0x7f, - 0x6a, 0x22, 0x03, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x06, 0x41, 0x0c, 0x49, - 0x0d, 0x00, 0x20, 0x01, 0x41, 0x70, 0x6a, 0x21, 0x05, 0x20, 0x00, 0x41, - 0x70, 0x6a, 0x21, 0x06, 0x03, 0x40, 0x20, 0x06, 0x20, 0x02, 0x6a, 0x22, - 0x03, 0x41, 0x0c, 0x6a, 0x20, 0x05, 0x20, 0x02, 0x6a, 0x22, 0x04, 0x41, - 0x0c, 0x6a, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00, 0x20, 0x03, 0x41, 0x08, - 0x6a, 0x20, 0x04, 0x41, 0x08, 0x6a, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00, - 0x20, 0x03, 0x41, 0x04, 0x6a, 0x20, 0x04, 0x41, 0x04, 0x6a, 0x28, 0x02, - 0x00, 0x36, 0x02, 0x00, 0x20, 0x03, 0x20, 0x04, 0x28, 0x02, 0x00, 0x36, - 0x02, 0x00, 0x20, 0x02, 0x41, 0x70, 0x6a, 0x22, 0x02, 0x41, 0x03, 0x4b, - 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x02, 0x45, 0x0d, 0x02, 0x20, 0x02, 0x21, - 0x03, 0x02, 0x40, 0x20, 0x02, 0x41, 0x03, 0x71, 0x22, 0x04, 0x45, 0x0d, - 0x00, 0x20, 0x01, 0x41, 0x7f, 0x6a, 0x21, 0x05, 0x20, 0x00, 0x41, 0x7f, - 0x6a, 0x21, 0x06, 0x20, 0x02, 0x21, 0x03, 0x03, 0x40, 0x20, 0x06, 0x20, - 0x03, 0x6a, 0x20, 0x05, 0x20, 0x03, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, - 0x00, 0x20, 0x03, 0x41, 0x7f, 0x6a, 0x21, 0x03, 0x20, 0x04, 0x41, 0x7f, - 0x6a, 0x22, 0x04, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x02, 0x41, 0x04, 0x49, - 0x0d, 0x02, 0x20, 0x01, 0x41, 0x7c, 0x6a, 0x21, 0x04, 0x20, 0x00, 0x41, - 0x7c, 0x6a, 0x21, 0x05, 0x03, 0x40, 0x20, 0x05, 0x20, 0x03, 0x6a, 0x22, - 0x01, 0x41, 0x03, 0x6a, 0x20, 0x04, 0x20, 0x03, 0x6a, 0x22, 0x02, 0x41, - 0x03, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x01, 0x41, 0x02, - 0x6a, 0x20, 0x02, 0x41, 0x02, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, - 0x20, 0x01, 0x41, 0x01, 0x6a, 0x20, 0x02, 0x41, 0x01, 0x6a, 0x2d, 0x00, - 0x00, 0x3a, 0x00, 0x00, 0x20, 0x01, 0x20, 0x02, 0x2d, 0x00, 0x00, 0x3a, - 0x00, 0x00, 0x20, 0x03, 0x41, 0x7c, 0x6a, 0x22, 0x03, 0x0d, 0x00, 0x0c, - 0x03, 0x0b, 0x0b, 0x20, 0x05, 0x41, 0x04, 0x49, 0x0d, 0x00, 0x02, 0x40, - 0x20, 0x05, 0x41, 0x7c, 0x6a, 0x22, 0x04, 0x41, 0x02, 0x76, 0x41, 0x01, - 0x6a, 0x41, 0x07, 0x71, 0x22, 0x02, 0x45, 0x0d, 0x00, 0x20, 0x05, 0x20, - 0x02, 0x41, 0x02, 0x74, 0x6b, 0x21, 0x05, 0x03, 0x40, 0x20, 0x03, 0x20, - 0x01, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00, 0x20, 0x01, 0x41, 0x04, 0x6a, - 0x21, 0x01, 0x20, 0x03, 0x41, 0x04, 0x6a, 0x21, 0x03, 0x20, 0x02, 0x41, - 0x7f, 0x6a, 0x22, 0x02, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x04, 0x41, 0x1c, - 0x49, 0x0d, 0x00, 0x03, 0x40, 0x20, 0x03, 0x20, 0x01, 0x28, 0x02, 0x00, - 0x36, 0x02, 0x00, 0x20, 0x03, 0x41, 0x04, 0x6a, 0x20, 0x01, 0x41, 0x04, - 0x6a, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00, 0x20, 0x03, 0x41, 0x08, 0x6a, - 0x20, 0x01, 0x41, 0x08, 0x6a, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00, 0x20, - 0x03, 0x41, 0x0c, 0x6a, 0x20, 0x01, 0x41, 0x0c, 0x6a, 0x28, 0x02, 0x00, - 0x36, 0x02, 0x00, 0x20, 0x03, 0x41, 0x10, 0x6a, 0x20, 0x01, 0x41, 0x10, - 0x6a, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00, 0x20, 0x03, 0x41, 0x14, 0x6a, - 0x20, 0x01, 0x41, 0x14, 0x6a, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00, 0x20, - 0x03, 0x41, 0x18, 0x6a, 0x20, 0x01, 0x41, 0x18, 0x6a, 0x28, 0x02, 0x00, - 0x36, 0x02, 0x00, 0x20, 0x03, 0x41, 0x1c, 0x6a, 0x20, 0x01, 0x41, 0x1c, - 0x6a, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00, 0x20, 0x01, 0x41, 0x20, 0x6a, - 0x21, 0x01, 0x20, 0x03, 0x41, 0x20, 0x6a, 0x21, 0x03, 0x20, 0x05, 0x41, - 0x60, 0x6a, 0x22, 0x05, 0x41, 0x03, 0x4b, 0x0d, 0x00, 0x0b, 0x0b, 0x20, - 0x05, 0x45, 0x0d, 0x00, 0x02, 0x40, 0x02, 0x40, 0x20, 0x05, 0x41, 0x07, - 0x71, 0x22, 0x02, 0x0d, 0x00, 0x20, 0x05, 0x21, 0x04, 0x0c, 0x01, 0x0b, - 0x20, 0x05, 0x41, 0x78, 0x71, 0x21, 0x04, 0x03, 0x40, 0x20, 0x03, 0x20, - 0x01, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x03, 0x41, 0x01, 0x6a, - 0x21, 0x03, 0x20, 0x01, 0x41, 0x01, 0x6a, 0x21, 0x01, 0x20, 0x02, 0x41, - 0x7f, 0x6a, 0x22, 0x02, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x05, 0x41, 0x08, - 0x49, 0x0d, 0x00, 0x03, 0x40, 0x20, 0x03, 0x20, 0x01, 0x2d, 0x00, 0x00, - 0x3a, 0x00, 0x00, 0x20, 0x03, 0x41, 0x01, 0x6a, 0x20, 0x01, 0x41, 0x01, - 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x03, 0x41, 0x02, 0x6a, - 0x20, 0x01, 0x41, 0x02, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, - 0x03, 0x41, 0x03, 0x6a, 0x20, 0x01, 0x41, 0x03, 0x6a, 0x2d, 0x00, 0x00, - 0x3a, 0x00, 0x00, 0x20, 0x03, 0x41, 0x04, 0x6a, 0x20, 0x01, 0x41, 0x04, - 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x03, 0x41, 0x05, 0x6a, - 0x20, 0x01, 0x41, 0x05, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, - 0x03, 0x41, 0x06, 0x6a, 0x20, 0x01, 0x41, 0x06, 0x6a, 0x2d, 0x00, 0x00, - 0x3a, 0x00, 0x00, 0x20, 0x03, 0x41, 0x07, 0x6a, 0x20, 0x01, 0x41, 0x07, - 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x03, 0x41, 0x08, 0x6a, - 0x21, 0x03, 0x20, 0x01, 0x41, 0x08, 0x6a, 0x21, 0x01, 0x20, 0x04, 0x41, - 0x78, 0x6a, 0x22, 0x04, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x00, 0x0b, 0x0d, - 0x00, 0x20, 0x00, 0x10, 0x9c, 0x80, 0x80, 0x80, 0x00, 0x20, 0x00, 0x47, - 0x0b, 0x0d, 0x00, 0x20, 0x00, 0x41, 0x20, 0x46, 0x20, 0x00, 0x41, 0x09, - 0x46, 0x72, 0x0b, 0x0a, 0x00, 0x20, 0x00, 0x10, 0xa1, 0x80, 0x80, 0x80, - 0x00, 0x0b, 0x0a, 0x00, 0x20, 0x00, 0x41, 0x50, 0x6a, 0x41, 0x0a, 0x49, - 0x0b, 0x4d, 0x01, 0x02, 0x7f, 0x20, 0x00, 0x20, 0x00, 0x10, 0x95, 0x80, - 0x80, 0x80, 0x00, 0x6a, 0x21, 0x03, 0x02, 0x40, 0x20, 0x02, 0x45, 0x0d, - 0x00, 0x03, 0x40, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x22, 0x04, 0x45, 0x0d, - 0x01, 0x20, 0x03, 0x20, 0x04, 0x3a, 0x00, 0x00, 0x20, 0x03, 0x41, 0x01, + 0x02, 0x41, 0x03, 0x6b, 0x22, 0x03, 0x6a, 0x22, 0x04, 0x20, 0x01, 0x20, + 0x03, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x04, 0x41, 0x03, + 0x71, 0x45, 0x04, 0x40, 0x20, 0x03, 0x21, 0x02, 0x0c, 0x01, 0x0b, 0x20, + 0x03, 0x45, 0x0d, 0x04, 0x20, 0x00, 0x20, 0x02, 0x41, 0x04, 0x6b, 0x22, + 0x02, 0x6a, 0x20, 0x01, 0x20, 0x02, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, + 0x00, 0x0b, 0x20, 0x02, 0x41, 0x04, 0x49, 0x0d, 0x00, 0x20, 0x02, 0x41, + 0x04, 0x6b, 0x22, 0x04, 0x41, 0x0c, 0x71, 0x41, 0x0c, 0x47, 0x04, 0x40, + 0x20, 0x04, 0x41, 0x02, 0x76, 0x41, 0x01, 0x6a, 0x41, 0x03, 0x71, 0x21, + 0x03, 0x20, 0x01, 0x41, 0x04, 0x6b, 0x21, 0x05, 0x20, 0x00, 0x41, 0x04, + 0x6b, 0x21, 0x06, 0x03, 0x40, 0x20, 0x02, 0x20, 0x06, 0x6a, 0x20, 0x02, + 0x20, 0x05, 0x6a, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00, 0x20, 0x02, 0x41, + 0x04, 0x6b, 0x21, 0x02, 0x20, 0x03, 0x41, 0x01, 0x6b, 0x22, 0x03, 0x0d, + 0x00, 0x0b, 0x0b, 0x20, 0x04, 0x41, 0x0c, 0x49, 0x0d, 0x00, 0x20, 0x01, + 0x41, 0x10, 0x6b, 0x21, 0x05, 0x20, 0x00, 0x41, 0x10, 0x6b, 0x21, 0x06, + 0x03, 0x40, 0x20, 0x02, 0x20, 0x06, 0x6a, 0x22, 0x03, 0x41, 0x0c, 0x6a, + 0x20, 0x02, 0x20, 0x05, 0x6a, 0x22, 0x04, 0x41, 0x0c, 0x6a, 0x28, 0x02, + 0x00, 0x36, 0x02, 0x00, 0x20, 0x03, 0x41, 0x08, 0x6a, 0x20, 0x04, 0x41, + 0x08, 0x6a, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00, 0x20, 0x03, 0x41, 0x04, + 0x6a, 0x20, 0x04, 0x41, 0x04, 0x6a, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00, + 0x20, 0x03, 0x20, 0x04, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00, 0x20, 0x02, + 0x41, 0x10, 0x6b, 0x22, 0x02, 0x41, 0x03, 0x4b, 0x0d, 0x00, 0x0b, 0x0b, + 0x20, 0x02, 0x45, 0x0d, 0x02, 0x20, 0x02, 0x22, 0x03, 0x41, 0x03, 0x71, + 0x22, 0x05, 0x04, 0x40, 0x20, 0x01, 0x41, 0x01, 0x6b, 0x21, 0x04, 0x20, + 0x00, 0x41, 0x01, 0x6b, 0x21, 0x06, 0x03, 0x40, 0x20, 0x03, 0x20, 0x06, + 0x6a, 0x20, 0x03, 0x20, 0x04, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, + 0x20, 0x03, 0x41, 0x01, 0x6b, 0x21, 0x03, 0x20, 0x05, 0x41, 0x01, 0x6b, + 0x22, 0x05, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x02, 0x41, 0x04, 0x49, 0x0d, + 0x02, 0x20, 0x01, 0x41, 0x04, 0x6b, 0x21, 0x04, 0x20, 0x00, 0x41, 0x04, + 0x6b, 0x21, 0x05, 0x03, 0x40, 0x20, 0x03, 0x20, 0x05, 0x6a, 0x22, 0x01, + 0x41, 0x03, 0x6a, 0x20, 0x03, 0x20, 0x04, 0x6a, 0x22, 0x02, 0x41, 0x03, + 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x01, 0x41, 0x02, 0x6a, + 0x20, 0x02, 0x41, 0x02, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, + 0x01, 0x41, 0x01, 0x6a, 0x20, 0x02, 0x41, 0x01, 0x6a, 0x2d, 0x00, 0x00, + 0x3a, 0x00, 0x00, 0x20, 0x01, 0x20, 0x02, 0x2d, 0x00, 0x00, 0x3a, 0x00, + 0x00, 0x20, 0x03, 0x41, 0x04, 0x6b, 0x22, 0x03, 0x0d, 0x00, 0x0b, 0x0c, + 0x02, 0x0b, 0x20, 0x04, 0x41, 0x04, 0x49, 0x0d, 0x00, 0x20, 0x04, 0x41, + 0x04, 0x6b, 0x22, 0x05, 0x41, 0x1c, 0x71, 0x41, 0x1c, 0x47, 0x04, 0x40, + 0x20, 0x04, 0x20, 0x05, 0x41, 0x02, 0x76, 0x41, 0x01, 0x6a, 0x41, 0x07, + 0x71, 0x22, 0x02, 0x41, 0x02, 0x74, 0x6b, 0x21, 0x04, 0x03, 0x40, 0x20, + 0x03, 0x20, 0x01, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00, 0x20, 0x01, 0x41, + 0x04, 0x6a, 0x21, 0x01, 0x20, 0x03, 0x41, 0x04, 0x6a, 0x21, 0x03, 0x20, + 0x02, 0x41, 0x01, 0x6b, 0x22, 0x02, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x05, + 0x41, 0x1c, 0x49, 0x0d, 0x00, 0x03, 0x40, 0x20, 0x03, 0x20, 0x01, 0x28, + 0x02, 0x00, 0x36, 0x02, 0x00, 0x20, 0x03, 0x41, 0x04, 0x6a, 0x20, 0x01, + 0x41, 0x04, 0x6a, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00, 0x20, 0x03, 0x41, + 0x08, 0x6a, 0x20, 0x01, 0x41, 0x08, 0x6a, 0x28, 0x02, 0x00, 0x36, 0x02, + 0x00, 0x20, 0x03, 0x41, 0x0c, 0x6a, 0x20, 0x01, 0x41, 0x0c, 0x6a, 0x28, + 0x02, 0x00, 0x36, 0x02, 0x00, 0x20, 0x03, 0x41, 0x10, 0x6a, 0x20, 0x01, + 0x41, 0x10, 0x6a, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00, 0x20, 0x03, 0x41, + 0x14, 0x6a, 0x20, 0x01, 0x41, 0x14, 0x6a, 0x28, 0x02, 0x00, 0x36, 0x02, + 0x00, 0x20, 0x03, 0x41, 0x18, 0x6a, 0x20, 0x01, 0x41, 0x18, 0x6a, 0x28, + 0x02, 0x00, 0x36, 0x02, 0x00, 0x20, 0x03, 0x41, 0x1c, 0x6a, 0x20, 0x01, + 0x41, 0x1c, 0x6a, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00, 0x20, 0x01, 0x41, + 0x20, 0x6a, 0x21, 0x01, 0x20, 0x03, 0x41, 0x20, 0x6a, 0x21, 0x03, 0x20, + 0x04, 0x41, 0x20, 0x6b, 0x22, 0x04, 0x41, 0x03, 0x4b, 0x0d, 0x00, 0x0b, + 0x0b, 0x20, 0x04, 0x45, 0x0d, 0x00, 0x02, 0x40, 0x20, 0x04, 0x41, 0x07, + 0x71, 0x22, 0x02, 0x45, 0x04, 0x40, 0x20, 0x04, 0x21, 0x05, 0x0c, 0x01, + 0x0b, 0x20, 0x04, 0x41, 0x78, 0x71, 0x21, 0x05, 0x03, 0x40, 0x20, 0x03, + 0x20, 0x01, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x03, 0x41, 0x01, 0x6a, 0x21, 0x03, 0x20, 0x01, 0x41, 0x01, 0x6a, 0x21, 0x01, 0x20, 0x02, - 0x41, 0x7f, 0x6a, 0x22, 0x02, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x03, 0x41, - 0x00, 0x3a, 0x00, 0x00, 0x20, 0x00, 0x0b, 0xf3, 0x03, 0x01, 0x04, 0x7f, - 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x20, 0x01, - 0x20, 0x00, 0x73, 0x41, 0x03, 0x71, 0x45, 0x0d, 0x00, 0x20, 0x00, 0x21, - 0x03, 0x0c, 0x01, 0x0b, 0x20, 0x02, 0x41, 0x00, 0x47, 0x21, 0x04, 0x02, - 0x40, 0x02, 0x40, 0x20, 0x01, 0x41, 0x03, 0x71, 0x0d, 0x00, 0x20, 0x00, - 0x21, 0x03, 0x0c, 0x01, 0x0b, 0x02, 0x40, 0x20, 0x02, 0x0d, 0x00, 0x20, - 0x00, 0x21, 0x03, 0x0c, 0x01, 0x0b, 0x20, 0x00, 0x20, 0x01, 0x2d, 0x00, - 0x00, 0x22, 0x03, 0x3a, 0x00, 0x00, 0x02, 0x40, 0x20, 0x03, 0x0d, 0x00, - 0x20, 0x00, 0x21, 0x03, 0x20, 0x02, 0x21, 0x05, 0x0c, 0x05, 0x0b, 0x20, - 0x00, 0x41, 0x01, 0x6a, 0x21, 0x03, 0x20, 0x02, 0x41, 0x7f, 0x6a, 0x22, - 0x05, 0x41, 0x00, 0x47, 0x21, 0x04, 0x02, 0x40, 0x20, 0x01, 0x41, 0x01, - 0x6a, 0x22, 0x06, 0x41, 0x03, 0x71, 0x45, 0x0d, 0x00, 0x20, 0x05, 0x45, - 0x0d, 0x00, 0x20, 0x03, 0x20, 0x06, 0x2d, 0x00, 0x00, 0x22, 0x04, 0x3a, - 0x00, 0x00, 0x20, 0x04, 0x45, 0x0d, 0x05, 0x20, 0x00, 0x41, 0x02, 0x6a, - 0x21, 0x03, 0x20, 0x02, 0x41, 0x7e, 0x6a, 0x22, 0x05, 0x41, 0x00, 0x47, - 0x21, 0x04, 0x02, 0x40, 0x20, 0x01, 0x41, 0x02, 0x6a, 0x22, 0x06, 0x41, - 0x03, 0x71, 0x45, 0x0d, 0x00, 0x20, 0x05, 0x45, 0x0d, 0x00, 0x20, 0x03, - 0x20, 0x06, 0x2d, 0x00, 0x00, 0x22, 0x04, 0x3a, 0x00, 0x00, 0x20, 0x04, - 0x45, 0x0d, 0x06, 0x20, 0x00, 0x41, 0x03, 0x6a, 0x21, 0x03, 0x20, 0x02, - 0x41, 0x7d, 0x6a, 0x22, 0x05, 0x41, 0x00, 0x47, 0x21, 0x04, 0x02, 0x40, - 0x20, 0x01, 0x41, 0x03, 0x6a, 0x22, 0x06, 0x41, 0x03, 0x71, 0x45, 0x0d, - 0x00, 0x20, 0x05, 0x45, 0x0d, 0x00, 0x20, 0x03, 0x20, 0x06, 0x2d, 0x00, - 0x00, 0x22, 0x04, 0x3a, 0x00, 0x00, 0x20, 0x04, 0x45, 0x0d, 0x07, 0x20, - 0x00, 0x41, 0x04, 0x6a, 0x21, 0x03, 0x20, 0x01, 0x41, 0x04, 0x6a, 0x21, - 0x01, 0x20, 0x02, 0x41, 0x7c, 0x6a, 0x22, 0x02, 0x41, 0x00, 0x47, 0x21, - 0x04, 0x0c, 0x03, 0x0b, 0x20, 0x06, 0x21, 0x01, 0x20, 0x05, 0x21, 0x02, - 0x0c, 0x02, 0x0b, 0x20, 0x06, 0x21, 0x01, 0x20, 0x05, 0x21, 0x02, 0x0c, - 0x01, 0x0b, 0x20, 0x06, 0x21, 0x01, 0x20, 0x05, 0x21, 0x02, 0x0b, 0x20, - 0x04, 0x45, 0x0d, 0x02, 0x02, 0x40, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x0d, - 0x00, 0x20, 0x02, 0x21, 0x05, 0x0c, 0x04, 0x0b, 0x20, 0x02, 0x41, 0x04, - 0x49, 0x0d, 0x00, 0x03, 0x40, 0x41, 0x80, 0x82, 0x84, 0x08, 0x20, 0x01, - 0x28, 0x02, 0x00, 0x22, 0x00, 0x6b, 0x20, 0x00, 0x72, 0x41, 0x80, 0x81, - 0x82, 0x84, 0x78, 0x71, 0x41, 0x80, 0x81, 0x82, 0x84, 0x78, 0x47, 0x0d, - 0x02, 0x20, 0x03, 0x20, 0x00, 0x36, 0x02, 0x00, 0x20, 0x03, 0x41, 0x04, - 0x6a, 0x21, 0x03, 0x20, 0x01, 0x41, 0x04, 0x6a, 0x21, 0x01, 0x20, 0x02, - 0x41, 0x7c, 0x6a, 0x22, 0x02, 0x41, 0x03, 0x4b, 0x0d, 0x00, 0x0b, 0x0b, - 0x20, 0x02, 0x45, 0x0d, 0x01, 0x0b, 0x03, 0x40, 0x20, 0x03, 0x20, 0x01, - 0x2d, 0x00, 0x00, 0x22, 0x00, 0x3a, 0x00, 0x00, 0x02, 0x40, 0x20, 0x00, - 0x0d, 0x00, 0x20, 0x02, 0x21, 0x05, 0x0c, 0x03, 0x0b, 0x20, 0x03, 0x41, - 0x01, 0x6a, 0x21, 0x03, 0x20, 0x01, 0x41, 0x01, 0x6a, 0x21, 0x01, 0x20, - 0x02, 0x41, 0x7f, 0x6a, 0x22, 0x02, 0x0d, 0x00, 0x0b, 0x0b, 0x41, 0x00, - 0x21, 0x05, 0x0b, 0x20, 0x03, 0x41, 0x00, 0x20, 0x05, 0x10, 0x94, 0x80, - 0x80, 0x80, 0x00, 0x0b, 0x11, 0x00, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, - 0x10, 0xa5, 0x80, 0x80, 0x80, 0x00, 0x1a, 0x20, 0x00, 0x0b, 0x17, 0x00, - 0x20, 0x00, 0x41, 0x50, 0x6a, 0x41, 0x0a, 0x49, 0x20, 0x00, 0x41, 0x20, - 0x72, 0x41, 0x9f, 0x7f, 0x6a, 0x41, 0x06, 0x49, 0x72, 0x0b, 0x2a, 0x01, - 0x03, 0x7f, 0x41, 0x00, 0x21, 0x01, 0x03, 0x40, 0x20, 0x00, 0x20, 0x01, - 0x6a, 0x21, 0x02, 0x20, 0x01, 0x41, 0x04, 0x6a, 0x22, 0x03, 0x21, 0x01, - 0x20, 0x02, 0x28, 0x02, 0x00, 0x0d, 0x00, 0x0b, 0x20, 0x03, 0x41, 0x7c, - 0x6a, 0x41, 0x02, 0x75, 0x0b, 0x45, 0x01, 0x01, 0x7f, 0x02, 0x40, 0x20, - 0x01, 0x45, 0x0d, 0x00, 0x20, 0x00, 0x41, 0x7c, 0x6a, 0x21, 0x00, 0x02, - 0x40, 0x03, 0x40, 0x20, 0x00, 0x41, 0x04, 0x6a, 0x22, 0x00, 0x28, 0x02, - 0x00, 0x22, 0x02, 0x45, 0x0d, 0x01, 0x20, 0x02, 0x20, 0x01, 0x47, 0x0d, - 0x00, 0x0b, 0x0b, 0x20, 0x00, 0x41, 0x00, 0x20, 0x02, 0x1b, 0x0f, 0x0b, - 0x20, 0x00, 0x20, 0x00, 0x10, 0xa8, 0x80, 0x80, 0x80, 0x00, 0x41, 0x02, - 0x74, 0x6a, 0x0b, 0x1d, 0x00, 0x02, 0x40, 0x20, 0x00, 0x0d, 0x00, 0x41, - 0x00, 0x0f, 0x0b, 0x41, 0x90, 0xc2, 0x84, 0x80, 0x00, 0x20, 0x00, 0x10, - 0xa9, 0x80, 0x80, 0x80, 0x00, 0x41, 0x00, 0x47, 0x0b, 0x24, 0x01, 0x01, - 0x7f, 0x41, 0x01, 0x21, 0x01, 0x02, 0x40, 0x20, 0x00, 0x41, 0x50, 0x6a, - 0x41, 0x0a, 0x49, 0x0d, 0x00, 0x20, 0x00, 0x10, 0x96, 0x80, 0x80, 0x80, - 0x00, 0x41, 0x00, 0x47, 0x21, 0x01, 0x0b, 0x20, 0x01, 0x0b, 0x0b, 0xf1, - 0x42, 0x01, 0x00, 0x41, 0x80, 0x80, 0x04, 0x0b, 0xe8, 0x42, 0x12, 0x11, - 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, - 0x1f, 0x20, 0x21, 0x11, 0x22, 0x23, 0x24, 0x11, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x2b, 0x2c, 0x11, 0x2d, 0x2e, 0x2f, 0x10, 0x10, 0x30, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x31, 0x32, 0x33, 0x10, 0x34, 0x35, - 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x41, 0x01, 0x6b, 0x22, 0x02, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x04, 0x41, + 0x08, 0x49, 0x0d, 0x00, 0x03, 0x40, 0x20, 0x03, 0x20, 0x01, 0x2d, 0x00, + 0x00, 0x3a, 0x00, 0x00, 0x20, 0x03, 0x41, 0x01, 0x6a, 0x20, 0x01, 0x41, + 0x01, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x03, 0x41, 0x02, + 0x6a, 0x20, 0x01, 0x41, 0x02, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, + 0x20, 0x03, 0x41, 0x03, 0x6a, 0x20, 0x01, 0x41, 0x03, 0x6a, 0x2d, 0x00, + 0x00, 0x3a, 0x00, 0x00, 0x20, 0x03, 0x41, 0x04, 0x6a, 0x20, 0x01, 0x41, + 0x04, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x03, 0x41, 0x05, + 0x6a, 0x20, 0x01, 0x41, 0x05, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, + 0x20, 0x03, 0x41, 0x06, 0x6a, 0x20, 0x01, 0x41, 0x06, 0x6a, 0x2d, 0x00, + 0x00, 0x3a, 0x00, 0x00, 0x20, 0x03, 0x41, 0x07, 0x6a, 0x20, 0x01, 0x41, + 0x07, 0x6a, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x03, 0x41, 0x08, + 0x6a, 0x21, 0x03, 0x20, 0x01, 0x41, 0x08, 0x6a, 0x21, 0x01, 0x20, 0x05, + 0x41, 0x08, 0x6b, 0x22, 0x05, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x00, 0x0f, + 0x0b, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0xfc, 0x0a, 0x00, 0x00, 0x20, + 0x00, 0x0b, 0x94, 0x03, 0x02, 0x03, 0x7f, 0x01, 0x7e, 0x02, 0x40, 0x20, + 0x02, 0x41, 0x21, 0x4f, 0x04, 0x40, 0x20, 0x02, 0x45, 0x0d, 0x01, 0x20, + 0x00, 0x20, 0x01, 0x20, 0x02, 0xfc, 0x0b, 0x00, 0x20, 0x00, 0x0f, 0x0b, + 0x20, 0x02, 0x45, 0x0d, 0x00, 0x20, 0x00, 0x20, 0x01, 0x3a, 0x00, 0x00, + 0x20, 0x00, 0x20, 0x02, 0x6a, 0x22, 0x03, 0x41, 0x01, 0x6b, 0x20, 0x01, + 0x3a, 0x00, 0x00, 0x20, 0x02, 0x41, 0x03, 0x49, 0x0d, 0x00, 0x20, 0x00, + 0x20, 0x01, 0x3a, 0x00, 0x02, 0x20, 0x00, 0x20, 0x01, 0x3a, 0x00, 0x01, + 0x20, 0x03, 0x41, 0x03, 0x6b, 0x20, 0x01, 0x3a, 0x00, 0x00, 0x20, 0x03, + 0x41, 0x02, 0x6b, 0x20, 0x01, 0x3a, 0x00, 0x00, 0x20, 0x02, 0x41, 0x07, + 0x49, 0x0d, 0x00, 0x20, 0x00, 0x20, 0x01, 0x3a, 0x00, 0x03, 0x20, 0x03, + 0x41, 0x04, 0x6b, 0x20, 0x01, 0x3a, 0x00, 0x00, 0x20, 0x02, 0x41, 0x09, + 0x49, 0x0d, 0x00, 0x20, 0x00, 0x41, 0x00, 0x20, 0x00, 0x6b, 0x41, 0x03, + 0x71, 0x22, 0x05, 0x6a, 0x22, 0x04, 0x20, 0x01, 0x41, 0xff, 0x01, 0x71, + 0x41, 0x81, 0x82, 0x84, 0x08, 0x6c, 0x22, 0x03, 0x36, 0x02, 0x00, 0x20, + 0x04, 0x20, 0x02, 0x20, 0x05, 0x6b, 0x41, 0x3c, 0x71, 0x22, 0x02, 0x6a, + 0x22, 0x01, 0x41, 0x04, 0x6b, 0x20, 0x03, 0x36, 0x02, 0x00, 0x20, 0x02, + 0x41, 0x09, 0x49, 0x0d, 0x00, 0x20, 0x04, 0x20, 0x03, 0x36, 0x02, 0x08, + 0x20, 0x04, 0x20, 0x03, 0x36, 0x02, 0x04, 0x20, 0x01, 0x41, 0x08, 0x6b, + 0x20, 0x03, 0x36, 0x02, 0x00, 0x20, 0x01, 0x41, 0x0c, 0x6b, 0x20, 0x03, + 0x36, 0x02, 0x00, 0x20, 0x02, 0x41, 0x19, 0x49, 0x0d, 0x00, 0x20, 0x04, + 0x20, 0x03, 0x36, 0x02, 0x18, 0x20, 0x04, 0x20, 0x03, 0x36, 0x02, 0x14, + 0x20, 0x04, 0x20, 0x03, 0x36, 0x02, 0x10, 0x20, 0x04, 0x20, 0x03, 0x36, + 0x02, 0x0c, 0x20, 0x01, 0x41, 0x10, 0x6b, 0x20, 0x03, 0x36, 0x02, 0x00, + 0x20, 0x01, 0x41, 0x14, 0x6b, 0x20, 0x03, 0x36, 0x02, 0x00, 0x20, 0x01, + 0x41, 0x18, 0x6b, 0x20, 0x03, 0x36, 0x02, 0x00, 0x20, 0x01, 0x41, 0x1c, + 0x6b, 0x20, 0x03, 0x36, 0x02, 0x00, 0x20, 0x02, 0x20, 0x04, 0x41, 0x04, + 0x71, 0x41, 0x18, 0x72, 0x22, 0x02, 0x6b, 0x22, 0x01, 0x41, 0x20, 0x49, + 0x0d, 0x00, 0x20, 0x03, 0xad, 0x42, 0x81, 0x80, 0x80, 0x80, 0x10, 0x7e, + 0x21, 0x06, 0x20, 0x02, 0x20, 0x04, 0x6a, 0x21, 0x02, 0x03, 0x40, 0x20, + 0x02, 0x20, 0x06, 0x37, 0x03, 0x00, 0x20, 0x02, 0x41, 0x18, 0x6a, 0x20, + 0x06, 0x37, 0x03, 0x00, 0x20, 0x02, 0x41, 0x10, 0x6a, 0x20, 0x06, 0x37, + 0x03, 0x00, 0x20, 0x02, 0x41, 0x08, 0x6a, 0x20, 0x06, 0x37, 0x03, 0x00, + 0x20, 0x02, 0x41, 0x20, 0x6a, 0x21, 0x02, 0x20, 0x01, 0x41, 0x20, 0x6b, + 0x22, 0x01, 0x41, 0x1f, 0x4b, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x00, 0x0b, + 0x09, 0x00, 0x20, 0x00, 0x10, 0x13, 0x20, 0x00, 0x47, 0x0b, 0xd5, 0x07, + 0x01, 0x04, 0x7f, 0x02, 0x40, 0x02, 0x7f, 0x02, 0x40, 0x20, 0x02, 0x41, + 0x20, 0x4d, 0x04, 0x40, 0x20, 0x01, 0x41, 0x03, 0x71, 0x45, 0x20, 0x02, + 0x45, 0x72, 0x0d, 0x01, 0x20, 0x00, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x3a, + 0x00, 0x00, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x20, 0x01, 0x41, 0x01, 0x6a, + 0x22, 0x03, 0x41, 0x03, 0x71, 0x45, 0x20, 0x02, 0x41, 0x01, 0x6b, 0x22, + 0x05, 0x45, 0x72, 0x0d, 0x02, 0x1a, 0x20, 0x00, 0x20, 0x01, 0x2d, 0x00, + 0x01, 0x3a, 0x00, 0x01, 0x20, 0x00, 0x41, 0x02, 0x6a, 0x20, 0x01, 0x41, + 0x02, 0x6a, 0x22, 0x03, 0x41, 0x03, 0x71, 0x45, 0x20, 0x02, 0x41, 0x02, + 0x6b, 0x22, 0x05, 0x45, 0x72, 0x0d, 0x02, 0x1a, 0x20, 0x00, 0x20, 0x01, + 0x2d, 0x00, 0x02, 0x3a, 0x00, 0x02, 0x20, 0x00, 0x41, 0x03, 0x6a, 0x20, + 0x01, 0x41, 0x03, 0x6a, 0x22, 0x03, 0x41, 0x03, 0x71, 0x45, 0x20, 0x02, + 0x41, 0x03, 0x6b, 0x22, 0x05, 0x45, 0x72, 0x0d, 0x02, 0x1a, 0x20, 0x00, + 0x20, 0x01, 0x2d, 0x00, 0x03, 0x3a, 0x00, 0x03, 0x20, 0x02, 0x41, 0x04, + 0x6b, 0x21, 0x05, 0x20, 0x01, 0x41, 0x04, 0x6a, 0x21, 0x03, 0x20, 0x00, + 0x41, 0x04, 0x6a, 0x0c, 0x02, 0x0b, 0x20, 0x02, 0x45, 0x0d, 0x02, 0x20, + 0x00, 0x20, 0x01, 0x20, 0x02, 0xfc, 0x0a, 0x00, 0x00, 0x20, 0x00, 0x0f, + 0x0b, 0x20, 0x02, 0x21, 0x05, 0x20, 0x01, 0x21, 0x03, 0x20, 0x00, 0x0b, + 0x22, 0x04, 0x41, 0x03, 0x71, 0x22, 0x02, 0x45, 0x04, 0x40, 0x02, 0x40, + 0x20, 0x05, 0x41, 0x10, 0x49, 0x04, 0x40, 0x20, 0x05, 0x21, 0x02, 0x0c, + 0x01, 0x0b, 0x20, 0x05, 0x41, 0x10, 0x6b, 0x22, 0x02, 0x41, 0x10, 0x71, + 0x45, 0x04, 0x40, 0x20, 0x04, 0x20, 0x03, 0x29, 0x02, 0x00, 0x37, 0x02, + 0x00, 0x20, 0x04, 0x20, 0x03, 0x29, 0x02, 0x08, 0x37, 0x02, 0x08, 0x20, + 0x04, 0x41, 0x10, 0x6a, 0x21, 0x04, 0x20, 0x03, 0x41, 0x10, 0x6a, 0x21, + 0x03, 0x20, 0x02, 0x21, 0x05, 0x0b, 0x20, 0x02, 0x41, 0x10, 0x49, 0x0d, + 0x00, 0x20, 0x05, 0x21, 0x02, 0x03, 0x40, 0x20, 0x04, 0x20, 0x03, 0x29, + 0x02, 0x00, 0x37, 0x02, 0x00, 0x20, 0x04, 0x41, 0x08, 0x6a, 0x20, 0x03, + 0x41, 0x08, 0x6a, 0x29, 0x02, 0x00, 0x37, 0x02, 0x00, 0x20, 0x04, 0x41, + 0x10, 0x6a, 0x20, 0x03, 0x41, 0x10, 0x6a, 0x29, 0x02, 0x00, 0x37, 0x02, + 0x00, 0x20, 0x04, 0x41, 0x18, 0x6a, 0x20, 0x03, 0x41, 0x18, 0x6a, 0x29, + 0x02, 0x00, 0x37, 0x02, 0x00, 0x20, 0x04, 0x41, 0x20, 0x6a, 0x21, 0x04, + 0x20, 0x03, 0x41, 0x20, 0x6a, 0x21, 0x03, 0x20, 0x02, 0x41, 0x20, 0x6b, + 0x22, 0x02, 0x41, 0x0f, 0x4b, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x02, 0x41, + 0x08, 0x4f, 0x04, 0x40, 0x20, 0x04, 0x20, 0x03, 0x29, 0x02, 0x00, 0x37, + 0x02, 0x00, 0x20, 0x04, 0x41, 0x08, 0x6a, 0x21, 0x04, 0x20, 0x03, 0x41, + 0x08, 0x6a, 0x21, 0x03, 0x0b, 0x20, 0x02, 0x41, 0x04, 0x71, 0x04, 0x40, + 0x20, 0x04, 0x20, 0x03, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00, 0x20, 0x04, + 0x41, 0x04, 0x6a, 0x21, 0x04, 0x20, 0x03, 0x41, 0x04, 0x6a, 0x21, 0x03, + 0x0b, 0x20, 0x02, 0x41, 0x02, 0x71, 0x04, 0x40, 0x20, 0x04, 0x20, 0x03, + 0x2f, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x20, 0x04, 0x41, 0x02, 0x6a, 0x21, + 0x04, 0x20, 0x03, 0x41, 0x02, 0x6a, 0x21, 0x03, 0x0b, 0x20, 0x02, 0x41, + 0x01, 0x71, 0x45, 0x0d, 0x01, 0x20, 0x04, 0x20, 0x03, 0x2d, 0x00, 0x00, + 0x3a, 0x00, 0x00, 0x20, 0x00, 0x0f, 0x0b, 0x02, 0x40, 0x02, 0x40, 0x02, + 0x7f, 0x02, 0x40, 0x20, 0x05, 0x41, 0x20, 0x4f, 0x04, 0x40, 0x20, 0x04, + 0x20, 0x03, 0x28, 0x02, 0x00, 0x22, 0x01, 0x3a, 0x00, 0x00, 0x02, 0x40, + 0x02, 0x40, 0x20, 0x02, 0x41, 0x02, 0x6b, 0x0e, 0x02, 0x00, 0x01, 0x03, + 0x0b, 0x20, 0x04, 0x20, 0x01, 0x41, 0x08, 0x76, 0x3a, 0x00, 0x01, 0x20, + 0x04, 0x20, 0x03, 0x41, 0x06, 0x6a, 0x29, 0x01, 0x00, 0x37, 0x02, 0x06, + 0x20, 0x04, 0x20, 0x03, 0x28, 0x02, 0x04, 0x41, 0x10, 0x74, 0x20, 0x01, + 0x41, 0x10, 0x76, 0x72, 0x36, 0x02, 0x02, 0x20, 0x03, 0x41, 0x12, 0x6a, + 0x21, 0x01, 0x41, 0x0e, 0x21, 0x06, 0x20, 0x03, 0x41, 0x0e, 0x6a, 0x28, + 0x01, 0x00, 0x21, 0x03, 0x41, 0x0e, 0x21, 0x05, 0x20, 0x04, 0x41, 0x12, + 0x6a, 0x0c, 0x03, 0x0b, 0x20, 0x04, 0x20, 0x03, 0x41, 0x05, 0x6a, 0x29, + 0x00, 0x00, 0x37, 0x02, 0x05, 0x20, 0x04, 0x20, 0x03, 0x28, 0x02, 0x04, + 0x41, 0x18, 0x74, 0x20, 0x01, 0x41, 0x08, 0x76, 0x72, 0x36, 0x02, 0x01, + 0x20, 0x03, 0x41, 0x11, 0x6a, 0x21, 0x01, 0x41, 0x0d, 0x21, 0x06, 0x20, + 0x03, 0x41, 0x0d, 0x6a, 0x28, 0x00, 0x00, 0x21, 0x03, 0x41, 0x0f, 0x21, + 0x05, 0x20, 0x04, 0x41, 0x11, 0x6a, 0x0c, 0x02, 0x0b, 0x02, 0x7f, 0x20, + 0x05, 0x41, 0x10, 0x49, 0x04, 0x40, 0x20, 0x04, 0x21, 0x02, 0x20, 0x03, + 0x0c, 0x01, 0x0b, 0x20, 0x04, 0x20, 0x03, 0x2d, 0x00, 0x00, 0x3a, 0x00, + 0x00, 0x20, 0x04, 0x20, 0x03, 0x28, 0x00, 0x01, 0x36, 0x00, 0x01, 0x20, + 0x04, 0x20, 0x03, 0x29, 0x00, 0x05, 0x37, 0x00, 0x05, 0x20, 0x04, 0x20, + 0x03, 0x2f, 0x00, 0x0d, 0x3b, 0x00, 0x0d, 0x20, 0x04, 0x20, 0x03, 0x2d, + 0x00, 0x0f, 0x3a, 0x00, 0x0f, 0x20, 0x04, 0x41, 0x10, 0x6a, 0x21, 0x02, + 0x20, 0x03, 0x41, 0x10, 0x6a, 0x0b, 0x21, 0x01, 0x20, 0x05, 0x41, 0x08, + 0x71, 0x0d, 0x02, 0x0c, 0x03, 0x0b, 0x20, 0x04, 0x20, 0x01, 0x41, 0x10, + 0x76, 0x3a, 0x00, 0x02, 0x20, 0x04, 0x20, 0x01, 0x41, 0x08, 0x76, 0x3a, + 0x00, 0x01, 0x20, 0x04, 0x20, 0x03, 0x41, 0x07, 0x6a, 0x29, 0x00, 0x00, + 0x37, 0x02, 0x07, 0x20, 0x04, 0x20, 0x03, 0x28, 0x02, 0x04, 0x41, 0x08, + 0x74, 0x20, 0x01, 0x41, 0x18, 0x76, 0x72, 0x36, 0x02, 0x03, 0x20, 0x03, + 0x41, 0x13, 0x6a, 0x21, 0x01, 0x41, 0x0f, 0x21, 0x06, 0x20, 0x03, 0x41, + 0x0f, 0x6a, 0x28, 0x00, 0x00, 0x21, 0x03, 0x41, 0x0d, 0x21, 0x05, 0x20, + 0x04, 0x41, 0x13, 0x6a, 0x0b, 0x21, 0x02, 0x20, 0x04, 0x20, 0x06, 0x6a, + 0x20, 0x03, 0x36, 0x02, 0x00, 0x0b, 0x20, 0x02, 0x20, 0x01, 0x29, 0x00, + 0x00, 0x37, 0x00, 0x00, 0x20, 0x02, 0x41, 0x08, 0x6a, 0x21, 0x02, 0x20, + 0x01, 0x41, 0x08, 0x6a, 0x21, 0x01, 0x0b, 0x20, 0x05, 0x41, 0x04, 0x71, + 0x04, 0x40, 0x20, 0x02, 0x20, 0x01, 0x28, 0x00, 0x00, 0x36, 0x00, 0x00, + 0x20, 0x02, 0x41, 0x04, 0x6a, 0x21, 0x02, 0x20, 0x01, 0x41, 0x04, 0x6a, + 0x21, 0x01, 0x0b, 0x20, 0x05, 0x41, 0x02, 0x71, 0x04, 0x40, 0x20, 0x02, + 0x20, 0x01, 0x2f, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x20, 0x02, 0x41, 0x02, + 0x6a, 0x21, 0x02, 0x20, 0x01, 0x41, 0x02, 0x6a, 0x21, 0x01, 0x0b, 0x20, + 0x05, 0x41, 0x01, 0x71, 0x45, 0x0d, 0x00, 0x20, 0x02, 0x20, 0x01, 0x2d, + 0x00, 0x00, 0x3a, 0x00, 0x00, 0x0b, 0x20, 0x00, 0x0b, 0x0d, 0x00, 0x20, + 0x00, 0x41, 0x20, 0x46, 0x20, 0x00, 0x41, 0x09, 0x46, 0x72, 0x0b, 0x0a, + 0x00, 0x20, 0x00, 0x41, 0x30, 0x6b, 0x41, 0x0a, 0x49, 0x0b, 0x49, 0x01, + 0x02, 0x7f, 0x20, 0x00, 0x10, 0x0c, 0x20, 0x00, 0x6a, 0x21, 0x03, 0x02, + 0x40, 0x20, 0x02, 0x45, 0x0d, 0x00, 0x03, 0x40, 0x20, 0x01, 0x2d, 0x00, + 0x00, 0x22, 0x04, 0x45, 0x0d, 0x01, 0x20, 0x03, 0x20, 0x04, 0x3a, 0x00, + 0x00, 0x20, 0x03, 0x41, 0x01, 0x6a, 0x21, 0x03, 0x20, 0x01, 0x41, 0x01, + 0x6a, 0x21, 0x01, 0x20, 0x02, 0x41, 0x01, 0x6b, 0x22, 0x02, 0x0d, 0x00, + 0x0b, 0x0b, 0x20, 0x03, 0x41, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x00, 0x0b, + 0xeb, 0x03, 0x01, 0x04, 0x7f, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, + 0x40, 0x20, 0x00, 0x20, 0x01, 0x22, 0x03, 0x73, 0x41, 0x03, 0x71, 0x04, + 0x40, 0x20, 0x00, 0x21, 0x04, 0x0c, 0x01, 0x0b, 0x20, 0x02, 0x41, 0x00, + 0x47, 0x21, 0x06, 0x02, 0x40, 0x20, 0x03, 0x41, 0x03, 0x71, 0x45, 0x04, + 0x40, 0x20, 0x00, 0x21, 0x04, 0x0c, 0x01, 0x0b, 0x20, 0x02, 0x45, 0x04, + 0x40, 0x20, 0x00, 0x21, 0x04, 0x0c, 0x01, 0x0b, 0x20, 0x00, 0x20, 0x03, + 0x2d, 0x00, 0x00, 0x22, 0x01, 0x3a, 0x00, 0x00, 0x20, 0x01, 0x45, 0x04, + 0x40, 0x20, 0x00, 0x21, 0x04, 0x20, 0x02, 0x21, 0x01, 0x0c, 0x05, 0x0b, + 0x20, 0x00, 0x41, 0x01, 0x6a, 0x21, 0x04, 0x20, 0x02, 0x41, 0x01, 0x6b, + 0x22, 0x01, 0x41, 0x00, 0x47, 0x21, 0x06, 0x20, 0x03, 0x41, 0x01, 0x6a, + 0x22, 0x05, 0x41, 0x03, 0x71, 0x45, 0x20, 0x01, 0x45, 0x72, 0x45, 0x04, + 0x40, 0x20, 0x04, 0x20, 0x05, 0x2d, 0x00, 0x00, 0x22, 0x05, 0x3a, 0x00, + 0x00, 0x20, 0x05, 0x45, 0x0d, 0x05, 0x20, 0x00, 0x41, 0x02, 0x6a, 0x21, + 0x04, 0x20, 0x02, 0x41, 0x02, 0x6b, 0x22, 0x01, 0x41, 0x00, 0x47, 0x21, + 0x06, 0x20, 0x03, 0x41, 0x02, 0x6a, 0x22, 0x05, 0x41, 0x03, 0x71, 0x45, + 0x20, 0x01, 0x45, 0x72, 0x45, 0x04, 0x40, 0x20, 0x04, 0x20, 0x05, 0x2d, + 0x00, 0x00, 0x22, 0x05, 0x3a, 0x00, 0x00, 0x20, 0x05, 0x45, 0x0d, 0x06, + 0x20, 0x00, 0x41, 0x03, 0x6a, 0x21, 0x04, 0x20, 0x02, 0x41, 0x03, 0x6b, + 0x22, 0x01, 0x41, 0x00, 0x47, 0x21, 0x06, 0x20, 0x03, 0x41, 0x03, 0x6a, + 0x22, 0x05, 0x41, 0x03, 0x71, 0x45, 0x20, 0x01, 0x45, 0x72, 0x45, 0x04, + 0x40, 0x20, 0x04, 0x20, 0x05, 0x2d, 0x00, 0x00, 0x22, 0x05, 0x3a, 0x00, + 0x00, 0x20, 0x05, 0x45, 0x0d, 0x07, 0x20, 0x00, 0x41, 0x04, 0x6a, 0x21, + 0x04, 0x20, 0x03, 0x41, 0x04, 0x6a, 0x21, 0x03, 0x20, 0x02, 0x41, 0x04, + 0x6b, 0x22, 0x02, 0x41, 0x00, 0x47, 0x21, 0x06, 0x0c, 0x03, 0x0b, 0x20, + 0x05, 0x21, 0x03, 0x20, 0x01, 0x21, 0x02, 0x0c, 0x02, 0x0b, 0x20, 0x05, + 0x21, 0x03, 0x20, 0x01, 0x21, 0x02, 0x0c, 0x01, 0x0b, 0x20, 0x05, 0x21, + 0x03, 0x20, 0x01, 0x21, 0x02, 0x0b, 0x20, 0x06, 0x45, 0x0d, 0x02, 0x20, + 0x03, 0x2d, 0x00, 0x00, 0x45, 0x04, 0x40, 0x20, 0x02, 0x21, 0x01, 0x0c, + 0x04, 0x0b, 0x20, 0x02, 0x41, 0x04, 0x49, 0x0d, 0x00, 0x03, 0x40, 0x41, + 0x80, 0x82, 0x84, 0x08, 0x20, 0x03, 0x28, 0x02, 0x00, 0x22, 0x01, 0x6b, + 0x20, 0x01, 0x72, 0x41, 0x80, 0x81, 0x82, 0x84, 0x78, 0x71, 0x41, 0x80, + 0x81, 0x82, 0x84, 0x78, 0x47, 0x0d, 0x02, 0x20, 0x04, 0x20, 0x01, 0x36, + 0x02, 0x00, 0x20, 0x04, 0x41, 0x04, 0x6a, 0x21, 0x04, 0x20, 0x03, 0x41, + 0x04, 0x6a, 0x21, 0x03, 0x20, 0x02, 0x41, 0x04, 0x6b, 0x22, 0x02, 0x41, + 0x03, 0x4b, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x02, 0x45, 0x0d, 0x01, 0x0b, + 0x03, 0x40, 0x20, 0x04, 0x20, 0x03, 0x2d, 0x00, 0x00, 0x22, 0x01, 0x3a, + 0x00, 0x00, 0x20, 0x01, 0x45, 0x04, 0x40, 0x20, 0x02, 0x21, 0x01, 0x0c, + 0x03, 0x0b, 0x20, 0x04, 0x41, 0x01, 0x6a, 0x21, 0x04, 0x20, 0x03, 0x41, + 0x01, 0x6a, 0x21, 0x03, 0x20, 0x02, 0x41, 0x01, 0x6b, 0x22, 0x02, 0x0d, + 0x00, 0x0b, 0x0b, 0x41, 0x00, 0x21, 0x01, 0x0b, 0x20, 0x01, 0x04, 0x40, + 0x20, 0x04, 0x41, 0x00, 0x20, 0x01, 0xfc, 0x0b, 0x00, 0x0b, 0x20, 0x00, + 0x0b, 0x17, 0x00, 0x20, 0x00, 0x41, 0x30, 0x6b, 0x41, 0x0a, 0x49, 0x20, + 0x00, 0x41, 0x20, 0x72, 0x41, 0xe1, 0x00, 0x6b, 0x41, 0x06, 0x49, 0x72, + 0x0b, 0x67, 0x01, 0x02, 0x7f, 0x20, 0x00, 0x45, 0x04, 0x40, 0x41, 0x00, + 0x0f, 0x0b, 0x02, 0x7f, 0x20, 0x00, 0x04, 0x40, 0x41, 0x8c, 0xc2, 0x04, + 0x21, 0x01, 0x03, 0x40, 0x20, 0x01, 0x41, 0x04, 0x6a, 0x22, 0x01, 0x28, + 0x02, 0x00, 0x22, 0x02, 0x41, 0x00, 0x20, 0x00, 0x20, 0x02, 0x47, 0x1b, + 0x0d, 0x00, 0x0b, 0x20, 0x01, 0x41, 0x00, 0x20, 0x02, 0x1b, 0x0c, 0x01, + 0x0b, 0x41, 0x00, 0x21, 0x00, 0x03, 0x40, 0x20, 0x00, 0x41, 0x90, 0xc2, + 0x04, 0x6a, 0x20, 0x00, 0x41, 0x04, 0x6a, 0x21, 0x00, 0x28, 0x02, 0x00, + 0x0d, 0x00, 0x0b, 0x20, 0x00, 0x41, 0x04, 0x6b, 0x41, 0x7c, 0x71, 0x41, + 0x90, 0xc2, 0x04, 0x6a, 0x0b, 0x41, 0x00, 0x47, 0x0b, 0x1d, 0x01, 0x01, + 0x7f, 0x41, 0x01, 0x21, 0x01, 0x20, 0x00, 0x41, 0x30, 0x6b, 0x41, 0x0a, + 0x4f, 0x04, 0x7f, 0x20, 0x00, 0x10, 0x0d, 0x41, 0x00, 0x47, 0x05, 0x20, + 0x01, 0x0b, 0x0b, 0x0b, 0xfc, 0x42, 0x02, 0x00, 0x41, 0x80, 0x80, 0x04, + 0x0b, 0xe8, 0x42, 0x12, 0x11, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x11, 0x22, 0x23, 0x24, + 0x11, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x11, 0x2d, 0x2e, + 0x2f, 0x10, 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x31, + 0x32, 0x33, 0x10, 0x34, 0x35, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x36, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x36, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x37, 0x11, 0x11, 0x11, 0x11, 0x38, 0x11, 0x39, 0x3a, 0x3b, 0x3c, - 0x3d, 0x3e, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x37, 0x11, 0x11, 0x11, 0x11, 0x38, + 0x11, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x3f, 0x10, 0x10, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x3f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x40, 0x41, 0x11, 0x42, - 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x11, 0x4b, 0x4c, 0x4d, - 0x4e, 0x4f, 0x50, 0x51, 0x10, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, - 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x10, 0x5e, 0x5f, 0x60, 0x10, 0x11, 0x11, - 0x11, 0x61, 0x62, 0x63, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x64, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, - 0x65, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x11, 0x40, 0x41, 0x11, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x11, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x10, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x10, 0x5e, + 0x5f, 0x60, 0x10, 0x11, 0x11, 0x11, 0x61, 0x62, 0x63, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x64, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, - 0x66, 0x67, 0x10, 0x10, 0x68, 0x69, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x10, 0x10, 0x10, 0x11, 0x11, 0x65, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x11, 0x11, 0x66, 0x67, 0x10, 0x10, 0x68, 0x69, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x6a, 0x11, 0x11, 0x6b, 0x10, 0x10, 0x10, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x6a, 0x11, + 0x11, 0x6b, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x6c, - 0x6d, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x6e, 0x10, + 0x10, 0x10, 0x10, 0x11, 0x6c, 0x6d, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x6e, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x6f, 0x70, - 0x71, 0x72, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x73, 0x74, - 0x75, 0x10, 0x10, 0x10, 0x10, 0x10, 0x76, 0x77, 0x10, 0x10, 0x10, 0x10, - 0x78, 0x10, 0x10, 0x79, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0x6f, 0x70, 0x71, 0x72, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x73, 0x74, 0x75, 0x10, 0x10, 0x10, 0x10, 0x10, 0x76, + 0x77, 0x10, 0x10, 0x10, 0x10, 0x78, 0x10, 0x10, 0x79, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x07, 0xfe, 0xff, - 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x04, 0xff, 0xff, - 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xff, 0x03, 0x00, 0x1f, 0x50, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xdf, 0xbc, 0x40, 0xd7, 0xff, 0xff, 0xfb, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, + 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x20, 0x04, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x03, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, + 0xff, 0x03, 0x00, 0x1f, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0xbc, 0x40, + 0xd7, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0x7f, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xbf, 0xb6, 0x00, 0xff, 0xff, 0xff, 0x87, - 0x07, 0x00, 0x00, 0x00, 0xff, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xef, 0x1f, 0xfe, 0xe1, 0xff, 0x9f, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x07, 0x30, 0x04, 0xff, 0xff, 0xff, 0xfc, 0xff, 0x1f, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xdf, 0x3f, 0x00, 0x00, 0xf0, 0xff, 0xf8, 0x03, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xdf, - 0xe1, 0xff, 0xcf, 0xff, 0xfe, 0xff, 0xef, 0x9f, 0xf9, 0xff, 0xff, 0xfd, - 0xc5, 0xe3, 0x9f, 0x59, 0x80, 0xb0, 0xcf, 0xff, 0x03, 0x10, 0xee, 0x87, - 0xf9, 0xff, 0xff, 0xfd, 0x6d, 0xc3, 0x87, 0x19, 0x02, 0x5e, 0xc0, 0xff, - 0x3f, 0x00, 0xee, 0xbf, 0xfb, 0xff, 0xff, 0xfd, 0xed, 0xe3, 0xbf, 0x1b, - 0x01, 0x00, 0xcf, 0xff, 0x00, 0x1e, 0xee, 0x9f, 0xf9, 0xff, 0xff, 0xfd, - 0xed, 0xe3, 0x9f, 0x19, 0xc0, 0xb0, 0xcf, 0xff, 0x02, 0x00, 0xec, 0xc7, - 0x3d, 0xd6, 0x18, 0xc7, 0xff, 0xc3, 0xc7, 0x1d, 0x81, 0x00, 0xc0, 0xff, - 0x00, 0x00, 0xef, 0xdf, 0xfd, 0xff, 0xff, 0xfd, 0xff, 0xe3, 0xdf, 0x1d, - 0x60, 0x07, 0xcf, 0xff, 0x00, 0x00, 0xef, 0xdf, 0xfd, 0xff, 0xff, 0xfd, - 0xef, 0xe3, 0xdf, 0x1d, 0x60, 0x40, 0xcf, 0xff, 0x06, 0x00, 0xef, 0xdf, - 0xfd, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xdf, 0x5d, 0xf0, 0x80, 0xcf, 0xff, - 0x00, 0xfc, 0xec, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0xfb, 0x2f, 0x7f, 0x80, - 0x5f, 0xff, 0xc0, 0xff, 0x0c, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x7f, - 0xff, 0x07, 0x3f, 0x20, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xf7, - 0xff, 0xff, 0xaf, 0xff, 0xff, 0x3b, 0x5f, 0x20, 0xff, 0xf3, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0x03, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x7f, 0xf9, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x20, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x3d, 0x7f, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, - 0xff, 0xff, 0xff, 0xff, 0x3d, 0x7f, 0x3d, 0xff, 0x7f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x3f, 0xfe, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0x7f, 0x02, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xbf, 0xb6, + 0x00, 0xff, 0xff, 0xff, 0x87, 0x07, 0x00, 0x00, 0x00, 0xff, 0x07, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xc3, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x1f, 0xfe, + 0xe1, 0xff, 0x9f, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x03, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x30, 0x04, 0xff, + 0xff, 0xff, 0xfc, 0xff, 0x1f, 0x00, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdf, 0x3f, 0x00, + 0x00, 0xf0, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xef, 0xff, 0xdf, 0xe1, 0xff, 0xcf, 0xff, 0xfe, 0xff, 0xef, + 0x9f, 0xf9, 0xff, 0xff, 0xfd, 0xc5, 0xe3, 0x9f, 0x59, 0x80, 0xb0, 0xcf, + 0xff, 0x03, 0x10, 0xee, 0x87, 0xf9, 0xff, 0xff, 0xfd, 0x6d, 0xc3, 0x87, + 0x19, 0x02, 0x5e, 0xc0, 0xff, 0x3f, 0x00, 0xee, 0xbf, 0xfb, 0xff, 0xff, + 0xfd, 0xed, 0xe3, 0xbf, 0x1b, 0x01, 0x00, 0xcf, 0xff, 0x00, 0x1e, 0xee, + 0x9f, 0xf9, 0xff, 0xff, 0xfd, 0xed, 0xe3, 0x9f, 0x19, 0xc0, 0xb0, 0xcf, + 0xff, 0x02, 0x00, 0xec, 0xc7, 0x3d, 0xd6, 0x18, 0xc7, 0xff, 0xc3, 0xc7, + 0x1d, 0x81, 0x00, 0xc0, 0xff, 0x00, 0x00, 0xef, 0xdf, 0xfd, 0xff, 0xff, + 0xfd, 0xff, 0xe3, 0xdf, 0x1d, 0x60, 0x07, 0xcf, 0xff, 0x00, 0x00, 0xef, + 0xdf, 0xfd, 0xff, 0xff, 0xfd, 0xef, 0xe3, 0xdf, 0x1d, 0x60, 0x40, 0xcf, + 0xff, 0x06, 0x00, 0xef, 0xdf, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xdf, + 0x5d, 0xf0, 0x80, 0xcf, 0xff, 0x00, 0xfc, 0xec, 0xff, 0x7f, 0xfc, 0xff, + 0xff, 0xfb, 0x2f, 0x7f, 0x80, 0x5f, 0xff, 0xc0, 0xff, 0x0c, 0x00, 0xfe, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0x07, 0x3f, 0x20, 0xff, 0x03, 0x00, + 0x00, 0x00, 0x00, 0xd6, 0xf7, 0xff, 0xff, 0xaf, 0xff, 0xff, 0x3b, 0x5f, + 0x20, 0xff, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, + 0x03, 0x00, 0x00, 0xff, 0xfe, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0x03, + 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xf9, 0xff, + 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0xff, 0xbf, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0x7f, 0x3d, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x3d, 0xff, 0xff, 0xff, 0xff, 0x3d, 0x7f, 0x3d, + 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x3f, 0x3f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, - 0xff, 0x01, 0xff, 0xdf, 0x0f, 0x00, 0xff, 0xff, 0x0f, 0x00, 0xff, 0xff, - 0x0f, 0x00, 0xff, 0xdf, 0x0d, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xcf, 0xff, 0xff, 0x01, 0x80, 0x10, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xff, 0xff, 0xff, 0x7f, 0xff, 0x0f, - 0xff, 0x01, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x1f, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x03, 0xff, 0x03, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x7f, 0xfe, 0xff, 0x1f, 0x00, 0xff, 0x03, 0xff, 0x03, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0x0f, 0xff, 0x03, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xbf, 0xff, 0x03, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x7f, 0x00, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0x01, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, - 0x6f, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x9f, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xc7, 0xff, 0x01, 0xff, 0xdf, 0x0f, 0x00, 0xff, + 0xff, 0x0f, 0x00, 0xff, 0xff, 0x0f, 0x00, 0xff, 0xdf, 0x0d, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0x01, 0x80, 0x10, 0xff, + 0x03, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xff, + 0xff, 0xff, 0x7f, 0xff, 0x0f, 0xff, 0x01, 0xc0, 0xff, 0xff, 0xff, 0xff, + 0x3f, 0x1f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, + 0x03, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0x1f, 0x00, 0xff, + 0x03, 0xff, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, + 0x0f, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0x03, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0xff, 0xe3, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x3f, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xde, 0x6f, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x1f, 0x00, 0xff, 0xff, - 0x3f, 0x3f, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x3f, 0xff, 0xaa, 0xff, 0xff, - 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0x5f, 0xdc, 0x1f, - 0xcf, 0x0f, 0xff, 0x1f, 0xdc, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0x1f, 0x00, 0xff, 0xff, 0x3f, 0x3f, 0xff, 0xff, 0xff, 0xff, 0x3f, + 0x3f, 0xff, 0xaa, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xdf, 0x5f, 0xdc, 0x1f, 0xcf, 0x0f, 0xff, 0x1f, 0xdc, 0x1f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x80, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0xfc, 0x2f, 0x3e, 0x50, + 0xbd, 0xff, 0xf3, 0xe0, 0x43, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x1f, 0x78, 0x0c, 0x00, 0xff, 0xff, 0xff, 0xff, 0xbf, + 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0xff, + 0xff, 0x7f, 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, + 0x00, 0x00, 0x00, 0xfe, 0x03, 0x3e, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xe0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7f, 0x00, 0x00, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x3f, 0xff, 0x1f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0xf0, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2f, 0x00, 0xff, 0x03, 0x00, + 0x00, 0xfc, 0xe8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, + 0xff, 0x07, 0x00, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf7, 0xff, 0x00, 0x80, 0xff, 0x03, 0xff, 0xff, 0xff, 0x7f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0xff, 0x3f, 0xff, 0x03, 0xff, + 0xff, 0x7f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x05, + 0x00, 0x00, 0x38, 0xff, 0xff, 0x3c, 0x00, 0x7e, 0x7e, 0x7e, 0x00, 0x7f, + 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x07, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, + 0x00, 0xff, 0xff, 0x7f, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0xf8, 0xe0, 0xff, + 0xfd, 0x7f, 0x5f, 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x03, 0xfe, + 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0x07, 0xc0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfc, 0xfc, 0xfc, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xef, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xb7, 0xff, + 0x3f, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x84, 0xfc, 0x2f, 0x3e, 0x50, 0xbd, 0xff, 0xf3, 0xe0, 0x43, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x78, - 0x0c, 0x00, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x20, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x7f, 0x7f, - 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xfe, 0x03, - 0x3e, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x7f, 0xe0, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xf7, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0xff, + 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0xff, 0x0f, 0xff, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0x03, 0xff, 0xff, 0xff, + 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0xff, + 0xff, 0x3f, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, + 0xfd, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x91, 0xff, 0xff, 0x3f, 0x00, 0xff, + 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x37, 0x00, 0xff, 0xff, 0x3f, 0x00, 0xff, + 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x6f, 0xf0, 0xef, 0xfe, 0xff, 0xff, 0x3f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0x1f, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xfe, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xff, 0xff, 0x3f, 0x00, 0xff, + 0xff, 0x07, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x07, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0x1f, 0x80, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0xff, + 0x01, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0xff, 0x70, + 0x00, 0xff, 0xff, 0xff, 0xff, 0x47, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x1e, 0x00, 0xff, 0x17, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xff, 0x9f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7f, 0xbd, 0xff, 0xbf, 0xff, 0x01, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0x03, 0xef, 0x9f, 0xf9, 0xff, 0xff, + 0xfd, 0xed, 0xe3, 0x9f, 0x19, 0x81, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbb, + 0x07, 0xff, 0x83, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xb3, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x7f, 0x00, + 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x7f, 0x11, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x01, 0xff, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xe7, 0xff, 0x07, 0xff, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x1a, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0x7f, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x20, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xfd, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0x01, 0x00, 0xff, 0x03, 0x00, + 0x00, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xfe, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfb, 0xff, 0xff, 0xff, + 0xff, 0x7f, 0xb4, 0xcb, 0x00, 0xff, 0x03, 0xbf, 0xfd, 0xff, 0xff, 0xff, + 0x7f, 0x7b, 0x01, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, + 0xff, 0xff, 0x7f, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x0f, 0x00, 0xff, 0x03, 0xf8, + 0xff, 0xff, 0xe0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0x1f, - 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, - 0xf0, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xfc, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x2f, 0x00, 0xff, 0x03, 0x00, 0x00, 0xfc, 0xe8, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, - 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0x00, 0x80, - 0xff, 0x03, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x7f, 0x00, 0xff, 0x3f, 0xff, 0x03, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x05, 0x00, 0x00, 0x38, 0xff, 0xff, - 0x3c, 0x00, 0x7e, 0x7e, 0x7e, 0x00, 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xf7, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0x03, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0xff, 0xff, 0x7f, 0xf8, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x7f, 0x00, 0xf8, 0xe0, 0xff, 0xfd, 0x7f, 0x5f, 0xdb, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x03, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x1f, 0x00, 0x00, 0xff, 0x03, 0xfe, 0xff, 0xff, 0x07, 0xfe, 0xff, - 0xff, 0x07, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x7f, 0xfc, 0xfc, 0xfc, 0x1c, 0x00, 0x00, 0x00, 0x00, 0xff, 0xef, - 0xff, 0xff, 0x7f, 0xff, 0xff, 0xb7, 0xff, 0x3f, 0xff, 0x3f, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x07, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, - 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x3f, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, - 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0xff, 0xff, 0x3f, 0x00, 0xff, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfd, 0xff, 0xff, 0xff, 0xff, - 0xbf, 0x91, 0xff, 0xff, 0x3f, 0x00, 0xff, 0xff, 0x7f, 0x00, 0xff, 0xff, - 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x37, 0x00, 0xff, 0xff, 0x3f, 0x00, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xf0, - 0xef, 0xfe, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x1f, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, - 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x3f, 0x00, 0xff, 0xff, 0x3f, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x07, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x1f, 0x80, 0x00, - 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x7f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, - 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, 0x03, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xc7, 0xff, 0x70, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x47, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, - 0xff, 0x17, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, - 0x9f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xbd, - 0xff, 0xbf, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, - 0xff, 0x03, 0xef, 0x9f, 0xf9, 0xff, 0xff, 0xfd, 0xed, 0xe3, 0x9f, 0x19, - 0x81, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbb, 0x07, 0xff, 0x83, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb3, 0x00, - 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x3f, 0x7f, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x11, 0x00, - 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x3f, 0x01, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xe7, 0xff, 0x07, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x1a, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xe7, 0x7f, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, - 0x7f, 0x7f, 0x01, 0x00, 0xff, 0x03, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, - 0xfc, 0xff, 0xff, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7f, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xb4, 0xcb, 0x00, - 0xff, 0x03, 0xbf, 0xfd, 0xff, 0xff, 0xff, 0x7f, 0x7b, 0x01, 0xff, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x7f, 0xff, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x0f, 0x00, 0xff, 0x03, 0xf8, 0xff, 0xff, 0xe0, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, - 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xf0, 0x00, + 0xff, 0x07, 0x00, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x07, 0xff, 0x1f, 0xff, 0x01, 0xff, 0x43, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0x64, 0xde, 0xff, 0xeb, 0xef, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xe7, 0xdf, 0xdf, 0xff, 0xff, - 0xff, 0x7b, 0x5f, 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0x1f, 0xff, + 0x01, 0xff, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0x64, + 0xde, 0xff, 0xeb, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, + 0xe7, 0xdf, 0xdf, 0xff, 0xff, 0xff, 0x7b, 0x5f, 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, - 0xff, 0xff, 0xfd, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, - 0xdf, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, - 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xf7, 0xcf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xf9, 0xdb, 0x07, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x80, 0x3f, 0xff, 0x43, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x0f, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0x08, - 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xff, - 0xff, 0xff, 0x96, 0xfe, 0xf7, 0x0a, 0x84, 0xea, 0x96, 0xaa, 0x96, 0xf7, - 0xf7, 0x5e, 0xff, 0xfb, 0xff, 0x0f, 0xee, 0xfb, 0xff, 0x0f, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xf7, 0xff, + 0xff, 0xff, 0xf7, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, + 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, + 0xfd, 0xff, 0xff, 0xf7, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, + 0xff, 0xff, 0xf9, 0xdb, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x1f, 0x80, 0x3f, 0xff, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x56, 0x01, 0x00, 0x00, 0x39, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, - 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xbf, 0x1d, 0x00, 0x00, 0xe7, - 0x02, 0x00, 0x00, 0x79, 0x00, 0x00, 0x02, 0x24, 0x00, 0x00, 0x01, 0x01, - 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, - 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x01, 0x39, 0xff, 0xff, 0x00, 0x18, - 0xff, 0xff, 0x01, 0x87, 0xff, 0xff, 0x00, 0xd4, 0xfe, 0xff, 0x00, 0xc3, - 0x00, 0x00, 0x01, 0xd2, 0x00, 0x00, 0x01, 0xce, 0x00, 0x00, 0x01, 0xcd, - 0x00, 0x00, 0x01, 0x4f, 0x00, 0x00, 0x01, 0xca, 0x00, 0x00, 0x01, 0xcb, - 0x00, 0x00, 0x01, 0xcf, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x01, 0xd3, - 0x00, 0x00, 0x01, 0xd1, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x01, 0xd5, - 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x01, 0xd6, 0x00, 0x00, 0x01, 0xda, - 0x00, 0x00, 0x01, 0xd9, 0x00, 0x00, 0x01, 0xdb, 0x00, 0x00, 0x00, 0x38, - 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0xb1, 0xff, 0xff, 0x01, 0x9f, - 0xff, 0xff, 0x01, 0xc8, 0xff, 0xff, 0x02, 0x28, 0x24, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x33, - 0xff, 0xff, 0x00, 0x26, 0xff, 0xff, 0x01, 0x7e, 0xff, 0xff, 0x01, 0x2b, - 0x2a, 0x00, 0x01, 0x5d, 0xff, 0xff, 0x01, 0x28, 0x2a, 0x00, 0x00, 0x3f, - 0x2a, 0x00, 0x01, 0x3d, 0xff, 0xff, 0x01, 0x45, 0x00, 0x00, 0x01, 0x47, - 0x00, 0x00, 0x00, 0x1f, 0x2a, 0x00, 0x00, 0x1c, 0x2a, 0x00, 0x00, 0x1e, - 0x2a, 0x00, 0x00, 0x2e, 0xff, 0xff, 0x00, 0x32, 0xff, 0xff, 0x00, 0x36, - 0xff, 0xff, 0x00, 0x35, 0xff, 0xff, 0x00, 0x4f, 0xa5, 0x00, 0x00, 0x4b, - 0xa5, 0x00, 0x00, 0x31, 0xff, 0xff, 0x00, 0x28, 0xa5, 0x00, 0x00, 0x44, - 0xa5, 0x00, 0x00, 0x2f, 0xff, 0xff, 0x00, 0x2d, 0xff, 0xff, 0x00, 0xf7, - 0x29, 0x00, 0x00, 0x41, 0xa5, 0x00, 0x00, 0xfd, 0x29, 0x00, 0x00, 0x2b, - 0xff, 0xff, 0x00, 0x2a, 0xff, 0xff, 0x00, 0xe7, 0x29, 0x00, 0x00, 0x43, - 0xa5, 0x00, 0x00, 0x2a, 0xa5, 0x00, 0x00, 0xbb, 0xff, 0xff, 0x00, 0x27, - 0xff, 0xff, 0x00, 0xb9, 0xff, 0xff, 0x00, 0x25, 0xff, 0xff, 0x00, 0x15, - 0xa5, 0x00, 0x00, 0x12, 0xa5, 0x00, 0x02, 0x24, 0x4c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x01, 0x01, - 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x54, 0x00, 0x00, 0x01, 0x74, - 0x00, 0x00, 0x01, 0x26, 0x00, 0x00, 0x01, 0x25, 0x00, 0x00, 0x01, 0x40, - 0x00, 0x00, 0x01, 0x3f, 0x00, 0x00, 0x00, 0xda, 0xff, 0xff, 0x00, 0xdb, - 0xff, 0xff, 0x00, 0xe1, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc1, - 0xff, 0xff, 0x01, 0x08, 0x00, 0x00, 0x00, 0xc2, 0xff, 0xff, 0x00, 0xc7, - 0xff, 0xff, 0x00, 0xd1, 0xff, 0xff, 0x00, 0xca, 0xff, 0xff, 0x00, 0xf8, - 0xff, 0xff, 0x00, 0xaa, 0xff, 0xff, 0x00, 0xb0, 0xff, 0xff, 0x00, 0x07, - 0x00, 0x00, 0x00, 0x8c, 0xff, 0xff, 0x01, 0xc4, 0xff, 0xff, 0x00, 0xa0, - 0xff, 0xff, 0x01, 0xf9, 0xff, 0xff, 0x02, 0x1a, 0x70, 0x00, 0x01, 0x01, - 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x01, 0x20, 0x00, 0x00, 0x00, 0xe0, - 0xff, 0xff, 0x01, 0x50, 0x00, 0x00, 0x01, 0x0f, 0x00, 0x00, 0x00, 0xf1, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x30, 0x00, 0x00, 0x00, 0xd0, - 0xff, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xc0, 0x0b, 0x00, 0x01, 0x60, 0x1c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0xd0, 0x97, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0xf8, - 0xff, 0xff, 0x02, 0x05, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, - 0xf4, 0xff, 0x00, 0x9e, 0xe7, 0xff, 0x00, 0xc2, 0x89, 0x00, 0x00, 0xdb, - 0xe7, 0xff, 0x00, 0x92, 0xe7, 0xff, 0x00, 0x93, 0xe7, 0xff, 0x00, 0x9c, - 0xe7, 0xff, 0x00, 0x9d, 0xe7, 0xff, 0x00, 0xa4, 0xe7, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x38, 0x8a, 0x00, 0x00, 0x04, 0x8a, 0x00, 0x00, 0xe6, - 0x0e, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xc5, 0xff, 0xff, 0x01, 0x41, 0xe2, 0xff, 0x02, 0x1d, - 0x8f, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01, 0xf8, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x01, 0xaa, 0xff, 0xff, 0x00, 0x4a, - 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x70, - 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x01, 0xb6, - 0xff, 0xff, 0x01, 0xf7, 0xff, 0xff, 0x00, 0xdb, 0xe3, 0xff, 0x01, 0x9c, - 0xff, 0xff, 0x01, 0x90, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff, 0x01, 0x82, - 0xff, 0xff, 0x02, 0x05, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, - 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x01, 0x1c, 0x00, 0x00, 0x01, 0x01, - 0x00, 0x00, 0x01, 0xa3, 0xe2, 0xff, 0x01, 0x41, 0xdf, 0xff, 0x01, 0xba, - 0xdf, 0xff, 0x00, 0xe4, 0xff, 0xff, 0x02, 0x0b, 0xb1, 0x00, 0x01, 0x01, - 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x01, 0x30, 0x00, 0x00, 0x00, 0xd0, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x09, 0xd6, 0xff, 0x01, 0x1a, - 0xf1, 0xff, 0x01, 0x19, 0xd6, 0xff, 0x00, 0xd5, 0xd5, 0xff, 0x00, 0xd8, - 0xd5, 0xff, 0x01, 0xe4, 0xd5, 0xff, 0x01, 0x03, 0xd6, 0xff, 0x01, 0xe1, - 0xd5, 0xff, 0x01, 0xe2, 0xd5, 0xff, 0x01, 0xc1, 0xd5, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xa0, 0xe3, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, - 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x02, 0x0c, 0xbc, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x01, 0xbc, - 0x5a, 0xff, 0x01, 0xa0, 0x03, 0x00, 0x01, 0xfc, 0x75, 0xff, 0x01, 0xd8, - 0x5a, 0xff, 0x00, 0x30, 0x00, 0x00, 0x01, 0xb1, 0x5a, 0xff, 0x01, 0xb5, - 0x5a, 0xff, 0x01, 0xbf, 0x5a, 0xff, 0x01, 0xee, 0x5a, 0xff, 0x01, 0xd6, - 0x5a, 0xff, 0x01, 0xeb, 0x5a, 0xff, 0x01, 0xd0, 0xff, 0xff, 0x01, 0xbd, - 0x5a, 0xff, 0x01, 0xc8, 0x75, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, - 0x68, 0xff, 0x00, 0x60, 0xfc, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, - 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x28, - 0x00, 0x00, 0x00, 0xd8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, - 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, - 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, - 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x22, - 0x00, 0x00, 0x00, 0xde, 0xff, 0xff, 0x30, 0x0c, 0x31, 0x0d, 0x78, 0x0e, - 0x7f, 0x0f, 0x80, 0x10, 0x81, 0x11, 0x86, 0x12, 0x89, 0x13, 0x8a, 0x13, - 0x8e, 0x14, 0x8f, 0x15, 0x90, 0x16, 0x93, 0x13, 0x94, 0x17, 0x95, 0x18, - 0x96, 0x19, 0x97, 0x1a, 0x9a, 0x1b, 0x9c, 0x19, 0x9d, 0x1c, 0x9e, 0x1d, - 0x9f, 0x1e, 0xa6, 0x1f, 0xa9, 0x1f, 0xae, 0x1f, 0xb1, 0x20, 0xb2, 0x20, - 0xb7, 0x21, 0xbf, 0x22, 0xc5, 0x23, 0xc8, 0x23, 0xcb, 0x23, 0xdd, 0x24, - 0xf2, 0x23, 0xf6, 0x25, 0xf7, 0x26, 0x20, 0x2d, 0x3a, 0x2e, 0x3d, 0x2f, - 0x3e, 0x30, 0x3f, 0x31, 0x40, 0x31, 0x43, 0x32, 0x44, 0x33, 0x45, 0x34, - 0x50, 0x35, 0x51, 0x36, 0x52, 0x37, 0x53, 0x38, 0x54, 0x39, 0x59, 0x3a, - 0x5b, 0x3b, 0x5c, 0x3c, 0x61, 0x3d, 0x63, 0x3e, 0x65, 0x3f, 0x66, 0x40, - 0x68, 0x41, 0x69, 0x42, 0x6a, 0x40, 0x6b, 0x43, 0x6c, 0x44, 0x6f, 0x42, - 0x71, 0x45, 0x72, 0x46, 0x75, 0x47, 0x7d, 0x48, 0x82, 0x49, 0x87, 0x4a, - 0x89, 0x4b, 0x8a, 0x4c, 0x8b, 0x4c, 0x8c, 0x4d, 0x92, 0x4e, 0x9d, 0x4f, - 0x9e, 0x50, 0x45, 0x57, 0x7b, 0x1d, 0x7c, 0x1d, 0x7d, 0x1d, 0x7f, 0x58, - 0x86, 0x59, 0x88, 0x5a, 0x89, 0x5a, 0x8a, 0x5a, 0x8c, 0x5b, 0x8e, 0x5c, - 0x8f, 0x5c, 0xac, 0x5d, 0xad, 0x5e, 0xae, 0x5e, 0xaf, 0x5e, 0xc2, 0x5f, - 0xcc, 0x60, 0xcd, 0x61, 0xce, 0x61, 0xcf, 0x62, 0xd0, 0x63, 0xd1, 0x64, - 0xd5, 0x65, 0xd6, 0x66, 0xd7, 0x67, 0xf0, 0x68, 0xf1, 0x69, 0xf2, 0x6a, - 0xf3, 0x6b, 0xf4, 0x6c, 0xf5, 0x6d, 0xf9, 0x6e, 0xfd, 0x2d, 0xfe, 0x2d, - 0xff, 0x2d, 0x50, 0x69, 0x51, 0x69, 0x52, 0x69, 0x53, 0x69, 0x54, 0x69, - 0x55, 0x69, 0x56, 0x69, 0x57, 0x69, 0x58, 0x69, 0x59, 0x69, 0x5a, 0x69, - 0x5b, 0x69, 0x5c, 0x69, 0x5d, 0x69, 0x5e, 0x69, 0x5f, 0x69, 0x82, 0x00, - 0x83, 0x00, 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, 0x88, 0x00, - 0x89, 0x00, 0xc0, 0x75, 0xcf, 0x76, 0x80, 0x89, 0x81, 0x8a, 0x82, 0x8b, - 0x85, 0x8c, 0x86, 0x8d, 0x70, 0x9d, 0x71, 0x9d, 0x76, 0x9e, 0x77, 0x9e, - 0x78, 0x9f, 0x79, 0x9f, 0x7a, 0xa0, 0x7b, 0xa0, 0x7c, 0xa1, 0x7d, 0xa1, - 0xb3, 0xa2, 0xba, 0xa3, 0xbb, 0xa3, 0xbc, 0xa4, 0xbe, 0xa5, 0xc3, 0xa2, - 0xcc, 0xa4, 0xda, 0xa6, 0xdb, 0xa6, 0xe5, 0x6a, 0xea, 0xa7, 0xeb, 0xa7, - 0xec, 0x6e, 0xf3, 0xa2, 0xf8, 0xa8, 0xf9, 0xa8, 0xfa, 0xa9, 0xfb, 0xa9, - 0xfc, 0xa4, 0x26, 0xb0, 0x2a, 0xb1, 0x2b, 0xb2, 0x4e, 0xb3, 0x84, 0x08, - 0x62, 0xba, 0x63, 0xbb, 0x64, 0xbc, 0x65, 0xbd, 0x66, 0xbe, 0x6d, 0xbf, - 0x6e, 0xc0, 0x6f, 0xc1, 0x70, 0xc2, 0x7e, 0xc3, 0x7f, 0xc3, 0x7d, 0xcf, - 0x8d, 0xd0, 0x94, 0xd1, 0xab, 0xd2, 0xac, 0xd3, 0xad, 0xd4, 0xb0, 0xd5, - 0xb1, 0xd6, 0xb2, 0xd7, 0xc4, 0xd8, 0xc5, 0xd9, 0xc6, 0xda, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x0d, 0x06, 0x06, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x0f, 0x10, 0x11, 0x12, 0x06, 0x13, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x14, 0x15, 0x06, 0x06, 0x06, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0x03, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x8f, 0x08, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xef, 0xff, 0xff, 0xff, 0x96, 0xfe, 0xf7, 0x0a, 0x84, + 0xea, 0x96, 0xaa, 0x96, 0xf7, 0xf7, 0x5e, 0xff, 0xfb, 0xff, 0x0f, 0xee, + 0xfb, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, + 0x03, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x56, + 0x01, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x00, + 0xbf, 0x1d, 0x00, 0x00, 0xe7, 0x02, 0x00, 0x00, 0x79, 0x00, 0x00, 0x02, + 0x24, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x01, + 0x39, 0xff, 0xff, 0x00, 0x18, 0xff, 0xff, 0x01, 0x87, 0xff, 0xff, 0x00, + 0xd4, 0xfe, 0xff, 0x00, 0xc3, 0x00, 0x00, 0x01, 0xd2, 0x00, 0x00, 0x01, + 0xce, 0x00, 0x00, 0x01, 0xcd, 0x00, 0x00, 0x01, 0x4f, 0x00, 0x00, 0x01, + 0xca, 0x00, 0x00, 0x01, 0xcb, 0x00, 0x00, 0x01, 0xcf, 0x00, 0x00, 0x00, + 0x61, 0x00, 0x00, 0x01, 0xd3, 0x00, 0x00, 0x01, 0xd1, 0x00, 0x00, 0x00, + 0xa3, 0x00, 0x00, 0x01, 0xd5, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x01, + 0xd6, 0x00, 0x00, 0x01, 0xda, 0x00, 0x00, 0x01, 0xd9, 0x00, 0x00, 0x01, + 0xdb, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0xb1, 0xff, 0xff, 0x01, 0x9f, 0xff, 0xff, 0x01, 0xc8, 0xff, 0xff, 0x02, + 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x00, 0x33, 0xff, 0xff, 0x00, 0x26, 0xff, 0xff, 0x01, + 0x7e, 0xff, 0xff, 0x01, 0x2b, 0x2a, 0x00, 0x01, 0x5d, 0xff, 0xff, 0x01, + 0x28, 0x2a, 0x00, 0x00, 0x3f, 0x2a, 0x00, 0x01, 0x3d, 0xff, 0xff, 0x01, + 0x45, 0x00, 0x00, 0x01, 0x47, 0x00, 0x00, 0x00, 0x1f, 0x2a, 0x00, 0x00, + 0x1c, 0x2a, 0x00, 0x00, 0x1e, 0x2a, 0x00, 0x00, 0x2e, 0xff, 0xff, 0x00, + 0x32, 0xff, 0xff, 0x00, 0x36, 0xff, 0xff, 0x00, 0x35, 0xff, 0xff, 0x00, + 0x4f, 0xa5, 0x00, 0x00, 0x4b, 0xa5, 0x00, 0x00, 0x31, 0xff, 0xff, 0x00, + 0x28, 0xa5, 0x00, 0x00, 0x44, 0xa5, 0x00, 0x00, 0x2f, 0xff, 0xff, 0x00, + 0x2d, 0xff, 0xff, 0x00, 0xf7, 0x29, 0x00, 0x00, 0x41, 0xa5, 0x00, 0x00, + 0xfd, 0x29, 0x00, 0x00, 0x2b, 0xff, 0xff, 0x00, 0x2a, 0xff, 0xff, 0x00, + 0xe7, 0x29, 0x00, 0x00, 0x43, 0xa5, 0x00, 0x00, 0x2a, 0xa5, 0x00, 0x00, + 0xbb, 0xff, 0xff, 0x00, 0x27, 0xff, 0xff, 0x00, 0xb9, 0xff, 0xff, 0x00, + 0x25, 0xff, 0xff, 0x00, 0x15, 0xa5, 0x00, 0x00, 0x12, 0xa5, 0x00, 0x02, + 0x24, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, + 0xe0, 0xff, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, + 0x54, 0x00, 0x00, 0x01, 0x74, 0x00, 0x00, 0x01, 0x26, 0x00, 0x00, 0x01, + 0x25, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0x3f, 0x00, 0x00, 0x00, + 0xda, 0xff, 0xff, 0x00, 0xdb, 0xff, 0xff, 0x00, 0xe1, 0xff, 0xff, 0x00, + 0xc0, 0xff, 0xff, 0x00, 0xc1, 0xff, 0xff, 0x01, 0x08, 0x00, 0x00, 0x00, + 0xc2, 0xff, 0xff, 0x00, 0xc7, 0xff, 0xff, 0x00, 0xd1, 0xff, 0xff, 0x00, + 0xca, 0xff, 0xff, 0x00, 0xf8, 0xff, 0xff, 0x00, 0xaa, 0xff, 0xff, 0x00, + 0xb0, 0xff, 0xff, 0x00, 0x07, 0x00, 0x00, 0x00, 0x8c, 0xff, 0xff, 0x01, + 0xc4, 0xff, 0xff, 0x00, 0xa0, 0xff, 0xff, 0x01, 0xf9, 0xff, 0xff, 0x02, + 0x1a, 0x70, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x01, + 0x20, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x01, 0x50, 0x00, 0x00, 0x01, + 0x0f, 0x00, 0x00, 0x00, 0xf1, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x30, 0x00, 0x00, 0x00, 0xd0, 0xff, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0b, 0x00, 0x01, + 0x60, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x97, 0x00, 0x01, + 0x08, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x02, 0x05, 0x8a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x40, 0xf4, 0xff, 0x00, 0x9e, 0xe7, 0xff, 0x00, + 0xc2, 0x89, 0x00, 0x00, 0xdb, 0xe7, 0xff, 0x00, 0x92, 0xe7, 0xff, 0x00, + 0x93, 0xe7, 0xff, 0x00, 0x9c, 0xe7, 0xff, 0x00, 0x9d, 0xe7, 0xff, 0x00, + 0xa4, 0xe7, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x8a, 0x00, 0x00, + 0x04, 0x8a, 0x00, 0x00, 0xe6, 0x0e, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0xff, 0xff, 0x01, + 0x41, 0xe2, 0xff, 0x02, 0x1d, 0x8f, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01, + 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x01, + 0xaa, 0xff, 0xff, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x01, 0xb6, 0xff, 0xff, 0x01, 0xf7, 0xff, 0xff, 0x00, + 0xdb, 0xe3, 0xff, 0x01, 0x9c, 0xff, 0xff, 0x01, 0x90, 0xff, 0xff, 0x01, + 0x80, 0xff, 0xff, 0x01, 0x82, 0xff, 0xff, 0x02, 0x05, 0xac, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x01, + 0x1c, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0xa3, 0xe2, 0xff, 0x01, + 0x41, 0xdf, 0xff, 0x01, 0xba, 0xdf, 0xff, 0x00, 0xe4, 0xff, 0xff, 0x02, + 0x0b, 0xb1, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x01, + 0x30, 0x00, 0x00, 0x00, 0xd0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x09, 0xd6, 0xff, 0x01, 0x1a, 0xf1, 0xff, 0x01, 0x19, 0xd6, 0xff, 0x00, + 0xd5, 0xd5, 0xff, 0x00, 0xd8, 0xd5, 0xff, 0x01, 0xe4, 0xd5, 0xff, 0x01, + 0x03, 0xd6, 0xff, 0x01, 0xe1, 0xd5, 0xff, 0x01, 0xe2, 0xd5, 0xff, 0x01, + 0xc1, 0xd5, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xe3, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x02, + 0x0c, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x01, 0xbc, 0x5a, 0xff, 0x01, 0xa0, 0x03, 0x00, 0x01, + 0xfc, 0x75, 0xff, 0x01, 0xd8, 0x5a, 0xff, 0x00, 0x30, 0x00, 0x00, 0x01, + 0xb1, 0x5a, 0xff, 0x01, 0xb5, 0x5a, 0xff, 0x01, 0xbf, 0x5a, 0xff, 0x01, + 0xee, 0x5a, 0xff, 0x01, 0xd6, 0x5a, 0xff, 0x01, 0xeb, 0x5a, 0xff, 0x01, + 0xd0, 0xff, 0xff, 0x01, 0xbd, 0x5a, 0xff, 0x01, 0xc8, 0x75, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x30, 0x68, 0xff, 0x00, 0x60, 0xfc, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x28, 0x00, 0x00, 0x00, 0xd8, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x22, 0x00, 0x00, 0x00, 0xde, 0xff, 0xff, 0x30, + 0x0c, 0x31, 0x0d, 0x78, 0x0e, 0x7f, 0x0f, 0x80, 0x10, 0x81, 0x11, 0x86, + 0x12, 0x89, 0x13, 0x8a, 0x13, 0x8e, 0x14, 0x8f, 0x15, 0x90, 0x16, 0x93, + 0x13, 0x94, 0x17, 0x95, 0x18, 0x96, 0x19, 0x97, 0x1a, 0x9a, 0x1b, 0x9c, + 0x19, 0x9d, 0x1c, 0x9e, 0x1d, 0x9f, 0x1e, 0xa6, 0x1f, 0xa9, 0x1f, 0xae, + 0x1f, 0xb1, 0x20, 0xb2, 0x20, 0xb7, 0x21, 0xbf, 0x22, 0xc5, 0x23, 0xc8, + 0x23, 0xcb, 0x23, 0xdd, 0x24, 0xf2, 0x23, 0xf6, 0x25, 0xf7, 0x26, 0x20, + 0x2d, 0x3a, 0x2e, 0x3d, 0x2f, 0x3e, 0x30, 0x3f, 0x31, 0x40, 0x31, 0x43, + 0x32, 0x44, 0x33, 0x45, 0x34, 0x50, 0x35, 0x51, 0x36, 0x52, 0x37, 0x53, + 0x38, 0x54, 0x39, 0x59, 0x3a, 0x5b, 0x3b, 0x5c, 0x3c, 0x61, 0x3d, 0x63, + 0x3e, 0x65, 0x3f, 0x66, 0x40, 0x68, 0x41, 0x69, 0x42, 0x6a, 0x40, 0x6b, + 0x43, 0x6c, 0x44, 0x6f, 0x42, 0x71, 0x45, 0x72, 0x46, 0x75, 0x47, 0x7d, + 0x48, 0x82, 0x49, 0x87, 0x4a, 0x89, 0x4b, 0x8a, 0x4c, 0x8b, 0x4c, 0x8c, + 0x4d, 0x92, 0x4e, 0x9d, 0x4f, 0x9e, 0x50, 0x45, 0x57, 0x7b, 0x1d, 0x7c, + 0x1d, 0x7d, 0x1d, 0x7f, 0x58, 0x86, 0x59, 0x88, 0x5a, 0x89, 0x5a, 0x8a, + 0x5a, 0x8c, 0x5b, 0x8e, 0x5c, 0x8f, 0x5c, 0xac, 0x5d, 0xad, 0x5e, 0xae, + 0x5e, 0xaf, 0x5e, 0xc2, 0x5f, 0xcc, 0x60, 0xcd, 0x61, 0xce, 0x61, 0xcf, + 0x62, 0xd0, 0x63, 0xd1, 0x64, 0xd5, 0x65, 0xd6, 0x66, 0xd7, 0x67, 0xf0, + 0x68, 0xf1, 0x69, 0xf2, 0x6a, 0xf3, 0x6b, 0xf4, 0x6c, 0xf5, 0x6d, 0xf9, + 0x6e, 0xfd, 0x2d, 0xfe, 0x2d, 0xff, 0x2d, 0x50, 0x69, 0x51, 0x69, 0x52, + 0x69, 0x53, 0x69, 0x54, 0x69, 0x55, 0x69, 0x56, 0x69, 0x57, 0x69, 0x58, + 0x69, 0x59, 0x69, 0x5a, 0x69, 0x5b, 0x69, 0x5c, 0x69, 0x5d, 0x69, 0x5e, + 0x69, 0x5f, 0x69, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85, 0x00, 0x86, + 0x00, 0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0xc0, 0x75, 0xcf, 0x76, 0x80, + 0x89, 0x81, 0x8a, 0x82, 0x8b, 0x85, 0x8c, 0x86, 0x8d, 0x70, 0x9d, 0x71, + 0x9d, 0x76, 0x9e, 0x77, 0x9e, 0x78, 0x9f, 0x79, 0x9f, 0x7a, 0xa0, 0x7b, + 0xa0, 0x7c, 0xa1, 0x7d, 0xa1, 0xb3, 0xa2, 0xba, 0xa3, 0xbb, 0xa3, 0xbc, + 0xa4, 0xbe, 0xa5, 0xc3, 0xa2, 0xcc, 0xa4, 0xda, 0xa6, 0xdb, 0xa6, 0xe5, + 0x6a, 0xea, 0xa7, 0xeb, 0xa7, 0xec, 0x6e, 0xf3, 0xa2, 0xf8, 0xa8, 0xf9, + 0xa8, 0xfa, 0xa9, 0xfb, 0xa9, 0xfc, 0xa4, 0x26, 0xb0, 0x2a, 0xb1, 0x2b, + 0xb2, 0x4e, 0xb3, 0x84, 0x08, 0x62, 0xba, 0x63, 0xbb, 0x64, 0xbc, 0x65, + 0xbd, 0x66, 0xbe, 0x6d, 0xbf, 0x6e, 0xc0, 0x6f, 0xc1, 0x70, 0xc2, 0x7e, + 0xc3, 0x7f, 0xc3, 0x7d, 0xcf, 0x8d, 0xd0, 0x94, 0xd1, 0xab, 0xd2, 0xac, + 0xd3, 0xad, 0xd4, 0xb0, 0xd5, 0xb1, 0xd6, 0xb2, 0xd7, 0xc4, 0xd8, 0xc5, + 0xd9, 0xc6, 0xda, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0d, 0x06, 0x06, 0x0e, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0f, 0x10, 0x11, 0x12, 0x06, + 0x13, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x14, + 0x15, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, @@ -1003,24 +946,23 @@ unsigned char STDLIB_WASM[] = { 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x16, 0x17, 0x06, 0x06, - 0x06, 0x18, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x16, 0x17, 0x06, 0x06, 0x06, 0x18, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x19, 0x06, 0x06, 0x06, 0x06, 0x1a, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x1b, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x1c, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x19, 0x06, 0x06, 0x06, 0x06, 0x1a, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1b, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1c, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x1d, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1d, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, @@ -1030,9 +972,9 @@ unsigned char STDLIB_WASM[] = { 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1041,294 +983,254 @@ unsigned char STDLIB_WASM[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x01, 0x00, 0x54, 0x56, 0x56, 0x56, - 0x56, 0x56, 0x56, 0x56, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x07, - 0x2b, 0x2b, 0x5b, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x4a, 0x56, - 0x56, 0x05, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, - 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x24, 0x50, 0x79, 0x31, 0x50, 0x31, - 0x50, 0x31, 0x38, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, - 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x4e, 0x31, 0x02, 0x4e, 0x0d, 0x0d, - 0x4e, 0x03, 0x4e, 0x00, 0x24, 0x6e, 0x00, 0x4e, 0x31, 0x26, 0x6e, 0x51, - 0x4e, 0x24, 0x50, 0x4e, 0x39, 0x14, 0x81, 0x1b, 0x1d, 0x1d, 0x53, 0x31, - 0x50, 0x31, 0x50, 0x0d, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x1b, 0x53, - 0x24, 0x50, 0x31, 0x02, 0x5c, 0x7b, 0x5c, 0x7b, 0x5c, 0x7b, 0x5c, 0x7b, - 0x5c, 0x7b, 0x14, 0x79, 0x5c, 0x7b, 0x5c, 0x7b, 0x5c, 0x2d, 0x2b, 0x49, - 0x03, 0x48, 0x03, 0x78, 0x5c, 0x7b, 0x14, 0x00, 0x96, 0x0a, 0x01, 0x2b, - 0x28, 0x06, 0x06, 0x00, 0x2a, 0x06, 0x2a, 0x2a, 0x2b, 0x07, 0xbb, 0xb5, - 0x2b, 0x1e, 0x00, 0x2b, 0x07, 0x2b, 0x2b, 0x2b, 0x01, 0x2b, 0x2b, 0x2b, + 0x00, 0x00, 0x24, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x01, + 0x00, 0x54, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x07, 0x2b, 0x2b, 0x5b, 0x56, 0x56, 0x56, 0x56, + 0x56, 0x56, 0x56, 0x4a, 0x56, 0x56, 0x05, 0x31, 0x50, 0x31, 0x50, 0x31, + 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x24, + 0x50, 0x79, 0x31, 0x50, 0x31, 0x50, 0x31, 0x38, 0x50, 0x31, 0x50, 0x31, + 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x4e, + 0x31, 0x02, 0x4e, 0x0d, 0x0d, 0x4e, 0x03, 0x4e, 0x00, 0x24, 0x6e, 0x00, + 0x4e, 0x31, 0x26, 0x6e, 0x51, 0x4e, 0x24, 0x50, 0x4e, 0x39, 0x14, 0x81, + 0x1b, 0x1d, 0x1d, 0x53, 0x31, 0x50, 0x31, 0x50, 0x0d, 0x31, 0x50, 0x31, + 0x50, 0x31, 0x50, 0x1b, 0x53, 0x24, 0x50, 0x31, 0x02, 0x5c, 0x7b, 0x5c, + 0x7b, 0x5c, 0x7b, 0x5c, 0x7b, 0x5c, 0x7b, 0x14, 0x79, 0x5c, 0x7b, 0x5c, + 0x7b, 0x5c, 0x2d, 0x2b, 0x49, 0x03, 0x48, 0x03, 0x78, 0x5c, 0x7b, 0x14, + 0x00, 0x96, 0x0a, 0x01, 0x2b, 0x28, 0x06, 0x06, 0x00, 0x2a, 0x06, 0x2a, + 0x2a, 0x2b, 0x07, 0xbb, 0xb5, 0x2b, 0x1e, 0x00, 0x2b, 0x07, 0x2b, 0x2b, + 0x2b, 0x01, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x01, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0xcd, 0x46, 0xcd, 0x2b, 0x00, 0x25, 0x2b, 0x07, 0x01, 0x06, 0x01, 0x55, + 0x56, 0x56, 0x56, 0x56, 0x56, 0x55, 0x56, 0x56, 0x02, 0x24, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x15, 0x81, 0x81, 0x81, 0x00, 0x00, 0x2b, 0x00, 0xb2, + 0xd1, 0xb2, 0xd1, 0xb2, 0xd1, 0xb2, 0xd1, 0x00, 0x00, 0xcd, 0xcc, 0x01, + 0x00, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0x83, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x50, 0x31, + 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x02, 0x00, 0x00, 0x31, + 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, + 0x50, 0x31, 0x50, 0x31, 0x50, 0x4e, 0x31, 0x50, 0x31, 0x50, 0x4e, 0x31, + 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, + 0x50, 0x31, 0x02, 0x87, 0xa6, 0x87, 0xa6, 0x87, 0xa6, 0x87, 0xa6, 0x87, + 0xa6, 0x87, 0xa6, 0x87, 0xa6, 0x87, 0xa6, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x00, 0x00, 0x00, 0x54, + 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x56, + 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x0c, + 0x00, 0x0c, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x07, 0x2a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x56, 0x56, 0x6c, 0x81, 0x15, 0x00, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x01, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0xcd, 0x46, 0xcd, 0x2b, 0x00, - 0x25, 0x2b, 0x07, 0x01, 0x06, 0x01, 0x55, 0x56, 0x56, 0x56, 0x56, 0x56, - 0x55, 0x56, 0x56, 0x02, 0x24, 0x81, 0x81, 0x81, 0x81, 0x81, 0x15, 0x81, - 0x81, 0x81, 0x00, 0x00, 0x2b, 0x00, 0xb2, 0xd1, 0xb2, 0xd1, 0xb2, 0xd1, - 0xb2, 0xd1, 0x00, 0x00, 0xcd, 0xcc, 0x01, 0x00, 0xd7, 0xd7, 0xd7, 0xd7, - 0xd7, 0x83, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0x1c, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, - 0x31, 0x50, 0x31, 0x02, 0x00, 0x00, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, - 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, - 0x4e, 0x31, 0x50, 0x31, 0x50, 0x4e, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, - 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x02, 0x87, 0xa6, - 0x87, 0xa6, 0x87, 0xa6, 0x87, 0xa6, 0x87, 0xa6, 0x87, 0xa6, 0x87, 0xa6, - 0x87, 0xa6, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x00, 0x00, 0x00, 0x54, 0x56, 0x56, 0x56, 0x56, 0x56, + 0x2b, 0x2b, 0x2b, 0x07, 0x6c, 0x03, 0x41, 0x2b, 0x2b, 0x56, 0x56, 0x56, + 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x2c, + 0x56, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, + 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, + 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, + 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, + 0x25, 0x06, 0x25, 0x56, 0x7a, 0x9e, 0x26, 0x06, 0x25, 0x06, 0x25, 0x06, + 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, + 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, + 0x25, 0x06, 0x01, 0x2b, 0x2b, 0x4f, 0x56, 0x56, 0x2c, 0x2b, 0x7f, 0x56, + 0x56, 0x39, 0x2b, 0x2b, 0x55, 0x56, 0x56, 0x2b, 0x2b, 0x4f, 0x56, 0x56, + 0x2c, 0x2b, 0x7f, 0x56, 0x56, 0x81, 0x37, 0x75, 0x5b, 0x7b, 0x5c, 0x2b, + 0x2b, 0x4f, 0x56, 0x56, 0x02, 0xac, 0x04, 0x00, 0x00, 0x39, 0x2b, 0x2b, + 0x55, 0x56, 0x56, 0x2b, 0x2b, 0x4f, 0x56, 0x56, 0x2c, 0x2b, 0x2b, 0x56, + 0x56, 0x32, 0x13, 0x81, 0x57, 0x00, 0x6f, 0x81, 0x7e, 0xc9, 0xd7, 0x7e, + 0x2d, 0x81, 0x81, 0x0e, 0x7e, 0x39, 0x7f, 0x6f, 0x57, 0x00, 0x81, 0x81, + 0x7e, 0x15, 0x00, 0x7e, 0x03, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x07, 0x2b, 0x24, 0x2b, 0x97, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x56, 0x56, 0x56, 0x56, 0x56, 0x80, 0x81, 0x81, 0x81, 0x81, 0x39, + 0xbb, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x01, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xc9, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xd0, 0x0d, 0x00, 0x4e, 0x31, 0x02, 0xb4, 0xc1, 0xc1, 0xd7, + 0xd7, 0x24, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, + 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, + 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0xd7, + 0xd7, 0x53, 0xc1, 0x47, 0xd4, 0xd7, 0xd7, 0xd7, 0x05, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x07, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x31, 0x50, 0x31, + 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x0d, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, + 0x50, 0x31, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x79, 0x5c, 0x7b, 0x5c, 0x7b, 0x4f, 0x7b, 0x5c, 0x7b, 0x5c, 0x7b, 0x5c, + 0x7b, 0x5c, 0x7b, 0x5c, 0x7b, 0x5c, 0x7b, 0x5c, 0x7b, 0x5c, 0x7b, 0x5c, + 0x7b, 0x5c, 0x2d, 0x2b, 0x2b, 0x79, 0x14, 0x5c, 0x7b, 0x5c, 0x2d, 0x79, + 0x2a, 0x5c, 0x27, 0x5c, 0x7b, 0x5c, 0x7b, 0x5c, 0x7b, 0xa4, 0x00, 0x0a, + 0xb4, 0x5c, 0x7b, 0x5c, 0x7b, 0x4f, 0x03, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x07, 0x00, 0x48, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x55, 0x56, 0x56, 0x56, + 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x07, 0x00, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x24, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, + 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, - 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x0c, 0x00, 0x0c, 0x2a, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x07, - 0x2a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, + 0x56, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x56, 0x56, 0x56, + 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x56, 0x56, - 0x6c, 0x81, 0x15, 0x00, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x07, 0x6c, - 0x03, 0x41, 0x2b, 0x2b, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, - 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x2c, 0x56, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x55, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, + 0x56, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x6c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x25, 0x06, 0x25, - 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, - 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, - 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, - 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x56, 0x7a, - 0x9e, 0x26, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, - 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, - 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x25, 0x06, 0x01, 0x2b, 0x2b, - 0x4f, 0x56, 0x56, 0x2c, 0x2b, 0x7f, 0x56, 0x56, 0x39, 0x2b, 0x2b, 0x55, - 0x56, 0x56, 0x2b, 0x2b, 0x4f, 0x56, 0x56, 0x2c, 0x2b, 0x7f, 0x56, 0x56, - 0x81, 0x37, 0x75, 0x5b, 0x7b, 0x5c, 0x2b, 0x2b, 0x4f, 0x56, 0x56, 0x02, - 0xac, 0x04, 0x00, 0x00, 0x39, 0x2b, 0x2b, 0x55, 0x56, 0x56, 0x2b, 0x2b, - 0x4f, 0x56, 0x56, 0x2c, 0x2b, 0x2b, 0x56, 0x56, 0x32, 0x13, 0x81, 0x57, - 0x00, 0x6f, 0x81, 0x7e, 0xc9, 0xd7, 0x7e, 0x2d, 0x81, 0x81, 0x0e, 0x7e, - 0x39, 0x7f, 0x6f, 0x57, 0x00, 0x81, 0x81, 0x7e, 0x15, 0x00, 0x7e, 0x03, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x07, 0x2b, 0x24, 0x2b, 0x97, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x56, 0x56, 0x56, 0x56, - 0x56, 0x80, 0x81, 0x81, 0x81, 0x81, 0x39, 0xbb, 0x2a, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x01, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0xc9, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xd0, 0x0d, 0x00, - 0x4e, 0x31, 0x02, 0xb4, 0xc1, 0xc1, 0xd7, 0xd7, 0x24, 0x50, 0x31, 0x50, - 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, - 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, - 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0xd7, 0xd7, 0x53, 0xc1, 0x47, 0xd4, - 0xd7, 0xd7, 0xd7, 0x05, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x07, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x27, 0x51, 0x6f, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x83, 0x8e, 0x92, 0x97, 0x00, 0xaa, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x4e, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, - 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x24, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x31, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x79, 0x5c, 0x7b, 0x5c, 0x7b, - 0x4f, 0x7b, 0x5c, 0x7b, 0x5c, 0x7b, 0x5c, 0x7b, 0x5c, 0x7b, 0x5c, 0x7b, - 0x5c, 0x7b, 0x5c, 0x7b, 0x5c, 0x7b, 0x5c, 0x7b, 0x5c, 0x2d, 0x2b, 0x2b, - 0x79, 0x14, 0x5c, 0x7b, 0x5c, 0x2d, 0x79, 0x2a, 0x5c, 0x27, 0x5c, 0x7b, - 0x5c, 0x7b, 0x5c, 0x7b, 0xa4, 0x00, 0x0a, 0xb4, 0x5c, 0x7b, 0x5c, 0x7b, - 0x4f, 0x03, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc9, 0x00, + 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x07, 0x00, 0x48, 0x56, 0x56, - 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x55, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, - 0x56, 0x56, 0x56, 0x56, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xde, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x24, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x07, 0x00, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, - 0x56, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x07, 0x00, 0x00, 0x00, 0x00, 0x56, 0x56, 0x56, 0x56, - 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, - 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x56, 0x56, - 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, - 0x56, 0x56, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x55, 0x56, 0x56, - 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x27, 0x51, 0x6f, 0x77, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, - 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x8e, - 0x92, 0x97, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xb4, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc9, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0x00, - 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, - 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, - 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x01, 0x20, - 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x04, 0x20, - 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0x08, 0x20, - 0x00, 0x00, 0x09, 0x20, 0x00, 0x00, 0x0a, 0x20, 0x00, 0x00, 0x28, 0x20, - 0x00, 0x00, 0x29, 0x20, 0x00, 0x00, 0x5f, 0x20, 0x00, 0x00, 0x00, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x05, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x00, 0x0c, 0x0b, 0x73, 0x74, 0x64, 0x6c, 0x69, 0x62, 0x2e, - 0x77, 0x61, 0x73, 0x6d, 0x01, 0xc9, 0x04, 0x2c, 0x00, 0x2a, 0x5f, 0x5f, - 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x77, 0x61, 0x73, - 0x69, 0x5f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x70, - 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x31, 0x5f, 0x61, 0x72, 0x67, 0x73, - 0x5f, 0x67, 0x65, 0x74, 0x01, 0x30, 0x5f, 0x5f, 0x69, 0x6d, 0x70, 0x6f, - 0x72, 0x74, 0x65, 0x64, 0x5f, 0x77, 0x61, 0x73, 0x69, 0x5f, 0x73, 0x6e, - 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x69, - 0x65, 0x77, 0x31, 0x5f, 0x61, 0x72, 0x67, 0x73, 0x5f, 0x73, 0x69, 0x7a, - 0x65, 0x73, 0x5f, 0x67, 0x65, 0x74, 0x02, 0x2b, 0x5f, 0x5f, 0x69, 0x6d, - 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x77, 0x61, 0x73, 0x69, 0x5f, - 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x70, 0x72, 0x65, - 0x76, 0x69, 0x65, 0x77, 0x31, 0x5f, 0x70, 0x72, 0x6f, 0x63, 0x5f, 0x65, - 0x78, 0x69, 0x74, 0x03, 0x11, 0x5f, 0x5f, 0x77, 0x61, 0x73, 0x6d, 0x5f, - 0x63, 0x61, 0x6c, 0x6c, 0x5f, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x04, 0x13, - 0x75, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x77, 0x65, - 0x61, 0x6b, 0x3a, 0x6d, 0x61, 0x69, 0x6e, 0x05, 0x12, 0x5f, 0x5f, 0x77, - 0x61, 0x73, 0x6d, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x6d, 0x65, 0x6d, - 0x6f, 0x72, 0x79, 0x06, 0x06, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x07, - 0x0a, 0x72, 0x65, 0x73, 0x65, 0x74, 0x5f, 0x68, 0x65, 0x61, 0x70, 0x08, - 0x06, 0x6d, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x09, 0x04, 0x66, 0x72, 0x65, - 0x65, 0x0a, 0x06, 0x63, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x0b, 0x07, 0x72, - 0x65, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x0c, 0x05, 0x5f, 0x45, 0x78, 0x69, - 0x74, 0x0d, 0x0b, 0x5f, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x76, 0x6f, - 0x69, 0x64, 0x0e, 0x0f, 0x5f, 0x5f, 0x77, 0x61, 0x73, 0x69, 0x5f, 0x61, - 0x72, 0x67, 0x73, 0x5f, 0x67, 0x65, 0x74, 0x0f, 0x15, 0x5f, 0x5f, 0x77, - 0x61, 0x73, 0x69, 0x5f, 0x61, 0x72, 0x67, 0x73, 0x5f, 0x73, 0x69, 0x7a, - 0x65, 0x73, 0x5f, 0x67, 0x65, 0x74, 0x10, 0x10, 0x5f, 0x5f, 0x77, 0x61, - 0x73, 0x69, 0x5f, 0x70, 0x72, 0x6f, 0x63, 0x5f, 0x65, 0x78, 0x69, 0x74, - 0x11, 0x05, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x12, 0x11, 0x5f, 0x5f, 0x77, - 0x61, 0x73, 0x6d, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x5f, 0x64, 0x74, 0x6f, - 0x72, 0x73, 0x13, 0x06, 0x6d, 0x65, 0x6d, 0x63, 0x70, 0x79, 0x14, 0x06, - 0x6d, 0x65, 0x6d, 0x73, 0x65, 0x74, 0x15, 0x06, 0x73, 0x74, 0x72, 0x6c, - 0x65, 0x6e, 0x16, 0x08, 0x69, 0x73, 0x77, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x17, 0x06, 0x6d, 0x65, 0x6d, 0x63, 0x6d, 0x70, 0x18, 0x06, 0x6d, 0x65, - 0x6d, 0x63, 0x68, 0x72, 0x19, 0x06, 0x73, 0x74, 0x72, 0x63, 0x6d, 0x70, - 0x1a, 0x08, 0x74, 0x6f, 0x77, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x1b, 0x07, - 0x63, 0x61, 0x73, 0x65, 0x6d, 0x61, 0x70, 0x1c, 0x08, 0x74, 0x6f, 0x77, - 0x75, 0x70, 0x70, 0x65, 0x72, 0x1d, 0x07, 0x73, 0x74, 0x72, 0x6e, 0x63, - 0x6d, 0x70, 0x1e, 0x08, 0x69, 0x73, 0x77, 0x75, 0x70, 0x70, 0x65, 0x72, - 0x1f, 0x07, 0x6d, 0x65, 0x6d, 0x6d, 0x6f, 0x76, 0x65, 0x20, 0x08, 0x69, - 0x73, 0x77, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x21, 0x07, 0x69, 0x73, 0x62, - 0x6c, 0x61, 0x6e, 0x6b, 0x22, 0x08, 0x69, 0x73, 0x77, 0x62, 0x6c, 0x61, - 0x6e, 0x6b, 0x23, 0x08, 0x69, 0x73, 0x77, 0x64, 0x69, 0x67, 0x69, 0x74, - 0x24, 0x07, 0x73, 0x74, 0x72, 0x6e, 0x63, 0x61, 0x74, 0x25, 0x09, 0x5f, - 0x5f, 0x73, 0x74, 0x70, 0x6e, 0x63, 0x70, 0x79, 0x26, 0x07, 0x73, 0x74, - 0x72, 0x6e, 0x63, 0x70, 0x79, 0x27, 0x09, 0x69, 0x73, 0x77, 0x78, 0x64, - 0x69, 0x67, 0x69, 0x74, 0x28, 0x06, 0x77, 0x63, 0x73, 0x6c, 0x65, 0x6e, - 0x29, 0x06, 0x77, 0x63, 0x73, 0x63, 0x68, 0x72, 0x2a, 0x08, 0x69, 0x73, - 0x77, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2b, 0x08, 0x69, 0x73, 0x77, 0x61, - 0x6c, 0x6e, 0x75, 0x6d, 0x07, 0x33, 0x02, 0x00, 0x0f, 0x5f, 0x5f, 0x73, - 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x01, 0x1f, 0x47, 0x4f, 0x54, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x5f, 0x5f, 0x6d, 0x65, - 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x09, 0x0a, 0x01, - 0x00, 0x07, 0x2e, 0x72, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x00, 0x26, 0x09, - 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x73, 0x01, 0x0c, 0x70, - 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x2d, 0x62, 0x79, 0x01, - 0x05, 0x63, 0x6c, 0x61, 0x6e, 0x67, 0x06, 0x31, 0x39, 0x2e, 0x31, 0x2e, - 0x37, 0x00, 0x56, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x66, - 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x05, 0x2b, 0x0b, 0x62, 0x75, - 0x6c, 0x6b, 0x2d, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x2b, 0x0a, 0x6d, - 0x75, 0x6c, 0x74, 0x69, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2b, 0x0f, 0x6d, - 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2d, 0x67, 0x6c, 0x6f, 0x62, 0x61, - 0x6c, 0x73, 0x2b, 0x0f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, - 0x65, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2b, 0x08, 0x73, 0x69, 0x67, - 0x6e, 0x2d, 0x65, 0x78, 0x74 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, + 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0b, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x03, + 0x20, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x06, + 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x09, 0x20, 0x00, 0x00, 0x0a, + 0x20, 0x00, 0x00, 0x28, 0x20, 0x00, 0x00, 0x29, 0x20, 0x00, 0x00, 0x5f, + 0x20, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x41, 0xe8, 0xc2, 0x04, 0x0b, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x8e, + 0x01, 0x09, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x73, 0x02, + 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x01, 0x03, 0x43, + 0x31, 0x31, 0x00, 0x0c, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, + 0x64, 0x2d, 0x62, 0x79, 0x01, 0x05, 0x63, 0x6c, 0x61, 0x6e, 0x67, 0x5f, + 0x32, 0x31, 0x2e, 0x31, 0x2e, 0x34, 0x2d, 0x77, 0x61, 0x73, 0x69, 0x2d, + 0x73, 0x64, 0x6b, 0x20, 0x28, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, + 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x6c, 0x6c, 0x76, 0x6d, 0x2f, 0x6c, 0x6c, 0x76, 0x6d, 0x2d, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x32, 0x32, 0x32, 0x66, 0x63, 0x31, + 0x31, 0x66, 0x32, 0x62, 0x38, 0x66, 0x32, 0x35, 0x66, 0x36, 0x61, 0x30, + 0x66, 0x34, 0x39, 0x37, 0x36, 0x32, 0x37, 0x32, 0x65, 0x66, 0x31, 0x62, + 0x62, 0x37, 0x62, 0x66, 0x34, 0x39, 0x35, 0x32, 0x31, 0x64, 0x29, 0x00, + 0xa4, 0x01, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x66, 0x65, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x09, 0x2b, 0x0f, 0x6d, 0x75, 0x74, + 0x61, 0x62, 0x6c, 0x65, 0x2d, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, + 0x2b, 0x13, 0x6e, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x70, 0x70, 0x69, 0x6e, + 0x67, 0x2d, 0x66, 0x70, 0x74, 0x6f, 0x69, 0x6e, 0x74, 0x2b, 0x0b, 0x62, + 0x75, 0x6c, 0x6b, 0x2d, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x2b, 0x08, + 0x73, 0x69, 0x67, 0x6e, 0x2d, 0x65, 0x78, 0x74, 0x2b, 0x0f, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x2d, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x2b, 0x0a, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x2b, 0x0e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x2d, + 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x2b, 0x0f, 0x62, 0x75, 0x6c, 0x6b, 0x2d, + 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x2d, 0x6f, 0x70, 0x74, 0x2b, 0x16, + 0x63, 0x61, 0x6c, 0x6c, 0x2d, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, + 0x74, 0x2d, 0x6f, 0x76, 0x65, 0x72, 0x6c, 0x6f, 0x6e, 0x67 }; -unsigned int STDLIB_WASM_LEN = 15965; +unsigned int STDLIB_WASM_LEN = 14794;