diff --git a/.github/workflows/build-arm64-wheels.yml b/.github/workflows/build-arm64-wheels.yml index ba40fe845..6d8a5f72c 100644 --- a/.github/workflows/build-arm64-wheels.yml +++ b/.github/workflows/build-arm64-wheels.yml @@ -5,12 +5,16 @@ on: branches: - main - dev - tags: - - '**' + release: + types: [published] pull_request: branches: - '**' +permissions: + id-token: write + contents: read + jobs: build_wheels: name: Build ARM64 Python Wheels @@ -61,7 +65,7 @@ jobs: name: wheels path: target/wheels/ - - name: Install Twine + - name: Install job deps run: | if [ ! -f "venv" ]; then rm -rf venv; fi sudo apt install python3 python3-pip -y @@ -69,49 +73,46 @@ jobs: if [ ! -f "activate" ]; then ln -s venv/bin/activate; fi . ./activate pip3 install setuptools_rust - pip3 install twine - name: Test for secrets access id: check_secrets shell: bash run: | - unset HAS_SECRET unset HAS_AWS_SECRET - if [ -n "$SECRET" ]; then HAS_SECRET='true' ; fi - echo "HAS_SECRET=${HAS_SECRET}" >>$GITHUB_OUTPUT - if [ -n "$AWS_SECRET" ]; then HAS_AWS_SECRET='true' ; fi echo HAS_AWS_SECRET=${HAS_AWS_SECRET} >>$GITHUB_OUTPUT env: - SECRET: "${{ secrets.test_pypi_password }}" - AWS_SECRET: "${{ secrets.INSTALLER_UPLOAD_KEY }}" + AWS_SECRET: "${{ secrets.CHIA_AWS_ACCOUNT_ID }}" - - name: publish (PyPi) - if: startsWith(github.event.ref, 'refs/tags') && steps.check_secrets.outputs.HAS_SECRET + - name: Set Env + uses: Chia-Network/actions/setjobenv@main env: - TWINE_USERNAME: __token__ - TWINE_NON_INTERACTIVE: 1 - TWINE_PASSWORD: ${{ secrets.pypi_password }} - run: | - . ./activate - twine upload --non-interactive --skip-existing --verbose 'target/wheels/*' + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: publish (PyPi) + if: env.RELEASE == 'true' + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: target/wheels/ + skip-existing: true + - name: publish (Test PyPi) - if: steps.check_secrets.outputs.HAS_SECRET - env: - TWINE_REPOSITORY_URL: https://test.pypi.org/legacy/ - TWINE_USERNAME: __token__ - TWINE_NON_INTERACTIVE: 1 - TWINE_PASSWORD: ${{ secrets.test_pypi_password }} - run: | - . ./activate - twine upload --non-interactive --skip-existing --verbose 'target/wheels/*' + if: env.PRE_RELEASE == 'true' + uses: pypa/gh-action-pypi-publish@release/v1 + with: + repository-url: https://test.pypi.org/legacy/ + packages-dir: target/wheels/ + skip-existing: true + + - name: Configure AWS credentials + if: steps.check_secrets.outputs.HAS_AWS_SECRET + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: arn:aws:iam::${{ secrets.CHIA_AWS_ACCOUNT_ID }}:role/installer-upload + aws-region: us-west-2 - name: Publish Dev if: steps.check_secrets.outputs.HAS_AWS_SECRET && github.ref == 'refs/heads/dev' - env: - AWS_ACCESS_KEY_ID: "${{ secrets.INSTALLER_UPLOAD_KEY }}" - AWS_SECRET_ACCESS_KEY: "${{ secrets.INSTALLER_UPLOAD_SECRET }}" - AWS_REGION: us-west-2 run: | FILES=$(find ${{ github.workspace }}/target/wheels -type f -name '*.whl') while IFS= read -r file; do diff --git a/.github/workflows/build-m1-wheel.yml b/.github/workflows/build-m1-wheel.yml index 917451d4f..5831afae7 100644 --- a/.github/workflows/build-m1-wheel.yml +++ b/.github/workflows/build-m1-wheel.yml @@ -5,8 +5,8 @@ on: branches: - main - dev - tags: - - '**' + release: + types: [published] pull_request: branches: - '**' @@ -15,10 +15,14 @@ concurrency: group: ${{ github.ref }}-${{ github.workflow }}-${{ github.event_name }}--${{ (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/') || startsWith(github.ref, 'refs/heads/long_lived/')) && github.sha || '' }} cancel-in-progress: true +permissions: + id-token: write + contents: read + jobs: build_wheels: name: Build wheel on Mac M1 - runs-on: [m1] + runs-on: [MacOS, ARM64] strategy: fail-fast: false @@ -45,43 +49,43 @@ jobs: - name: Build m1 wheels run: | - arch -arm64 python3 -m venv venv + python3 -m venv venv . ./venv/bin/activate export PATH=~/.cargo/bin:$PATH - arch -arm64 pip install maturin==1.1.0 - arch -arm64 maturin build -i python --release --strip - arch -arm64 cargo test + pip install maturin==1.1.0 + maturin build -i python --release --strip + cargo test - name: Install clvm_tools_rs wheel run: | . ./venv/bin/activate ls target/wheels/ - arch -arm64 pip install ./target/wheels/clvm_tools_rs*.whl + pip install ./target/wheels/clvm_tools_rs*.whl - name: Install other wheels run: | . ./venv/bin/activate - arch -arm64 python -m pip install pytest - arch -arm64 python -m pip install blspy + python -m pip install pytest + python -m pip install blspy - name: install clvm & clvm_tools run: | . ./venv/bin/activate - arch -arm64 git clone https://github.com/Chia-Network/clvm.git --branch=main --single-branch - arch -arm64 python -m pip install ./clvm - arch -arm64 python -m pip install clvm_rs + git clone https://github.com/Chia-Network/clvm.git --branch=main --single-branch + python -m pip install ./clvm + python -m pip install clvm_rs - arch -arm64 git clone https://github.com/Chia-Network/clvm_tools.git --branch=main --single-branch - arch -arm64 python -m pip install ./clvm_tools + git clone https://github.com/Chia-Network/clvm_tools.git --branch=main --single-branch + python -m pip install ./clvm_tools - name: Ensure clvm, clvm_rs, clvm_tools are installed run: | . ./venv/bin/activate - arch -arm64 python -c 'import clvm' - arch -arm64 python -c 'import clvm; print(clvm.__file__)' - arch -arm64 python -c 'import clvm_rs; print(clvm_rs.__file__)' - arch -arm64 python -c 'import clvm_tools; print(clvm_tools.__file__)' - arch -arm64 python -c 'import clvm_tools_rs; print(clvm_tools_rs.__file__)' + python -c 'import clvm' + python -c 'import clvm; print(clvm.__file__)' + python -c 'import clvm_rs; print(clvm_rs.__file__)' + python -c 'import clvm_tools; print(clvm_tools.__file__)' + python -c 'import clvm_tools_rs; print(clvm_tools_rs.__file__)' - name: Install pytest run: | @@ -93,13 +97,13 @@ jobs: # run: | # . ./venv/bin/activate # cd clvm -# arch -arm64 python -m py.test tests +# python -m py.test tests - name: Run tests from clvm_tools run: | . ./venv/bin/activate cd clvm_tools - arch -arm64 pytest + pytest - name: Upload wheels uses: actions/upload-artifact@v3 @@ -111,44 +115,42 @@ jobs: id: check_secrets shell: bash run: | - unset HAS_SECRET unset HAS_AWS_SECRET - if [ -n "$SECRET" ]; then HAS_SECRET='true' ; fi - echo "HAS_SECRET=${HAS_SECRET}" >>$GITHUB_OUTPUT - if [ -n "$AWS_SECRET" ]; then HAS_AWS_SECRET='true' ; fi echo HAS_AWS_SECRET=${HAS_AWS_SECRET} >>$GITHUB_OUTPUT env: - SECRET: "${{ secrets.test_pypi_password }}" - AWS_SECRET: "${{ secrets.INSTALLER_UPLOAD_KEY }}" - - - name: Install twine - run: arch -arm64 pip install twine + AWS_SECRET: "${{ secrets.CHIA_AWS_ACCOUNT_ID }}" - - name: Publish distribution to PyPI - if: startsWith(github.event.ref, 'refs/tags') && steps.check_secrets.outputs.HAS_SECRET + - name: Set Env + uses: Chia-Network/actions/setjobenv@main env: - TWINE_USERNAME: __token__ - TWINE_NON_INTERACTIVE: 1 - TWINE_PASSWORD: ${{ secrets.pypi_password }} - run: arch -arm64 twine upload --non-interactive --skip-existing --verbose 'target/wheels/*' + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Publish distribution to Test PyPI - if: steps.check_secrets.outputs.HAS_SECRET - env: - TWINE_REPOSITORY_URL: https://test.pypi.org/legacy/ - TWINE_USERNAME: __token__ - TWINE_NON_INTERACTIVE: 1 - TWINE_PASSWORD: ${{ secrets.test_pypi_password }} - run: arch -arm64 twine upload --non-interactive --skip-existing --verbose 'target/wheels/*' + - name: publish (PyPi) + if: env.RELEASE == 'true' + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: target/wheels/ + skip-existing: true + + - name: publish (Test PyPi) + if: env.PRE_RELEASE == 'true' + uses: pypa/gh-action-pypi-publish@release/v1 + with: + repository-url: https://test.pypi.org/legacy/ + packages-dir: target/wheels/ + skip-existing: true + + - name: Configure AWS credentials + if: steps.check_secrets.outputs.HAS_AWS_SECRET + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: arn:aws:iam::${{ secrets.CHIA_AWS_ACCOUNT_ID }}:role/installer-upload + aws-region: us-west-2 - name: Publish Dev if: steps.check_secrets.outputs.HAS_AWS_SECRET && github.ref == 'refs/heads/dev' - env: - AWS_ACCESS_KEY_ID: "${{ secrets.INSTALLER_UPLOAD_KEY }}" - AWS_SECRET_ACCESS_KEY: "${{ secrets.INSTALLER_UPLOAD_SECRET }}" - AWS_REGION: us-west-2 run: | FILES=$(find ${{ github.workspace }}/target/wheels -type f -name '*.whl') while IFS= read -r file; do diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index f56023f04..409609482 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -1,17 +1,21 @@ # Thanks: clvm_rs' github actions. -name: Build Mac, Linux, and Windows wheels +name: Build on: push: branches: - base - dev - tags: - - '**' + release: + types: [published] pull_request: branches: - '**' +permissions: + id-token: write + contents: read + jobs: build_wheels: name: Wheel on ${{ matrix.os }} py-${{ matrix.python }} @@ -85,12 +89,6 @@ jobs: # Ensure an empty .cargo-lock file exists. touch target/release/.cargo-lock - - name: Build alpine wheel via docker - if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.python, '3.8') - run: | - cd resources/alpine && docker build -t clvm-tools-rs-alpine . - docker run -v ${GITHUB_WORKSPACE}:/root/clvm_tools_rs -t clvm-tools-rs-alpine sh /root/build-alpine.sh - - name: Build Windows with maturin on Python ${{ matrix.python }} if: startsWith(matrix.os, 'windows') run: | @@ -116,7 +114,7 @@ jobs: run: | . ./activate python -m pip install pytest - python -m pip install blspy + python -m pip install blspy - name: install clvm & clvm_tools run: | @@ -140,10 +138,13 @@ jobs: python -c 'import clvm; print(clvm.__file__)' python -c 'import clvm_rs; print(clvm_rs.__file__)' python -c 'import clvm_tools_rs; print(clvm_tools_rs.__file__)' + echo "CLVM_TOOLS_RS_VERSION=$(python -c 'import clvm_tools_rs; print(clvm_tools_rs.get_version())')" >> "$GITHUB_ENV" - - name: Verify recompilation of old sources match + + - name: Verify recompilation of old sources match with new compiler if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.python, '3.8') run: | + set -x . ./activate # Build cmd line tools PYO3_PYTHON=`which python` cargo build --no-default-features --release @@ -152,9 +153,16 @@ jobs: rm -rf chia-blockchain git clone https://github.com/Chia-Network/chia-blockchain - # Check recompiles - cp support/recompile_check.py chia-blockchain - (cd chia-blockchain && python recompile_check.py) + # Check that recompiling deployed puzzles match with their deployed hashes + cp support/install_deps.sh support/verify_compiler_version.sh chia-blockchain + (cd chia-blockchain && python -m venv venv && . venv/bin/activate && pip install --upgrade pip && \ + python -m pip install maturin==1.1.0 && \ + cd .. && python support/wheelname.py && \ + cd chia-blockchain && \ + # deps for manage_clvm.py + pip install click typing_extensions chia_rs clvm && \ + export PYTHONPATH=${PYTHONPATH}:$(pwd) && \ + ./verify_compiler_version.sh ${CLVM_TOOLS_RS_VERSION} && ./activated.py python tools/manage_clvm.py check) - name: Test Classic command line tools with pytest if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.python, '3.8') @@ -204,6 +212,10 @@ jobs: if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.python, '3.8') run: cargo test --no-default-features + - name: Exhaustive assign tests + if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.python, '3.8') + run: cargo test -- --include-ignored assign + - name: Check coverage if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.python, '3.8') run: | @@ -217,51 +229,48 @@ jobs: name: wheels path: ./target/wheels/ - - name: Install Twine - run: pip install twine - - name: Test for secrets access id: check_secrets shell: bash run: | - unset HAS_SECRET unset HAS_AWS_SECRET - if [ -n "$SECRET" ]; then HAS_SECRET='true' ; fi - echo "HAS_SECRET=${HAS_SECRET}" >>$GITHUB_OUTPUT - if [ -n "$AWS_SECRET" ]; then HAS_AWS_SECRET='true' ; fi echo HAS_AWS_SECRET=${HAS_AWS_SECRET} >>$GITHUB_OUTPUT + env: + AWS_SECRET: "${{ secrets.CHIA_AWS_ACCOUNT_ID }}" + - name: Set Env + uses: Chia-Network/actions/setjobenv@main env: - SECRET: "${{ secrets.test_pypi_password }}" - AWS_SECRET: "${{ secrets.INSTALLER_UPLOAD_KEY }}" + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: publish (PyPi) - if: startsWith(github.event.ref, 'refs/tags') && steps.check_secrets.outputs.HAS_SECRET - env: - TWINE_USERNAME: __token__ - TWINE_NON_INTERACTIVE: 1 - TWINE_PASSWORD: ${{ secrets.pypi_password }} - run: twine upload --non-interactive --skip-existing --verbose 'target/wheels/*' + if: env.RELEASE == 'true' + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: target/wheels/ + skip-existing: true - name: publish (Test PyPi) - if: steps.check_secrets.outputs.HAS_SECRET - env: - TWINE_REPOSITORY_URL: https://test.pypi.org/legacy/ - TWINE_USERNAME: __token__ - TWINE_NON_INTERACTIVE: 1 - TWINE_PASSWORD: ${{ secrets.test_pypi_password }} - run: twine upload --non-interactive --skip-existing --verbose 'target/wheels/*' + if: env.PRE_RELEASE == 'true' + uses: pypa/gh-action-pypi-publish@release/v1 + with: + repository-url: https://test.pypi.org/legacy/ + packages-dir: target/wheels/ + skip-existing: true + + - name: Configure AWS credentials + if: steps.check_secrets.outputs.HAS_AWS_SECRET + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: arn:aws:iam::${{ secrets.CHIA_AWS_ACCOUNT_ID }}:role/installer-upload + aws-region: us-west-2 - name: Publish Dev if: steps.check_secrets.outputs.HAS_AWS_SECRET && github.ref == 'refs/heads/dev' shell: bash working-directory: ./target/wheels - env: - AWS_ACCESS_KEY_ID: "${{ secrets.INSTALLER_UPLOAD_KEY }}" - AWS_SECRET_ACCESS_KEY: "${{ secrets.INSTALLER_UPLOAD_SECRET }}" - AWS_REGION: us-west-2 run: | FILES=$(find . -type f -name '*.whl') while IFS= read -r file; do @@ -269,6 +278,12 @@ jobs: aws --no-progress s3 cp "$file" "s3://download.chia.net/simple-dev/clvm-tools-rs/$filename" done <<< "$FILES" + - name: Build alpine wheel via docker + if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.python, '3.8') + run: | + cd resources/alpine && docker build -t clvm-tools-rs-alpine . + docker run -v ${GITHUB_WORKSPACE}:/root/clvm_tools_rs -t clvm-tools-rs-alpine sh /root/build-alpine.sh + fmt: runs-on: ubuntu-20.04 name: cargo fmt @@ -296,10 +311,10 @@ jobs: override: true - name: clippy run: cargo clippy --all -- -D warnings - - uses: actions-rs/clippy-check@v1 + - uses: giraffate/clippy-action@v1 with: - token: ${{ secrets.GITHUB_TOKEN }} - args: --all-features + reporter: 'github-pr-review' + github_token: ${{ secrets.GITHUB_TOKEN }} unit_tests: runs-on: ubuntu-20.04 @@ -322,11 +337,26 @@ jobs: - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: - toolchain: nightly - - name: Install tarpaulin - run: cargo +nightly install cargo-tarpaulin - - name: Run tarpaulin - run: cargo tarpaulin --no-dead-code --engine llvm --workspace --all-features --ignore-panics --out Lcov + toolchain: stable + - name: Run for coverage + run: | + sudo apt-get update + sudo apt-get install lcov -y + rustup component add llvm-tools-preview + cargo install grcov + export RUSTFLAGS="-Cinstrument-coverage" + export LLVM_PROFILE_FILE=$(pwd)/target/clvm_tools_rs-%p-%m.profraw + export CARGO_TARGET_DIR=$(pwd)/target + cargo test --release --workspace + python -m venv venv + source venv/bin/activate + git clone https://github.com/Chia-Network/clvm_tools.git --branch=main --single-branch + pip install ./clvm_tools + pip install maturin pytest + maturin develop --release + (cd resources/tests/cmdline/tests && pytest) + grcov . --binary-path target -s . --branch --ignore-not-existing --ignore='*/.cargo/*' --ignore='*/tests/*' -o rust_cov.info + python -c 'with open("rust_cov.info") as f: lines = [l for l in f if not (l.startswith("DA:") and int(l.split(",")[1].strip()) >= 2**63)]; open("lcov.info", "w").writelines(lines)' - name: Upload to Coveralls uses: coverallsapp/github-action@v2 if: always() diff --git a/.github/workflows/extensive-tests.yml b/.github/workflows/extensive-tests.yml new file mode 100644 index 000000000..6bf997da7 --- /dev/null +++ b/.github/workflows/extensive-tests.yml @@ -0,0 +1,120 @@ +# Taken from clvm_rs' version. +name: Extensive tests + +on: + push: + branches: + - main + - dev + tags: + - '**' + pull_request: + branches: + - '**' + +jobs: + extensive_tests: + name: Extensive tests + runs-on: ubuntu-latest + strategy: + fail-fast: false + + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Set up rusts + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + components: rustfmt, clippy + + - name: Set up rust (stable) + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + components: rustfmt, clippy + + - uses: actions/setup-python@v4 + name: Install Python 3.11 + with: + python-version: 3.11 + + - name: Update pip + run: | + python -m pip install --upgrade pip + + - name: Set up rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + + - name: Install dependencies + run: | + python -m pip install maturin==1.1.0 + + - name: Build Linux in manylinux2010 with maturin on Python ${{ matrix.python }} + run: | + podman run --rm=true \ + -v ${{ github.workspace }}:/ws:rw --workdir=/ws \ + ghcr.io/chia-network/build-images/centos-pypa-rust-x86_64 \ + bash -exc '\ + yum -y install libc6 openssl-devel && \ + source $HOME/.cargo/env && \ + rustup target add x86_64-unknown-linux-musl && \ + rm -rf venv && \ + PY_VERSION=${{ matrix.python }} + PY_VERSION=${PY_VERSION/.} && \ + echo "Python version with dot removed is $PY_VERSION" && \ + if [ "$PY_VERSION" = "37" ]; \ + then export SCND_VERSION="${PY_VERSION}m"; \ + else export SCND_VERSION="$PY_VERSION"; fi && \ + echo "Exporting path /opt/python/cp$PY_VERSION-cp$SCND_VERSION/bin" && \ + export PATH=/opt/python/cp$PY_VERSION-cp$SCND_VERSION/bin/:$PATH && \ + /opt/python/cp38-cp38/bin/python -m venv venv && \ + if [ ! -f "activate" ]; then ln -s venv/bin/activate; fi && \ + . ./activate && \ + pip install --upgrade pip + ' + docker run --rm -v $(pwd):/io ghcr.io/pyo3/maturin:v1.1.0 build --release --strip --manylinux 2014 + # Refresh in case any ownerships changed. + mv target target.docker && cp -r target.docker target + # Ensure an empty .cargo-lock file exists. + touch target/release/.cargo-lock + + - name: Install clvm_tools_rs wheel + if: ${{ !startsWith(matrix.os, 'windows') }} + run: | + . ./activate + ls target/wheels/ + # this mess puts the name of the `.whl` file into `$WHEEL_PATH` + # remove the dot, use the `glob` lib to grab the file from the directory + export WHEEL_PATH=$(echo ${{ matrix.python }} | python -c 'DOTLESS=input().replace(".", ""); import glob; print(" ".join(filter(lambda x: "musl" not in x, glob.glob("target/wheels/clvm_tools_rs-*-cp*-*.whl"))))' ) + echo ${WHEEL_PATH} + pip install ${WHEEL_PATH} + + - name: Install other wheels + run: | + . ./activate + python -m pip install pytest + python -m pip install blspy + + - name: install clvm & clvm_tools + run: | + . ./activate + git clone https://github.com/Chia-Network/clvm.git --branch=main --single-branch + python -m pip install ./clvm + + echo "installing clvm_rs via pip" + pip install clvm_rs + + echo "installing clvm_tools for clvm tests" + # clvm tools is required to run the tests is clvm + python -m pip install clvm_tools + + - name: Run game referee test + run: | + . ./activate + cp support/test-game-referee.sh . + sh test-game-referee.sh resources/tests/game-referee-in-cl21 diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 395a02866..46a2d9fe6 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -3,26 +3,33 @@ name: npm publish on: push: branches: - - main - - dev - tags: - - '**' + - base + release: + types: [published] pull_request: branches: - '**' +concurrency: + # SHA is added to the end if on `main` to let all main workflows run + group: ${{ github.ref }}-${{ github.workflow }}-${{ github.event_name }}-${{ (github.ref == 'refs/heads/main') && github.sha || '' }} + cancel-in-progress: true + jobs: build_npm: name: Npm runs-on: ubuntu-latest - strategy: - fail-fast: false steps: - uses: actions/checkout@v3 with: fetch-depth: 0 + - name: Set Env + uses: Chia-Network/actions/setjobenv@main + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Set up rusts uses: actions-rs/toolchain@v1 with: @@ -40,9 +47,20 @@ jobs: with: node-version: '16.x' + # Cargo.toml won't allow an "@" in the name, so we just update the package name this way for NPM + - name: Update package name for npm + working-directory: ${{ github.workspace }}/wasm/pkg + run: | + cp package.json package.json.orig + jq '.name="@chia/chialisp"' package.json > temp.json && mv temp.json package.json + - name: Test wasm run: node wasm/tests/index.js + - name: Test clvm-js like wasm interface + run: | + cd wasm/tests/clvm-tools-interface && npm install && yarn test + - name: Upload npm pkg artifacts uses: actions/upload-artifact@v3 with: @@ -57,12 +75,14 @@ jobs: if [ -n "$SECRET" ]; then HAS_SECRET='true' ; fi echo "HAS_SECRET=${HAS_SECRET}" >>$GITHUB_OUTPUT env: - SECRET: "${{ secrets.test_pypi_password }}" + SECRET: "${{ secrets.NPM_TOKEN }}" - name: Publish wasm - if: steps.check_secrets.HAS_SECRET - shell: bash + if: env.FULL_RELEASE == 'true' && steps.check_secrets.outputs.HAS_SECRET + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + working-directory: ${{ github.workspace }}/wasm/pkg run: | - cd wasm/pkg + echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc rm -f clvm_tools_wasm-*.tgz npm publish --access public diff --git a/.gitignore b/.gitignore index 77e2b42a7..a343936cb 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,9 @@ wasm/tests/node_modules resources/tests/bridgeref/*.sym resources/tests/bridgeref/*.clvm.hex resources/tests/gameref21/*.sym -resources/tests/gameref21/*.clvm.hex \ No newline at end of file +resources/tests/gameref21/*.clvm.hex +resources/tests/gameref21/*.clvm.hex +resources/tests/game-referee/*.sym +resources/tests/game-referee/*.clvm.hex +__pycache__ +.pytest_cache diff --git a/CHANGELOG.md b/CHANGELOG.md index a2bbf5116..a1b58b09b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,3 +24,13 @@ Skipped - hierarchial debug was added. - clvm command linetools: supported more command line features in both compiler front-ends. +## 0.1.35 + +- embed-file was added. +- &rest arguments. +- new bls and sec256 operators. + +## 0.1.36 + +- modern lambda added +- updated some internal data strucutres and call interfaces to support env variable renaming at during closure generation / lambda capture, or any step during transformation. diff --git a/Cargo.lock b/Cargo.lock index 6cc688bc4..e24af67df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,7 +117,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clvm_tools_rs" -version = "0.1.34" +version = "0.1.36" dependencies = [ "binascii", "bls12_381", @@ -151,9 +151,9 @@ dependencies = [ [[package]] name = "clvmr" -version = "0.2.7" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2890f01537f1be43d2767ae71bbba0d0b3543dbb1ee892092d0ed4d913227fc" +checksum = "9cd344b6dc76235f446025fe9ebe54aa6131e2e59acb49e16be48a3bb3492491" dependencies = [ "bls12_381", "getrandom", diff --git a/Cargo.toml b/Cargo.toml index 63337780e..6172b9058 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clvm_tools_rs" -version = "0.1.34" +version = "0.1.36" edition = "2018" authors = ["Art Yerkes "] description = "tools for working with chialisp language; compiler, repl, python and wasm bindings" @@ -32,7 +32,7 @@ do-notation = "0.1.3" serde_json = "1.0" sha2 = "0.9.5" tempfile = "3.3.0" -clvmr = { version = "0.2.6", features = ["pre-eval"] } +clvmr = { version = "0.3.0", features = ["pre-eval"] } binascii = "0.1.4" yaml-rust = "0.4" linked-hash-map = "0.5.6" diff --git a/pyproject.toml b/pyproject.toml index bd9c56524..6049eb79b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["maturin>=0.11.3,<0.12"] +requires = ["maturin>=1.1.0,<1.3.0"] build-backend = "maturin" [tool.maturin] diff --git a/resources/coverage/run_coverage.py b/resources/coverage/run_coverage.py index 5399cf0c7..4c6b48b06 100644 --- a/resources/coverage/run_coverage.py +++ b/resources/coverage/run_coverage.py @@ -62,7 +62,7 @@ def collect_coverage(): required_percentage = int(args.require_percent) has_required_pct = True - for file in result: + for file in filter(lambda f: '/tests/' not in f['name'], result): have_pct = int(file['coveragePercent']) if have_pct < required_percentage: print(f"{file['name']} lacks required coverage have {have_pct} want {required_percentage}") diff --git a/resources/tests/chia-gaming/last.clinc b/resources/tests/chia-gaming/last.clinc new file mode 100644 index 000000000..5a6ffd73e --- /dev/null +++ b/resources/tests/chia-gaming/last.clinc @@ -0,0 +1,39 @@ +( + (defun last_inner ((next . remainder)) + (if remainder + (last_inner remainder) + next + ) + ) + + (defmacro last ARGS + (defun snoc (L agg) + (if L + (if (r L) + (snoc (r L) (c (f L) agg)) + (c (f L) agg) + ) + (c () ()) + ) + ) + + (defun prefix (L P) + (if L + (c (f L) (prefix (r L) P)) + P + ) + ) + + (if ARGS + (if (r ARGS) + (assign + (final . rest) (snoc ARGS ()) + reversed (prefix rest (list final)) + (qq (last_inner (unquote (c list reversed)))) + ) + (qq (last_inner (unquote (f ARGS)))) + ) + (x "Last takes at least one argument") + ) + ) +) diff --git a/resources/tests/chia-gaming/test-last.clsp b/resources/tests/chia-gaming/test-last.clsp new file mode 100644 index 000000000..eb2076769 --- /dev/null +++ b/resources/tests/chia-gaming/test-last.clsp @@ -0,0 +1,6 @@ +(mod () + (include *standard-cl-21*) + (include last.clinc) + + (last 99 100 101) + ) diff --git a/resources/tests/game-referee-in-cl21/all-in-list.clinc b/resources/tests/game-referee-in-cl21/all-in-list.clinc new file mode 100644 index 000000000..1db5f26ad --- /dev/null +++ b/resources/tests/game-referee-in-cl21/all-in-list.clinc @@ -0,0 +1,12 @@ +( + (defun enquote-rest (L) + (if L + (c (c 1 (f L)) (enquote-rest (r L))) + () + ) + ) + + (defun all-in-list (L) + (a (c 34 (enquote-rest L)) ()) + ) +) diff --git a/resources/tests/game-referee-in-cl21/assert.clinc b/resources/tests/game-referee-in-cl21/assert.clinc new file mode 100644 index 000000000..c9f212394 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/assert.clinc @@ -0,0 +1,8 @@ +( + (defmacro assert items + (if (r items) + (list if (f items) (c assert (r items)) (q . (x))) + (f items) + ) + ) +) diff --git a/resources/tests/game-referee-in-cl21/busy.clinc b/resources/tests/game-referee-in-cl21/busy.clinc new file mode 100644 index 000000000..e534d2125 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/busy.clinc @@ -0,0 +1,11 @@ +( + (defun busy (myfunc mylist returnval) + (if mylist + (last + (a myfunc (list (f mylist))) + (busy myfunc (r mylist) returnval) + ) + returnval + ) + ) +) diff --git a/resources/tests/game-referee-in-cl21/condition_codes.clinc b/resources/tests/game-referee-in-cl21/condition_codes.clinc new file mode 100644 index 000000000..45f3265da --- /dev/null +++ b/resources/tests/game-referee-in-cl21/condition_codes.clinc @@ -0,0 +1,41 @@ +; See chia/types/condition_opcodes.py + +( + (defconstant AGG_SIG_UNSAFE 49) + (defconstant AGG_SIG_ME 50) + + ; the conditions below reserve coin amounts and have to be accounted for in output totals + + (defconstant CREATE_COIN 51) + (defconstant RESERVE_FEE 52) + + ; the conditions below deal with announcements, for inter-coin communication + + ; coin announcements + (defconstant CREATE_COIN_ANNOUNCEMENT 60) + (defconstant ASSERT_COIN_ANNOUNCEMENT 61) + + ; puzzle announcements + (defconstant CREATE_PUZZLE_ANNOUNCEMENT 62) + (defconstant ASSERT_PUZZLE_ANNOUNCEMENT 63) + + ; the conditions below let coins inquire about themselves + + (defconstant ASSERT_MY_COIN_ID 70) + (defconstant ASSERT_MY_PARENT_ID 71) + (defconstant ASSERT_MY_PUZZLEHASH 72) + (defconstant ASSERT_MY_AMOUNT 73) + + ; the conditions below ensure that we're "far enough" in the future + + ; wall-clock time + (defconstant ASSERT_SECONDS_RELATIVE 80) + (defconstant ASSERT_SECONDS_ABSOLUTE 81) + + ; block index + (defconstant ASSERT_HEIGHT_RELATIVE 82) + (defconstant ASSERT_HEIGHT_ABSOLUTE 83) + + ; A condition that is always true and always ignore all arguments + (defconstant REMARK 1) +) diff --git a/resources/tests/game-referee-in-cl21/curry-and-treehash.clinc b/resources/tests/game-referee-in-cl21/curry-and-treehash.clinc new file mode 100644 index 000000000..6a63e9364 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/curry-and-treehash.clinc @@ -0,0 +1,92 @@ +( + ;; The code below is used to calculate of the tree hash of a curried function + ;; without actually doing the curry, and using other optimization tricks + ;; like unrolling `shatree`. + + (defconstant ONE 1) + (defconstant TWO 2) + (defconstant A_KW #a) + (defconstant Q_KW #q) + (defconstant C_KW #c) + + ;; Given the tree hash `environment-hash` of an environment tree E + ;; and the tree hash `parameter-hash` of a constant parameter P + ;; return the tree hash of the tree corresponding to + ;; `(c (q . P) E)` + ;; This is the new environment tree with the addition parameter P curried in. + ;; + ;; Note that `(c (q . P) E)` = `(c . ((q . P) . (E . 0)))` + + (defun-inline update-hash-for-parameter-hash (parameter-hash environment-hash) + (sha256 TWO (sha256 ONE C_KW) + (sha256 TWO (sha256 TWO (sha256 ONE Q_KW) parameter-hash) + (sha256 TWO environment-hash (sha256 ONE 0)))) + ) + + ;; This function recursively calls `update-hash-for-parameter-hash`, updating `environment-hash` + ;; along the way. + + (defun build-curry-list (reversed-curry-parameter-hashes environment-hash) + (if reversed-curry-parameter-hashes + (build-curry-list (r reversed-curry-parameter-hashes) + (update-hash-for-parameter-hash (f reversed-curry-parameter-hashes) environment-hash)) + environment-hash + ) + ) + + ;; Given the tree hash `environment-hash` of an environment tree E + ;; and the tree hash `function-hash` of a function tree F + ;; return the tree hash of the tree corresponding to + ;; `(a (q . F) E)` + ;; This is the hash of a new function that adopts the new environment E. + ;; This is used to build of the tree hash of a curried function. + ;; + ;; Note that `(a (q . F) E)` = `(a . ((q . F) . (E . 0)))` + + (defun-inline tree-hash-of-apply (function-hash environment-hash) + (sha256 TWO (sha256 ONE A_KW) + (sha256 TWO (sha256 TWO (sha256 ONE Q_KW) function-hash) + (sha256 TWO environment-hash (sha256 ONE 0)))) + ) + + ;; function-hash: + ;; the hash of a puzzle function, ie. a `mod` + ;; + ;; reversed-curry-parameter-hashes: + ;; a list of pre-hashed trees representing parameters to be curried into the puzzle. + ;; Note that this must be applied in REVERSED order. This may seem strange, but it greatly simplifies + ;; the underlying code, since we calculate the tree hash from the bottom nodes up, and the last + ;; parameters curried must have their hashes calculated first. + ;; + ;; we return the hash of the curried expression + ;; (a (q . function-hash) (c (cp1 (c cp2 (c ... 1)...)))) + ;; + ;; Note that from a user's perspective the hashes passed in here aren't simply + ;; the hashes of the desired parameters, but their treehash representation since + ;; that's the form we're assuming they take in the actual curried program. + + (defun puzzle-hash-of-curried-function (function-hash . reversed-curry-parameter-hashes) + (tree-hash-of-apply function-hash + (build-curry-list reversed-curry-parameter-hashes (sha256 ONE ONE))) + ) + + (defconstant b32 32) + + (defun-inline size_b32 (var) + (= (strlen var) b32) + ) + + (defun calculate_coin_id (parent puzzlehash amount) + (if (all (size_b32 parent) (size_b32 puzzlehash) (> amount -1)) + (sha256 parent puzzlehash amount) + (x) + ) + ) + + ; takes a lisp tree and returns the hash of it + (defun shatree (TREE) + (if (l TREE) + (sha256 2 (shatree (f TREE)) (shatree (r TREE))) + (sha256 1 TREE))) + +) diff --git a/resources/tests/game-referee-in-cl21/curry.clinc b/resources/tests/game-referee-in-cl21/curry.clinc new file mode 100644 index 000000000..81a1ec3a6 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/curry.clinc @@ -0,0 +1,104 @@ +( + ;; The code below is used to calculate of the tree hash of a curried function + ;; without actually doing the curry, and using other optimization tricks + ;; like unrolling `shatree`. + + (defconstant TWO 2) + (defconstant constant-tree ( + (0x4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a . ; = `(sha256 1)` + 0x9dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2) . ; = `(sha256 1 1)` = `(sha256 1 #q)` + (0x02a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222 . ; = `(concat 2 (sha256 1 #a))` + 0x02a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5) ; = `(concat 2 (sha256 1 #c))` + ) + ) + + ; I looked into calculating the values of `constant-tree` because it's pretty easy to code-golf + ; out an implementation that produces the values cheaper than just inlining them. The problem is, + ; when do we calculate them? If there were a way to calculate it "before main" and include it in + ; the globally-accessible constant table, we could do that. But we can't which means to be optimal, + ; client code should call the "build table" code once, then pass it around to anyone that wants to + ; call `curry` or `curry2`. This is pretty intrusive, so for now we'll just use the existing + ; global constant infrastructure, and include it as a fixed table so the tree of four values will + ; appear in all code that includes this file, and it will compress better in generators. + + (defun-inline sha256_one _noargs (f (f constant-tree))) + (defun-inline sha256_one_one _noargs (r (f constant-tree))) + (defun-inline two_sha256_one_a_kw _noargs (f (r constant-tree))) + (defun-inline two_sha256_one_c_kw _noargs (r (r constant-tree))) + + ;; this returns the sha256 tree hash of expression F = `((q . a1) a2)` + (defun hash-expression-F (a1 a2) + (sha256 TWO (sha256 TWO (sha256_one_one) a1) + (sha256 TWO a2 (sha256_one))) + ) + + ;; Given the tree hash `environment-hash` of an environment tree E + ;; and the tree hash `parameter-hash` of a constant parameter P + ;; return the tree hash of the tree corresponding to + ;; `(c (q . P) E)` + ;; This is the new environment tree with the addition parameter P curried in. + ;; + ;; Note that `(c (q . P) E)` = `(c . ((q . P) . (E . 0)))` + + (defun-inline update-hash-for-parameter-hash (parameter-hash environment-hash) + (sha256 (two_sha256_one_c_kw) (hash-expression-F parameter-hash environment-hash)) + ) + + ;; Given the tree hash `environment-hash` of an environment tree E + ;; and the tree hash `mod-hash` of a mod M + ;; return the tree hash of the tree corresponding to + ;; `(a (q . M) E)` + ;; This is the hash of a new function that adopts the new environment E. + ;; This is used to build of the tree hash of a curried function. + ;; + ;; Note that `(a (q . M) E)` = `(a . ((q . M) . (E . 0)))` + + (defun-inline tree-hash-of-apply (mod-hash environment-hash) + (sha256 (two_sha256_one_a_kw) (hash-expression-F mod-hash environment-hash)) + ) + + ;; This function recursively calls `update-hash-for-parameter-hash` + + (defun calculate-hash-of-curried-parameters (curry-parameter-hashes) + (if curry-parameter-hashes + (update-hash-for-parameter-hash (f curry-parameter-hashes) (calculate-hash-of-curried-parameters (r curry-parameter-hashes))) + (sha256_one_one) + ) + ) + + ;; mod-hash: + ;; the hash of a puzzle function, ie. a `mod` + ;; + ;; curry-parameter-hashes: + ;; a list of pre-hashed trees representing parameters to be curried into the puzzle. + ;; + ;; we return the hash of the curried expression + ;; (a (q . mod-hash) (c (cp1 (c cp2 (c ... 1)...)))) + ;; + ;; Note that from a user's perspective the hashes passed in here aren't simply + ;; the hashes of the desired parameters, but their treehash representation since + ;; that's the form we're assuming they take in the acutal curried program. + + ;; inline functions that take varargs don't seem to work, so we can't inline `curry` + + (defun curry_hashes (mod-hash . curry-parameter-hashes) + (tree-hash-of-apply mod-hash + (calculate-hash-of-curried-parameters curry-parameter-hashes)) + ) + + + ;; this is included for future compilers that handle it properly. If you get weird + ;; errors using this, it may be your tooling. Use `curry` above instead, or inline manually. + + (defun-inline curry_hashes_inline (mod-hash . curry-parameter-hashes) + (tree-hash-of-apply mod-hash + (calculate-hash-of-curried-parameters curry-parameter-hashes)) + ) + + ;; `curry_mod_hashes_inline` takes exactly two parameters rather than varags, and it can be inlined + + (defun-inline curry_mod_hashes_inline (mod-hash curry-parameter-hashes) + (tree-hash-of-apply mod-hash + (calculate-hash-of-curried-parameters curry-parameter-hashes)) + ) +) diff --git a/resources/tests/game-referee-in-cl21/deep_compare.clinc b/resources/tests/game-referee-in-cl21/deep_compare.clinc new file mode 100644 index 000000000..0a863ae33 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/deep_compare.clinc @@ -0,0 +1,41 @@ + +( + (defun deep_compare (a b) + (if (l a) + (if (l b) + (assign-lambda inner_result (deep_compare (f a) (f b)) + (if inner_result + inner_result + (deep_compare (r a) (r b)) + ) + ) + 1 + ) + (if (l b) + -1 + (if (> a b) + 1 + (- 0 (> b a)) + ) + ) + ) + ) + (defun deep< (a b) + (= (deep_compare a b) -1) + ) + (defun deep> (a b) + (= (deep_compare a b) 1) + ) + (defun deep= (a b) + (= (deep_compare a b) 0) + ) + (defun deep<= (a b) + (not (deep> a b)) + ) + (defun deep>= (a b) + (not (deep< a b)) + ) + (defun deep!= (a b) + (not (deep= a b)) + ) +) diff --git a/resources/tests/game-referee-in-cl21/filtermap.clinc b/resources/tests/game-referee-in-cl21/filtermap.clinc new file mode 100644 index 000000000..59c827858 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/filtermap.clinc @@ -0,0 +1,14 @@ + +( + (defun filtermap (process remaining init) + (if remaining + (assign next (a process (list (f remaining))) + (if next + (c next (filtermap process (r remaining) init)) + (filtermap process (r remaining) init) + ) + ) + init + ) + ) +) \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/flatten.clinc b/resources/tests/game-referee-in-cl21/flatten.clinc new file mode 100644 index 000000000..ab3815abd --- /dev/null +++ b/resources/tests/game-referee-in-cl21/flatten.clinc @@ -0,0 +1,12 @@ +( + (defun flatten_list (everything) + (if + (not everything) 0 + (prepend (f everything) (flatten_list (r everything))) + ) + ) + (defun flatten everything + (flatten_list everything) + ) + +) \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/handcalc.clinc b/resources/tests/game-referee-in-cl21/handcalc.clinc new file mode 100644 index 000000000..6317733f4 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/handcalc.clinc @@ -0,0 +1,140 @@ + +; ranks are 2-14 with 2 being two, 13 being king, and 14 being ace +; suits are 1-4 with no particular labelling +; takes a list of cards (rank . suit) and returns the value of the best poker +; hand which can be made with them +; returned list is hand type followed by cards in descending order +; doesn't work for ten or more cards if there are multiple flushes +; all sorting is done highest to lowest +( + (defconstant STRAIGHT_FLUSH 9) + (defconstant FOUR_OF_A_KIND 8) + (defconstant FULL_HOUSE 7) + (defconstant FLUSH 6) + (defconstant STRAIGHT 5) + (defconstant THREE_OF_A_KIND 4) + (defconstant TWO_PAIR 3) + (defconstant PAIR 2) + (defconstant HIGH_CARD 1) + (defun find_flush_inner (suits last count) + (if (not suits) + 0 + (if (= (f suits) last) + (if (= count 4) + last + (find_flush_inner (r suits) last (+ count 1)) + ) + (find_flush_inner (r suits) (f suits) 1) + ) + ) + ) + ; returns the flush suit or 0 if there isn't any + ; suits must be clustered/sorted + (defun find_flush (suits) + (find_flush_inner (sort (lambda (x y) (deep> x y)) suits) 0 0) + ) + (defun straight_high_inner (ranks started_ace last count) + (if (not ranks) + ; at the end of the list + (if (logand (= last 2) (= count 4) started_ace) + ; ace to five + 5 + ; no straight + 0 + ) + (if (= last (f ranks)) + ; skip identical cards + (straight_high_inner (r ranks) started_ace last count) + ; if the partial straight continues + (if (= (f ranks) (- last 1)) + (if (= count 4) + ; found a straight, add 3 to last because next and last are included + (+ last 3) + ; keep looking for a straight with the count going up by one + (straight_high_inner (r ranks) started_ace (f ranks) (+ count 1)) + ) + ; reset the count + (straight_high_inner (r ranks) started_ace (f ranks) 1) + ) + ) + ) + ) + ; returns the high card of a straight or 0 if there isn't any + ; ranks must be sorted in descending order + (defun straight_high (ranks) + (straight_high_inner ranks (= (f ranks) 14) 0 0) + ) + (defun group_by_count_inner (items last count) + (if (not items) + (list (c count last)) + (if (= (f items) last) + (group_by_count_inner (r items) last (+ count 1)) + (assign val (group_by_count_inner (r items) (f items) 1) + (c (c count last) val) + ) + ) + ) + ) + (defun group_by_count (items) + (group_by_count_inner items (f items) 0) + ) + (defun handcalc (cards) + (assign-lambda + first (lambda (x) (f x)) + rest (lambda (x) (r x)) + fsuit (find_flush (map rest cards)) + max_flush (if (not fsuit) + 0 + (assign-lambda + fnosuits + (sort + (lambda (x y) (deep> x y)) + (filtermap + (lambda ((& fsuit) (card_rank . card_suit)) + (if (= fsuit card_suit) + card_rank + 0 + ) + ) + cards + 0 + ) + ) + + fsh (straight_high fnosuits) + (if fsh + (list STRAIGHT_FLUSH fsh) + (c FLUSH (slice fnosuits 5)) + ) + ) + ) + nosuits (sort (lambda (x y) (deep> x y)) (map first cards)) + sh (straight_high nosuits) + max_straight (if sh + (list STRAIGHT sh) + 0 + ) + groups (sort (lambda (x y) (deep> x y)) (group_by_count nosuits)) + (top_count . top_card) (f groups) + (second_count . second_card) (f (r groups)) + topcards (map rest groups) + max_group (if (= top_count 1) + (c HIGH_CARD (slice topcards 5)) + (if (= top_count 2) + (if (= second_count 1) + (c PAIR (slice topcards 4)) + (c TWO_PAIR (slice topcards 3)) + ) + (if (= top_count 3) + (if (= second_count 1) + (c THREE_OF_A_KIND (slice topcards 3)) + (c FULL_HOUSE (slice topcards 2)) + ) + (c FOUR_OF_A_KIND (slice topcards 2)) + ) + ) + ) + (max (lambda (x y) (deep< x y)) (list max_flush max_straight max_group)) + ) + ) +) diff --git a/resources/tests/game-referee-in-cl21/handcalc_a.clinc b/resources/tests/game-referee-in-cl21/handcalc_a.clinc new file mode 100644 index 000000000..06c326392 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/handcalc_a.clinc @@ -0,0 +1,256 @@ + +; ranks are 2-14 with 2 being two, 13 being king, and 14 being ace +; suits are 1-4 with no particular labelling +; takes a list of cards (rank . suit) and returns the value of the best poker +; hand which can be made with them +; returned list is hand type followed by cards in descending order +; doesn't work for ten or more cards if there are multiple flushes +; all sorting is done highest to lowest +( + (defconstant STRAIGHT_FLUSH 9) + (defconstant FOUR_OF_A_KIND 8) + (defconstant FULL_HOUSE 7) + (defconstant FLUSH 6) + (defconstant STRAIGHT 5) + (defconstant THREE_OF_A_KIND 4) + (defconstant TWO_PAIR 3) + (defconstant PAIR 2) + (defconstant HIGH_CARD 1) + (defun hand_compare (a b) + (if (= (f a) (f b)) + (if (r a) + (hand_compare (r a) (r b)) + 0 + ) + (- (* 2 (> (f a) (f b))) 1) + ) + ) + (defun hand< (a b) + (= (hand_compare a b) -1) + ) + (defun merge (a b) + (if (not a) + b + (if (not b) + a + (if (> (f a) (f b)) + (c (f a) (merge (r a) b)) + (c (f b) (merge a (r b))) + ) + ) + ) + ) + ; Sorts atoms into descending order + ; This is optimized for sorting short lists + ; A more general function would return a list of lists of ascending sizes + ; to be merged + (defun atomsort ((@ firstpos (first @ secondpos (second @ thirdpos (third . remaining))))) + (if firstpos + (if secondpos + (if thirdpos + (assign-lambda + mylist + (if (> first second) + (if (> second third) + (list first second third) + (if (> first third) + (list first third second) + (list third first second) + ) + ) + (if (> first third) + (list second first third) + (if (> second third) + (list second third first) + (list third second first) + ) + ) + ) + (merge mylist (atomsort remaining)) + ) + (if (> first second) + firstpos + (list second first) + ) + ) + firstpos + ) + 0 + ) + ) + (defun count_suits_2 ((@ suits (firstsuit . remaining))) + (if (not suits) + (c (c 0 0) (c 0 0)) + (assign-lambda ((@ cd (clubs . diamonds)) . (@ hs (hearts . spades))) (count_suits remaining) + (if (= firstsuit 1) + (c (c (+ clubs 1) diamonds) hs) + (if (= firstsuit 2) + (c (c clubs (+ diamonds 1)) hs) + (if (= firstsuit 3) + (c cd (c (+ hearts 1) spades)) + (c cd (c hearts (+ spades 1))) + ) + ) + ) + ) + ) + ) + (defun find_flush_2 (suits) + (assign-lambda ((clubs . diamonds) . (hearts . spades)) (count_suits suits) + (if (> clubs 4) + 1 + (if (> diamonds 4) + 2 + (if (> hearts 4) + 3 + (if (> spades 4) + 4 + 0 + ) + ) + ) + ) + ) + ) + (defun count_suits (suits) + (if suits + (+ (count_suits (r suits)) (ash 1 (* 4 (- (f suits) 1)))) + 0 + ) + ) + (defun find_flush (suits) + (assign-lambda + myvals (count_suits suits) + (if (> (logand myvals 0xF000) 0x4000) + 4 + (if (> (logand myvals 0x0F00) 0x0400) + 3 + (if (> (logand myvals 0x00F0) 0x0040) + 2 + (if (> (logand myvals 0x0F) 0x04) + 1 + 0 + ) + ) + ) + ) + ) + ) + (defun straight_high_inner (ranks last count) + (if (not ranks) + (if (logand (= last 2) (= count 4)) + ; maybe ace to five + 5 + 0 + ) + (if (= last (f ranks)) + ; skip identical cards + (straight_high_inner (r ranks) last count) + ; if the partial straight continues + (if (= (f ranks) (- last 1)) + (if (= count 4) + ; found a straight, add 3 to last because next and last are included + (+ last 3) + ; keep looking for a straight with the count going up by one + (straight_high_inner (r ranks) (f ranks) (+ count 1)) + ) + ; reset the count + (straight_high_inner (r ranks) (f ranks) 1) + ) + ) + ) + ) + ; returns the high card of a straight or 0 if there isn't any + ; ranks must be sorted in descending order + (defun straight_high (ranks) + (assign-lambda high (straight_high_inner ranks 0 0) + (if (= high 5) + (* (= (f ranks) 14) 5) + high + ) + ) + ) + (defun group_by_count_inner (items last count) + (if (not items) + (list (logior (lsh count 4) last)) + (if (= (f items) last) + (group_by_count_inner (r items) last (+ count 1)) + (assign-inline val (group_by_count_inner (r items) (f items) 1) + (c (logior (lsh count 4) last) val) + ) + ) + ) + ) + (defun group_by_count (items) + (group_by_count_inner items (f items) 0) + ) + (defun handcalc (cards) + (assign-lambda + first (lambda (x) (f x)) + rest (lambda (x) (r x)) + fsuit (find_flush (map rest cards)) + max_flush (if (not fsuit) + (list 0) + (assign-lambda + flushcards + (filtermap + (lambda ((& fsuit) (card_rank . card_suit)) + (if (= fsuit card_suit) + card_rank + 0 + ) + ) + cards + 0 + ) + flushranks (atomsort flushcards) + fsh (straight_high flushranks) + (if fsh + (list STRAIGHT_FLUSH fsh) + (c FLUSH (slice flushranks 5)) + ) + ) + ) + ranks (atomsort (map first cards)) + sh (straight_high ranks) + max_straight (if sh + (list STRAIGHT sh) + (list 0) + ) + groups (map + (lambda (myval) (c (lsh myval -4) (logand myval 0x0F))) + (atomsort (group_by_count ranks)) + ) + (top_count . top_card) (f groups) + (second_count . second_card) (f (r groups)) + topcards (map rest groups) + max_group (if (= top_count 1) + (c HIGH_CARD (slice topcards 5)) + (if (= top_count 2) + (if (= second_count 1) + (c PAIR (slice topcards 4)) + (c TWO_PAIR (slice topcards 3)) + ) + (if (= top_count 3) + (if (= second_count 1) + (c THREE_OF_A_KIND (slice topcards 3)) + (c FULL_HOUSE (slice topcards 2)) + ) + (c FOUR_OF_A_KIND (slice topcards 2)) + ) + ) + ) + ; max of max_flush max_straight and max_group + (if (> (f max_flush) (f max_straight)) + (if (> (f max_flush) (f max_group)) + max_flush + max_group + ) + (if (> (f max_straight) (f max_group)) + max_straight + max_group + ) + ) + ) + ) +) diff --git a/resources/tests/game-referee-in-cl21/last.clinc b/resources/tests/game-referee-in-cl21/last.clinc new file mode 100644 index 000000000..5a6ffd73e --- /dev/null +++ b/resources/tests/game-referee-in-cl21/last.clinc @@ -0,0 +1,39 @@ +( + (defun last_inner ((next . remainder)) + (if remainder + (last_inner remainder) + next + ) + ) + + (defmacro last ARGS + (defun snoc (L agg) + (if L + (if (r L) + (snoc (r L) (c (f L) agg)) + (c (f L) agg) + ) + (c () ()) + ) + ) + + (defun prefix (L P) + (if L + (c (f L) (prefix (r L) P)) + P + ) + ) + + (if ARGS + (if (r ARGS) + (assign + (final . rest) (snoc ARGS ()) + reversed (prefix rest (list final)) + (qq (last_inner (unquote (c list reversed)))) + ) + (qq (last_inner (unquote (f ARGS)))) + ) + (x "Last takes at least one argument") + ) + ) +) diff --git a/resources/tests/game-referee-in-cl21/len.clinc b/resources/tests/game-referee-in-cl21/len.clinc new file mode 100644 index 000000000..407c36694 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/len.clinc @@ -0,0 +1,3 @@ +( + (defun len (L) (if L (+ 1 (len (r L))) 0)) +) diff --git a/resources/tests/game-referee-in-cl21/map.clinc b/resources/tests/game-referee-in-cl21/map.clinc new file mode 100644 index 000000000..016c3a0e4 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/map.clinc @@ -0,0 +1,17 @@ +( + (defun map-with-rest (F L R) + (if L + (c (a F (list (f L))) (map-with-rest F (r L) R)) + R + ) + ) + + (defmacro map ARGS + (defun list-len (X) (if X (+ 1 (list-len (r X))) 0)) + + (if (= (list-len ARGS) 3) + (qq (map-with-rest (unquote (f ARGS)) (unquote (f (r ARGS))) (unquote (f (r (r ARGS)))))) + (qq (map-with-rest (unquote (f ARGS)) (unquote (f (r ARGS))) ())) + ) + ) +) diff --git a/resources/tests/game-referee-in-cl21/match.clinc b/resources/tests/game-referee-in-cl21/match.clinc new file mode 100644 index 000000000..d66593c55 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/match.clinc @@ -0,0 +1,12 @@ + +( + (defun match (process remaining) + (if remaining + (if (a process (list (f remaining))) + (f remaining) + (match process (r remaining)) + ) + 0 + ) + ) +) diff --git a/resources/tests/game-referee-in-cl21/max.clinc b/resources/tests/game-referee-in-cl21/max.clinc new file mode 100644 index 000000000..5ec6d54f6 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/max.clinc @@ -0,0 +1,13 @@ +( + (defun max_inner (myless best_so_far mylist) + (if (not mylist) best_so_far + (if (a myless (list best_so_far (f mylist))) + (max_inner myless (f mylist) (r mylist)) + (max_inner myless best_so_far (r mylist)) + ) + ) + ) + (defun max (myless mylist) + (max_inner myless (f mylist) (r mylist)) + ) +) diff --git a/resources/tests/game-referee-in-cl21/permutations.clinc b/resources/tests/game-referee-in-cl21/permutations.clinc new file mode 100644 index 000000000..9664c6aff --- /dev/null +++ b/resources/tests/game-referee-in-cl21/permutations.clinc @@ -0,0 +1,21 @@ +( + (defun permutations_inner (pre post agg) + (if (not post) + agg + (assign + myatom (f post) + newrest (r post) + (map (lambda ((& myatom) x) (c myatom x)) + (permutations (prepend pre newrest)) + (permutations_inner (c myatom pre) newrest agg) + ) + ) + ) + ) + (defun permutations (vals) + (if vals + (permutations_inner 0 vals 0) + (q ()) + ) + ) +) diff --git a/resources/tests/game-referee-in-cl21/prefix.clinc b/resources/tests/game-referee-in-cl21/prefix.clinc new file mode 100644 index 000000000..641723dad --- /dev/null +++ b/resources/tests/game-referee-in-cl21/prefix.clinc @@ -0,0 +1,16 @@ +( + (defmacro prefix ARGS + (defun compile-list (args) + (if args + (if (r args) + ;; We have at least 2 things left... recurse once. + (qq (c (unquote (f args)) (unquote (compile-list (r args))))) + ;; This is the last item, so we return it whole (improper list form). + (qq (unquote (f args))) + ) + 0 + ) + ) + (compile-list ARGS) + ) +) \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/prepend.clinc b/resources/tests/game-referee-in-cl21/prepend.clinc new file mode 100644 index 000000000..2ea293409 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/prepend.clinc @@ -0,0 +1,8 @@ +( + (defun prepend (a b) + (if a + (c (f a) (prepend (r a) b)) + b + ) + ) +) \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/print.clinc b/resources/tests/game-referee-in-cl21/print.clinc new file mode 100644 index 000000000..95d459b36 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/print.clinc @@ -0,0 +1,3 @@ +( + (defun print (R P) (if (all "$print$" R P) P P)) +) diff --git a/resources/tests/game-referee-in-cl21/range.clinc b/resources/tests/game-referee-in-cl21/range.clinc new file mode 100644 index 000000000..dc1e61ca3 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/range.clinc @@ -0,0 +1,11 @@ +( + (defun range_inner (next final) + (if (= next final) + 0 + (c next (range_inner (+ next 1) final)) + ) + ) + (defun range (i) + (range_inner 0 i) + ) +) \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/reduce.clinc b/resources/tests/game-referee-in-cl21/reduce.clinc new file mode 100644 index 000000000..3251c79a7 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/reduce.clinc @@ -0,0 +1,10 @@ + +( + ; From here to the meat should be in a standard library + (defun reduce (fun lst init) + (if lst + (reduce fun (r lst) (a fun (list (f lst) init))) + init + ) + ) +) diff --git a/resources/tests/game-referee-in-cl21/reverse.clinc b/resources/tests/game-referee-in-cl21/reverse.clinc new file mode 100644 index 000000000..389963ee9 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/reverse.clinc @@ -0,0 +1,11 @@ +( + (defun reverse_inner (reversed rest) + (if rest + (reverse_inner (c (f rest) reversed) (r rest)) + reversed + ) + ) + (defun reverse (vals) + (reverse_inner 0 vals) + ) +) diff --git a/resources/tests/game-referee-in-cl21/shatree.clinc b/resources/tests/game-referee-in-cl21/shatree.clinc new file mode 100644 index 000000000..05bdb2699 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/shatree.clinc @@ -0,0 +1,11 @@ +( + ;; hash a tree + ;; This is used to calculate a puzzle hash given a puzzle program. + (defun shatree + (TREE) + (if (l TREE) + (sha256 2 (shatree (f TREE)) (shatree (r TREE))) + (sha256 1 TREE) + ) + ) +) \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/slice.clinc b/resources/tests/game-referee-in-cl21/slice.clinc new file mode 100644 index 000000000..2c98a09c5 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/slice.clinc @@ -0,0 +1,10 @@ + +( + ; returns the first count elements of mylist + (defun slice (mylist count) + (if (print (list "slice inputs" nylist count) (not count)) + 0 + (c (f mylist) (slice (r mylist) (- count 1))) + ) + ) +) diff --git a/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clsp b/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clsp new file mode 100644 index 000000000..8df629518 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clsp @@ -0,0 +1,28 @@ +(mod () + (include *standard-cl-21*) + (include print.clinc) + (include prepend.clinc) + (include sort.clinc) + (include assert.clinc) + (include map.clinc) + (include deep_compare.clinc) + + (map + (lambda ((want_cmp_val cmp_a cmp_b)) + (= (deep_compare cmp_a cmp_b) want_cmp_val) + ) + (q + (0 0 0) + (-1 () (1 14 5 4 3 2)) + (1 (1 14 5 4 3 2) ()) + (-1 "X" (1 2)) + (1 (1 2) "X") + (0 (3 2) (3 2)) + (-1 (3 1) (3 3)) + (1 (3 3) (3 1)) + (-1 (1 1) (2 1)) + (1 (3 1) (2 2)) + (-1 (2 2) (3 1)) + ) + ) + ) diff --git a/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clvm.hex.reference b/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clvm.hex.reference new file mode 100644 index 000000000..cb3eb0bf7 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clvm.hex.reference @@ -0,0 +1 @@ +ff02ffff01ff02ff08ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff0e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff01ffff80ff80ff8080ffff81ffff80ffff01ff0eff05ff04ff03ff028080ffff01ffff01ff0eff05ff04ff03ff0280ff8080ffff81ffff58ffff01ff028080ffff01ffff01ff0280ff5880ffff80ffff03ff0280ffff03ff028080ffff81ffffff03ff0180ffff03ff038080ffff01ffff03ff0380ffff03ff018080ffff81ffffff01ff0180ffff02ff018080ffff01ffff03ff0180ffff02ff028080ffff81ffffff02ff0280ffff03ff01808080ffff04ffff0180ff808080808080ffff04ffff01ffffff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff08ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff0affff04ff02ffff04ffff06ff0180ffff04ffff02ff0cffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff0cffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ff09ffff02ff0cffff04ff02ffff04ff2bffff04ff5bff8080808080ff1380ff018080 diff --git a/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.sym b/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.sym new file mode 100644 index 000000000..3d2e104b3 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.sym @@ -0,0 +1 @@ +{"026e28eecfeb07594300bd6c3bce34bd4fe340a189ddd5312c7361e242b52160_arguments": "(() (want_cmp_val cmp_a cmp_b))", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clsp", "__chia__main_arguments": "()", "4fd7e0dfbd7ac5775e6d61670f548dc35ff62a1a4b14f2f3efe09d8b39e6988b_left_env": "1", "a08c534dd3a89e22a8fadaa027c6b9a8dd4f9a00b72c315821703d8ee1c8f687": "deep_compare", "026e28eecfeb07594300bd6c3bce34bd4fe340a189ddd5312c7361e242b52160_left_env": "1", "a08c534dd3a89e22a8fadaa027c6b9a8dd4f9a00b72c315821703d8ee1c8f687_arguments": "(a b)", "d9f6d93919b2fb79bc296ac80d73b5c48bf044e457f0f678b210f990efeea743": "letbinding_$_58", "d9f6d93919b2fb79bc296ac80d73b5c48bf044e457f0f678b210f990efeea743_left_env": "1", "a08c534dd3a89e22a8fadaa027c6b9a8dd4f9a00b72c315821703d8ee1c8f687_left_env": "1", "4fd7e0dfbd7ac5775e6d61670f548dc35ff62a1a4b14f2f3efe09d8b39e6988b": "map-with-rest", "4fd7e0dfbd7ac5775e6d61670f548dc35ff62a1a4b14f2f3efe09d8b39e6988b_arguments": "(F L R)", "d9f6d93919b2fb79bc296ac80d73b5c48bf044e457f0f678b210f990efeea743_arguments": "((a_$_43 b_$_44) inner_result)", "026e28eecfeb07594300bd6c3bce34bd4fe340a189ddd5312c7361e242b52160": "lambda_$_57"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/smoke_test_permutations.clsp b/resources/tests/game-referee-in-cl21/smoke_test_permutations.clsp new file mode 100644 index 000000000..2ed3fbbcc --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_permutations.clsp @@ -0,0 +1,9 @@ +(mod (X) + (include *standard-cl-21*) + (include map.clinc) + (include prepend.clinc) + (include print.clinc) + (include permutations.clinc) + + (permutations X) + ) diff --git a/resources/tests/game-referee-in-cl21/smoke_test_permutations.clvm.hex.reference b/resources/tests/game-referee-in-cl21/smoke_test_permutations.clvm.hex.reference new file mode 100644 index 000000000..ad4e2fba6 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_permutations.clvm.hex.reference @@ -0,0 +1 @@ +ff02ffff01ff02ff1effff04ff02ffff04ff05ff80808080ffff04ffff01ffffff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff08ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff14ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ffff20ff0b80ffff01ff02ffff0117ff0180ffff01ff02ffff01ff02ff0affff04ff02ffff04ffff06ff0180ffff04ffff05ff0b80ffff04ffff06ff0b80ff808080808080ff018080ff0180ffff02ff08ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff1680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff0bff808080ffff01ff01808080ff80808080ffff04ffff02ff1effff04ff02ffff04ffff02ff14ffff04ff02ffff04ff09ffff04ff17ff8080808080ff80808080ffff04ffff02ff1cffff04ff02ffff04ffff04ff0bff0980ffff04ff17ffff04ff2dff808080808080ff808080808080ffff04ff09ff0b80ff02ffff03ff05ffff01ff02ffff01ff02ff1cffff04ff02ffff04ffff0180ffff04ff05ffff04ffff0180ff808080808080ff0180ffff01ff02ffff01ff01ff8080ff018080ff0180ff018080 diff --git a/resources/tests/game-referee-in-cl21/smoke_test_permutations.sym b/resources/tests/game-referee-in-cl21/smoke_test_permutations.sym new file mode 100644 index 000000000..c53c294de --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_permutations.sym @@ -0,0 +1 @@ +{"0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_arguments": "((myatom) x)", "4fd7e0dfbd7ac5775e6d61670f548dc35ff62a1a4b14f2f3efe09d8b39e6988b": "map-with-rest", "cbc879391ee3747e5a0a6457916b75a38118f0febf74e14983e66c8105ffb9c8": "permutations_inner", "f6344fd0045418e460a57d88fc880464d12fcafb3b3c3adbc52e0e39672bf0c8": "letbinding_$_387", "e209270f1dc5e9d4b9d3c077d401c47f47bb866e87d1707551d101b8717f4edf_arguments": "(vals)", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-in-cl21/smoke_test_permutations.clsp", "cbc879391ee3747e5a0a6457916b75a38118f0febf74e14983e66c8105ffb9c8_arguments": "(pre post agg)", "048d5413ce5265ab36813735bc75ba7b7c5e9454553198bfdafef009677e420b_arguments": "(a b)", "e209270f1dc5e9d4b9d3c077d401c47f47bb866e87d1707551d101b8717f4edf_left_env": "1", "4fd7e0dfbd7ac5775e6d61670f548dc35ff62a1a4b14f2f3efe09d8b39e6988b_arguments": "(F L R)", "4fd7e0dfbd7ac5775e6d61670f548dc35ff62a1a4b14f2f3efe09d8b39e6988b_left_env": "1", "048d5413ce5265ab36813735bc75ba7b7c5e9454553198bfdafef009677e420b": "prepend", "cbc879391ee3747e5a0a6457916b75a38118f0febf74e14983e66c8105ffb9c8_left_env": "1", "__chia__main_arguments": "(X)", "e209270f1dc5e9d4b9d3c077d401c47f47bb866e87d1707551d101b8717f4edf": "permutations", "f6344fd0045418e460a57d88fc880464d12fcafb3b3c3adbc52e0e39672bf0c8_left_env": "1", "f6344fd0045418e460a57d88fc880464d12fcafb3b3c3adbc52e0e39672bf0c8_arguments": "((pre_$_383 post_$_384 agg_$_385) myatom newrest)", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708": "lambda_$_388", "048d5413ce5265ab36813735bc75ba7b7c5e9454553198bfdafef009677e420b_left_env": "1", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_left_env": "1"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/smoke_test_sort.clsp b/resources/tests/game-referee-in-cl21/smoke_test_sort.clsp new file mode 100644 index 000000000..59b8a886e --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_sort.clsp @@ -0,0 +1,11 @@ +(mod (X) + (include *standard-cl-21*) + (include prepend.clinc) + (include sort.clinc) + (include assert.clinc) + (include map.clinc) + (include reverse.clinc) + (include print.clinc) + + (sort (lambda (a b) (> b a)) X) + ) diff --git a/resources/tests/game-referee-in-cl21/smoke_test_sort.clvm.hex.reference b/resources/tests/game-referee-in-cl21/smoke_test_sort.clvm.hex.reference new file mode 100644 index 000000000..476b5f74e --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_sort.clvm.hex.reference @@ -0,0 +1 @@ +ff02ffff01ff02ff12ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff3e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff05ff8080808080ffff04ffff01ffffffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff10ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ff05ffff01ff02ffff01ff02ff18ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ffff02ff18ffff04ff02ffff04ff05ffff01ff80ff8080808080ffff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff10ffff04ff02ffff04ffff02ff2effff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff10ffff04ff02ffff04ffff02ff2effff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff2cffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff2cffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff02ff2cffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ffffff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff2affff04ff02ffff04ffff06ff0180ffff04ffff02ff14ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ffff02ff3affff04ff02ffff04ff03ffff04ffff02ff12ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff12ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ff02ff3cffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ffff02ffff03ff0bffff01ff02ffff01ff02ff16ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ffff02ff16ffff04ff02ffff04ff80ffff04ff05ff8080808080ff15ff17ff0b80ff018080 diff --git a/resources/tests/game-referee-in-cl21/smoke_test_sort.sym b/resources/tests/game-referee-in-cl21/smoke_test_sort.sym new file mode 100644 index 000000000..2a0f8ed38 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_sort.sym @@ -0,0 +1 @@ +{"aa2a43f5d1d2ed44bd135ee807b27cb33eea736d2e50b2787c5fd4100f128f47": "letbinding_$_108", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-in-cl21/smoke_test_sort.clsp", "842642e018168c91bd70ba0be54c311ce3947fe0ce5e418f6a1c88289e11c84b_left_env": "1", "fa9304ef33f250463c38ac3368ad79c5416173e5a666c6571e9b4c5d8b983da1_left_env": "1", "6336806e19a49e9e91a62932f741d94eeca9a3656f35ecf39bc22e15d9940d53_arguments": "(mylist)", "f51796fc523809b04629ca42cffbb3514471eade8cd7d6908f3015f535a97de4": "letbinding_$_107", "842642e018168c91bd70ba0be54c311ce3947fe0ce5e418f6a1c88289e11c84b": "lambda_$_106", "842642e018168c91bd70ba0be54c311ce3947fe0ce5e418f6a1c88289e11c84b_arguments": "(() a b)", "a3ddf8cdd53afc8bcdd3082f709b5f66156f31f8a56e603da27b4e382a68b9f3": "sort", "aa2a43f5d1d2ed44bd135ee807b27cb33eea736d2e50b2787c5fd4100f128f47_left_env": "1", "b8edc250e5666a96397652bb34bdc9979fcd8df7f5aec90e481b7ae4234525aa": "merge", "9d8df0b4587c62404485833b9a811fe717b4f9eb3ff4a11a7806e7fd07a1c5f8": "prepend", "9d8df0b4587c62404485833b9a811fe717b4f9eb3ff4a11a7806e7fd07a1c5f8_arguments": "(a b)", "95e75b36710d3038b1cfe847cc61158c78d91e4d6db6757217c8b32ac4ae13b3_arguments": "(@ everything (rest aggl aggr))", "a3ddf8cdd53afc8bcdd3082f709b5f66156f31f8a56e603da27b4e382a68b9f3_arguments": "(myless mylist)", "9d8df0b4587c62404485833b9a811fe717b4f9eb3ff4a11a7806e7fd07a1c5f8_left_env": "1", "1b7d3888612a5d795887e5e192e68b15536e0e4c08e19324569a576ff06c6299_left_env": "1", "a3ddf8cdd53afc8bcdd3082f709b5f66156f31f8a56e603da27b4e382a68b9f3_left_env": "1", "107eecc0e2d1b059c660f3c81d6e61dd2fc7f71d4f446067132a09d395202140_left_env": "1", "95e75b36710d3038b1cfe847cc61158c78d91e4d6db6757217c8b32ac4ae13b3": "split_inner", "b8edc250e5666a96397652bb34bdc9979fcd8df7f5aec90e481b7ae4234525aa_left_env": "1", "f51796fc523809b04629ca42cffbb3514471eade8cd7d6908f3015f535a97de4_arguments": "((myless_$_91 mylist_$_92) (a b))", "b8edc250e5666a96397652bb34bdc9979fcd8df7f5aec90e481b7ae4234525aa_arguments": "(myless a b)", "107eecc0e2d1b059c660f3c81d6e61dd2fc7f71d4f446067132a09d395202140_arguments": "(vals)", "95e75b36710d3038b1cfe847cc61158c78d91e4d6db6757217c8b32ac4ae13b3_left_env": "1", "f51796fc523809b04629ca42cffbb3514471eade8cd7d6908f3015f535a97de4_left_env": "1", "__chia__main_arguments": "(X)", "107eecc0e2d1b059c660f3c81d6e61dd2fc7f71d4f446067132a09d395202140": "reverse", "6336806e19a49e9e91a62932f741d94eeca9a3656f35ecf39bc22e15d9940d53": "split", "1b7d3888612a5d795887e5e192e68b15536e0e4c08e19324569a576ff06c6299": "reverse_inner", "fa9304ef33f250463c38ac3368ad79c5416173e5a666c6571e9b4c5d8b983da1": "merge_inner", "1b7d3888612a5d795887e5e192e68b15536e0e4c08e19324569a576ff06c6299_arguments": "(reversed rest)", "6336806e19a49e9e91a62932f741d94eeca9a3656f35ecf39bc22e15d9940d53_left_env": "1", "aa2a43f5d1d2ed44bd135ee807b27cb33eea736d2e50b2787c5fd4100f128f47_arguments": "(((myless_$_91 mylist_$_92) (a b)) sa sb)", "fa9304ef33f250463c38ac3368ad79c5416173e5a666c6571e9b4c5d8b983da1_arguments": "(myless A B agg)"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/sort.clinc b/resources/tests/game-referee-in-cl21/sort.clinc new file mode 100644 index 000000000..a9afed46a --- /dev/null +++ b/resources/tests/game-referee-in-cl21/sort.clinc @@ -0,0 +1,44 @@ + +( + (defun split_inner (@ everything (rest aggl aggr)) + (if rest + (split_inner (r rest) aggr (c (f rest) aggl)) + (r everything) + ) + ) + (defun split (mylist) + (split_inner mylist 0 0) + ) + (defun merge_inner (myless A B agg) + ; this should use continued if + (if (not A) + (prepend (reverse agg) B) + (if (not B) + (prepend (reverse agg) A) + (if (a myless (list (f A) (f B))) + (merge_inner myless (r A) B (c (f A) agg)) + (merge_inner myless A (r B) (c (f B) agg)) + ) + ) + ) + ) + (defun merge (myless a b) + (merge_inner myless a b 0) + ) + (defun sort-split (myless (a b)) + (merge myless (sort myless a) (sort myless b)) + ) + (defun sort (myless mylist) + (if mylist + (if (r mylist) + (assign (a b) (split mylist) + sa (sort myless a) + sb (sort myless b) + (merge myless sa sb) + ) + mylist + ) + () + ) + ) +) diff --git a/resources/tests/game-referee-in-cl21/spacehandcalc.clinc b/resources/tests/game-referee-in-cl21/spacehandcalc.clinc new file mode 100644 index 000000000..3bfae65ca --- /dev/null +++ b/resources/tests/game-referee-in-cl21/spacehandcalc.clinc @@ -0,0 +1,104 @@ + +; ranks are 1-13 with 1 being two, 12 being king, and 13 being ace +; there are no suits, flushes, or ace-to-four straights +; takes a list of card ranks and returns the value of the best poker +; hand which can be made with them +; returned list is hand type followed by cards in descending order +; all sorting is done highest to lowest +( + (include *standard-cl-22*) + (include sort.clinc) + (include deep_compare.clinc) + (include filtermap.clinc) + (include slice.clinc) + (include max.clinc) + (defconstant FIVE_OF_A_KIND 10) + (defconstant STRAIGHT_FLUSH 9) + (defconstant FOUR_OF_A_KIND 8) + (defconstant FULL_HOUSE 7) + (defconstant FLUSH 6) + (defconstant STRAIGHT 5) + (defconstant THREE_OF_A_KIND 4) + (defconstant TWO_PAIR 3) + (defconstant PAIR 2) + (defconstant HIGH_CARD 1) + (defun straight_high_inner (ranks last count) + (if (not ranks) + ; at the end of the list + 0 + (if (= last (f ranks)) + ; skip identical cards + (straight_high_inner (r ranks) started_ace last count) + ; if the partial straight continues + (if (= (f ranks) (- last 1)) + (if (= count 4) + ; found a straight, add 3 to last because next and last are included + (+ last 3) + ; keep looking for a straight with the count going up by one + (straight_high_inner (r ranks) started_ace (f ranks) (+ count 1)) + ) + ; reset the count + (straight_high_inner (r ranks) started_ace (f ranks) 1) + ) + ) + ) + ) + ; returns the high card of a straight or 0 if there isn't any + ; ranks must be sorted in descending order + (defun straight_high (ranks) + (straight_high_inner (ranks (= (f ranks) 13) 0 0)) + ) + (defun group_by_count_inner (items last count) + (if (not items) + 0 + (if (= (f items) last) + (group_by_count_inner (r items) last (+ count 1)) + (assign val (group_by_count_inner (r items) (f items) 1) + (if last + (c (c count last) val) + val + ) + ) + ) + ) + ) + (defun group_by_count (items) + (group_by_count_inner items 0 0) + ) + (defun space_hand_calc (cards) + (assign + rest (lambda (x) (r x)) + greater (lambda (x y) (> x y)) + ranks (sort greater cards) + sh (straight_high ranks) + max_straight (if sh + (list STRAIGHT sh) + 0 + ) + groups (sort deep> (group_by_count ranks)) + (top_count . top_card) (f groups) + (second_count . second_card) (f (r groups)) + topcards (map rest groups) + max_group (if (= top_count 1) + (c HIGH_CARD (slice topcards 5)) + (if (= top_count 2) + (if (= second_count 1) + (c PAIR (slice topcards 4)) + (c TWO_PAIR (slice topcards 3)) + ) + (if (= top_count 3) + (if (= second_count 1) + (c THREE_OF_A_KIND (slice topcards 3)) + (c FULL_HOUSE (slice topcards 2)) + ) + (if (= top_count 4) + (c FOUR_OF_A_KIND (slice topcards 2)) + (c FIVE_OF_A_KIND (slice topcards 1)) + ) + ) + ) + ) + (max deep< (list max_straight max_group)) + ) + ) +) diff --git a/resources/tests/game-referee-in-cl21/test_handcalc.clsp b/resources/tests/game-referee-in-cl21/test_handcalc.clsp new file mode 100644 index 000000000..16c46f664 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_handcalc.clsp @@ -0,0 +1,379 @@ + +(mod () + (include *standard-cl-21*) + (include deep_compare.clinc) + (include assert.clinc) + (include reverse.clinc) + (include prepend.clinc) + (include map.clinc) + (include filtermap.clinc) + (include slice.clinc) + (include print.clinc) + (include sort.clinc) + (include max.clinc) + (include handcalc.clinc) + + (defun runtests_inner ((myfunc firstarg secondarg . remaining)) + (assign-lambda + firstval (handcalc firstarg) + secondval (handcalc secondarg) + (assert + (a myfunc (list firstval secondval)) + (deep= firstval (handcalc (reverse firstarg))) + (deep= secondval (handcalc (reverse secondarg))) + (if remaining + (runtests_inner remaining) + 0 + ) + ) + ) + ) + + (defun runtests tests (if tests (runtests_inner tests) ())) + + ;; Join these up when large application bug is fixed. + (runtests + ; all beats both emerge over and measure higher + ; straight flush with higher kicker ties + ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 81 + deep= + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 8 1)) + ; straight flushes of different suits tie + ; A1 K1 Q1 J1 T1 = A2 K2 Q2 J2 T2 + deep= + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) + (list (c 14 2) (c 13 2) (c 12 2) (c 11 2) (c 10 2)) + ; higher straight flush beats lower straight flush + ; A1 K1 Q1 J1 T1 > 61 51 41 31 21 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 + deep= + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) + (list (c 14 2) (c 11 2) (c 10 2) (c 13 2) (c 12 2)) + ; lower (2-6) straight flush beats ace to four straight flush + ; 61 51 41 31 21 > A2 52 42 32 22 + deep> + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) + ; A1 61 51 41 31 21 = 61 51 41 31 21 + deep= + (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; ace to four straight flush with higher kicker ties + ; A2 52 42 32 22 61 = A1 51 41 31 21 71 + deep= + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2) (c 6 1)) + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1) (c 7 1)) + ; ace to four straight flushes of different suits tie + ; A1 51 41 31 21 = A2 52 42 32 22 + deep= + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) + ; ace to four straight flush beats four of a kind + ; A1 51 41 31 21 > K1 K2 K3 K4 J1 + deep> + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) + ; A1 A2 A3 A4 51 41 31 21 = A1 51 41 31 21 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; four of a kind with higher kicker wins + ; K1 K2 K3 K4 Q1 > K1 K2 K3 K4 J1 + deep> + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) + ; K1 K2 K3 K4 T1 91 = K1 K2 K3 K4 T1 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1) (c 9 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1)) + ; four of a kind with higher second kicker ties + ; K1 K2 K3 K4 Q1 J1 = K1 K2 K3 K4 Q1 T1 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 11 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 10 1)) + ; higher four of a kind beats lower four of a kind + ; K1 K2 K3 K4 21 > 31 32 33 34 A1 + deep> + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 2 1)) + (list (c 3 1) (c 3 2) (c 3 3) (c 3 4) (c 14 1)) + ; K1 K2 K3 K4 31 32 33 34 = K1 K2 K3 K4 32 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 1) (c 3 2) (c 3 3) (c 3 4)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 2)) + ; four of a kind beats full house + ; 21 22 23 24 31 > A1 A2 A3 K1 K2 + deep> + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 3 1)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; 21 22 23 24 A1 A2 A3 = 21 22 23 24 A2 + deep= + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 1) (c 14 2) (c 14 3)) + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 2)) + ; full house with higher set wins + ; 51 52 53 21 22 > 31 32 33 71 72 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 2 1) (c 2 2)) + (list (c 3 1) (c 3 2) (c 3 3) (c 7 1) (c 7 2)) + ; A1 A2 A3 K1 K2 K3 = A1 A2 A3 K1 K2 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 13 3)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; full house with same set and higher pair wins + ; 51 52 53 41 42 > 51 52 53 31 32 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + (list (c 5 1) (c 5 2) (c 5 3) (c 3 1) (c 3 2)) + ; A1 A2 A3 K1 K2 51 52 = A1 A2 A3 K1 K2 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 5 1) (c 5 2)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; full house ties with two sets + ; 51 52 53 41 42 A1 = 51 52 53 41 42 43 + deep= + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 4 3)) + ; full house beats flush + ; 51 52 53 41 42 > A1 Q1 T1 81 71 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + (list (c 14 1) (c 12 1) (c 10 1) (c 8 1) (c 7 1)) + ; 51 52 53 41 42 A1 K1 Q1 = 51 52 53 41 42 + deep= + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1) (c 13 1) (c 12 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + ; higher flush beats lower flush + ; A1 61 51 41 31 > K1 Q1 J1 T1 81 + deep> + (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1)) + (list (c 13 1) (c 12 2) (c 11 1) (c 10 1) (c 8 1)) + ; A1 K1 Q1 J1 81 71 = A1 K1 Q1 J1 81 + deep= + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1) (c 7 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1)) + ; flush with higher second card wins + ; A1 K1 51 41 31 > A1 Q1 J1 T1 91 + deep> + (list (c 14 1) (c 13 1) (c 5 1) (c 4 1) (c 3 1)) + (list (c 14 1) (c 12 2) (c 11 1) (c 10 1) (c 9 1)) + ; flush with higher third card wins + ; A1 K1 Q1 41 31 > A1 K1 J1 T1 91 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 4 1) (c 3 1)) + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 9 1)) + ; flush with higher fourth card wins + ; A1 K1 Q1 T1 21 > A1 K1 Q1 91 81 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 2 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 9 1) (c 8 1)) + ; flush with higher fifth card wins + ; A1 K1 Q1 T1 81 > A1 K1 Q1 T1 71 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 8 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 7 1)) + ; flushes of different suits tie + ; A1 K1 J1 T1 81 = A2 K2 J2 T2 82 + deep= + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1)) + (list (c 14 2) (c 13 2) (c 11 2) (c 10 2) (c 8 2)) + ; same flush with higher sixth card ties + ; A1 K1 J1 T1 81 71 = A1 K1 J1 T1 81 61 + deep= + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 7 1)) + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 6 1)) + ; flush beats straight + ; 71 61 51 41 21 > A1 K2 Q3 J4 T1 + deep> + (list (c 7 1) (c 6 1) (c 5 1) (c 4 1) (c 2 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + ; A1 K2 Q3 J4 T1 81 71 61 = A1 T1 81 71 61 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) + (list (c 14 1) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) + ; straight with higher kicker ties + ; A1 K2 Q3 J4 T1 92 = A1 K2 Q3 J4 T1 22 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 2 2)) + ; straights of different suits tie + ; A1 K2 Q3 J4 T1 = A2 K3 Q4 J1 T2 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) + ; higher straight beats lower straight + ; A1 K2 Q3 J4 T1 > 61 52 43 34 21 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + ; A1 K2 Q3 J4 T1 92 83 = A1 K2 Q3 J4 T1 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2) (c 8 3)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) + ; lower (2-6) straight beats ace to four straight + ; 61 52 43 34 21 > A1 52 43 34 21 + deep> + (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + ; A1 62 53 44 31 22 = 62 53 44 31 22 + deep= + (list (c 14 1) (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + (list (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + ; ace to four straight with higher kicker ties + ; A1 52 43 34 21 K2 = A1 52 43 34 21 72 + deep= + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 13 2)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 7 2)) + ; ace to fours of different suits tie + ; A1 52 43 34 21 = A2 53 44 31 22 + deep= + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + ; ace to four straight beats set + ; A1 52 43 34 21 > A1 A2 A3 K1 Q2 + deep> + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 12 2)) + ; A1 A2 A3 52 43 34 21 = A1 52 43 34 21 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 2) (c 2 1)) + ; higher set wins + ; 71 72 73 34 21 > 51 52 53 A4 K1 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 14 4) (c 13 1)) + ; set with higher first kicker wins + ; 71 72 73 A1 22 > 71 72 73 K1 Q2 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 2 2)) + (list (c 7 1) (c 7 2) (c 7 3) (c 13 1) (c 12 2)) + ; 71 72 73 A1 K2 J3 54 43 = 71 72 73 A1 K2 + deep= + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3) (c 5 4) (c 4 3)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) + ; set with higher second kicker wins + ; 71 72 73 A1 K2 > 71 72 73 A1 Q2 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 12 2)) + ; set with higher third kicker ties + ; 71 72 73 A1 K2 Q3 = 71 72 73 A1 K2 J3 + deep= + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 12 3)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3)) + ; set beats two pair + ; 71 72 73 34 21 > A1 A2 K3 K4 Q1 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 13 3) (c 13 4) (c 12 1)) + ; two pair with higher high pair wins + ; K1 K2 33 34 21 > Q1 Q2 J3 J4 A1 + deep> + (list (c 13 1) (c 13 2) (c 3 3) (c 3 4) (c 2 1)) + (list (c 12 1) (c 12 2) (c 11 3) (c 11 4) (c 14 1)) + ; A1 A2 K1 K2 J1 J2 = A1 A2 K1 K2 J3 + deep= + (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 1) (c 11 2)) + (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 3)) + ; two pair with tied higher pair and higher lower pair wins + ; K1 K2 71 72 23 > K1 K2 63 64 A1 + deep> + (list (c 13 1) (c 13 2) (c 7 1) (c 7 2) (c 2 3)) + (list (c 13 1) (c 13 2) (c 6 3) (c 6 4) (c 14 1)) + ; two pair with higher kicker wins + ; K1 K2 Q3 Q4 J1 > K1 K2 Q3 Q4 T1 + deep> + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 10 1)) + ; K1 K2 Q3 Q4 A1 T1 92 63 = K1 K2 Q3 Q4 A1 + deep= + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1) (c 10 1) (c 9 2) (c 6 3)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1)) + ; two pair with higher second kicker ties + ; K1 K2 Q3 Q4 J1 T2 = K1 K2 Q3 Q4 J1 92 + deep= + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 10 2)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 9 2)) + ; two pair beats pair + ; 41 42 33 34 21 > A1 A2 K3 Q4 J1 + deep> + (list (c 4 1) (c 4 2) (c 3 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 13 3) (c 12 4) (c 11 1)) + ; higher pair wins + ; 71 72 53 44 31 > 61 62 A3 K4 Q1 + deep> + (list (c 7 1) (c 7 2) (c 5 3) (c 4 4) (c 3 1)) + (list (c 6 1) (c 6 2) (c 14 3) (c 13 4) (c 12 1)) + ; tied pair with higher first kicker wins + ; 91 92 A3 34 21 > 91 92 K3 Q4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 3 4) (c 2 1)) + (list (c 9 1) (c 9 2) (c 13 3) (c 12 4) (c 11 1)) + ; 21 22 A1 Q2 J3 94 81 = 21 22 A1 Q2 J3 + deep= + (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3) (c 9 4) (c 8 1)) + (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3)) + ; tied pair with higher second kicker wins + ; 91 92 A3 K4 21 > 91 92 A3 Q4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 2 1)) + (list (c 9 1) (c 9 2) (c 14 3) (c 12 4) (c 11 1)) + ; tied pair with higher third kicker wins + ; 91 92 A3 K4 Q1 > 91 92 A3 K4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1)) + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 11 1)) + ; tied pair with higher fourth kicker ties + ; 91 92 A3 K4 Q1 J2 = 91 92 A3 K4 Q1 T2 + deep= + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 11 2)) + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 10 2)) + ; pair beats high card + ; 21 22 33 44 51 > A1 Q2 J3 T4 91 + deep> + (list (c 2 1) (c 2 2) (c 3 3) (c 4 4) (c 5 1)) + (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher high card wins + ; A1 22 33 44 61 > K1 Q2 J3 T4 81 + deep> + (list (c 14 1) (c 2 2) (c 3 3) (c 4 4) (c 6 1)) + (list (c 13 1) (c 12 2) (c 11 3) (c 10 4) (c 8 1)) + ; A1 K2 J3 T4 81 72 53 = A1 K2 J3 T4 81 + deep= + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1) (c 7 2) (c 5 3)) + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1)) + ; higher second card wins + ; A1 K2 23 34 41 > A1 Q2 J3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 2 3) (c 3 4) (c 4 1)) + (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher third card wins + ; A1 K2 Q3 24 41 > A1 K2 J3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 2 4) (c 4 1)) + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher fourth card wins + ; A1 K2 Q3 J4 31 > A1 K2 Q3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 3 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 10 4) (c 9 1)) + ; higher fifth card wins + ; A1 K2 Q3 J4 91 > A1 K2 Q3 J4 81 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 8 1)) + ; higher sixth card ties + ; A1 K2 Q3 J4 91 22 = A1 K2 Q3 J4 91 82 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 2 2)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 8 2)) + ; high cards of different suits ties + ; A1 K2 Q3 J4 91 = A2 K3 Q4 J1 92 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 9 2)) + ) +) diff --git a/resources/tests/game-referee-in-cl21/test_handcalc.clvm.hex.reference b/resources/tests/game-referee-in-cl21/test_handcalc.clvm.hex.reference new file mode 100644 index 000000000..441ac847b --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_handcalc.clvm.hex.reference @@ -0,0 +1 @@ +ff02ffff01ff02ff8200feffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010280ffff04ffff04ffff010affff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010bffff010280ffff04ffff04ffff010affff010280ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff0180808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0106ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0107ffff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff0180808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff01808080808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0103ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff018080808080808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff010effff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff01808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff010effff010180ffff0180808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0104ffff010380ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff01808080808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0107ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010280ffff04ffff04ffff010affff010280ffff04ffff04ffff0108ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0106ffff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0106ffff010180ffff01808080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0106ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0102ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff0108ffff010380ffff018080808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0106ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010280ffff0180808080808080ffff04ffff04ffff04ffff0106ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff04ffff04ffff010dffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0107ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff010effff010480ffff04ffff04ffff010dffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff0105ffff010480ffff04ffff04ffff0104ffff010380ffff01808080808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff0180808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010180ffff04ffff04ffff010bffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0102ffff010380ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0106ffff010380ffff04ffff04ffff0106ffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010effff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff0106ffff010380ffff01808080808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010280ffff0180808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff0109ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0106ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff0109ffff010480ffff04ffff04ffff0108ffff010180ffff018080808080808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010280ffff0180808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0105ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0106ffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0105ffff010380ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0104ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff0104ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0102ffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0108ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff0109ffff010280ffff01808080808080ff808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080ffff04ffff01ffffffffffff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff8200a0ffff04ff02ffff04ffff06ff0180ffff04ffff02ff40ffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff40ffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ff09ffff02ff40ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff0181ff80ffff09ffff02ff40ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff010180ffff09ffff02ff40ffff04ff02ffff04ff05ffff04ff0bff8080808080ff8080ff02ffff03ff0bffff01ff02ffff01ff02ff8200f0ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ffffff02ff8200f0ffff04ff02ffff04ff80ffff04ff05ff8080808080ffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff8200a8ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff8200e8ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff02ff8200b8ffff04ff02ffff04ffff06ff0180ffff04ffff02ff05ffff04ffff05ff0b80ffff01808080ff8080808080ff0180ffff01ff02ffff0117ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff04ff0bffff02ff58ffff04ff02ffff04ff09ffff04ffff06ff1580ffff04ff2dff80808080808080ff0180ffff01ff02ffff01ff02ff58ffff04ff02ffff04ff09ffff04ffff06ff1580ffff04ff2dff808080808080ff018080ff0180ff02ffff03ffff02ff44ffff04ff02ffff04ffff04ffff018c736c69636520696e70757473ffff04ffff01866e796c697374ffff04ff0bff80808080ffff04ffff20ff0b80ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ffff05ff0580ffff02ff8200f8ffff04ff02ffff04ffff06ff0580ffff04ffff11ff0bffff010180ff808080808080ff018080ff0180ffffffff02ffff03ffff22ffff0187247072696e7424ff05ff0b80ffff01ff02ffff010bff0180ffff01ff02ffff010bff018080ff0180ffff02ffff03ff05ffff01ff02ffff01ff02ff8200a4ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ff02ff8200a4ffff04ff02ffff04ff05ffff01ff80ff8080808080ffff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff8200a8ffff04ff02ffff04ffff02ff48ffff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff8200a8ffff04ff02ffff04ffff02ff48ffff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff54ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff54ffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ff54ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff4cffff04ff02ffff04ffff06ff0180ffff04ffff02ff8200e4ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ffffff02ff8200acffff04ff02ffff04ff03ffff04ffff02ff8200f4ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff8200f4ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ffff02ff8200b4ffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ff02ffff03ffff20ff1780ffff01ff02ffff010bff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ff0bffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff8200ecffff04ff02ffff04ff05ffff04ffff05ff1780ffff04ffff06ff1780ff808080808080ff0180ffff01ff02ffff01ff02ff8200ecffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ff808080808080ff018080ff0180ff018080ff0180ffff02ff8200ecffff04ff02ffff04ff05ffff04ff13ffff04ff1bff808080808080ffff02ffff03ffff20ff0580ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff02ffff03ffff09ffff05ff0580ff0b80ffff01ff02ffff01ff02ffff03ffff09ff17ffff010480ffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff8200bcffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff10ff17ffff010180ff808080808080ff018080ff0180ff0180ffff01ff02ffff01ff02ff8200bcffff04ff02ffff04ffff06ff0580ffff04ffff05ff0580ffff04ffff0101ff808080808080ff018080ff0180ff018080ff0180ff02ff8200bcffff04ff02ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4280ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ff05ff8080808080ffff01ff80ff8080808080ffffffffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ffff02ffff03ffff20ff0580ffff01ff02ffff01ff02ffff03ffff18ffff09ff17ffff010280ffff09ff2fffff010480ff0b80ffff01ff02ffff01ff0105ff0180ffff01ff02ffff01ff0180ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff09ff17ffff05ff058080ffff01ff02ffff01ff02ff8200a2ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ff17ffff04ff2fff80808080808080ff0180ffff01ff02ffff01ff02ffff03ffff09ffff05ff0580ffff11ff17ffff01018080ffff01ff02ffff01ff02ffff03ffff09ff2fffff010480ffff01ff02ffff01ff10ff17ffff010380ff0180ffff01ff02ffff01ff02ff8200a2ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff05ff0580ffff04ffff10ff2fffff010180ff80808080808080ff018080ff0180ff0180ffff01ff02ffff01ff02ff8200a2ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff05ff0580ffff04ffff0101ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff02ff8200a2ffff04ff02ffff04ff05ffff04ffff09ff09ffff010e80ffff01ff80ff808080808080ffff02ffff03ffff20ff0580ffff01ff02ffff01ff04ffff04ff17ff0b80ffff018080ff0180ffff01ff02ffff01ff02ffff03ffff09ffff05ff0580ff0b80ffff01ff02ffff01ff02ff52ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff10ff17ffff010180ff808080808080ff0180ffff01ff02ffff01ff02ff8200b2ffff04ff02ffff04ffff06ff0180ffff04ffff02ff52ffff04ff02ffff04ffff06ff0580ffff04ffff05ff0580ffff04ffff0101ff808080808080ff8080808080ff018080ff0180ff018080ff0180ffff04ffff04ff2dff1580ff0b80ff02ff52ffff04ff02ffff04ff05ffff04ff09ffff01ff808080808080ffffff02ff5affff04ff02ffff04ff03ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200aa80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200ea80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ff808080808080ff131bffff02ff8200faffff04ff02ffff04ff03ffff04ffff02ff8200fcffff04ff02ffff04ffff02ff8200e8ffff04ff02ffff04ff17ffff04ff09ffff01ff808080808080ff80808080ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200ba80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff02ff8200e8ffff04ff02ffff04ff0bffff04ff09ffff01ff808080808080ff8080808080ff808080808080ffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ff02ff8200f6ffff04ff02ffff04ff03ffff04ffff02ffff03ffff20ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff02ff8200e6ffff04ff02ffff04ffff06ff0180ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff02ff58ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200a680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff0bffff01808080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff11ffff04ffff0180ff808080808080ff8080808080ff8080808080ff018080ff0180ffff04ffff02ff8200e2ffff04ff02ffff04ff17ff80808080ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200b680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff02ff8200f2ffff04ff02ffff04ff17ff80808080ff8080808080ff80808080808080ffffffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ffff02ffff03ffff09ff09ff1b80ffff01ff02ffff0113ff0180ffff01ff02ffff01ff0180ff018080ff0180ff02ff56ffff04ff02ffff04ff03ffff04ffff02ff8200e2ffff04ff02ffff04ff0bff80808080ff8080808080ffff02ffff03ff0bffff01ff02ffff01ff04ffff0109ffff04ff0bffff01808080ff0180ffff01ff02ffff01ff04ffff0106ffff02ff8200f8ffff04ff02ffff04ff15ffff04ffff0105ff808080808080ff018080ff0180ffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ff02ff4effff04ff02ffff04ff03ffff04ffff02ffff03ff17ffff01ff02ffff01ff04ffff0105ffff04ff17ffff01808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ffff04ff4fffff04ff81afffff04ffff02ff8200e8ffff04ff02ffff04ff59ffff04ff2fffff01ff808080808080ff8080808080808080ffffff02ff8200aeffff04ff02ffff04ff03ffff04ffff02ffff03ffff09ff27ffff010180ffff01ff02ffff01ff04ffff0101ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0105ff808080808080ff0180ffff01ff02ffff01ff02ffff03ffff09ff27ffff010280ffff01ff02ffff01ff02ffff03ffff09ff4fffff010180ffff01ff02ffff01ff04ffff0102ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0104ff808080808080ff0180ffff01ff02ffff01ff04ffff0103ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0103ff808080808080ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff09ff27ffff010380ffff01ff02ffff01ff02ffff03ffff09ff4fffff010180ffff01ff02ffff01ff04ffff0104ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0103ff808080808080ff0180ffff01ff02ffff01ff04ffff0107ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0102ff808080808080ff018080ff0180ff0180ffff01ff02ffff01ff04ffff0108ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0102ff808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff8080808080ffff02ff5cffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200ee80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff04ff29ffff04ff15ffff04ff0bff80808080ff8080808080ff02ff8200e0ffff04ff02ffff04ff0bffff04ff17ff8080808080ffff02ff8200beffff04ff02ffff04ff03ffff04ffff02ff4affff04ff02ffff04ff15ff80808080ffff04ffff02ff4affff04ff02ffff04ff2dff80808080ff808080808080ffff02ffff03ffff02ff11ffff04ff0bffff04ff17ff80808080ffff01ff02ffff01ff02ffff03ffff02ff8200b0ffff04ff02ffff04ff0bffff04ffff02ff4affff04ff02ffff04ffff02ff48ffff04ff02ffff04ff29ff80808080ff80808080ff8080808080ffff01ff02ffff01ff02ffff03ffff02ff8200b0ffff04ff02ffff04ff17ffff04ffff02ff4affff04ff02ffff04ffff02ff48ffff04ff02ffff04ff59ff80808080ff80808080ff8080808080ffff01ff02ffff01ff02ffff03ff79ffff01ff02ffff01ff02ff5effff04ff02ffff04ff79ff80808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff02ffff03ff03ffff01ff02ffff01ff02ff5effff04ff02ffff04ff03ff80808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_handcalc.sym b/resources/tests/game-referee-in-cl21/test_handcalc.sym new file mode 100644 index 000000000..4ff5ca1eb --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_handcalc.sym @@ -0,0 +1 @@ +{"dd3953423ae82b313d5361cb4c9ea7d18b43294e1c0801e1c021d101a7ce58f6_left_env": "1", "24d7dbd0fece56391d516812ca037a910985789b424144b4dc8f8c57cf3ce108": "straight_high_inner", "e51e3ecc739e0c9b646889ad797fa268d9acbb09f42f70b1a75be411440dcf36_left_env": "1", "76751a9c95444501c3ad57278f9ace3e6a1e41fca43bd93d6e5a8ca125e8c4a3_arguments": "(((myless_$_453 mylist_$_454) (a b)) sa sb)", "3ac370c3d91282c6eb94742d40cdb371de392eaca8a0a213d3d3ade6d1b03367_left_env": "1", "36900466483b112787abffe419202a499c8e5467e750cf3aec03ac5fd0ba9cfd_left_env": "1", "36900466483b112787abffe419202a499c8e5467e750cf3aec03ac5fd0ba9cfd_arguments": "(myless mylist)", "40fe864fddcab141770d7e0c0be5d5d07bcb8efd496a6f4bb2cdc3834e94eab9_left_env": "1", "c4e96a2219a3d6389693cfb81c4309f5bf5f1a89f300c7c12d019e08d14cde09_arguments": "(a b)", "1c2f95563ff25508afc464b19cd91787c95ac0b12f1d4fa16addeaa6335aac8d_arguments": "((((((cards_$_473) first rest) fsuit nosuits) max_flush sh groups) max_straight (top_count . top_card) (second_count . second_card) topcards) max_group)", "01ed928ebc640669bfdc000b292962b919f6635176dd9119325f5f912d7567b8_arguments": "(() x y)", "a87d2e2e13539c8f9f66137bdee9a7fd750b8bdb6a07fc1e6cd8416d771d9958_arguments": "(() x y)", "c60f4e2e12ab7285ef437f63bb24f4e5e6267fc76479893a179ebae738aca004": "letbinding_$_481", "64499f3fb4ed1322a24ece83ce5664a10e41b8cb291c4c395d961004680802ca_arguments": "(process remaining init)", "ff5f6181808cb059cffecd54a408a6b4566b861a8905208bbeb87a10e3c8ec65": "merge", "d8c50d6282a1ba47f0a23430d177bbfbb72e2b84713745e894f575570f1f3d6e": "lambda_$_486", "973ed02dde4588cd7699bdec8c1138e788edf49380ca7a8c62c74ad021bf8022_arguments": "((((cards_$_473) first rest) fsuit nosuits) fnosuits)", "1bde90fbef9d7a4c5cb7133780d4275aa03dfc0a54a905b899d65b4b578f6661": "letbinding_$_479", "4b216afca35845442571c30c6d827724285ca82490dbdae1b27f2d082e85ff66": "runtests", "64499f3fb4ed1322a24ece83ce5664a10e41b8cb291c4c395d961004680802ca_left_env": "1", "f5470fda7b930fc12a27be2810e4c48ad7e35ceda81273ba026cd6da98d94c3c_left_env": "1", "5c2c8bfc9ac6c103562c9017a5cee2634da7ee43d44bd4f3d46d11e519942ea6": "straight_high", "724d50ee95e66b90e255e2cecc58cc35c2eb27302b1952948538ad95f7387a4b_arguments": "(F L R)", "24d7dbd0fece56391d516812ca037a910985789b424144b4dc8f8c57cf3ce108_arguments": "(ranks started_ace last count)", "ea58983a62a5d0a526c32f3423717af26c6d9d5963eb4831a0d1049227eba060_arguments": "(suits last count)", "26df51fddc60f80f199438e505e3832df819036418c8bf439a572679ebfd1897": "split_inner", "d8c50d6282a1ba47f0a23430d177bbfbb72e2b84713745e894f575570f1f3d6e_left_env": "1", "2379a74341919286585b51fa8ff2bf5a2e76254197c786fdcd96d4b004be17ba": "deep>", "3ac370c3d91282c6eb94742d40cdb371de392eaca8a0a213d3d3ade6d1b03367_arguments": "(a b)", "7245d12b7785f1ee23a0ec0d3a03432057ec41fb0561d373d91cda267f44c3e9": "reverse", "b131c2e07b1152ba1bd67a5398a6b58cde3020e01fa510f0f7c3cd502fcdb30d_left_env": "1", "c64dc59aae25053fe8d872e13fca4e2c43765a1a83335d520435180f3ab55485_arguments": "(myless A B agg)", "d121f71fcb5513b6d2b097255deb884ff40c26dd366b0ba7cf2eea1440b07901_left_env": "1", "6776e296095747790c1a208caea4e4b8633e2c146890367f13a0238f42b28c87_left_env": "1", "0dda9e9f845e653fbb9f1065f098a0c439bf605b2e8830546184c95eae822f25_arguments": "((process_$_431 remaining_$_432 init_$_433) next)", "76751a9c95444501c3ad57278f9ace3e6a1e41fca43bd93d6e5a8ca125e8c4a3_left_env": "1", "20f4eca5a09be558c75518290c48d6aad0e4e8306e79cf03e92b8ca828d35f99": "runtests_inner", "c4f6f8551c01bbcf52ab1fd2b92333649110b28aee8570a9422e2b3a671fe94b_arguments": "((((cards_$_473) first rest) fsuit nosuits) max_flush sh groups)", "d121f71fcb5513b6d2b097255deb884ff40c26dd366b0ba7cf2eea1440b07901_arguments": "(mylist)", "00c86eab1caeadaaf967420becbefef7170e5e996890edc355d16c263ea32e27_arguments": "(myless best_so_far mylist)", "ca3aa00f92cd656fbf2e7c7863a2bd3ebfcdf0bdb05ca8f00ce9d51648d38b1f_arguments": "(a b)", "042c55b626937b8d6be258a97f8d25cdedeee2e712dbddef9438fa900eff883e_left_env": "1", "24d7dbd0fece56391d516812ca037a910985789b424144b4dc8f8c57cf3ce108_left_env": "1", "6776e296095747790c1a208caea4e4b8633e2c146890367f13a0238f42b28c87_arguments": "(((((cards_$_473) first rest) fsuit nosuits) max_flush sh groups) max_straight (top_count . top_card) (second_count . second_card) topcards)", "40fe864fddcab141770d7e0c0be5d5d07bcb8efd496a6f4bb2cdc3834e94eab9_arguments": "((items_$_469 last_$_470 count_$_471) val)", "0dda9e9f845e653fbb9f1065f098a0c439bf605b2e8830546184c95eae822f25_left_env": "1", "5c2c8bfc9ac6c103562c9017a5cee2634da7ee43d44bd4f3d46d11e519942ea6_arguments": "(ranks)", "8bda8ccb43702a3e1a1b2354adfb39e9a229ae4dc896e7481a569ecc19dd2d6d": "deep<", "0dda9e9f845e653fbb9f1065f098a0c439bf605b2e8830546184c95eae822f25": "letbinding_$_480", "724d50ee95e66b90e255e2cecc58cc35c2eb27302b1952948538ad95f7387a4b": "map-with-rest", "40fe864fddcab141770d7e0c0be5d5d07bcb8efd496a6f4bb2cdc3834e94eab9": "letbinding_$_484", "8c4576eb20d2f8cc795c065e3a585703145c1f6beff372bf37b4634ad785adc8": "letbinding_$_488", "ff5f6181808cb059cffecd54a408a6b4566b861a8905208bbeb87a10e3c8ec65_left_env": "1", "ea58983a62a5d0a526c32f3423717af26c6d9d5963eb4831a0d1049227eba060_left_env": "1", "2379a74341919286585b51fa8ff2bf5a2e76254197c786fdcd96d4b004be17ba_arguments": "(a b)", "8c4576eb20d2f8cc795c065e3a585703145c1f6beff372bf37b4634ad785adc8_left_env": "1", "__chia__main_arguments": "()", "b131c2e07b1152ba1bd67a5398a6b58cde3020e01fa510f0f7c3cd502fcdb30d": "letbinding_$_485", "c64b0acdb9bfc5a1bec80732d64bee90fd12e869207674a220042725441f9cb3": "find_flush", "7245d12b7785f1ee23a0ec0d3a03432057ec41fb0561d373d91cda267f44c3e9_arguments": "(vals)", "a87d2e2e13539c8f9f66137bdee9a7fd750b8bdb6a07fc1e6cd8416d771d9958": "lambda_$_494", "01ed928ebc640669bfdc000b292962b919f6635176dd9119325f5f912d7567b8": "lambda_$_498", "b16167d2466d1fb9c6fd4b5636fa809f866e9b7a0a698f1a18ffa308d7280c42": "letbinding_$_499", "f5470fda7b930fc12a27be2810e4c48ad7e35ceda81273ba026cd6da98d94c3c": "slice", "76751a9c95444501c3ad57278f9ace3e6a1e41fca43bd93d6e5a8ca125e8c4a3": "letbinding_$_482", "1c2f95563ff25508afc464b19cd91787c95ac0b12f1d4fa16addeaa6335aac8d": "letbinding_$_497", "042c55b626937b8d6be258a97f8d25cdedeee2e712dbddef9438fa900eff883e_arguments": "(R P)", "8bda8ccb43702a3e1a1b2354adfb39e9a229ae4dc896e7481a569ecc19dd2d6d_left_env": "1", "26df51fddc60f80f199438e505e3832df819036418c8bf439a572679ebfd1897_arguments": "(@ everything (rest aggl aggr))", "24d45638962c8ac6b0923f0f2c912177b1b1c710bbcd3e10fccf01fc6f771263_arguments": "(myless mylist)", "d013fcaaa576d263aa86406509a11272424931651d958cff6ba9be6d2b9a7fed_arguments": "(items last count)", "24d45638962c8ac6b0923f0f2c912177b1b1c710bbcd3e10fccf01fc6f771263": "sort", "4b216afca35845442571c30c6d827724285ca82490dbdae1b27f2d082e85ff66_arguments": "tests", "b131c2e07b1152ba1bd67a5398a6b58cde3020e01fa510f0f7c3cd502fcdb30d_arguments": "((cards_$_473) first rest)", "c64dc59aae25053fe8d872e13fca4e2c43765a1a83335d520435180f3ab55485": "merge_inner", "973ed02dde4588cd7699bdec8c1138e788edf49380ca7a8c62c74ad021bf8022": "letbinding_$_491", "1bde90fbef9d7a4c5cb7133780d4275aa03dfc0a54a905b899d65b4b578f6661_left_env": "1", "973ed02dde4588cd7699bdec8c1138e788edf49380ca7a8c62c74ad021bf8022_left_env": "1", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-in-cl21/test_handcalc.clsp", "ca3aa00f92cd656fbf2e7c7863a2bd3ebfcdf0bdb05ca8f00ce9d51648d38b1f_left_env": "1", "20f4eca5a09be558c75518290c48d6aad0e4e8306e79cf03e92b8ca828d35f99_arguments": "((myfunc firstarg secondarg . remaining))", "471488bbd4b64848f0c6592900ef2a751e8907a72557b0ba794e0d6f1252c374_left_env": "1", "ff5f6181808cb059cffecd54a408a6b4566b861a8905208bbeb87a10e3c8ec65_arguments": "(myless a b)", "00c86eab1caeadaaf967420becbefef7170e5e996890edc355d16c263ea32e27": "max_inner", "26df51fddc60f80f199438e505e3832df819036418c8bf439a572679ebfd1897_left_env": "1", "00c86eab1caeadaaf967420becbefef7170e5e996890edc355d16c263ea32e27_left_env": "1", "d013fcaaa576d263aa86406509a11272424931651d958cff6ba9be6d2b9a7fed": "group_by_count_inner", "c4e96a2219a3d6389693cfb81c4309f5bf5f1a89f300c7c12d019e08d14cde09": "prepend", "145bfb83f7b3ef33ac1eada788c187e4d1feb7326bcf340bb060a62e75434854_left_env": "1", "1c2f95563ff25508afc464b19cd91787c95ac0b12f1d4fa16addeaa6335aac8d_left_env": "1", "f4c3c71dddb1c7ee50bc104032f26172d61ff77f9bca9876d1846c47cd72020e": "handcalc", "7245d12b7785f1ee23a0ec0d3a03432057ec41fb0561d373d91cda267f44c3e9_left_env": "1", "a87d2e2e13539c8f9f66137bdee9a7fd750b8bdb6a07fc1e6cd8416d771d9958_left_env": "1", "c64b0acdb9bfc5a1bec80732d64bee90fd12e869207674a220042725441f9cb3_arguments": "(suits)", "c4e96a2219a3d6389693cfb81c4309f5bf5f1a89f300c7c12d019e08d14cde09_left_env": "1", "36900466483b112787abffe419202a499c8e5467e750cf3aec03ac5fd0ba9cfd": "max", "d013fcaaa576d263aa86406509a11272424931651d958cff6ba9be6d2b9a7fed_left_env": "1", "1bde90fbef9d7a4c5cb7133780d4275aa03dfc0a54a905b899d65b4b578f6661_arguments": "((a_$_404 b_$_405) inner_result)", "64499f3fb4ed1322a24ece83ce5664a10e41b8cb291c4c395d961004680802ca": "filtermap", "e51e3ecc739e0c9b646889ad797fa268d9acbb09f42f70b1a75be411440dcf36": "lambda_$_493", "c4f6f8551c01bbcf52ab1fd2b92333649110b28aee8570a9422e2b3a671fe94b_left_env": "1", "79f3cf5c572162105f8688174041050314a154956ef27d7ea6414a9dcd402faa_arguments": "(items)", "042c55b626937b8d6be258a97f8d25cdedeee2e712dbddef9438fa900eff883e": "print", "e51e3ecc739e0c9b646889ad797fa268d9acbb09f42f70b1a75be411440dcf36_arguments": "((fsuit) (card_rank . card_suit))", "f4c3c71dddb1c7ee50bc104032f26172d61ff77f9bca9876d1846c47cd72020e_arguments": "(cards)", "b16167d2466d1fb9c6fd4b5636fa809f866e9b7a0a698f1a18ffa308d7280c42_arguments": "(((myfunc_$_474 firstarg_$_475 secondarg_$_476 . remaining_$_477)) firstval secondval)", "8bda8ccb43702a3e1a1b2354adfb39e9a229ae4dc896e7481a569ecc19dd2d6d_arguments": "(a b)", "471488bbd4b64848f0c6592900ef2a751e8907a72557b0ba794e0d6f1252c374": "reverse_inner", "f5470fda7b930fc12a27be2810e4c48ad7e35ceda81273ba026cd6da98d94c3c_arguments": "(mylist count)", "c64dc59aae25053fe8d872e13fca4e2c43765a1a83335d520435180f3ab55485_left_env": "1", "79f3cf5c572162105f8688174041050314a154956ef27d7ea6414a9dcd402faa": "group_by_count", "b16167d2466d1fb9c6fd4b5636fa809f866e9b7a0a698f1a18ffa308d7280c42_left_env": "1", "2379a74341919286585b51fa8ff2bf5a2e76254197c786fdcd96d4b004be17ba_left_env": "1", "724d50ee95e66b90e255e2cecc58cc35c2eb27302b1952948538ad95f7387a4b_left_env": "1", "5c2c8bfc9ac6c103562c9017a5cee2634da7ee43d44bd4f3d46d11e519942ea6_left_env": "1", "c64b0acdb9bfc5a1bec80732d64bee90fd12e869207674a220042725441f9cb3_left_env": "1", "79f3cf5c572162105f8688174041050314a154956ef27d7ea6414a9dcd402faa_left_env": "1", "145bfb83f7b3ef33ac1eada788c187e4d1feb7326bcf340bb060a62e75434854": "lambda_$_487", "c60f4e2e12ab7285ef437f63bb24f4e5e6267fc76479893a179ebae738aca004_arguments": "((myless_$_453 mylist_$_454) (a b))", "dd3953423ae82b313d5361cb4c9ea7d18b43294e1c0801e1c021d101a7ce58f6_arguments": "(((((cards_$_473) first rest) fsuit nosuits) fnosuits) fsh)", "d8c50d6282a1ba47f0a23430d177bbfbb72e2b84713745e894f575570f1f3d6e_arguments": "(() x)", "f4c3c71dddb1c7ee50bc104032f26172d61ff77f9bca9876d1846c47cd72020e_left_env": "1", "6776e296095747790c1a208caea4e4b8633e2c146890367f13a0238f42b28c87": "letbinding_$_496", "24d45638962c8ac6b0923f0f2c912177b1b1c710bbcd3e10fccf01fc6f771263_left_env": "1", "d121f71fcb5513b6d2b097255deb884ff40c26dd366b0ba7cf2eea1440b07901": "split", "01ed928ebc640669bfdc000b292962b919f6635176dd9119325f5f912d7567b8_left_env": "1", "4b216afca35845442571c30c6d827724285ca82490dbdae1b27f2d082e85ff66_left_env": "1", "c4f6f8551c01bbcf52ab1fd2b92333649110b28aee8570a9422e2b3a671fe94b": "letbinding_$_490", "dd3953423ae82b313d5361cb4c9ea7d18b43294e1c0801e1c021d101a7ce58f6": "letbinding_$_495", "c60f4e2e12ab7285ef437f63bb24f4e5e6267fc76479893a179ebae738aca004_left_env": "1", "ca3aa00f92cd656fbf2e7c7863a2bd3ebfcdf0bdb05ca8f00ce9d51648d38b1f": "deep=", "ea58983a62a5d0a526c32f3423717af26c6d9d5963eb4831a0d1049227eba060": "find_flush_inner", "20f4eca5a09be558c75518290c48d6aad0e4e8306e79cf03e92b8ca828d35f99_left_env": "1", "8c4576eb20d2f8cc795c065e3a585703145c1f6beff372bf37b4634ad785adc8_arguments": "(((cards_$_473) first rest) fsuit nosuits)", "145bfb83f7b3ef33ac1eada788c187e4d1feb7326bcf340bb060a62e75434854_arguments": "(() x)", "3ac370c3d91282c6eb94742d40cdb371de392eaca8a0a213d3d3ade6d1b03367": "deep_compare", "471488bbd4b64848f0c6592900ef2a751e8907a72557b0ba794e0d6f1252c374_arguments": "(reversed rest)"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/test_handcalc_b.clsp b/resources/tests/game-referee-in-cl21/test_handcalc_b.clsp new file mode 100644 index 000000000..674bbd414 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_handcalc_b.clsp @@ -0,0 +1,377 @@ + +(mod () + (include *standard-cl-21*) + (include deep_compare.clinc) + (include assert.clinc) + (include reverse.clinc) + (include prepend.clinc) + (include map.clinc) + (include filtermap.clinc) + (include slice.clinc) + (include print.clinc) + (include handcalc.clinc) + + (defun runtests_inner ((myfunc firstarg secondarg . remaining)) + (assign-lambda + firstval (handcalc firstarg) + secondval (handcalc secondarg) + (assert + (a myfunc (list firstval secondval)) + (deep= firstval (handcalc (reverse firstarg))) + (deep= secondval (handcalc (reverse secondarg))) + (if remaining + (runtests_inner remaining) + 0 + ) + ) + ) + ) + + (defun runtests tests (if tests (runtests_inner tests) ())) + + ;; Join these up when large application bug is fixed. + (runtests + ; all beats both emerge over and measure higher + ; straight flush with higher kicker ties + ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 81 + deep= + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 8 1)) + ; straight flushes of different suits tie + ; A1 K1 Q1 J1 T1 = A2 K2 Q2 J2 T2 + deep= + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) + (list (c 14 2) (c 13 2) (c 12 2) (c 11 2) (c 10 2)) + ; higher straight flush beats lower straight flush + ; A1 K1 Q1 J1 T1 > 61 51 41 31 21 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 + deep= + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) + (list (c 14 2) (c 11 2) (c 10 2) (c 13 2) (c 12 2)) + ; lower (2-6) straight flush beats ace to four straight flush + ; 61 51 41 31 21 > A2 52 42 32 22 + deep> + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) + ; A1 61 51 41 31 21 = 61 51 41 31 21 + deep= + (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; ace to four straight flush with higher kicker ties + ; A2 52 42 32 22 61 = A1 51 41 31 21 71 + deep= + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2) (c 6 1)) + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1) (c 7 1)) + ; ace to four straight flushes of different suits tie + ; A1 51 41 31 21 = A2 52 42 32 22 + deep= + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) + ; ace to four straight flush beats four of a kind + ; A1 51 41 31 21 > K1 K2 K3 K4 J1 + deep> + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) + ; A1 A2 A3 A4 51 41 31 21 = A1 51 41 31 21 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; four of a kind with higher kicker wins + ; K1 K2 K3 K4 Q1 > K1 K2 K3 K4 J1 + deep> + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) + ; K1 K2 K3 K4 T1 91 = K1 K2 K3 K4 T1 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1) (c 9 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1)) + ; four of a kind with higher second kicker ties + ; K1 K2 K3 K4 Q1 J1 = K1 K2 K3 K4 Q1 T1 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 11 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 10 1)) + ; higher four of a kind beats lower four of a kind + ; K1 K2 K3 K4 21 > 31 32 33 34 A1 + deep> + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 2 1)) + (list (c 3 1) (c 3 2) (c 3 3) (c 3 4) (c 14 1)) + ; K1 K2 K3 K4 31 32 33 34 = K1 K2 K3 K4 32 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 1) (c 3 2) (c 3 3) (c 3 4)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 2)) + ; four of a kind beats full house + ; 21 22 23 24 31 > A1 A2 A3 K1 K2 + deep> + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 3 1)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; 21 22 23 24 A1 A2 A3 = 21 22 23 24 A2 + deep= + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 1) (c 14 2) (c 14 3)) + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 2)) + ; full house with higher set wins + ; 51 52 53 21 22 > 31 32 33 71 72 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 2 1) (c 2 2)) + (list (c 3 1) (c 3 2) (c 3 3) (c 7 1) (c 7 2)) + ; A1 A2 A3 K1 K2 K3 = A1 A2 A3 K1 K2 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 13 3)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; full house with same set and higher pair wins + ; 51 52 53 41 42 > 51 52 53 31 32 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + (list (c 5 1) (c 5 2) (c 5 3) (c 3 1) (c 3 2)) + ; A1 A2 A3 K1 K2 51 52 = A1 A2 A3 K1 K2 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 5 1) (c 5 2)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; full house ties with two sets + ; 51 52 53 41 42 A1 = 51 52 53 41 42 43 + deep= + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 4 3)) + ; full house beats flush + ; 51 52 53 41 42 > A1 Q1 T1 81 71 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + (list (c 14 1) (c 12 1) (c 10 1) (c 8 1) (c 7 1)) + ; 51 52 53 41 42 A1 K1 Q1 = 51 52 53 41 42 + deep= + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1) (c 13 1) (c 12 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + ; higher flush beats lower flush + ; A1 61 51 41 31 > K1 Q1 J1 T1 81 + deep> + (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1)) + (list (c 13 1) (c 12 2) (c 11 1) (c 10 1) (c 8 1)) + ; A1 K1 Q1 J1 81 71 = A1 K1 Q1 J1 81 + deep= + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1) (c 7 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1)) + ; flush with higher second card wins + ; A1 K1 51 41 31 > A1 Q1 J1 T1 91 + deep> + (list (c 14 1) (c 13 1) (c 5 1) (c 4 1) (c 3 1)) + (list (c 14 1) (c 12 2) (c 11 1) (c 10 1) (c 9 1)) + ; flush with higher third card wins + ; A1 K1 Q1 41 31 > A1 K1 J1 T1 91 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 4 1) (c 3 1)) + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 9 1)) + ; flush with higher fourth card wins + ; A1 K1 Q1 T1 21 > A1 K1 Q1 91 81 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 2 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 9 1) (c 8 1)) + ; flush with higher fifth card wins + ; A1 K1 Q1 T1 81 > A1 K1 Q1 T1 71 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 8 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 7 1)) + ; flushes of different suits tie + ; A1 K1 J1 T1 81 = A2 K2 J2 T2 82 + deep= + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1)) + (list (c 14 2) (c 13 2) (c 11 2) (c 10 2) (c 8 2)) + ; same flush with higher sixth card ties + ; A1 K1 J1 T1 81 71 = A1 K1 J1 T1 81 61 + deep= + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 7 1)) + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 6 1)) + ; flush beats straight + ; 71 61 51 41 21 > A1 K2 Q3 J4 T1 + deep> + (list (c 7 1) (c 6 1) (c 5 1) (c 4 1) (c 2 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + ; A1 K2 Q3 J4 T1 81 71 61 = A1 T1 81 71 61 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) + (list (c 14 1) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) + ; straight with higher kicker ties + ; A1 K2 Q3 J4 T1 92 = A1 K2 Q3 J4 T1 22 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 2 2)) + ; straights of different suits tie + ; A1 K2 Q3 J4 T1 = A2 K3 Q4 J1 T2 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) + ; higher straight beats lower straight + ; A1 K2 Q3 J4 T1 > 61 52 43 34 21 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + ; A1 K2 Q3 J4 T1 92 83 = A1 K2 Q3 J4 T1 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2) (c 8 3)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) + ; lower (2-6) straight beats ace to four straight + ; 61 52 43 34 21 > A1 52 43 34 21 + deep> + (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + ; A1 62 53 44 31 22 = 62 53 44 31 22 + deep= + (list (c 14 1) (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + (list (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + ; ace to four straight with higher kicker ties + ; A1 52 43 34 21 K2 = A1 52 43 34 21 72 + deep= + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 13 2)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 7 2)) + ; ace to fours of different suits tie + ; A1 52 43 34 21 = A2 53 44 31 22 + deep= + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + ; ace to four straight beats set + ; A1 52 43 34 21 > A1 A2 A3 K1 Q2 + deep> + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 12 2)) + ; A1 A2 A3 52 43 34 21 = A1 52 43 34 21 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 2) (c 2 1)) + ; higher set wins + ; 71 72 73 34 21 > 51 52 53 A4 K1 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 14 4) (c 13 1)) + ; set with higher first kicker wins + ; 71 72 73 A1 22 > 71 72 73 K1 Q2 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 2 2)) + (list (c 7 1) (c 7 2) (c 7 3) (c 13 1) (c 12 2)) + ; 71 72 73 A1 K2 J3 54 43 = 71 72 73 A1 K2 + deep= + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3) (c 5 4) (c 4 3)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) + ; set with higher second kicker wins + ; 71 72 73 A1 K2 > 71 72 73 A1 Q2 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 12 2)) + ; set with higher third kicker ties + ; 71 72 73 A1 K2 Q3 = 71 72 73 A1 K2 J3 + deep= + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 12 3)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3)) + ; set beats two pair + ; 71 72 73 34 21 > A1 A2 K3 K4 Q1 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 13 3) (c 13 4) (c 12 1)) + ; two pair with higher high pair wins + ; K1 K2 33 34 21 > Q1 Q2 J3 J4 A1 + deep> + (list (c 13 1) (c 13 2) (c 3 3) (c 3 4) (c 2 1)) + (list (c 12 1) (c 12 2) (c 11 3) (c 11 4) (c 14 1)) + ; A1 A2 K1 K2 J1 J2 = A1 A2 K1 K2 J3 + deep= + (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 1) (c 11 2)) + (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 3)) + ; two pair with tied higher pair and higher lower pair wins + ; K1 K2 71 72 23 > K1 K2 63 64 A1 + deep> + (list (c 13 1) (c 13 2) (c 7 1) (c 7 2) (c 2 3)) + (list (c 13 1) (c 13 2) (c 6 3) (c 6 4) (c 14 1)) + ; two pair with higher kicker wins + ; K1 K2 Q3 Q4 J1 > K1 K2 Q3 Q4 T1 + deep> + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 10 1)) + ; K1 K2 Q3 Q4 A1 T1 92 63 = K1 K2 Q3 Q4 A1 + deep= + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1) (c 10 1) (c 9 2) (c 6 3)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1)) + ; two pair with higher second kicker ties + ; K1 K2 Q3 Q4 J1 T2 = K1 K2 Q3 Q4 J1 92 + deep= + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 10 2)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 9 2)) + ; two pair beats pair + ; 41 42 33 34 21 > A1 A2 K3 Q4 J1 + deep> + (list (c 4 1) (c 4 2) (c 3 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 13 3) (c 12 4) (c 11 1)) + ; higher pair wins + ; 71 72 53 44 31 > 61 62 A3 K4 Q1 + deep> + (list (c 7 1) (c 7 2) (c 5 3) (c 4 4) (c 3 1)) + (list (c 6 1) (c 6 2) (c 14 3) (c 13 4) (c 12 1)) + ; tied pair with higher first kicker wins + ; 91 92 A3 34 21 > 91 92 K3 Q4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 3 4) (c 2 1)) + (list (c 9 1) (c 9 2) (c 13 3) (c 12 4) (c 11 1)) + ; 21 22 A1 Q2 J3 94 81 = 21 22 A1 Q2 J3 + deep= + (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3) (c 9 4) (c 8 1)) + (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3)) + ; tied pair with higher second kicker wins + ; 91 92 A3 K4 21 > 91 92 A3 Q4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 2 1)) + (list (c 9 1) (c 9 2) (c 14 3) (c 12 4) (c 11 1)) + ; tied pair with higher third kicker wins + ; 91 92 A3 K4 Q1 > 91 92 A3 K4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1)) + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 11 1)) + ; tied pair with higher fourth kicker ties + ; 91 92 A3 K4 Q1 J2 = 91 92 A3 K4 Q1 T2 + deep= + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 11 2)) + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 10 2)) + ; pair beats high card + ; 21 22 33 44 51 > A1 Q2 J3 T4 91 + deep> + (list (c 2 1) (c 2 2) (c 3 3) (c 4 4) (c 5 1)) + (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher high card wins + ; A1 22 33 44 61 > K1 Q2 J3 T4 81 + deep> + (list (c 14 1) (c 2 2) (c 3 3) (c 4 4) (c 6 1)) + (list (c 13 1) (c 12 2) (c 11 3) (c 10 4) (c 8 1)) + ; A1 K2 J3 T4 81 72 53 = A1 K2 J3 T4 81 + deep= + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1) (c 7 2) (c 5 3)) + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1)) + ; higher second card wins + ; A1 K2 23 34 41 > A1 Q2 J3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 2 3) (c 3 4) (c 4 1)) + (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher third card wins + ; A1 K2 Q3 24 41 > A1 K2 J3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 2 4) (c 4 1)) + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher fourth card wins + ; A1 K2 Q3 J4 31 > A1 K2 Q3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 3 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 10 4) (c 9 1)) + ; higher fifth card wins + ; A1 K2 Q3 J4 91 > A1 K2 Q3 J4 81 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 8 1)) + ; higher sixth card ties + ; A1 K2 Q3 J4 91 22 = A1 K2 Q3 J4 91 82 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 2 2)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 8 2)) + ; high cards of different suits ties + ; A1 K2 Q3 J4 91 = A2 K3 Q4 J1 92 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 9 2)) + ) +) diff --git a/resources/tests/game-referee-in-cl21/test_library_basics.py b/resources/tests/game-referee-in-cl21/test_library_basics.py new file mode 100644 index 000000000..926ddde7a --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_library_basics.py @@ -0,0 +1,165 @@ +import os +import pytest +import random +from itertools import permutations +from typing import List +#from hsms.streamables.program import Program +#from steprun import diag_run_clvm, compile_module_with_symbols +#from lib.program import Program +from pathlib import Path +from clvm_rs import Program +from lib.steprun import diag_run_clvm, compile_module_with_symbols +from clvm_tools_rs import get_version + +print(f"clvm_tools_rs version is {get_version()}") +#include_dirs = os.getcwd() +include_dirs = [Path(__file__).parent, Path(__file__).parent.parent / "lib"] +Program.set_run_unsafe_max_cost(11000000000) + +print(f"XXX: {include_dirs}") +compile_module_with_symbols(include_dirs, 'smoke_test_deep_compare.clsp') +compare_program = Program.from_bytes(bytes.fromhex(open('smoke_test_deep_compare.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'smoke_test_sort.clsp') +sort_program = Program.from_bytes(bytes.fromhex(open('smoke_test_sort.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_sort.clsp') +test_sort_program = Program.from_bytes(bytes.fromhex(open('test_sort.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_permutations.clsp') +test_permutations_program = Program.from_bytes(bytes.fromhex(open('test_permutations.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_reverse.clsp') +test_reverse_program = Program.from_bytes(bytes.fromhex(open('test_reverse.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_prepend.clsp') +test_prepend_program = Program.from_bytes(bytes.fromhex(open('test_prepend.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_range.clsp') +test_range_program = Program.from_bytes(bytes.fromhex(open('test_range.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'smoke_test_permutations.clsp') +smoke_test_permutations_program = Program.from_bytes(bytes.fromhex(open('smoke_test_permutations.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_handcalc.clsp') +test_handcalc_program = Program.from_bytes(bytes.fromhex(open('test_handcalc.clvm.hex').read())) + +def as_atom_list(prg: Program) -> List[bytes]: + """ + Pretend `prg` is a list of atoms. Return the corresponding + python list of atoms. + + At each step, we always assume a node to be an atom or a pair. + If the assumption is wrong, we exit early. This way we never fail + and always return SOMETHING. + """ + items = [] + obj = prg + while True: + pair = obj.pair + if pair is None: + break + atom = pair[0].atom + if atom is None: + break + items.append(atom) + obj = pair[1] + return items + +def test_smoke_compare(): + compare_program.run(Program.to([])) + +def test_handcalc(): + diag_run_clvm(test_handcalc_program, Program.to([]), 'test_handcalc.sym') + +def proper_list_inner(result,cl): + if hasattr(cl, 'pair') and cl.pair is not None: + result.append(cl.pair[0]) + return proper_list_inner(result,cl.pair[1]) + else: + return result + +def proper_list(cl): + result = [] + return proper_list_inner(result,cl) + +def int_list(cl): + return [Program.to(x).as_int() for x in as_atom_list(Program.to(cl))] + +def de_none_list(l): + return [x if x is not None else [] for x in l] + +def with_random_lists(n,f): + for length in range(n): # 0-10 length + for i in range(1 + (3 * length)): # A few orders each + orig_list = [random.randint(0,100) for x in range(length)] + f(orig_list) + +def test_prepend(): + for length1 in range(5): + list_1 = list(range(length1)) + for length2 in range(length1): + prepend_result = test_prepend_program.run([Program.to(list_1[:length2]),Program.to(list_1[length2:])]) + assert list_1 == int_list(prepend_result) + +def test_reverse(): + def test_reverse_list(l): + rev_args = Program.to([l]) + reversed_result = Program.to(list(reversed(l))) + reversed_by_prog = test_reverse_program.run(rev_args) + assert reversed_result == reversed_by_prog + + with_random_lists(10,test_reverse_list) + +def test_range(): + for length in range(10): + want_list = list(range(length)) + result = test_range_program.run(Program.to([length])) + assert want_list == result + +def do_test_permutations_of_size_n(n): + try_list = [random.randint(0,100) for x in range(n)] + want_set = list([list(v) for v in sorted(permutations(try_list))]) + listed_result = smoke_test_permutations_program.run(Program.to([try_list])) + pl = proper_list(listed_result) + perms_result = sorted([int_list(x) for x in de_none_list(pl)]) + assert want_set == perms_result + +def test_permutations_0(): + do_test_permutations_of_size_n(0) + +def test_permutations_1(): + do_test_permutations_of_size_n(1) + +def test_permutations_2(): + n = 2 + all_a_string = 0x616161616161 + all_b_string = 0x626262626262 + for try_list in [[all_a_string,all_b_string], [all_b_string,all_a_string]]: + want_set = list([list(v) for v in sorted(permutations(try_list))]) + listed_result = diag_run_clvm(smoke_test_permutations_program, Program.to([try_list]), 'smoke_test_permutations.sym') + pl = proper_list(listed_result) + perms_result = sorted([int_list(x) for x in de_none_list(pl)]) + assert want_set == perms_result + +def test_chialisp_sort_program(): + diag_run_clvm(test_sort_program, Program.to([]), 'test_sort.sym') + +def test_permutations_n(): + for i in range(3,6): + do_test_permutations_of_size_n(i) + +def test_chialisp_permutations_program(): + diag_run_clvm(test_permutations_program, Program.to([3, 5]), 'test_permutations.sym') + +def test_smoke_sort(): + for length in range(7): # 0-7 length + for i in range(1 + (3 * length)): # A few orders each + orig_list = [random.randint(0,100) for x in range(length)] + sort_args = Program.to([orig_list]) + sorted_list = Program.to(sorted(orig_list)) + sort_res = sort_program.run(sort_args) + assert sort_res == sorted_list + +if __name__ == '__main__': + test_smoke_sort() diff --git a/resources/tests/game-referee-in-cl21/test_permutations.clsp b/resources/tests/game-referee-in-cl21/test_permutations.clsp new file mode 100644 index 000000000..d5b6d125f --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_permutations.clsp @@ -0,0 +1,63 @@ +(mod (M N) + (include *standard-cl-21*) + (include prepend.clinc) + (include reverse.clinc) + (include map.clinc) + (include len.clinc) + (include range.clinc) + (include sort.clinc) + (include assert.clinc) + (include deep_compare.clinc) + (include permutations.clinc) + (include last.clinc) + (include busy.clinc) + (include all-in-list.clinc) + (include print.clinc) + + (defun ! (x) + (if x + (* x (! (- x 1))) + 1 + ) + ) + (defun no_repeats_inner ((first . remainder)) + (if remainder + (if (deep= first (f remainder)) + 0 + (no_repeats_inner remainder) + ) + 1 + ) + ) + (defun no_repeats (mylist) + (if mylist + (no_repeats_inner (sort (lambda (a b) (= (deep_compare a b) -1)) mylist)) + 1 + ) + ) + (assert + ;; Is permutations expected to collapse equal alternatives when two of + ;; the items to shuffle are equal? + (= (* (! M) 4) (len (permutations (c 0 (range M))))) + (busy + (lambda (listlen) + (assign + mylist (range listlen) + permed (permutations mylist) + (assert + (= (len permed) (! listlen)) + ;; ensure we didn't produce any permutations that have + ;; repeated elements in them, which would indicate that + ;; the permutation function misbehaved + (all-in-list (map (lambda (L) (no_repeats L)) permed)) + (no_repeats permed) + ) + ) + ) + (reverse (range N)) + 1 + ) + (deep= (permutations 0) (q ())) + 0 + ) +) diff --git a/resources/tests/game-referee-in-cl21/test_permutations.clvm.hex.reference b/resources/tests/game-referee-in-cl21/test_permutations.clvm.hex.reference new file mode 100644 index 000000000..9758d6fd7 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_permutations.clvm.hex.reference @@ -0,0 +1 @@ +ff02ffff01ff02ffff03ffff09ffff12ffff02ff66ffff04ff02ffff04ff05ff80808080ffff010480ffff02ff48ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff04ffff0180ffff02ff58ffff04ff02ffff04ff05ff8080808080ff80808080ff8080808080ffff01ff02ffff01ff02ffff03ffff02ff5affff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200fe80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff02ff50ffff04ff02ffff04ffff02ff58ffff04ff02ffff04ff0bff80808080ff80808080ffff04ffff0101ff808080808080ffff01ff02ffff01ff02ffff03ffff02ff42ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff0180ff80808080ffff04ffff01ff8080ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ffff04ffff01ffffffffffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff40ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ff0bffff01ff02ffff01ff02ff60ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ffff02ff60ffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff70ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ffffff02ffff03ff05ffff01ff02ffff01ff10ffff0101ffff02ff48ffff04ff02ffff04ffff06ff0580ff8080808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ff02ffff03ffff09ff05ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ff05ffff02ff68ffff04ff02ffff04ffff10ff05ffff010180ffff04ff0bff808080808080ff018080ff0180ffff02ff68ffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ff05ffff01ff02ffff01ff02ff78ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ffffffff02ff78ffff04ff02ffff04ff05ffff01ff80ff8080808080ff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff40ffff04ff02ffff04ffff02ff50ffff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff40ffff04ff02ffff04ffff02ff50ffff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff64ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff64ffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ff64ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff4cffff04ff02ffff04ffff06ff0180ffff04ffff02ff44ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ffffff02ff6cffff04ff02ffff04ff03ffff04ffff02ff74ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff74ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ff02ff54ffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ffff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff7cffff04ff02ffff04ffff06ff0180ffff04ffff02ff5cffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff5cffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ffffffffff09ffff02ff5cffff04ff02ffff04ff05ffff04ff0bff8080808080ff8080ff02ffff03ffff20ff0b80ffff01ff02ffff0117ff0180ffff01ff02ffff01ff02ff52ffff04ff02ffff04ffff06ff0180ffff04ffff05ff0b80ffff04ffff06ff0b80ff808080808080ff018080ff0180ffff02ff70ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff7280ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff0bff808080ffff01ff01808080ff80808080ffff04ffff02ff4affff04ff02ffff04ffff02ff40ffff04ff02ffff04ff09ffff04ff17ff8080808080ff80808080ffff04ffff02ff62ffff04ff02ffff04ffff04ff0bff0980ffff04ff17ffff04ff2dff808080808080ff808080808080ff04ff09ff0b80ffffff02ffff03ff05ffff01ff02ffff01ff02ff62ffff04ff02ffff04ffff0180ffff04ff05ffff04ffff0180ff808080808080ff0180ffff01ff02ffff01ff01ff8080ff018080ff0180ff02ffff03ff0dffff01ff02ffff01ff02ff6affff04ff02ffff04ff0dff80808080ff0180ffff01ff02ffff0109ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff02ff6affff04ff02ffff04ffff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff04ffff02ff5affff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff808080808080ffff01808080ff80808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ff05ffff01ff02ffff01ff04ffff04ffff0101ffff05ff058080ffff02ff7affff04ff02ffff04ffff06ff0580ff8080808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ffffffff02ffff04ffff0122ffff02ff7affff04ff02ffff04ff05ff8080808080ff8080ff02ffff03ff05ffff01ff02ffff01ff12ff05ffff02ff66ffff04ff02ffff04ffff11ff05ffff010180ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ffff02ffff03ff0dffff01ff02ffff01ff02ffff03ffff02ff42ffff04ff02ffff04ff09ffff04ffff05ff0d80ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff02ff56ffff04ff02ffff04ff0dff80808080ff018080ff0180ff0180ffff01ff02ffff01ff0101ff018080ff0180ff02ffff03ff05ffff01ff02ffff01ff02ff56ffff04ff02ffff04ffff02ff74ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff05ff8080808080ff80808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ffffff09ffff02ff5cffff04ff02ffff04ff0bffff04ff17ff8080808080ffff0181ff80ff02ff5effff04ff02ffff04ff03ffff04ffff02ff4affff04ff02ffff04ff0bff80808080ff8080808080ffff02ffff03ffff09ffff02ff48ffff04ff02ffff04ff0bff80808080ffff02ff66ffff04ff02ffff04ff29ff8080808080ffff01ff02ffff01ff02ffff03ffff02ff46ffff04ff02ffff04ffff02ff70ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200be80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff0bffff04ffff0180ff808080808080ff80808080ffff01ff02ffff01ff02ff76ffff04ff02ffff04ff0bff80808080ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ffff02ff76ffff04ff02ffff04ff0bff80808080ff02ff6effff04ff02ffff04ffff04ff80ffff04ff0bff808080ffff04ffff02ff58ffff04ff02ffff04ff0bff80808080ff8080808080ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_permutations.sym b/resources/tests/game-referee-in-cl21/test_permutations.sym new file mode 100644 index 000000000..d28b3e38a --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_permutations.sym @@ -0,0 +1 @@ +{"42e1f82cf8542a5f31de7edcd596df9a08e48bcf0aa637f866be044a0c96841f_left_env": "1", "78956ca35a10cbc40b04bd0a14ca12faae5f292d70b9e072da61ef82f3677522": "no_repeats_inner", "9acbd39570d133bd1318e96254949ed3f9d84fb6796324d393b68b898c4999c8_left_env": "1", "ae7e4ed6da640a7bd1e9ef3b1d683440bf9297b217bf0743328f9ae54bbc5b53_arguments": "(reversed rest)", "85c5c955b32be4fef52509b26fe07ce1c3086244572fde3f3bc47636c20f86de": "deep_compare", "93ebb2292470d39d1a556d1294e5da2de17b55aa7d6b591cb885754273777746": "permutations_inner", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_left_env": "1", "19f60e08ef187986cf06532ba696b5b91efeb5c043318b9e6b731f1cd80adf79": "last_inner", "85c5c955b32be4fef52509b26fe07ce1c3086244572fde3f3bc47636c20f86de_arguments": "(a b)", "1c9d01e44e9c5f35a282358422033e4e960609d9f5ef0efc7c7b48bf311208ff_left_env": "1", "0ebdfa3c097ba5b3ef741e8a33b6af2f741209b3e29d94c1c55deb599e4c41d7_left_env": "1", "657a0532257810b1c203d201026eccd16b845b156e25600b57a7ed5429c59682": "no_repeats", "858e89b0997add55f954ceda806d5a77e9914f6d31bed3dedd1e9b67581ee202_arguments": "(@ everything (rest aggl aggr))", "93ebb2292470d39d1a556d1294e5da2de17b55aa7d6b591cb885754273777746_left_env": "1", "42e1f82cf8542a5f31de7edcd596df9a08e48bcf0aa637f866be044a0c96841f_arguments": "(myless A B agg)", "0ebdfa3c097ba5b3ef741e8a33b6af2f741209b3e29d94c1c55deb599e4c41d7": "busy", "e23db45dac9015daa0e667d0d846c354b2b9d9aaa3faedb560854d8662f2e238_arguments": "((() listlen) mylist)", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-in-cl21/test_permutations.clsp", "0871deba30de6d95a0b04a45e6e036162f8abe844ae21b31f7d7cd518845fe9c": "range_inner", "ae7e4ed6da640a7bd1e9ef3b1d683440bf9297b217bf0743328f9ae54bbc5b53": "reverse_inner", "93ebb2292470d39d1a556d1294e5da2de17b55aa7d6b591cb885754273777746_arguments": "(pre post agg)", "a91dc4bec838278871d09bbe4a7206242b852404596d71f8e7962df872da447e_arguments": "(L)", "9fbce34b16a7c4618d5816009b42c6e661cb7efbcaf90314a2f840362f175793": "lambda_$_305", "ae7e4ed6da640a7bd1e9ef3b1d683440bf9297b217bf0743328f9ae54bbc5b53_left_env": "1", "5087819cc352ab86b0b64eebf0a29725fb6306291a42ac51f17253919f7b899c_left_env": "1", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708": "lambda_$_304", "657a0532257810b1c203d201026eccd16b845b156e25600b57a7ed5429c59682_left_env": "1", "9242b5b6b2f9c8d952001db1fbcffc4b477638bf957f6a5dd3a2cc742919c977_arguments": "(vals)", "6c37e5a9ce5bcf0ae750dd4bb1db5898f49d63eadcdf27fbe04c787362459f5d_arguments": "(((() listlen) mylist) permed)", "9acbd39570d133bd1318e96254949ed3f9d84fb6796324d393b68b898c4999c8_arguments": "(F L R)", "1443073ed355cb83607d1c2a6d5612f28a038d3887fa750de973e6aa0ed83f08_arguments": "(myless a b)", "85c5c955b32be4fef52509b26fe07ce1c3086244572fde3f3bc47636c20f86de_left_env": "1", "5087819cc352ab86b0b64eebf0a29725fb6306291a42ac51f17253919f7b899c": "letbinding_$_300", "ae16459987997a1c9872031a855e1dfe8138fde4d1d5b9a5f188d3292ea97565": "sort", "2c82355dea6595dde07e0d5e05aa96b89052c8b97d0e0c868356df4914f2fe68_left_env": "1", "2e3d155705dec0e05e5d4c87c93395ffe98fffe9f21542faca3c5c8751a18047": "deep=", "483fcccf52dd01c7be19ebb1f6ec50a0c235873236a8ab545236771af634b706": "lambda_$_298", "ae16459987997a1c9872031a855e1dfe8138fde4d1d5b9a5f188d3292ea97565_arguments": "(myless mylist)", "a0c582b1c6b05c8a3f5d5d7afd51404b874bb63f21ef73f31c383007fce81e87": "prepend", "7381ec0d3e15950009d8b999a34b828e9964b79470270e7ed6c5409cf2f69bb9_left_env": "1", "6c37e5a9ce5bcf0ae750dd4bb1db5898f49d63eadcdf27fbe04c787362459f5d": "letbinding_$_306", "6c37e5a9ce5bcf0ae750dd4bb1db5898f49d63eadcdf27fbe04c787362459f5d_left_env": "1", "657a0532257810b1c203d201026eccd16b845b156e25600b57a7ed5429c59682_arguments": "(mylist)", "6eb64b0043f60821f8c78916633c5d028164853a0ef677c0b35666673f4163ba_left_env": "1", "02c081d44a600583556699febd4e3bc2eb117b61bd5cfc612c2bf091c952fa0a_left_env": "1", "61f9f86f9df2ce0986b2ae605b74b6111f767e89b83729af6f34110bf65bdeb2": "!", "02c081d44a600583556699febd4e3bc2eb117b61bd5cfc612c2bf091c952fa0a": "len", "a91dc4bec838278871d09bbe4a7206242b852404596d71f8e7962df872da447e_left_env": "1", "9242b5b6b2f9c8d952001db1fbcffc4b477638bf957f6a5dd3a2cc742919c977": "reverse", "858e89b0997add55f954ceda806d5a77e9914f6d31bed3dedd1e9b67581ee202_left_env": "1", "6eb64b0043f60821f8c78916633c5d028164853a0ef677c0b35666673f4163ba_arguments": "((pre_$_275 post_$_276 agg_$_277) myatom newrest)", "5f7a25198045f0621cc78620e8739d731e1761a379e94ee1dae0717e4192e860": "letbinding_$_301", "c6e0bf4deaac4dc5ac02244c56fcaba2652b33bfb38f812ba0a6ef67d3049f61": "permutations", "f8de27975a5aa0f0169626c8874de2ee78c9879c44424bfc1153bc150c6282fe": "range", "5f7a25198045f0621cc78620e8739d731e1761a379e94ee1dae0717e4192e860_arguments": "(((myless_$_257 mylist_$_258) (a b)) sa sb)", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_arguments": "((myatom) x)", "7381ec0d3e15950009d8b999a34b828e9964b79470270e7ed6c5409cf2f69bb9_arguments": "(L)", "bde59c348f4163416518c666a1c5a1d39560d2b09c9b2b38b047e4da574c745e_arguments": "(mylist)", "2e3d155705dec0e05e5d4c87c93395ffe98fffe9f21542faca3c5c8751a18047_left_env": "1", "61f9f86f9df2ce0986b2ae605b74b6111f767e89b83729af6f34110bf65bdeb2_left_env": "1", "2c82355dea6595dde07e0d5e05aa96b89052c8b97d0e0c868356df4914f2fe68": "lambda_$_307", "9fbce34b16a7c4618d5816009b42c6e661cb7efbcaf90314a2f840362f175793_left_env": "1", "483fcccf52dd01c7be19ebb1f6ec50a0c235873236a8ab545236771af634b706_arguments": "(() listlen)", "9acbd39570d133bd1318e96254949ed3f9d84fb6796324d393b68b898c4999c8": "map-with-rest", "1443073ed355cb83607d1c2a6d5612f28a038d3887fa750de973e6aa0ed83f08": "merge", "e23db45dac9015daa0e667d0d846c354b2b9d9aaa3faedb560854d8662f2e238": "letbinding_$_299", "bde59c348f4163416518c666a1c5a1d39560d2b09c9b2b38b047e4da574c745e_left_env": "1", "a0c582b1c6b05c8a3f5d5d7afd51404b874bb63f21ef73f31c383007fce81e87_arguments": "(a b)", "0871deba30de6d95a0b04a45e6e036162f8abe844ae21b31f7d7cd518845fe9c_arguments": "(next final)", "__chia__main_arguments": "(M N)", "bde59c348f4163416518c666a1c5a1d39560d2b09c9b2b38b047e4da574c745e": "split", "02c081d44a600583556699febd4e3bc2eb117b61bd5cfc612c2bf091c952fa0a_arguments": "(L)", "f8de27975a5aa0f0169626c8874de2ee78c9879c44424bfc1153bc150c6282fe_arguments": "(i)", "0871deba30de6d95a0b04a45e6e036162f8abe844ae21b31f7d7cd518845fe9c_left_env": "1", "78956ca35a10cbc40b04bd0a14ca12faae5f292d70b9e072da61ef82f3677522_left_env": "1", "e23db45dac9015daa0e667d0d846c354b2b9d9aaa3faedb560854d8662f2e238_left_env": "1", "c6e0bf4deaac4dc5ac02244c56fcaba2652b33bfb38f812ba0a6ef67d3049f61_left_env": "1", "6eb64b0043f60821f8c78916633c5d028164853a0ef677c0b35666673f4163ba": "letbinding_$_303", "1443073ed355cb83607d1c2a6d5612f28a038d3887fa750de973e6aa0ed83f08_left_env": "1", "61f9f86f9df2ce0986b2ae605b74b6111f767e89b83729af6f34110bf65bdeb2_arguments": "(x)", "a0c582b1c6b05c8a3f5d5d7afd51404b874bb63f21ef73f31c383007fce81e87_left_env": "1", "7381ec0d3e15950009d8b999a34b828e9964b79470270e7ed6c5409cf2f69bb9": "enquote-rest", "ae16459987997a1c9872031a855e1dfe8138fde4d1d5b9a5f188d3292ea97565_left_env": "1", "9fbce34b16a7c4618d5816009b42c6e661cb7efbcaf90314a2f840362f175793_arguments": "(() a b)", "858e89b0997add55f954ceda806d5a77e9914f6d31bed3dedd1e9b67581ee202": "split_inner", "78956ca35a10cbc40b04bd0a14ca12faae5f292d70b9e072da61ef82f3677522_arguments": "((first . remainder))", "f8de27975a5aa0f0169626c8874de2ee78c9879c44424bfc1153bc150c6282fe_left_env": "1", "9242b5b6b2f9c8d952001db1fbcffc4b477638bf957f6a5dd3a2cc742919c977_left_env": "1", "19f60e08ef187986cf06532ba696b5b91efeb5c043318b9e6b731f1cd80adf79_arguments": "((next . remainder))", "2c82355dea6595dde07e0d5e05aa96b89052c8b97d0e0c868356df4914f2fe68_arguments": "(() L)", "483fcccf52dd01c7be19ebb1f6ec50a0c235873236a8ab545236771af634b706_left_env": "1", "5f7a25198045f0621cc78620e8739d731e1761a379e94ee1dae0717e4192e860_left_env": "1", "5087819cc352ab86b0b64eebf0a29725fb6306291a42ac51f17253919f7b899c_arguments": "((myless_$_257 mylist_$_258) (a b))", "a91dc4bec838278871d09bbe4a7206242b852404596d71f8e7962df872da447e": "all-in-list", "42e1f82cf8542a5f31de7edcd596df9a08e48bcf0aa637f866be044a0c96841f": "merge_inner", "1c9d01e44e9c5f35a282358422033e4e960609d9f5ef0efc7c7b48bf311208ff": "letbinding_$_302", "2e3d155705dec0e05e5d4c87c93395ffe98fffe9f21542faca3c5c8751a18047_arguments": "(a b)", "19f60e08ef187986cf06532ba696b5b91efeb5c043318b9e6b731f1cd80adf79_left_env": "1", "0ebdfa3c097ba5b3ef741e8a33b6af2f741209b3e29d94c1c55deb599e4c41d7_arguments": "(myfunc mylist returnval)", "1c9d01e44e9c5f35a282358422033e4e960609d9f5ef0efc7c7b48bf311208ff_arguments": "((a_$_261 b_$_262) inner_result)", "c6e0bf4deaac4dc5ac02244c56fcaba2652b33bfb38f812ba0a6ef67d3049f61_arguments": "(vals)"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/test_prepend.clsp b/resources/tests/game-referee-in-cl21/test_prepend.clsp new file mode 100644 index 000000000..9f0d45819 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_prepend.clsp @@ -0,0 +1,5 @@ +(mod (X Y) + (include *standard-cl-21*) + (include prepend.clinc) + (prepend X Y) + ) diff --git a/resources/tests/game-referee-in-cl21/test_prepend.clvm.hex.reference b/resources/tests/game-referee-in-cl21/test_prepend.clvm.hex.reference new file mode 100644 index 000000000..47dd7f1f1 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_prepend.clvm.hex.reference @@ -0,0 +1 @@ +ff02ffff01ff02ff02ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff04ffff01ff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff02ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_prepend.sym b/resources/tests/game-referee-in-cl21/test_prepend.sym new file mode 100644 index 000000000..368cc453d --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_prepend.sym @@ -0,0 +1 @@ +{"source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-in-cl21/test_prepend.clsp", "dfe61be8d5db02605605573b4d298395c7a871cc5390a79d535d07bbd2338987_left_env": "1", "__chia__main_arguments": "(X Y)", "dfe61be8d5db02605605573b4d298395c7a871cc5390a79d535d07bbd2338987": "prepend", "dfe61be8d5db02605605573b4d298395c7a871cc5390a79d535d07bbd2338987_arguments": "(a b)"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/test_range.clsp b/resources/tests/game-referee-in-cl21/test_range.clsp new file mode 100644 index 000000000..a7dc5edd9 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_range.clsp @@ -0,0 +1,6 @@ +(mod (X) + (include *standard-cl-21*) + (include range.clinc) + + (range X) + ) diff --git a/resources/tests/game-referee-in-cl21/test_range.clvm.hex.reference b/resources/tests/game-referee-in-cl21/test_range.clvm.hex.reference new file mode 100644 index 000000000..628a68fe6 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_range.clvm.hex.reference @@ -0,0 +1 @@ +ff02ffff01ff02ff06ffff04ff02ffff04ff05ff80808080ffff04ffff01ffff02ffff03ffff09ff05ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ff05ffff02ff04ffff04ff02ffff04ffff10ff05ffff010180ffff04ff0bff808080808080ff018080ff0180ff02ff04ffff04ff02ffff04ff80ffff04ff05ff8080808080ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_range.sym b/resources/tests/game-referee-in-cl21/test_range.sym new file mode 100644 index 000000000..fabe9f400 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_range.sym @@ -0,0 +1 @@ +{"0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a_left_env": "1", "6ba774998680757c6e60d6d6e8a94176f76b74e5f8c6f2cf5d99fb134e916556": "range_inner", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-in-cl21/test_range.clsp", "0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a_arguments": "(i)", "6ba774998680757c6e60d6d6e8a94176f76b74e5f8c6f2cf5d99fb134e916556_left_env": "1", "6ba774998680757c6e60d6d6e8a94176f76b74e5f8c6f2cf5d99fb134e916556_arguments": "(next final)", "0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a": "range", "__chia__main_arguments": "(X)"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/test_reverse.clsp b/resources/tests/game-referee-in-cl21/test_reverse.clsp new file mode 100644 index 000000000..b1d843648 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_reverse.clsp @@ -0,0 +1,6 @@ +(mod (X) + (include *standard-cl-21*) + (include reverse.clinc) + + (reverse X) + ) diff --git a/resources/tests/game-referee-in-cl21/test_reverse.clvm.hex.reference b/resources/tests/game-referee-in-cl21/test_reverse.clvm.hex.reference new file mode 100644 index 000000000..492966787 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_reverse.clvm.hex.reference @@ -0,0 +1 @@ +ff02ffff01ff02ff06ffff04ff02ffff04ff05ff80808080ffff04ffff01ffff02ffff03ff0bffff01ff02ffff01ff02ff04ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ff02ff04ffff04ff02ffff04ff80ffff04ff05ff8080808080ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_reverse.sym b/resources/tests/game-referee-in-cl21/test_reverse.sym new file mode 100644 index 000000000..e573ba66a --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_reverse.sym @@ -0,0 +1 @@ +{"0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a_arguments": "(vals)", "893ed9a33d9ef594068ddc5aa4e669dce55ad0e7588062968c1d76ba4c830c01_left_env": "1", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-in-cl21/test_reverse.clsp", "0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a_left_env": "1", "893ed9a33d9ef594068ddc5aa4e669dce55ad0e7588062968c1d76ba4c830c01": "reverse_inner", "0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a": "reverse", "893ed9a33d9ef594068ddc5aa4e669dce55ad0e7588062968c1d76ba4c830c01_arguments": "(reversed rest)", "__chia__main_arguments": "(X)"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/test_sort.clsp b/resources/tests/game-referee-in-cl21/test_sort.clsp new file mode 100644 index 000000000..8185024d0 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_sort.clsp @@ -0,0 +1,37 @@ + +(mod () + (include *standard-cl-21*) + (include print.clinc) + (include sort.clinc) + (include assert.clinc) + (include deep_compare.clinc) + (include reverse.clinc) + (include prepend.clinc) + (include map.clinc) + (include range.clinc) + (include permutations.clinc) + (include last.clinc) + (include busy.clinc) + + (defun try_list (mylist newlist) + (assert (deep= (print "sorted" (sort (lambda (A B) (deep< A B)) newlist)) mylist) 0) + ) + + (defun try_permuted_list (mylist) + (busy (lambda ((& mylist) newlist) (try_list mylist newlist)) + (print "sort all these" (permutations (print "mylist" mylist))) + 0 + ) + ) + (last + (try_list 0 0) + (try_list (range 15) (range 15)) + (try_list (range 15) (reverse (range 15))) + (try_permuted_list (list -1 -1 0 0 2)) + (busy (lambda (i) (try_permuted_list (print "sortme" (range i)))) + (range 4) + 0 + ) + 1 + ) +) diff --git a/resources/tests/game-referee-in-cl21/test_sort.clvm.hex.reference b/resources/tests/game-referee-in-cl21/test_sort.clvm.hex.reference new file mode 100644 index 000000000..4cf09e661 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_sort.clvm.hex.reference @@ -0,0 +1 @@ +ff02ffff01ff02ff66ffff04ff02ffff04ffff04ffff02ff56ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff7e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff02ff4affff04ff02ffff04ffff0104ff80808080ffff04ffff0180ff808080808080ffff04ffff02ff6effff04ff02ffff04ffff04ffff0181ffffff04ffff0181ffffff04ffff0180ffff04ffff0180ffff04ffff0102ffff01808080808080ff80808080ffff04ffff02ff76ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ffff04ffff02ff7cffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ff80808080ff8080808080ffff04ffff02ff76ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ff8080808080ffff04ffff02ff76ffff04ff02ffff04ffff0180ffff04ffff0180ff8080808080ffff04ffff0101ffff0180808080808080ff80808080ffff04ffff01ffffffffff02ffff03ffff22ffff0187247072696e7424ff05ff0b80ffff01ff02ffff010bff0180ffff01ff02ffff010bff018080ff0180ffff02ffff03ff05ffff01ff02ffff01ff02ff50ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ff02ff50ffff04ff02ffff04ff05ffff01ff80ff8080808080ffffff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff22ffff04ff02ffff04ffff02ff7cffff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff22ffff04ff02ffff04ffff02ff7cffff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff48ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff48ffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff02ff48ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ffff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff78ffff04ff02ffff04ffff06ff0180ffff04ffff02ff70ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ff02ff24ffff04ff02ffff04ff03ffff04ffff02ff58ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff58ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ffffff02ff68ffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ffff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff74ffff04ff02ffff04ffff06ff0180ffff04ffff02ff54ffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff54ffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ffffff09ffff02ff54ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff0181ff80ff09ffff02ff54ffff04ff02ffff04ff05ffff04ff0bff8080808080ff8080ffff02ffff03ff0bffff01ff02ffff01ff02ff5cffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ff02ff5cffff04ff02ffff04ff80ffff04ff05ff8080808080ffffffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff22ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff52ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ffff09ff05ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ff05ffff02ff72ffff04ff02ffff04ffff10ff05ffff010180ffff04ff0bff808080808080ff018080ff0180ffffff02ff72ffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ffff20ff0b80ffff01ff02ffff0117ff0180ffff01ff02ffff01ff02ff5affff04ff02ffff04ffff06ff0180ffff04ffff05ff0b80ffff04ffff06ff0b80ff808080808080ff018080ff0180ffff02ff52ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff7a80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff0bff808080ffff01ff01808080ff80808080ffff04ffff02ff46ffff04ff02ffff04ffff02ff22ffff04ff02ffff04ff09ffff04ff17ff8080808080ff80808080ffff04ffff02ff6affff04ff02ffff04ffff04ff0bff0980ffff04ff17ffff04ff2dff808080808080ff808080808080ff04ff09ff0b80ffffffff02ffff03ff05ffff01ff02ffff01ff02ff6affff04ff02ffff04ffff0180ffff04ff05ffff04ffff0180ff808080808080ff0180ffff01ff02ffff01ff01ff8080ff018080ff0180ff02ffff03ff0dffff01ff02ffff01ff02ff66ffff04ff02ffff04ff0dff80808080ff0180ffff01ff02ffff0109ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff02ff66ffff04ff02ffff04ffff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff04ffff02ff56ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff808080808080ffff01808080ff80808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ffff02ff6cffff04ff02ffff04ffff02ff20ffff04ff02ffff04ffff0186736f72746564ffff04ffff02ff58ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ff0bff8080808080ff8080808080ffff04ff05ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ffffff02ff4cffff04ff02ffff04ff0bffff04ff17ff8080808080ff02ff56ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff5e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff05ff808080ffff01ff01808080ff80808080ffff04ffff02ff20ffff04ff02ffff04ffff018e736f727420616c6c207468657365ffff04ffff02ff46ffff04ff02ffff04ffff02ff20ffff04ff02ffff04ffff01866d796c697374ffff04ff05ff8080808080ff80808080ff8080808080ffff01ff808080808080ffff02ff76ffff04ff02ffff04ff09ffff04ff0bff8080808080ff02ff6effff04ff02ffff04ffff02ff20ffff04ff02ffff04ffff0186736f72746d65ffff04ffff02ff4affff04ff02ffff04ff0bff80808080ff8080808080ff80808080ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_sort.sym b/resources/tests/game-referee-in-cl21/test_sort.sym new file mode 100644 index 000000000..6bea76365 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_sort.sym @@ -0,0 +1 @@ +{"e31ef9039be21ebbff9fca105dadf444914415d83cf1f74f6e299ccc760ca58c": "map-with-rest", "bcf06844cee9589ac2df23d9cf5d9a372b71fc3725db9c7249f0db72a2c7fdc3": "reverse", "7aaf175b403f21a9b93e40356ff378a531810f127922e726506b07915393384f": "reverse_inner", "997e0518ff66cefb408f6f6b874f0395ae1399f73650dc57f45d6f4eb79daccc_left_env": "1", "ca9b60a19af98d1290d1161582331f43d6518cbe383dcb87452e253773cf9329_arguments": "(@ everything (rest aggl aggr))", "d2586583545bb886183ab7b08b5c6561b6fdd931d8ee8e12b993d114579e6219_left_env": "1", "1d6bc99de7f858798725d96803a52ef1fa5cf7315c337ea51e560209f7366de5_arguments": "((next . remainder))", "1a3f28c2eeaf6c592d86f46dc96c10910a05739bbeda09e147e67fa64927c6f5_left_env": "1", "aff6f9e4b1d082994645068345db6e378e1839b24b4947111b4fd5d77bef5b4b": "range_inner", "2d2168734160822b5569309f8541a5b632b035f41c89907e79cb1983fc851a7b_arguments": "((myless_$_144 mylist_$_145) (a b))", "e31ef9039be21ebbff9fca105dadf444914415d83cf1f74f6e299ccc760ca58c_arguments": "(F L R)", "131cca40e81a7248781e5edf321f83b96282a9cf4e5ff0151b8dd2fdd5078499": "try_permuted_list", "2a7aff98de69b1fef1b6bc350cb81e2dd99d40254e7f541ef22f8837937ffdbb_left_env": "1", "131cca40e81a7248781e5edf321f83b96282a9cf4e5ff0151b8dd2fdd5078499_arguments": "(mylist)", "d2b16ed82a656d685d88e5e248fe3221b20f9082377d1263d95076bda402dd8d_left_env": "1", "1a3f28c2eeaf6c592d86f46dc96c10910a05739bbeda09e147e67fa64927c6f5": "sort", "b8b601fdb8fab0e12e98d10b1e8169d4209f502a901b4084e2f2c099065460e7_arguments": "(a b)", "02eae9c80ab3ae5e70fcb788e6753ac557297c5b882f6318db705b18b766e872": "letbinding_$_197", "85734bcc0a0243b28bb41bedb69f548a97a473bd3e87b1b5c8acb3a1140ba3d5_left_env": "1", "d155f473544dcda36e0bfa2a3f1579d2e32e251b1b2683a1a1eb73f919eefef2": "letbinding_$_196", "042c55b626937b8d6be258a97f8d25cdedeee2e712dbddef9438fa900eff883e_arguments": "(R P)", "d155f473544dcda36e0bfa2a3f1579d2e32e251b1b2683a1a1eb73f919eefef2_arguments": "(((myless_$_144 mylist_$_145) (a b)) sa sb)", "d5c36bb1c58c5974069b15c197ca27352476f19db460fb8cfa79fc1f35f55b13_left_env": "1", "c5bd34dcdeed87a6c78ea6b36052df8f96895a13a69b4179c15faf9f83ba4560": "lambda_$_201", "d2b16ed82a656d685d88e5e248fe3221b20f9082377d1263d95076bda402dd8d": "merge_inner", "d76bbcd6d3800803e66cb762aa942d5836553c18a50638e3dfcf3deca86f4141": "split", "24c1a323b918bc0b01064cb6171c20899e9d4e4e08a81d7e88013815e7c3fc22": "merge", "6b79b32d680005d302468e9d2c1592335cee3e4e0a454c9ede7653eb17b9c26d_arguments": "(a b)", "7aaf175b403f21a9b93e40356ff378a531810f127922e726506b07915393384f_arguments": "(reversed rest)", "bcf06844cee9589ac2df23d9cf5d9a372b71fc3725db9c7249f0db72a2c7fdc3_left_env": "1", "d76bbcd6d3800803e66cb762aa942d5836553c18a50638e3dfcf3deca86f4141_arguments": "(mylist)", "c5bd34dcdeed87a6c78ea6b36052df8f96895a13a69b4179c15faf9f83ba4560_arguments": "((mylist_$_193) newlist)", "962986191da6874f39aeb123a2daa2d87bd1d8a68f612e83d33070a0315fa3d7": "lambda_$_194", "27306e11834170f40679ff25b0e24deeb74c7a9b32495134103d6f952600b48d_arguments": "(a b)", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708": "lambda_$_199", "ca9b60a19af98d1290d1161582331f43d6518cbe383dcb87452e253773cf9329_left_env": "1", "bcf06844cee9589ac2df23d9cf5d9a372b71fc3725db9c7249f0db72a2c7fdc3_arguments": "(vals)", "e31ef9039be21ebbff9fca105dadf444914415d83cf1f74f6e299ccc760ca58c_left_env": "1", "aff6f9e4b1d082994645068345db6e378e1839b24b4947111b4fd5d77bef5b4b_left_env": "1", "aff6f9e4b1d082994645068345db6e378e1839b24b4947111b4fd5d77bef5b4b_arguments": "(next final)", "27306e11834170f40679ff25b0e24deeb74c7a9b32495134103d6f952600b48d": "deep_compare", "27306e11834170f40679ff25b0e24deeb74c7a9b32495134103d6f952600b48d_left_env": "1", "d2586583545bb886183ab7b08b5c6561b6fdd931d8ee8e12b993d114579e6219_arguments": "(mylist newlist)", "c5bd34dcdeed87a6c78ea6b36052df8f96895a13a69b4179c15faf9f83ba4560_left_env": "1", "1d6bc99de7f858798725d96803a52ef1fa5cf7315c337ea51e560209f7366de5_left_env": "1", "131cca40e81a7248781e5edf321f83b96282a9cf4e5ff0151b8dd2fdd5078499_left_env": "1", "6b79b32d680005d302468e9d2c1592335cee3e4e0a454c9ede7653eb17b9c26d_left_env": "1", "2a7aff98de69b1fef1b6bc350cb81e2dd99d40254e7f541ef22f8837937ffdbb": "busy", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_arguments": "((myatom) x)", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_left_env": "1", "5b656ea16b982e0b3da35bd883c9ff6407dadbbf05faeca2d53f4348dad67679": "prepend", "02eae9c80ab3ae5e70fcb788e6753ac557297c5b882f6318db705b18b766e872_left_env": "1", "962986191da6874f39aeb123a2daa2d87bd1d8a68f612e83d33070a0315fa3d7_arguments": "(() i)", "d155f473544dcda36e0bfa2a3f1579d2e32e251b1b2683a1a1eb73f919eefef2_left_env": "1", "042c55b626937b8d6be258a97f8d25cdedeee2e712dbddef9438fa900eff883e": "print", "997e0518ff66cefb408f6f6b874f0395ae1399f73650dc57f45d6f4eb79daccc_arguments": "(pre post agg)", "7aaf175b403f21a9b93e40356ff378a531810f127922e726506b07915393384f_left_env": "1", "d5c36bb1c58c5974069b15c197ca27352476f19db460fb8cfa79fc1f35f55b13": "letbinding_$_198", "2d2168734160822b5569309f8541a5b632b035f41c89907e79cb1983fc851a7b_left_env": "1", "ca9b60a19af98d1290d1161582331f43d6518cbe383dcb87452e253773cf9329": "split_inner", "6a477b54f8811bb3d5111ee9d39d29db7e3cca8f2521efd80f46dcfd9bc0573b_arguments": "(i)", "d76bbcd6d3800803e66cb762aa942d5836553c18a50638e3dfcf3deca86f4141_left_env": "1", "e9570c55a298e52c75e1ab676bdb601ab3a9939994f3f50be22ce4ebe6a1cc24": "permutations", "d2586583545bb886183ab7b08b5c6561b6fdd931d8ee8e12b993d114579e6219": "try_list", "85734bcc0a0243b28bb41bedb69f548a97a473bd3e87b1b5c8acb3a1140ba3d5_arguments": "(() A B)", "962986191da6874f39aeb123a2daa2d87bd1d8a68f612e83d33070a0315fa3d7_left_env": "1", "997e0518ff66cefb408f6f6b874f0395ae1399f73650dc57f45d6f4eb79daccc": "permutations_inner", "1d6bc99de7f858798725d96803a52ef1fa5cf7315c337ea51e560209f7366de5": "last_inner", "24c1a323b918bc0b01064cb6171c20899e9d4e4e08a81d7e88013815e7c3fc22_left_env": "1", "d5c36bb1c58c5974069b15c197ca27352476f19db460fb8cfa79fc1f35f55b13_arguments": "((pre_$_176 post_$_177 agg_$_178) myatom newrest)", "6a477b54f8811bb3d5111ee9d39d29db7e3cca8f2521efd80f46dcfd9bc0573b_left_env": "1", "b8b601fdb8fab0e12e98d10b1e8169d4209f502a901b4084e2f2c099065460e7_left_env": "1", "1a3f28c2eeaf6c592d86f46dc96c10910a05739bbeda09e147e67fa64927c6f5_arguments": "(myless mylist)", "__chia__main_arguments": "()", "e9570c55a298e52c75e1ab676bdb601ab3a9939994f3f50be22ce4ebe6a1cc24_arguments": "(vals)", "d2b16ed82a656d685d88e5e248fe3221b20f9082377d1263d95076bda402dd8d_arguments": "(myless A B agg)", "02eae9c80ab3ae5e70fcb788e6753ac557297c5b882f6318db705b18b766e872_arguments": "((a_$_148 b_$_149) inner_result)", "b8b601fdb8fab0e12e98d10b1e8169d4209f502a901b4084e2f2c099065460e7": "deep=", "24c1a323b918bc0b01064cb6171c20899e9d4e4e08a81d7e88013815e7c3fc22_arguments": "(myless a b)", "5b656ea16b982e0b3da35bd883c9ff6407dadbbf05faeca2d53f4348dad67679_arguments": "(a b)", "6b79b32d680005d302468e9d2c1592335cee3e4e0a454c9ede7653eb17b9c26d": "deep<", "5b656ea16b982e0b3da35bd883c9ff6407dadbbf05faeca2d53f4348dad67679_left_env": "1", "042c55b626937b8d6be258a97f8d25cdedeee2e712dbddef9438fa900eff883e_left_env": "1", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-in-cl21/test_sort.clsp", "85734bcc0a0243b28bb41bedb69f548a97a473bd3e87b1b5c8acb3a1140ba3d5": "lambda_$_200", "2d2168734160822b5569309f8541a5b632b035f41c89907e79cb1983fc851a7b": "letbinding_$_195", "2a7aff98de69b1fef1b6bc350cb81e2dd99d40254e7f541ef22f8837937ffdbb_arguments": "(myfunc mylist returnval)", "6a477b54f8811bb3d5111ee9d39d29db7e3cca8f2521efd80f46dcfd9bc0573b": "range", "e9570c55a298e52c75e1ab676bdb601ab3a9939994f3f50be22ce4ebe6a1cc24_left_env": "1"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/testnoncegame.py b/resources/tests/game-referee-in-cl21/testnoncegame.py new file mode 100644 index 000000000..3b4cd2c2a --- /dev/null +++ b/resources/tests/game-referee-in-cl21/testnoncegame.py @@ -0,0 +1,33 @@ +import hashlib + +from hsms.streamables.program import Program + +from clvm.EvalError import EvalError + +noncegame = Program.from_bytes(bytes.fromhex(open("noncegame.clvm.hex").read())) +noncehash = noncegame.tree_hash() + +def drun(prog: Program, args: Program): + try: + return prog.run(args) + except EvalError as ee: + print(f"brun -x -y main.sym {prog} {Program.to(args)}") + raise + +def testnonce(startnonce, maxnonce): + for i in range(startnonce, maxnonce): + mygame = noncegame.curry(i, noncehash) + good_parameters = [i*2, noncegame.curry(i+1, noncehash).tree_hash(), 1, (i*4, b'g')] + bad_parameters = [i*3, noncegame.curry(i+2, noncehash).tree_hash(), 2, (i*5, b'g')] + assert drun(mygame, good_parameters) == b'g' + for j in range(len(good_parameters)): + try: + p = list(good_parameters) + p[j] = bad_parameters[j] + mygame.run(p) + assert False + except EvalError as ee: + pass + +if __name__ == '__main__': + testnonce(3, 7) diff --git a/resources/tests/game-referee-in-cl21/testreferee.py b/resources/tests/game-referee-in-cl21/testreferee.py new file mode 100644 index 000000000..01eb53643 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/testreferee.py @@ -0,0 +1,479 @@ +import pytest +from hashlib import sha256 +from contextlib import asynccontextmanager +from chia.clvm.spend_sim import SimClient, SpendSim +from pathlib import Path +from clvm.casts import int_to_bytes, int_from_bytes + +from hsms.streamables.program import Program +from clvm_tools_rs import compile_clvm +from clvm_tools.binutils import disassemble + +from clvm.EvalError import EvalError +from chia.types.mempool_inclusion_status import MempoolInclusionStatus +from chia.util.errors import Err +from dataclasses import dataclass +from typing import Any +from chia_rs import Coin +from chia.types.spend_bundle import SpendBundle +from chia.types.coin_spend import CoinSpend +from blspy import G2Element + +from steprun import diag_run_clvm, compile_module_with_symbols + +compile_module_with_symbols(['.'],'referee.clsp') +referee = Program.from_bytes(bytes.fromhex(open("referee.clvm.hex").read())) +refhash = referee.tree_hash() +compile_module_with_symbols(['.'],'referee_accuse.clsp') +referee_accuse = Program.from_bytes(bytes.fromhex(open("referee_accuse.clvm.hex").read())) +refaccusehash = referee.tree_hash() +compile_clvm('rockpaperscissorsa.clsp', 'rockpaperscissorsa.clvm.hex', ['.']) +MOD_A = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsa.clvm.hex").read())) +compile_clvm('rockpaperscissorsb.clsp', 'rockpaperscissorsb.clvm.hex', ['.']) +MOD_B = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsb.clvm.hex").read())) +compile_clvm('rockpaperscissorsc.clsp', 'rockpaperscissorsc.clvm.hex', ['.']) +MOD_C = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsc.clvm.hex").read())) +compile_clvm('rockpaperscissorsd.clsp', 'rockpaperscissorsd.clvm.hex', ['.']) +MOD_D = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsd.clvm.hex").read())) + +move = 0 +accuse = 1 +timeout = 2 + +def drun(prog: Program, *args: Program): + try: + return prog.run(*args) + except EvalError as ee: + print(f"brun -x -y main.sym {prog} {Program.to(list(args))}") + raise + +def sha(blob:bytes) -> bytes: + return sha256(blob).digest() + +@pytest.fixture(scope="function") +@asynccontextmanager +async def setup_sim() : + sim = await SpendSim.create(db_path=Path("file:db_test?mode=memory&cache=shared")) + sim_client = SimClient(sim) + await sim.farm_block() + + try: + yield sim, sim_client + finally: + await sim.close() + +def bootstrap_referee(parent_coin_id, initial_validation_program_hash, initial_split, + amount, timeout, max_move_size, mover_puzzle, waiter_puzzle): + """ + returns referee_wrap + """ + puzzle_hash = referee.curry( + [initial_validation_program_hash, 0, initial_split, amount, timeout, max_move_size, mover_puzzle.tree_hash(), + waiter_puzzle.tree_hash(), referee.tree_hash()]).tree_hash() + coin = Coin(parent_coin_id, puzzle_hash, amount) + return RefereeWrap(coin, bytes(32), bytes(32), bytes(32), + initial_validation_program_hash, 0, initial_split, timeout, max_move_size, + mover_puzzle, waiter_puzzle) + +@dataclass +class RefereeWrap: + coin: Any + grandparent_id: Any + parent_validation_program_hash: Any + parent_everything_else_hash: Any + validation_program_hash: Any + move: Any + split: Any + timeout: Any + max_move_size: Any + mover_puzzle: Any + waiter_puzzle: Any + + def curried_parameters_for_our_puzzle(self, purpose, for_self, move_to_make, split, validation_program_hash): + result = Program.to([ + validation_program_hash, + move_to_make, + split, + self.coin.amount, + self.timeout, + self.max_move_size, + self.mover_puzzle.tree_hash() if for_self else self.waiter_puzzle.tree_hash(), + self.waiter_puzzle.tree_hash() if for_self else self.mover_puzzle.tree_hash(), + refhash + ]) + print(f'for {purpose} curried_parameters_for_our_puzzle is {result}') + return result + + def get_puzzle(self): + return referee.curry(self.curried_parameters_for_our_puzzle( + "GET_PUZZLE", + True, + self.move, + self.split, + self.validation_program_hash + )) + + def SpendMove(self, password, move_to_make, split, validation_program_hash): + """ + returns (solution, new RefereeWrap) + """ + print(f"MOVE referee mover_puzzle {self.mover_puzzle.tree_hash()}") + print(f"MOVE referee waiter_puzzle {self.waiter_puzzle.tree_hash()}") + curried_parameters = self.curried_parameters_for_our_puzzle( + "SPEND_MOVE", + False, + move_to_make, + split, + validation_program_hash + ) + print(f"MOVE referee curried parameters {curried_parameters}") + new_puzzle_hash = referee.curry(curried_parameters).tree_hash() + print(f"MOVE new puzzle hash {Program.to(new_puzzle_hash)}") + solution = Program.to([move, move_to_make, split, validation_program_hash, self.mover_puzzle, + [password, [51, new_puzzle_hash, self.coin.amount]]]) + coin = Coin(self.coin.name(), new_puzzle_hash, self.coin.amount) + everything_else_hash = Program.to([self.move, self.split, self.coin.amount, self.timeout, + self.max_move_size, self.mover_puzzle.tree_hash(), self.waiter_puzzle.tree_hash(), + referee.tree_hash()]).tree_hash() + return (solution, RefereeWrap(coin, self.coin.parent_coin_info, self.validation_program_hash, everything_else_hash, + validation_program_hash, move_to_make, split, self.timeout, self.max_move_size, + self.waiter_puzzle, self.mover_puzzle)) + + def SpendAccuse(self, password): + """ + returns (solution, RefereeAccuse) + """ + print(f"ACCUSE starting with puzzle hash {Program.to(self.get_puzzle().tree_hash())}") + print(f"ACCUSE parent_id {Program.to(self.coin.parent_coin_info)}") + print(f"ACCUSE referee mover_puzzle {self.mover_puzzle.tree_hash()}") + print(f"ACCUSE referee waiter_puzzle {self.waiter_puzzle.tree_hash()}") + new_puzzle_hash = referee_accuse.curry([ + self.parent_validation_program_hash, + self.validation_program_hash, + self.move, + self.split, + self.coin.amount, + self.timeout, + self.waiter_puzzle.tree_hash(), + self.mover_puzzle.tree_hash() + ]).tree_hash() + solution = Program.to([accuse, self.grandparent_id, self.parent_validation_program_hash, + self.parent_everything_else_hash, self.mover_puzzle, [password, [51, new_puzzle_hash, self.coin.amount]]]) + coin = Coin(self.coin.name(), new_puzzle_hash, self.coin.amount) + return (solution, RefereeAccuseWrap(coin, self.parent_validation_program_hash, self.validation_program_hash, + self.move, self.split, self.timeout, self.waiter_puzzle.tree_hash(), + self.mover_puzzle.tree_hash())) + + def SpendTimeout(self): + """ + returns (solution, movercoinid, waitercoinid) + """ + movercoinid = Coin(self.coin.name(), self.mover_puzzle.tree_hash(), self.split).name() + waitercoinid = Coin(self.coin.name(), self.waiter_puzzle.tree_hash(), + self.coin.amount - self.split).name() + return (Program.to((timeout, 0)), movercoinid, waitercoinid) + +@dataclass +class RefereeAccuseWrap: + coin: Any + old_validation_puzzle_hash: Any + new_validation_puzzle_hash: Any + move: Any + split: Any + timeout: Any + accused_puzzle_hash: Any + accuser_puzzle_hash: Any + + def get_puzzle(self): + return referee_accuse.curry([self.old_validation_puzzle_hash, self.new_validation_puzzle_hash, + self.move, self.split, self.coin.amount, self.timeout, self.accused_puzzle_hash, + self.accuser_puzzle_hash]) + + def SpendTimeout(self): + """ + returns (solution, coinid) + """ + coin = Coin(self.coin.name(), self.accuser_puzzle_hash, self.coin.amount) + return (Program.to(0), coin.name()) + + def SpendDefend(self, validation_program_reveal, validation_program_solution): + """ + returns (solution, coinid) + """ + solution = Program.to([validation_program_reveal, validation_program_solution]) + coin = Coin(self.coin.name(), self.accused_puzzle_hash, self.coin.amount) + return (solution, coin.name()) + +@pytest.mark.asyncio +@pytest.mark.parametrize('amove', [0, 1, 2]) +@pytest.mark.parametrize('bmove', [0, 1, 2]) +async def test_rps(amove, bmove, setup_sim): + total = 100 + alice_final = (total//2 if amove == bmove else (0 if bmove == (amove + 1) % 3 else total)) + alice_preimage = int_to_bytes(60 + amove) + alice_image = sha(alice_preimage) + bob_preimage = int_to_bytes(60 + bmove) + bob_image = sha(bob_preimage) + alice_move = int_to_bytes(amove) + nil = Program.to(0) + + # (mod (password . conditions) (if (= password 'alice') conditions (x))) + alice_puzzle = Program.from_bytes(bytes.fromhex('ff02ffff03ffff09ff02ffff0185616c69636580ffff0103ffff01ff088080ff0180')) + alice_puzzle_hash = alice_puzzle.tree_hash() + # (mod (password . conditions) (if (= password 'bob') conditions (x))) + bob_puzzle = Program.from_bytes(bytes.fromhex('ff02ffff03ffff09ff02ffff0183626f6280ffff0103ffff01ff088080ff0180')) + bob_puzzle_hash = bob_puzzle.tree_hash() + + async with setup_sim as (sym, client): + acs = Program.to(1) + acs_hash = acs.tree_hash() + await sym.farm_block(acs_hash) + mycoin = (await client.get_coin_records_by_puzzle_hashes([acs_hash], include_spent_coins = False))[0].coin + # make a coin for a game + referee = bootstrap_referee(mycoin.name(), MOD_A.tree_hash(), 2, total, 1000, 50, alice_puzzle, bob_puzzle) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(mycoin, acs, Program.to([[51, referee.coin.puzzle_hash, + referee.coin.amount]]))], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Alice accuse Bob of cheating (negative test, should fail) + solution, accuse = referee.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.ASSERT_MY_PARENT_ID_FAILED + # timeout too early fail + solution, alice_reward_id, bob_reward_id = referee.SpendTimeout() + spend = SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), solution)], G2Element()) + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.ASSERT_SECONDS_RELATIVE_FAILED + # timeout succeeds + sym.pass_time(2000) + await sym.farm_block() + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.SUCCESS + assert err is None + await sym.farm_block() + assert (await client.get_coin_records_by_names([alice_reward_id], include_spent_coins = False))[0].coin.amount == 2 + assert (await client.get_coin_records_by_names([bob_reward_id], include_spent_coins = False))[0].coin.amount == total - 2 + await sym.rewind(savepoint) + # Alice makes an illegally large move, fails + solution, ref2 = referee.SpendMove('alice', bytes(100), 0, bytes(32)) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # Alice makes move with negative split, fails + solution, ref2 = referee.SpendMove('alice', 'abc', -1, bytes(32)) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # Alice makes move with split greater than amount, fails + solution, ref2 = referee.SpendMove('alice', 'abc', referee.coin.amount + 1, bytes(32)) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # Alice move 1 commit to image + bpuz = MOD_B.curry(alice_image) + solution, ref2 = referee.SpendMove('alice', alice_image, 0, bpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Bob accuse Alice of cheating + solution, accuse = ref2.SpendAccuse('bob') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref2.coin, ref2.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint2 = sym.block_height + # Alice accusation defend, gets everything + solution, reward_id = accuse.SpendDefend(MOD_A, nil) + print(solution) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + reward_coin_wrapper = await client.get_coin_records_by_names([reward_id], include_spent_coins = + False) + reward_coin = reward_coin_wrapper[0].coin + assert reward_coin.amount == referee.coin.amount + assert reward_coin.puzzle_hash == alice_puzzle_hash + await sym.rewind(savepoint2) + # accusation timeout too early fail + solution, reward_id = accuse.SpendTimeout() + spend = SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), solution)], G2Element()) + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.ASSERT_SECONDS_RELATIVE_FAILED + # accusation timeout succeed, Bob gets everything + sym.pass_time(2000) + await sym.farm_block() + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.SUCCESS + assert err is None + await sym.farm_block() + reward_coin_wrapper = await client.get_coin_records_by_names([reward_id], include_spent_coins = + False) + reward_coin = reward_coin_wrapper[0].coin + assert reward_coin.amount == referee.coin.amount + assert reward_coin.puzzle_hash == bob_puzzle_hash + await sym.rewind(savepoint) + # Bob move 2 commit to image + cpuz = MOD_C.curry([alice_image, bob_image]) + solution, ref3 = ref2.SpendMove('bob', bob_image, 0, cpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref2.coin, ref2.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Alice accuse + solution, accuse = ref3.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref3.coin, ref3.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob defends + solution, reward_id = accuse.SpendDefend(bpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + reward_coin = (await client.get_coin_records_by_names([reward_id], include_spent_coins = + False))[0].coin + assert reward_coin.amount == referee.coin.amount + assert reward_coin.puzzle_hash == bob_puzzle_hash + await sym.rewind(savepoint) + # Alice reveals wrong preimage + alice_bad_preimage = int_to_bytes(61 + amove) + dpuz = MOD_D.curry([(amove + 1) % 3, bob_image]) + solution, ref4 = ref3.SpendMove('alice', alice_bad_preimage, 0, dpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref3.coin, ref3.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob accuses + solution, accuse = ref4.SpendAccuse('bob') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Alice defends, fails + solution, reward_id = accuse.SpendDefend(cpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + await sym.rewind(savepoint) + # Alice move 3 reveal preimage + dpuz = MOD_D.curry([alice_move, bob_image]) + solution, ref4 = ref3.SpendMove('alice', alice_preimage, 0, dpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref3.coin, ref3.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Bob accuses + solution, accuse = ref4.SpendAccuse('bob') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Alice defends + solution, reward_id = accuse.SpendDefend(cpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.rewind(savepoint) + # Bob move 4 reveal wrong preimage + bob_bad_preimage = int_to_bytes(121 + amove) + solution, ref5 = ref4.SpendMove('bob', bob_bad_preimage, 0, dpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Alice accuses + solution, accuse = ref5.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob attempts defense, fails + solution, reward_id = accuse.SpendDefend(dpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # Bob attempts defense with wrong validation program, fails + solution, reward_id = accuse.SpendDefend(acs, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + await sym.rewind(savepoint) + if amove == bmove: + # Bob move 4 gives wrong split + solution, ref5 = ref4.SpendMove('bob', bob_preimage, 0, dpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Alice accuses + solution, accuse = ref5.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob attempts defense, fails + solution, reward_id = accuse.SpendDefend(dpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + await sym.rewind(savepoint) + # Bob move 4 reveal preimage + solution, ref5 = ref4.SpendMove('bob', bob_preimage, alice_final, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Alice attempts move, fails + solution, ref6 = ref5.SpendMove('alice', nil, 0, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # timeout, split correct + sym.pass_time(2000) + await sym.farm_block() + solution, alice_reward_id, bob_reward_id = ref5.SpendTimeout() + spend = SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), solution)], G2Element()) + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.SUCCESS + assert err is None + await sym.farm_block() + if alice_final != 0: + assert (await client.get_coin_records_by_names([alice_reward_id], include_spent_coins = False))[0].coin.amount == alice_final + else: + assert len(await client.get_coin_records_by_names([alice_reward_id], include_spent_coins = False)) == 0 + if alice_final != ref5.coin.amount: + assert (await client.get_coin_records_by_names([bob_reward_id], include_spent_coins = False))[0].coin.amount == ref5.coin.amount - alice_final + else: + assert len(await client.get_coin_records_by_names([bob_reward_id], include_spent_coins = False)) == 0 + await sym.rewind(savepoint) + # Alice accuses + solution, accuse = ref5.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob defends + solution, reward_id = accuse.SpendDefend(dpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert (status, err) == (MempoolInclusionStatus.SUCCESS, None) diff --git a/resources/tests/game-referee-in-cl21/testrockpaperscissors.py b/resources/tests/game-referee-in-cl21/testrockpaperscissors.py new file mode 100644 index 000000000..ed45dbccc --- /dev/null +++ b/resources/tests/game-referee-in-cl21/testrockpaperscissors.py @@ -0,0 +1,48 @@ +import hashlib + +from hsms.streamables.program import Program +from hsms.puzzles.load_clvm import load_clvm + +from clvm.EvalError import EvalError + + +MOD_A = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsa.clvm.hex").read())) +MOD_B = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsb.clvm.hex").read())) +MOD_C = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsc.clvm.hex").read())) +MOD_D = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsd.clvm.hex").read())) + + +def drun(prog: Program, *args: Program): + try: + return prog.run(*args) + except EvalError as ee: + print(f"brun -x -y main.sym {prog} {Program.to(list(args))}") + raise + +def sha256(blob:bytes) -> bytes: + return hashlib.sha256(blob).digest() + +def testrps(amove, bmove): + total = 100 + alice_final = (total//2 if amove == bmove else (0 if bmove == (amove + 1) % 3 else total)) + alice_preimage = Program.to(60 + amove) + bob_preimage = Program.to(60 + bmove) + alice_image = sha256(alice_preimage.atom) + bob_image = sha256(bob_preimage.atom) + alice_move = Program.to(amove) + + cd = MOD_D.curry(alice_move, bob_image) + assert cd.run([total, bob_preimage, b'', alice_final, b'j']).atom == b'j' + cc = MOD_C.curry(alice_image, bob_image) + assert cc.run([total, alice_preimage, cd.tree_hash(), 0, b'j']).atom == b'j' + cb = MOD_B.curry(alice_image) + assert cb.run([total, bob_image, cc.tree_hash(), 0, b'j']).atom == b'j' + assert MOD_A.run([total, alice_image, cb.tree_hash(), 0, b'j']).atom == b'j' + +def testall(): + for i in range(3): + for j in range(3): + testrps(i, j) + +if __name__ == '__main__': + testall() diff --git a/resources/tests/game-referee-in-cl21/utils.clinc b/resources/tests/game-referee-in-cl21/utils.clinc new file mode 100644 index 000000000..7d754e001 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/utils.clinc @@ -0,0 +1,17 @@ +( + (defmacro ifc ARGS + (defun list-length (lst) + (if (l lst) + (+ 1 (list-length (r lst))) + 0 + ) + ) + (defun do-continued-if (ARGS) + (if (= (list-length ARGS) 3) + (qq (i (unquote (f ARGS)) (com (unquote (f (r ARGS)))) (com (unquote (f (r (r ARGS))))))) + (qq (i (unquote (f ARGS)) (com (unquote (f (r ARGS)))) (unquote (do-continued-if (r (r ARGS)))))) + ) + ) + (qq (a (unquote (do-continued-if ARGS)) @)) + ) +) diff --git a/resources/tests/lib/__init__.py b/resources/tests/lib/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/resources/tests/lib/load_clvm.py b/resources/tests/lib/load_clvm.py new file mode 100644 index 000000000..a01f37fbc --- /dev/null +++ b/resources/tests/lib/load_clvm.py @@ -0,0 +1,168 @@ +from __future__ import annotations + +import importlib +import inspect +import os +import pathlib +import sys +import tempfile +from typing import List + +import pkg_resources +from clvm_tools_rs import compile_clvm as compile_clvm_rust + +from chia.types.blockchain_format.program import Program +from chia.types.blockchain_format.serialized_program import SerializedProgram +from chia.util.lock import Lockfile + +compile_clvm_py = None + +recompile_requested = ( + (os.environ.get("CHIA_DEV_COMPILE_CLVM_ON_IMPORT", "") != "") or ("pytest" in sys.modules) +) and os.environ.get("CHIA_DEV_COMPILE_CLVM_DISABLED", None) is None + + +def translate_path(p_): + p = str(p_) + if os.path.isdir(p): + return p + else: + module_object = importlib.import_module(p) + return os.path.dirname(inspect.getfile(module_object)) + + +# Handle optional use of python clvm_tools if available and requested +if "CLVM_TOOLS" in os.environ: + try: + from clvm_tools.clvmc import compile_clvm as compile_clvm_py_candidate + + compile_clvm_py = compile_clvm_py_candidate + finally: + pass + + +def compile_clvm_in_lock(full_path: pathlib.Path, output: pathlib.Path, search_paths: List[pathlib.Path]): + # Compile using rust (default) + + # Ensure path translation is done in the idiomatic way currently + # expected. It can use either a filesystem path or name a python + # module. + treated_include_paths = list(map(translate_path, search_paths)) + res = compile_clvm_rust(str(full_path), str(output), treated_include_paths) + + if "CLVM_TOOLS" in os.environ and os.environ["CLVM_TOOLS"] == "check" and compile_clvm_py is not None: + # Simple helper to read the compiled output + def sha256file(f): + import hashlib + + m = hashlib.sha256() + m.update(open(f).read().strip().encode("utf8")) + return m.hexdigest() + + orig = "%s.orig" % output + + compile_clvm_py(full_path, orig, search_paths=search_paths) + orig256 = sha256file(orig) + rs256 = sha256file(output) + + if orig256 != rs256: + print("Compiled original %s: %s vs rust %s\n" % (full_path, orig256, rs256)) + print("Aborting compilation due to mismatch with rust") + assert orig256 == rs256 + else: + print("Compilation match %s: %s\n" % (full_path, orig256)) + + return res + + +def compile_clvm(full_path: pathlib.Path, output: pathlib.Path, search_paths: List[pathlib.Path] = []): + with Lockfile.create(pathlib.Path(tempfile.gettempdir()) / "clvm_compile" / full_path.name): + compile_clvm_in_lock(full_path, output, search_paths) + + +def load_serialized_clvm( + clvm_filename, package_or_requirement=__name__, include_standard_libraries: bool = False, recompile: bool = True +) -> SerializedProgram: + """ + This function takes a .clsp file in the given package and compiles it to a + .clsp.hex file if the .hex file is missing or older than the .clsp file, then + returns the contents of the .hex file as a `Program`. + + clvm_filename: file name + package_or_requirement: usually `__name__` if the clvm file is in the same package + """ + hex_filename = f"{clvm_filename}.hex" + + # Set the CHIA_DEV_COMPILE_CLVM_ON_IMPORT environment variable to anything except + # "" or "0" to trigger automatic recompilation of the Chialisp on load. + if recompile: + try: + if pkg_resources.resource_exists(package_or_requirement, clvm_filename): + # Establish whether the size is zero on entry + full_path = pathlib.Path(pkg_resources.resource_filename(package_or_requirement, clvm_filename)) + output = full_path.parent / hex_filename + if not output.exists() or os.stat(full_path).st_mtime > os.stat(output).st_mtime: + search_paths = [full_path.parent] + if include_standard_libraries: + # we can't get the dir, but we can get a file then get its parent. + chia_puzzles_path = pathlib.Path( + pkg_resources.resource_filename(__name__, "__init__.py") + ).parent + search_paths.append(chia_puzzles_path) + compile_clvm(full_path, output, search_paths=search_paths) + + except NotImplementedError: + # pyinstaller doesn't support `pkg_resources.resource_exists` + # so we just fall through to loading the hex clvm + pass + + clvm_hex = pkg_resources.resource_string(package_or_requirement, hex_filename).decode("utf8") + assert len(clvm_hex.strip()) != 0 + clvm_blob = bytes.fromhex(clvm_hex) + return SerializedProgram.from_bytes(clvm_blob) + + +def load_clvm( + clvm_filename, + package_or_requirement=__name__, + include_standard_libraries: bool = False, + recompile: bool = True, +) -> Program: + return Program.from_bytes( + bytes( + load_serialized_clvm( + clvm_filename, + package_or_requirement=package_or_requirement, + include_standard_libraries=include_standard_libraries, + recompile=recompile, + ) + ) + ) + + +def load_clvm_maybe_recompile( + clvm_filename, + package_or_requirement=__name__, + include_standard_libraries: bool = False, + recompile: bool = recompile_requested, +) -> Program: + return load_clvm( + clvm_filename=clvm_filename, + package_or_requirement=package_or_requirement, + include_standard_libraries=include_standard_libraries, + recompile=recompile, + ) + + +def load_serialized_clvm_maybe_recompile( + clvm_filename, + package_or_requirement=__name__, + include_standard_libraries: bool = False, + recompile: bool = recompile_requested, +) -> SerializedProgram: + return load_serialized_clvm( + clvm_filename=clvm_filename, + package_or_requirement=package_or_requirement, + include_standard_libraries=include_standard_libraries, + recompile=recompile, + ) diff --git a/resources/tests/lib/program.py b/resources/tests/lib/program.py new file mode 100644 index 000000000..eff5badd0 --- /dev/null +++ b/resources/tests/lib/program.py @@ -0,0 +1,231 @@ +from __future__ import annotations + +import io +from typing import Any, Callable, Dict, Set, Tuple + +from chia_rs import run_chia_program, tree_hash +from clvm import SExp +from clvm.casts import int_from_bytes +from clvm.EvalError import EvalError +from clvm.serialize import sexp_from_stream, sexp_to_stream + +from chia.types.blockchain_format.sized_bytes import bytes32 +from chia.util.byte_types import hexstr_to_bytes +from chia.util.hash import std_hash + +from .tree_hash import sha256_treehash + +INFINITE_COST = 11000000000 + + +class Program(SExp): + """ + A thin wrapper around s-expression data intended to be invoked with "eval". + """ + + @classmethod + def parse(cls, f) -> "Program": + return sexp_from_stream(f, cls.to) + + def stream(self, f): + sexp_to_stream(self, f) + + @classmethod + def from_bytes(cls, blob: bytes) -> Program: + # this runs the program "1", which just returns the first argument. + # the first argument is the buffer we want to parse. This effectively + # leverages the rust parser and LazyNode, making it a lot faster to + # parse serialized programs into a python compatible structure + cost, ret = run_chia_program( + b"\x01", + blob, + 50, + 0, + ) + return Program.to(ret) + + @classmethod + def fromhex(cls, hexstr: str) -> "Program": + return cls.from_bytes(hexstr_to_bytes(hexstr)) + + def __bytes__(self) -> bytes: + f = io.BytesIO() + self.stream(f) # noqa + return f.getvalue() + + def __str__(self) -> str: + return bytes(self).hex() + + def at(self, position: str) -> "Program": + """ + Take a string of only `f` and `r` characters and follow the corresponding path. + + Example: + + `assert Program.to(17) == Program.to([10, 20, 30, [15, 17], 40, 50]).at("rrrfrf")` + + """ + v = self + for c in position.lower(): + if c == "f": + v = v.first() + elif c == "r": + v = v.rest() + else: + raise ValueError(f"`at` got illegal character `{c}`. Only `f` & `r` allowed") + return v + + def replace(self, **kwargs) -> "Program": + """ + Create a new program replacing the given paths (using `at` syntax). + Example: + ``` + >>> p1 = Program.to([100, 200, 300]) + >>> print(p1.replace(f=105) == Program.to([105, 200, 300])) + True + >>> print(p1.replace(rrf=[301, 302]) == Program.to([100, 200, [301, 302]])) + True + >>> print(p1.replace(f=105, rrf=[301, 302]) == Program.to([105, 200, [301, 302]])) + True + ``` + + This is a convenience method intended for use in the wallet or command-line hacks where + it would be easier to morph elements of an existing clvm object tree than to rebuild + one from scratch. + + Note that `Program` objects are immutable. This function returns a new object; the + original is left as-is. + """ + return _sexp_replace(self, self.to, **kwargs) + + def get_tree_hash_precalc(self, *args: bytes32) -> bytes32: + """ + Any values in `args` that appear in the tree + are presumed to have been hashed already. + """ + return sha256_treehash(self, set(args)) + + def get_tree_hash(self) -> bytes32: + return bytes32(tree_hash(bytes(self))) + + def run_with_cost(self, max_cost: int, args) -> Tuple[int, "Program"]: + prog_args = Program.to(args) + cost, r = run_chia_program(self.as_bin(), prog_args.as_bin(), max_cost, 0) + return cost, Program.to(r) + + def run(self, args) -> "Program": + cost, r = self.run_with_cost(INFINITE_COST, args) + return r + + # Replicates the curry function from clvm_tools, taking advantage of *args + # being a list. We iterate through args in reverse building the code to + # create a clvm list. + # + # Given arguments to a function addressable by the '1' reference in clvm + # + # fixed_args = 1 + # + # Each arg is prepended as fixed_args = (c (q . arg) fixed_args) + # + # The resulting argument list is interpreted with apply (2) + # + # (2 (1 . self) rest) + # + # Resulting in a function which places its own arguments after those + # curried in in the form of a proper list. + def curry(self, *args) -> "Program": + fixed_args: Any = 1 + for arg in reversed(args): + fixed_args = [4, (1, arg), fixed_args] + return Program.to([2, (1, self), fixed_args]) + + def uncurry(self) -> Tuple[Program, Program]: + def match(o: SExp, expected: bytes) -> None: + if o.atom != expected: + raise ValueError(f"expected: {expected.hex()}") + + try: + # (2 (1 . ) ) + ev, quoted_inner, args_list = self.as_iter() + match(ev, b"\x02") + match(quoted_inner.pair[0], b"\x01") + mod = quoted_inner.pair[1] + args = [] + while args_list.pair is not None: + # (4 (1 . ) ) + cons, quoted_arg, rest = args_list.as_iter() + match(cons, b"\x04") + match(quoted_arg.pair[0], b"\x01") + args.append(quoted_arg.pair[1]) + args_list = rest + match(args_list, b"\x01") + return Program.to(mod), Program.to(args) + except ValueError: # too many values to unpack + # when unpacking as_iter() + # or when a match() fails + return self, self.to(0) + except TypeError: # NoneType not subscriptable + # when an object is not a pair or atom as expected + return self, self.to(0) + except EvalError: # first of non-cons + # when as_iter() fails + return self, self.to(0) + + def as_int(self) -> int: + return int_from_bytes(self.as_atom()) + + def __deepcopy__(self, memo): + return type(self).from_bytes(bytes(self)) + + EvalError = EvalError + + +def _tree_hash(node: SExp, precalculated: Set[bytes32]) -> bytes32: + """ + Hash values in `precalculated` are presumed to have been hashed already. + """ + if node.listp(): + left = _tree_hash(node.first(), precalculated) + right = _tree_hash(node.rest(), precalculated) + s = b"\2" + left + right + else: + atom = node.as_atom() + if atom in precalculated: + return bytes32(atom) + s = b"\1" + atom + return bytes32(std_hash(s)) + + +NIL = Program.from_bytes(b"\x80") + + +def _sexp_replace(sexp: SExp, to_sexp: Callable[[Any], SExp], **kwargs) -> SExp: + # if `kwargs == {}` then `return sexp` unchanged + if len(kwargs) == 0: + return sexp + + if "" in kwargs: + if len(kwargs) > 1: + raise ValueError("conflicting paths") + return kwargs[""] + + # we've confirmed that no `kwargs` is the empty string. + # Now split `kwargs` into two groups: those + # that start with `f` and those that start with `r` + + args_by_prefix: Dict[str, SExp] = {} + for k, v in kwargs.items(): + c = k[0] + if c not in "fr": + raise ValueError("bad path containing %s: must only contain `f` and `r`") + args_by_prefix.setdefault(c, dict())[k[1:]] = v + + pair = sexp.pair + if pair is None: + raise ValueError("path into atom") + + # recurse down the tree + new_f = _sexp_replace(pair[0], to_sexp, **args_by_prefix.get("f", {})) + new_r = _sexp_replace(pair[1], to_sexp, **args_by_prefix.get("r", {})) + + return to_sexp((new_f, new_r)) diff --git a/resources/tests/lib/smoke_test_deep_compare.clsp b/resources/tests/lib/smoke_test_deep_compare.clsp new file mode 100644 index 000000000..8df629518 --- /dev/null +++ b/resources/tests/lib/smoke_test_deep_compare.clsp @@ -0,0 +1,28 @@ +(mod () + (include *standard-cl-21*) + (include print.clinc) + (include prepend.clinc) + (include sort.clinc) + (include assert.clinc) + (include map.clinc) + (include deep_compare.clinc) + + (map + (lambda ((want_cmp_val cmp_a cmp_b)) + (= (deep_compare cmp_a cmp_b) want_cmp_val) + ) + (q + (0 0 0) + (-1 () (1 14 5 4 3 2)) + (1 (1 14 5 4 3 2) ()) + (-1 "X" (1 2)) + (1 (1 2) "X") + (0 (3 2) (3 2)) + (-1 (3 1) (3 3)) + (1 (3 3) (3 1)) + (-1 (1 1) (2 1)) + (1 (3 1) (2 2)) + (-1 (2 2) (3 1)) + ) + ) + ) diff --git a/resources/tests/lib/smoke_test_permutations.clsp b/resources/tests/lib/smoke_test_permutations.clsp new file mode 100644 index 000000000..2ed3fbbcc --- /dev/null +++ b/resources/tests/lib/smoke_test_permutations.clsp @@ -0,0 +1,9 @@ +(mod (X) + (include *standard-cl-21*) + (include map.clinc) + (include prepend.clinc) + (include print.clinc) + (include permutations.clinc) + + (permutations X) + ) diff --git a/resources/tests/lib/smoke_test_sort.clsp b/resources/tests/lib/smoke_test_sort.clsp new file mode 100644 index 000000000..59b8a886e --- /dev/null +++ b/resources/tests/lib/smoke_test_sort.clsp @@ -0,0 +1,11 @@ +(mod (X) + (include *standard-cl-21*) + (include prepend.clinc) + (include sort.clinc) + (include assert.clinc) + (include map.clinc) + (include reverse.clinc) + (include print.clinc) + + (sort (lambda (a b) (> b a)) X) + ) diff --git a/resources/tests/lib/steprun.py b/resources/tests/lib/steprun.py new file mode 100644 index 000000000..02db51339 --- /dev/null +++ b/resources/tests/lib/steprun.py @@ -0,0 +1,69 @@ +import binascii +import json +import os +from pathlib import Path +from typing import List + +# from chia.types.blockchain_format.program import Program +from clvm_rs import Program +from clvm_tools.binutils import assemble, disassemble + +from clvm_tools_rs import compile_clvm, compose_run_function, start_clvm_program + + +def compile_module_with_symbols(include_paths: List[Path], source: Path): + path_obj = Path(source) + file_path = path_obj.parent + file_stem = path_obj.stem + target_file = file_path / (file_stem + ".clvm.hex") + sym_file = file_path / (file_stem + ".sym") + # print(f"compile_clvm({path_obj.absolute()}, {str(target_file.absolute().as_posix())}, {include_paths}, True)") + compile_result = compile_clvm( + str(path_obj.resolve()), str(target_file.absolute()), [str(p) for p in include_paths], True + ) + print(f"Writing to {target_file} {compile_result}") + # symbols = compile_result["symbols"] + # if len(symbols) != 0: + # with open(str(sym_file.absolute()), "w") as symfile: + # symfile.write(json.dumps(symbols)) + + +def run_until_end(p): + last = None + location = None + + while not p.is_ended(): + step_result = p.step() + if step_result is not None: + last = step_result + if "Print" in last: + to_print = last["Print"] + if "Print-Location" in last: + print(f"{last['Print-Location']}: print {to_print}") + else: + print(f"print {to_print}") + + return last + + +def diag_run_clvm(program, args, symbols): + hex_form_of_program = binascii.hexlify(bytes(program)).decode("utf8") + hex_form_of_args = binascii.hexlify(bytes(args)).decode("utf8") + symbols = json.loads(open(symbols).read()) + p = start_clvm_program( + hex_form_of_program, hex_form_of_args, symbols, None + ) + report = run_until_end(p) + if "Failure" in report: + raise Exception(report) + else: + return assemble(report["Final"]) + + +if __name__ == "__main__": + # smoke test + import sys + + program = Program.fromhex(open(sys.argv[1]).read()) + args = Program.fromhex(open(sys.argv[2]).read()) + diag_run_clvm(program, args) diff --git a/resources/tests/lib/tree_hash.py b/resources/tests/lib/tree_hash.py new file mode 100644 index 000000000..1e59e9b7c --- /dev/null +++ b/resources/tests/lib/tree_hash.py @@ -0,0 +1,62 @@ +""" +This is an implementation of `sha256_treehash`, used to calculate +puzzle hashes in clvm. + +This implementation goes to great pains to be non-recursive so we don't +have to worry about blowing out the python stack. +""" + +from __future__ import annotations + +from typing import Callable, List, Optional, Set + +from clvm import CLVMObject + +from chia.types.blockchain_format.sized_bytes import bytes32 +from chia.util.hash import std_hash + +Op = Callable[[List["CLVMObject"], List["Op"], Set[bytes32]], None] + + +def sha256_treehash(sexp: CLVMObject, precalculated: Optional[Set[bytes32]] = None) -> bytes32: + """ + Hash values in `precalculated` are presumed to have been hashed already. + """ + + if precalculated is None: + precalculated = set() + + def handle_sexp(sexp_stack: List[CLVMObject], op_stack: List[Op], precalculated: Set[bytes32]) -> None: + sexp = sexp_stack.pop() + if sexp.pair: + p0, p1 = sexp.pair + sexp_stack.append(p0) + sexp_stack.append(p1) + op_stack.append(handle_pair) + op_stack.append(handle_sexp) + op_stack.append(roll) + op_stack.append(handle_sexp) + else: + if sexp.atom in precalculated: + r = sexp.atom + else: + r = std_hash(b"\1" + sexp.atom) + sexp_stack.append(r) + + def handle_pair(sexp_stack: List[CLVMObject], op_stack: List[Op], precalculated: Set[bytes32]) -> None: + p0 = sexp_stack.pop() + p1 = sexp_stack.pop() + sexp_stack.append(std_hash(b"\2" + p0 + p1)) + + def roll(sexp_stack: List[CLVMObject], op_stack: List[Op], precalculated: Set[bytes32]) -> None: + p0 = sexp_stack.pop() + p1 = sexp_stack.pop() + sexp_stack.append(p0) + sexp_stack.append(p1) + + sexp_stack = [sexp] + op_stack: List[Op] = [handle_sexp] + while len(op_stack) > 0: + op = op_stack.pop() + op(sexp_stack, op_stack, precalculated) + return bytes32(sexp_stack[0]) diff --git a/resources/tests/rps-referee-uncaptured.clsp b/resources/tests/rps-referee-uncaptured.clsp new file mode 100644 index 000000000..1dcf38858 --- /dev/null +++ b/resources/tests/rps-referee-uncaptured.clsp @@ -0,0 +1,29 @@ +(mod ((VALIDATION_PROGRAM_HASH AMOUNT) action . args) + + (include *standard-cl-21*) + + (defun reduce (fun lst init) + (if lst + (reduce fun (r lst) (a fun (list (f lst) init))) + init + ) + ) + + (let + ((new_puzzle_hash 38911) + ) + (reduce + (lambda ((@ condition (condname arg1 arg2)) agg) + (if agg + 1 + (if (= condname CREATE_COIN) + (logand (= arg1 new_puzzle_hash) (= arg2 AMOUNT)) + 0 + ) + ) + ) + conditions + 0 + ) + ) + ) diff --git a/resources/tests/rps-referee.clsp b/resources/tests/rps-referee.clsp new file mode 100644 index 000000000..38741b09f --- /dev/null +++ b/resources/tests/rps-referee.clsp @@ -0,0 +1,29 @@ +(mod ((VALIDATION_PROGRAM_HASH AMOUNT) action . args) + + (include *standard-cl-21*) + + (defun reduce (fun lst init) + (if lst + (reduce fun (r lst) (a fun (list (f lst) init))) + init + ) + ) + + (let + ((new_puzzle_hash 38911) + ) + (reduce + (lambda ((& AMOUNT new_puzzle_hash) (@ condition (condname arg1 arg2)) agg) + (if agg + 1 + (if (= condname CREATE_COIN) + (logand (= arg1 new_puzzle_hash) (= arg2 AMOUNT)) + 0 + ) + ) + ) + conditions + 0 + ) + ) + ) diff --git a/src/classic/clvm/serialize.rs b/src/classic/clvm/serialize.rs index 05246789a..f863a42df 100644 --- a/src/classic/clvm/serialize.rs +++ b/src/classic/clvm/serialize.rs @@ -98,7 +98,7 @@ impl<'a> Iterator for SExpToBytesIterator<'a> { fn next(&mut self) -> Option { self.state.pop().and_then(|step| match step { SExpToByteOp::Object(x) => match self.allocator.sexp(x) { - SExp::Atom() => { + SExp::Atom => { // The only node we have in scope is x, so this atom // capture is trivial. let buf = self.allocator.atom(x).to_vec(); diff --git a/src/classic/clvm/sexp.rs b/src/classic/clvm/sexp.rs index 4757014b4..fd26de905 100644 --- a/src/classic/clvm/sexp.rs +++ b/src/classic/clvm/sexp.rs @@ -150,7 +150,7 @@ pub fn to_sexp_type(allocator: &mut Allocator, value: CastableType) -> Result { + SExp::Atom => { return Err(EvalErr( *target_value, "attempt to set_pair in atom".to_string(), @@ -336,7 +336,7 @@ pub fn non_nil(allocator: &Allocator, sexp: NodePtr) -> bool { match allocator.sexp(sexp) { SExp::Pair(_, _) => true, // sexp is the only node in scope, was !is_empty - SExp::Atom() => allocator.atom_len(sexp) != 0, + SExp::Atom => allocator.atom_len(sexp) != 0, } } @@ -356,7 +356,7 @@ pub fn rest(allocator: &Allocator, sexp: NodePtr) -> Result { pub fn atom(allocator: &Allocator, sexp: NodePtr) -> Result, EvalErr> { match allocator.sexp(sexp) { - SExp::Atom() => Ok(allocator.atom(sexp).to_vec()), // only sexp in scope + SExp::Atom => Ok(allocator.atom(sexp).to_vec()), // only sexp in scope _ => Err(EvalErr(sexp, "not an atom".to_string())), } } @@ -366,7 +366,7 @@ pub fn proper_list(allocator: &Allocator, sexp: NodePtr, store: bool) -> Option< let mut args_sexp = sexp; loop { match allocator.sexp(args_sexp) { - SExp::Atom() => { + SExp::Atom => { if !non_nil(allocator, args_sexp) { return Some(args); } else { @@ -454,7 +454,7 @@ pub fn equal_to(allocator: &mut Allocator, first_: NodePtr, second_: NodePtr) -> return true; } match (allocator.sexp(first), allocator.sexp(second)) { - (SExp::Atom(), SExp::Atom()) => { + (SExp::Atom, SExp::Atom) => { // two atoms in scope, both are used return allocator.atom(first) == allocator.atom(second); } @@ -477,7 +477,7 @@ pub fn flatten(allocator: &mut Allocator, tree_: NodePtr, res: &mut Vec loop { match allocator.sexp(tree) { - SExp::Atom() => { + SExp::Atom => { if non_nil(allocator, tree) { res.push(tree); } diff --git a/src/classic/clvm_tools/binutils.rs b/src/classic/clvm_tools/binutils.rs index 670d70e52..505123057 100644 --- a/src/classic/clvm_tools/binutils.rs +++ b/src/classic/clvm_tools/binutils.rs @@ -128,7 +128,7 @@ pub fn disassemble_to_ir_with_kw( IRRepr::Cons(Rc::new(v0), Rc::new(v1)) } - SExp::Atom() => { + SExp::Atom => { // sexp is the only node in scope. let bytes = Bytes::new(Some(BytesFromType::Raw(allocator.atom(sexp).to_vec()))); ir_for_atom(&bytes, allow_keyword, keyword_from_atom) @@ -141,7 +141,7 @@ pub fn disassemble_with_kw( sexp: NodePtr, keyword_from_atom: &Record, String>, ) -> String { - let with_keywords = !matches!(allocator.sexp(sexp), SExp::Atom()); + let with_keywords = !matches!(allocator.sexp(sexp), SExp::Atom); let symbols = disassemble_to_ir_with_kw(allocator, sexp, keyword_from_atom, with_keywords); write_ir(Rc::new(symbols)) } diff --git a/src/classic/clvm_tools/clvmc.rs b/src/classic/clvm_tools/clvmc.rs index 9318120a1..f0f1a00ca 100644 --- a/src/classic/clvm_tools/clvmc.rs +++ b/src/classic/clvm_tools/clvmc.rs @@ -52,6 +52,9 @@ pub fn compile_clvm_text_maybe_opt( let dialect = detect_modern(allocator, assembled_sexp); // Now the stepping is optional (None for classic) but we may communicate // other information in dialect as well. + // + // I think stepping is a good name for the number below as dialect is going + // to get more members that are somewhat independent. if let Some(stepping) = dialect.stepping { let runner = Rc::new(DefaultProgramRunner::new()); let opts = opts diff --git a/src/classic/clvm_tools/debug.rs b/src/classic/clvm_tools/debug.rs index 25767e05d..15bd5142a 100644 --- a/src/classic/clvm_tools/debug.rs +++ b/src/classic/clvm_tools/debug.rs @@ -180,7 +180,7 @@ fn table_trace( ) { let (sexp, args) = match allocator.sexp(form) { SExp::Pair(sexp, args) => (sexp, args), - SExp::Atom() => (form, allocator.null()), + SExp::Atom => (form, allocator.null()), }; stdout.write_str(&format!("exp: {}\n", disassemble_f(allocator, sexp))); diff --git a/src/classic/clvm_tools/pattern_match.rs b/src/classic/clvm_tools/pattern_match.rs index 0df1345cd..02e894b4e 100644 --- a/src/classic/clvm_tools/pattern_match.rs +++ b/src/classic/clvm_tools/pattern_match.rs @@ -51,7 +51,7 @@ pub fn match_sexp( */ match (allocator.sexp(pattern), allocator.sexp(sexp)) { - (SExp::Atom(), SExp::Atom()) => { + (SExp::Atom, SExp::Atom) => { // Two nodes in scope, both used. if allocator.atom(pattern) == allocator.atom(sexp) { Some(known_bindings) @@ -60,10 +60,10 @@ pub fn match_sexp( } } (SExp::Pair(pleft, pright), _) => match (allocator.sexp(pleft), allocator.sexp(pright)) { - (SExp::Atom(), SExp::Atom()) => { + (SExp::Atom, SExp::Atom) => { let pright_atom = allocator.atom(pright).to_vec(); match allocator.sexp(sexp) { - SExp::Atom() => { + SExp::Atom => { // Expression is ($ . $), sexp is '$', result: no capture. // Avoid double borrow. if allocator.atom(pleft) == ATOM_MATCH { @@ -114,11 +114,11 @@ pub fn match_sexp( } } _ => match allocator.sexp(sexp) { - SExp::Atom() => None, + SExp::Atom => None, SExp::Pair(sleft, sright) => match_sexp(allocator, pleft, sleft, known_bindings) .and_then(|new_bindings| match_sexp(allocator, pright, sright, new_bindings)), }, }, - (SExp::Atom(), _) => None, + (SExp::Atom, _) => None, } } diff --git a/src/classic/clvm_tools/sha256tree.rs b/src/classic/clvm_tools/sha256tree.rs index 0212d0c78..ebbc3197c 100644 --- a/src/classic/clvm_tools/sha256tree.rs +++ b/src/classic/clvm_tools/sha256tree.rs @@ -34,7 +34,7 @@ pub fn sha256tree(allocator: &mut Allocator, v: NodePtr) -> Bytes { .concat(&right), ) } - SExp::Atom() => sha256( + SExp::Atom => sha256( Bytes::new(Some(BytesFromType::Raw(vec![1]))).concat(&Bytes::new(Some( // only v in scope. BytesFromType::Raw(allocator.atom(v).to_vec()), diff --git a/src/classic/clvm_tools/stages/stage_2/compile.rs b/src/classic/clvm_tools/stages/stage_2/compile.rs index c71e18340..27d8c3f04 100644 --- a/src/classic/clvm_tools/stages/stage_2/compile.rs +++ b/src/classic/clvm_tools/stages/stage_2/compile.rs @@ -122,12 +122,12 @@ pub fn compile_qq( }; match allocator.sexp(sexp) { - SExp::Atom() => { + SExp::Atom => { // (qq ATOM) => (q . ATOM) quote(allocator, sexp) } SExp::Pair(op, sexp_rest) => { - if let SExp::Atom() = allocator.sexp(op) { + if let SExp::Atom = allocator.sexp(op) { // opbuf => op if allocator.atom(op).to_vec() == qq_atom() { return m! { @@ -211,7 +211,7 @@ fn lower_quote_(allocator: &mut Allocator, prog: NodePtr) -> Result { + SExp::Atom => { // was macro_name, but it's singular and probably // not useful to rename. if allocator.atom(mp_list[0]) == operator { @@ -385,7 +385,7 @@ fn transform_program_atom( let value = if v.len() > 1 { v[1] } else { allocator.null() }; match allocator.sexp(v[0]) { - SExp::Atom() => { + SExp::Atom => { // v[0] is close by, and probably not useful to // rename here. if allocator.atom(v[0]) == a { @@ -462,7 +462,7 @@ fn find_symbol_match( } match allocator.sexp(symdef[0]) { - SExp::Atom() => { + SExp::Atom => { let symbol = symdef[0]; let value = if symdef.len() == 1 { allocator.null() @@ -638,7 +638,7 @@ fn do_com_prog_( // quote atoms match allocator.sexp(prog) { - SExp::Atom() => { + SExp::Atom => { // Note: can't co-borrow with allocator below. let prog_bytes = allocator.atom(prog).to_vec(); transform_program_atom( @@ -650,7 +650,7 @@ fn do_com_prog_( }, SExp::Pair(operator,prog_rest) => { match allocator.sexp(operator) { - SExp::Atom() => { + SExp::Atom => { // Note: can't co-borrow with allocator below. let opbuf = allocator.atom(operator).to_vec(); get_macro_program(allocator, &opbuf, macro_lookup). @@ -783,7 +783,7 @@ pub fn get_compile_filename( return Ok(None); } - if let SExp::Atom() = allocator.sexp(cvt_prog_result) { + if let SExp::Atom = allocator.sexp(cvt_prog_result) { // only cvt_prog_result in scope. let abuf = allocator.atom(cvt_prog_result).to_vec(); return Ok(Some(Bytes::new(Some(BytesFromType::Raw(abuf))).decode())); @@ -806,7 +806,7 @@ pub fn get_search_paths( let mut res = Vec::new(); if let Some(l) = proper_list(allocator, search_path_result.1, true) { for elt in l.iter().copied() { - if let SExp::Atom() = allocator.sexp(elt) { + if let SExp::Atom = allocator.sexp(elt) { // Only elt in scope. res.push( Bytes::new(Some(BytesFromType::Raw(allocator.atom(elt).to_vec()))).decode(), diff --git a/src/classic/clvm_tools/stages/stage_2/inline.rs b/src/classic/clvm_tools/stages/stage_2/inline.rs index d0db520f1..215c3679d 100644 --- a/src/classic/clvm_tools/stages/stage_2/inline.rs +++ b/src/classic/clvm_tools/stages/stage_2/inline.rs @@ -15,7 +15,7 @@ pub fn is_at_capture( tree_first: NodePtr, tree_rest: NodePtr, ) -> Option<(NodePtr, NodePtr)> { - if let (SExp::Atom(), Some(spec)) = ( + if let (SExp::Atom, Some(spec)) = ( allocator.sexp(tree_first), proper_list(allocator, tree_rest, true), ) { @@ -88,7 +88,7 @@ fn formulate_path_selections_for_destructuring_arg( SExp::Pair(a, b) => { let next_depth = arg_depth.clone() * 2_u32.to_bigint().unwrap(); if let Some((capture, substructure)) = is_at_capture(allocator, a, b) { - if let SExp::Atom() = allocator.sexp(capture) { + if let SExp::Atom = allocator.sexp(capture) { let (new_arg_path, new_arg_depth, tail) = if let Some(prev_ref) = referenced_from { (arg_path, arg_depth, prev_ref) @@ -147,7 +147,7 @@ fn formulate_path_selections_for_destructuring_arg( ) } } - SExp::Atom() => { + SExp::Atom => { // Note: can't co-borrow with allocator below. let buf = allocator.atom(arg_sexp).to_vec(); if !buf.is_empty() { @@ -225,7 +225,7 @@ pub fn formulate_path_selections_for_destructuring( ) -> Result { if let SExp::Pair(a, b) = allocator.sexp(args_sexp) { if let Some((capture, substructure)) = is_at_capture(allocator, a, b) { - if let SExp::Atom() = allocator.sexp(capture) { + if let SExp::Atom = allocator.sexp(capture) { let quoted_arg_list = wrap_in_unquote(allocator, capture)?; let tail = wrap_in_compile_time_list(allocator, quoted_arg_list)?; // Was: cbuf from capture. diff --git a/src/classic/clvm_tools/stages/stage_2/module.rs b/src/classic/clvm_tools/stages/stage_2/module.rs index d905fad28..74083616a 100644 --- a/src/classic/clvm_tools/stages/stage_2/module.rs +++ b/src/classic/clvm_tools/stages/stage_2/module.rs @@ -146,7 +146,7 @@ fn build_used_constants_names( let matching_names = matching_names_1.iter().filter_map(|v| { // Only v usefully in scope. - if let SExp::Atom() = allocator.sexp(*v) { + if let SExp::Atom = allocator.sexp(*v) { Some(allocator.atom(*v).to_vec()) } else { None @@ -224,7 +224,7 @@ fn unquote_args( matches: &HashMap, NodePtr>, ) -> Result { match allocator.sexp(code) { - SExp::Atom() => { + SExp::Atom => { // Only code in scope. let code_atom = allocator.atom(code); let matching_args = args @@ -286,7 +286,7 @@ fn defun_inline_to_macro( let arg_name_list = arg_atom_list .iter() .filter_map(|x| { - if let SExp::Atom() = allocator.sexp(*x) { + if let SExp::Atom = allocator.sexp(*x) { // only x usefully in scope. Some(allocator.atom(*x)) } else { @@ -326,12 +326,12 @@ fn parse_mod_sexp( let op = match allocator.sexp(op_node) { // op_node in use. - SExp::Atom() => allocator.atom(op_node).to_vec(), + SExp::Atom => allocator.atom(op_node).to_vec(), _ => Vec::new(), }; let name = match allocator.sexp(name_node) { // name_node in use. - SExp::Atom() => allocator.atom(name_node).to_vec(), + SExp::Atom => allocator.atom(name_node).to_vec(), _ => Vec::new(), }; @@ -551,7 +551,7 @@ fn symbol_table_for_tree( } match allocator.sexp(tree) { - SExp::Atom() => Ok(vec![(tree, root_node.as_path().data().to_vec())]), + SExp::Atom => Ok(vec![(tree, root_node.as_path().data().to_vec())]), SExp::Pair(_, _) => { let left_bytes = NodePath::new(None).first(); let right_bytes = NodePath::new(None).rest(); diff --git a/src/classic/clvm_tools/stages/stage_2/operators.rs b/src/classic/clvm_tools/stages/stage_2/operators.rs index e95e48eb3..2e69564d3 100644 --- a/src/classic/clvm_tools/stages/stage_2/operators.rs +++ b/src/classic/clvm_tools/stages/stage_2/operators.rs @@ -205,7 +205,7 @@ impl CompilerOperatorsInternal { match allocator.sexp(sexp) { SExp::Pair(f, _) => match allocator.sexp(f) { - SExp::Atom() => { + SExp::Atom => { let filename = Bytes::new(Some(BytesFromType::Raw(allocator.atom(f).to_vec()))).decode(); // Use the read interface in CompilerOpts if we have one. @@ -238,7 +238,7 @@ impl CompilerOperatorsInternal { fn write(&self, allocator: &Allocator, sexp: NodePtr) -> Response { if let SExp::Pair(filename_sexp, r) = allocator.sexp(sexp) { if let SExp::Pair(data, _) = allocator.sexp(r) { - if let SExp::Atom() = allocator.sexp(filename_sexp) { + if let SExp::Atom = allocator.sexp(filename_sexp) { let filename_buf = allocator.atom(filename_sexp); let filename_bytes = Bytes::new(Some(BytesFromType::Raw(filename_buf.to_vec()))); @@ -285,7 +285,7 @@ impl CompilerOperatorsInternal { }; if let SExp::Pair(l, _r) = allocator.sexp(sexp) { - if let SExp::Atom() = allocator.sexp(l) { + if let SExp::Atom = allocator.sexp(l) { // l most relevant in scope. let filename = Bytes::new(Some(BytesFromType::Raw(allocator.atom(l).to_vec()))).decode(); @@ -319,9 +319,7 @@ impl CompilerOperatorsInternal { { for kv in symtable.iter() { if let SExp::Pair(hash, name) = allocator.sexp(*kv) { - if let (SExp::Atom(), SExp::Atom()) = - (allocator.sexp(hash), allocator.sexp(name)) - { + if let (SExp::Atom, SExp::Atom) = (allocator.sexp(hash), allocator.sexp(name)) { // hash and name in scope. let hash_text = Bytes::new(Some(BytesFromType::Raw(allocator.atom(hash).to_vec()))) @@ -389,7 +387,7 @@ impl Dialect for CompilerOperatorsInternal { let extensions_to_clvmr_during_compile = self.get_operators_extension(); match allocator.sexp(op) { - SExp::Atom() => { + SExp::Atom => { // use of op obvious. let opbuf = allocator.atom(op); if opbuf == "_read".as_bytes() { diff --git a/src/classic/clvm_tools/stages/stage_2/optimize.rs b/src/classic/clvm_tools/stages/stage_2/optimize.rs index 64519c8c4..9aef8e77c 100644 --- a/src/classic/clvm_tools/stages/stage_2/optimize.rs +++ b/src/classic/clvm_tools/stages/stage_2/optimize.rs @@ -41,7 +41,7 @@ pub fn seems_constant_tail(allocator: &mut Allocator, sexp_: NodePtr) -> bool { sexp = r; } - SExp::Atom() => { + SExp::Atom => { return sexp == allocator.null(); } } @@ -50,12 +50,12 @@ pub fn seems_constant_tail(allocator: &mut Allocator, sexp_: NodePtr) -> bool { pub fn seems_constant(allocator: &mut Allocator, sexp: NodePtr) -> bool { match allocator.sexp(sexp) { - SExp::Atom() => { + SExp::Atom => { return sexp == allocator.null(); } SExp::Pair(operator, r) => { match allocator.sexp(operator) { - SExp::Atom() => { + SExp::Atom => { // Was buf of operator. let atom = allocator.atom(operator); if atom.len() == 1 && atom[0] == 1 { @@ -93,7 +93,7 @@ pub fn constant_optimizer( */ if let SExp::Pair(first, _) = allocator.sexp(r) { // first relevant in scope. - if let SExp::Atom() = allocator.sexp(first) { + if let SExp::Atom = allocator.sexp(first) { let buf = allocator.atom(first); if buf.len() == 1 && buf[0] == 1 { // Short circuit already quoted expression. @@ -137,7 +137,7 @@ pub fn constant_optimizer( } pub fn is_args_call(allocator: &Allocator, r: NodePtr) -> bool { - if let SExp::Atom() = allocator.sexp(r) { + if let SExp::Atom = allocator.sexp(r) { // Only r in scope. let buf = allocator.atom(r); buf.len() == 1 && buf[0] == 1 @@ -220,7 +220,7 @@ fn path_from_args( new_args: NodePtr, ) -> Result { match allocator.sexp(sexp) { - SExp::Atom() => { + SExp::Atom => { // Only sexp in scope. let v = number_from_u8(allocator.atom(sexp)); if v <= bi_one() { @@ -246,7 +246,7 @@ pub fn sub_args( new_args: NodePtr, ) -> Result { match allocator.sexp(sexp) { - SExp::Atom() => path_from_args(allocator, sexp, new_args), + SExp::Atom => path_from_args(allocator, sexp, new_args), SExp::Pair(first_pre, rest) => { let first; @@ -254,7 +254,7 @@ pub fn sub_args( SExp::Pair(_, _) => { first = sub_args(allocator, first_pre, new_args)?; } - SExp::Atom() => { + SExp::Atom => { // Atom is a reflection of first_pre. let atom = allocator.atom(first_pre); if atom.len() == 1 && atom[0] == 1 { @@ -374,7 +374,7 @@ pub fn var_change_optimizer_cons_eval( } let increment = match allocator.sexp(val) { SExp::Pair(val_first, _) => match allocator.sexp(val_first) { - SExp::Atom() => { + SExp::Atom => { // Atom reflects val_first. let vf_buf = allocator.atom(val_first); (vf_buf.len() != 1 || vf_buf[0] != 1) as i32 @@ -419,7 +419,7 @@ pub fn children_optimizer( if list.is_empty() { return Ok(r); } - if let SExp::Atom() = allocator.sexp(list[0]) { + if let SExp::Atom = allocator.sexp(list[0]) { if allocator.atom(list[0]).to_vec() == vec![1] { return Ok(r); } @@ -683,7 +683,7 @@ pub fn optimize_sexp_( let mut name = "".to_string(); match allocator.sexp(r) { - SExp::Atom() => { + SExp::Atom => { return Ok(r); } SExp::Pair(_, _) => { diff --git a/src/classic/clvm_tools/stages/stage_2/reader.rs b/src/classic/clvm_tools/stages/stage_2/reader.rs index bc91c89b4..716988f75 100644 --- a/src/classic/clvm_tools/stages/stage_2/reader.rs +++ b/src/classic/clvm_tools/stages/stage_2/reader.rs @@ -90,7 +90,7 @@ pub fn process_embed_file( )); } - if let (SExp::Atom(), SExp::Atom(), SExp::Atom()) = ( + if let (SExp::Atom, SExp::Atom, SExp::Atom) = ( allocator.sexp(l[0]), allocator.sexp(l[1]), allocator.sexp(l[2]), diff --git a/src/compiler/clvm.rs b/src/compiler/clvm.rs index 88cbdd77d..7246aae96 100644 --- a/src/compiler/clvm.rs +++ b/src/compiler/clvm.rs @@ -246,9 +246,9 @@ pub fn convert_to_clvm_rs( }) } } - SExp::Cons(_, a, b) => convert_to_clvm_rs(allocator, a.clone()).and_then(|head| { + SExp::Cons(_, a, b) => convert_to_clvm_rs(allocator, a.clone()).and_then(|head_ptr| { convert_to_clvm_rs(allocator, b.clone()).and_then(|tail| { - allocator.new_pair(head, tail).map_err(|_e| { + allocator.new_pair(head_ptr, tail).map_err(|_e| { RunFailure::RunErr(a.loc(), format!("failed to alloc cons {head}")) }) }) @@ -263,7 +263,7 @@ pub fn convert_from_clvm_rs( head: NodePtr, ) -> Result, RunFailure> { match allocator.sexp(head) { - allocator::SExp::Atom() => { + allocator::SExp::Atom => { let atom_data = allocator.atom(head); if atom_data.is_empty() { Ok(Rc::new(SExp::Nil(loc))) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index 1dc4ecf09..bf44f65c6 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -1,33 +1,34 @@ use std::borrow::Borrow; use std::collections::HashMap; use std::collections::HashSet; +use std::mem::swap; use std::rc::Rc; use num_bigint::ToBigInt; -use crate::classic::clvm_tools::stages::stage_0::TRunProgram; -use clvm_rs::allocator::Allocator; - use crate::classic::clvm::__type_compatibility__::bi_one; use crate::compiler::clvm::run; use crate::compiler::compiler::{is_at_capture, run_optimizer}; use crate::compiler::comptypes::{ - fold_m, join_vecs_to_string, list_to_cons, Binding, BodyForm, CallSpec, Callable, CompileErr, - CompileForm, CompiledCode, CompilerOpts, ConstantKind, DefunCall, DefunData, HelperForm, - InlineFunction, LetData, LetFormKind, PrimaryCodegen, RawCallSpec, + fold_m, join_vecs_to_string, list_to_cons, Binding, BindingPattern, BodyForm, CallSpec, + Callable, CompileErr, CompileForm, CompiledCode, CompilerOpts, ConstantKind, DefunCall, + DefunData, HelperForm, InlineFunction, LetData, LetFormInlineHint, LetFormKind, PrimaryCodegen, + RawCallSpec, }; use crate::compiler::debug::{build_swap_table_mut, relabel}; use crate::compiler::evaluate::{Evaluator, EVAL_STACK_LIMIT}; -use crate::compiler::frontend::compile_bodyform; +use crate::compiler::frontend::{compile_bodyform, make_provides_set}; use crate::compiler::gensym::gensym; use crate::compiler::inline::{replace_in_inline, synthesize_args}; +use crate::compiler::lambda::lambda_codegen; use crate::compiler::optimize::optimize_expr; use crate::compiler::prims::{primapply, primcons, primquote}; use crate::compiler::runtypes::RunFailure; use crate::compiler::sexp::{decode_string, SExp}; use crate::compiler::srcloc::Srcloc; -use crate::util::u8_from_number; +use crate::compiler::{BasicCompileContext, CompileContextWrapper}; +use crate::util::{toposort, u8_from_number, TopoSortItem}; const MACRO_TIME_LIMIT: usize = 1000000; const CONST_EVAL_LIMIT: usize = 1000000; @@ -181,18 +182,103 @@ fn create_name_lookup_( } } +// Tell whether there's a non-inline defun called 'name' in this program. +// If so, the reference to this name is a reference to a function, which +// will make variable references to it capture the program's function +// environment. +fn is_defun_in_codegen(compiler: &PrimaryCodegen, name: &[u8]) -> bool { + for h in compiler.original_helpers.iter() { + if matches!(h, HelperForm::Defun(false, _)) && h.name() == name { + return true; + } + } + + false +} + +// At the CLVM level, given a list of clvm expressios, make an expression +// that contains that list using conses. +fn make_list(loc: Srcloc, elements: Vec>) -> Rc { + let mut res = Rc::new(SExp::Nil(loc.clone())); + for e in elements.iter().rev() { + res = Rc::new(primcons(loc.clone(), e.clone(), res)); + } + res +} + +// +// Get the clvm expression that represents the indicated function as a +// callable value using the CLVM a operator. This value can be returned +// and even passed to another program because it carries the required +// environment to call functions it depends on from the call site. +// +// To do this, it writes an expression that conses the left env. +// +// (list (q . 2) (c (q . 1) n) (list (q . 4) (c (q . 1) 2) (q . 1))) +// +// Something like: +// (apply (quoted (expanded n)) (cons (quoted (expanded 2)) given-args)) +// +fn lambda_for_defun(loc: Srcloc, lookup: Rc) -> Rc { + let one_atom = Rc::new(SExp::Atom(loc.clone(), vec![1])); + let two_atom = Rc::new(SExp::Atom(loc.clone(), vec![2])); + let apply_atom = two_atom.clone(); + let cons_atom = Rc::new(SExp::Atom(loc.clone(), vec![4])); + make_list( + loc.clone(), + vec![ + Rc::new(primquote(loc.clone(), apply_atom)), + Rc::new(primcons( + loc.clone(), + Rc::new(primquote(loc.clone(), one_atom.clone())), + lookup, + )), + make_list( + loc.clone(), + vec![ + Rc::new(primquote(loc.clone(), cons_atom)), + Rc::new(primcons( + loc.clone(), + Rc::new(primquote(loc.clone(), one_atom.clone())), + two_atom, + )), + Rc::new(primquote(loc, one_atom)), + ], + ), + ], + ) +} + fn create_name_lookup( compiler: &PrimaryCodegen, l: Srcloc, name: &[u8], + // If the lookup is in head position, then it is a lookup as a callable, + // otherwise it's a lookup as a variable, which means that if a function + // is named, it will be built into an expression that allows it to be + // called by a CLVM 'a' operator as one would expect, regardless of how + // it integrates with the rest of the program it lives in. + as_variable: bool, ) -> Result, CompileErr> { compiler .constants .get(name) .map(|x| Ok(x.clone())) .unwrap_or_else(|| { - create_name_lookup_(l.clone(), name, compiler.env.clone(), compiler.env.clone()) - .map(|i| Rc::new(SExp::Integer(l.clone(), i.to_bigint().unwrap()))) + create_name_lookup_(l.clone(), name, compiler.env.clone(), compiler.env.clone()).map( + |i| { + // Determine if it's a defun. If so we can ensure that it's + // callable like a lambda by repeating the left env into it. + let find_program = Rc::new(SExp::Integer(l.clone(), i.to_bigint().unwrap())); + if as_variable && is_defun_in_codegen(compiler, name) { + // It's a defun. Harden the result so it is callable + // directly by the CLVM 'a' operator. + lambda_for_defun(l.clone(), find_program) + } else { + find_program + } + }, + ) }) } @@ -220,7 +306,9 @@ pub fn get_callable( SExp::Atom(l, name) => { let macro_def = compiler.macros.get(name); let inline = compiler.inlines.get(name); - let defun = create_name_lookup(compiler, l.clone(), name); + // We're getting a callable, so the access requested is not as + // a variable. + let defun = create_name_lookup(compiler, l.clone(), name, false); let prim = get_prim(l.clone(), compiler.prims.clone(), name); let atom_is_com = *name == "com".as_bytes().to_vec(); let atom_is_at = *name == "@".as_bytes().to_vec(); @@ -254,8 +342,7 @@ pub fn get_callable( } pub fn process_macro_call( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, compiler: &PrimaryCodegen, l: Srcloc, @@ -267,9 +354,10 @@ pub fn process_macro_call( let args_to_macro = list_to_cons(l.clone(), &converted_args); build_swap_table_mut(&mut swap_table, &args_to_macro); + let runner = context.runner(); run( - allocator, - runner.clone(), + context.allocator(), + runner, opts.prim_map(), code, Rc::new(args_to_macro), @@ -284,12 +372,11 @@ pub fn process_macro_call( let relabeled_expr = relabel(&swap_table, &v); compile_bodyform(opts.clone(), Rc::new(relabeled_expr)) }) - .and_then(|body| generate_expr_code(allocator, runner, opts, compiler, Rc::new(body))) + .and_then(|body| generate_expr_code(context, opts, compiler, Rc::new(body))) } fn generate_args_code( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, compiler: &PrimaryCodegen, call: &CallSpec, @@ -302,7 +389,7 @@ fn generate_args_code( // Ensure we start with either the specified tail or nil. let mut compiled_args: Rc = if let Some(t) = call.tail.as_ref() { - generate_expr_code(allocator, runner.clone(), opts.clone(), compiler, t.clone())?.1 + generate_expr_code(context, opts.clone(), compiler, t.clone())?.1 } else { Rc::new(SExp::Nil(call.loc.clone())) }; @@ -310,14 +397,7 @@ fn generate_args_code( // Now that we have the tail, generate the code for each argument in reverse // order to cons on. for hd in call.args.iter().rev() { - let generated = generate_expr_code( - allocator, - runner.clone(), - opts.clone(), - compiler, - hd.clone(), - )? - .1; + let generated = generate_expr_code(context, opts.clone(), compiler, hd.clone())?.1; // This function is now reused for purposes that make a simple list of the // converted arguments, or generate valid code with primitive conses. @@ -371,8 +451,7 @@ pub fn get_call_name(l: Srcloc, body: BodyForm) -> Result, CompileErr> } fn compile_call( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, compiler: &PrimaryCodegen, call: &RawCallSpec, @@ -400,19 +479,12 @@ fn compile_call( Rc::new(SExp::Atom(al.clone(), an.to_vec())), ) .and_then(|calltype| match calltype { - Callable::CallMacro(l, code) => process_macro_call( - allocator, - runner, - opts.clone(), - compiler, - l, - tl, - Rc::new(code), - ), + Callable::CallMacro(l, code) => { + process_macro_call(context, opts.clone(), compiler, l, tl, Rc::new(code)) + } Callable::CallInline(l, inline) => replace_in_inline( - allocator, - runner.clone(), + context, opts.clone(), compiler, l.clone(), @@ -423,8 +495,7 @@ fn compile_call( ), Callable::CallDefun(l, lookup) => generate_args_code( - allocator, - runner, + context, opts.clone(), compiler, // A callspec is a way to collect some info about a call, mainly @@ -443,8 +514,7 @@ fn compile_call( }), Callable::CallPrim(l, p) => generate_args_code( - allocator, - runner.clone(), + context, opts, compiler, &CallSpec { @@ -501,9 +571,10 @@ fn compile_call( ); let mut unused_symbol_table = HashMap::new(); + let runner = context.runner(); updated_opts .compile_program( - allocator, + context.allocator(), runner, Rc::new(use_body), &mut unused_symbol_table, @@ -531,9 +602,30 @@ fn compile_call( } } +pub fn do_mod_codegen( + context: &mut BasicCompileContext, + opts: Rc, + program: &CompileForm, +) -> Result { + // A mod form yields the compiled code. + let without_env = opts.set_start_env(None).set_in_defun(false); + let mut throwaway_symbols = HashMap::new(); + let runner = context.runner(); + let mut context_wrapper = + CompileContextWrapper::new(context.allocator(), runner.clone(), &mut throwaway_symbols); + let code = codegen(&mut context_wrapper.context, without_env, program)?; + Ok(CompiledCode( + program.loc.clone(), + Rc::new(SExp::Cons( + program.loc.clone(), + Rc::new(SExp::Atom(program.loc.clone(), vec![1])), + Rc::new(code), + )), + )) +} + pub fn generate_expr_code( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, compiler: &PrimaryCodegen, expr: Rc, @@ -542,7 +634,7 @@ pub fn generate_expr_code( BodyForm::Let(LetFormKind::Parallel, letdata) => { /* Depends on a defun having been desugared from this let and the let expressing rewritten. */ - generate_expr_code(allocator, runner, opts, compiler, letdata.body.clone()) + generate_expr_code(context, opts, compiler, letdata.body.clone()) } BodyForm::Quoted(q) => { let l = q.loc(); @@ -560,7 +652,10 @@ pub fn generate_expr_code( Rc::new(SExp::Integer(l.clone(), bi_one())), )) } else { - create_name_lookup(compiler, l.clone(), atom) + // This is as a variable access, given that we've got + // a Value bodyform containing an Atom, so if a defun + // is returned, it should be a packaged callable. + create_name_lookup(compiler, l.clone(), atom, true) .map(|f| Ok(CompiledCode(l.clone(), f))) .unwrap_or_else(|_| { // Finally enable strictness for variable names. @@ -587,8 +682,7 @@ pub fn generate_expr_code( // macros, as it's possible that a macro returned // something that's canonically a name in number form. generate_expr_code( - allocator, - runner, + context, opts, compiler, Rc::new(BodyForm::Quoted(SExp::Atom(l.clone(), atom.clone()))), @@ -603,8 +697,7 @@ pub fn generate_expr_code( // like values from modern macros. if opts.dialect().strict { return generate_expr_code( - allocator, - runner, + context, opts, compiler, Rc::new(BodyForm::Quoted(SExp::Integer(l.clone(), i.clone()))), @@ -616,8 +709,7 @@ pub fn generate_expr_code( // accomodate bare numbers coming back in place of identifiers, // but only in legacy non-strict mode. generate_expr_code( - allocator, - runner, + context, opts, compiler, Rc::new(BodyForm::Value(SExp::Atom( @@ -640,8 +732,7 @@ pub fn generate_expr_code( )) } else { compile_call( - allocator, - runner, + context, opts, compiler, // This is a partial callspec. @@ -654,18 +745,7 @@ pub fn generate_expr_code( ) } } - BodyForm::Mod(_, program) => { - // A mod form yields the compiled code. - let code = codegen(allocator, runner, opts, program, &mut HashMap::new())?; - Ok(CompiledCode( - program.loc.clone(), - Rc::new(SExp::Cons( - program.loc.clone(), - Rc::new(SExp::Atom(program.loc.clone(), vec![1])), - Rc::new(code), - )), - )) - } + BodyForm::Mod(_, program) => do_mod_codegen(context, opts, program), _ => Err(CompileErr( expr.loc(), format!("don't know how to compile {}", expr.to_sexp()), @@ -698,8 +778,7 @@ fn fail_if_present( } fn codegen_( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, compiler: &PrimaryCodegen, h: &HelperForm, @@ -727,12 +806,13 @@ fn codegen_( defun.args.clone(), ))); + let runner = context.runner(); let opt = if opts.optimize() { // Run optimizer on frontend style forms. optimize_expr( - allocator, + context.allocator(), opts.clone(), - runner.clone(), + runner, compiler, defun.body.clone(), ) @@ -757,16 +837,17 @@ fn codegen_( ); let mut unused_symbol_table = HashMap::new(); + let runner = context.runner(); updated_opts .compile_program( - allocator, + context.allocator(), runner.clone(), Rc::new(tocompile), &mut unused_symbol_table, ) .and_then(|code| { if opts.optimize() { - run_optimizer(allocator, runner, Rc::new(code)) + run_optimizer(context.allocator(), runner, Rc::new(code)) } else { Ok(Rc::new(code)) } @@ -818,17 +899,34 @@ pub fn empty_compiler(prim_map: Rc, Rc>>, l: Srcloc) -> Pr } } +pub fn should_inline_let(inline_hint: &Option) -> bool { + matches!(inline_hint, None | Some(LetFormInlineHint::Inline(_))) +} + +#[allow(clippy::too_many_arguments)] fn generate_let_defun( l: Srcloc, kwl: Option, name: &[u8], args: Rc, + // Tells what the user's preference is for inlining. It can be set to None, + // which means use the form's default. + // Some(LetFormInlineHint::NoPreference), meaning the system should choose the + // best inlining strategy, + // Some(LetFormInlineHint::Inline(_)) or Some(LetFormInlineHint::NonInline(_)) + inline_hint: &Option, bindings: Vec>, body: Rc, ) -> HelperForm { let new_arguments: Vec> = bindings .iter() - .map(|b| Rc::new(SExp::Atom(l.clone(), b.name.clone()))) + .map(|b| match &b.pattern { + // This is the classic let form. It doesn't support destructuring. + BindingPattern::Name(name) => Rc::new(SExp::Atom(l.clone(), name.clone())), + // The assign form, which supports destructuring and signals newer + // handling. + BindingPattern::Complex(sexp) => sexp.clone(), + }) .collect(); let inner_function_args = Rc::new(SExp::Cons( @@ -838,7 +936,10 @@ fn generate_let_defun( )); HelperForm::Defun( - true, + // Some forms will be inlined and some as separate functions based on + // binary size, when permitted. Sometimes the user will signal a + // preference. + should_inline_let(inline_hint), DefunData { loc: l.clone(), nl: l, @@ -855,15 +956,160 @@ fn generate_let_args(_l: Srcloc, blist: Vec>) -> Vec> { blist.iter().map(|b| b.body.clone()).collect() } +/// Assign arranges its variable names via need and split into batches that don't +/// add additional dependencies. To illustrate: +/// +/// (assign +/// (X . Y) (F A W) +/// W (G A) +/// Z (H X Y W) +/// Next (H2 X Y W) +/// (doit Y Next) +/// +/// In this case, we have the following dependencies: +/// W depends on A (external) +/// X and Y depend on A (external) and W +/// Z depends on X Y and W +/// Next depends on X Y and W +/// The body depends on Y and Next. +/// +/// So we sort this: +/// W (G A) +/// --- X and Y add a dependency on W --- +/// (X . Y) (F A W) +/// --- Z and Next depend on X Y and W +/// Z (H X Y W) +/// Next (H2 X Y W) +/// --- done sorting, the body has access to all bindings --- +/// +/// We return TopoSortItem> (bytewise names), which is used in the +/// generic toposort function in util. +/// +/// This is used by facilities that need to know the order of the assignments. +/// +/// A good number of languages support reorderable assignment (haskell, elm). +pub fn toposort_assign_bindings( + loc: &Srcloc, + bindings: &[Rc], +) -> Result>>, CompileErr> { + // Topological sort of bindings. + toposort( + bindings, + CompileErr(loc.clone(), "deadlock resolving binding order".to_string()), + // Needs: What this binding relies on. + |possible, b| { + let mut need_set = HashSet::new(); + make_provides_set(&mut need_set, b.body.to_sexp()); + let mut need_set_thats_possible = HashSet::new(); + for need in need_set.intersection(possible) { + need_set_thats_possible.insert(need.clone()); + } + Ok(need_set_thats_possible) + }, + // Has: What this binding provides. + |b| match &b.pattern { + BindingPattern::Name(name) => HashSet::from([name.clone()]), + BindingPattern::Complex(sexp) => { + let mut result_set = HashSet::new(); + make_provides_set(&mut result_set, sexp.clone()); + result_set + } + }, + ) +} + +/// Let forms are "hoisted" (promoted) from being body forms to being functions +/// in the program (either defun or defun-inline). The arguments given are bound +/// in the downstream code, allowing the code generator to re-use functions to +/// allow the inner body forms to use the variable names defined in the assign. +/// This is isolated here from hoist_body_let_binding because it has its own +/// complexity that's separate from the original let features. +/// +/// In the future, things such as lambdas will also desugar along these same +/// routes. +pub fn hoist_assign_form(letdata: &LetData) -> Result { + let sorted_spec = toposort_assign_bindings(&letdata.loc, &letdata.bindings)?; + + // Break up into stages of parallel let forms. + // Track the needed bindings of this level. + // If this becomes broader in a way that doesn't + // match the existing provides, we need to break + // the let binding. + let mut current_provides = HashSet::new(); + let mut binding_lists = Vec::new(); + let mut this_round_bindings = Vec::new(); + let mut new_provides: HashSet> = HashSet::new(); + + for spec in sorted_spec.iter() { + let mut new_needs = spec.needs.difference(¤t_provides).cloned(); + if new_needs.next().is_some() { + // Roll over the set we're accumulating to the finished version. + let mut empty_tmp: Vec> = Vec::new(); + swap(&mut empty_tmp, &mut this_round_bindings); + binding_lists.push(empty_tmp); + for provided in new_provides.iter() { + current_provides.insert(provided.clone()); + } + new_provides.clear(); + } + // Record what we can provide to the next round. + for p in spec.has.iter() { + new_provides.insert(p.clone()); + } + this_round_bindings.push(letdata.bindings[spec.index].clone()); + } + + // Pick up the last ones that didn't add new needs. + if !this_round_bindings.is_empty() { + binding_lists.push(this_round_bindings); + } + + binding_lists.reverse(); + + // Spill let forms as parallel sets to get the best stack we can. + let mut end_bindings = Vec::new(); + swap(&mut end_bindings, &mut binding_lists[0]); + + // build a stack of let forms starting with the inner most bindings. + let mut output_let = BodyForm::Let( + LetFormKind::Parallel, + Box::new(LetData { + bindings: end_bindings, + ..letdata.clone() + }), + ); + + // build rest of the stack. + for binding_list in binding_lists.into_iter().skip(1) { + output_let = BodyForm::Let( + LetFormKind::Parallel, + Box::new(LetData { + bindings: binding_list, + body: Rc::new(output_let), + ..letdata.clone() + }), + ) + } + + Ok(output_let) +} + +/// The main function that, when encountering something that needs to desugar to +/// a function, returns the functions that result (because things inside it may +/// also need to desugar) and rewrites the expression to incorporate that +/// function. +/// +/// We add result here in case something needs extra processing, such as assign +/// form sorting, which can fail if a workable order can't be solved. pub fn hoist_body_let_binding( outer_context: Option>, args: Rc, body: Rc, -) -> (Vec, Rc) { +) -> Result<(Vec, Rc), CompileErr> { match body.borrow() { BodyForm::Let(LetFormKind::Sequential, letdata) => { if letdata.bindings.is_empty() { - return (vec![], letdata.body.clone()); + return Ok((vec![], letdata.body.clone())); } // If we're here, we're in the middle of hoisting. @@ -876,12 +1122,10 @@ pub fn hoist_body_let_binding( let sub_bindings = letdata.bindings.iter().skip(1).cloned().collect(); Rc::new(BodyForm::Let( LetFormKind::Sequential, - LetData { - loc: letdata.loc.clone(), - kw: letdata.kw.clone(), + Box::new(LetData { bindings: sub_bindings, - body: letdata.body.clone(), - }, + ..*letdata.clone() + }), )) }; @@ -890,12 +1134,11 @@ pub fn hoist_body_let_binding( args, Rc::new(BodyForm::Let( LetFormKind::Parallel, - LetData { - loc: letdata.loc.clone(), - kw: letdata.kw.clone(), + Box::new(LetData { bindings: vec![letdata.bindings[0].clone()], body: new_sub_expr, - }, + ..*letdata.clone() + }), )), ) } @@ -906,21 +1149,21 @@ pub fn hoist_body_let_binding( let mut revised_bindings = Vec::new(); for b in letdata.bindings.iter() { let (mut new_helpers, new_binding) = - hoist_body_let_binding(outer_context.clone(), args.clone(), b.body.clone()); + hoist_body_let_binding(outer_context.clone(), args.clone(), b.body.clone())?; out_defuns.append(&mut new_helpers); revised_bindings.push(Rc::new(Binding { loc: b.loc.clone(), nl: b.nl.clone(), - name: b.name.clone(), + pattern: b.pattern.clone(), body: new_binding, })); } - let generated_defun = generate_let_defun( letdata.loc.clone(), None, &defun_name, args, + &letdata.inline_hint, revised_bindings.to_vec(), letdata.body.clone(), ); @@ -952,38 +1195,88 @@ pub fn hoist_body_let_binding( ]; call_args.append(&mut let_args); - // Calling desugared let so we decide what the tail looks like. let final_call = BodyForm::Call(letdata.loc.clone(), call_args, None); - (out_defuns, Rc::new(final_call)) + Ok((out_defuns, Rc::new(final_call))) + } + // New alternative for assign forms. + BodyForm::Let(LetFormKind::Assign, letdata) => { + hoist_body_let_binding(outer_context, args, Rc::new(hoist_assign_form(letdata)?)) } BodyForm::Call(l, list, tail) => { let mut vres = Vec::new(); let mut new_call_list = vec![list[0].clone()]; for i in list.iter().skip(1) { let (mut new_helpers, new_arg) = - hoist_body_let_binding(outer_context.clone(), args.clone(), i.clone()); + hoist_body_let_binding(outer_context.clone(), args.clone(), i.clone())?; new_call_list.push(new_arg); vres.append(&mut new_helpers); } // Ensure that we hoist a let occupying the &rest tail. - let new_tail = tail.as_ref().map(|t| { + let new_tail = if let Some(t) = tail.as_ref() { let (mut new_tail_helpers, new_tail) = - hoist_body_let_binding(outer_context.clone(), args.clone(), t.clone()); + hoist_body_let_binding(outer_context, args, t.clone())?; vres.append(&mut new_tail_helpers); - new_tail - }); + Some(new_tail) + } else { + None + }; - ( + Ok(( vres, Rc::new(BodyForm::Call(l.clone(), new_call_list, new_tail)), - ) + )) } - _ => (Vec::new(), body.clone()), + BodyForm::Lambda(letdata) => { + // A lambda is exactly the same as + // 1) A function whose argument list is the captures plus the + // non-capture arguments. + // 2) A call site which includes a reference to the function + // surrounded with a structure that curries on the capture + // arguments. + + // Compose the function and return it as a desugared function. + // The functions desugared here also come from let bindings. + let new_function_args = Rc::new(SExp::Cons( + letdata.loc.clone(), + letdata.capture_args.clone(), + letdata.args.clone(), + )); + let new_function_name = gensym(b"lambda".to_vec()); + let (mut new_helpers_from_body, new_body) = hoist_body_let_binding( + Some(new_function_args.clone()), + new_function_args.clone(), + letdata.body.clone(), + )?; + let function = HelperForm::Defun( + false, + DefunData { + loc: letdata.loc.clone(), + name: new_function_name.clone(), + kw: letdata.kw.clone(), + nl: letdata.args.loc(), + orig_args: new_function_args.clone(), + args: new_function_args, + body: new_body, + }, + ); + new_helpers_from_body.push(function); + + // new_expr is the generated code at the call site. The reference + // to the actual function additionally is enriched by a left-env + // reference that gives it access to the program. + let new_expr = lambda_codegen(&new_function_name, letdata); + Ok((new_helpers_from_body, Rc::new(new_expr))) + } + _ => Ok((Vec::new(), body.clone())), } } -pub fn process_helper_let_bindings(helpers: &[HelperForm]) -> Vec { +/// Turn the helpers for a program into the fully desugared set of helpers for +/// that program. This expands and re-processes the helper set until all +/// desugarable body forms have been transformed to a state where no more +/// desugaring is needed. +pub fn process_helper_let_bindings(helpers: &[HelperForm]) -> Result, CompileErr> { let mut result = helpers.to_owned(); let mut i = 0; @@ -996,7 +1289,7 @@ pub fn process_helper_let_bindings(helpers: &[HelperForm]) -> Vec { None }; let helper_result = - hoist_body_let_binding(context, defun.args.clone(), defun.body.clone()); + hoist_body_let_binding(context, defun.args.clone(), defun.body.clone())?; let hoisted_helpers = helper_result.0; let hoisted_body = helper_result.1.clone(); @@ -1025,12 +1318,11 @@ pub fn process_helper_let_bindings(helpers: &[HelperForm]) -> Vec { } } - result + Ok(result) } fn start_codegen( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, program: CompileForm, ) -> Result { @@ -1059,15 +1351,16 @@ fn start_codegen( )), ); let updated_opts = opts.set_code_generator(code_generator.clone()); + let runner = context.runner(); let code = updated_opts.compile_program( - allocator, + context.allocator(), runner.clone(), Rc::new(expand_program), &mut HashMap::new(), )?; run( - allocator, - runner.clone(), + context.allocator(), + runner, opts.prim_map(), Rc::new(code), Rc::new(SExp::Nil(defc.loc.clone())), @@ -1092,9 +1385,9 @@ fn start_codegen( } ConstantKind::Complex => { let evaluator = - Evaluator::new(opts.clone(), runner.clone(), program.helpers.clone()); + Evaluator::new(opts.clone(), context.runner(), program.helpers.clone()); let constant_result = evaluator.shrink_bodyform( - allocator, + context.allocator(), Rc::new(SExp::Nil(defc.loc.clone())), &HashMap::new(), defc.body.clone(), @@ -1133,18 +1426,20 @@ fn start_codegen( .set_code_generator(code_generator.clone()) .set_in_defun(false) .set_stdenv(false) + .set_start_env(None) .set_frontend_opt(false); + let runner = context.runner(); updated_opts .compile_program( - allocator, + context.allocator(), runner.clone(), macro_program, &mut HashMap::new(), ) .and_then(|code| { if opts.optimize() { - run_optimizer(allocator, runner.clone(), Rc::new(code)) + run_optimizer(context.allocator(), runner, Rc::new(code)) } else { Ok(Rc::new(code)) } @@ -1172,23 +1467,27 @@ fn start_codegen( }; code_generator.to_process = program.helpers.clone(); - code_generator.original_helpers = program.helpers.clone(); + // Ensure that we have the synthesis of the previous codegen's helpers and + // The ones provided with the new form if any. + let mut combined_helpers_for_codegen = program.helpers.clone(); + combined_helpers_for_codegen.append(&mut code_generator.original_helpers); + code_generator.original_helpers = combined_helpers_for_codegen; code_generator.final_expr = program.exp; Ok(code_generator) } fn final_codegen( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, compiler: &PrimaryCodegen, ) -> Result { + let runner = context.runner(); let opt_final_expr = if opts.optimize() { optimize_expr( - allocator, + context.allocator(), opts.clone(), - runner.clone(), + runner, compiler, compiler.final_expr.clone(), ) @@ -1198,7 +1497,7 @@ fn final_codegen( compiler.final_expr.clone() }; - generate_expr_code(allocator, runner, opts, compiler, opt_final_expr).map(|code| { + generate_expr_code(context, opts, compiler, opt_final_expr).map(|code| { let mut final_comp = compiler.clone(); final_comp.final_code = Some(CompiledCode(code.0, code.1)); final_comp @@ -1206,8 +1505,7 @@ fn final_codegen( } fn finalize_env_( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, c: &PrimaryCodegen, _l: Srcloc, @@ -1222,8 +1520,7 @@ fn finalize_env_( Some(res) => { let (arg_list, arg_tail) = synthesize_args(res.args.clone()); replace_in_inline( - allocator, - runner.clone(), + context, opts.clone(), c, l.clone(), @@ -1253,45 +1550,23 @@ fn finalize_env_( } } - SExp::Cons(l, h, r) => finalize_env_( - allocator, - runner.clone(), - opts.clone(), - c, - l.clone(), - h.clone(), - ) - .and_then(|h| { - finalize_env_( - allocator, - runner.clone(), - opts.clone(), - c, - l.clone(), - r.clone(), - ) - .map(|r| Rc::new(SExp::Cons(l.clone(), h.clone(), r))) - }), + SExp::Cons(l, h, r) => finalize_env_(context, opts.clone(), c, l.clone(), h.clone()) + .and_then(|h| { + finalize_env_(context, opts.clone(), c, l.clone(), r.clone()) + .map(|r| Rc::new(SExp::Cons(l.clone(), h.clone(), r))) + }), _ => Ok(env.clone()), } } fn finalize_env( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, c: &PrimaryCodegen, ) -> Result, CompileErr> { match c.env.borrow() { - SExp::Cons(l, h, _) => finalize_env_( - allocator, - runner.clone(), - opts.clone(), - c, - l.clone(), - h.clone(), - ), + SExp::Cons(l, h, _) => finalize_env_(context, opts.clone(), c, l.clone(), h.clone()), _ => Ok(c.env.clone()), } } @@ -1329,30 +1604,25 @@ fn dummy_functions(compiler: &PrimaryCodegen) -> Result, + context: &mut BasicCompileContext, opts: Rc, cmod: &CompileForm, - symbol_table: &mut HashMap, ) -> Result { - let mut code_generator = dummy_functions(&start_codegen( - allocator, - runner.clone(), - opts.clone(), - cmod.clone(), - )?)?; + let mut code_generator = dummy_functions(&start_codegen(context, opts.clone(), cmod.clone())?)?; let to_process = code_generator.to_process.clone(); for f in to_process { - code_generator = codegen_(allocator, runner.clone(), opts.clone(), &code_generator, &f)?; + code_generator = codegen_(context, opts.clone(), &code_generator, &f)?; } - *symbol_table = code_generator.function_symbols.clone(); - symbol_table.insert("source_file".to_string(), opts.filename()); + *context.symbols() = code_generator.function_symbols.clone(); + context + .symbols() + .insert("source_file".to_string(), opts.filename()); - final_codegen(allocator, runner.clone(), opts.clone(), &code_generator).and_then(|c| { - let final_env = finalize_env(allocator, runner.clone(), opts.clone(), &c)?; + final_codegen(context, opts.clone(), &code_generator).and_then(|c| { + let final_env = finalize_env(context, opts.clone(), &c)?; match c.final_code { None => Err(CompileErr( @@ -1361,7 +1631,9 @@ pub fn codegen( )), Some(code) => { // Capture symbols now that we have the final form of the produced code. - symbol_table.insert("__chia__main_arguments".to_string(), cmod.args.to_string()); + context + .symbols() + .insert("__chia__main_arguments".to_string(), cmod.args.to_string()); if opts.in_defun() { let final_code = primapply( diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index 8b496de8f..7f458d078 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -23,6 +23,7 @@ use crate::compiler::prims; use crate::compiler::runtypes::RunFailure; use crate::compiler::sexp::{parse_sexp, SExp}; use crate::compiler::srcloc::Srcloc; +use crate::compiler::{BasicCompileContext, CompileContextWrapper}; use crate::util::Number; lazy_static! { @@ -108,11 +109,11 @@ pub fn create_prim_map() -> Rc, Rc>> { } fn fe_opt( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, compileform: CompileForm, ) -> Result { + let runner = context.runner(); let evaluator = Evaluator::new(opts.clone(), runner.clone(), compileform.helpers.clone()); let mut optimized_helpers: Vec = Vec::new(); for h in compileform.helpers.iter() { @@ -121,7 +122,7 @@ fn fe_opt( let mut env = HashMap::new(); build_reflex_captures(&mut env, defun.args.clone()); let body_rc = evaluator.shrink_bodyform( - allocator, + context.allocator(), defun.args.clone(), &env, defun.body.clone(), @@ -150,7 +151,7 @@ fn fe_opt( let new_evaluator = Evaluator::new(opts.clone(), runner.clone(), optimized_helpers.clone()); let shrunk = new_evaluator.shrink_bodyform( - allocator, + context.allocator(), Rc::new(SExp::Nil(compileform.args.loc())), &HashMap::new(), compileform.exp.clone(), @@ -174,22 +175,25 @@ pub fn compile_from_compileform( p0: CompileForm, symbol_table: &mut HashMap, ) -> Result { + let mut wrapper = CompileContextWrapper::new( + allocator, runner, symbol_table + ); let p1 = if opts.frontend_opt() { // Front end optimization - fe_opt(allocator, runner.clone(), opts.clone(), p0)? + fe_opt(&mut wrapper.context, opts.clone(), p0)? } else { p0 }; // Transform let bindings, merging nested let scopes with the top namespace - let hoisted_bindings = hoist_body_let_binding(None, p1.args.clone(), p1.exp.clone()); + let hoisted_bindings = hoist_body_let_binding(None, p1.args.clone(), p1.exp.clone())?; let mut new_helpers = hoisted_bindings.0; let expr = hoisted_bindings.1; // expr is the let-hoisted program // TODO: Distinguish the frontend_helpers and the hoisted_let helpers for later stages let mut combined_helpers = p1.helpers.clone(); combined_helpers.append(&mut new_helpers); - let combined_helpers = process_helper_let_bindings(&combined_helpers); + let combined_helpers = process_helper_let_bindings(&combined_helpers)?; let p2 = CompileForm { loc: p1.loc.clone(), @@ -200,7 +204,7 @@ pub fn compile_from_compileform( }; // generate code from AST, optionally with optimization - codegen(allocator, runner, opts, &p2, symbol_table) + codegen(&mut wrapper.context, opts, &p2) } pub fn compile_pre_forms( @@ -230,7 +234,6 @@ pub fn compile_file( symbol_table: &mut HashMap, ) -> Result { let pre_forms = parse_sexp(Srcloc::start(&opts.filename()), content.bytes())?; - compile_pre_forms(allocator, runner, opts, &pre_forms, symbol_table) } diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index 32b08b180..133f4f6fe 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -9,11 +9,19 @@ use clvm_rs::allocator::Allocator; use crate::classic::clvm::__type_compatibility__::{Bytes, BytesFromType}; use crate::classic::clvm_tools::stages::stage_0::TRunProgram; -use crate::compiler::clvm::sha256tree; +use crate::compiler::clvm::{sha256tree, truthy}; use crate::compiler::dialect::AcceptedDialect; -use crate::compiler::sexp::{decode_string, SExp}; +use crate::compiler::sexp::{decode_string, enlist, SExp}; use crate::compiler::srcloc::Srcloc; +// Note: only used in tests, not normally dependencies. +#[cfg(test)] +use crate::compiler::compiler::DefaultCompilerOpts; +#[cfg(test)] +use crate::compiler::frontend::compile_bodyform; +#[cfg(test)] +use crate::compiler::sexp::parse_sexp; + /// The basic error type. It contains a Srcloc identifying coordinates of the /// error in the source file and a message. It probably should be made even better /// but this works ok. @@ -82,6 +90,24 @@ pub fn list_to_cons(l: Srcloc, list: &[Rc]) -> SExp { result } +/// Specifies the pattern that is destructured in let bindings. +#[derive(Clone, Debug, Serialize)] +pub enum BindingPattern { + /// The whole expression is bound to this name. + Name(Vec), + /// Specifies a tree of atoms into which the value will be destructured. + Complex(Rc), +} + +/// If present, states an intention for desugaring of this let form to favor +/// inlining or functions. +#[derive(Clone, Debug, Serialize)] +pub enum LetFormInlineHint { + NoChoice, + Inline(Srcloc), + NonInline(Srcloc), +} + /// A binding from a (let ...) form. Specifies the name of the bound variable /// the location of the whole binding form, the location of the name atom (nl) /// and the body as a BodyForm (which are chialisp expressions). @@ -91,8 +117,11 @@ pub struct Binding { pub loc: Srcloc, /// Location of the name atom specifically. pub nl: Srcloc, - /// The name. - pub name: Vec, + /// Specifies the pattern which is extracted from the expression, which can + /// be a Name (a single name names the whole subexpression) or Complex which + /// can destructure and is used in code that extends cl21 past the definition + /// of the language at that point. + pub pattern: BindingPattern, /// The expression the binding refers to. pub body: Rc, } @@ -105,6 +134,7 @@ pub struct Binding { pub enum LetFormKind { Parallel, Sequential, + Assign, } /// Information about a let form. Encapsulates everything except whether it's @@ -115,16 +145,29 @@ pub struct LetData { pub loc: Srcloc, /// The location specifically of the let or let* keyword. pub kw: Option, + /// Inline hint. + pub inline_hint: Option, /// The bindings introduced. pub bindings: Vec>, /// The expression evaluated in the context of all the bindings. pub body: Rc, } +/// Describes a lambda used in an expression. +#[derive(Clone, Debug, Serialize)] +pub struct LambdaData { + pub loc: Srcloc, + pub kw: Option, + pub capture_args: Rc, + pub captures: Rc, + pub args: Rc, + pub body: Rc, +} + #[derive(Clone, Debug, Serialize)] pub enum BodyForm { /// A let or let* form (depending on LetFormKind). - Let(LetFormKind, LetData), + Let(LetFormKind, Box), /// An explicitly quoted constant of some kind. Quoted(SExp), /// An undiferentiated "value" of some kind in the source language. @@ -148,6 +191,17 @@ pub enum BodyForm { /// the compiled code. Here, it contains a CompileForm, which represents /// the full significant input of a program (yielded by frontend()). Mod(Srcloc, CompileForm), + /// A lambda form (lambda (...) ...) + /// + /// The lambda arguments are in two parts: + /// + /// (lambda ((& captures) real args) ...) + /// + /// Where the parts in captures are captured from the hosting environment. + /// Captures are optional. + /// The real args are given in the indicated shape when the lambda is applied + /// with the 'a' operator. + Lambda(Box), } /// The information needed to know about a defun. Whether it's inline is left in @@ -644,6 +698,88 @@ impl HelperForm { } } +fn compose_lambda_serialized_form(ldata: &LambdaData) -> Rc { + let lambda_kw = Rc::new(SExp::Atom(ldata.loc.clone(), b"lambda".to_vec())); + let amp_kw = Rc::new(SExp::Atom(ldata.loc.clone(), b"&".to_vec())); + let arguments = if truthy(ldata.capture_args.clone()) { + Rc::new(SExp::Cons( + ldata.loc.clone(), + Rc::new(SExp::Cons( + ldata.loc.clone(), + amp_kw, + ldata.capture_args.clone(), + )), + ldata.args.clone(), + )) + } else { + ldata.args.clone() + }; + let rest_of_body = Rc::new(SExp::Cons( + ldata.loc.clone(), + ldata.body.to_sexp(), + Rc::new(SExp::Nil(ldata.loc.clone())), + )); + + Rc::new(SExp::Cons( + ldata.loc.clone(), + lambda_kw, + Rc::new(SExp::Cons(ldata.loc.clone(), arguments, rest_of_body)), + )) +} + +fn compose_let(marker: &[u8], letdata: &LetData) -> Rc { + let translated_bindings: Vec> = letdata.bindings.iter().map(|x| x.to_sexp()).collect(); + let bindings_cons = list_to_cons(letdata.loc.clone(), &translated_bindings); + let translated_body = letdata.body.to_sexp(); + let kw_loc = letdata.kw.clone().unwrap_or_else(|| letdata.loc.clone()); + Rc::new(SExp::Cons( + letdata.loc.clone(), + Rc::new(SExp::Atom(kw_loc, marker.to_vec())), + Rc::new(SExp::Cons( + letdata.loc.clone(), + Rc::new(bindings_cons), + Rc::new(SExp::Cons( + letdata.loc.clone(), + translated_body, + Rc::new(SExp::Nil(letdata.loc.clone())), + )), + )), + )) +} + +fn compose_assign(letdata: &LetData) -> Rc { + let mut result = Vec::new(); + let kw_loc = letdata.kw.clone().unwrap_or_else(|| letdata.loc.clone()); + result.push(Rc::new(SExp::Atom(kw_loc, b"assign".to_vec()))); + for b in letdata.bindings.iter() { + // Binding pattern + match &b.pattern { + BindingPattern::Name(v) => { + result.push(Rc::new(SExp::Atom(b.nl.clone(), v.to_vec()))); + } + BindingPattern::Complex(c) => { + result.push(c.clone()); + } + } + + // Binding body. + result.push(b.body.to_sexp()); + } + + result.push(letdata.body.to_sexp()); + Rc::new(enlist(letdata.loc.clone(), &result)) +} + +fn get_let_marker_text(kind: &LetFormKind, letdata: &LetData) -> Vec { + match (kind, letdata.inline_hint.as_ref()) { + (LetFormKind::Sequential, _) => b"let*".to_vec(), + (LetFormKind::Parallel, _) => b"let".to_vec(), + (LetFormKind::Assign, Some(LetFormInlineHint::Inline(_))) => b"assign-inline".to_vec(), + (LetFormKind::Assign, Some(LetFormInlineHint::NonInline(_))) => b"assign-lambda".to_vec(), + (LetFormKind::Assign, _) => b"assign".to_vec(), + } +} + impl BodyForm { /// Get the general location of the BodyForm. pub fn loc(&self) -> Srcloc { @@ -653,6 +789,7 @@ impl BodyForm { BodyForm::Call(loc, _, _) => loc.clone(), BodyForm::Value(a) => a.loc(), BodyForm::Mod(kl, program) => kl.ext(&program.loc), + BodyForm::Lambda(ldata) => ldata.loc.ext(&ldata.body.loc()), } } @@ -661,29 +798,10 @@ impl BodyForm { /// afterward. pub fn to_sexp(&self) -> Rc { match self { + BodyForm::Let(LetFormKind::Assign, letdata) => compose_assign(letdata), BodyForm::Let(kind, letdata) => { - let translated_bindings: Vec> = - letdata.bindings.iter().map(|x| x.to_sexp()).collect(); - let bindings_cons = list_to_cons(letdata.loc.clone(), &translated_bindings); - let translated_body = letdata.body.to_sexp(); - let marker = match kind { - LetFormKind::Parallel => "let", - LetFormKind::Sequential => "let*", - }; - let kw_loc = letdata.kw.clone().unwrap_or_else(|| letdata.loc.clone()); - Rc::new(SExp::Cons( - letdata.loc.clone(), - Rc::new(SExp::atom_from_string(kw_loc, marker)), - Rc::new(SExp::Cons( - letdata.loc.clone(), - Rc::new(bindings_cons), - Rc::new(SExp::Cons( - letdata.loc.clone(), - translated_body, - Rc::new(SExp::Nil(letdata.loc.clone())), - )), - )), - )) + let marker = get_let_marker_text(kind, letdata); + compose_let(&marker, letdata) } BodyForm::Quoted(body) => Rc::new(SExp::Cons( body.loc(), @@ -704,16 +822,45 @@ impl BodyForm { Rc::new(SExp::Atom(loc.clone(), b"mod".to_vec())), program.to_sexp(), )), + BodyForm::Lambda(ldata) => compose_lambda_serialized_form(ldata), } } } +// Note: in cfg(test), this will not be part of the finished binary. +// Also: not a test in itself, just named test so for at least some readers, +// its association with test infrastructure will be apparent. +#[cfg(test)] +fn test_parse_bodyform_to_frontend(bf: &str) { + let name = "*test*"; + let loc = Srcloc::start(name); + let opts = Rc::new(DefaultCompilerOpts::new(name)); + let parsed = parse_sexp(loc, bf.bytes()).expect("should parse"); + let bodyform = compile_bodyform(opts, parsed[0].clone()).expect("should compile"); + assert_eq!(bodyform.to_sexp(), parsed[0]); +} + +// Inline unit tests for sexp serialization. +#[test] +fn test_mod_serialize_regular_mod() { + test_parse_bodyform_to_frontend("(mod (X) (+ X 1))"); +} + +#[test] +fn test_mod_serialize_simple_lambda() { + test_parse_bodyform_to_frontend("(lambda (X) (+ X 1))"); +} + impl Binding { /// Express the binding as it would be used in a let form. pub fn to_sexp(&self) -> Rc { + let pat = match &self.pattern { + BindingPattern::Name(name) => Rc::new(SExp::atom_from_vec(self.loc.clone(), name)), + BindingPattern::Complex(sexp) => sexp.clone(), + }; Rc::new(SExp::Cons( self.loc.clone(), - Rc::new(SExp::atom_from_vec(self.loc.clone(), &self.name)), + pat, Rc::new(SExp::Cons( self.loc.clone(), self.body.to_sexp(), @@ -810,7 +957,10 @@ pub fn cons_of_string_map( list_to_cons(l, &sorted_converted) } -pub fn map_m(f: &dyn Fn(&T) -> Result, list: &[T]) -> Result, E> { +pub fn map_m(mut f: F, list: &[T]) -> Result, E> +where + F: FnMut(&T) -> Result, +{ let mut result = Vec::new(); for e in list { let val = f(e)?; @@ -819,6 +969,18 @@ pub fn map_m(f: &dyn Fn(&T) -> Result, list: &[T]) -> Result(mut f: F, list: &[T]) -> Result, E> +where + F: FnMut(&T) -> Result, +{ + let mut result = Vec::new(); + for e in list { + let val = f(e)?; + result.push(val); + } + Ok(result.into_iter().rev().collect()) +} + pub fn fold_m(f: &dyn Fn(&R, &T) -> Result, start: R, list: &[T]) -> Result { let mut res: R = start; for elt in list.iter() { diff --git a/src/compiler/dialect.rs b/src/compiler/dialect.rs index 4dc8a10b3..e3f876e93 100644 --- a/src/compiler/dialect.rs +++ b/src/compiler/dialect.rs @@ -88,7 +88,7 @@ lazy_static! { fn include_dialect(allocator: &Allocator, e: &[NodePtr]) -> Option { let include_keyword_sexp = e[0]; let name_sexp = e[1]; - if let (SExp::Atom(), SExp::Atom()) = ( + if let (SExp::Atom, SExp::Atom) = ( allocator.sexp(include_keyword_sexp), allocator.sexp(name_sexp), ) { diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index e0b4f7da6..dac42fd32 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -9,18 +9,19 @@ use clvm_rs::allocator::Allocator; use crate::classic::clvm::__type_compatibility__::{bi_one, bi_zero}; use crate::classic::clvm_tools::stages::stage_0::TRunProgram; -use crate::compiler::clvm::run; -use crate::compiler::codegen::codegen; +use crate::compiler::clvm::{run, truthy}; +use crate::compiler::codegen::{codegen, hoist_assign_form}; use crate::compiler::compiler::is_at_capture; use crate::compiler::comptypes::{ - Binding, BodyForm, CallSpec, CompileErr, CompileForm, CompilerOpts, HelperForm, LetData, - LetFormKind, + Binding, BindingPattern, BodyForm, CallSpec, CompileErr, CompileForm, CompilerOpts, DefunData, + HelperForm, LambdaData, LetData, LetFormInlineHint, LetFormKind, }; use crate::compiler::frontend::frontend; use crate::compiler::runtypes::RunFailure; use crate::compiler::sexp::{enlist, SExp}; use crate::compiler::srcloc::Srcloc; use crate::compiler::stackvisit::{HasDepthLimit, VisitedMarker}; +use crate::compiler::CompileContextWrapper; use crate::util::{number_from_u8, u8_from_number, Number}; const PRIM_RUN_LIMIT: usize = 1000000; @@ -63,6 +64,12 @@ impl<'info> VisitedInfoAccess for VisitedMarker<'info, VisitedInfo> { } } +pub struct LambdaApply { + lambda: LambdaData, + body: Rc, + env: Rc, +} + // Frontend evaluator based on my fuzzer representation and direct interpreter of // that. @@ -145,13 +152,74 @@ fn select_helper(bindings: &[HelperForm], name: &[u8]) -> Option { None } +fn compute_paths_of_destructure( + bindings: &mut Vec<(Vec, Rc)>, + structure: Rc, + path: Number, + mask: Number, + bodyform: Rc, +) { + match structure.atomize() { + SExp::Cons(_, a, b) => { + let next_mask = mask.clone() * 2_u32.to_bigint().unwrap(); + let next_right_path = mask + path.clone(); + compute_paths_of_destructure(bindings, a, path, next_mask.clone(), bodyform.clone()); + compute_paths_of_destructure(bindings, b, next_right_path, next_mask, bodyform); + } + SExp::Atom(_, name) => { + let mut produce_path = path.clone() | mask; + let mut output_form = bodyform.clone(); + + while produce_path > bi_one() { + if path.clone() & produce_path.clone() != bi_zero() { + // Right path + output_form = Rc::new(make_operator1( + &bodyform.loc(), + "r".to_string(), + output_form, + )); + } else { + // Left path + output_form = Rc::new(make_operator1( + &bodyform.loc(), + "f".to_string(), + output_form, + )); + } + + produce_path /= 2_u32.to_bigint().unwrap(); + } + + bindings.push((name, output_form)); + } + _ => {} + } +} + fn update_parallel_bindings( bindings: &HashMap, Rc>, have_bindings: &[Rc], ) -> HashMap, Rc> { let mut new_bindings = bindings.clone(); for b in have_bindings.iter() { - new_bindings.insert(b.name.clone(), b.body.clone()); + match &b.pattern { + BindingPattern::Name(name) => { + new_bindings.insert(name.clone(), b.body.clone()); + } + BindingPattern::Complex(structure) => { + let mut computed_getters = Vec::new(); + compute_paths_of_destructure( + &mut computed_getters, + structure.clone(), + bi_zero(), + bi_one(), + b.body.clone(), + ); + for (name, p) in computed_getters.iter() { + new_bindings.insert(name.clone(), p.clone()); + } + } + } } new_bindings } @@ -306,6 +374,16 @@ fn arg_inputs_primitive(arginputs: Rc) -> bool { } } +fn decons_args(formed_tail: Rc) -> ArgInputs { + if let Some((head, tail)) = match_cons(formed_tail.clone()) { + let arg_head = decons_args(head.clone()); + let arg_tail = decons_args(tail.clone()); + ArgInputs::Pair(Rc::new(arg_head), Rc::new(arg_tail)) + } else { + ArgInputs::Whole(formed_tail) + } +} + pub fn build_argument_captures( l: &Srcloc, arguments_to_convert: &[Rc], @@ -313,7 +391,7 @@ pub fn build_argument_captures( args: Rc, ) -> Result, Rc>, CompileErr> { let formed_tail = tail.unwrap_or_else(|| Rc::new(BodyForm::Quoted(SExp::Nil(l.clone())))); - let mut formed_arguments = ArgInputs::Whole(formed_tail); + let mut formed_arguments = decons_args(formed_tail); for i_reverse in 0..arguments_to_convert.len() { let i = arguments_to_convert.len() - i_reverse - 1; @@ -625,6 +703,31 @@ fn flatten_expression_to_names(expr: Rc) -> Rc { Rc::new(BodyForm::Call(expr.loc(), call_vec, None)) } +pub fn eval_dont_expand_let(inline_hint: &Option) -> bool { + matches!(inline_hint, Some(LetFormInlineHint::NonInline(_))) +} + +pub fn filter_capture_args(args: Rc, name_map: &HashMap, Rc>) -> Rc { + match args.borrow() { + SExp::Cons(l, a, b) => { + let a_filtered = filter_capture_args(a.clone(), name_map); + let b_filtered = filter_capture_args(b.clone(), name_map); + if !truthy(a_filtered.clone()) && !truthy(b_filtered.clone()) { + return Rc::new(SExp::Nil(l.clone())); + } + Rc::new(SExp::Cons(l.clone(), a_filtered, b_filtered)) + } + SExp::Atom(l, n) => { + if name_map.contains_key(n) { + Rc::new(SExp::Nil(l.clone())) + } else { + args + } + } + _ => Rc::new(SExp::Nil(args.loc())), + } +} + impl<'info> Evaluator { pub fn new( opts: Rc, @@ -737,11 +840,98 @@ impl<'info> Evaluator { )) } + fn is_lambda_apply( + &self, + allocator: &mut Allocator, + visited_: &'info mut VisitedMarker<'_, VisitedInfo>, + prog_args: Rc, + env: &HashMap, Rc>, + parts: &[Rc], + only_inline: bool, + ) -> Result, CompileErr> { + if parts.len() == 3 && is_apply_atom(parts[0].to_sexp()) { + let mut visited = VisitedMarker::again(parts[0].loc(), visited_)?; + let evaluated_prog = self.shrink_bodyform_visited( + allocator, + &mut visited, + prog_args.clone(), + env, + parts[1].clone(), + only_inline, + )?; + let evaluated_env = self.shrink_bodyform_visited( + allocator, + &mut visited, + prog_args, + env, + parts[2].clone(), + only_inline, + )?; + if let BodyForm::Lambda(ldata) = evaluated_prog.borrow() { + return Ok(Some(LambdaApply { + lambda: *ldata.clone(), + body: ldata.body.clone(), + env: evaluated_env, + })); + } + } + + Ok(None) + } + + fn do_lambda_apply( + &self, + allocator: &mut Allocator, + visited: &mut VisitedMarker<'info, VisitedInfo>, + prog_args: Rc, + env: &HashMap, Rc>, + lapply: &LambdaApply, + only_inline: bool, + ) -> Result, CompileErr> { + let mut lambda_env = env.clone(); + + // Finish eta-expansion. + + // We're carrying an enriched environment which we can use to enrich + // the env map at this time. Once we do that we can expand the body + // fully because we're carring the info that goes with the primary + // arguments. + // + // Generate the enriched environment. + let reified_captures = self.shrink_bodyform_visited( + allocator, + visited, + prog_args, + env, + lapply.lambda.captures.clone(), + only_inline, + )?; + let formed_caps = ArgInputs::Whole(reified_captures); + create_argument_captures( + &mut lambda_env, + &formed_caps, + lapply.lambda.capture_args.clone(), + )?; + + // Create captures with the actual parameters. + let formed_args = ArgInputs::Whole(lapply.env.clone()); + create_argument_captures(&mut lambda_env, &formed_args, lapply.lambda.args.clone())?; + + self.shrink_bodyform_visited( + allocator, + visited, + lapply.lambda.args.clone(), + &lambda_env, + lapply.body.clone(), + only_inline, + ) + } + #[allow(clippy::too_many_arguments)] fn invoke_primitive( &self, allocator: &mut Allocator, - visited: &mut VisitedMarker<'info, VisitedInfo>, + visited_: &'info mut VisitedMarker<'_, VisitedInfo>, call: &CallSpec, prog_args: Rc, arguments_to_convert: &[Rc], @@ -750,6 +940,7 @@ impl<'info> Evaluator { ) -> Result, CompileErr> { let mut all_primitive = true; let mut target_vec: Vec> = call.args.to_owned(); + let mut visited = VisitedMarker::again(call.loc.clone(), visited_)?; if call.name == "@".as_bytes() { // Synthesize the environment for this function @@ -775,7 +966,7 @@ impl<'info> Evaluator { let i = arguments_to_convert.len() - i_reverse - 1; let shrunk = self.shrink_bodyform_visited( allocator, - visited, + &mut visited, prog_args.clone(), env, arguments_to_convert[i].clone(), @@ -812,11 +1003,27 @@ impl<'info> Evaluator { } } } + } else if let Some(applied_lambda) = self.is_lambda_apply( + allocator, + &mut visited, + prog_args.clone(), + env, + &target_vec, + only_inline, + )? { + self.do_lambda_apply( + allocator, + &mut visited, + prog_args.clone(), + env, + &applied_lambda, + only_inline, + ) } else { // Since this is a primitive, there's no tail transform. let reformed = BodyForm::Call(call.loc.clone(), target_vec.clone(), call.tail.clone()); - self.chase_apply(allocator, visited, Rc::new(reformed)) + self.chase_apply(allocator, &mut visited, Rc::new(reformed)) } }) .unwrap_or_else(|| { @@ -1001,10 +1208,23 @@ impl<'info> Evaluator { return Ok(call.original.clone()); } + let translated_tail = if let Some(t) = call.tail.as_ref() { + Some(self.shrink_bodyform_visited( + allocator, + visited, + prog_args.clone(), + env, + t.clone(), + only_inline, + )?) + } else { + None + }; + let argument_captures_untranslated = build_argument_captures( &call.loc.clone(), arguments_to_convert, - call.tail.clone(), + translated_tail.clone(), defun.args.clone(), )?; @@ -1047,6 +1267,101 @@ impl<'info> Evaluator { } } + fn enrich_lambda_site_info( + &self, + allocator: &mut Allocator, + visited: &'info mut VisitedMarker<'_, VisitedInfo>, + prog_args: Rc, + env: &HashMap, Rc>, + ldata: &LambdaData, + only_inline: bool, + ) -> Result, CompileErr> { + if !truthy(ldata.capture_args.clone()) { + return Ok(Rc::new(BodyForm::Lambda(Box::new(ldata.clone())))); + } + + // Rewrite the captures based on what we know at the call site. + let new_captures = self.shrink_bodyform_visited( + allocator, + visited, + prog_args.clone(), + env, + ldata.captures.clone(), + only_inline, + )?; + + // Break up and make binding map. + let deconsed_args = decons_args(new_captures.clone()); + let mut arg_captures = HashMap::new(); + create_argument_captures( + &mut arg_captures, + &deconsed_args, + ldata.capture_args.clone(), + )?; + + // Filter out elements that are not interpretable yet. + let mut interpretable_captures = HashMap::new(); + for (n, v) in arg_captures.iter() { + if dequote(v.loc(), v.clone()).is_ok() { + // This capture has already been made into a literal. + // We will substitute it in the lambda body and remove it + // from the capture set. + interpretable_captures.insert(n.clone(), v.clone()); + } + } + + let combined_args = Rc::new(SExp::Cons( + ldata.loc.clone(), + ldata.capture_args.clone(), + ldata.args.clone(), + )); + + // Eliminate the captures via beta substituion. + let simplified_body = self.shrink_bodyform_visited( + allocator, + visited, + combined_args.clone(), + &interpretable_captures, + ldata.body.clone(), + only_inline, + )?; + + let new_capture_args = + filter_capture_args(ldata.capture_args.clone(), &interpretable_captures); + Ok(Rc::new(BodyForm::Lambda(Box::new(LambdaData { + args: ldata.args.clone(), + capture_args: new_capture_args, + captures: new_captures, + body: simplified_body, + ..ldata.clone() + })))) + } + + fn get_function(&self, name: &[u8]) -> Option> { + for h in self.helpers.iter() { + if let HelperForm::Defun(false, dd) = &h { + if name == h.name() { + return Some(Box::new(dd.clone())); + } + } + } + + None + } + + fn create_mod_for_fun(&self, l: &Srcloc, function: &DefunData) -> Rc { + Rc::new(BodyForm::Mod( + l.clone(), + CompileForm { + loc: l.clone(), + include_forms: Vec::new(), + args: function.args.clone(), + helpers: self.helpers.clone(), + exp: function.body.clone(), + }, + )) + } + // A frontend language evaluator and minifier fn shrink_bodyform_visited( &self, @@ -1060,6 +1375,10 @@ impl<'info> Evaluator { let mut visited = VisitedMarker::again(body.loc(), visited_)?; match body.borrow() { BodyForm::Let(LetFormKind::Parallel, letdata) => { + if eval_dont_expand_let(&letdata.inline_hint) && only_inline { + return Ok(body.clone()); + } + let updated_bindings = update_parallel_bindings(env, &letdata.bindings); self.shrink_bodyform_visited( allocator, @@ -1071,6 +1390,10 @@ impl<'info> Evaluator { ) } BodyForm::Let(LetFormKind::Sequential, letdata) => { + if eval_dont_expand_let(&letdata.inline_hint) && only_inline { + return Ok(body.clone()); + } + if letdata.bindings.is_empty() { self.shrink_bodyform_visited( allocator, @@ -1094,17 +1417,29 @@ impl<'info> Evaluator { &updated_bindings, Rc::new(BodyForm::Let( LetFormKind::Sequential, - LetData { - loc: letdata.loc.clone(), - kw: letdata.kw.clone(), + Box::new(LetData { bindings: rest_of_bindings, - body: letdata.body.clone(), - }, + ..*letdata.clone() + }), )), only_inline, ) } } + BodyForm::Let(LetFormKind::Assign, letdata) => { + if eval_dont_expand_let(&letdata.inline_hint) && only_inline { + return Ok(body.clone()); + } + + self.shrink_bodyform_visited( + allocator, + &mut visited, + prog_args, + env, + Rc::new(hoist_assign_form(letdata)?), + only_inline, + ) + } BodyForm::Quoted(_) => Ok(body.clone()), BodyForm::Value(SExp::Atom(l, name)) => { if name == &"@".as_bytes().to_vec() { @@ -1117,6 +1452,15 @@ impl<'info> Evaluator { literal_args, only_inline, ) + } else if let Some(function) = self.get_function(name) { + self.shrink_bodyform_visited( + allocator, + &mut visited, + prog_args, + env, + self.create_mod_for_fun(l, function.borrow()), + only_inline, + ) } else { env.get(name) .map(|x| { @@ -1206,15 +1550,20 @@ impl<'info> Evaluator { } BodyForm::Mod(_, program) => { // A mod form yields the compiled code. - let code = codegen( - allocator, - self.runner.clone(), - self.opts.clone(), - program, - &mut HashMap::new(), - )?; + let mut symbols = HashMap::new(); + let mut context_wrapper = + CompileContextWrapper::new(allocator, self.runner.clone(), &mut symbols); + let code = codegen(&mut context_wrapper.context, self.opts.clone(), program)?; Ok(Rc::new(BodyForm::Quoted(code))) } + BodyForm::Lambda(ldata) => self.enrich_lambda_site_info( + allocator, + &mut visited, + prog_args, + env, + ldata, + only_inline, + ), } } diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index d936a8d75..bcd91247e 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -5,17 +5,18 @@ use std::rc::Rc; use crate::classic::clvm::__type_compatibility__::bi_one; use crate::compiler::comptypes::{ - list_to_cons, ArgsAndTail, Binding, BodyForm, CompileErr, CompileForm, CompilerOpts, - ConstantKind, DefconstData, DefmacData, DefunData, HelperForm, IncludeDesc, LetData, - LetFormKind, ModAccum, + list_to_cons, ArgsAndTail, Binding, BindingPattern, BodyForm, CompileErr, CompileForm, + CompilerOpts, ConstantKind, DefconstData, DefmacData, DefunData, HelperForm, IncludeDesc, + LetData, LetFormInlineHint, LetFormKind, ModAccum, }; +use crate::compiler::lambda::handle_lambda; use crate::compiler::preprocessor::preprocess; use crate::compiler::rename::rename_children_compileform; -use crate::compiler::sexp::{enlist, SExp}; +use crate::compiler::sexp::{decode_string, enlist, SExp}; use crate::compiler::srcloc::Srcloc; use crate::util::u8_from_number; -fn collect_used_names_sexp(body: Rc) -> Vec> { +pub fn collect_used_names_sexp(body: Rc) -> Vec> { match body.borrow() { SExp::Atom(_, name) => vec![name.to_vec()], SExp::Cons(_, head, tail) => { @@ -69,6 +70,11 @@ fn collect_used_names_bodyform(body: &BodyForm) -> Vec> { result } BodyForm::Mod(_, _) => vec![], + BodyForm::Lambda(ldata) => { + let mut capture_names = collect_used_names_bodyform(ldata.captures.borrow()); + capture_names.append(&mut collect_used_names_bodyform(ldata.body.borrow())); + capture_names + } } } @@ -253,20 +259,25 @@ fn make_let_bindings( body.loc(), format!("Bad binding tail {body:?}") )); - eprintln!("make_let_bindings {body}"); + let do_atomize = if opts.dialect().strict { + |a: &SExp| -> SExp { a.atomize() } + } else { + |a: &SExp| -> SExp { a.clone() } + }; match body.borrow() { SExp::Nil(_) => Ok(vec![]), SExp::Cons(_, head, tl) => head .proper_list() - .map(|x| match &x[..] { - [SExp::Atom(l, name), expr] => { + .filter(|x| x.len() == 2) + .map(|x| match (do_atomize(&x[0]), &x[1]) { + (SExp::Atom(l, name), expr) => { let compiled_body = compile_bodyform(opts.clone(), Rc::new(expr.clone()))?; let mut result = Vec::new(); let mut rest_bindings = make_let_bindings(opts, tl.clone())?; result.push(Rc::new(Binding { loc: l.clone(), - nl: l.clone(), - name: name.to_vec(), + nl: l, + pattern: BindingPattern::Name(name.to_vec()), body: Rc::new(compiled_body), })); result.append(&mut rest_bindings); @@ -282,6 +293,83 @@ fn make_let_bindings( } } +// Make a set of names in this sexp. +pub fn make_provides_set(provides_set: &mut HashSet>, body_sexp: Rc) { + match body_sexp.atomize() { + SExp::Cons(_, a, b) => { + make_provides_set(provides_set, a); + make_provides_set(provides_set, b); + } + SExp::Atom(_, name) => { + provides_set.insert(name); + } + _ => {} + } +} + +fn handle_assign_form( + opts: Rc, + l: Srcloc, + v: &[SExp], + inline_hint: Option, +) -> Result { + if v.len() % 2 == 0 { + return Err(CompileErr( + l, + "assign form should be in pairs of pattern value followed by an expression".to_string(), + )); + } + + let mut bindings = Vec::new(); + let mut check_duplicates = HashSet::new(); + + for idx in (0..(v.len() - 1) / 2).map(|idx| idx * 2) { + let destructure_pattern = Rc::new(v[idx].clone()); + let binding_body = compile_bodyform(opts.clone(), Rc::new(v[idx + 1].clone()))?; + + // Ensure bindings aren't duplicated as we won't be able to + // guarantee their order during toposort. + let mut this_provides = HashSet::new(); + make_provides_set(&mut this_provides, destructure_pattern.clone()); + + for item in this_provides.iter() { + if check_duplicates.contains(item) { + return Err(CompileErr( + destructure_pattern.loc(), + format!("Duplicate binding {}", decode_string(item)), + )); + } + check_duplicates.insert(item.clone()); + } + + bindings.push(Rc::new(Binding { + loc: v[idx].loc().ext(&v[idx + 1].loc()), + nl: destructure_pattern.loc(), + pattern: BindingPattern::Complex(destructure_pattern), + body: Rc::new(binding_body), + })); + } + + let compiled_body = compile_bodyform(opts.clone(), Rc::new(v[v.len() - 1].clone()))?; + // We don't need to do much if there were no bindings. + if bindings.is_empty() { + return Ok(compiled_body); + } + + // Return a precise representation of this assign while storing up the work + // we did breaking it down. + Ok(BodyForm::Let( + LetFormKind::Assign, + Box::new(LetData { + loc: l.clone(), + kw: Some(l), + bindings, + inline_hint, + body: Rc::new(compiled_body), + }), + )) +} + pub fn compile_bodyform( opts: Rc, body: Rc, @@ -316,23 +404,22 @@ pub fn compile_bodyform( match op.borrow() { SExp::Atom(l, atom_name) => { - if *atom_name == "q".as_bytes().to_vec() - || (atom_name.len() == 1 && atom_name[0] == 1) - { + if *atom_name == b"q" || (atom_name.len() == 1 && atom_name[0] == 1) { let tail_copy: &SExp = tail.borrow(); return Ok(BodyForm::Quoted(tail_copy.clone())); } + let assign_lambda = *atom_name == "assign-lambda".as_bytes().to_vec(); + let assign_inline = *atom_name == "assign-inline".as_bytes().to_vec(); + match tail.proper_list() { Some(v) => { - if *atom_name == "let".as_bytes().to_vec() - || *atom_name == "let*".as_bytes().to_vec() - { + if *atom_name == b"let" || *atom_name == b"let*" { if v.len() != 2 { return finish_err("let"); } - let kind = if *atom_name == "let".as_bytes().to_vec() { + let kind = if *atom_name == b"let" { LetFormKind::Parallel } else { LetFormKind::Sequential @@ -346,13 +433,30 @@ pub fn compile_bodyform( let compiled_body = compile_bodyform(opts, Rc::new(body))?; Ok(BodyForm::Let( kind, - LetData { + Box::new(LetData { loc: l.clone(), kw: Some(l.clone()), bindings: let_bindings, + inline_hint: None, body: Rc::new(compiled_body), - }, + }), )) + } else if assign_lambda + || assign_inline + || *atom_name == "assign".as_bytes().to_vec() + { + handle_assign_form( + opts.clone(), + l.clone(), + &v, + if assign_lambda { + Some(LetFormInlineHint::NonInline(l.clone())) + } else if assign_inline { + Some(LetFormInlineHint::Inline(l.clone())) + } else { + Some(LetFormInlineHint::NoChoice) + }, + ) } else if *atom_name == "quote".as_bytes().to_vec() { if v.len() != 1 { return finish_err("quote"); @@ -361,7 +465,7 @@ pub fn compile_bodyform( let quote_body = v[0].clone(); Ok(BodyForm::Quoted(quote_body)) - } else if *atom_name == "qq".as_bytes().to_vec() { + } else if *atom_name == b"qq" { if v.len() != 1 { return finish_err("qq"); } @@ -369,9 +473,11 @@ pub fn compile_bodyform( let quote_body = v[0].clone(); qq_to_expression(opts, Rc::new(quote_body)) - } else if *atom_name == "mod".as_bytes().to_vec() { + } else if *atom_name == b"mod" { let subparse = frontend(opts, &[body.clone()])?; Ok(BodyForm::Mod(op.loc(), subparse)) + } else if *atom_name == b"lambda" { + handle_lambda(opts, Some(l.clone()), &v) } else { application() } @@ -755,7 +861,7 @@ fn frontend_start( )); } - if *mod_atom == "mod".as_bytes().to_vec() { + if *mod_atom == b"mod" { let args = Rc::new(x[1].clone()); let body_vec: Vec> = x.iter().skip(2).map(|s| Rc::new(s.clone())).collect(); @@ -812,7 +918,7 @@ pub fn frontend( } }; - let our_mod = rename_children_compileform(&compiled?); + let our_mod = rename_children_compileform(&compiled?)?; let expr_names: HashSet> = collect_used_names_bodyform(our_mod.exp.borrow()) .iter() diff --git a/src/compiler/inline.rs b/src/compiler/inline.rs index 604014e2b..c977e65ba 100644 --- a/src/compiler/inline.rs +++ b/src/compiler/inline.rs @@ -3,8 +3,6 @@ use std::borrow::Borrow; use std::collections::HashSet; use std::rc::Rc; -use clvm_rs::allocator::Allocator; - use crate::classic::clvm::__type_compatibility__::bi_one; use crate::classic::clvm_tools::stages::stage_0::TRunProgram; @@ -12,10 +10,11 @@ use crate::compiler::codegen::{generate_expr_code, get_call_name, get_callable}; use crate::compiler::compiler::is_at_capture; use crate::compiler::comptypes::{ ArgsAndTail, BodyForm, CallSpec, Callable, CompileErr, CompiledCode, CompilerOpts, - InlineFunction, PrimaryCodegen, + InlineFunction, LambdaData, PrimaryCodegen, }; use crate::compiler::sexp::{decode_string, SExp}; use crate::compiler::srcloc::Srcloc; +use crate::compiler::BasicCompileContext; use crate::util::Number; @@ -446,6 +445,24 @@ fn replace_inline_body( .unwrap_or_else(|| expr.clone()); Ok(alookup) } + BodyForm::Lambda(ldata) => { + let rewritten_captures = replace_inline_body( + visited_inlines, + runner, + opts, + compiler, + loc, + inline, + args, + tail, + callsite, + ldata.captures.clone(), + )?; + Ok(Rc::new(BodyForm::Lambda(Box::new(LambdaData { + captures: rewritten_captures, + ..*ldata.clone() + })))) + } _ => Ok(expr.clone()), } } @@ -468,8 +485,7 @@ fn replace_inline_body( /// tail argument if one exists. If not, then they're discarded. #[allow(clippy::too_many_arguments)] pub fn replace_in_inline( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, compiler: &PrimaryCodegen, loc: Srcloc, @@ -479,6 +495,7 @@ pub fn replace_in_inline( tail: Option>, ) -> Result { let mut visited = HashSet::new(); + let runner = context.runner(); visited.insert(inline.name.clone()); replace_inline_body( &mut visited, @@ -492,5 +509,5 @@ pub fn replace_in_inline( callsite, inline.body.clone(), ) - .and_then(|x| generate_expr_code(allocator, runner, opts, compiler, x)) + .and_then(|x| generate_expr_code(context, opts, compiler, x)) } diff --git a/src/compiler/lambda.rs b/src/compiler/lambda.rs new file mode 100644 index 000000000..1ce93538f --- /dev/null +++ b/src/compiler/lambda.rs @@ -0,0 +1,155 @@ +use std::borrow::Borrow; +use std::rc::Rc; + +use crate::compiler::clvm::truthy; +use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts, LambdaData}; +use crate::compiler::frontend::compile_bodyform; +use crate::compiler::sexp::SExp; +use crate::compiler::srcloc::Srcloc; + +fn make_captures(opts: Rc, sexp: Rc) -> Result, CompileErr> { + if let SExp::Cons(l, f, r) = sexp.borrow() { + Ok(Rc::new(make_operator( + l.clone(), + 4, + make_captures(opts.clone(), f.clone())?, + make_captures(opts, r.clone())?, + ))) + } else if !truthy(sexp.clone()) { + Ok(Rc::new(BodyForm::Quoted(SExp::Nil(sexp.loc())))) + } else { + Ok(Rc::new(compile_bodyform(opts, sexp)?)) + } +} + +struct FoundLambdaCaptures { + args: Rc, + capture_args: Rc, + captures: Rc, +} + +fn find_and_compose_captures( + opts: Rc, + sexp: &SExp, +) -> Result { + let mut found = FoundLambdaCaptures { + args: Rc::new(sexp.clone()), + capture_args: Rc::new(SExp::Nil(sexp.loc())), + captures: Rc::new(BodyForm::Quoted(SExp::Nil(sexp.loc()))), + }; + if let SExp::Cons(_, l, r) = sexp { + if let SExp::Cons(_, head, rest) = l.borrow() { + if let SExp::Atom(_, name) = head.borrow() { + if name == b"&" { + found.args = r.clone(); + found.capture_args = rest.clone(); + found.captures = make_captures(opts, rest.clone())?; + } + } + } + } + + Ok(found) +} + +fn make_operator(loc: Srcloc, op: u8, arg1: Rc, arg2: Rc) -> BodyForm { + BodyForm::Call( + loc.clone(), + vec![ + Rc::new(BodyForm::Value(SExp::Atom(loc, vec![op]))), + arg1, + arg2, + ], + // Calling a primitive, no tail. + None, + ) +} + +fn make_cons(loc: Srcloc, arg1: Rc, arg2: Rc) -> BodyForm { + make_operator(loc, 4, arg1, arg2) +} + +fn make_list(loc: Srcloc, args: &[BodyForm]) -> BodyForm { + let mut res = BodyForm::Quoted(SExp::Nil(loc.clone())); + let cons_atom = BodyForm::Value(SExp::Atom(loc.clone(), vec![4])); + for a in args.iter().rev() { + res = BodyForm::Call( + loc.clone(), + vec![Rc::new(cons_atom.clone()), Rc::new(a.clone()), Rc::new(res)], + // Calling a primitive, no tail. + None, + ); + } + res +} + +// +// Lambda +// +// (lambda ((& captures) arguments) +// (body) +// ) +// +// Yields: +// +// (list 2 +// (c 1 ) +// (list 4 (list 4 (c 1 compose_captures) @)) +// ) +// +pub fn lambda_codegen(name: &[u8], ldata: &LambdaData) -> BodyForm { + // Code to retrieve and quote the captures. + let quote_atom = BodyForm::Value(SExp::Atom(ldata.loc.clone(), vec![1])); + let apply_atom = BodyForm::Value(SExp::Atom(ldata.loc.clone(), vec![2])); + let cons_atom = BodyForm::Value(SExp::Atom(ldata.loc.clone(), vec![4])); + let whole_env = quote_atom.clone(); + + let compose_captures = make_cons( + ldata.loc.clone(), + Rc::new(quote_atom.clone()), + ldata.captures.clone(), + ); + + make_list( + ldata.loc.clone(), + &[ + apply_atom, + make_cons( + ldata.loc.clone(), + Rc::new(quote_atom), + Rc::new(BodyForm::Value(SExp::Atom( + ldata.loc.clone(), + name.to_vec(), + ))), + ), + make_list(ldata.loc.clone(), &[cons_atom, compose_captures, whole_env]), + ], + ) +} + +pub fn handle_lambda( + opts: Rc, + kw_loc: Option, + v: &[SExp], +) -> Result { + if v.len() < 2 { + return Err(CompileErr( + v[0].loc(), + "Must provide at least arguments and body to lambda".to_string(), + )); + } + + let found = find_and_compose_captures(opts.clone(), &v[0])?; + + // Requires captures + let subparse = compile_bodyform(opts, Rc::new(v[1].clone()))?; + + Ok(BodyForm::Lambda(Box::new(LambdaData { + loc: v[0].loc(), + kw: kw_loc, + args: found.args.clone(), + capture_args: found.capture_args.clone(), + captures: found.captures, + body: Rc::new(subparse), + }))) +} diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs index af2c6ff15..d3159d72e 100644 --- a/src/compiler/mod.rs +++ b/src/compiler/mod.rs @@ -20,7 +20,8 @@ pub mod evaluate; pub mod frontend; pub mod gensym; mod inline; -mod optimize; +mod lambda; +pub mod optimize; pub mod preprocessor; pub mod prims; pub mod rename; @@ -30,3 +31,129 @@ pub mod sexp; pub mod srcloc; pub mod stackvisit; pub mod usecheck; + +use clvmr::allocator::Allocator; +use std::collections::HashMap; +use std::mem::swap; +use std::rc::Rc; + +use crate::classic::clvm_tools::stages::stage_0::TRunProgram; + +/// An object which represents the standard set of mutable items passed down the +/// stack when compiling chialisp. +pub struct BasicCompileContext { + pub allocator: Allocator, + pub runner: Rc, + pub symbols: HashMap, +} + +impl BasicCompileContext { + /// Get a mutable allocator reference from this compile context. The + /// allocator is used any time we need to execute pure CLVM operators, such + /// as when evaluating macros or constant folding any chialisp expression. + fn allocator(&mut self) -> &mut Allocator { + &mut self.allocator + } + + /// Get the runner this compile context carries. This is used with the + /// allocator above to execute pure CLVM when needed either on behalf of a + /// macro or constant folding. + fn runner(&self) -> Rc { + self.runner.clone() + } + + /// Get the mutable symbol store this compile context carries. During + /// compilation, the compiler records the relationships between objects in + /// the source code and emitted CLVM expressions, along with other useful + /// information. + /// + /// There are times when we're in a subcompile (such as mod expressions when + /// the compile context needs to do swap in or out symbols or transform them + /// on behalf of the child. + fn symbols(&mut self) -> &mut HashMap { + &mut self.symbols + } + + /// Given allocator, runner and symbols, move the mutable objects into this + /// BasicCompileContext so it can own them and pass a single mutable + /// reference to itself down the stack. This allows these objects to be + /// queried and used by appropriate machinery. + pub fn new( + allocator: Allocator, + runner: Rc, + symbols: HashMap, + ) -> Self { + BasicCompileContext { + allocator, + runner, + symbols, + } + } +} + +/// A wrapper that owns a BasicCompileContext and remembers a mutable reference +/// to an allocator and symbols. It is used as a container to swap out these +/// objects for new ones used in an inner compile context. This is used when +/// a subcompile occurs such as when a macro is compiled to CLVM to be executed +/// or an inner mod is compiled. +pub struct CompileContextWrapper<'a> { + pub allocator: &'a mut Allocator, + pub symbols: &'a mut HashMap, + pub context: BasicCompileContext, +} + +impl<'a> CompileContextWrapper<'a> { + /// Given an allocator, runner and symbols, hold the mutable references from + /// the code above, swapping content into a new BasicCompileContext this + /// object contains. + /// + /// The new and drop methods both rely on the object's private 'switch' method + /// which swaps the mutable reference to allocator and symbols that the caller + /// holds with the new empty allocator and hashmap held by the inner + /// BasicCompileContext. This allows us to pin the mutable references here, + /// ensuring that this object is the only consumer of these objects when in + /// use, while allowing a new BasicCompileContext to be passed down. The user + /// may inspect, copy, modify etc the inner context before allowing the + /// CompileContextWrapper object to be dropped, which will put the modified + /// objects back in the mutable references given by the user. + /// + /// This object does more in the current (nightly) code, such as carrying the + /// optimizer, which is modified when an inner compile has a different sigil + /// and must be optimized differently. + pub fn new( + allocator: &'a mut Allocator, + runner: Rc, + symbols: &'a mut HashMap, + ) -> Self { + let bcc = BasicCompileContext { + allocator: Allocator::new(), + runner, + symbols: HashMap::new(), + }; + let mut wrapper = CompileContextWrapper { + allocator, + symbols, + context: bcc, + }; + wrapper.switch(); + wrapper + } + + /// Swap allocator and symbols with the ones in self.context. This has the + /// effect of making the inner context hold the same information that would + /// have been passed down in these members had it come from the caller's + /// perspective. Useful when compile context has more fields and needs + /// to change for a consumer down the stack. + fn switch(&mut self) { + swap(self.allocator, &mut self.context.allocator); + swap(self.symbols, &mut self.context.symbols); + } +} + +/// Drop CompileContextWrapper reverts the contained objects back to the ones +/// owned by the caller. +impl<'a> Drop for CompileContextWrapper<'a> { + fn drop(&mut self) { + self.switch(); + } +} diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index 6cff08790..bc94064a6 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -368,7 +368,7 @@ impl Preprocessor { )), )); if let Some(helper) = compile_helperform(self.opts.clone(), target_defun)? { - self.add_helper(rename_args_helperform(&helper)); + self.add_helper(rename_args_helperform(&helper)?); } else { return Err(CompileErr( definition.loc(), @@ -376,7 +376,7 @@ impl Preprocessor { )); } } else if let Some(helper) = compile_helperform(self.opts.clone(), definition)? { - self.add_helper(rename_args_helperform(&helper)); + self.add_helper(rename_args_helperform(&helper)?); } } } diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index c8219175a..74a1335c4 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -2,12 +2,15 @@ use std::borrow::Borrow; use std::collections::HashMap; use std::rc::Rc; +use crate::compiler::codegen::toposort_assign_bindings; use crate::compiler::comptypes::{ - Binding, BodyForm, CompileForm, DefconstData, DefmacData, DefunData, HelperForm, LetData, - LetFormKind, + map_m, map_m_reverse, Binding, BindingPattern, BodyForm, CompileErr, CompileForm, DefconstData, + DefmacData, DefunData, HelperForm, LambdaData, LetData, LetFormKind, }; use crate::compiler::gensym::gensym; use crate::compiler::sexp::SExp; +use crate::compiler::srcloc::Srcloc; +use crate::util::TopoSortItem; /// Rename in a qq form. This searches for (unquote ...) forms inside and performs /// rename inside them, leaving the rest of the qq form as is. @@ -16,7 +19,7 @@ fn rename_in_qq(namemap: &HashMap, Vec>, body: Rc) -> Rc .and_then(|x| { if let [SExp::Atom(_, q), body] = &x[..] { if q == b"unquote" { - return Some(rename_in_cons(namemap, Rc::new(body.clone()))); + return Some(rename_in_cons(namemap, Rc::new(body.clone()), true)); } } @@ -33,7 +36,11 @@ fn rename_in_qq(namemap: &HashMap, Vec>, body: Rc) -> Rc } /* Given a cons cell, rename occurrences of oldname to newname */ -fn rename_in_cons(namemap: &HashMap, Vec>, body: Rc) -> Rc { +pub fn rename_in_cons( + namemap: &HashMap, Vec>, + body: Rc, + qq_handling: bool, +) -> Rc { match body.borrow() { SExp::Atom(l, name) => match namemap.get(name) { Some(v) => Rc::new(SExp::Atom(l.clone(), v.to_vec())), @@ -63,7 +70,7 @@ fn rename_in_cons(namemap: &HashMap, Vec>, body: Rc) -> Rc body.clone(), }) .unwrap_or_else(|| body.clone()); - } else if *q == "qq".as_bytes().to_vec() { + } else if *q == "qq".as_bytes().to_vec() && qq_handling { return r .proper_list() .map(|x| match &x[..] { @@ -76,8 +83,8 @@ fn rename_in_cons(namemap: &HashMap, Vec>, body: Rc) -> Rc body.clone(), @@ -106,80 +113,164 @@ fn invent_new_names_sexp(body: Rc) -> Vec<(Vec, Vec)> { } } -fn make_binding_unique(b: &Binding) -> (Vec, Binding) { - ( - b.name.to_vec(), - Binding { - loc: b.loc.clone(), - nl: b.nl.clone(), - name: gensym(b.name.clone()), - body: b.body.clone(), +#[derive(Debug, Clone)] +struct InnerRenameList { + bindings: HashMap, Vec>, + from_wing: Binding, +} + +fn make_binding_unique(b: &Binding) -> InnerRenameList { + match &b.pattern { + BindingPattern::Name(name) => { + let mut single_name_map = HashMap::new(); + let new_name = gensym(name.clone()); + single_name_map.insert(name.to_vec(), new_name.clone()); + InnerRenameList { + bindings: single_name_map, + from_wing: Binding { + loc: b.loc.clone(), + nl: b.nl.clone(), + pattern: BindingPattern::Name(new_name), + body: b.body.clone(), + }, + } + } + BindingPattern::Complex(pat) => { + let new_names_vec = invent_new_names_sexp(pat.clone()); + let mut new_names = HashMap::new(); + + for (n, v) in new_names_vec.iter() { + new_names.insert(n.clone(), v.clone()); + } + + let renamed_pattern = rename_in_cons(&new_names, pat.clone(), false); + InnerRenameList { + bindings: new_names, + from_wing: Binding { + loc: b.loc.clone(), + nl: b.nl.clone(), + pattern: BindingPattern::Complex(renamed_pattern), + body: b.body.clone(), + }, + } + } + } +} + +pub fn rename_assign_bindings( + l: &Srcloc, + bindings: &[Rc], + body: Rc, +) -> Result<(BodyForm, Vec>), CompileErr> { + // Order the bindings. + let sorted_bindings = toposort_assign_bindings(l, bindings)?; + let mut renames = HashMap::new(); + // Process in reverse order so we rename from inner to outer. + let bindings_to_rename: Vec> = sorted_bindings.to_vec(); + let renamed_bindings = map_m_reverse( + |item: &TopoSortItem<_>| -> Result, CompileErr> { + let b: &Binding = bindings[item.index].borrow(); + if let BindingPattern::Complex(p) = &b.pattern { + let new_names = invent_new_names_sexp(p.clone()); + for (name, renamed) in new_names.iter() { + renames.insert(name.clone(), renamed.clone()); + } + Ok(Rc::new(Binding { + pattern: BindingPattern::Complex(rename_in_cons(&renames, p.clone(), false)), + body: Rc::new(rename_in_bodyform(&renames, b.body.clone())?), + ..b.clone() + })) + } else { + Ok(bindings[item.index].clone()) + } }, - ) + &bindings_to_rename, + )?; + Ok((rename_in_bodyform(&renames, body)?, renamed_bindings)) } -fn rename_in_bodyform(namemap: &HashMap, Vec>, b: Rc) -> BodyForm { +fn rename_in_bodyform( + namemap: &HashMap, Vec>, + b: Rc, +) -> Result { match b.borrow() { BodyForm::Let(kind, letdata) => { - let new_bindings = letdata - .bindings - .iter() - .map(|b| { - Rc::new(Binding { + let new_bindings = map_m( + &|b: &Rc| -> Result, CompileErr> { + Ok(Rc::new(Binding { loc: b.loc(), nl: b.nl.clone(), - name: b.name.clone(), - body: Rc::new(rename_in_bodyform(namemap, b.body.clone())), - }) - }) - .collect(); - let new_body = rename_in_bodyform(namemap, letdata.body.clone()); - BodyForm::Let( + pattern: b.pattern.clone(), + body: Rc::new(rename_in_bodyform(namemap, b.body.clone())?), + })) + }, + &letdata.bindings, + )?; + let new_body = rename_in_bodyform(namemap, letdata.body.clone())?; + let res = BodyForm::Let( kind.clone(), - LetData { - loc: letdata.loc.clone(), - kw: letdata.kw.clone(), + Box::new(LetData { bindings: new_bindings, body: Rc::new(new_body), - }, - ) + ..*letdata.clone() + }), + ); + Ok(res) } BodyForm::Quoted(atom) => match atom { SExp::Atom(l, n) => match namemap.get(n) { - Some(named) => BodyForm::Quoted(SExp::Atom(l.clone(), named.to_vec())), - None => BodyForm::Quoted(atom.clone()), + Some(named) => Ok(BodyForm::Quoted(SExp::Atom(l.clone(), named.to_vec()))), + None => Ok(BodyForm::Quoted(atom.clone())), }, - _ => BodyForm::Quoted(atom.clone()), + _ => Ok(BodyForm::Quoted(atom.clone())), }, BodyForm::Value(atom) => match atom { SExp::Atom(l, n) => match namemap.get(n) { - Some(named) => BodyForm::Value(SExp::Atom(l.clone(), named.to_vec())), - None => BodyForm::Value(atom.clone()), + Some(named) => Ok(BodyForm::Value(SExp::Atom(l.clone(), named.to_vec()))), + None => Ok(BodyForm::Value(atom.clone())), }, - _ => BodyForm::Value(atom.clone()), + _ => Ok(BodyForm::Value(atom.clone())), }, BodyForm::Call(l, vs, tail) => { - let new_vs = vs - .iter() - .enumerate() - .map(|(i, x)| { - if i == 0 { - x.clone() - } else { - Rc::new(rename_in_bodyform(namemap, x.clone())) - } - }) - .collect(); - let new_tail = tail - .as_ref() - .map(|t| Rc::new(rename_in_bodyform(namemap, t.clone()))); - BodyForm::Call(l.clone(), new_vs, new_tail) + let mut new_vs = map_m( + &|x: &Rc| -> Result, CompileErr> { + Ok(Rc::new(rename_in_bodyform(namemap, x.clone())?)) + }, + vs, + )?; + // Ensure that we haven't renamed the 0th element of a call + // They exist in a separate (global) namespace of callables + // and aren't in the variable scope stack. + if !vs.is_empty() { + new_vs[0] = vs[0].clone(); + } + let new_tail = if let Some(t) = tail.as_ref() { + Some(Rc::new(rename_in_bodyform(namemap, t.clone())?)) + } else { + None + }; + Ok(BodyForm::Call(l.clone(), new_vs, new_tail)) } - BodyForm::Mod(l, prog) => BodyForm::Mod(l.clone(), prog.clone()), + BodyForm::Mod(l, prog) => Ok(BodyForm::Mod(l.clone(), prog.clone())), + // Rename lambda arguments down the lexical scope. + BodyForm::Lambda(ldata) => { + let renamed_capture_inputs = + Rc::new(rename_in_bodyform(namemap, ldata.captures.clone())?); + let renamed_capture_outputs = + rename_in_cons(namemap, ldata.capture_args.clone(), false); + let renamed_body = Rc::new(rename_args_bodyform(ldata.body.borrow())?); + let outer_renamed_body = rename_in_bodyform(namemap, renamed_body)?; + Ok(BodyForm::Lambda(Box::new(LambdaData { + captures: renamed_capture_inputs, + capture_args: renamed_capture_outputs, + body: Rc::new(outer_renamed_body), + ..*ldata.clone() + }))) + } } } @@ -198,98 +289,138 @@ pub fn desugar_sequential_let_bindings( bindings, &BodyForm::Let( LetFormKind::Parallel, - LetData { + Box::new(LetData { loc: want_binding.loc(), kw: None, bindings: vec![want_binding], + inline_hint: None, body: Rc::new(body.clone()), - }, + }), ), n - 1, ) } } -fn rename_args_bodyform(b: &BodyForm) -> BodyForm { +fn rename_args_bodyform(b: &BodyForm) -> Result { match b { BodyForm::Let(LetFormKind::Sequential, letdata) => { // Renaming a sequential let is exactly as if the bindings were // nested in separate parallel lets. - rename_args_bodyform(&desugar_sequential_let_bindings( + let res = rename_args_bodyform(&desugar_sequential_let_bindings( &letdata.bindings, letdata.body.borrow(), letdata.bindings.len(), - )) + ))?; + Ok(res) } BodyForm::Let(LetFormKind::Parallel, letdata) => { - let renames: Vec<(Vec, Binding)> = letdata + let renames: Vec = letdata .bindings .iter() .map(|x| make_binding_unique(x.borrow())) .collect(); - let new_renamed_bindings: Vec> = - renames.iter().map(|(_, x)| Rc::new(x.clone())).collect(); + let new_renamed_bindings: Vec> = renames + .iter() + .map(|ir| Rc::new(ir.from_wing.clone())) + .collect(); let mut local_namemap = HashMap::new(); - for x in renames.iter() { - let (oldname, binding) = x; - local_namemap.insert(oldname.to_vec(), binding.name.clone()); + for ir in renames.iter() { + for (oldname, binding_name) in ir.bindings.iter() { + local_namemap.insert(oldname.to_vec(), binding_name.clone()); + } } - let new_bindings = new_renamed_bindings - .iter() - .map(|x| { - Rc::new(Binding { + let new_bindings = map_m( + &|x: &Rc| -> Result, CompileErr> { + Ok(Rc::new(Binding { loc: x.loc.clone(), nl: x.nl.clone(), - name: x.name.clone(), - body: Rc::new(rename_args_bodyform(&x.body)), - }) - }) - .collect(); - let locally_renamed_body = rename_in_bodyform(&local_namemap, letdata.body.clone()); - BodyForm::Let( + pattern: x.pattern.clone(), + body: Rc::new(rename_args_bodyform(&x.body)?), + })) + }, + &new_renamed_bindings, + )?; + let args_renamed = rename_args_bodyform(letdata.body.borrow())?; + let locally_renamed_body = rename_in_bodyform(&local_namemap, Rc::new(args_renamed))?; + let new_form = BodyForm::Let( LetFormKind::Parallel, - LetData { - loc: letdata.loc.clone(), - kw: letdata.kw.clone(), + Box::new(LetData { bindings: new_bindings, body: Rc::new(locally_renamed_body), - }, - ) + ..*letdata.clone() + }), + ); + Ok(new_form) } - BodyForm::Quoted(e) => BodyForm::Quoted(e.clone()), - BodyForm::Value(v) => BodyForm::Value(v.clone()), + BodyForm::Let(LetFormKind::Assign, letdata) => { + let (new_compiled_body, new_bindings) = + rename_assign_bindings(&letdata.loc, &letdata.bindings, letdata.body.clone())?; + Ok(BodyForm::Let( + LetFormKind::Assign, + Box::new(LetData { + body: Rc::new(new_compiled_body), + bindings: new_bindings, + ..*letdata.clone() + }), + )) + } + + BodyForm::Quoted(e) => Ok(BodyForm::Quoted(e.clone())), + BodyForm::Value(v) => Ok(BodyForm::Value(v.clone())), BodyForm::Call(l, vs, tail) => { - let new_vs = vs - .iter() - .map(|a| Rc::new(rename_args_bodyform(a))) - .collect(); - let new_tail = tail - .as_ref() - .map(|t| Rc::new(rename_args_bodyform(t.borrow()))); - BodyForm::Call(l.clone(), new_vs, new_tail) + let new_vs = map_m( + &|a: &Rc| -> Result, CompileErr> { + Ok(Rc::new(rename_args_bodyform(a)?)) + }, + vs, + )?; + let new_tail = if let Some(t) = tail.as_ref() { + Some(Rc::new(rename_args_bodyform(t.borrow())?)) + } else { + None + }; + Ok(BodyForm::Call(l.clone(), new_vs, new_tail)) + } + BodyForm::Mod(l, program) => Ok(BodyForm::Mod(l.clone(), program.clone())), + BodyForm::Lambda(ldata) => { + let mut own_args = HashMap::new(); + for (n, v) in invent_new_names_sexp(ldata.args.clone()).iter() { + own_args.insert(n.clone(), v.clone()); + } + let new_args = rename_in_cons(&own_args, ldata.args.clone(), false); + let new_body = rename_args_bodyform(ldata.body.borrow())?; + let renamed_with_own_args = rename_in_bodyform(&own_args, Rc::new(new_body))?; + Ok(BodyForm::Lambda(Box::new(LambdaData { + args: new_args, + body: Rc::new(renamed_with_own_args), + ..*ldata.clone() + }))) } - BodyForm::Mod(l, program) => BodyForm::Mod(l.clone(), program.clone()), } } -fn rename_in_helperform(namemap: &HashMap, Vec>, h: &HelperForm) -> HelperForm { +fn rename_in_helperform( + namemap: &HashMap, Vec>, + h: &HelperForm, +) -> Result { match h { - HelperForm::Defconstant(defc) => HelperForm::Defconstant(DefconstData { + HelperForm::Defconstant(defc) => Ok(HelperForm::Defconstant(DefconstData { loc: defc.loc.clone(), kind: defc.kind.clone(), name: defc.name.to_vec(), nl: defc.nl.clone(), kw: defc.kw.clone(), - body: Rc::new(rename_in_bodyform(namemap, defc.body.clone())), - }), - HelperForm::Defmacro(mac) => HelperForm::Defmacro(DefmacData { - program: Rc::new(rename_in_compileform(namemap, mac.program.clone())), + body: Rc::new(rename_in_bodyform(namemap, defc.body.clone())?), + })), + HelperForm::Defmacro(mac) => Ok(HelperForm::Defmacro(DefmacData { + program: Rc::new(rename_in_compileform(namemap, mac.program.clone())?), ..mac.clone() - }), - HelperForm::Defun(inline, defun) => HelperForm::Defun( + })), + HelperForm::Defun(inline, defun) => Ok(HelperForm::Defun( *inline, DefunData { loc: defun.loc.clone(), @@ -298,22 +429,22 @@ fn rename_in_helperform(namemap: &HashMap, Vec>, h: &HelperForm) -> name: defun.name.to_vec(), orig_args: defun.orig_args.clone(), args: defun.args.clone(), - body: Rc::new(rename_in_bodyform(namemap, defun.body.clone())), + body: Rc::new(rename_in_bodyform(namemap, defun.body.clone())?), }, - ), + )), } } -pub fn rename_args_helperform(h: &HelperForm) -> HelperForm { +pub fn rename_args_helperform(h: &HelperForm) -> Result { match h { - HelperForm::Defconstant(defc) => HelperForm::Defconstant(DefconstData { + HelperForm::Defconstant(defc) => Ok(HelperForm::Defconstant(DefconstData { loc: defc.loc.clone(), kind: defc.kind.clone(), nl: defc.nl.clone(), kw: defc.kw.clone(), name: defc.name.clone(), - body: Rc::new(rename_args_bodyform(defc.body.borrow())), - }), + body: Rc::new(rename_args_bodyform(defc.body.borrow())?), + })), HelperForm::Defmacro(mac) => { let mut new_names: HashMap, Vec> = HashMap::new(); for x in invent_new_names_sexp(mac.args.clone()).iter() { @@ -323,16 +454,16 @@ pub fn rename_args_helperform(h: &HelperForm) -> HelperForm { for x in new_names.iter() { local_namemap.insert(x.0.to_vec(), x.1.to_vec()); } - let local_renamed_arg = rename_in_cons(&local_namemap, mac.args.clone()); - let local_renamed_body = rename_args_compileform(mac.program.borrow()); - HelperForm::Defmacro(DefmacData { + let local_renamed_arg = rename_in_cons(&local_namemap, mac.args.clone(), true); + let local_renamed_body = rename_args_compileform(mac.program.borrow())?; + Ok(HelperForm::Defmacro(DefmacData { args: local_renamed_arg, program: Rc::new(rename_in_compileform( &local_namemap, Rc::new(local_renamed_body), - )), + )?), ..mac.clone() - }) + })) } HelperForm::Defun(inline, defun) => { let new_names = invent_new_names_sexp(defun.args.clone()); @@ -340,9 +471,9 @@ pub fn rename_args_helperform(h: &HelperForm) -> HelperForm { for x in new_names.iter() { local_namemap.insert(x.0.clone(), x.1.clone()); } - let local_renamed_arg = rename_in_cons(&local_namemap, defun.args.clone()); - let local_renamed_body = rename_args_bodyform(defun.body.borrow()); - HelperForm::Defun( + let local_renamed_arg = rename_in_cons(&local_namemap, defun.args.clone(), true); + let local_renamed_body = rename_args_bodyform(defun.body.borrow())?; + Ok(HelperForm::Defun( *inline, DefunData { loc: defun.loc.clone(), @@ -354,39 +485,37 @@ pub fn rename_args_helperform(h: &HelperForm) -> HelperForm { body: Rc::new(rename_in_bodyform( &local_namemap, Rc::new(local_renamed_body), - )), + )?), }, - ) + )) } } } -fn rename_in_compileform(namemap: &HashMap, Vec>, c: Rc) -> CompileForm { - CompileForm { +fn rename_in_compileform( + namemap: &HashMap, Vec>, + c: Rc, +) -> Result { + Ok(CompileForm { loc: c.loc.clone(), args: c.args.clone(), include_forms: c.include_forms.clone(), - helpers: c - .helpers - .iter() - .map(|x| rename_in_helperform(namemap, x)) - .collect(), - exp: Rc::new(rename_in_bodyform(namemap, c.exp.clone())), - } + helpers: map_m(|x| rename_in_helperform(namemap, x), &c.helpers)?, + exp: Rc::new(rename_in_bodyform(namemap, c.exp.clone())?), + }) } /// For all the HelperForms in a CompileForm, do renaming in them so that all /// unique variable bindings in the program have unique names. -pub fn rename_children_compileform(c: &CompileForm) -> CompileForm { - let local_renamed_helpers = c.helpers.iter().map(rename_args_helperform).collect(); - let local_renamed_body = rename_args_bodyform(c.exp.borrow()); - CompileForm { - loc: c.loc.clone(), - args: c.args.clone(), - include_forms: c.include_forms.clone(), +pub fn rename_children_compileform(c: &CompileForm) -> Result { + let c_ref: &CompileForm = c; + let local_renamed_helpers = map_m(&rename_args_helperform, &c.helpers)?; + let local_renamed_body = rename_args_bodyform(c.exp.borrow())?; + Ok(CompileForm { helpers: local_renamed_helpers, exp: Rc::new(local_renamed_body), - } + ..c_ref.clone() + }) } /// Given a compileform, perform renaming in descendants so that every variable @@ -395,27 +524,26 @@ pub fn rename_children_compileform(c: &CompileForm) -> CompileForm { /// that look the same but refer to different variables are different. It also /// ensures that future tricky variable name uses decide on one binding from their /// lexical scope. -pub fn rename_args_compileform(c: &CompileForm) -> CompileForm { +pub fn rename_args_compileform(c: &CompileForm) -> Result { let new_names = invent_new_names_sexp(c.args.clone()); let mut local_namemap = HashMap::new(); for x in new_names.iter() { local_namemap.insert(x.0.clone(), x.1.clone()); } - let local_renamed_arg = rename_in_cons(&local_namemap, c.args.clone()); - let local_renamed_helpers: Vec = - c.helpers.iter().map(rename_args_helperform).collect(); - let local_renamed_body = rename_args_bodyform(c.exp.borrow()); - CompileForm { + let local_renamed_arg = rename_in_cons(&local_namemap, c.args.clone(), true); + let local_renamed_helpers: Vec = map_m(&rename_args_helperform, &c.helpers)?; + let local_renamed_body = rename_args_bodyform(c.exp.borrow())?; + Ok(CompileForm { loc: c.loc(), args: local_renamed_arg, include_forms: c.include_forms.clone(), - helpers: local_renamed_helpers - .iter() - .map(|x| rename_in_helperform(&local_namemap, x)) - .collect(), + helpers: map_m( + |x| rename_in_helperform(&local_namemap, x), + &local_renamed_helpers, + )?, exp: Rc::new(rename_in_bodyform( &local_namemap, Rc::new(local_renamed_body), - )), - } + )?), + }) } diff --git a/src/compiler/sexp.rs b/src/compiler/sexp.rs index 93ef4c848..605bf48d0 100644 --- a/src/compiler/sexp.rs +++ b/src/compiler/sexp.rs @@ -16,6 +16,8 @@ use num_traits::{zero, Num}; use serde::Serialize; +#[cfg(test)] +use crate::classic::clvm::__type_compatibility__::bi_one; use crate::classic::clvm::__type_compatibility__::{bi_zero, Bytes, BytesFromType}; use crate::classic::clvm::casts::{bigint_from_bytes, bigint_to_bytes_clvm, TConvertOption}; use crate::compiler::prims::prims; @@ -191,35 +193,28 @@ impl Hash for SExp { } fn make_cons(a: Rc, b: Rc) -> SExp { - SExp::Cons(a.loc().ext(&b.loc()), a.clone(), b.clone()) + SExp::Cons(a.loc().ext(&b.loc()), Rc::clone(&a), Rc::clone(&b)) } #[derive(Debug, PartialEq, Eq)] -enum TermListCommentState { - InComment, - Empty, -} - -#[derive(Debug)] enum SExpParseState { // The types of state that the Rust pre-forms can take Empty, - CommentText(Srcloc, Vec), //srcloc contains the file, line, column and length for the captured form - Bareword(Srcloc, Vec), + CommentText, + Bareword(Srcloc, Vec), //srcloc contains the file, line, column and length for the captured form QuotedText(Srcloc, u8, Vec), QuotedEscaped(Srcloc, u8, Vec), OpenList(Srcloc), ParsingList(Srcloc, Rc, Vec>), TermList( Srcloc, - TermListCommentState, Option>, // this is the second value in the dot expression Rc, // used for inner parsing - Vec>, + Vec>, // list content ), } -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] enum SExpParseResult { // the result of a call to parse an SExp Resume(SExpParseState), @@ -313,7 +308,7 @@ pub fn enlist(l: Srcloc, v: &[Rc]) -> SExp { let mut result = SExp::Nil(l); for i_reverse in 0..v.len() { let i = v.len() - i_reverse - 1; - result = make_cons(v[i].clone(), Rc::new(result)); + result = make_cons(Rc::clone(&v[i]), Rc::new(result)); } result } @@ -421,14 +416,14 @@ impl SExp { pub fn cons_fst(&self) -> Rc { match self { - SExp::Cons(_, a, _) => a.clone(), + SExp::Cons(_, a, _) => Rc::clone(a), _ => Rc::new(SExp::Nil(self.loc())), } } pub fn cons_snd(&self) -> Rc { match self { - SExp::Cons(_, _, b) => b.clone(), + SExp::Cons(_, _, b) => Rc::clone(b), _ => Rc::new(SExp::Nil(self.loc())), } } @@ -547,7 +542,7 @@ fn parse_sexp_step(loc: Srcloc, current_state: &SExpParseState, this_char: u8) - // we are not currently in a list '(' => resume(SExpParseState::OpenList(loc)), // move to OpenList state '\n' => resume(SExpParseState::Empty), // new line, same state - ';' => resume(SExpParseState::CommentText(loc, Vec::new())), + ';' => resume(SExpParseState::CommentText), ')' => error(loc, "Too many close parens"), '"' => resume(SExpParseState::QuotedText(loc, b'"', Vec::new())), // match on " '\'' => resume(SExpParseState::QuotedText(loc, b'\'', Vec::new())), // match on ' @@ -560,14 +555,9 @@ fn parse_sexp_step(loc: Srcloc, current_state: &SExpParseState, this_char: u8) - } }, // t is a Vec of the previous characters in this comment string - SExpParseState::CommentText(srcloc, t) => match this_char as char { - '\r' => resume(SExpParseState::CommentText(srcloc.clone(), t.to_vec())), + SExpParseState::CommentText => match this_char as char { '\n' => resume(SExpParseState::Empty), - _ => { - let mut tcopy = t.to_vec(); - tcopy.push(this_char); - resume(SExpParseState::CommentText(srcloc.ext(&loc), tcopy)) - } + _ => resume(SExpParseState::CommentText), }, // we currently processing a new word SExpParseState::Bareword(srcloc, word_so_far) => { @@ -639,7 +629,6 @@ fn parse_sexp_step(loc: Srcloc, current_state: &SExpParseState, this_char: u8) - ('.', SExpParseState::Empty) => resume(SExpParseState::TermList( // dot notation showing cons cell srcloc.ext(&loc), - TermListCommentState::Empty, // we are not inside a comment None, Rc::new(SExpParseState::Empty), // nested state is empty list_content.to_vec(), @@ -683,81 +672,55 @@ fn parse_sexp_step(loc: Srcloc, current_state: &SExpParseState, this_char: u8) - }, } } - // if we're in a comment then just check for newline or carriage return otherwise stay in InComment state - SExpParseState::TermList( - srcloc, - TermListCommentState::InComment, - parsed, - pp, - list_content, - ) => { - let end_comment = if this_char as char == '\n' || this_char as char == '\r' { - TermListCommentState::Empty - } else { - TermListCommentState::InComment - }; - resume(SExpParseState::TermList( - srcloc.clone(), - end_comment, // store the new commentstate - parsed.clone(), - pp.clone(), - list_content.clone(), - )) - } + // if we're not in a comment and have already found a parsed second word for this dot expression - SExpParseState::TermList( - srcloc, - TermListCommentState::Empty, - Some(parsed), - pp, - list_content, - ) => { - if this_char.is_ascii_whitespace() { - // ignore whitespace after second word - resume(SExpParseState::TermList( - srcloc.ext(&loc), - TermListCommentState::Empty, - Some(parsed.clone()), - pp.clone(), - list_content.to_vec(), - )) - } else if this_char == b')' { - // if we see a `)` then we're ready to close this list - let mut list_copy = list_content.to_vec(); - match list_copy.pop() { - Some(v) => { - let new_tail = make_cons(v, parsed.clone()); - if list_copy.is_empty() { - emit(Rc::new(new_tail), SExpParseState::Empty) - } else { - let mut result_list = new_tail; - for item in list_copy.iter().rev() { - result_list = make_cons(item.clone(), Rc::new(result_list)); + SExpParseState::TermList(srcloc, Some(parsed), pp, list_content) => { + match (this_char as char, pp.borrow()) { + (')', SExpParseState::Empty) => { + // if we see a `)` then we're ready to close this list + let mut list_copy = list_content.to_vec(); + match list_copy.pop() { + Some(v) => { + let new_tail = make_cons(v, Rc::clone(parsed)); + if list_copy.is_empty() { + emit(Rc::new(new_tail), SExpParseState::Empty) + } else { + let mut result_list = new_tail; + for item in list_copy.iter().rev() { + result_list = make_cons(Rc::clone(item), Rc::new(result_list)); + } + emit(Rc::new(result_list), SExpParseState::Empty) + // emit the resultant list } - emit(Rc::new(result_list), SExpParseState::Empty) // emit the resultant list } + None => error(loc, "Dot as first element of list?"), } - None => error(loc, "Dot as first element of list?"), } - } else if this_char == b';' { - // entering a comment - resume(SExpParseState::TermList( - srcloc.clone(), - TermListCommentState::InComment, - Some(parsed.clone()), - pp.clone(), - list_content.clone(), - )) - } else { - // we don't want to see any more characters after we've concluded a dot expression - error( - srcloc.clone(), - &format!("unexpected character {}", this_char as char), - ) + _ => match parse_sexp_step(loc.clone(), pp.borrow(), this_char) { + // nothing should be emitted as we're a term list with an object found + SExpParseResult::Emit(_, _current_state) => { + error(loc, "found object during termlist") + } + // resume means it didn't finish parsing yet, so store inner state and keep going + SExpParseResult::Resume(current_state) => { + match current_state { + SExpParseState::Empty | SExpParseState::CommentText => { + resume(SExpParseState::TermList( + srcloc.ext(&loc), + Some(parsed.clone()), + Rc::new(current_state), // store our partial inner parsestate in pp + list_content.to_vec(), + )) + } + _ => error(loc, "Illegal state during term list."), + } + } + SExpParseResult::Error(l, e) => SExpParseResult::Error(l, e), + }, } } // we are passing a dot-expression (x . y) and not in a comment and don't have an object already discovered - SExpParseState::TermList(srcloc, TermListCommentState::Empty, None, pp, list_content) => { + SExpParseState::TermList(srcloc, None, pp, list_content) => { // pp is the inner parsestate inside the dot-expressions match (this_char as char, pp.borrow()) { //match based on current character and inner state @@ -768,7 +731,7 @@ fn parse_sexp_step(loc: Srcloc, current_state: &SExpParseState, this_char: u8) - (')', SExpParseState::Empty) => { // attempt to close the list if list_content.len() == 1 { - emit(list_content[0].clone(), SExpParseState::Empty) + emit(Rc::clone(&list_content[0]), SExpParseState::Empty) } else { emit( Rc::new(enlist(srcloc.ext(&loc), list_content)), @@ -787,7 +750,7 @@ fn parse_sexp_step(loc: Srcloc, current_state: &SExpParseState, this_char: u8) - } else { let mut result_list = new_tail; for item in list_copy.iter().rev() { - result_list = make_cons(item.clone(), Rc::new(result_list)); + result_list = make_cons(Rc::clone(item), Rc::new(result_list)); } emit(Rc::new(result_list), SExpParseState::Empty) } @@ -800,16 +763,14 @@ fn parse_sexp_step(loc: Srcloc, current_state: &SExpParseState, this_char: u8) - SExpParseResult::Emit(parsed_object, _current_state) => { resume(SExpParseState::TermList( loc, - TermListCommentState::Empty, Some(parsed_object), // assert parsed_object is not None and then store it in parsed_list - pp.clone(), + Rc::new(SExpParseState::Empty), list_content.clone(), )) } // resume means it didn't finish parsing yet, so store inner state and keep going SExpParseResult::Resume(current_state) => resume(SExpParseState::TermList( srcloc.ext(&loc), - TermListCommentState::Empty, None, Rc::new(current_state), // store our partial inner parsestate in pp list_content.to_vec(), @@ -821,58 +782,82 @@ fn parse_sexp_step(loc: Srcloc, current_state: &SExpParseState, this_char: u8) - } } -fn parse_sexp_inner( - mut start: Srcloc, - mut parse_state: SExpParseState, - s: I, -) -> Result>, (Srcloc, String)> -where - I: Iterator, -{ +#[derive(Debug, PartialEq, Eq)] +pub struct ParsePartialResult { // we support compiling multiple things at once, keep these in a Vec // at the moment this will almost certainly only return 1 thing - let mut res = Vec::new(); + res: Vec>, + srcloc: Srcloc, + parse_state: SExpParseState, +} - // Loop through all the characters - for this_char in s { - let next_location = start.clone().advance(this_char); +impl ParsePartialResult { + pub fn new(srcloc: Srcloc) -> Self { + ParsePartialResult { + res: Default::default(), + srcloc, + parse_state: SExpParseState::Empty, + } + } + pub fn push(&mut self, this_char: u8) -> Result<(), (Srcloc, String)> { + let next_location = self.srcloc.clone().advance(this_char); // call parse_sexp_step for current character // it will return a ParseResult which contains the new ParseState - match parse_sexp_step(start.clone(), &parse_state, this_char) { + match parse_sexp_step(self.srcloc.clone(), &self.parse_state, this_char) { // catch error and propagate itupwards SExpParseResult::Error(l, e) => { return Err((l, e)); } // Keep parsing SExpParseResult::Resume(new_parse_state) => { - start = next_location; - parse_state = new_parse_state; + self.srcloc = next_location; + self.parse_state = new_parse_state; } // End of list (top level compile object), but not necessarily end of file SExpParseResult::Emit(o, new_parse_state) => { - start = next_location; - parse_state = new_parse_state; - res.push(o); + self.srcloc = next_location; + self.parse_state = new_parse_state; + self.res.push(o); } } + + Ok(()) } - // depending on the state when we finished return Ok or Err enums - match parse_state { - SExpParseState::Empty => Ok(res), - SExpParseState::Bareword(l, t) => Ok(vec![Rc::new(make_atom(l, t))]), - SExpParseState::CommentText(_, _) => Ok(res), - SExpParseState::QuotedText(l, _, _) => Err((l, "unterminated quoted string".to_string())), - SExpParseState::QuotedEscaped(l, _, _) => { - Err((l, "unterminated quoted string with escape".to_string())) + pub fn finalize(self) -> Result>, (Srcloc, String)> { + // depending on the state when we finished return Ok or Err enums + match self.parse_state { + SExpParseState::Empty => Ok(self.res), + SExpParseState::Bareword(l, t) => Ok(vec![Rc::new(make_atom(l, t))]), + SExpParseState::CommentText => Ok(self.res), + SExpParseState::QuotedText(l, _, _) => { + Err((l, "unterminated quoted string".to_string())) + } + SExpParseState::QuotedEscaped(l, _, _) => { + Err((l, "unterminated quoted string with escape".to_string())) + } + SExpParseState::OpenList(l) => Err((l, "Unterminated list (empty)".to_string())), + SExpParseState::ParsingList(l, _, _) => Err((l, "Unterminated mid list".to_string())), + SExpParseState::TermList(l, _, _, _) => Err((l, "Unterminated tail list".to_string())), } - SExpParseState::OpenList(l) => Err((l, "Unterminated list (empty)".to_string())), - SExpParseState::ParsingList(l, _, _) => Err((l, "Unterminated mid list".to_string())), - SExpParseState::TermList(l, _, _, _, _) => Err((l, "Unterminated tail list".to_string())), } } +fn parse_sexp_inner(start: Srcloc, s: I) -> Result>, (Srcloc, String)> +where + I: Iterator, +{ + let mut partial_result = ParsePartialResult::new(start); + + // Loop through all the characters + for this_char in s { + partial_result.push(this_char)?; + } + + partial_result.finalize() +} + /// /// Entrypoint for parsing chialisp input. /// Called from compiler.rs @@ -883,7 +868,117 @@ pub fn parse_sexp(start: Srcloc, input: I) -> Result>, (Srcloc, where I: Iterator, { - parse_sexp_inner(start, SExpParseState::Empty, input) + parse_sexp_inner(start, input) +} + +#[cfg(test)] +fn check_parser_for_intermediate_result( + parser: &mut ParsePartialResult, + s: &str, + desired: SExpParseState, +) { + for this_char in s.bytes() { + parser.push(this_char).unwrap(); + } + assert_eq!(parser.parse_state, desired); +} + +#[cfg(test)] +fn srcloc_range(name: &Rc, start: usize, end: usize) -> Srcloc { + Srcloc::new(name.clone(), 1, start).ext(&Srcloc::new(name.clone(), 1, end)) +} + +#[test] +fn test_tricky_parser_tail_01() { + let testname = Rc::new("*test*".to_string()); + let loc = Srcloc::start(&testname); + let mut parser = ParsePartialResult::new(loc.clone()); + check_parser_for_intermediate_result( + &mut parser, + "(1 . x", + SExpParseState::TermList( + srcloc_range(&testname, 1, 6), + None, + Rc::new(SExpParseState::Bareword( + srcloc_range(&testname, 6, 6), + vec![b'x'], + )), + vec![Rc::new(SExp::Integer( + srcloc_range(&testname, 2, 2), + bi_one(), + ))], + ), + ); + + parser.push(b')').expect("should complete"); + assert_eq!( + parser.finalize(), + Ok(vec![Rc::new(SExp::Cons( + srcloc_range(&testname, 1, 7), + Rc::new(SExp::Integer(srcloc_range(&testname, 2, 2), bi_one())), + Rc::new(SExp::Atom(srcloc_range(&testname, 6, 7), b"x".to_vec())) + ))]) + ); +} + +#[test] +fn test_tricky_parser_tail_02() { + let testname = Rc::new("*test*".to_string()); + let loc = Srcloc::start(&testname); + let mut parser = ParsePartialResult::new(loc.clone()); + check_parser_for_intermediate_result( + &mut parser, + "(1 . ()", + SExpParseState::TermList( + srcloc_range(&testname, 7, 7), + Some(Rc::new(SExp::Nil(srcloc_range(&testname, 6, 7)))), + Rc::new(SExpParseState::Empty), + vec![Rc::new(SExp::Integer( + srcloc_range(&testname, 2, 2), + bi_one(), + ))], + ), + ); + + parser.push(b')').expect("should complete"); + assert_eq!( + parser.finalize(), + Ok(vec![Rc::new(SExp::Cons( + srcloc_range(&testname, 1, 7), + Rc::new(SExp::Integer(srcloc_range(&testname, 2, 2), bi_one())), + Rc::new(SExp::Nil(srcloc_range(&testname, 6, 7))) + ))]) + ); +} + +#[test] +fn test_tricky_parser_tail_03() { + let testname = Rc::new("*test*".to_string()); + let loc = Srcloc::start(&testname); + let mut parser = ParsePartialResult::new(loc.clone()); + check_parser_for_intermediate_result( + &mut parser, + "(1 . () ;; Test\n", + SExpParseState::TermList( + srcloc_range(&testname, 7, 16), + Some(Rc::new(SExp::Nil(srcloc_range(&testname, 6, 7)))), + Rc::new(SExpParseState::Empty), + vec![Rc::new(SExp::Integer( + srcloc_range(&testname, 2, 2), + bi_one(), + ))], + ), + ); + + parser.push(b')').expect("should complete"); + assert_eq!( + parser.finalize(), + Ok(vec![Rc::new(SExp::Cons( + srcloc_range(&testname, 1, 7), + Rc::new(SExp::Integer(srcloc_range(&testname, 2, 2), bi_one())), + Rc::new(SExp::Nil(srcloc_range(&testname, 6, 7))) + ))]) + ); } // This is a trait that generates a haskell-like ad-hoc type from the user's diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index be2b99733..94b93010a 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -530,7 +530,7 @@ fn test_treehash_constant_embedded_modern_loop() { .trim() .to_string(); eprintln!("{result_text}"); - assert!(result_text.starts_with("*command*")); + // Asserting where the stack overflows isn't necessary. assert!(result_text.contains("stack limit exceeded")); } @@ -974,6 +974,93 @@ fn test_modern_sets_source_file_in_symbols() { ); } +// Test that leaving off the lambda captures causes bare words for the +// requested values to find their way into the output and that having +// the capture catches it. This shows that uses of uncaptured words +// are unencumbered. +#[test] +fn test_lambda_without_capture_reproduces_bare_word_in_output() { + let compiled = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests".to_string(), + "resources/tests/rps-referee-uncaptured.clsp".to_string(), + ]) + .trim() + .to_string(); + assert!(compiled.contains("AMOUNT")); + assert!(compiled.contains("new_puzzle_hash")); +} + +// Test that having a lambda capture captures all the associated words. +#[test] +fn test_lambda_with_capture_defines_word() { + let compiled = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests".to_string(), + "resources/tests/rps-referee.clsp".to_string(), + ]) + .trim() + .to_string(); + assert!(!compiled.contains("AMOUNT")); + assert!(!compiled.contains("new_puzzle_hash")); +} + +#[test] +fn test_assign_lambda_code_generation() { + let tname = "test_assign_lambda_code_generation.sym".to_string(); + do_basic_run(&vec![ + "run".to_string(), + "--extra-syms".to_string(), + "--symbol-output-file".to_string(), + tname.clone(), + "(mod (A) (include *standard-cl-21*) (defun F (X) (+ X 1)) (assign-lambda X (F A) X))" + .to_string(), + ]); + let read_in_file = fs::read_to_string(&tname).expect("should have dropped symbols"); + fs::remove_file(&tname).expect("should have existed"); + let decoded_symbol_file: HashMap = + serde_json::from_str(&read_in_file).expect("should decode"); + let found_wanted_symbols: Vec = decoded_symbol_file + .iter() + .filter(|(_, v)| *v == "F" || v.starts_with("letbinding")) + .map(|(k, _)| k.clone()) + .collect(); + assert_eq!(found_wanted_symbols.len(), 2); + // We should have these two functions. + assert!(found_wanted_symbols + .contains(&"ccd5be506752cebf01f9930b4c108fe18058c65e1ab57a72ca0a00d9788c7ca6".to_string())); + assert!(found_wanted_symbols + .contains(&"0a5af5ae61fae2e53cb309d4d9c2c64baf0261824823008b9cf2b21b09221e44".to_string())); +} + +#[test] +fn test_assign_lambda_code_generation_normally_inlines() { + let tname = "test_assign_inline_code_generation.sym".to_string(); + do_basic_run(&vec![ + "run".to_string(), + "--extra-syms".to_string(), + "--symbol-output-file".to_string(), + tname.clone(), + "(mod (A) (include *standard-cl-21*) (defun F (X) (+ X 1)) (assign-inline X (F A) X))" + .to_string(), + ]); + let read_in_file = fs::read_to_string(&tname).expect("should have dropped symbols"); + fs::remove_file(&tname).expect("should have existed"); + let decoded_symbol_file: HashMap = + serde_json::from_str(&read_in_file).expect("should decode"); + let found_wanted_symbols: Vec = decoded_symbol_file + .iter() + .filter(|(_, v)| *v == "F" || v.starts_with("letbinding")) + .map(|(k, _)| k.clone()) + .collect(); + assert_eq!(found_wanted_symbols.len(), 1); + // We should have these two functions. + assert!(found_wanted_symbols + .contains(&"ccd5be506752cebf01f9930b4c108fe18058c65e1ab57a72ca0a00d9788c7ca6".to_string())); +} + #[test] fn test_cost_reporting_0() { let program = "(2 (1 2 6 (4 2 (4 (1 . 1) ()))) (4 (1 (2 (1 2 (3 (7 5) (1 2 (1 11 (1 . 2) (2 4 (4 2 (4 (5 5) ()))) (2 4 (4 2 (4 (6 5) ())))) 1) (1 2 (1 11 (1 . 1) 5) 1)) 1) 1) 2 (1 16 5 (1 . 50565442356047746631413349885570059132562040184787699607120092457326103992436)) 1) 1))"; @@ -1179,6 +1266,20 @@ fn test_defmac_assert_smoke_preprocess() { assert_eq!(run_result_false.trim(), "FAIL: clvm raise ()"); } +#[test] +fn test_assign_fancy_final_dot_rest() { + let result_prog = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/chia-gaming".to_string(), + "resources/tests/chia-gaming/test-last.clsp".to_string(), + ]); + let result = do_basic_brun(&vec!["brun".to_string(), result_prog, "()".to_string()]) + .trim() + .to_string(); + assert_eq!(result, "101"); +} + #[test] fn test_g1_map_op_modern() { let program = "(mod (S) (include *standard-cl-21*) (g1_map S \"BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_AUG_\"))"; diff --git a/src/tests/classic/smoke.rs b/src/tests/classic/smoke.rs index c3d7ad72e..98e5187cd 100644 --- a/src/tests/classic/smoke.rs +++ b/src/tests/classic/smoke.rs @@ -148,7 +148,7 @@ fn mid_negative_value_bin() { Box::new(SimpleCreateCLVMObject {}), ) .expect("should be able to make nodeptr"); - if let SExp::Atom() = allocator.sexp(atom.1) { + if let SExp::Atom = allocator.sexp(atom.1) { let res_bytes = allocator.atom(atom.1); assert_eq!(res_bytes, &[0xff, 0xff]); } else { @@ -276,7 +276,7 @@ fn can_run_from_source_nil() { let mut allocator = Allocator::new(); let res = run_from_source(&mut allocator, "()".to_string()); match allocator.sexp(res) { - SExp::Atom() => { + SExp::Atom => { let res_bytes = allocator.atom(res); assert_eq!(res_bytes.len(), 0); } @@ -291,7 +291,7 @@ fn can_echo_quoted_nil() { let mut allocator = Allocator::new(); let res = run_from_source(&mut allocator, "(1)".to_string()); match allocator.sexp(res) { - SExp::Atom() => { + SExp::Atom => { let res_bytes = allocator.atom(res); assert_eq!(res_bytes.len(), 0); } @@ -322,7 +322,7 @@ fn can_echo_quoted_atom() { let mut allocator = Allocator::new(); let res = run_from_source(&mut allocator, "(1 . 3)".to_string()); match allocator.sexp(res) { - SExp::Atom() => { + SExp::Atom => { let res_bytes = allocator.atom(res); assert_eq!(res_bytes.len(), 1); assert_eq!(res_bytes[0], 3); @@ -338,7 +338,7 @@ fn can_do_operations() { let mut allocator = Allocator::new(); let res = run_from_source(&mut allocator, "(16 (1 . 3) (1 . 5))".to_string()); match allocator.sexp(res) { - SExp::Atom() => { + SExp::Atom => { let res_bytes = allocator.atom(res); assert_eq!(res_bytes.len(), 1); assert_eq!(res_bytes[0], 8); @@ -354,7 +354,7 @@ fn can_do_operations_kw() { let mut allocator = Allocator::new(); let res = run_from_source(&mut allocator, "(+ (q . 3) (q . 5))".to_string()); match allocator.sexp(res) { - SExp::Atom() => { + SExp::Atom => { let res_bytes = allocator.atom(res); assert_eq!(res_bytes.len(), 1); assert_eq!(res_bytes[0], 8); diff --git a/src/tests/compiler/assign.rs b/src/tests/compiler/assign.rs new file mode 100644 index 000000000..1f071c9f8 --- /dev/null +++ b/src/tests/compiler/assign.rs @@ -0,0 +1,368 @@ +use crate::tests::classic::run::{do_basic_brun, do_basic_run}; +use std::rc::Rc; + +trait TestCompute { + fn compute(&self, x: i64, y: i64) -> (i64, i64); +} + +#[derive(Default, Clone)] +struct ComposedComputation { + to_run: Vec>, +} +impl TestCompute for ComposedComputation { + fn compute(&self, mut x: i64, mut y: i64) -> (i64, i64) { + for entry in self.to_run.iter() { + let (new_x, new_y) = entry.compute(x, y); + x = new_x; + y = new_y; + } + (x, y) + } +} + +struct XPlus1 {} +impl TestCompute for XPlus1 { + fn compute(&self, x: i64, y: i64) -> (i64, i64) { + (x + 1, y) + } +} + +struct YPlus1 {} +impl TestCompute for YPlus1 { + fn compute(&self, x: i64, y: i64) -> (i64, i64) { + (x, y + 1) + } +} + +struct FFunc {} +impl TestCompute for FFunc { + fn compute(&self, x: i64, y: i64) -> (i64, i64) { + let divxy = x / y; + let modxy = x % y; + (divxy, modxy) + } +} + +struct GFunc {} +impl TestCompute for GFunc { + fn compute(&self, x: i64, _y: i64) -> (i64, i64) { + let v = 1 + (3 * x); + (v, v) + } +} + +struct HFunc {} +impl TestCompute for HFunc { + fn compute(&self, x: i64, y: i64) -> (i64, i64) { + let v = x * y; + (v, v) + } +} + +struct IFunc {} +impl TestCompute for IFunc { + fn compute(&self, x: i64, _y: i64) -> (i64, i64) { + (x - 1, x * 2) + } +} + +struct UseTestFunction { + name: String, + args: usize, + outputs: usize, + text: String, + compute: Rc, +} + +struct AssignTestMatrix { + functions: Vec, +} + +#[test] +#[ignore] +fn test_assign_matrix() { + let inline_kwds = vec!["assign", "assign-lambda", "assign-inline"]; + let matrix = AssignTestMatrix { + functions: vec![ + UseTestFunction { + name: "F".to_string(), + args: 2, + outputs: 2, + text: "(defun F (X Y) (divmod X Y))".to_string(), + compute: Rc::new(FFunc {}), + }, + UseTestFunction { + name: "F-inline".to_string(), + args: 2, + outputs: 2, + text: "(defun-inline F-inline (X Y) (divmod X Y))".to_string(), + compute: Rc::new(FFunc {}), + }, + UseTestFunction { + name: "G".to_string(), + args: 1, + outputs: 1, + text: "(defun G (X) (+ 1 (* 3 X)))".to_string(), + compute: Rc::new(GFunc {}), + }, + UseTestFunction { + name: "G-inline".to_string(), + args: 1, + outputs: 1, + text: "(defun-inline G-inline (X) (+ 1 (* 3 X)))".to_string(), + compute: Rc::new(GFunc {}), + }, + UseTestFunction { + name: "H".to_string(), + args: 2, + outputs: 1, + text: "(defun H (X Y) (* X Y))".to_string(), + compute: Rc::new(HFunc {}), + }, + UseTestFunction { + name: "H-inline".to_string(), + args: 2, + outputs: 1, + text: "(defun-inline H-inline (X Y) (* X Y))".to_string(), + compute: Rc::new(HFunc {}), + }, + UseTestFunction { + name: "I".to_string(), + args: 1, + outputs: 2, + text: "(defun I (X) (c (- X 1) (* X 2)))".to_string(), + compute: Rc::new(IFunc {}), + }, + UseTestFunction { + name: "I-inline".to_string(), + args: 1, + outputs: 2, + text: "(defun-inline I-inline (X) (c (- X 1) (* X 2)))".to_string(), + compute: Rc::new(IFunc {}), + }, + ], + }; + + // The program will take X, Y + + let mut starter_program = vec!["(mod (X Y) (include *standard-cl-21*) ".to_string()]; + for func in matrix.functions.iter() { + starter_program.push(func.text.clone()); + } + + let assert_program_worked = |program: &[String], to_compute: &ComposedComputation| { + let joined = program.join("\n").to_string(); + let compiled = do_basic_run(&vec!["run".to_string(), joined]); + let executed = do_basic_brun(&vec![ + "brun".to_string(), + "-n".to_string(), + compiled, + "(13 19)".to_string(), + ]); + let (ex, ey) = to_compute.compute(13, 19); + let expected = do_basic_brun(&vec![ + "brun".to_string(), + "-n".to_string(), + format!("(1 . ({ex} . {ey}))"), + ]); + assert_eq!(expected, executed); + }; + + let finish_program = |program: &mut Vec, main_or_function: usize, assign_expr: &str| { + if main_or_function == 0 { + program.push(assign_expr.to_string()); + } else { + if main_or_function == 1 { + program.push(format!("(defun Q (X Y) {})", assign_expr)); + } else { + program.push(format!("(defun-inline Q (X Y) {})", assign_expr)); + } + program.push("(Q X Y)".to_string()); + } + program.push(")".to_string()); + }; + + let test_triple_nesting = + |to_compute: &ComposedComputation, main_or_function: usize, assign_expr_list: &[String]| { + let assign_expr = assign_expr_list.join("\n").to_string(); + let mut program = starter_program.clone(); + finish_program(&mut program, main_or_function, &assign_expr); + assert_program_worked(&program, &to_compute); + }; + + let test_third_level_nestings = |to_compute_x: &ComposedComputation, + fourth_var: &str, + y: &UseTestFunction, + main_or_function: usize, + assign_expr: &str, + second_assign: &str, + end_parens: &str| { + // Put on a third level on the stack. + for z in matrix.functions.iter() { + let assign_call_z = if z.args == 1 { + format!("({} V2)", z.name) + } else { + format!("({} V2 (+ 1 {fourth_var}))", z.name) + }; + + let (third_assign, sixth_var) = if z.outputs == 1 { + (format!("V4 {assign_call_z}"), "V4") + } else { + (format!("(V4 . V5) {assign_call_z}"), "V5") + }; + + let final_expr = format!("(c V4 {sixth_var}))"); + let mut to_compute = to_compute_x.clone(); + to_compute.to_run.push(y.compute.clone()); + to_compute.to_run.push(Rc::new(YPlus1 {})); + to_compute.to_run.push(z.compute.clone()); + + // Try with z in the same assign. + test_triple_nesting( + &to_compute, + main_or_function, + &[ + assign_expr.to_string(), + second_assign.to_string(), + third_assign.clone(), + final_expr.clone(), + end_parens.to_string(), + ], + ); + + // Try with z nested. + test_triple_nesting( + &to_compute, + main_or_function, + &[ + assign_expr.to_string(), + second_assign.to_string(), + "(assign".to_string(), + third_assign, + final_expr, + ")".to_string(), + end_parens.to_string(), + ], + ); + } + }; + + for x in matrix.functions.iter() { + let main_expr = if x.args == 1 { + format!("({} X)", x.name) + } else { + format!("({} X Y)", x.name) + }; + + // Depth 1. + for inline_choice in inline_kwds.iter() { + let mut to_compute_x = ComposedComputation::default(); + to_compute_x.to_run.push(x.compute.clone()); + for main_or_function in 0..=2 { + let (assign_expr, second_var) = if x.outputs == 1 { + (format!("({inline_choice} V0 {main_expr}"), "V0") + } else { + (format!("({inline_choice} (V0 . V1) {main_expr}"), "V1") + }; + + { + let mut program = starter_program.clone(); + let finished_assign_expr = + vec![assign_expr.clone(), format!("(c V0 {second_var}))")] + .join("\n") + .to_string(); + finish_program(&mut program, main_or_function, &finished_assign_expr); + assert_program_worked(&program, &to_compute_x); + } + + // Second set of assignments. + for y in matrix.functions.iter() { + // Use both arguments in one more function call. + let second_var = if x.outputs == 1 { "V0" } else { "V1" }; + let assign_call_y = if y.args == 1 { + format!("({} V0)", y.name) + } else { + format!("({} V0 {second_var})", y.name) + }; + let (second_assign, fourth_var) = if y.outputs == 1 { + (format!("V2 {assign_call_y}"), "V2") + } else { + (format!("(V2 . V3) {assign_call_y}"), "V3") + }; + + { + let assign_expr = vec![ + assign_expr.clone(), + second_assign.clone(), + format!("(c V2 {fourth_var}))"), + ] + .join("\n") + .to_string(); + let mut program = starter_program.clone(); + let mut to_compute = to_compute_x.clone(); + to_compute.to_run.push(y.compute.clone()); + finish_program(&mut program, main_or_function, &assign_expr); + assert_program_worked(&program, &to_compute); + } + + test_third_level_nestings( + &to_compute_x, + fourth_var, + y, + main_or_function, + &assign_expr, + &second_assign, + "", + ); + } + + // Nested + for y in matrix.functions.iter() { + for inline_choice_y in inline_kwds.iter() { + // Use both arguments in one more function call. + let second_var = if x.outputs == 1 { "V0" } else { "V1" }; + let assign_call_y = if y.args == 1 { + format!("({} V0)", y.name) + } else { + format!("({} V0 {second_var})", y.name) + }; + let (second_assign, fourth_var) = if y.outputs == 1 { + (format!("({inline_choice_y} V2 {assign_call_y}"), "V2") + } else { + ( + format!("({inline_choice_y} (V2 . V3) {assign_call_y}"), + "V3", + ) + }; + + { + let assign_expr = vec![ + assign_expr.clone(), + second_assign.clone(), + format!("(c V2 {fourth_var})))"), + ] + .join("\n") + .to_string(); + + let mut program = starter_program.clone(); + let mut to_compute = to_compute_x.clone(); + to_compute.to_run.push(y.compute.clone()); + finish_program(&mut program, main_or_function, &assign_expr); + assert_program_worked(&program, &to_compute); + } + + test_third_level_nestings( + &to_compute_x, + fourth_var, + y, + main_or_function, + &assign_expr, + &second_assign, + ")", + ); + } + } + } + } + } +} diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index 38a2ceceb..61c7b8828 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{BTreeSet, HashMap}; use std::rc::Rc; use clvm_rs::allocator::Allocator; @@ -7,8 +7,10 @@ use crate::classic::clvm_tools::stages::stage_0::DefaultProgramRunner; use crate::compiler::clvm::run; use crate::compiler::compiler::{compile_file, DefaultCompilerOpts}; use crate::compiler::comptypes::{CompileErr, CompilerOpts}; +use crate::compiler::frontend::{collect_used_names_sexp, frontend}; +use crate::compiler::rename::rename_in_cons; use crate::compiler::runtypes::RunFailure; -use crate::compiler::sexp::{parse_sexp, SExp}; +use crate::compiler::sexp::{decode_string, parse_sexp, SExp}; use crate::compiler::srcloc::Srcloc; const TEST_TIMEOUT: usize = 1000000; @@ -63,6 +65,38 @@ pub fn run_string(content: &String, args: &String) -> Result, CompileEr run_string_maybe_opt(content, args, false) } +// Given some renaming that leaves behind gensym style names with _$_ in them, +// order them and use a locally predictable renaming scheme to give them a final +// test checkable value. +pub fn squash_name_differences(in_sexp: Rc) -> Result, String> { + let found_names_set: BTreeSet<_> = collect_used_names_sexp(in_sexp.clone()) + .into_iter() + .filter(|n| n.contains(&b'$')) + .collect(); + let mut found_names_progression = b'A'; + let mut replacement_map = HashMap::new(); + for found_name in found_names_set.iter() { + if let Some(located_dollar_part) = found_name.iter().position(|x| *x == b'$') { + let mut new_name: Vec = found_name + .iter() + .take(located_dollar_part + 2) + .copied() + .collect(); + new_name.push(found_names_progression); + found_names_progression += 1; + replacement_map.insert(found_name.clone(), new_name); + } else { + return Err(decode_string(&found_name)); + } + } + if replacement_map.len() != found_names_set.len() { + return Err(format!( + "mismatched lengths {replacement_map:?} vs {found_names_set:?}" + )); + } + Ok(rename_in_cons(&replacement_map, in_sexp, false)) +} + /* // Upcoming support for extra optimization (WIP) fn run_string_opt(content: &String, args: &String) -> Result, CompileErr> { run_string_maybe_opt(content, args, true) @@ -1130,8 +1164,7 @@ fn arg_destructure_test_1() { (include *standard-cl-21*) delegated_puzzle_hash -)" - } +)"} .to_string(); let res = run_string(&prog, &"(1 2 3 . 4)".to_string()).unwrap(); assert_eq!(res.to_string(), "4"); @@ -1150,6 +1183,251 @@ fn test_defconstant_tree() { assert_eq!(res.to_string(), "((0x4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a . 0x9dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2) 0x02a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222 . 0x02a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5)"); } +#[test] +fn test_assign_form_0() { + let prog = indoc! {" +(mod (X) + (assign + X1 (+ X 1) ;; X1 is 14 if X is 13. + X1 + ) + )"} + .to_string(); + let res = run_string(&prog, &"(13)".to_string()).unwrap(); + assert_eq!(res.to_string(), "14"); +} + +#[test] +fn test_assign_form_1() { + let prog = indoc! {" +(mod (X) + (assign + ;; A lot of forms in order. + X1 (+ X 1) ;; 14 + X2 (+ X1 1) ;; 15 + X3 (+ X2 1) ;; 16 + Y0 (+ X3 1) ;; 17 + X4 (+ X3 1) ;; 17 + X5 (+ Y0 1) ;; 18 + Y1 (+ X5 Y0) ;; 35 + Y1 + ) + )"} + .to_string(); + let res = run_string(&prog, &"(13)".to_string()).unwrap(); + assert_eq!(res.to_string(), "35"); +} + +#[test] +fn test_assign_form_cplx_1() { + let prog = indoc! {" +(mod (X) + (defun-inline tup (X Y) (c X Y)) + (assign + (X1 . X2) (tup (+ X 1) (+ X 2)) ;; 14 + X3 (+ X1 1) ;; 15 + X4 (+ X2 1) ;; 16 + (Y0 . X5) (tup (+ X4 1) (+ X4 1)) ;; 17 + X6 (+ Y0 1) ;; 18 + Y1 (+ X6 Y0) ;; 35 + Y1 + ) + )"} + .to_string(); + let res = run_string(&prog, &"(13)".to_string()).unwrap(); + assert_eq!(res.to_string(), "35"); +} + +#[test] +fn test_assign_form_in_let_binding() { + let prog = indoc! {" +(mod (X) + (defun-inline tup (X Y) (c X Y)) + (let + ((FOO + (assign + (X1 . X2) (tup (+ X 1) (+ X 2)) ;; 14 + X3 (+ X1 1) ;; 15 + X4 (+ X2 1) ;; 16 + (Y0 . X5) (tup (+ X4 1) (+ X4 1)) ;; 17 + X6 (+ Y0 1) ;; 18 + Y1 (+ X6 Y0) ;; 35 + Y1 + ))) + FOO + ) + )"} + .to_string(); + let res = run_string(&prog, &"(13)".to_string()).unwrap(); + assert_eq!(res.to_string(), "35"); +} + +#[test] +fn test_assign_form_in_function_argument() { + let prog = indoc! {" +(mod (X) + (defun-inline tup (X Y) (c X Y)) + (defun F (A B) (+ A B)) + (F + (assign + (X1 . X2) (tup (+ X 1) (+ X 2)) ;; 14 + X3 (+ X1 1) ;; 15 + X4 (+ X2 1) ;; 16 + (Y0 . X5) (tup (+ X4 1) (+ X4 1)) ;; 17 + X6 (+ Y0 1) ;; 18 + Y1 (+ X6 Y0) ;; 35 + Y1 + ) + 101 + ) + )"} + .to_string(); + let res = run_string(&prog, &"(13)".to_string()).unwrap(); + assert_eq!(res.to_string(), "136"); +} + +#[test] +fn test_assign_form_in_inline_argument() { + let prog = indoc! {" +(mod (X) + (defun-inline tup (X Y) (c X Y)) + (defun-inline F (A B) (+ A B)) + (F + (assign + (X1 . X2) (tup (+ X 1) (+ X 2)) ;; 14 + X3 (+ X1 1) ;; 15 + X4 (+ X2 1) ;; 16 + (Y0 . X5) (tup (+ X4 1) (+ X4 1)) ;; 17 + X6 (+ Y0 1) ;; 18 + Y1 (+ X6 Y0) ;; 35 + Y1 + ) + 101 + ) + )"} + .to_string(); + let res = run_string(&prog, &"(13)".to_string()).unwrap(); + assert_eq!(res.to_string(), "136"); +} + +#[test] +fn test_assign_in_if() { + let prog = indoc! {" +(mod (X) + (defun-inline tup (X Y) (c X Y)) + (defun-inline F (A B) (+ A B)) + (if X + (assign + (X1 . X2) (tup (+ X 1) (+ X 2)) ;; 14 + X3 (+ X1 1) ;; 15 + X4 (+ X3 1) ;; 16 + (Y0 . X5) (tup (+ X4 1) (+ X4 1)) ;; 17 + X6 (+ Y0 1) ;; 18 + Y1 (+ X6 Y0) ;; 35 + Y1 + ) + 101 + ) + )"} + .to_string(); + let res = run_string(&prog, &"(13)".to_string()).unwrap(); + assert_eq!(res.to_string(), "35"); +} + +#[test] +fn test_assign_fun_cplx_2() { + let prog = indoc! {" +(mod (X) + (defun-inline tup (X Y) (c X Y)) + (defun-inline F (A B) (+ A B)) + (if X + (let* + ((Z + (assign + (X1 . X2) (tup (+ X 1) (+ X 2)) ;; 14 + X3 (+ X1 1) ;; 15 + X4 (+ X2 1) ;; 16 + (Y0 . X5) (tup (+ X4 1) (+ X4 1)) ;; 17 + X6 (+ Y0 1) ;; 18 + Y1 (+ X6 Y0) ;; 35 + Y1 + )) + (Q (assign R (+ 3 2) (* R Z))) + ) + Q + ) + 101 + ) + )"} + .to_string(); + let res = run_string(&prog, &"(13)".to_string()).unwrap(); + assert_eq!(res.to_string(), "175"); +} + +#[test] +fn test_assign_simple_with_reodering() { + let prog = indoc! {" +(mod (A) ;; 11 + (include *standard-cl-21*) + (defun tup (a b) (c a b)) + (assign + ;; This exercises reordering in assign. + ;; Each set os grouped with a tier that will be taken together. + ;; The tiers are numbered in order, but given out of order. + + ;; Tier 1 + (X0 . X1) (tup (+ A 1) (- A 1)) ;; 12 10 + + ;; Tier 4 + finish (+ x2_gtr_x3 (- X3 x2_minus_x3)) ;; 1 + (70 - 50) + + ;; Tier 3 + x2_gtr_x3 (> X2 X3) ;; 1 + x2_minus_x3 (- X2 X3) ;; 50 + + ;; Tier 2 + X2 (* X0 10) ;; 120 + X3 (* X1 7) ;; 70 + + finish + ))"} + .to_string(); + let res = run_string(&prog, &"(11)".to_string()).unwrap(); + assert_eq!(res.to_string(), "21"); +} + +#[test] +fn test_assign_detect_multiple_definition() { + let prog = indoc! {" +(mod (A) ;; 11 + (include *standard-cl-21*) + (defun tup (a b) (c a b)) + (assign + ;; Tier 1 + (X0 . X1) (tup (+ A 1) (- A 1)) ;; 12 10 + + ;; Tier 4 + finish (+ x2_gtr_x3 (- X3 x2_minus_x3)) ;; 1 + (70 - 50) + + ;; Tier 3 + x2_gtr_x3 (> X2 X3) ;; 1 + x2_minus_x3 (- X2 X3) ;; 50 + + ;; Tier 2 + X2 (* X0 10) ;; 120 + X2 (* X1 7) ;; 70 + + finish + ))"} + .to_string(); + if let Err(CompileErr(l, e)) = run_string(&prog, &"(11)".to_string()) { + assert_eq!(l.line, 17); + assert!(e.starts_with("Duplicate")); + } else { + assert!(false); + } +} + #[test] fn test_assign_dont_detect_unrelated_inlines_as_recursive() { let prog = indoc! {" @@ -1194,6 +1472,393 @@ fn test_inline_out_of_bounds_diagnostic() { } } +#[test] +fn test_lambda_without_capture_from_function() { + let prog = indoc! {" +(mod (A B) + (include *standard-cl-21*) + (defun FOO () (lambda (X Y) (+ X Y))) + (a (FOO) (list A B)) + )"} + .to_string(); + let res = run_string(&prog, &"(3 4)".to_string()).unwrap(); + assert_eq!(res.to_string(), "7"); +} + +#[test] +fn test_lambda_without_capture() { + let prog = indoc! {" +(mod (A B) + (include *standard-cl-21*) + (a (lambda (X Y) (+ X Y)) (list A B)) + )"} + .to_string(); + let res = run_string(&prog, &"(3 4)".to_string()).unwrap(); + assert_eq!(res.to_string(), "7"); +} + +#[test] +fn test_lambda_with_capture_from_function() { + let prog = indoc! {" +(mod (A B) + (include *standard-cl-21*) + (defun FOO (Z) (lambda ((& Z) X) (- X Z))) + (a (FOO A) (list B)) + )"} + .to_string(); + let res = run_string(&prog, &"(5 19)".to_string()).unwrap(); + assert_eq!(res.to_string(), "14"); +} + +#[test] +fn test_lambda_with_capture() { + let prog = indoc! {" +(mod (A B) + (include *standard-cl-21*) + (a (lambda ((& A) Y) (- Y A)) (list B)) + )"} + .to_string(); + let res = run_string(&prog, &"(5 19)".to_string()).unwrap(); + assert_eq!(res.to_string(), "14"); +} + +#[test] +fn test_lambda_in_let_0() { + let prog = indoc! {" +(mod (A) + (include *standard-cl-21*) + (defun FOO (Z) + (let ((Q (* 2 Z))) + (lambda ((& Q)) (- 100 Q)) + ) + ) + (a (FOO A) ()) + )"} + .to_string(); + let res = run_string(&prog, &"(5)".to_string()).unwrap(); + assert_eq!(res.to_string(), "90"); +} + +#[test] +fn test_lambda_in_let_1() { + let prog = indoc! {" +(mod (A B) + (include *standard-cl-21*) + (defun FOO (Z) + (let ((Q (* 2 Z))) + (lambda ((& Q) X) (- X Q)) + ) + ) + (a (FOO A) (list B)) + )"} + .to_string(); + let res = run_string(&prog, &"(5 19)".to_string()).unwrap(); + assert_eq!(res.to_string(), "9"); +} + +#[test] +fn test_lambda_in_map() { + let prog = indoc! {" +(mod (add-number L) + + (include *standard-cl-21*) + + (defun map (F L) + (if L + (c (a F (list (f L))) (map F (r L))) + () + ) + ) + + (map + (lambda ((& add-number) number) (+ add-number number)) + L + ) + ) +"} + .to_string(); + let res = run_string(&prog, &"(5 (1 2 3 4))".to_string()).unwrap(); + assert_eq!(res.to_string(), "(6 7 8 9)"); +} + +#[test] +fn test_lambda_in_map_with_let_surrounding() { + let prog = indoc! {" +(mod (add-number L) + + (include *standard-cl-21*) + + (defun map (F L) + (if L + (c (a F (list (f L))) (map F (r L))) + () + ) + ) + + (map + (let ((A (* add-number 2))) + (lambda ((& A) number) (+ A number)) + ) + L + ) + ) +"} + .to_string(); + let res = run_string(&prog, &"(5 (1 2 3 4))".to_string()).unwrap(); + assert_eq!(res.to_string(), "(11 12 13 14)"); +} + +#[test] +fn test_map_with_lambda_function_from_env_and_bindings() { + let prog = indoc! {" + (mod (add-number L) + + (include *standard-cl-21*) + + (defun map (F L) + (if L + (c (a F (list (f L))) (map F (r L))) + () + ) + ) + + (defun add-twice (X Y) (+ (* 2 X) Y)) + + (map + (lambda ((& add-number) number) (add-twice add-number number)) + L + ) + )"} + .to_string(); + let res = run_string(&prog, &"(5 (1 2 3 4))".to_string()).unwrap(); + assert_eq!(res.to_string(), "(11 12 13 14)"); +} + +#[test] +fn test_map_with_lambda_function_from_env_no_bindings() { + let prog = indoc! {" + (mod (L) + + (include *standard-cl-21*) + + (defun map (F L) + (if L + (c (a F (list (f L))) (map F (r L))) + () + ) + ) + + (defun sum-list (L) + (if L + (+ (f L) (sum-list (r L))) + () + ) + ) + + (map + (lambda (lst) (sum-list lst)) + L + ) + )"} + .to_string(); + let res = run_string(&prog, &"(((5 10 15) (2 4 8) (3 6 9)))".to_string()).unwrap(); + assert_eq!(res.to_string(), "(30 14 18)"); +} + +#[test] +fn test_lambda_using_let() { + let prog = indoc! {" + (mod (P L) + + (include *standard-cl-21*) + + (defun map (F L) + (if L + (c (a F (list (f L))) (map F (r L))) + () + ) + ) + + (map + (lambda ((& P) item) (let ((composed (c P item))) composed)) + L + ) + )"} + .to_string(); + let res = run_string(&prog, &"(1 (10 20 30))".to_string()).unwrap(); + assert_eq!(res.to_string(), "((1 . 10) (1 . 20) (1 . 30))"); +} + +#[test] +fn test_lambda_using_macro() { + let prog = indoc! {" + (mod (P L) + + (include *standard-cl-21*) + + (defun map (F L) + (if L + (c (a F (list (f L))) (map F (r L))) + () + ) + ) + + (map + (lambda ((& P) item) (list P item)) + L + ) + )"} + .to_string(); + let res = run_string(&prog, &"(1 (10 20 30))".to_string()).unwrap(); + assert_eq!(res.to_string(), "((1 10) (1 20) (1 30))"); +} + +#[test] +fn test_lambda_reduce() { + let prog = indoc! {" + (mod (LST) + (include *standard-cl-21*) + (defun reduce (fun lst init) + (if lst + (reduce fun (r lst) (a fun (list (f lst) init))) + init + ) + ) + + (let + ((capture 100)) + (reduce (lambda ((& capture) (X Y) ACC) (+ (* X Y) ACC capture)) LST 0) + ) + ) + "} + .to_string(); + let res = run_string(&prog, &"(((2 3) (4 9)))".to_string()).unwrap(); + assert_eq!(res.to_string(), "242"); +} + +#[test] +fn test_lambda_as_let_binding() { + let prog = indoc! {" + (mod (P L) + (defun map (F L) + (if L (c (a F (list (f L))) (map F (r L))) ()) + ) + (defun x2 (N) (* 2 N)) + (defun x3p1 (N) (+ 1 (* 3 N))) + (let* ((H (lambda (N) (x2 N))) + (G (lambda (N) (x3p1 N))) + (F (if P G H))) + (map F L) + ) + ) + "} + .to_string(); + let res0 = run_string(&prog, &"(0 (1 2 3))".to_string()).unwrap(); + assert_eq!(res0.to_string(), "(2 4 6)"); + let res1 = run_string(&prog, &"(1 (1 2 3))".to_string()).unwrap(); + assert_eq!(res1.to_string(), "(4 7 10)"); +} + +#[test] +fn test_lambda_mixed_let_binding() { + let prog = indoc! {" + (mod (P L) + (defun map (F L) + (if L (c (a F (list (f L))) (map F (r L))) ()) + ) + (defun x2 (N) (* 2 N)) + (defun x3p1 (N) (+ 1 (* 3 N))) + (let* ((G (lambda (N) (x3p1 N))) + (F (if P G (lambda (N) (x2 N))))) + (map F L) + ) + ) + "} + .to_string(); + let res0 = run_string(&prog, &"(0 (1 2 3))".to_string()).unwrap(); + assert_eq!(res0.to_string(), "(2 4 6)"); + let res1 = run_string(&prog, &"(1 (1 2 3))".to_string()).unwrap(); + assert_eq!(res1.to_string(), "(4 7 10)"); +} + +#[test] +fn test_lambda_hof_1() { + let prog = indoc! {" + (mod (P) + (a (a (lambda ((& P) X) (lambda ((& P X)) (+ P X))) (list 3)) ()) + ) + "} + .to_string(); + let res = run_string(&prog, &"(1)".to_string()).unwrap(); + assert_eq!(res.to_string(), "4"); +} + +#[test] +fn test_lambda_as_argument_to_macro() { + let prog = indoc! {" + (mod (P) + (defun map-f (A L) + (if L (c (a (f L) A) (map-f A (r L))) ()) + ) + (let ((Fs (list (lambda (X) (- X 1)) (lambda (X) (+ X 1)) (lambda (X) (* 2 X)))) + (args (list P))) + (map-f args Fs) + ) + ) + "} + .to_string(); + let res = run_string(&prog, &"(10)".to_string()).unwrap(); + assert_eq!(res.to_string(), "(9 11 20)"); +} + +#[test] +fn test_lambda_as_argument_to_macro_with_inner_let() { + let prog = indoc! {" + (mod (P) + (defun map-f (A L) + (if L (c (a (f L) A) (map-f A (r L))) ()) + ) + (let ((Fs (list (lambda (X) (let ((N (* X 3))) N)) (lambda (X) (+ X 1)) (lambda (X) (* 2 X)))) + (args (list P))) + (map-f args Fs) + ) + ) + "} + .to_string(); + let res = run_string(&prog, &"(10)".to_string()).unwrap(); + assert_eq!(res.to_string(), "(30 11 20)"); +} + +#[test] +fn test_treat_function_name_as_value() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + (defun G (X) (* 2 X)) + (defun F (X) (G (+ 1 X))) + (a F (list X)) +) + "} + .to_string(); + let res = run_string(&prog, &"(99)".to_string()).expect("should compile"); + assert_eq!(res.to_string(), "200"); +} + +#[test] +fn test_treat_function_name_as_value_filter() { + let prog = indoc! {" + (mod L + (include *standard-cl-21*) + (defun greater-than-3 (X) (> X 3)) + (defun filter (F L) (let ((rest (filter F (r L)))) (if L (if (a F (list (f L))) (c (f L) rest) rest) ()))) + (filter greater-than-3 L) + ) + "} + .to_string(); + let res = run_string(&prog, &"(1 2 3 4 5)".to_string()).expect("should compile"); + assert_eq!(res.to_string(), "(4 5)"); +} + #[test] fn test_inline_in_assign_not_actually_recursive() { let prog = indoc! {" @@ -1248,3 +1913,359 @@ fn test_simple_rest_call_inline() { let res = run_string(&prog, &"(13 99 144)".to_string()).expect("should compile and run"); assert_eq!(res.to_string(), "768"); } + +#[test] +fn test_simple_rest_lambda() { + let prog = indoc! {" +(mod (Z X) + (include *standard-cl-21*) + + (defun silly-lambda-consumer (Q F) (a F (list Q))) + + (silly-lambda-consumer &rest (list X (lambda ((& Z) X) (* Z X)))) + )"} + .to_string(); + let res = run_string(&prog, &"(13 51)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "663"); +} + +#[test] +fn test_lambda_in_lambda() { + let prog = indoc! {" +(mod (Z X) + (include *standard-cl-21*) + + (defun silly-lambda-consumer (Q F) (a F (list Q))) + + (a (silly-lambda-consumer X (lambda ((& Z) X) (lambda ((& Z X)) (* Z X)))) ()) + )"} + .to_string(); + let res = run_string(&prog, &"(13 51)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "663"); +} + +#[test] +fn test_let_in_rest_0() { + let prog = indoc! {" +(mod (Z X) + (include *standard-cl-21*) + + (defun F (X) (+ X 3)) + + (F &rest (list (let ((Q (* X Z))) (+ Q 99)))) + )"} + .to_string(); + let res = run_string(&prog, &"(3 2)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "108"); +} + +#[test] +fn test_let_in_rest_1() { + let prog = indoc! {" +(mod (Z X) + (include *standard-cl-21*) + + (defun F (X) (+ X 3)) + + (F &rest (let ((Q (* X Z))) (list (+ Q 99)))) + )"} + .to_string(); + let res = run_string(&prog, &"(3 2)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "108"); +} + +#[test] +fn test_lambda_override_name_arg_let_capture() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F (overridden) + (let ((overridden (* 3 overridden))) + (lambda ((& overridden) z) (+ overridden z)) + ) + ) + + (a (F X) (list 17)) + )"} + .to_string(); + let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "50"); +} + +#[test] +fn test_lambda_override_name_arg_let_with_let_in_lambda_1() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F (overridden) + (let ((overridden (* 3 overridden))) + (lambda ((& overridden) z) + (let + ((z (+ 123 z))) + (+ overridden z) + ) + ) + ) + ) + + (a (F X) (list 17)) + )"} + .to_string(); + let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "173"); +} + +#[test] +fn test_lambda_override_name_arg_let_with_let_in_lambda_2() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F (overridden) + (let ((overridden (* 3 overridden))) + (lambda ((& overridden) z) + (let + ((overridden (+ 123 overridden))) + (+ overridden z) + ) + ) + ) + ) + + (a (F X) (list 17)) + )"} + .to_string(); + let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "173"); +} + +#[test] +fn test_lambda_override_name_arg_assign_with_assign_in_lambda_1() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F (Z) + (assign overridden (* 3 Z) + (lambda ((& overridden) z) + (let + ((z (+ 123 z))) + (+ overridden z) + ) + ) + ) + ) + + (a (F X) (list 17)) + )"} + .to_string(); + let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "173"); +} + +#[test] +fn test_lambda_override_name_arg_let_with_assign_in_lambda_1() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F (overridden) + (let ((overridden (* 3 overridden))) ;; overridden = 33 + (lambda ((& overridden) z) ;; overridden = 33 + (assign overridden (+ 123 z) ;; overridden = 17 + 123 = 140 + (+ overridden z) ;; 157 + ) + ) + ) + ) + + (a (F X) (list 17)) + )"} + .to_string(); + let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "157"); +} + +#[test] +fn test_lambda_override_name_arg_let_with_let_in_lambda_3() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F (overridden) + (let ((overridden (* 3 overridden))) ;; overridden = 33 + (lambda ((& overridden) z) ;; overridden = 33 + (let ((overridden (+ 123 z))) ;; overridden = 17 + 123 = 140 + (+ overridden z) ;; 157 + ) + ) + ) + ) + + (a (F X) (list 17)) + )"} + .to_string(); + let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "157"); +} + +#[test] +fn test_lambda_override_name_arg_let_with_assign_twice_in_lambda() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F (overridden) + (let ((overridden (* 3 overridden))) ;; overridden = 33 + (lambda ((& overridden) y z) ;; overridden = 33 + (assign + overridden (+ 123 z) ;; overridden = 123 + 17 = 140 + y (+ 191 z overridden) ;; y = 191 + 17 + 140 = 348 + (+ overridden z y) ;; 505 + ) + ) + ) + ) + + (a (F X) (list 13 17)) + )"} + .to_string(); + let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "505"); +} + +#[test] +fn test_lambda_override_name_arg_let_with_let_twice_in_lambda() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F (overridden) + (let ((overridden (* 3 overridden))) ;; overridden = 33 + (lambda ((& overridden) y z) ;; overridden = 33 + (let + ((overridden (+ 123 z))) ;; overridden = 123 + 17 = 140 + (let ((y (+ 191 z overridden))) ;; y = 191 + 17 + 140 = 348 + (+ overridden z y) ;; 505 + ) + ) + ) + ) + ) + + (a (F X) (list 13 17)) + )"} + .to_string(); + let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "505"); +} + +#[test] +fn test_lambda_override_name_arg_let_with_let_star_twice_in_lambda() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F (overridden) + (let ((overridden (* 3 overridden))) ;; overridden = 33 + (lambda ((& overridden) y z) ;; overridden = 33 + (let* + ((overridden (+ 123 z)) ;; overridden = 123 + 17 = 140 + (y (+ 191 z overridden))) ;; y = 191 + 17 + 140 = 348 + (+ overridden z y) ;; 505 + ) + ) + ) + ) + + (a (F X) (list 13 17)) + )"} + .to_string(); + let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "505"); +} + +#[test] +fn test_lambda_let_override_in_binding() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F (overridden) + (let ((overridden (* 3 overridden))) ;; overridden = 33 + (lambda ((& overridden) y z) ;; overridden = 33 + (let + ((y (+ 191 z (let ((overridden (+ 123 z))) overridden)))) ;; overridden = 123 + 17 = 140, y = 191 + 17 + 140 = 348 + (+ overridden z y) ;; 33 + 17 + 348 = 398 + ) + ) + ) + ) + + (a (F X) (list 13 17)) + )"} + .to_string(); + let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "398"); +} + +#[test] +fn test_rename_in_compileform_run() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F overridden + (let + ((overridden (* 3 (f overridden))) ;; overridden = 33 + (y (f (r overridden))) ;; y = 13 + (z (f (r (r overridden))))) ;; z = 17 + (+ overridden z y) ;; 33 + 13 + 17 = 63 + ) + ) + + (F X 13 17) + )"} + .to_string(); + + let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "63"); +} + +#[test] +fn test_rename_in_compileform_simple() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F overridden + (let + ((overridden (* 3 (f overridden))) ;; overridden = 33 + (y (f (r overridden))) ;; y = 11 + (z (f (r (r overridden))))) ;; z = 17 + (+ overridden z y) ;; 33 11 17 + ) + ) + + (F X 13 17) + )"} + .to_string(); + // Note: renames use gensym so they're unique but not spot predictable. + // + // We'll rename them in detection order to a specific set of names and should + // get for F: + // + let desired_outcome = "(defun F overridden_$_A (let ((overridden_$_B (* 3 (f overridden_$_A))) (y_$_C (f (r overridden_$_A))) (z_$_D (f (r (r overridden_$_A))))) (+ overridden_$_B z_$_D y_$_C)))"; + let parsed = parse_sexp(Srcloc::start("*test*"), prog.bytes()).expect("should parse"); + let opts: Rc = Rc::new(DefaultCompilerOpts::new(&"*test*".to_string())); + let compiled = frontend(opts, &parsed).expect("should compile"); + let helper_f: Vec<_> = compiled + .helpers + .iter() + .filter(|f| f.name() == b"F") + .collect(); + let renamed_helperform = squash_name_differences(helper_f[0].to_sexp()).expect("should rename"); + assert_eq!(renamed_helperform.to_string(), desired_outcome); +} diff --git a/src/tests/compiler/evaluate.rs b/src/tests/compiler/evaluate.rs index 393342ddd..df42a5fa0 100644 --- a/src/tests/compiler/evaluate.rs +++ b/src/tests/compiler/evaluate.rs @@ -14,12 +14,14 @@ use crate::compiler::srcloc::Srcloc; use crate::classic::clvm_tools::stages::stage_0::DefaultProgramRunner; use crate::util::ErrInto; +use crate::tests::compiler::compiler::squash_name_differences; + fn shrink_expr_from_string(s: String) -> Result { let mut allocator = Allocator::new(); let runner = Rc::new(DefaultProgramRunner::new()); let opts = Rc::new(DefaultCompilerOpts::new(&"*program*".to_string())); let loc = Srcloc::start(&"*program*".to_string()); - parse_sexp(loc.clone(), s.bytes()) + let result = parse_sexp(loc.clone(), s.bytes()) .err_into() .and_then(|parsed_program| { return frontend(opts.clone(), &parsed_program); @@ -34,8 +36,11 @@ fn shrink_expr_from_string(s: String) -> Result { false, Some(EVAL_STACK_LIMIT), ); - }) - .map(|result| result.to_sexp().to_string()) + })?; + + let result_sexp = + squash_name_differences(result.to_sexp()).map_err(|e| CompileErr(loc.clone(), e))?; + Ok(result_sexp.to_string()) } #[test] @@ -118,3 +123,65 @@ fn test_simple_fe_opt_compile_1() { "(2 (1 1 . 99) (4 (1) 1))".to_string() ); } + +#[test] +fn test_lambda_eval_1() { + assert_eq!( + shrink_expr_from_string("(lambda (X) (+ X 1))".to_string()).unwrap(), + "(lambda (X_$_A) (+ X_$_A 1))".to_string() + ); +} + +#[test] +fn test_assign_simple_form_0() { + assert_eq!( + shrink_expr_from_string("(assign A (* Z 3) X 3 Y 4 Z (+ X Y) A)".to_string()).unwrap(), + "(q . 21)" + ); +} + +#[test] +fn test_lambda_eval_2() { + assert_eq!( + shrink_expr_from_string("(a (lambda (X) (+ X 1)) (list 3))".to_string()).unwrap(), + "(q . 4)".to_string() + ); +} + +#[test] +fn test_assign_simple_form_1() { + assert_eq!( + shrink_expr_from_string("(assign A (* Z 3) Z 2 A)".to_string()).unwrap(), + "(q . 6)" + ); +} + +#[test] +fn test_lambda_eval_3() { + assert_eq!( + shrink_expr_from_string( + "(let ((L 10)) (a (lambda ((& L) X) (+ X L)) (list 3)))".to_string() + ) + .unwrap(), + "(q . 13)".to_string() + ); +} + +#[test] +fn test_lambda_eval_4() { + assert_eq!( + shrink_expr_from_string( + "(a (let ((L 10)) (lambda ((& L) X) (+ X L))) (list 3))".to_string() + ) + .unwrap(), + "(q . 13)".to_string() + ); +} + +#[test] +fn test_assign_simple_form_2() { + assert_eq!( + shrink_expr_from_string("(assign Z 2 A (* Z 3) A)".to_string()).unwrap(), + "(q . 6)" + ); +} diff --git a/src/tests/compiler/mod.rs b/src/tests/compiler/mod.rs index 249e2cf23..f7e502ead 100644 --- a/src/tests/compiler/mod.rs +++ b/src/tests/compiler/mod.rs @@ -4,6 +4,7 @@ use std::rc::Rc; use crate::compiler::sexp::{parse_sexp, SExp}; use crate::compiler::srcloc::{Srcloc, Until}; +mod assign; mod cldb; mod clvm; mod compiler; diff --git a/src/tests/compiler/preprocessor.rs b/src/tests/compiler/preprocessor.rs index 2c36f965d..a53cf808a 100644 --- a/src/tests/compiler/preprocessor.rs +++ b/src/tests/compiler/preprocessor.rs @@ -410,6 +410,7 @@ fn test_defmac_string_needs_conversion() { "} .to_string(); let res = run_string(&prog, &"(5)".to_string()); + eprintln!("res {res:?}"); assert!(res.is_err()); } diff --git a/src/tests/compiler/repl.rs b/src/tests/compiler/repl.rs index a392c77b8..d5c0977ca 100644 --- a/src/tests/compiler/repl.rs +++ b/src/tests/compiler/repl.rs @@ -302,6 +302,95 @@ fn test_eval_list_partially_evaluated_xyz() { ); } +#[test] +fn test_defun_value_in_repl_0() { + assert_eq!( + test_repl_outcome(vec![ + "(defun greater-than-3 (X) (> X 3))", + "(a greater-than-3 (list 5))" + ]) + .unwrap() + .unwrap(), + "(q . 1)" + ); +} + +#[test] +fn test_defun_value_repl_map() { + assert_eq!( + test_repl_outcome(vec![ + "(defun greater-than-3 (X) (> X 3))", + "(defun map (F L) (if L (c (a F (list (f L))) (map F (r L))) ()))", + "(map greater-than-3 (list 1 2 3 4 5))" + ]) + .unwrap() + .unwrap(), + "(q () () () 1 1)" + ); +} + +#[test] +fn test_lambda_eval_5() { + assert_eq!( + test_repl_outcome_with_stack_limit( + vec![ + "(defun GetFun (L) (lambda ((& L) X) (+ X L)))", + "(a (GetFun 10) (list 3))" + ], + None + ) + .unwrap() + .unwrap(), + "(q . 13)" + ); +} + +#[test] +fn test_lambda_eval_6() { + assert_eq!( + test_repl_outcome(vec![ + indoc! {" +(defun visit-atoms (fn acc mask path pattern) + (if (l pattern) + (visit-atoms + fn + (visit-atoms fn acc (* 2 mask) path (f pattern)) + (* 2 mask) + (logior mask path) + (r pattern) + ) + + (a fn (list acc (logior path mask) pattern)) + ) + ) +"}, + indoc! {" + (defun if-match (match) + (c 1 + (visit-atoms + (lambda (cb path pat) + (if (l pat) + (list cb \"A\") ;; Unbound use of cb + (list cb \"B\") + ) + ) + () + 1 + 0 + match + ) + ) + ) + +"}, + "(if-match (q test \"test\" t1 (t2 . t3)))" + ]) + .unwrap() + .unwrap(), + "(q 1 (((((() B) B) B) B) B) B)" + ); +} + #[test] fn test_eval_new_bls_operator() { assert_eq!( @@ -315,3 +404,68 @@ fn test_eval_new_bls_operator() { "(q)" ); } + +#[test] +fn test_repl_base_lambda_case() { + assert_eq!( + test_repl_outcome_with_stack_limit( + vec![ + "(defun F (X F) (a F (list X)))".to_string(), + "(F 3 (lambda (Y) (+ Y 9)))".to_string(), + ], + None + ) + .unwrap() + .unwrap(), + "(q . 12)" + ); +} + +#[test] +fn test_repl_rest_lambda_case() { + assert_eq!( + test_repl_outcome_with_stack_limit( + vec![ + "(defun F (X F) (a F (list X)))".to_string(), + "(F &rest (list 3 (lambda (Y) (+ Y 9))))".to_string() + ], + None + ) + .unwrap() + .unwrap(), + "(q . 12)" + ); +} + +#[test] +fn test_repl_lambda_with_captures_rest() { + assert_eq!( + test_repl_outcome_with_stack_limit( + vec![ + "(defun map (F L) (if L (c (a F (list (f L))) (map F (r L))) ()))".to_string(), + "(defun F (X L) (map &rest (list (lambda ((& X) Y) (+ X Y)) L)))".to_string(), + "(F 3 (list 99 101 103))".to_string() + ], + None + ) + .unwrap() + .unwrap(), + "(q 102 104 106)" + ); +} + +#[test] +fn test_repl_lambda_with_captures_out_of_own_function() { + assert_eq!( + test_repl_outcome_with_stack_limit( + vec![ + "(defun F (X) (lambda ((& X) Y) (+ X Y)))".to_string(), + "(a (F 3) (list 4))".to_string(), + ], + None + ) + .unwrap() + .unwrap(), + "(q . 7)" + ); +} diff --git a/src/tests/compiler/restargs.rs b/src/tests/compiler/restargs.rs index 0bd66c842..15ea7e930 100644 --- a/src/tests/compiler/restargs.rs +++ b/src/tests/compiler/restargs.rs @@ -936,6 +936,42 @@ fn test_compiler_tail_let_ni() { assert_eq!(res.to_string(), "(5 7 8)"); } +#[test] +fn test_compiler_tail_assign_ni() { + let prog = indoc! {" +(mod (X Y) + (include *standard-cl-21*) + + (defun F (A B C) (list A B C)) + + (defun G (X Y) (F X &rest (assign Q (+ Y 1) (list Y Q)))) + + (G X Y) + )"} + .to_string(); + + let res = run_string(&prog, &"(5 7)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "(5 7 8)"); +} + +#[test] +fn test_compiler_tail_assign_inline() { + let prog = indoc! {" +(mod (X Y) + (include *standard-cl-21*) + + (defun F (A B C) (list A B C)) + + (defun-inline G (X Y) (F X &rest (assign Q (+ Y 1) (list Y Q)))) + + (G X Y) + )"} + .to_string(); + + let res = run_string(&prog, &"(5 7)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "(5 7 8)"); +} + #[test] fn test_repl_tail_let() { assert_eq!( diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 032619a9d..ed0d311e9 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,2 +1,3 @@ mod classic; mod compiler; +mod util; diff --git a/src/tests/util.rs b/src/tests/util.rs new file mode 100644 index 000000000..5585a2ba0 --- /dev/null +++ b/src/tests/util.rs @@ -0,0 +1,96 @@ +use crate::util::toposort; +use std::collections::HashSet; + +#[derive(Debug, Clone)] +struct TopoSortCheckItem { + needs: HashSet, + has: HashSet, +} + +impl TopoSortCheckItem { + pub fn new(needs_s: &[&str], has_s: &[&str]) -> Self { + let mut needs: HashSet = HashSet::new(); + let mut has: HashSet = HashSet::new(); + for n in needs_s.iter() { + needs.insert(n.to_string()); + } + for h in has_s.iter() { + has.insert(h.to_string()); + } + TopoSortCheckItem { needs, has } + } +} + +// Given +// +// A B -> X +// X Y -> Z +// A W -> Y +// [] -> A +// [] -> B +// B -> W +// +// We should get something like this: +// +// [] -> A +// [] -> B +// B -> W +// A B -> X +// A W -> Y +// X Y -> Z +// +#[test] +fn test_topo_sort_0() { + let t = |n, h| TopoSortCheckItem::new(n, h); + let items = vec![ + t(&["A", "B"], &["X"]), + t(&["X", "Y"], &["Z"]), + t(&["A", "W"], &["Y"]), + t(&[], &["A"]), + t(&[], &["B"]), + t(&["B"], &["W"]), + ]; + let result = toposort( + &items, + true, + |_p, n: &TopoSortCheckItem| Ok(n.needs.clone()), + |h| h.has.clone(), + ) + .expect("no deadlocks in this data"); + + for (i, item) in result.iter().enumerate() { + let have_item = &items[item.index]; + for j in 0..i { + let item_to_check = &result[j]; + let item_to_check_for_dependencies_on_have = &items[item_to_check.index]; + // item_to_check_for_dependencies is an item occurring prior to + // have_item in the sorted output. + // If its 'needs' has anything in have_item's 'has', then we failed. + let mut intersection = item_to_check_for_dependencies_on_have + .needs + .intersection(&have_item.has); + assert!(intersection.next().is_none()); + } + } +} + +#[test] +fn test_topo_sort_1() { + let t = |n, h| TopoSortCheckItem::new(n, h); + let items = vec![ + t(&["A", "B"], &["X"]), + t(&["X", "Y"], &["Z"]), + t(&["A", "W"], &["Y"]), + t(&[], &["A"]), + t(&["Z"], &["B"]), + t(&["B"], &["W"]), + ]; + let result = toposort( + &items, + true, + |_p, n: &TopoSortCheckItem| Ok(n.needs.clone()), + |h| h.has.clone(), + ); + + assert!(result.is_err()); +} diff --git a/src/util/mod.rs b/src/util/mod.rs index 279ecb0d6..51943649f 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,4 +1,6 @@ use num_bigint::BigInt; +use std::collections::HashSet; +use std::mem::swap; use unicode_segmentation::UnicodeSegmentation; pub type Number = BigInt; @@ -44,6 +46,93 @@ pub fn collapse(r: Result) -> A { } } +#[derive(Debug, Clone)] +pub struct TopoSortItem { + pub index: usize, + pub needs: HashSet, + pub has: HashSet, +} + +// F: tells whether t2 includes t1. +pub fn toposort( + list: &[T], + deadlock: E, + needs: Needs, + has: Has, +) -> Result>, E> +where + Needs: Fn(&HashSet, &T) -> Result, E>, + Has: Fn(&T) -> HashSet, + K: std::cmp::Eq, + K: std::hash::Hash, + K: Clone, +{ + let mut possible = HashSet::new(); + let mut done = HashSet::new(); + let mut items: Vec> = list + .iter() + .enumerate() + .map(|(i, item)| TopoSortItem { + index: i, + needs: HashSet::new(), + has: has(item), + }) + .collect(); + let mut finished_idx = 0; + + // Determine what's defined in these bindings. + for (_, item) in items.iter().enumerate() { + for new_item in item.has.iter() { + possible.insert(new_item.clone()); + } + } + + // Set needs based on possible. We may fail. + for i in 0..items.len() { + items[i].needs = needs(&possible, &list[i])?; + } + + while finished_idx < items.len() { + // Find things with no new dependencies. + let move_to_front: Vec<(usize, TopoSortItem)> = items + .iter() + .enumerate() + .skip(finished_idx) + .filter(|(_, item)| item.needs.is_subset(&done)) + .map(|(i, item)| (i, item.clone())) + .collect(); + + if move_to_front.is_empty() { + // Circular dependency somewhere. + return Err(deadlock); + } + + // Swap items into place earlier in the list. + for (idx, _tomove) in move_to_front.iter() { + if *idx != finished_idx { + let mut tmp = items[*idx].clone(); + swap(&mut tmp, &mut items[finished_idx]); + items[*idx] = tmp; + } + + // Add new 'has' items to done. + let mut tmp = HashSet::new(); + for u in done.union(&items[finished_idx].has) { + tmp.insert(u.clone()); + } + let intersection = tmp.intersection(&possible); + done.clear(); + for i in intersection { + done.insert(i.clone()); + } + + finished_idx += 1; + } + } + + Ok(items) +} + pub trait ErrInto { fn err_into(self) -> D; } diff --git a/support/install_deps.sh b/support/install_deps.sh new file mode 100755 index 000000000..ebc1a11a0 --- /dev/null +++ b/support/install_deps.sh @@ -0,0 +1,24 @@ +#!/bin/bash -x + +# This script is called from $GIT_ROOT/.github/workflows/build-test.yml +# This script is called while in $GIT_ROOT/chia-blockchain of clvm_tools_rs + +. ./venv/bin/activate + +python -m pip install --upgrade pip +python -m pip uninstall clvm clvm_rs clvm_tools clvm_tools_rs + +git clone https://github.com/Chia-Network/clvm.git --branch=main --single-branch +python -m pip install ./clvm + +echo "installing clvm_rs via pip" +pip install clvm_rs + +echo "installing clvm_tools for clvm tests" + +# Ensure clvm_tools is installed from its own repo. +git clone https://github.com/Chia-Network/clvm_tools.git --branch=main --single-branch +python -m pip install ./clvm_tools + +# Install clvm_tools_rs from the directory above. +python -m pip install .. diff --git a/support/recompile_check.py.use-deployed-hash-list.diff b/support/recompile_check.py.use-deployed-hash-list.diff new file mode 100644 index 000000000..752262468 --- /dev/null +++ b/support/recompile_check.py.use-deployed-hash-list.diff @@ -0,0 +1,15 @@ +diff --git a/support/recompile_check.py b/support/recompile_check.py +index c991198e..999896b6 100644 +--- a/support/recompile_check.py ++++ b/support/recompile_check.py +@@ -66,6 +66,10 @@ recompile_list = [ + gentest('test_multiple_generator_input_arguments.clsp') + ] + ++here = Path(__file__).parent.resolve() ++root = here.parent ++hashes_path = root.joinpath("chia/wallet/puzzles/deployed_puzzle_hashes.json") ++ + for recompile_entry in recompile_list: + if 'dirname' in recompile_entry and 'fname' in recompile_entry: + dirname = recompile_entry['dirname'] diff --git a/support/test-game-referee.sh b/support/test-game-referee.sh new file mode 100755 index 000000000..31e28a93a --- /dev/null +++ b/support/test-game-referee.sh @@ -0,0 +1,16 @@ +#!/bin/bash -x + +if [ "x$1" = x ] ; then + echo "usage: test-game-referee.sh [game-referee-version]" + exit 1 +fi + +REF_SUBDIR="$1" + +python -m pip install --upgrade pip +python -m pip install chia_rs==0.2.5 +python -m pip install clvm_tools +python -m pip install pytest + +export PYTHONPATH=$PWD/resources/tests:.:$PYTHONPATH +(cd "${REF_SUBDIR}" && pytest -s .) diff --git a/support/verify_compiler_version.sh b/support/verify_compiler_version.sh new file mode 100755 index 000000000..7efbbdb75 --- /dev/null +++ b/support/verify_compiler_version.sh @@ -0,0 +1,22 @@ +#!/bin/bash -x + +if [[ $# -ne 1 ]]; then + echo "Illegal number of parameters" >&2 + echo "Usage: $0 " >&2 + exit 2 +fi + +pip_installed_version=$(pip list | grep clvm_tools_rs | awk '{print $2}') +python_import_version=$(python -c 'import clvm_tools_rs; print(clvm_tools_rs.get_version())') + +expected_version="$1" + +if [ "$expected_version" == "$pip_installed_version" ] && [ "$expected_version" == "$python_import_version" ]; then + exit 0 +else + echo "clvm_tools_rs VERSIONS does not match expected version" + echo "PIP INSTALLED VERSION: $pip_installed_version" + echo "PYTHON IMPORTED VERSION: $python_import_version" + echo "EXPECTED VERSION: $expected_version" + exit 1 +fi diff --git a/wasm/Cargo.lock b/wasm/Cargo.lock index e6087b96a..63de4da73 100644 --- a/wasm/Cargo.lock +++ b/wasm/Cargo.lock @@ -117,7 +117,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clvm_tools_rs" -version = "0.1.34" +version = "0.1.36" dependencies = [ "binascii", "bls12_381", @@ -148,20 +148,22 @@ dependencies = [ [[package]] name = "clvm_tools_wasm" -version = "0.1.34" +version = "0.1.36" dependencies = [ "clvm_tools_rs", "clvmr", "js-sys", + "num-bigint", + "num-traits", "wasm-bindgen", "wasm-bindgen-test", ] [[package]] name = "clvmr" -version = "0.2.7" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2890f01537f1be43d2767ae71bbba0d0b3543dbb1ee892092d0ed4d913227fc" +checksum = "9cd344b6dc76235f446025fe9ebe54aa6131e2e59acb49e16be48a3bb3492491" dependencies = [ "bls12_381", "getrandom", diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml index 4388b2dc0..b37b03e44 100644 --- a/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clvm_tools_wasm" -version = "0.1.34" +version = "0.1.36" edition = "2018" authors = ["Art Yerkes "] description = "tools for working with chialisp language; compiler, repl, python and wasm bindings" @@ -18,7 +18,9 @@ path = "src/mod.rs" [dependencies] clvm_tools_rs = { path= "..", features = [] } -clvmr = { version = "0.2.5", features = ["pre-eval"] } +clvmr = { version = "0.3.0", features = ["pre-eval"] } wasm-bindgen = "=0.2.83" wasm-bindgen-test = "=0.3.25" js-sys = "0.3.60" +num-bigint = "0.4.0" +num-traits = "0.2.15" diff --git a/wasm/README.md b/wasm/README.md index a8af1335d..d73c2b4c6 100644 --- a/wasm/README.md +++ b/wasm/README.md @@ -30,3 +30,118 @@ Prerequisite: # Make sure you're at /wasm node ./tests/index.js ``` + +Program +=== + +Program is exported by ```clvm_tools_rs``` and contains a ```to``` function +among a few others. Its use is very like Program.to in the python code and +similar to chiaminejp's ```clvm_tools``` library. It produces a value that +can be used together with other such values, can be curried (and uncurried) +converted to the hex representation and run. + +```Program.to(javascript_value)``` + +Converts javascript values to SExp objects which can be used together and run +as CLVM programs or used as program arguments. This conversion follows simple +conventions that were established in ```clvm_tools```. + +- There's a tuple object returned by the ```t``` function (2 arguments) which +produces a cons. + +- javascript arrays are treated as linear proper lists. Each element appears +as the first of a cons with the rest of the converted list as its tail. The +list is terminated by a nil. + +- an object which has a serialize method treats the result of ```o.serialize()``` +as an array-like object which specifies the byte values of the object's atom +representation. This covers bls primitives such as G1Element and G2Element. + +- javascript numbers, bignums, strings and bools are treated as atoms. + +- javascript objects which contain an array-like ```pair``` member are treated +the same as tuple objects above. + +```Program.from_hex(hex_str)``` + +Converts a string of pairs of hex digits into the CLVM deserialized form of the +object. + +```Program.null()``` + +Returns a null object. + +The returned objects have these methods: + +SExp methods +=== + +```SExp.toString()``` + +Convert the object to its hex representation. + +```SExp.as_pair()``` + +If it is a cons, return a tuple-compatible object containing a ```pair``` array +with 2 elements, otherwise null. + +```SExp.listp()``` + +Return true if the object is a cons. + +```SExp.nullp()``` + +Return true if the object is falsey. + +```SExp.as_int()``` + +Returns a javascript number that fits within the 32-bit integers representing the object's atom value, or throw. + +```SExp.as_bigint()``` + +Returns a javascript big number representing the value of the given atom or throw. + +```SExp.first()``` + +If the object is a cons, return its first or left component, or throw if not. + +```SExp.rest()``` + +If the object is a cons, return its rest or right component, or throw if not. + +```SExp.cons(other)``` + +Creates an SExp which is a cons of this sexp and other. + +```SExp.run(env)``` + +Runs the indicated SExp as a program with the given environment. + +```SExp.as_bin()``` + +Serialize the object into an array of byte values. + +```SExp.list_len()``` + +Give the number of conses one needs to traverse until reaching a non-cons rest. +For a proper list, this gives the list's length. + +```SExp.as_javascript()``` + +Return a javascript value that allows the given SExp to be inspected via +javascript. + +```SExp.curry(a, b, c ...)``` + +Given a number of positional arguments, build a curried application that provides +values for the left arguments of some runnable CLVM code, giving code that can +be correctly called with fewer arguments. This is common for providing values to +the upper case parameters of chialisp programs, such as coin puzzles. + +```SExp.uncurry(program) -> [inner_program, [args...]]``` +```SExp.uncurry_error(program)``` + +Uncurry returns an array with the inner program and the retrievable arguments +separated out, or the original program and null. uncurry_error throws instead +of returning a value if the object wasn't a curried program. + diff --git a/wasm/src/api.rs b/wasm/src/api.rs index 36f2db93e..333057018 100644 --- a/wasm/src/api.rs +++ b/wasm/src/api.rs @@ -34,6 +34,7 @@ use crate::jsval::{ btreemap_to_object, get_property, js_object_from_sexp, js_pair, object_to_value, read_string_to_string_map, sexp_from_js_object, }; +use crate::objects::Program; #[cfg(feature = "wee_alloc")] #[global_allocator] @@ -61,7 +62,7 @@ thread_local! { }; } -fn get_next_id() -> i32 { +pub fn get_next_id() -> i32 { NEXT_ID.with(|n| n.fetch_add(1, Ordering::SeqCst) as i32) } @@ -96,11 +97,8 @@ where runcell.replace_with(|coll| { let mut work_collection = HashMap::new(); swap(coll, &mut work_collection); - match work_collection.get_mut(&this_id) { - Some(r_ref) => { - result = f(r_ref); - } - _ => {} + if let Some(r_ref) = work_collection.get_mut(&this_id) { + result = f(r_ref); } work_collection }); @@ -108,22 +106,22 @@ where result } -fn create_clvm_runner_err(error: String) -> JsValue { +pub fn create_clvm_runner_err(error: String) -> JsValue { let array = js_sys::Array::new(); array.set( 0, js_pair(JsValue::from_str("error"), JsValue::from_str(&error)), ); - return object_to_value(&js_sys::Object::from_entries(&array).unwrap()); + object_to_value(&js_sys::Object::from_entries(&array).unwrap()) } fn create_clvm_runner_run_failure(err: &RunFailure) -> JsValue { match err { RunFailure::RunErr(l, e) => { - return create_clvm_runner_err(format!("{}: Error {}", l.to_string(), e)); + create_clvm_runner_err(format!("{}: Error {}", l, e)) } RunFailure::RunExn(l, e) => { - return create_clvm_runner_err(format!("{}: Exn {}", l.to_string(), e.to_string())) + create_clvm_runner_err(format!("{}: Exn {}", l, e)) } } } @@ -131,7 +129,7 @@ fn create_clvm_runner_run_failure(err: &RunFailure) -> JsValue { fn create_clvm_compile_failure(err: &CompileErr) -> JsValue { match err { CompileErr(l, e) => { - return create_clvm_runner_err(format!("{}: Error {}", l.to_string(), e)); + create_clvm_runner_err(format!("{}: Error {}", l, e)) } } } @@ -146,7 +144,7 @@ impl CldbSingleBespokeOverride for JsBespokeOverride { // When the user returns, try to convert the result back to sexp. fn get_override(&self, env: Rc) -> Result, RunFailure> { let args = js_sys::Array::new(); - args.set(0, js_object_from_sexp(env.clone())); + args.set(0, js_object_from_sexp(env.clone()).map_err(|_| RunFailure::RunErr(env.loc(), "error converting override value".to_string()))?); self.fun .apply(&JsValue::null(), &args) .map_err(|e| { @@ -158,7 +156,7 @@ impl CldbSingleBespokeOverride for JsBespokeOverride { }) .and_then(|v| { sexp_from_js_object(env.loc(), &v) - .map(|s| Ok(s)) + .map(Ok) .unwrap_or_else(|| { Err(RunFailure::RunErr( env.loc(), @@ -182,8 +180,8 @@ pub fn create_clvm_runner( ) -> JsValue { let mut allocator = Allocator::new(); let runner = Rc::new(DefaultProgramRunner::new()); - let args_srcloc = Srcloc::start(&"*args*".to_string()); - let prog_srcloc = Srcloc::start(&"*program*".to_string()); + let args_srcloc = Srcloc::start("*args*"); + let prog_srcloc = Srcloc::start("*program*"); let mut prim_map = HashMap::new(); let mut override_funs: HashMap> = HashMap::new(); @@ -207,14 +205,11 @@ pub fn create_clvm_runner( } }; - for ent in js_sys::Object::keys(&overrides).values() { + for ent in js_sys::Object::keys(overrides).values() { let key = ent.unwrap().as_string().unwrap(); - let val = get_property(&overrides, &key).unwrap(); - match val.dyn_ref::() { - Some(f) => { - override_funs.insert(key, Box::new(JsBespokeOverride { fun: f.clone() })); - } - _ => {} + let val = get_property(overrides, &key).unwrap(); + if let Some(f) = val.dyn_ref::() { + override_funs.insert(key, Box::new(JsBespokeOverride { fun: f.clone() })); } } @@ -246,15 +241,15 @@ pub fn create_clvm_runner( let this_id = get_next_id(); insert_runner(this_id, JsRunStep { allocator, cldbrun }); - return JsValue::from(this_id); + JsValue::from(this_id) } #[wasm_bindgen] pub fn final_value(runner: i32) -> JsValue { with_runner(runner, |r| { - r.cldbrun.final_result().map(|v| js_object_from_sexp(v)) + r.cldbrun.final_result().map(|v| js_object_from_sexp(v).unwrap_or_else(|e| e)) }) - .unwrap_or_else(|| JsValue::null()) + .unwrap_or_else(JsValue::null) } #[wasm_bindgen] @@ -273,7 +268,7 @@ pub fn run_step(runner: i32) -> JsValue { r.cldbrun.step(&mut r.allocator) }) .map(|result_hash| btreemap_to_object(result_hash.iter())) - .unwrap_or_else(|| JsValue::null()) + .unwrap_or_else(JsValue::null) } fn make_compile_output(result_stream: &Stream, symbol_table: &HashMap) -> JsValue { @@ -284,10 +279,8 @@ fn make_compile_output(result_stream: &Stream, symbol_table: &HashMap JsValue { let mut allocator = Allocator::new(); - let loc = Srcloc::start(&"*js*".to_string()); + let loc = Srcloc::start("*js*"); let symbol_table = match read_string_to_string_map(symbol_table_js) { Ok(s) => s, Err(e) => { @@ -386,7 +379,7 @@ pub fn compose_run_function( }, Ok(x) => x, }; - + let function_path = match path_to_function(main_env.1.clone(), &hash_bytes.data().clone()) { Some(p) => p, _ => { @@ -416,7 +409,7 @@ pub fn compose_run_function( #[wasm_bindgen] pub fn create_repl() -> i32 { let allocator = Allocator::new(); - let opts = Rc::new(DefaultCompilerOpts::new(&"*repl*".to_string())); + let opts = Rc::new(DefaultCompilerOpts::new("*repl*")); let runner = Rc::new(DefaultProgramRunner::new()); let repl = Repl::new(opts, runner.clone()); let new_id = get_next_id(); @@ -469,12 +462,12 @@ pub fn repl_run_string(repl_id: i32, input: String) -> JsValue { r.process_line(a, input) } else { Err(CompileErr( - Srcloc::start(&"*repl*".to_string()), + Srcloc::start("*repl*"), "no such repl".to_string(), )) } }) - .map(|v| v.map(|v| js_object_from_sexp(v.to_sexp()))) + .map(|v| v.map(|v| js_object_from_sexp(v.to_sexp()).unwrap_or_else(|e| e))) .unwrap_or_else(|e| { Some(create_clvm_runner_err(format!( "{}: {}", @@ -482,13 +475,25 @@ pub fn repl_run_string(repl_id: i32, input: String) -> JsValue { e.1 ))) }) - .unwrap_or_else(|| JsValue::null()) + .unwrap_or_else(JsValue::null) } #[wasm_bindgen] pub fn sexp_to_string(v: &JsValue) -> JsValue { - let loc = Srcloc::start(&"*val*".to_string()); + let loc = Srcloc::start("*val*"); + sexp_from_js_object(loc, v) .map(|s| JsValue::from_str(&s.to_string())) .unwrap_or_else(|| create_clvm_runner_err("unable to convert to value".to_string())) } + +#[wasm_bindgen] +pub fn h(v: String) -> Result, JsValue> { + let hex_data = Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex(v))).map_err(|_| js_sys::JsString::from("bad hex input"))?; + Ok(hex_data.data().clone()) +} + +#[wasm_bindgen] +pub fn t(a: &JsValue, b: &JsValue) -> Result { + Program::as_pair_internal(&Program::cons_internal(&Program::to(a)?, &Program::to(b)?)?) +} diff --git a/wasm/src/jsval.rs b/wasm/src/jsval.rs index 3ca5ed42d..0b9a65e13 100644 --- a/wasm/src/jsval.rs +++ b/wasm/src/jsval.rs @@ -1,8 +1,13 @@ use js_sys; use js_sys::JSON::stringify; -use js_sys::{Array, BigInt, Object}; +use js_sys::{Array, BigInt, Object, Reflect}; +use wasm_bindgen::JsCast; + +use num_bigint::ToBigInt; + use std::borrow::Borrow; use std::collections::HashMap; +use std::convert::TryFrom; use std::rc::Rc; use std::str::FromStr; @@ -13,6 +18,9 @@ use clvm_tools_rs::util::Number; use wasm_bindgen::prelude::*; +use crate::api::t; +use crate::objects::{find_cached_sexp, js_cache_value_from_js}; + pub fn array_to_value(v: Array) -> JsValue { let jref: &JsValue = v.as_ref(); jref.clone() @@ -30,77 +38,27 @@ pub fn js_pair(a: JsValue, b: JsValue) -> JsValue { array_to_value(pair_array) } -pub fn js_from_location(l: Srcloc) -> JsValue { - let loc_array = Array::new(); - let file_copy: &String = l.file.borrow(); - loc_array.set( - 0, - js_pair(JsValue::from_str("file"), JsValue::from_str(&file_copy)), - ); - loc_array.set( - 1, - js_pair(JsValue::from_str("line"), JsValue::from_f64(l.line as f64)), - ); - loc_array.set( - 2, - js_pair(JsValue::from_str("col"), JsValue::from_f64(l.col as f64)), - ); - match l.until { - Some(u) => { - let til_array = Array::new(); - til_array.set( - 0, - js_pair(JsValue::from_str("line"), JsValue::from_f64(u.line as f64)), - ); - til_array.set( - 1, - js_pair(JsValue::from_str("col"), JsValue::from_f64(u.col as f64)), - ); - loc_array.set( - 3, - object_to_value(Object::from_entries(&til_array).as_ref().unwrap()), - ); - } - _ => {} - } - object_to_value(Object::from_entries(&loc_array).as_ref().unwrap()) -} - -pub fn js_object_from_sexp(v: Rc) -> JsValue { +pub fn js_object_from_sexp(v: Rc) -> Result { match v.borrow() { - SExp::Nil(_) => JsValue::null(), - SExp::Integer(_, i) => JsValue::bigint_from_str(&i.to_string()), + SExp::Nil(_) => Ok(JsValue::null()), + SExp::Integer(_, i) => Ok(JsValue::bigint_from_str(&i.to_string())), SExp::QuotedString(_, _, q) => { - JsValue::from_str(&Bytes::new(Some(BytesFromType::Raw(q.clone()))).decode()) + Ok(JsValue::from_str(&Bytes::new(Some(BytesFromType::Raw(q.clone()))).decode())) } SExp::Atom(_, q) => { - JsValue::from_str(&Bytes::new(Some(BytesFromType::Raw(q.clone()))).decode()) + Ok(JsValue::from_str(&Bytes::new(Some(BytesFromType::Raw(q.clone()))).decode())) } - SExp::Cons(l, a, b) => v - .proper_list() - .map(|lst| { + SExp::Cons(_, a, b) => { + if let Some(lst) = v.proper_list() { let array = Array::new(); for i in 0..lst.len() { - array.set(i as u32, js_object_from_sexp(Rc::new(lst[i].clone()))); + array.set(i as u32, js_object_from_sexp(Rc::new(lst[i].clone())).unwrap_or_else(|e| e)); } - array_to_value(array) - }) - .unwrap_or_else(|| { - let array = Array::new(); - array.set( - 0, - js_pair(JsValue::from_str("location"), js_from_location(l.clone())), - ); - let pair: JsValue = js_pair( - JsValue::from_str("pair"), - js_pair( - js_object_from_sexp(a.clone()), - js_object_from_sexp(b.clone()), - ), - ); - array.set(1, pair); - object_to_value(&Object::from_entries(&array).unwrap()) - }), + Ok(array_to_value(array)) + } else { + t(&js_object_from_sexp(a.clone())?, &js_object_from_sexp(b.clone())?) + } + } } } @@ -151,14 +109,60 @@ fn location(o: &Object) -> Option { }) } +pub fn detect_serializable(loc: &Srcloc, v: &JsValue) -> Option> { + let serialize_key = JsValue::from_str("serialize"); + js_sys::Reflect::get(v, &serialize_key).ok().and_then(|serialize| { + Reflect::apply(serialize.unchecked_ref(), v, &js_sys::Array::new()).ok().and_then(|array| { + Array::try_from(array).ok().and_then(|array| { + let mut bytes_array: Vec = vec![]; + for item in array.iter() { + if let Some(n) = item.as_f64() { + if n < 0.0 || n > 255.0 { + return None; + } + bytes_array.push(n as u8); + } else { + return None; + } + } + + return Some(Rc::new(SExp::QuotedString(loc.clone(), b'x', bytes_array))); + }) + }) + }) +} + +pub fn detect_convertible(v: &JsValue) -> Result, JsValue> { + let convert_key = JsValue::from_str("to_program"); + let to_program = js_sys::Reflect::get(v, &convert_key)?; + let call_args = js_sys::Array::new(); + call_args.push(v); + let call_result = Reflect::apply(to_program.unchecked_ref(), v, &call_args)?; + let cacheval = js_cache_value_from_js(&call_result)?; + let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; + Ok(cached.modern.clone()) +} + pub fn sexp_from_js_object(sstart: Srcloc, v: &JsValue) -> Option> { - if v.is_bigint() { + // Already converted value. + if let Ok(res) = js_cache_value_from_js(v) { + find_cached_sexp(res.entry, &res.content).map(|result| { + result.modern.clone() + }).ok() + } else if v.is_bigint() { BigInt::new(v) .ok() .and_then(|v| v.to_string(10).ok()) .and_then(|v| v.as_string()) .and_then(|v| v.parse::().ok()) .map(|x| Rc::new(SExp::Integer(sstart.clone(), x))) + } else if let Some(fval) = v.as_f64() { + (fval as i64).to_bigint() + .map(|x| Rc::new(SExp::Integer(sstart.clone(), x))) + } else if let Some(g1_bytes) = detect_serializable(&sstart, v) { + Some(g1_bytes) + } else if let Some(converted) = detect_convertible(v).ok() { + Some(converted) } else if Array::is_array(v) { let a = Array::from(v); let mut result_value = Rc::new(SExp::Nil(Srcloc::start(&"*js*".to_string()))); diff --git a/wasm/src/mod.rs b/wasm/src/mod.rs index cffabd1ef..04e57bbc2 100644 --- a/wasm/src/mod.rs +++ b/wasm/src/mod.rs @@ -1,2 +1,3 @@ pub mod api; mod jsval; +pub mod objects; diff --git a/wasm/src/objects.rs b/wasm/src/objects.rs new file mode 100644 index 000000000..3e13b3421 --- /dev/null +++ b/wasm/src/objects.rs @@ -0,0 +1,771 @@ +use js_sys; +use js_sys::{Array, JsString, Reflect}; +use num_traits::cast::ToPrimitive; +use std::borrow::Borrow; +use std::cell::{RefCell, RefMut}; +use std::collections::HashMap; +use std::rc::Rc; +use wasm_bindgen::prelude::*; + +use clvmr::Allocator; +use clvm_tools_rs::classic::clvm::__type_compatibility__::{Bytes, Stream, UnvalidatedBytesFromType, bi_one}; +use clvm_tools_rs::classic::clvm::serialize::{SimpleCreateCLVMObject, sexp_to_stream, sexp_from_stream}; +use clvm_tools_rs::classic::clvm_tools::stages::stage_0::{DefaultProgramRunner, TRunProgram}; +use clvm_tools_rs::compiler::clvm::{convert_from_clvm_rs, convert_to_clvm_rs, sha256tree, truthy}; +use clvm_tools_rs::compiler::prims::{primapply, primcons, primquote}; +use clvm_tools_rs::compiler::sexp::SExp; +use clvm_tools_rs::compiler::srcloc::Srcloc; + +use crate::api::{create_clvm_runner_err, get_next_id}; +use crate::jsval::{js_object_from_sexp, sexp_from_js_object}; + +const DEFAULT_CACHE_ENTRIES: usize = 1024; + +struct FunctionWrapperDesc { + export_name: &'static str, + member_name: &'static str, + varargs: bool, +} + +#[derive(Clone)] +pub struct ObjectCacheMember { + pub modern: Rc, +} + +struct ObjectCache { + cache_data: HashMap, + cache_order: Vec, + cache_length: usize, +} + +pub struct JsCacheValue { + pub entry: i32, + pub content: String +} + +pub fn js_cache_value_from_js(jsval: &JsValue) -> Result { + let entry = js_sys::Reflect::get( + jsval, + &JsString::from("id") + )?.as_f64().ok_or(JsString::from("id was not a number"))?; + let content = js_sys::Reflect::get( + jsval, + &JsString::from("content") + )?.as_string().ok_or(JsString::from("content was not a string"))?; + + Ok(JsCacheValue { entry: entry as i32, content }) +} + +impl Default for ObjectCache { + fn default() -> Self { + ObjectCache { + cache_data: HashMap::default(), + cache_order: Vec::default(), + cache_length: DEFAULT_CACHE_ENTRIES, + } + } +} + +impl ObjectCache { + fn create_or_update_cache_entry(&mut self, id: i32, cache_member: ObjectCacheMember) { + if id < 0 { + // Special nil handling. + return; + } + + if self.cache_order.len() > self.cache_length { + self.cache_data.remove(&self.cache_order[0]); + self.cache_order.remove(0); + } + + self.cache_data.insert(id, cache_member); + self.cache_order.push(id); + } + + fn create_entry_from_sexp(&mut self, id: i32, sexp: Rc) -> Result { + let mut allocator = Allocator::new(); + let node = convert_to_clvm_rs( + &mut allocator, + sexp.clone() + ).map_err(|_| js_sys::JsString::from("could not convert to clvm"))?; + let mut stream = Stream::new(None); + sexp_to_stream(&mut allocator, node, &mut stream); + + self.create_or_update_cache_entry(id, ObjectCacheMember { + modern: sexp.clone(), + }); + + Ok(stream.get_value().hex()) + } + + fn find_or_create_entry_from_hex(&mut self, entry: i32, content: &str) -> Result { + if let Some(res) = self.cache_data.get(&entry) { + return Ok(res.clone()); + } + + let mut allocator = Allocator::new(); + let bytes_from_hex = Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex(content.to_string()))).map_err(|_| JsString::from("could not parse hex"))?; + let mut stream = Stream::new(Some(bytes_from_hex)); + let parsed = sexp_from_stream( + &mut allocator, + &mut stream, + Box::new(SimpleCreateCLVMObject {}) + ) + .map(|x| x.1) + .map_err(|_| JsString::from("could not parse sexp from hex"))?; + let srcloc = Srcloc::start("*var*"); + let modern = convert_from_clvm_rs( + &mut allocator, + srcloc, + parsed + ).map_err(|_| JsString::from("could not realize parsed sexp"))?; + + let cache_entry = ObjectCacheMember { + modern + }; + self.create_or_update_cache_entry(entry, cache_entry.clone()); + + Ok(cache_entry) + } +} + +static PROGRAM_FUNCTIONS: &[FunctionWrapperDesc] = &[ + FunctionWrapperDesc { + export_name: "toString", + member_name: "to_string_internal", + varargs: false, + }, + FunctionWrapperDesc { + export_name: "as_pair", + member_name: "as_pair_internal", + varargs: false, + }, + FunctionWrapperDesc { + export_name: "listp", + member_name: "listp_internal", + varargs: false, + }, + FunctionWrapperDesc { + export_name: "nullp", + member_name: "nullp_internal", + varargs: false, + }, + FunctionWrapperDesc { + export_name: "as_int", + member_name: "as_int_internal", + varargs: false, + }, + FunctionWrapperDesc { + export_name: "as_bigint", + member_name: "as_bigint_internal", + varargs: false, + }, + FunctionWrapperDesc { + export_name: "as_bin", + member_name: "as_bin_internal", + varargs: false, + }, + FunctionWrapperDesc { + export_name: "first", + member_name: "first_internal", + varargs: false, + }, + FunctionWrapperDesc { + export_name: "rest", + member_name: "rest_internal", + varargs: false, + }, + FunctionWrapperDesc { + export_name: "cons", + member_name: "cons_internal", + varargs: false, + }, + FunctionWrapperDesc { + export_name: "run", + member_name: "run_internal", + varargs: false, + }, + FunctionWrapperDesc { + export_name: "list_len", + member_name: "list_len_internal", + varargs: false, + }, + FunctionWrapperDesc { + export_name: "equal_to", + member_name: "equal_to_internal", + varargs: false, + }, + FunctionWrapperDesc { + export_name: "as_javascript", + member_name: "as_javascript_internal", + varargs: false, + }, + FunctionWrapperDesc { + export_name: "curry", + member_name: "curry_internal", + varargs: true, + }, + FunctionWrapperDesc { + export_name: "sha256tree", + member_name: "sha256tree_internal", + varargs: false, + }, + FunctionWrapperDesc { + export_name: "uncurry_error", + member_name: "uncurry_error_internal", + varargs: false, + }, + FunctionWrapperDesc { + export_name: "uncurry", + member_name: "uncurry_internal", + varargs: false, + }, +]; + +static TUPLE_FUNCTIONS: &[FunctionWrapperDesc] = &[ + FunctionWrapperDesc { + export_name: "to_program", + member_name: "tuple_to_program_internal", + varargs: false + }, +]; + +thread_local! { + static OBJECT_CACHE: RefCell = { + return RefCell::new(ObjectCache::default()); + }; + static PROGRAM_PROTOTYPE: RefCell> = RefCell::new(None); + static TUPLE_PROTOTYPE: RefCell> = RefCell::new(None); + static SRCLOC: Srcloc = Srcloc::start("*var*"); +} + +fn create_cached_sexp(id: i32, sexp: Rc) -> Result { + if !truthy(sexp.clone()) { + return Ok("80".to_string()); + } + OBJECT_CACHE.with(|ocache| { + let mut mut_object_cache_ref: RefMut = ocache.borrow_mut(); + mut_object_cache_ref.create_entry_from_sexp(id, sexp) + }) +} + +fn get_srcloc() -> Srcloc { + SRCLOC.with(|s| s.clone()) +} + +pub fn find_cached_sexp(entry: i32, content: &str) -> Result { + if content == "80" { + return Ok(ObjectCacheMember { + modern: Rc::new(SExp::Nil(get_srcloc())) + }); + } + + OBJECT_CACHE.with(|ocache| { + let mut mut_object_cache_ref: RefMut = ocache.borrow_mut(); + mut_object_cache_ref.find_or_create_entry_from_hex(entry, content) + }) +} + +// Strategy for Program objects. +// We'll provide a Program object that allows users to have something that +// acts js-y but conserves compute time when possible. +// +// The result object we'll give back contain a string representation of the +// program they're associated with but also a cache hint. If the cache object +// doesn't exist we'll re-parse the hex and re-cache it. +// +// The object is structured like this: +// +// {"cache-hint":33, "hex":"ff..."} +// +// Cache hints are never reused, and cleared when the counter transitions from +// low half to high half or vice versa. +// +// The object's prototype will include methods for Program, such as cons and call +// the real static methods of Program. +#[wasm_bindgen(inspectable)] +pub struct Program { } + +// Build prototype +fn get_program_prototype() -> Result { + // We've already built the program prototype object. + if let Some(pp) = PROGRAM_PROTOTYPE.with(|pp| pp.borrow().clone()) { + return Ok(pp); + } + + let prototype = js_sys::Object::new(); + + let program_self = js_sys::eval("Program")?; + for func_wrapper_desc in PROGRAM_FUNCTIONS.iter() { + let pass_on_args = + if func_wrapper_desc.varargs { + "[args]" + } else { + "args" + }; + let to_string_fun = js_sys::Function::new_with_args( + "", + &format!("const t = this; return function() {{ let args = Array.prototype.slice.call(arguments); let apply_args = {pass_on_args}; apply_args.unshift(this); return t.{}.apply(null, apply_args); }}", func_wrapper_desc.member_name) + ); + + let to_string_final = to_string_fun.call0(&program_self)?; + js_sys::Reflect::set( + &prototype, + &js_sys::JsString::from(func_wrapper_desc.export_name), + &to_string_final, + )?; + } + + PROGRAM_PROTOTYPE.with(|pp| { + pp.replace(Some(prototype.clone().into())); + }); + + Ok(prototype.into()) +} + +fn get_tuple_prototype() -> Result { + if let Some(pp) = TUPLE_PROTOTYPE.with(|pp| pp.borrow().clone()) { + return Ok(pp); + } + + let prototype = js_sys::Object::new(); + + let program_self = js_sys::eval("Program")?; + for func_wrapper_desc in TUPLE_FUNCTIONS.iter() { + let to_string_fun = js_sys::Function::new_with_args( + "", + &format!("const t = this; return function() {{ let args = Array.prototype.slice.call(arguments); args.unshift(this); return t.{}.apply(null, args); }}", func_wrapper_desc.member_name) + ); + + let to_string_final = to_string_fun.call0(&program_self)?; + js_sys::Reflect::set( + &prototype, + &js_sys::JsString::from(func_wrapper_desc.export_name), + &to_string_final, + )?; + } + + TUPLE_PROTOTYPE.with(|pp| { + pp.replace(Some(prototype.clone().into())); + }); + + Ok(prototype.into()) +} + +pub fn finish_new_object(id: i32, encoded_hex: &str) -> Result { + let prototype = get_program_prototype()?; + + let new_object = js_sys::Object::new(); + js_sys::Reflect::set_prototype_of( + &new_object, + &prototype + )?; + + js_sys::Reflect::set( + &new_object, + &js_sys::JsString::from("content"), + &js_sys::JsString::from(encoded_hex), + )?; + js_sys::Reflect::set( + &new_object, + &js_sys::JsString::from("id"), + &js_sys::Number::from(id), + )?; + + Ok(new_object.into()) +} + +// Return a vector of arguments if the given SExp is the expected operator +// and has the required number of arguments. +fn match_op(opcode: u8, expected_args: usize, opname: &str, program: Rc) -> Result>, JsValue> { + let plist = + if let Some(plist) = program.proper_list() { + plist + } else { + // Not a list so can't be an apply. + return Err(JsValue::from_str(&format!("program wasn't a list representing an {opname} op: {program}"))); + }; + + // Not the right length + if plist.len() != expected_args + 1 { + return Err(JsValue::from_str(&format!("program list wasn't a list of {} representing an {opname} op: {program}", expected_args + 1))); + } + + // Not an apply + if plist[0] != SExp::Atom(plist[0].loc(), vec![opcode]) { + return Err(JsValue::from_str("program isn't an {opname} op: {program}")); + } + + Ok(plist.into_iter().skip(1).map(Rc::new).collect()) +} + +fn cache_and_accumulate_arg(array: &Array, prog: Rc) -> Result<(), JsValue> { + let arg_id = get_next_id(); + let new_cached_arg = create_cached_sexp(arg_id, prog)?; + let arg_js = finish_new_object(arg_id, &new_cached_arg)?; + + array.push(&arg_js); + + Ok(()) +} + +#[wasm_bindgen] +impl Program { + #[wasm_bindgen] + pub fn to(input: &JsValue) -> Result { + let loc = get_srcloc(); + let sexp = sexp_from_js_object(loc, input).map(Ok).unwrap_or_else(|| Err(create_clvm_runner_err(format!("unable to convert to value"))))?; + + let new_id = get_next_id(); + + let encoded = create_cached_sexp(new_id, sexp)?; + + // Build the object + finish_new_object(new_id, &encoded) + } + + #[wasm_bindgen] + pub fn from_hex(input: &str) -> Result { + let new_id = get_next_id(); + let obj = finish_new_object(new_id, input)?; + Program::to(&obj) + } + + #[wasm_bindgen] + pub fn null() -> Result { + let new_id = get_next_id(); + let encoded = create_cached_sexp(new_id, Rc::new(SExp::Nil(get_srcloc())))?; + + finish_new_object(new_id, &encoded) + } + + #[wasm_bindgen] + pub fn sha256tree_internal(obj: &JsValue) -> Result, JsValue> { + let cacheval = js_cache_value_from_js(obj)?; + let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; + Ok(sha256tree(cached.modern.clone())) + } + + #[wasm_bindgen] + pub fn to_string_internal(obj: &JsValue) -> Result { + js_sys::Reflect::get( + obj, + &js_sys::JsString::from("content"), + ) + } + + #[wasm_bindgen] + pub fn as_pair_internal(obj: &JsValue) -> Result { + let prototype = get_tuple_prototype()?; + let cacheval = js_cache_value_from_js(obj)?; + let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; + + if let SExp::Cons(_, a, b) = cached.modern.borrow() { + let id_a = get_next_id(); + let new_cached_a = create_cached_sexp(id_a, a.clone())?; + let object_a = finish_new_object(id_a, &new_cached_a)?; + let id_b = get_next_id(); + let new_cached_b = create_cached_sexp(id_b, b.clone())?; + let object_b = finish_new_object(id_b, &new_cached_b)?; + + let result_value = Array::new(); + result_value.set(0, object_a); + result_value.set(1, object_b); + // Support reading as a classic clvm input. + Reflect::set( + &result_value, + &JsString::from("pair"), + &result_value, + )?; + Reflect::set_prototype_of( + &result_value, + &prototype + )?; + return Ok(result_value.into()); + } + + Ok(JsValue::null()) + } + + #[wasm_bindgen] + pub fn listp_internal(obj: &JsValue) -> Result { + let cacheval = js_cache_value_from_js(obj)?; + Ok(cacheval.content.starts_with("ff")) + } + + #[wasm_bindgen] + pub fn nullp_internal(obj: &JsValue) -> Result { + let cacheval = js_cache_value_from_js(obj)?; + Ok(cacheval.content == "80") + } + + #[wasm_bindgen] + pub fn as_int_internal(obj: &JsValue) -> Result { + let cacheval = js_cache_value_from_js(obj)?; + let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; + let number = cached.modern.get_number().map_err(|_| JsString::from("not a number"))?; + (number.to_i32()).ok_or(JsString::from("number out of range").into()) + } + + #[wasm_bindgen] + pub fn as_bigint_internal(obj: &JsValue) -> Result { + let cacheval = js_cache_value_from_js(obj)?; + let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; + let number = cached.modern.get_number().map_err(|_| JsString::from("not a number"))?; + let num_string = number.to_string(); + let num_str: &str = &num_string; + js_sys::BigInt::new(&JsString::from(num_str)).map_err(|_| JsString::from("couldn't construct bigint").into()) + } + + #[wasm_bindgen] + pub fn first_internal(obj: &JsValue) -> Result { + let cacheval = js_cache_value_from_js(obj)?; + let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; + if let SExp::Cons(_, a, _) = cached.modern.borrow() { + let id_a = get_next_id(); + let new_cached_a = create_cached_sexp(id_a, a.clone())?; + return finish_new_object(id_a, &new_cached_a); + } + + Err(JsString::from("not a cons").into()) + } + + #[wasm_bindgen] + pub fn rest_internal(obj: &JsValue) -> Result { + let cacheval = js_cache_value_from_js(obj)?; + let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; + if let SExp::Cons(_, _, a) = cached.modern.borrow() { + let id_a = get_next_id(); + let new_cached_a = create_cached_sexp(id_a, a.clone())?; + return finish_new_object(id_a, &new_cached_a); + } + + Err(JsString::from("not a cons").into()) + } + + #[wasm_bindgen] + pub fn cons_internal(obj: &JsValue, other: &JsValue) -> Result { + let cacheval = js_cache_value_from_js(obj)?; + let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; + + let other_val = js_cache_value_from_js(other)?; + let other_cache = find_cached_sexp(other_val.entry, &other_val.content)?; + + let new_id = get_next_id(); + let new_sexp = Rc::new(SExp::Cons(get_srcloc(), cached.modern.clone(), other_cache.modern.clone())); + let new_cached = create_cached_sexp(new_id, new_sexp)?; + finish_new_object(new_id, &new_cached) + } + + #[wasm_bindgen] + pub fn run_internal(obj: &JsValue, args: &JsValue) -> Result { + let progval = js_cache_value_from_js(obj)?; + let prog_cache = find_cached_sexp(progval.entry, &progval.content)?; + + let argval = js_cache_value_from_js(args)?; + let arg_cache = find_cached_sexp(argval.entry, &argval.content)?; + + let mut allocator = Allocator::new(); + let prog_classic = convert_to_clvm_rs( + &mut allocator, + prog_cache.modern.clone() + ).map_err(|_| { + let err: JsValue = JsString::from("error converting program").into(); + err + })?; + let arg_classic = convert_to_clvm_rs( + &mut allocator, + arg_cache.modern.clone() + ).map_err(|_| { + let err: JsValue = JsString::from("error converting args").into(); + err + })?; + + let runner = DefaultProgramRunner::default(); + let run_result = + runner.run_program( + &mut allocator, + prog_classic, + arg_classic, + None + ).map_err(|e| { + let err_str: &str = &e.1; + let err: JsValue = JsString::from(err_str).into(); + err + })?; + let modern_result = convert_from_clvm_rs( + &mut allocator, + get_srcloc(), + run_result.1 + ).map_err(|_| { + let err: JsValue = JsString::from("error converting result").into(); + err + })?; + let result_id = get_next_id(); + let new_cached_result = create_cached_sexp(result_id, modern_result)?; + let result_object = finish_new_object(result_id, &new_cached_result)?; + let cost_and_result_array = Array::new(); + cost_and_result_array.push(&JsValue::from_f64(run_result.0 as f64)); + cost_and_result_array.push(&result_object); + Ok(cost_and_result_array.into()) + } + + #[wasm_bindgen] + pub fn tuple_to_program_internal(obj: &JsValue) -> Result { + let a = js_sys::Reflect::get( + obj, + &JsString::from("0"), + )?; + let b = js_sys::Reflect::get( + obj, + &JsString::from("1"), + )?; + Program::cons_internal(&a, &b) + } + + #[wasm_bindgen] + pub fn as_bin_internal(obj: &JsValue) -> Result, JsValue> { + let convert = Reflect::get( + obj, + &JsString::from("content"), + )?.as_string().ok_or(JsString::from("content wasn't a hex string"))?; + let bytes = Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex(convert))).map_err(|_| JsString::from("could not convert to binary data"))?; + Ok(bytes.data().clone()) + } + + #[wasm_bindgen] + pub fn list_len_internal(obj: &JsValue) -> Result { + let cacheval = js_cache_value_from_js(obj)?; + let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; + let mut val_ref = cached.modern.clone(); + let mut count: i32 = 0; + while let SExp::Cons(_, _, b) = val_ref.borrow() { + val_ref = b.clone(); + count += 1; + } + Ok(count) + } + + #[wasm_bindgen] + pub fn equal_to_internal(a: &JsValue, b: &JsValue) -> Result { + let a_cacheval = js_cache_value_from_js(a)?; + let a_cached = find_cached_sexp(a_cacheval.entry, &a_cacheval.content)?; + let b_cacheval = js_cache_value_from_js(b)?; + let b_cached = find_cached_sexp(b_cacheval.entry, &b_cacheval.content)?; + // Short circuit address equality. + if Rc::as_ptr(&a_cached.modern) == Rc::as_ptr(&b_cached.modern) { + return Ok(true); + } + Ok(a_cached.modern == b_cached.modern) + } + + #[wasm_bindgen] + pub fn as_javascript_internal(obj: &JsValue) -> Result { + let cacheval = js_cache_value_from_js(obj)?; + let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; + js_object_from_sexp(cached.modern.clone()) + } + + // Ported from chia.types.blockchain_format.program in chia-blockchain. + // + // original comment: + // + // Replicates the curry function from clvm_tools, taking advantage of *args + // being a list. We iterate through args in reverse building the code to + // create a clvm list. + // + // Given arguments to a function addressable by the '1' reference in clvm + // + // fixed_args = 1 + // + // Each arg is prepended as fixed_args = (c (q . arg) fixed_args) + // + // The resulting argument list is interpreted with apply (2) + // + // (2 (1 . self) rest) + // + // Resulting in a function which places its own arguments after those + // curried in in the form of a proper list. + #[wasm_bindgen] + pub fn curry_internal(obj: &JsValue, args: Vec) -> Result { + let program_val = Program::to(obj)?; + let cacheval = js_cache_value_from_js(&program_val)?; + let program = find_cached_sexp(cacheval.entry, &cacheval.content)?; + let mut fixed_args = Rc::new(SExp::Integer(get_srcloc(), bi_one())); + + for a in args.iter().rev() { + let argval = Program::to(a)?; + let a_cacheval = js_cache_value_from_js(&argval)?; + let a_cached = find_cached_sexp(a_cacheval.entry, &a_cacheval.content)?; + fixed_args = Rc::new(primcons( + get_srcloc(), + Rc::new(primquote(get_srcloc(), a_cached.modern.clone())), + fixed_args + )); + } + + let result = Rc::new(primapply( + get_srcloc(), + Rc::new(primquote(get_srcloc(), program.modern.clone())), + fixed_args + )); + + let new_id = get_next_id(); + let new_cached = create_cached_sexp(new_id, result)?; + finish_new_object(new_id, &new_cached) + } + + #[wasm_bindgen] + pub fn uncurry_error_internal(obj: &JsValue) -> Result { + let program_val = Program::to(obj)?; + let cacheval = js_cache_value_from_js(&program_val)?; + let program = find_cached_sexp(cacheval.entry, &cacheval.content)?; + + let apply_args = match_op(2, 2, "apply", program.modern.clone())?; + // Not used in code, but detects a quoted program. + let quoted_prog = match_op(1, 1, "quote", apply_args[0].clone())?; + + let retrieved_args = Array::new(); + let mut cons_expr = match_op(4, 2, "cons", apply_args[1].clone())?; + cache_and_accumulate_arg(&retrieved_args, cons_expr[0].clone())?; + let mut next_cons = cons_expr[1].clone(); + while matches!(next_cons.borrow(), SExp::Cons(_, _, _)) { + cons_expr = match_op(4, 2, "cons", next_cons)?; + + // Convert to the external js form and insert into cache so we can + // forego conversion if still cached. + cache_and_accumulate_arg(&retrieved_args, cons_expr[0].clone())?; + + // Move on to the tail that's being built. + next_cons = cons_expr[1].clone(); + } + + // Verify that we're at a 1 env ref. + let borrowed_next: &SExp = next_cons.borrow(); + if borrowed_next != &SExp::Atom(next_cons.loc(), vec![1]) { + return Err(JsValue::from_str("curry didn't end with 1 env ref")); + } + + // Make a cache slot for the program. + let mod_id = get_next_id(); + let new_cached_mod = create_cached_sexp(mod_id, quoted_prog[0].clone())?; + let mod_js = finish_new_object(mod_id, &new_cached_mod)?; + + let res = Array::new(); + res.push(&mod_js); + res.push(&retrieved_args); + Ok(res.into()) + } + + #[wasm_bindgen] + pub fn uncurry_internal(obj: &JsValue) -> JsValue { + if let Ok(res) = Program::uncurry_error_internal(obj) { + res + } else { + let res = Array::new(); + res.push(obj); + res.push(&JsValue::null()); + res.into() + } + } +} diff --git a/wasm/tests/clvm-tools-interface/.eslintignore b/wasm/tests/clvm-tools-interface/.eslintignore new file mode 100644 index 000000000..2c7ea48ea --- /dev/null +++ b/wasm/tests/clvm-tools-interface/.eslintignore @@ -0,0 +1,2 @@ +build/* +/**/*.d.ts \ No newline at end of file diff --git a/wasm/tests/clvm-tools-interface/.eslintrc.json b/wasm/tests/clvm-tools-interface/.eslintrc.json new file mode 100644 index 000000000..d614b0b2f --- /dev/null +++ b/wasm/tests/clvm-tools-interface/.eslintrc.json @@ -0,0 +1,31 @@ +{ + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module", + "ecmaFeatures": { + "modules": true, + "experimentalObjectRestSpread": true + } + }, + "plugins": ["@typescript-eslint"], + "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], + "rules": { + "comma-dangle": 0, + "no-unused-vars": "warn", + "no-unexpected-multiline": "warn", + "prefer-const": "warn", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-var-requires": "off" + }, + "settings": {}, + "env": { + "browser": true, + "node": true, + "jasmine": true, + "jest": true, + "es6": true + } +} diff --git a/wasm/tests/clvm-tools-interface/.gitignore b/wasm/tests/clvm-tools-interface/.gitignore new file mode 100644 index 000000000..a6b9b35fa --- /dev/null +++ b/wasm/tests/clvm-tools-interface/.gitignore @@ -0,0 +1,21 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local +.vscode + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/wasm/tests/clvm-tools-interface/.npmignore b/wasm/tests/clvm-tools-interface/.npmignore new file mode 100644 index 000000000..d36841e97 --- /dev/null +++ b/wasm/tests/clvm-tools-interface/.npmignore @@ -0,0 +1,36 @@ +# dependencies +/node_modules + +# testing +/tests +/coverage + +# docs +/docs + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local +/.github +/demo +.esdoc.json + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Development folders and files +public +src +scripts +config +.travis.yml +CHANGELOG.md +README.md +.eslintignore +.eslintrc.json +webpack.config.js +babel.config.js \ No newline at end of file diff --git a/wasm/tests/clvm-tools-interface/babel.config.js b/wasm/tests/clvm-tools-interface/babel.config.js new file mode 100644 index 000000000..f60764c10 --- /dev/null +++ b/wasm/tests/clvm-tools-interface/babel.config.js @@ -0,0 +1,7 @@ +module.exports = { + presets: [["@babel/env"]], + plugins: [ + ["@babel/plugin-proposal-class-properties"], + ["@babel/plugin-transform-typescript"], + ], +}; diff --git a/wasm/tests/clvm-tools-interface/content/p2_delegated_puzzle_or_hidden_puzzle.clvm.hex b/wasm/tests/clvm-tools-interface/content/p2_delegated_puzzle_or_hidden_puzzle.clvm.hex new file mode 100644 index 000000000..4d96fe6ce --- /dev/null +++ b/wasm/tests/clvm-tools-interface/content/p2_delegated_puzzle_or_hidden_puzzle.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ffff03ff0bffff01ff02ffff03ffff09ff05ffff1dff0bffff1effff0bff0bffff02ff06ffff04ff02ffff04ff17ff8080808080808080ffff01ff02ff17ff2f80ffff01ff088080ff0180ffff01ff04ffff04ff04ffff04ff05ffff04ffff02ff06ffff04ff02ffff04ff17ff80808080ff80808080ffff02ff17ff2f808080ff0180ffff04ffff01ff32ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 diff --git a/wasm/tests/clvm-tools-interface/package.json b/wasm/tests/clvm-tools-interface/package.json new file mode 100644 index 000000000..3fc737a5f --- /dev/null +++ b/wasm/tests/clvm-tools-interface/package.json @@ -0,0 +1,80 @@ +{ + "name": "clvm-tools-interface", + "version": "0.1.35", + "description": "Tests and extras for the clvm_tools_rs javascript interface", + "main": "build/index.js", + "types": "build/types/index.d.ts", + "scripts": { + "start": "webpack serve --config webpack.config.demo.js", + "build": "webpack && tsc", + "build:demo": "webpack --config webpack.config.demo.js", + "test": "jest", + "coverage": "npm run test -- --coverage", + "prepare": "npm run build", + "trypublish": "npm publish || true" + }, + "repository": { + "type": "git", + "url": "https://github.com/hodgef/ts-library-boilerplate-basic" + }, + "author": "Francisco Hodge (https://github.com/hodgef)", + "license": "MIT", + "bugs": { + "url": "https://github.com/hodgef/ts-library-boilerplate-basic/issues" + }, + "homepage": "https://github.com/hodgef/ts-library-boilerplate-basic", + "keywords": [ + "library", + "starter", + "es6" + ], + "devDependencies": { + "@babel/cli": "^7.22.9", + "@babel/core": "^7.22.10", + "@babel/plugin-proposal-class-properties": "^7.16.0", + "@babel/plugin-transform-typescript": "^7.22.10", + "@babel/polyfill": "^7.12.1", + "@babel/preset-env": "^7.22.10", + "@types/jest": "^29.5.3", + "@typescript-eslint/eslint-plugin": "^4.33.0", + "@typescript-eslint/parser": "^4.33.0", + "babel-eslint": "^10.1.0", + "babel-loader": "^9.1.3", + "babel-preset-minify": "^0.5.2", + "css-loader": "^6.8.1", + "css-minimizer-webpack-plugin": "^5.0.1", + "eslint": "^7.32.0", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.3", + "jest": "^29.6.2", + "mini-css-extract-plugin": "^2.7.6", + "style-loader": "^3.3.2", + "terser-webpack-plugin": "^5.3.9", + "typescript": "^4.9.5", + "url-loader": "^4.1.1", + "webpack": "^5.88.2", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "4.13.3" + }, + "jest": { + "moduleNameMapper": { + "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/scripts/testMock.js", + "\\.(css|less)$": "/scripts/testMock.js" + }, + "moduleFileExtensions": [ + "web.js", + "js", + "web.ts", + "ts", + "web.tsx", + "tsx", + "json", + "web.jsx", + "jsx", + "node" + ] + }, + "dependencies": { + "bls-signatures": "^2.0.2" + } +} diff --git a/wasm/tests/clvm-tools-interface/scripts/getPackageJson.js b/wasm/tests/clvm-tools-interface/scripts/getPackageJson.js new file mode 100644 index 000000000..fe44d4b5d --- /dev/null +++ b/wasm/tests/clvm-tools-interface/scripts/getPackageJson.js @@ -0,0 +1,25 @@ +const fs = require('fs'); +const path = require('path'); + +/** + * A module to get package informations from package.json + * @module getPackageJson + * @param {...string} keys from package.json if no arguments passed it returns package.json content as object + * @returns {object} with given keys or content of package.json as object + */ + +/** + * Returns package info + */ +const getPackageJson = function(...args) { + const packageJSON = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json'))); + if (!args.length) { + return packageJSON; + } + return args.reduce((out, key) => { + out[key] = packageJSON[key]; + return out; + }, {}); +}; + +module.exports = getPackageJson; \ No newline at end of file diff --git a/wasm/tests/clvm-tools-interface/scripts/testMock.js b/wasm/tests/clvm-tools-interface/scripts/testMock.js new file mode 100644 index 000000000..a09954537 --- /dev/null +++ b/wasm/tests/clvm-tools-interface/scripts/testMock.js @@ -0,0 +1 @@ +module.exports = {}; \ No newline at end of file diff --git a/wasm/tests/clvm-tools-interface/src/lib/index.ts b/wasm/tests/clvm-tools-interface/src/lib/index.ts new file mode 100644 index 000000000..e69de29bb diff --git a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts new file mode 100644 index 000000000..626d11b41 --- /dev/null +++ b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts @@ -0,0 +1,186 @@ +import * as fs from 'fs'; +import { resolve } from 'path'; +import * as assert from 'assert'; +import * as bls_loader from 'bls-signatures'; +const {h, t, Program} = require('../../../../../pkg/clvm_tools_wasm'); + +it('Has BLS signatures support', async () => { + let bls = await bls_loader.default(); + let g1element = new bls.G1Element(); + let converted_g1_element = Program.to(g1element); + assert.equal('b0c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', converted_g1_element.toString()); +}); + +it('Has the "h" function', async () => { + let unhexed = h('21203031'); + assert.equal([0x21, 0x20, 0x30, 0x31].toString(), unhexed.toString()); +}); + +it('Converts to string', async () => { + let converted_sexp = Program.to([1, 2, 3]); + assert.equal("ff01ff02ff0380", converted_sexp.toString()); +}); + +it('Accepts already converted objects', async () => { + let converted_sexp = Program.to([1, 2, 3]); + let twice_converted = Program.to(converted_sexp); + assert.equal("ff01ff02ff0380", twice_converted.toString()); +}); + +it('Has as_pair', async () => { + let converted_sexp = Program.to([1, 2, 3]); + let as_pair = converted_sexp.as_pair(); + assert.equal("01", as_pair[0].toString()); + assert.equal("ff02ff0380", as_pair[1].toString()); +}); + +it('Has null', async () => { + assert.equal(Program.null().toString(), '80'); +}); + +it('Has listp', async () => { + let is_list = Program.to([1,2,3]); + let isnt_list = Program.to(456); + assert.equal(is_list.listp(), true); + assert.equal(isnt_list.listp(), false); +}); + +it('Has nullp', async () => { + let is_null = Program.to([]); + let is_also_null = Program.to(0); + let isnt_null = Program.to(7); + let isnt_also_null = Program.to([99,101]); + assert.equal(is_null.nullp(), true); + assert.equal(is_also_null.nullp(), true); + assert.equal(isnt_null.nullp(), false); + assert.equal(isnt_also_null.nullp(), false); +}); + +it('Has as_int', async () => { + let int_value = Program.to(7).as_int(); + assert.equal(int_value, 7); + try { + non_int_value = Program.to([7,13]).as_int(); + assert.fail(true); + } catch (e) { + assert.equal(e.toString(), "not a number"); + } +}); + +it('Has as_bigint', async () => { + let int_value = Program.to(10000000000000000000000n).as_bigint(); + assert.equal(int_value, 10000000000000000000000n); + try { + non_int_value = Program.to([7,13]).as_bigint(); + assert.fail(true); + } catch (e) { + assert.equal(e.toString(), "not a number"); + } +}); + +it('Has first and rest', async () => { + let test_list = Program.to([7,13,17,23]); + assert.equal(test_list.first().toString(), '07'); + assert.equal(test_list.rest().toString(), 'ff0dff11ff1780'); + try { + Program.to([]).first(); + assert.fail(true); + } catch (e) { + assert.equal(e.toString(), "not a cons"); + } + try { + Program.to([]).rest(); + assert.fail(true); + } catch (e) { + assert.equal(e.toString(), "not a cons"); + } +}); + +it('Has cons', async () => { + let test_1 = Program.to(7); + let test_2 = Program.to([8,9,10]); + let consed = test_1.cons(test_2); + let test_3 = Program.to([7,8,9,10]); + assert.equal(consed.toString(), test_3.toString()); +}); + +it('Has the t function', async () => { + let p1 = Program.to(7); + let p2 = Program.to(9); + let tuple = t(p1, p2); + let consed = p1.cons(p2); + assert.equal(Program.to(tuple).toString(), consed.toString()); +}); + +it('Has as_bin', async () => { + let test_data = Program.to([7,8,9,10]); + let as_bin = test_data.as_bin(); + assert.equal([255,7,255,8,255,9,255,10,128].toString(), as_bin.toString()); +}); + +it('Has list_len', async () => { + let list_data = Program.to([7,8,9,10]); + let list_len = list_data.list_len(); + assert.equal(list_len, 4); + let not_list = Program.to(16); + let not_list_len = not_list.list_len(); + assert.equal(not_list_len, 0); +}); + +it('Has equal_to', async () => { + let p1 = Program.to([7,8,[9,10],11]); + let p2 = Program.from_hex('ff07ff08ffff09ff0a80ff0b80'); + let p3 = Program.to([7,8,[9,11],11]); + assert.ok(p1.equal_to(p2)); + assert.ok(!p1.equal_to(p3)); + assert.ok(!p2.equal_to(p3)); +}); + +it('Has as_javascript', async () => { + let tuple = t(9,(t(10,11))); + let original = [7,8,tuple,12]; + let p1 = Program.to(original); + let p1_as_js = p1.as_javascript(); + assert.equal(original.toString(), p1_as_js.toString()); +}); + +it('Has run', async () => { + let program = Program.from_hex('ff12ffff10ff02ffff010180ffff11ff02ffff01018080'); + let args = Program.to([13]); + const [cost, run_result] = program.run(args); + assert.equal(run_result.toString(), '8200a8'); + assert.equal(cost, 2658); +}); + +it('Has curry', async () => { + let program = Program.from_hex('ff12ffff10ff02ffff010180ffff11ff02ffff01018080'); + let program_with_arg = program.curry(Program.to(13)); + const [cost, run_result] = program_with_arg.run(Program.to([])); + assert.equal(run_result.toString(), '8200a8'); + assert.equal(cost, 2884); +}); + +export class ChiaExample { + constructor(MOD) { + this.MOD = MOD; + } + public puzzle_for_synthetic_public_key(synthetic_public_key: G1Element): Program { + return this.MOD.curry(synthetic_public_key); + } +} + +it('works as expected in context', async () => { + let bls = await bls_loader.default(); + const program_text = fs.readFileSync(resolve(__dirname, '../../../content/p2_delegated_puzzle_or_hidden_puzzle.clvm.hex'),'utf-8'); + const MOD: Program = Program.from_hex(program_text); + let ce = new ChiaExample(MOD); + let sk = bls.AugSchemeMPL.key_gen([ + 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, 19, 18, 12, 89, 6, 220, + 18, 102, 58, 209, 82, 12, 62, 89, 110, 182, 9, 44, 20, 254, 22 + ]); + let pk = bls.AugSchemeMPL.sk_to_g1(sk); + // pk bytes 86243290bbcbfd9ae75bdece7981965350208eb5e99b04d5cd24e955ada961f8c0a162dee740be7bdc6c3c0613ba2eb1 + // Expected puzzle hash = 30cdae3d54778db5eba21584c452cfb1a278136b2ec352ba44a52078efea7507 + let target_puzzle = ce.puzzle_for_synthetic_public_key(pk); + assert.equal(target_puzzle.sha256tree().toString(), h('30cdae3d54778db5eba21584c452cfb1a278136b2ec352ba44a52078efea7507').toString()); +}); diff --git a/wasm/tests/clvm-tools-interface/tsconfig.json b/wasm/tests/clvm-tools-interface/tsconfig.json new file mode 100644 index 000000000..9ea99e98e --- /dev/null +++ b/wasm/tests/clvm-tools-interface/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "noImplicitAny": true, + "outDir": "build/types", + "module": "esnext", + "target": "es5", + "allowJs": true, + "checkJs": false, + "sourceMap": true, + "declaration": true, + "emitDeclarationOnly": true, + "suppressImplicitAnyIndexErrors": true, + "lib": ["es2018", "dom"], + "moduleResolution": "node", + }, + "include": ["src/lib"], + "exclude": ["src/lib/**/tests"], +} diff --git a/wasm/tests/clvm-tools-interface/webpack.config.demo.js b/wasm/tests/clvm-tools-interface/webpack.config.demo.js new file mode 100644 index 000000000..1627bd603 --- /dev/null +++ b/wasm/tests/clvm-tools-interface/webpack.config.demo.js @@ -0,0 +1,47 @@ +const MiniCssExtractPlugin = require("mini-css-extract-plugin"); +const HtmlWebpackPlugin = require('html-webpack-plugin'); + +module.exports = { + mode: "development", + devtool: 'cheap-module-source-map', + entry: './src/demo/index.ts', + output: { + filename: 'index.js' + }, + optimization: { + minimize: false, + }, + devServer: { + open: true, + hot: true, + host: "localhost", + port: 9000 + }, + module: { + rules: [ + { + test: /\.(m|j|t)s$/, + exclude: /(node_modules|bower_components)/, + use: { + loader: 'babel-loader' + } + }, + { + test: /\.(sa|sc|c)ss$/, + use: [ + MiniCssExtractPlugin.loader, + { loader: "css-loader", options: { sourceMap: true } }, + ], + } + ] + }, + plugins: [ + new MiniCssExtractPlugin({ + filename: 'css/index.css' + }), + new HtmlWebpackPlugin(), + ], + resolve: { + extensions: ['.ts', '.js', '.json'] + } +}; \ No newline at end of file diff --git a/wasm/tests/clvm-tools-interface/webpack.config.js b/wasm/tests/clvm-tools-interface/webpack.config.js new file mode 100644 index 000000000..c050382c7 --- /dev/null +++ b/wasm/tests/clvm-tools-interface/webpack.config.js @@ -0,0 +1,71 @@ +const path = require('path'); +const webpack = require('webpack'); +const TerserPlugin = require('terser-webpack-plugin'); +const getPackageJson = require('./scripts/getPackageJson'); +const MiniCssExtractPlugin = require("mini-css-extract-plugin"); +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +const { + version, + name, + license, + repository, + author, +} = getPackageJson('version', 'name', 'license', 'repository', 'author'); + +const banner = ` + ${name} v${version} + ${repository.url} + + Copyright (c) ${author.replace(/ *<[^)]*> */g, " ")} and project contributors. + + This source code is licensed under the ${license} license found in the + LICENSE file in the root directory of this source tree. +`; + +module.exports = { + mode: "production", + devtool: 'source-map', + entry: './src/lib/index.ts', + output: { + filename: 'index.js', + path: path.resolve(__dirname, 'build'), + library: "MyLibrary", + libraryTarget: 'umd', + clean: true + }, + optimization: { + minimize: true, + minimizer: [ + new TerserPlugin({ extractComments: false }), + new CssMinimizerPlugin() + ], + }, + module: { + rules: [ + { + test: /\.(m|j|t)s$/, + exclude: /(node_modules|bower_components)/, + use: { + loader: 'babel-loader' + } + }, + { + test: /\.(sa|sc|c)ss$/, + use: [ + MiniCssExtractPlugin.loader, + { loader: "css-loader", options: { sourceMap: true } }, + ], + } + ] + }, + plugins: [ + new MiniCssExtractPlugin({ + filename: 'css/index.css' + }), + new webpack.BannerPlugin(banner) + ], + resolve: { + extensions: ['.ts', '.js', '.json'] + } +}; diff --git a/wasm/tests/clvm-tools-interface/yarn.lock b/wasm/tests/clvm-tools-interface/yarn.lock new file mode 100644 index 000000000..162a52399 --- /dev/null +++ b/wasm/tests/clvm-tools-interface/yarn.lock @@ -0,0 +1,6146 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + +"@ampproject/remapping@^2.2.0": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/cli@^7.22.9": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.22.10.tgz#25e4bbd8d0a0d8b4b389e1b5e2d7a238bd4c1b75" + integrity sha512-rM9ZMmaII630zGvtMtQ3P4GyHs28CHLYE9apLG7L8TgaSqcfoIGrlLSLsh4Q8kDTdZQQEXZm1M0nQtOvU/2heg== + dependencies: + "@jridgewell/trace-mapping" "^0.3.17" + commander "^4.0.1" + convert-source-map "^1.1.0" + fs-readdir-recursive "^1.1.0" + glob "^7.2.0" + make-dir "^2.1.0" + slash "^2.0.0" + optionalDependencies: + "@nicolo-ribaudo/chokidar-2" "2.1.8-no-fsevents.3" + chokidar "^3.4.0" + +"@babel/code-frame@7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" + integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.22.10", "@babel/code-frame@^7.22.5": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.10.tgz#1c20e612b768fefa75f6e90d6ecb86329247f0a3" + integrity sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA== + dependencies: + "@babel/highlight" "^7.22.10" + chalk "^2.4.2" + +"@babel/compat-data@^7.22.5", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.9.tgz#71cdb00a1ce3a329ce4cbec3a44f9fef35669730" + integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ== + +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.10.tgz#aad442c7bcd1582252cb4576747ace35bc122f35" + integrity sha512-fTmqbbUBAwCcre6zPzNngvsI0aNrPZe77AeqvDxWM9Nm+04RrJ3CAmGHA9f7lJQY6ZMhRztNemy4uslDxTX4Qw== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.22.10" + "@babel/generator" "^7.22.10" + "@babel/helper-compilation-targets" "^7.22.10" + "@babel/helper-module-transforms" "^7.22.9" + "@babel/helpers" "^7.22.10" + "@babel/parser" "^7.22.10" + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.10" + "@babel/types" "^7.22.10" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.2" + semver "^6.3.1" + +"@babel/generator@^7.22.10", "@babel/generator@^7.7.2": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.10.tgz#c92254361f398e160645ac58831069707382b722" + integrity sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A== + dependencies: + "@babel/types" "^7.22.10" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + +"@babel/helper-annotate-as-pure@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882" + integrity sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.22.5": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.10.tgz#573e735937e99ea75ea30788b57eb52fab7468c9" + integrity sha512-Av0qubwDQxC56DoUReVDeLfMEjYYSN1nZrTUrWkXd7hpU73ymRANkbuDm3yni9npkn+RXy9nNbEJZEzXr7xrfQ== + dependencies: + "@babel/types" "^7.22.10" + +"@babel/helper-compilation-targets@^7.22.10", "@babel/helper-compilation-targets@^7.22.5", "@babel/helper-compilation-targets@^7.22.6": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz#01d648bbc25dd88f513d862ee0df27b7d4e67024" + integrity sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q== + dependencies: + "@babel/compat-data" "^7.22.9" + "@babel/helper-validator-option" "^7.22.5" + browserslist "^4.21.9" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.22.10", "@babel/helper-create-class-features-plugin@^7.22.5": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.10.tgz#dd2612d59eac45588021ac3d6fa976d08f4e95a3" + integrity sha512-5IBb77txKYQPpOEdUdIhBx8VrZyDCQ+H82H0+5dX1TmuscP5vJKEE3cKurjtIw/vFwzbVH48VweE78kVDBrqjA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-member-expression-to-functions" "^7.22.5" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + semver "^6.3.1" + +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.22.5": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.9.tgz#9d8e61a8d9366fe66198f57c40565663de0825f6" + integrity sha512-+svjVa/tFwsNSG4NEy1h85+HQ5imbT92Q5/bgtS7P0GTQlP8WuFdqsiABmQouhiFGyV66oGxZFpeYHza1rNsKw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + regexpu-core "^5.3.1" + semver "^6.3.1" + +"@babel/helper-define-polyfill-provider@^0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz#82c825cadeeeee7aad237618ebbe8fa1710015d7" + integrity sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw== + dependencies: + "@babel/helper-compilation-targets" "^7.22.6" + "@babel/helper-plugin-utils" "^7.22.5" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + +"@babel/helper-environment-visitor@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98" + integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q== + +"@babel/helper-function-name@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be" + integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ== + dependencies: + "@babel/template" "^7.22.5" + "@babel/types" "^7.22.5" + +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-member-expression-to-functions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.5.tgz#0a7c56117cad3372fbf8d2fb4bf8f8d64a1e76b2" + integrity sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-imports@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz#1a8f4c9f4027d23f520bd76b364d44434a72660c" + integrity sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-transforms@^7.22.5", "@babel/helper-module-transforms@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz#92dfcb1fbbb2bc62529024f72d942a8c97142129" + integrity sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ== + dependencies: + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.5" + +"@babel/helper-optimise-call-expression@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz#f21531a9ccbff644fdd156b4077c16ff0c3f609e" + integrity sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" + integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== + +"@babel/helper-remap-async-to-generator@^7.22.5", "@babel/helper-remap-async-to-generator@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.9.tgz#53a25b7484e722d7efb9c350c75c032d4628de82" + integrity sha512-8WWC4oR4Px+tr+Fp0X3RHDVfINGpF3ad1HIbrc8A77epiR6eMMc6jsgozkzT2uDiOOdoS9cLIQ+XD2XvI2WSmQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-wrap-function" "^7.22.9" + +"@babel/helper-replace-supers@^7.22.5", "@babel/helper-replace-supers@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz#cbdc27d6d8d18cd22c81ae4293765a5d9afd0779" + integrity sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg== + dependencies: + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-member-expression-to-functions" "^7.22.5" + "@babel/helper-optimise-call-expression" "^7.22.5" + +"@babel/helper-simple-access@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" + integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-skip-transparent-expression-wrappers@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz#007f15240b5751c537c40e77abb4e89eeaaa8847" + integrity sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-string-parser@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" + integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== + +"@babel/helper-validator-identifier@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193" + integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ== + +"@babel/helper-validator-option@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz#de52000a15a177413c8234fa3a8af4ee8102d0ac" + integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw== + +"@babel/helper-wrap-function@^7.22.9": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.22.10.tgz#d845e043880ed0b8c18bd194a12005cb16d2f614" + integrity sha512-OnMhjWjuGYtdoO3FmsEFWvBStBAe2QOgwOLsLNDjN+aaiMD8InJk1/O3HSD8lkqTjCgg5YI34Tz15KNNA3p+nQ== + dependencies: + "@babel/helper-function-name" "^7.22.5" + "@babel/template" "^7.22.5" + "@babel/types" "^7.22.10" + +"@babel/helpers@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.10.tgz#ae6005c539dfbcb5cd71fb51bfc8a52ba63bc37a" + integrity sha512-a41J4NW8HyZa1I1vAndrraTlPZ/eZoga2ZgS7fEr0tZJGVU4xqdE80CEm0CcNjha5EZ8fTBYLKHF0kqDUuAwQw== + dependencies: + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.10" + "@babel/types" "^7.22.10" + +"@babel/highlight@^7.10.4", "@babel/highlight@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.10.tgz#02a3f6d8c1cb4521b2fd0ab0da8f4739936137d7" + integrity sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ== + dependencies: + "@babel/helper-validator-identifier" "^7.22.5" + chalk "^2.4.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.22.10", "@babel/parser@^7.22.5", "@babel/parser@^7.7.0": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.10.tgz#e37634f9a12a1716136c44624ef54283cabd3f55" + integrity sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ== + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.5.tgz#87245a21cd69a73b0b81bcda98d443d6df08f05e" + integrity sha512-NP1M5Rf+u2Gw9qfSO4ihjcTGW5zXTi36ITLd4/EoAcEhIZ0yjMqmftDNl3QC19CX7olhrjpyU454g/2W7X0jvQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.5.tgz#fef09f9499b1f1c930da8a0c419db42167d792ca" + integrity sha512-31Bb65aZaUwqCbWMnZPduIZxCBngHFlzyN6Dq6KAJjtx+lx6ohKHubc61OomYi7XwVD4Ol0XCVz4h+pYFR048g== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/plugin-transform-optional-chaining" "^7.22.5" + +"@babel/plugin-proposal-class-properties@^7.16.0": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" + integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": + version "7.21.0-placeholder-for-preset-env.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" + integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-import-assertions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz#07d252e2aa0bc6125567f742cd58619cb14dce98" + integrity sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-import-attributes@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz#ab840248d834410b829f569f5262b9e517555ecb" + integrity sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-import-meta@^7.10.4", "@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz#a6b68e84fb76e759fc3b93e901876ffabbe1d918" + integrity sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5", "@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.22.5", "@babel/plugin-syntax-typescript@^7.7.2": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz#aac8d383b062c5072c647a31ef990c1d0af90272" + integrity sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" + integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-arrow-functions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz#e5ba566d0c58a5b2ba2a8b795450641950b71958" + integrity sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-async-generator-functions@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.10.tgz#45946cd17f915b10e65c29b8ed18a0a50fc648c8" + integrity sha512-eueE8lvKVzq5wIObKK/7dvoeKJ+xc6TvRn6aysIjS6pSCeLy7S/eVi7pEQknZqyqvzaNKdDtem8nUNTBgDVR2g== + dependencies: + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-remap-async-to-generator" "^7.22.9" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-transform-async-to-generator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz#c7a85f44e46f8952f6d27fe57c2ed3cc084c3775" + integrity sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ== + dependencies: + "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-remap-async-to-generator" "^7.22.5" + +"@babel/plugin-transform-block-scoped-functions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz#27978075bfaeb9fa586d3cb63a3d30c1de580024" + integrity sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-block-scoping@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.10.tgz#88a1dccc3383899eb5e660534a76a22ecee64faa" + integrity sha512-1+kVpGAOOI1Albt6Vse7c8pHzcZQdQKW+wJH+g8mCaszOdDVwRXa/slHPqIw+oJAJANTKDMuM2cBdV0Dg618Vg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-class-properties@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.5.tgz#97a56e31ad8c9dc06a0b3710ce7803d5a48cca77" + integrity sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-class-static-block@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.5.tgz#3e40c46f048403472d6f4183116d5e46b1bff5ba" + integrity sha512-SPToJ5eYZLxlnp1UzdARpOGeC2GbHvr9d/UV0EukuVx8atktg194oe+C5BqQ8jRTkgLRVOPYeXRSBg1IlMoVRA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-transform-classes@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.6.tgz#e04d7d804ed5b8501311293d1a0e6d43e94c3363" + integrity sha512-58EgM6nuPNG6Py4Z3zSuu0xWu2VfodiMi72Jt5Kj2FECmaYk1RrTXA45z6KBFsu9tRgwQDwIiY4FXTt+YsSFAQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-compilation-targets" "^7.22.6" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz#cd1e994bf9f316bd1c2dafcd02063ec261bb3869" + integrity sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/template" "^7.22.5" + +"@babel/plugin-transform-destructuring@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.10.tgz#38e2273814a58c810b6c34ea293be4973c4eb5e2" + integrity sha512-dPJrL0VOyxqLM9sritNbMSGx/teueHF/htMKrPT7DNxccXxRDPYqlgPFFdr8u+F+qUZOkZoXue/6rL5O5GduEw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-dotall-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz#dbb4f0e45766eb544e193fb00e65a1dd3b2a4165" + integrity sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-duplicate-keys@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz#b6e6428d9416f5f0bba19c70d1e6e7e0b88ab285" + integrity sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-dynamic-import@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.5.tgz#d6908a8916a810468c4edff73b5b75bda6ad393e" + integrity sha512-0MC3ppTB1AMxd8fXjSrbPa7LT9hrImt+/fcj+Pg5YMD7UQyWp/02+JWpdnCymmsXwIx5Z+sYn1bwCn4ZJNvhqQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-transform-exponentiation-operator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz#402432ad544a1f9a480da865fda26be653e48f6a" + integrity sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-export-namespace-from@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.5.tgz#57c41cb1d0613d22f548fddd8b288eedb9973a5b" + integrity sha512-X4hhm7FRnPgd4nDA4b/5V280xCx6oL7Oob5+9qVS5C13Zq4bh1qq7LU0GgRU6b5dBWBvhGaXYVB4AcN6+ol6vg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-transform-for-of@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.5.tgz#ab1b8a200a8f990137aff9a084f8de4099ab173f" + integrity sha512-3kxQjX1dU9uudwSshyLeEipvrLjBCVthCgeTp6CzE/9JYrlAIaeekVxRpCWsDDfYTfRZRoCeZatCQvwo+wvK8A== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-function-name@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz#935189af68b01898e0d6d99658db6b164205c143" + integrity sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg== + dependencies: + "@babel/helper-compilation-targets" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-json-strings@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.5.tgz#14b64352fdf7e1f737eed68de1a1468bd2a77ec0" + integrity sha512-DuCRB7fu8MyTLbEQd1ew3R85nx/88yMoqo2uPSjevMj3yoN7CDM8jkgrY0wmVxfJZyJ/B9fE1iq7EQppWQmR5A== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-transform-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz#e9341f4b5a167952576e23db8d435849b1dd7920" + integrity sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-logical-assignment-operators@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.5.tgz#66ae5f068fd5a9a5dc570df16f56c2a8462a9d6c" + integrity sha512-MQQOUW1KL8X0cDWfbwYP+TbVbZm16QmQXJQ+vndPtH/BoO0lOKpVoEDMI7+PskYxH+IiE0tS8xZye0qr1lGzSA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-transform-member-expression-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz#4fcc9050eded981a468347dd374539ed3e058def" + integrity sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-modules-amd@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz#4e045f55dcf98afd00f85691a68fc0780704f526" + integrity sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ== + dependencies: + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-modules-commonjs@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.5.tgz#7d9875908d19b8c0536085af7b053fd5bd651bfa" + integrity sha512-B4pzOXj+ONRmuaQTg05b3y/4DuFz3WcCNAXPLb2Q0GT0TrGKGxNKV4jwsXts+StaM0LQczZbOpj8o1DLPDJIiA== + dependencies: + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-simple-access" "^7.22.5" + +"@babel/plugin-transform-modules-systemjs@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.5.tgz#18c31410b5e579a0092638f95c896c2a98a5d496" + integrity sha512-emtEpoaTMsOs6Tzz+nbmcePl6AKVtS1yC4YNAeMun9U8YCsgadPNxnOPQ8GhHFB2qdx+LZu9LgoC0Lthuu05DQ== + dependencies: + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.5" + +"@babel/plugin-transform-modules-umd@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz#4694ae40a87b1745e3775b6a7fe96400315d4f98" + integrity sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ== + dependencies: + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz#67fe18ee8ce02d57c855185e27e3dc959b2e991f" + integrity sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-new-target@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz#1b248acea54ce44ea06dfd37247ba089fcf9758d" + integrity sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-nullish-coalescing-operator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.5.tgz#f8872c65776e0b552e0849d7596cddd416c3e381" + integrity sha512-6CF8g6z1dNYZ/VXok5uYkkBBICHZPiGEl7oDnAx2Mt1hlHVHOSIKWJaXHjQJA5VB43KZnXZDIexMchY4y2PGdA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-transform-numeric-separator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.5.tgz#57226a2ed9e512b9b446517ab6fa2d17abb83f58" + integrity sha512-NbslED1/6M+sXiwwtcAB/nieypGw02Ejf4KtDeMkCEpP6gWFMX1wI9WKYua+4oBneCCEmulOkRpwywypVZzs/g== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-transform-object-rest-spread@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.5.tgz#9686dc3447df4753b0b2a2fae7e8bc33cdc1f2e1" + integrity sha512-Kk3lyDmEslH9DnvCDA1s1kkd3YWQITiBOHngOtDL9Pt6BZjzqb6hiOlb8VfjiiQJ2unmegBqZu0rx5RxJb5vmQ== + dependencies: + "@babel/compat-data" "^7.22.5" + "@babel/helper-compilation-targets" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.22.5" + +"@babel/plugin-transform-object-super@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz#794a8d2fcb5d0835af722173c1a9d704f44e218c" + integrity sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.5" + +"@babel/plugin-transform-optional-catch-binding@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.5.tgz#842080be3076703be0eaf32ead6ac8174edee333" + integrity sha512-pH8orJahy+hzZje5b8e2QIlBWQvGpelS76C63Z+jhZKsmzfNaPQ+LaW6dcJ9bxTpo1mtXbgHwy765Ro3jftmUg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-transform-optional-chaining@^7.22.10", "@babel/plugin-transform-optional-chaining@^7.22.5": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.10.tgz#076d28a7e074392e840d4ae587d83445bac0372a" + integrity sha512-MMkQqZAZ+MGj+jGTG3OTuhKeBpNcO+0oCEbrGNEaOmiEn+1MzRyQlYsruGiU8RTK3zV6XwrVJTmwiDOyYK6J9g== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-transform-parameters@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.5.tgz#c3542dd3c39b42c8069936e48717a8d179d63a18" + integrity sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-private-methods@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.5.tgz#21c8af791f76674420a147ae62e9935d790f8722" + integrity sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-private-property-in-object@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.5.tgz#07a77f28cbb251546a43d175a1dda4cf3ef83e32" + integrity sha512-/9xnaTTJcVoBtSSmrVyhtSvO3kbqS2ODoh2juEU72c3aYonNF0OMGiaz2gjukyKM2wBBYJP38S4JiE0Wfb5VMQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-transform-property-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz#b5ddabd73a4f7f26cd0e20f5db48290b88732766" + integrity sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-regenerator@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.10.tgz#8ceef3bd7375c4db7652878b0241b2be5d0c3cca" + integrity sha512-F28b1mDt8KcT5bUyJc/U9nwzw6cV+UmTeRlXYIl2TNqMMJif0Jeey9/RQ3C4NOd2zp0/TRsDns9ttj2L523rsw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + regenerator-transform "^0.15.2" + +"@babel/plugin-transform-reserved-words@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz#832cd35b81c287c4bcd09ce03e22199641f964fb" + integrity sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-shorthand-properties@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz#6e277654be82b5559fc4b9f58088507c24f0c624" + integrity sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-spread@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz#6487fd29f229c95e284ba6c98d65eafb893fea6b" + integrity sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + +"@babel/plugin-transform-sticky-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz#295aba1595bfc8197abd02eae5fc288c0deb26aa" + integrity sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-template-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz#8f38cf291e5f7a8e60e9f733193f0bcc10909bff" + integrity sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-typeof-symbol@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz#5e2ba478da4b603af8673ff7c54f75a97b716b34" + integrity sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-typescript@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.22.10.tgz#aadd98fab871f0bb5717bcc24c31aaaa455af923" + integrity sha512-7++c8I/ymsDo4QQBAgbraXLzIM6jmfao11KgIBEYZRReWzNWH9NtNgJcyrZiXsOPh523FQm6LfpLyy/U5fn46A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-create-class-features-plugin" "^7.22.10" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-typescript" "^7.22.5" + +"@babel/plugin-transform-unicode-escapes@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.10.tgz#c723f380f40a2b2f57a62df24c9005834c8616d9" + integrity sha512-lRfaRKGZCBqDlRU3UIFovdp9c9mEvlylmpod0/OatICsSfuQ9YFthRo1tpTkGsklEefZdqlEFdY4A2dwTb6ohg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-unicode-property-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz#098898f74d5c1e86660dc112057b2d11227f1c81" + integrity sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-unicode-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz#ce7e7bb3ef208c4ff67e02a22816656256d7a183" + integrity sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-unicode-sets-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz#77788060e511b708ffc7d42fdfbc5b37c3004e91" + integrity sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/polyfill@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.12.1.tgz#1f2d6371d1261bbd961f3c5d5909150e12d0bd96" + integrity sha512-X0pi0V6gxLi6lFZpGmeNa4zxtwEmCs42isWLNjZZDE0Y8yVfgu0T2OAHlzBbdYlqbW/YXVvoBHpATEM+goCj8g== + dependencies: + core-js "^2.6.5" + regenerator-runtime "^0.13.4" + +"@babel/preset-env@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.22.10.tgz#3263b9fe2c8823d191d28e61eac60a79f9ce8a0f" + integrity sha512-riHpLb1drNkpLlocmSyEg4oYJIQFeXAK/d7rI6mbD0XsvoTOOweXDmQPG/ErxsEhWk3rl3Q/3F6RFQlVFS8m0A== + dependencies: + "@babel/compat-data" "^7.22.9" + "@babel/helper-compilation-targets" "^7.22.10" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-validator-option" "^7.22.5" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.22.5" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.22.5" + "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-import-assertions" "^7.22.5" + "@babel/plugin-syntax-import-attributes" "^7.22.5" + "@babel/plugin-syntax-import-meta" "^7.10.4" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" + "@babel/plugin-transform-arrow-functions" "^7.22.5" + "@babel/plugin-transform-async-generator-functions" "^7.22.10" + "@babel/plugin-transform-async-to-generator" "^7.22.5" + "@babel/plugin-transform-block-scoped-functions" "^7.22.5" + "@babel/plugin-transform-block-scoping" "^7.22.10" + "@babel/plugin-transform-class-properties" "^7.22.5" + "@babel/plugin-transform-class-static-block" "^7.22.5" + "@babel/plugin-transform-classes" "^7.22.6" + "@babel/plugin-transform-computed-properties" "^7.22.5" + "@babel/plugin-transform-destructuring" "^7.22.10" + "@babel/plugin-transform-dotall-regex" "^7.22.5" + "@babel/plugin-transform-duplicate-keys" "^7.22.5" + "@babel/plugin-transform-dynamic-import" "^7.22.5" + "@babel/plugin-transform-exponentiation-operator" "^7.22.5" + "@babel/plugin-transform-export-namespace-from" "^7.22.5" + "@babel/plugin-transform-for-of" "^7.22.5" + "@babel/plugin-transform-function-name" "^7.22.5" + "@babel/plugin-transform-json-strings" "^7.22.5" + "@babel/plugin-transform-literals" "^7.22.5" + "@babel/plugin-transform-logical-assignment-operators" "^7.22.5" + "@babel/plugin-transform-member-expression-literals" "^7.22.5" + "@babel/plugin-transform-modules-amd" "^7.22.5" + "@babel/plugin-transform-modules-commonjs" "^7.22.5" + "@babel/plugin-transform-modules-systemjs" "^7.22.5" + "@babel/plugin-transform-modules-umd" "^7.22.5" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.22.5" + "@babel/plugin-transform-new-target" "^7.22.5" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.22.5" + "@babel/plugin-transform-numeric-separator" "^7.22.5" + "@babel/plugin-transform-object-rest-spread" "^7.22.5" + "@babel/plugin-transform-object-super" "^7.22.5" + "@babel/plugin-transform-optional-catch-binding" "^7.22.5" + "@babel/plugin-transform-optional-chaining" "^7.22.10" + "@babel/plugin-transform-parameters" "^7.22.5" + "@babel/plugin-transform-private-methods" "^7.22.5" + "@babel/plugin-transform-private-property-in-object" "^7.22.5" + "@babel/plugin-transform-property-literals" "^7.22.5" + "@babel/plugin-transform-regenerator" "^7.22.10" + "@babel/plugin-transform-reserved-words" "^7.22.5" + "@babel/plugin-transform-shorthand-properties" "^7.22.5" + "@babel/plugin-transform-spread" "^7.22.5" + "@babel/plugin-transform-sticky-regex" "^7.22.5" + "@babel/plugin-transform-template-literals" "^7.22.5" + "@babel/plugin-transform-typeof-symbol" "^7.22.5" + "@babel/plugin-transform-unicode-escapes" "^7.22.10" + "@babel/plugin-transform-unicode-property-regex" "^7.22.5" + "@babel/plugin-transform-unicode-regex" "^7.22.5" + "@babel/plugin-transform-unicode-sets-regex" "^7.22.5" + "@babel/preset-modules" "0.1.6-no-external-plugins" + "@babel/types" "^7.22.10" + babel-plugin-polyfill-corejs2 "^0.4.5" + babel-plugin-polyfill-corejs3 "^0.8.3" + babel-plugin-polyfill-regenerator "^0.5.2" + core-js-compat "^3.31.0" + semver "^6.3.1" + +"@babel/preset-modules@0.1.6-no-external-plugins": + version "0.1.6-no-external-plugins" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz#ccb88a2c49c817236861fee7826080573b8a923a" + integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/regjsgen@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" + integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== + +"@babel/runtime@^7.8.4": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.10.tgz#ae3e9631fd947cb7e3610d3e9d8fef5f76696682" + integrity sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ== + dependencies: + regenerator-runtime "^0.14.0" + +"@babel/template@^7.22.5", "@babel/template@^7.3.3": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec" + integrity sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw== + dependencies: + "@babel/code-frame" "^7.22.5" + "@babel/parser" "^7.22.5" + "@babel/types" "^7.22.5" + +"@babel/traverse@^7.22.10", "@babel/traverse@^7.7.0": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.10.tgz#20252acb240e746d27c2e82b4484f199cf8141aa" + integrity sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig== + dependencies: + "@babel/code-frame" "^7.22.10" + "@babel/generator" "^7.22.10" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.22.10" + "@babel/types" "^7.22.10" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.10", "@babel/types@^7.22.5", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.10.tgz#4a9e76446048f2c66982d1a989dd12b8a2d2dc03" + integrity sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg== + dependencies: + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.5" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@discoveryjs/json-ext@^0.5.0": + version "0.5.7" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" + integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== + +"@eslint/eslintrc@^0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" + integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== + dependencies: + ajv "^6.12.4" + debug "^4.1.1" + espree "^7.3.0" + globals "^13.9.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^3.13.1" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + +"@humanwhocodes/config-array@^0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" + integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== + dependencies: + "@humanwhocodes/object-schema" "^1.2.0" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.0": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.6.2.tgz#bf1d4101347c23e07c029a1b1ae07d550f5cc541" + integrity sha512-0N0yZof5hi44HAR2pPS+ikJ3nzKNoZdVu8FffRf3wy47I7Dm7etk/3KetMdRUqzVd16V4O2m2ISpNTbnIuqy1w== + dependencies: + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.6.2" + jest-util "^29.6.2" + slash "^3.0.0" + +"@jest/core@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.6.2.tgz#6f2d1dbe8aa0265fcd4fb8082ae1952f148209c8" + integrity sha512-Oj+5B+sDMiMWLhPFF+4/DvHOf+U10rgvCLGPHP8Xlsy/7QxS51aU/eBngudHlJXnaWD5EohAgJ4js+T6pa+zOg== + dependencies: + "@jest/console" "^29.6.2" + "@jest/reporters" "^29.6.2" + "@jest/test-result" "^29.6.2" + "@jest/transform" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.5.0" + jest-config "^29.6.2" + jest-haste-map "^29.6.2" + jest-message-util "^29.6.2" + jest-regex-util "^29.4.3" + jest-resolve "^29.6.2" + jest-resolve-dependencies "^29.6.2" + jest-runner "^29.6.2" + jest-runtime "^29.6.2" + jest-snapshot "^29.6.2" + jest-util "^29.6.2" + jest-validate "^29.6.2" + jest-watcher "^29.6.2" + micromatch "^4.0.4" + pretty-format "^29.6.2" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.6.2.tgz#794c0f769d85e7553439d107d3f43186dc6874a9" + integrity sha512-AEcW43C7huGd/vogTddNNTDRpO6vQ2zaQNrttvWV18ArBx9Z56h7BIsXkNFJVOO4/kblWEQz30ckw0+L3izc+Q== + dependencies: + "@jest/fake-timers" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + jest-mock "^29.6.2" + +"@jest/expect-utils@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.6.2.tgz#1b97f290d0185d264dd9fdec7567a14a38a90534" + integrity sha512-6zIhM8go3RV2IG4aIZaZbxwpOzz3ZiM23oxAlkquOIole+G6TrbeXnykxWYlqF7kz2HlBjdKtca20x9atkEQYg== + dependencies: + jest-get-type "^29.4.3" + +"@jest/expect@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.6.2.tgz#5a2ad58bb345165d9ce0a1845bbf873c480a4b28" + integrity sha512-m6DrEJxVKjkELTVAztTLyS/7C92Y2b0VYqmDROYKLLALHn8T/04yPs70NADUYPrV3ruI+H3J0iUIuhkjp7vkfg== + dependencies: + expect "^29.6.2" + jest-snapshot "^29.6.2" + +"@jest/fake-timers@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.6.2.tgz#fe9d43c5e4b1b901168fe6f46f861b3e652a2df4" + integrity sha512-euZDmIlWjm1Z0lJ1D0f7a0/y5Kh/koLFMUBE5SUYWrmy8oNhJpbTBDAP6CxKnadcMLDoDf4waRYCe35cH6G6PA== + dependencies: + "@jest/types" "^29.6.1" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.6.2" + jest-mock "^29.6.2" + jest-util "^29.6.2" + +"@jest/globals@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.6.2.tgz#74af81b9249122cc46f1eb25793617eec69bf21a" + integrity sha512-cjuJmNDjs6aMijCmSa1g2TNG4Lby/AeU7/02VtpW+SLcZXzOLK2GpN2nLqcFjmhy3B3AoPeQVx7BnyOf681bAw== + dependencies: + "@jest/environment" "^29.6.2" + "@jest/expect" "^29.6.2" + "@jest/types" "^29.6.1" + jest-mock "^29.6.2" + +"@jest/reporters@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.6.2.tgz#524afe1d76da33d31309c2c4a2c8062d0c48780a" + integrity sha512-sWtijrvIav8LgfJZlrGCdN0nP2EWbakglJY49J1Y5QihcQLfy7ovyxxjJBRXMNltgt4uPtEcFmIMbVshEDfFWw== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.6.2" + "@jest/test-result" "^29.6.2" + "@jest/transform" "^29.6.2" + "@jest/types" "^29.6.1" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.6.2" + jest-util "^29.6.2" + jest-worker "^29.6.2" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@^29.6.0": + version "29.6.0" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.0.tgz#0f4cb2c8e3dca80c135507ba5635a4fd755b0040" + integrity sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^29.6.0": + version "29.6.0" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.0.tgz#bd34a05b5737cb1a99d43e1957020ac8e5b9ddb1" + integrity sha512-oA+I2SHHQGxDCZpbrsCQSoMLb3Bz547JnM+jUr9qEbuw0vQlWZfpPS7CO9J7XiwKicEz9OFn/IYoLkkiUD7bzA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.6.2.tgz#fdd11583cd1608e4db3114e8f0cce277bf7a32ed" + integrity sha512-3VKFXzcV42EYhMCsJQURptSqnyjqCGbtLuX5Xxb6Pm6gUf1wIRIl+mandIRGJyWKgNKYF9cnstti6Ls5ekduqw== + dependencies: + "@jest/console" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.6.2.tgz#585eff07a68dd75225a7eacf319780cb9f6b9bf4" + integrity sha512-GVYi6PfPwVejO7slw6IDO0qKVum5jtrJ3KoLGbgBWyr2qr4GaxFV6su+ZAjdTX75Sr1DkMFRk09r2ZVa+wtCGw== + dependencies: + "@jest/test-result" "^29.6.2" + graceful-fs "^4.2.9" + jest-haste-map "^29.6.2" + slash "^3.0.0" + +"@jest/transform@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.6.2.tgz#522901ebbb211af08835bc3bcdf765ab778094e3" + integrity sha512-ZqCqEISr58Ce3U+buNFJYUktLJZOggfyvR+bZMaiV1e8B1SIvJbwZMrYz3gx/KAPn9EXmOmN+uB08yLCjWkQQg== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.1" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.6.2" + jest-regex-util "^29.4.3" + jest-util "^29.6.2" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + +"@jest/types@^29.6.1": + version "29.6.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.1.tgz#ae79080278acff0a6af5eb49d063385aaa897bf2" + integrity sha512-tPKQNMPuXgvdOn2/Lg9HNfUvjYVGolt04Hp03f5hAk878uwOLikN+JzeLY0HcVgKgFl9Hs3EIqpu3WX27XNhnw== + dependencies: + "@jest/schemas" "^29.6.0" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/source-map@^0.3.3": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91" + integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.19" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811" + integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@leichtgewicht/ip-codec@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" + integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== + +"@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3": + version "2.1.8-no-fsevents.3" + resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b" + integrity sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + +"@sinonjs/commons@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.0.tgz#beb434fe875d965265e04722ccfc21df7f755d72" + integrity sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^10.0.2": + version "10.3.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== + dependencies: + "@sinonjs/commons" "^3.0.0" + +"@trysound/sax@0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" + integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== + +"@types/babel__core@^7.1.14": + version "7.20.1" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.1.tgz#916ecea274b0c776fec721e333e55762d3a9614b" + integrity sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" + integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.1" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.20.1" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.1.tgz#dd6f1d2411ae677dcb2db008c962598be31d6acf" + integrity sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg== + dependencies: + "@babel/types" "^7.20.7" + +"@types/body-parser@*": + version "1.19.2" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" + integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/bonjour@^3.5.9": + version "3.5.10" + resolved "https://registry.yarnpkg.com/@types/bonjour/-/bonjour-3.5.10.tgz#0f6aadfe00ea414edc86f5d106357cda9701e275" + integrity sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw== + dependencies: + "@types/node" "*" + +"@types/connect-history-api-fallback@^1.3.5": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#9fd20b3974bdc2bcd4ac6567e2e0f6885cb2cf41" + integrity sha512-4x5FkPpLipqwthjPsF7ZRbOv3uoLUFkTA9G9v583qi4pACvq0uTELrB8OLUzPWUI4IJIyvM85vzkV1nyiI2Lig== + dependencies: + "@types/express-serve-static-core" "*" + "@types/node" "*" + +"@types/connect@*": + version "3.4.35" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" + integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== + dependencies: + "@types/node" "*" + +"@types/eslint-scope@^3.7.3": + version "3.7.4" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16" + integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "8.44.2" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.44.2.tgz#0d21c505f98a89b8dd4d37fa162b09da6089199a" + integrity sha512-sdPRb9K6iL5XZOmBubg8yiFp5yS/JdUDQsq5e6h95km91MCYMuvp7mh1fjPEYUhvHepKpZOjnEaMBR4PxjWDzg== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194" + integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA== + +"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33": + version "4.17.35" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz#c95dd4424f0d32e525d23812aa8ab8e4d3906c4f" + integrity sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express@*", "@types/express@^4.17.13": + version "4.17.17" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.17.tgz#01d5437f6ef9cfa8668e616e13c2f2ac9a491ae4" + integrity sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.33" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/graceful-fs@^4.1.3": + version "4.1.6" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.6.tgz#e14b2576a1c25026b7f02ede1de3b84c3a1efeae" + integrity sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw== + dependencies: + "@types/node" "*" + +"@types/html-minifier-terser@^6.0.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35" + integrity sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg== + +"@types/http-errors@*": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.1.tgz#20172f9578b225f6c7da63446f56d4ce108d5a65" + integrity sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ== + +"@types/http-proxy@^1.17.8": + version "1.17.11" + resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.11.tgz#0ca21949a5588d55ac2b659b69035c84bd5da293" + integrity sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^29.5.3": + version "29.5.3" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.3.tgz#7a35dc0044ffb8b56325c6802a4781a626b05777" + integrity sha512-1Nq7YrO/vJE/FYnqYyw0FS8LdrjExSgIiHyKg7xPpn+yi8Q4huZryKnkJatN1ZRH89Kw2v33/8ZMB7DuZeSLlA== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/json-schema@*", "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": + version "7.0.12" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" + integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== + +"@types/mime@*": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" + integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== + +"@types/mime@^1": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" + integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== + +"@types/node@*": + version "20.4.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.9.tgz#c7164e0f8d3f12dfae336af0b1f7fdec8c6b204f" + integrity sha512-8e2HYcg7ohnTUbHk8focoklEQYvemQmu9M/f43DZVx43kHn0tE3BY/6gSDxS7k0SprtS0NHvj+L80cGLnoOUcQ== + +"@types/qs@*": + version "6.9.7" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" + integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== + +"@types/range-parser@*": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" + integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== + +"@types/retry@0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" + integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== + +"@types/send@*": + version "0.17.1" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.1.tgz#ed4932b8a2a805f1fe362a70f4e62d0ac994e301" + integrity sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/serve-index@^1.9.1": + version "1.9.1" + resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.1.tgz#1b5e85370a192c01ec6cec4735cf2917337a6278" + integrity sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg== + dependencies: + "@types/express" "*" + +"@types/serve-static@*", "@types/serve-static@^1.13.10": + version "1.15.2" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.2.tgz#3e5419ecd1e40e7405d34093f10befb43f63381a" + integrity sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw== + dependencies: + "@types/http-errors" "*" + "@types/mime" "*" + "@types/node" "*" + +"@types/sockjs@^0.3.33": + version "0.3.33" + resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.33.tgz#570d3a0b99ac995360e3136fd6045113b1bd236f" + integrity sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw== + dependencies: + "@types/node" "*" + +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + +"@types/ws@^8.5.1": + version "8.5.5" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.5.tgz#af587964aa06682702ee6dcbc7be41a80e4b28eb" + integrity sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg== + dependencies: + "@types/node" "*" + +"@types/yargs-parser@*": + version "21.0.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" + integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== + +"@types/yargs@^17.0.8": + version "17.0.24" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.24.tgz#b3ef8d50ad4aa6aecf6ddc97c580a00f5aa11902" + integrity sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw== + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@^4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" + integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg== + dependencies: + "@typescript-eslint/experimental-utils" "4.33.0" + "@typescript-eslint/scope-manager" "4.33.0" + debug "^4.3.1" + functional-red-black-tree "^1.0.1" + ignore "^5.1.8" + regexpp "^3.1.0" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/experimental-utils@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" + integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q== + dependencies: + "@types/json-schema" "^7.0.7" + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/parser@^4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" + integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA== + dependencies: + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" + debug "^4.3.1" + +"@typescript-eslint/scope-manager@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" + integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== + dependencies: + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" + +"@typescript-eslint/types@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" + integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== + +"@typescript-eslint/typescript-estree@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" + integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== + dependencies: + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" + debug "^4.3.1" + globby "^11.0.3" + is-glob "^4.0.1" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/visitor-keys@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" + integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== + dependencies: + "@typescript-eslint/types" "4.33.0" + eslint-visitor-keys "^2.0.0" + +"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24" + integrity sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + +"@webassemblyjs/floating-point-hex-parser@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" + integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== + +"@webassemblyjs/helper-api-error@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" + integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== + +"@webassemblyjs/helper-buffer@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz#b66d73c43e296fd5e88006f18524feb0f2c7c093" + integrity sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA== + +"@webassemblyjs/helper-numbers@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" + integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" + integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== + +"@webassemblyjs/helper-wasm-section@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz#ff97f3863c55ee7f580fd5c41a381e9def4aa577" + integrity sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + +"@webassemblyjs/ieee754@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" + integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" + integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" + integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== + +"@webassemblyjs/wasm-edit@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz#c72fa8220524c9b416249f3d94c2958dfe70ceab" + integrity sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-wasm-section" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + "@webassemblyjs/wasm-opt" "1.11.6" + "@webassemblyjs/wasm-parser" "1.11.6" + "@webassemblyjs/wast-printer" "1.11.6" + +"@webassemblyjs/wasm-gen@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz#fb5283e0e8b4551cc4e9c3c0d7184a65faf7c268" + integrity sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wasm-opt@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz#d9a22d651248422ca498b09aa3232a81041487c2" + integrity sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + "@webassemblyjs/wasm-parser" "1.11.6" + +"@webassemblyjs/wasm-parser@1.11.6", "@webassemblyjs/wasm-parser@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz#bb85378c527df824004812bbdb784eea539174a1" + integrity sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wast-printer@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz#a7bf8dd7e362aeb1668ff43f35cb849f188eff20" + integrity sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@xtuc/long" "4.2.2" + +"@webpack-cli/configtest@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-2.1.1.tgz#3b2f852e91dac6e3b85fb2a314fb8bef46d94646" + integrity sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw== + +"@webpack-cli/info@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-2.0.2.tgz#cc3fbf22efeb88ff62310cf885c5b09f44ae0fdd" + integrity sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A== + +"@webpack-cli/serve@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e" + integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ== + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +acorn-import-assertions@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" + integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== + +acorn-jsx@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^7.4.0: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +acorn@^8.7.1, acorn@^8.8.2: + version "8.10.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" + integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== + +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + +ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv-keywords@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== + dependencies: + fast-deep-equal "^3.1.3" + +ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.0, ajv@^8.0.1, ajv@^8.9.0: + version "8.12.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" + integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +ansi-colors@^4.1.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-html-community@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41" + integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +anymatch@^3.0.3, anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +array-flatten@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +babel-eslint@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" + integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.7.0" + "@babel/traverse" "^7.7.0" + "@babel/types" "^7.7.0" + eslint-visitor-keys "^1.0.0" + resolve "^1.12.0" + +babel-helper-evaluate-path@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz#a62fa9c4e64ff7ea5cea9353174ef023a900a67c" + integrity sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA== + +babel-helper-flip-expressions@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.4.3.tgz#3696736a128ac18bc25254b5f40a22ceb3c1d3fd" + integrity sha512-rSrkRW4YQ2ETCWww9gbsWk4N0x1BOtln349Tk0dlCS90oT68WMLyGR7WvaMp3eAnsVrCqdUtC19lo1avyGPejA== + +babel-helper-is-nodes-equiv@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz#34e9b300b1479ddd98ec77ea0bbe9342dfe39684" + integrity sha512-ri/nsMFVRqXn7IyT5qW4/hIAGQxuYUFHa3qsxmPtbk6spZQcYlyDogfVpNm2XYOslH/ULS4VEJGUqQX5u7ACQw== + +babel-helper-is-void-0@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-helper-is-void-0/-/babel-helper-is-void-0-0.4.3.tgz#7d9c01b4561e7b95dbda0f6eee48f5b60e67313e" + integrity sha512-07rBV0xPRM3TM5NVJEOQEkECX3qnHDjaIbFvWYPv+T1ajpUiVLiqTfC+MmiZxY5KOL/Ec08vJdJD9kZiP9UkUg== + +babel-helper-mark-eval-scopes@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz#d244a3bef9844872603ffb46e22ce8acdf551562" + integrity sha512-+d/mXPP33bhgHkdVOiPkmYoeXJ+rXRWi7OdhwpyseIqOS8CmzHQXHUp/+/Qr8baXsT0kjGpMHHofHs6C3cskdA== + +babel-helper-remove-or-void@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz#a4f03b40077a0ffe88e45d07010dee241ff5ae60" + integrity sha512-eYNceYtcGKpifHDir62gHJadVXdg9fAhuZEXiRQnJJ4Yi4oUTpqpNY//1pM4nVyjjDMPYaC2xSf0I+9IqVzwdA== + +babel-helper-to-multiple-sequence-expressions@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz#a3f924e3561882d42fcf48907aa98f7979a4588d" + integrity sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA== + +babel-jest@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.6.2.tgz#cada0a59e07f5acaeb11cbae7e3ba92aec9c1126" + integrity sha512-BYCzImLos6J3BH/+HvUCHG1dTf2MzmAB4jaVxHV+29RZLjR29XuYTmsf2sdDwkrb+FczkGo3kOhE7ga6sI0P4A== + dependencies: + "@jest/transform" "^29.6.2" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.5.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-loader@^9.1.3: + version "9.1.3" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-9.1.3.tgz#3d0e01b4e69760cc694ee306fe16d358aa1c6f9a" + integrity sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw== + dependencies: + find-cache-dir "^4.0.0" + schema-utils "^4.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz#a97db437936f441ec196990c9738d4b88538618a" + integrity sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-plugin-minify-builtins@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.5.0.tgz#31eb82ed1a0d0efdc31312f93b6e4741ce82c36b" + integrity sha512-wpqbN7Ov5hsNwGdzuzvFcjgRlzbIeVv1gMIlICbPj0xkexnfoIDe7q+AZHMkQmAE/F9R5jkrB6TLfTegImlXag== + +babel-plugin-minify-constant-folding@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.5.0.tgz#f84bc8dbf6a561e5e350ff95ae216b0ad5515b6e" + integrity sha512-Vj97CTn/lE9hR1D+jKUeHfNy+m1baNiJ1wJvoGyOBUx7F7kJqDZxr9nCHjO/Ad+irbR3HzR6jABpSSA29QsrXQ== + dependencies: + babel-helper-evaluate-path "^0.5.0" + +babel-plugin-minify-dead-code-elimination@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.2.tgz#f386ceec77a80cc4e76022a04c21b7d68e0aa5eb" + integrity sha512-krq9Lwi0QIzyAlcNBXTL4usqUvevB4BzktdEsb8srcXC1AaYqRJiAQw6vdKdJSaXbz6snBvziGr6ch/aoRCfpA== + dependencies: + babel-helper-evaluate-path "^0.5.0" + babel-helper-mark-eval-scopes "^0.4.3" + babel-helper-remove-or-void "^0.4.3" + lodash "^4.17.11" + +babel-plugin-minify-flip-comparisons@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.4.3.tgz#00ca870cb8f13b45c038b3c1ebc0f227293c965a" + integrity sha512-8hNwgLVeJzpeLVOVArag2DfTkbKodzOHU7+gAZ8mGBFGPQHK6uXVpg3jh5I/F6gfi5Q5usWU2OKcstn1YbAV7A== + dependencies: + babel-helper-is-void-0 "^0.4.3" + +babel-plugin-minify-guarded-expressions@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.4.tgz#818960f64cc08aee9d6c75bec6da974c4d621135" + integrity sha512-RMv0tM72YuPPfLT9QLr3ix9nwUIq+sHT6z8Iu3sLbqldzC1Dls8DPCywzUIzkTx9Zh1hWX4q/m9BPoPed9GOfA== + dependencies: + babel-helper-evaluate-path "^0.5.0" + babel-helper-flip-expressions "^0.4.3" + +babel-plugin-minify-infinity@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.4.3.tgz#dfb876a1b08a06576384ef3f92e653ba607b39ca" + integrity sha512-X0ictxCk8y+NvIf+bZ1HJPbVZKMlPku3lgYxPmIp62Dp8wdtbMLSekczty3MzvUOlrk5xzWYpBpQprXUjDRyMA== + +babel-plugin-minify-mangle-names@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.1.tgz#3dfba7f4e649ff37a767542ea0d1093bee3bb155" + integrity sha512-8KMichAOae2FHlipjNDTo2wz97MdEb2Q0jrn4NIRXzHH7SJ3c5TaNNBkeTHbk9WUsMnqpNUx949ugM9NFWewzw== + dependencies: + babel-helper-mark-eval-scopes "^0.4.3" + +babel-plugin-minify-numeric-literals@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.4.3.tgz#8e4fd561c79f7801286ff60e8c5fd9deee93c0bc" + integrity sha512-5D54hvs9YVuCknfWywq0eaYDt7qYxlNwCqW9Ipm/kYeS9gYhJd0Rr/Pm2WhHKJ8DC6aIlDdqSBODSthabLSX3A== + +babel-plugin-minify-replace@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.5.0.tgz#d3e2c9946c9096c070efc96761ce288ec5c3f71c" + integrity sha512-aXZiaqWDNUbyNNNpWs/8NyST+oU7QTpK7J9zFEFSA0eOmtUNMU3fczlTTTlnCxHmq/jYNFEmkkSG3DDBtW3Y4Q== + +babel-plugin-minify-simplify@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.5.1.tgz#f21613c8b95af3450a2ca71502fdbd91793c8d6a" + integrity sha512-OSYDSnoCxP2cYDMk9gxNAed6uJDiDz65zgL6h8d3tm8qXIagWGMLWhqysT6DY3Vs7Fgq7YUDcjOomhVUb+xX6A== + dependencies: + babel-helper-evaluate-path "^0.5.0" + babel-helper-flip-expressions "^0.4.3" + babel-helper-is-nodes-equiv "^0.0.1" + babel-helper-to-multiple-sequence-expressions "^0.5.0" + +babel-plugin-minify-type-constructors@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.4.3.tgz#1bc6f15b87f7ab1085d42b330b717657a2156500" + integrity sha512-4ADB0irJ/6BeXWHubjCJmrPbzhxDgjphBMjIjxCc25n4NGJ00NsYqwYt+F/OvE9RXx8KaSW7cJvp+iZX436tnQ== + dependencies: + babel-helper-is-void-0 "^0.4.3" + +babel-plugin-polyfill-corejs2@^0.4.5: + version "0.4.5" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz#8097b4cb4af5b64a1d11332b6fb72ef5e64a054c" + integrity sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg== + dependencies: + "@babel/compat-data" "^7.22.6" + "@babel/helper-define-polyfill-provider" "^0.4.2" + semver "^6.3.1" + +babel-plugin-polyfill-corejs3@^0.8.3: + version "0.8.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.3.tgz#b4f719d0ad9bb8e0c23e3e630c0c8ec6dd7a1c52" + integrity sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.4.2" + core-js-compat "^3.31.0" + +babel-plugin-polyfill-regenerator@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz#80d0f3e1098c080c8b5a65f41e9427af692dc326" + integrity sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.4.2" + +babel-plugin-transform-inline-consecutive-adds@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz#323d47a3ea63a83a7ac3c811ae8e6941faf2b0d1" + integrity sha512-8D104wbzzI5RlxeVPYeQb9QsUyepiH1rAO5hpPpQ6NPRgQLpIVwkS/Nbx944pm4K8Z+rx7CgjPsFACz/VCBN0Q== + +babel-plugin-transform-member-expression-literals@^6.9.4: + version "6.9.4" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz#37039c9a0c3313a39495faac2ff3a6b5b9d038bf" + integrity sha512-Xq9/Rarpj+bjOZSl1nBbZYETsNEDDJSrb6Plb1sS3/36FukWFLLRysgecva5KZECjUJTrJoQqjJgtWToaflk5Q== + +babel-plugin-transform-merge-sibling-variables@^6.9.5: + version "6.9.5" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.5.tgz#0b2faa9e027ef47d4e7502f77cd1a7f3a6dfbc7b" + integrity sha512-xj/KrWi6/uP+DrD844h66Qh2cZN++iugEIgH8QcIxhmZZPNP6VpOE9b4gP2FFW39xDAY43kCmYMM6U0QNKN8fw== + +babel-plugin-transform-minify-booleans@^6.9.4: + version "6.9.4" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz#acbb3e56a3555dd23928e4b582d285162dd2b198" + integrity sha512-9pW9ePng6DZpzGPalcrULuhSCcauGAbn8AeU3bE34HcDkGm8Ldt0ysjGkyb64f0K3T5ilV4mriayOVv5fg0ASA== + +babel-plugin-transform-property-literals@^6.9.4: + version "6.9.4" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz#98c1d21e255736573f93ece54459f6ce24985d39" + integrity sha512-Pf8JHTjTPxecqVyL6KSwD/hxGpoTZjiEgV7nCx0KFQsJYM0nuuoCajbg09KRmZWeZbJ5NGTySABYv8b/hY1eEA== + dependencies: + esutils "^2.0.2" + +babel-plugin-transform-regexp-constructors@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.4.3.tgz#58b7775b63afcf33328fae9a5f88fbd4fb0b4965" + integrity sha512-JjymDyEyRNhAoNFp09y/xGwYVYzT2nWTGrBrWaL6eCg2m+B24qH2jR0AA8V8GzKJTgC8NW6joJmc6nabvWBD/g== + +babel-plugin-transform-remove-console@^6.9.4: + version "6.9.4" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz#b980360c067384e24b357a588d807d3c83527780" + integrity sha512-88blrUrMX3SPiGkT1GnvVY8E/7A+k6oj3MNvUtTIxJflFzXTw1bHkuJ/y039ouhFMp2prRn5cQGzokViYi1dsg== + +babel-plugin-transform-remove-debugger@^6.9.4: + version "6.9.4" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz#42b727631c97978e1eb2d199a7aec84a18339ef2" + integrity sha512-Kd+eTBYlXfwoFzisburVwrngsrz4xh9I0ppoJnU/qlLysxVBRgI4Pj+dk3X8F5tDiehp3hhP8oarRMT9v2Z3lw== + +babel-plugin-transform-remove-undefined@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.5.0.tgz#80208b31225766c630c97fa2d288952056ea22dd" + integrity sha512-+M7fJYFaEE/M9CXa0/IRkDbiV3wRELzA1kKQFCJ4ifhrzLKn/9VCCgj9OFmYWwBd8IB48YdgPkHYtbYq+4vtHQ== + dependencies: + babel-helper-evaluate-path "^0.5.0" + +babel-plugin-transform-simplify-comparison-operators@^6.9.4: + version "6.9.4" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz#f62afe096cab0e1f68a2d753fdf283888471ceb9" + integrity sha512-GLInxhGAQWJ9YIdjwF6dAFlmh4U+kN8pL6Big7nkDzHoZcaDQOtBm28atEhQJq6m9GpAovbiGEShKqXv4BSp0A== + +babel-plugin-transform-undefined-to-void@^6.9.4: + version "6.9.4" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz#be241ca81404030678b748717322b89d0c8fe280" + integrity sha512-D2UbwxawEY1xVc9svYAUZQM2xarwSNXue2qDIx6CeV2EuMGaes/0su78zlIDIAgE7BvnMw4UpmSo9fDy+znghg== + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz#57bc8cc88097af7ff6a5ab59d1cd29d52a5916e2" + integrity sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg== + dependencies: + babel-plugin-jest-hoist "^29.5.0" + babel-preset-current-node-syntax "^1.0.0" + +babel-preset-minify@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/babel-preset-minify/-/babel-preset-minify-0.5.2.tgz#4d5be8b1c21d126ac403a3fd002d8b5fb7bb3c34" + integrity sha512-v4GL+kk0TfovbRIKZnC3HPbu2cAGmPAby7BsOmuPdMJfHV+4FVdsGXTH/OOGQRKYdjemBuL1+MsE6mobobhe9w== + dependencies: + babel-plugin-minify-builtins "^0.5.0" + babel-plugin-minify-constant-folding "^0.5.0" + babel-plugin-minify-dead-code-elimination "^0.5.2" + babel-plugin-minify-flip-comparisons "^0.4.3" + babel-plugin-minify-guarded-expressions "^0.4.4" + babel-plugin-minify-infinity "^0.4.3" + babel-plugin-minify-mangle-names "^0.5.1" + babel-plugin-minify-numeric-literals "^0.4.3" + babel-plugin-minify-replace "^0.5.0" + babel-plugin-minify-simplify "^0.5.1" + babel-plugin-minify-type-constructors "^0.4.3" + babel-plugin-transform-inline-consecutive-adds "^0.4.3" + babel-plugin-transform-member-expression-literals "^6.9.4" + babel-plugin-transform-merge-sibling-variables "^6.9.5" + babel-plugin-transform-minify-booleans "^6.9.4" + babel-plugin-transform-property-literals "^6.9.4" + babel-plugin-transform-regexp-constructors "^0.4.3" + babel-plugin-transform-remove-console "^6.9.4" + babel-plugin-transform-remove-debugger "^6.9.4" + babel-plugin-transform-remove-undefined "^0.5.0" + babel-plugin-transform-simplify-comparison-operators "^6.9.4" + babel-plugin-transform-undefined-to-void "^6.9.4" + lodash "^4.17.11" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw== + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +binascii@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/binascii/-/binascii-0.0.2.tgz#a7f8a8801dbccf8b1756b743daa0fee9e2d9e0ee" + integrity sha512-rA2CrUl1+6yKrn+XgLs8Hdy18OER1UW146nM+ixzhQXDY+Bd3ySkyIJGwF2a4I45JwbvF1mDL/nWkqBwpOcdBA== + +bls-signatures@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/bls-signatures/-/bls-signatures-2.0.2.tgz#a02cde31876d56dd4fb3c12b4e0b042a1b090a46" + integrity sha512-f60Oh1HRUfumYykCHaCzVRJKEXC2VlN+4YKl58fsFpovpx6/M023GdeK1sJqTH1eXFLqaERiCCPGWOhoubYtlA== + dependencies: + binascii "0.0.2" + +body-parser@1.20.1: + version "1.20.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" + integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== + dependencies: + bytes "3.1.2" + content-type "~1.0.4" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.1" + type-is "~1.6.18" + unpipe "1.0.0" + +bonjour-service@^1.0.11: + version "1.1.1" + resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.1.1.tgz#960948fa0e0153f5d26743ab15baf8e33752c135" + integrity sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg== + dependencies: + array-flatten "^2.1.2" + dns-equal "^1.0.0" + fast-deep-equal "^3.1.3" + multicast-dns "^7.2.5" + +boolbase@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.21.4, browserslist@^4.21.9: + version "4.21.10" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0" + integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ== + dependencies: + caniuse-lite "^1.0.30001517" + electron-to-chromium "^1.4.477" + node-releases "^2.0.13" + update-browserslist-db "^1.0.11" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camel-case@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" + integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== + dependencies: + pascal-case "^3.1.2" + tslib "^2.0.3" + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-api@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" + integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== + dependencies: + browserslist "^4.0.0" + caniuse-lite "^1.0.0" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001517: + version "1.0.30001519" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001519.tgz#3e7b8b8a7077e78b0eb054d69e6edf5c7df35601" + integrity sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg== + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +chokidar@^3.4.0, chokidar@^3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +ci-info@^3.2.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" + integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== + +cjs-module-lexer@^1.0.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" + integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== + +clean-css@^5.2.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.2.tgz#70ecc7d4d4114921f5d298349ff86a31a9975224" + integrity sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww== + dependencies: + source-map "~0.6.0" + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" + integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colord@^2.9.1: + version "2.9.3" + resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43" + integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw== + +colorette@^2.0.10, colorette@^2.0.14: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +commander@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + +commander@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + +commander@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + +common-path-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/common-path-prefix/-/common-path-prefix-3.0.0.tgz#7d007a7e07c58c4b4d5f433131a19141b29f11e0" + integrity sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w== + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +connect-history-api-fallback@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8" + integrity sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA== + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +convert-source-map@^1.1.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" + integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== + +core-js-compat@^3.31.0: + version "3.32.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.32.0.tgz#f41574b6893ab15ddb0ac1693681bd56c8550a90" + integrity sha512-7a9a3D1k4UCVKnLhrgALyFcP7YCsLOQIxPd0dKjf/6GuPcgyiGP70ewWdCGrSK7evyhymi0qO4EqCmSJofDeYw== + dependencies: + browserslist "^4.21.9" + +core-js@^2.6.5: + version "2.6.12" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" + integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +css-declaration-sorter@^6.3.1: + version "6.4.1" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz#28beac7c20bad7f1775be3a7129d7eae409a3a71" + integrity sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g== + +css-loader@^6.8.1: + version "6.8.1" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.8.1.tgz#0f8f52699f60f5e679eab4ec0fcd68b8e8a50a88" + integrity sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g== + dependencies: + icss-utils "^5.1.0" + postcss "^8.4.21" + postcss-modules-extract-imports "^3.0.0" + postcss-modules-local-by-default "^4.0.3" + postcss-modules-scope "^3.0.0" + postcss-modules-values "^4.0.0" + postcss-value-parser "^4.2.0" + semver "^7.3.8" + +css-minimizer-webpack-plugin@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-5.0.1.tgz#33effe662edb1a0bf08ad633c32fa75d0f7ec565" + integrity sha512-3caImjKFQkS+ws1TGcFn0V1HyDJFq1Euy589JlD6/3rV2kj+w7r5G9WDMgSHvpvXHNZ2calVypZWuEDQd9wfLg== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" + cssnano "^6.0.1" + jest-worker "^29.4.3" + postcss "^8.4.24" + schema-utils "^4.0.1" + serialize-javascript "^6.0.1" + +css-select@^4.1.3: + version "4.3.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b" + integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ== + dependencies: + boolbase "^1.0.0" + css-what "^6.0.1" + domhandler "^4.3.1" + domutils "^2.8.0" + nth-check "^2.0.1" + +css-select@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-5.1.0.tgz#b8ebd6554c3637ccc76688804ad3f6a6fdaea8a6" + integrity sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg== + dependencies: + boolbase "^1.0.0" + css-what "^6.1.0" + domhandler "^5.0.2" + domutils "^3.0.1" + nth-check "^2.0.1" + +css-tree@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.3.1.tgz#10264ce1e5442e8572fc82fbe490644ff54b5c20" + integrity sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw== + dependencies: + mdn-data "2.0.30" + source-map-js "^1.0.1" + +css-tree@~2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.2.1.tgz#36115d382d60afd271e377f9c5f67d02bd48c032" + integrity sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA== + dependencies: + mdn-data "2.0.28" + source-map-js "^1.0.1" + +css-what@^6.0.1, css-what@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" + integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +cssnano-preset-default@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-6.0.1.tgz#2a93247140d214ddb9f46bc6a3562fa9177fe301" + integrity sha512-7VzyFZ5zEB1+l1nToKyrRkuaJIx0zi/1npjvZfbBwbtNTzhLtlvYraK/7/uqmX2Wb2aQtd983uuGw79jAjLSuQ== + dependencies: + css-declaration-sorter "^6.3.1" + cssnano-utils "^4.0.0" + postcss-calc "^9.0.0" + postcss-colormin "^6.0.0" + postcss-convert-values "^6.0.0" + postcss-discard-comments "^6.0.0" + postcss-discard-duplicates "^6.0.0" + postcss-discard-empty "^6.0.0" + postcss-discard-overridden "^6.0.0" + postcss-merge-longhand "^6.0.0" + postcss-merge-rules "^6.0.1" + postcss-minify-font-values "^6.0.0" + postcss-minify-gradients "^6.0.0" + postcss-minify-params "^6.0.0" + postcss-minify-selectors "^6.0.0" + postcss-normalize-charset "^6.0.0" + postcss-normalize-display-values "^6.0.0" + postcss-normalize-positions "^6.0.0" + postcss-normalize-repeat-style "^6.0.0" + postcss-normalize-string "^6.0.0" + postcss-normalize-timing-functions "^6.0.0" + postcss-normalize-unicode "^6.0.0" + postcss-normalize-url "^6.0.0" + postcss-normalize-whitespace "^6.0.0" + postcss-ordered-values "^6.0.0" + postcss-reduce-initial "^6.0.0" + postcss-reduce-transforms "^6.0.0" + postcss-svgo "^6.0.0" + postcss-unique-selectors "^6.0.0" + +cssnano-utils@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-4.0.0.tgz#d1da885ec04003ab19505ff0e62e029708d36b08" + integrity sha512-Z39TLP+1E0KUcd7LGyF4qMfu8ZufI0rDzhdyAMsa/8UyNUU8wpS0fhdBxbQbv32r64ea00h4878gommRVg2BHw== + +cssnano@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-6.0.1.tgz#87c38c4cd47049c735ab756d7e77ac3ca855c008" + integrity sha512-fVO1JdJ0LSdIGJq68eIxOqFpIJrZqXUsBt8fkrBcztCQqAjQD51OhZp7tc0ImcbwXD4k7ny84QTV90nZhmqbkg== + dependencies: + cssnano-preset-default "^6.0.1" + lilconfig "^2.1.0" + +csso@^5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/csso/-/csso-5.0.5.tgz#f9b7fe6cc6ac0b7d90781bb16d5e9874303e2ca6" + integrity sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ== + dependencies: + css-tree "~2.2.0" + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +dedent@^1.0.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" + integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deepmerge@^4.2.2: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +default-gateway@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71" + integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg== + dependencies: + execa "^5.0.0" + +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +detect-node@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + +diff-sequences@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" + integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + integrity sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg== + +dns-packet@^5.2.2: + version "5.6.0" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.6.0.tgz#2202c947845c7a63c23ece58f2f70ff6ab4c2f7d" + integrity sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ== + dependencies: + "@leichtgewicht/ip-codec" "^2.0.1" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dom-converter@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" + integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== + dependencies: + utila "~0.4" + +dom-serializer@^1.0.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30" + integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.2.0" + entities "^2.0.0" + +dom-serializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" + integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + entities "^4.2.0" + +domelementtype@^2.0.1, domelementtype@^2.2.0, domelementtype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" + integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== + +domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" + integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== + dependencies: + domelementtype "^2.2.0" + +domhandler@^5.0.2, domhandler@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" + integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== + dependencies: + domelementtype "^2.3.0" + +domutils@^2.5.2, domutils@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" + integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + +domutils@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e" + integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA== + dependencies: + dom-serializer "^2.0.0" + domelementtype "^2.3.0" + domhandler "^5.0.3" + +dot-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +electron-to-chromium@^1.4.477: + version "1.4.490" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.490.tgz#d99286f6e915667fa18ea4554def1aa60eb4d5f1" + integrity sha512-6s7NVJz+sATdYnIwhdshx/N/9O6rvMxmhVoDSDFdj6iA45gHR8EQje70+RYsF4GeB+k0IeNSBnP7yG9ZXJFr7A== + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +enhanced-resolve@^5.15.0: + version "5.15.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" + integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +enquirer@^2.3.5: + version "2.4.1" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" + integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== + dependencies: + ansi-colors "^4.1.1" + strip-ansi "^6.0.1" + +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + +entities@^4.2.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + +envinfo@^7.7.3: + version "7.10.0" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.10.0.tgz#55146e3909cc5fe63c22da63fb15b05aeac35b13" + integrity sha512-ZtUjZO6l5mwTHvc1L9+1q5p/R3wTopcfqMW8r5t8SJSKqeVI/LtajORwRFEKpEFuekjD0VBjwu1HMxL4UalIRw== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-module-lexer@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.3.0.tgz#6be9c9e0b4543a60cd166ff6f8b4e9dae0b0c16f" + integrity sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA== + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-scope@5.1.1, eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint@^7.32.0: + version "7.32.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" + integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== + dependencies: + "@babel/code-frame" "7.12.11" + "@eslint/eslintrc" "^0.4.3" + "@humanwhocodes/config-array" "^0.5.0" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + enquirer "^2.3.5" + escape-string-regexp "^4.0.0" + eslint-scope "^5.1.1" + eslint-utils "^2.1.0" + eslint-visitor-keys "^2.0.0" + espree "^7.3.1" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.1.2" + globals "^13.6.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^6.0.9" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^7.3.0, espree@^7.3.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" + integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== + dependencies: + acorn "^7.4.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^1.3.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.4.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expect@^29.0.0, expect@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.6.2.tgz#7b08e83eba18ddc4a2cf62b5f2d1918f5cd84521" + integrity sha512-iAErsLxJ8C+S02QbLAwgSGSezLQK+XXRDt8IuFXFpwCNw2ECmzZSmjKcCaFVp5VRMk+WAvz6h6jokzEzBFZEuA== + dependencies: + "@jest/expect-utils" "^29.6.2" + "@types/node" "*" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.6.2" + jest-message-util "^29.6.2" + jest-util "^29.6.2" + +express@^4.17.3: + version "4.18.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" + integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.1" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.5.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.2.0" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.11.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== + 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.4" + +fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastest-levenshtein@^1.0.12: + version "1.0.16" + resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" + integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== + +fastq@^1.6.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + dependencies: + reusify "^1.0.4" + +faye-websocket@^0.11.3: + version "0.11.4" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" + integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== + dependencies: + websocket-driver ">=0.5.1" + +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +file-loader@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d" + integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw== + dependencies: + loader-utils "^2.0.0" + schema-utils "^3.0.0" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +find-cache-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-4.0.0.tgz#a30ee0448f81a3990708f6453633c733e2f6eec2" + integrity sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg== + dependencies: + common-path-prefix "^3.0.0" + pkg-dir "^7.0.0" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-6.3.0.tgz#2abab3d3280b2dc7ac10199ef324c4e002c8c790" + integrity sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw== + dependencies: + locate-path "^7.1.0" + path-exists "^5.0.0" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.7" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + +follow-redirects@^1.0.0: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +fs-monkey@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.4.tgz#ee8c1b53d3fe8bb7e5d2c5c5dfc0168afdd2f747" + integrity sha512-INM/fWAxMICjttnD0DX1rBvinKskj5G1w+oy/pnm9u/tSlnBrzFonJMcalKJ30P8RRsPzKcCG7Q8l0jx5Fh9YQ== + +fs-readdir-recursive@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" + integrity sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@^2.3.2, fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" + integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-proto "^1.0.1" + has-symbols "^1.0.3" + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@^7.1.3, glob@^7.1.4, glob@^7.2.0: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.6.0, globals@^13.9.0: + version "13.20.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" + integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + dependencies: + type-fest "^0.20.2" + +globby@^11.0.3: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +graceful-fs@^4.1.2, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +handle-thing@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" + integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +he@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ== + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +html-entities@^2.3.2: + version "2.4.0" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.4.0.tgz#edd0cee70402584c8c76cc2c0556db09d1f45061" + integrity sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ== + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +html-minifier-terser@^6.0.2: + version "6.1.0" + resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#bfc818934cc07918f6b3669f5774ecdfd48f32ab" + integrity sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw== + dependencies: + camel-case "^4.1.2" + clean-css "^5.2.2" + commander "^8.3.0" + he "^1.2.0" + param-case "^3.0.4" + relateurl "^0.2.7" + terser "^5.10.0" + +html-webpack-plugin@^5.5.3: + version "5.5.3" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz#72270f4a78e222b5825b296e5e3e1328ad525a3e" + integrity sha512-6YrDKTuqaP/TquFH7h4srYWsZx+x6k6+FbsTm0ziCwGHDP78Unr1r9F/H4+sGmMbX08GQcJ+K64x55b+7VM/jg== + dependencies: + "@types/html-minifier-terser" "^6.0.0" + html-minifier-terser "^6.0.2" + lodash "^4.17.21" + pretty-error "^4.0.0" + tapable "^2.0.0" + +htmlparser2@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" + integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.0.0" + domutils "^2.5.2" + entities "^2.0.0" + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw== + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-parser-js@>=0.5.1: + version "0.5.8" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.8.tgz#af23090d9ac4e24573de6f6aecc9d84a48bf20e3" + integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== + +http-proxy-middleware@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz#e1a4dd6979572c7ab5a4e4b55095d1f32a74963f" + integrity sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw== + dependencies: + "@types/http-proxy" "^1.17.8" + http-proxy "^1.18.1" + is-glob "^4.0.1" + is-plain-obj "^3.0.0" + micromatch "^4.0.2" + +http-proxy@^1.18.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +icss-utils@^5.0.0, icss-utils@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" + integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +ignore@^5.1.8, ignore@^5.2.0: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== + +interpret@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4" + integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ== + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +ipaddr.js@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.1.0.tgz#2119bc447ff8c257753b196fc5f1ce08a4cdf39f" + integrity sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-core-module@^2.13.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" + integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== + dependencies: + has "^1.0.3" + +is-docker@^2.0.0, is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" + integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== + +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + +istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.1.6" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.6.tgz#2544bcab4768154281a2f0870471902704ccaa1a" + integrity sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.5.0.tgz#e88786dca8bf2aa899ec4af7644e16d9dcf9b23e" + integrity sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag== + dependencies: + execa "^5.0.0" + p-limit "^3.1.0" + +jest-circus@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.6.2.tgz#1e6ffca60151ac66cad63fce34f443f6b5bb4258" + integrity sha512-G9mN+KOYIUe2sB9kpJkO9Bk18J4dTDArNFPwoZ7WKHKel55eKIS/u2bLthxgojwlf9NLCVQfgzM/WsOVvoC6Fw== + dependencies: + "@jest/environment" "^29.6.2" + "@jest/expect" "^29.6.2" + "@jest/test-result" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^1.0.0" + is-generator-fn "^2.0.0" + jest-each "^29.6.2" + jest-matcher-utils "^29.6.2" + jest-message-util "^29.6.2" + jest-runtime "^29.6.2" + jest-snapshot "^29.6.2" + jest-util "^29.6.2" + p-limit "^3.1.0" + pretty-format "^29.6.2" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.6.2.tgz#edb381763398d1a292cd1b636a98bfa5644b8fda" + integrity sha512-TT6O247v6dCEX2UGHGyflMpxhnrL0DNqP2fRTKYm3nJJpCTfXX3GCMQPGFjXDoj0i5/Blp3jriKXFgdfmbYB6Q== + dependencies: + "@jest/core" "^29.6.2" + "@jest/test-result" "^29.6.2" + "@jest/types" "^29.6.1" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^29.6.2" + jest-util "^29.6.2" + jest-validate "^29.6.2" + prompts "^2.0.1" + yargs "^17.3.1" + +jest-config@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.6.2.tgz#c68723f06b31ca5e63030686e604727d406cd7c3" + integrity sha512-VxwFOC8gkiJbuodG9CPtMRjBUNZEHxwfQXmIudSTzFWxaci3Qub1ddTRbFNQlD/zUeaifLndh/eDccFX4wCMQw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.6.2" + "@jest/types" "^29.6.1" + babel-jest "^29.6.2" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.6.2" + jest-environment-node "^29.6.2" + jest-get-type "^29.4.3" + jest-regex-util "^29.4.3" + jest-resolve "^29.6.2" + jest-runner "^29.6.2" + jest-util "^29.6.2" + jest-validate "^29.6.2" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.6.2" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.6.2.tgz#c36001e5543e82a0805051d3ceac32e6825c1c46" + integrity sha512-t+ST7CB9GX5F2xKwhwCf0TAR17uNDiaPTZnVymP9lw0lssa9vG+AFyDZoeIHStU3WowFFwT+ky+er0WVl2yGhA== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.4.3" + jest-get-type "^29.4.3" + pretty-format "^29.6.2" + +jest-docblock@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.4.3.tgz#90505aa89514a1c7dceeac1123df79e414636ea8" + integrity sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg== + dependencies: + detect-newline "^3.0.0" + +jest-each@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.6.2.tgz#c9e4b340bcbe838c73adf46b76817b15712d02ce" + integrity sha512-MsrsqA0Ia99cIpABBc3izS1ZYoYfhIy0NNWqPSE0YXbQjwchyt6B1HD2khzyPe1WiJA7hbxXy77ZoUQxn8UlSw== + dependencies: + "@jest/types" "^29.6.1" + chalk "^4.0.0" + jest-get-type "^29.4.3" + jest-util "^29.6.2" + pretty-format "^29.6.2" + +jest-environment-node@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.6.2.tgz#a9ea2cabff39b08eca14ccb32c8ceb924c8bb1ad" + integrity sha512-YGdFeZ3T9a+/612c5mTQIllvWkddPbYcN2v95ZH24oWMbGA4GGS2XdIF92QMhUhvrjjuQWYgUGW2zawOyH63MQ== + dependencies: + "@jest/environment" "^29.6.2" + "@jest/fake-timers" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + jest-mock "^29.6.2" + jest-util "^29.6.2" + +jest-get-type@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5" + integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg== + +jest-haste-map@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.6.2.tgz#298c25ea5255cfad8b723179d4295cf3a50a70d1" + integrity sha512-+51XleTDAAysvU8rT6AnS1ZJ+WHVNqhj1k6nTvN2PYP+HjU3kqlaKQ1Lnw3NYW3bm2r8vq82X0Z1nDDHZMzHVA== + dependencies: + "@jest/types" "^29.6.1" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.4.3" + jest-util "^29.6.2" + jest-worker "^29.6.2" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.6.2.tgz#e2b307fee78cab091c37858a98c7e1d73cdf5b38" + integrity sha512-aNqYhfp5uYEO3tdWMb2bfWv6f0b4I0LOxVRpnRLAeque2uqOVVMLh6khnTcE2qJ5wAKop0HcreM1btoysD6bPQ== + dependencies: + jest-get-type "^29.4.3" + pretty-format "^29.6.2" + +jest-matcher-utils@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.6.2.tgz#39de0be2baca7a64eacb27291f0bd834fea3a535" + integrity sha512-4LiAk3hSSobtomeIAzFTe+N8kL6z0JtF3n6I4fg29iIW7tt99R7ZcIFW34QkX+DuVrf+CUe6wuVOpm7ZKFJzZQ== + dependencies: + chalk "^4.0.0" + jest-diff "^29.6.2" + jest-get-type "^29.4.3" + pretty-format "^29.6.2" + +jest-message-util@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.6.2.tgz#af7adc2209c552f3f5ae31e77cf0a261f23dc2bb" + integrity sha512-vnIGYEjoPSuRqV8W9t+Wow95SDp6KPX2Uf7EoeG9G99J2OVh7OSwpS4B6J0NfpEIpfkBNHlBZpA2rblEuEFhZQ== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.1" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.6.2" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.6.2.tgz#ef9c9b4d38c34a2ad61010a021866dad41ce5e00" + integrity sha512-hoSv3lb3byzdKfwqCuT6uTscan471GUECqgNYykg6ob0yiAw3zYc7OrPnI9Qv8Wwoa4lC7AZ9hyS4AiIx5U2zg== + dependencies: + "@jest/types" "^29.6.1" + "@types/node" "*" + jest-util "^29.6.2" + +jest-pnp-resolver@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.4.3.tgz#a42616141e0cae052cfa32c169945d00c0aa0bb8" + integrity sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg== + +jest-resolve-dependencies@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.6.2.tgz#36435269b6672c256bcc85fb384872c134cc4cf2" + integrity sha512-LGqjDWxg2fuQQm7ypDxduLu/m4+4Lb4gczc13v51VMZbVP5tSBILqVx8qfWcsdP8f0G7aIqByIALDB0R93yL+w== + dependencies: + jest-regex-util "^29.4.3" + jest-snapshot "^29.6.2" + +jest-resolve@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.6.2.tgz#f18405fe4b50159b7b6d85e81f6a524d22afb838" + integrity sha512-G/iQUvZWI5e3SMFssc4ug4dH0aZiZpsDq9o1PtXTV1210Ztyb2+w+ZgQkB3iOiC5SmAEzJBOHWz6Hvrd+QnNPw== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.6.2" + jest-pnp-resolver "^1.2.2" + jest-util "^29.6.2" + jest-validate "^29.6.2" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + +jest-runner@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.6.2.tgz#89e8e32a8fef24781a7c4c49cd1cb6358ac7fc01" + integrity sha512-wXOT/a0EspYgfMiYHxwGLPCZfC0c38MivAlb2lMEAlwHINKemrttu1uSbcGbfDV31sFaPWnWJPmb2qXM8pqZ4w== + dependencies: + "@jest/console" "^29.6.2" + "@jest/environment" "^29.6.2" + "@jest/test-result" "^29.6.2" + "@jest/transform" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.4.3" + jest-environment-node "^29.6.2" + jest-haste-map "^29.6.2" + jest-leak-detector "^29.6.2" + jest-message-util "^29.6.2" + jest-resolve "^29.6.2" + jest-runtime "^29.6.2" + jest-util "^29.6.2" + jest-watcher "^29.6.2" + jest-worker "^29.6.2" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.6.2.tgz#692f25e387f982e89ab83270e684a9786248e545" + integrity sha512-2X9dqK768KufGJyIeLmIzToDmsN0m7Iek8QNxRSI/2+iPFYHF0jTwlO3ftn7gdKd98G/VQw9XJCk77rbTGZnJg== + dependencies: + "@jest/environment" "^29.6.2" + "@jest/fake-timers" "^29.6.2" + "@jest/globals" "^29.6.2" + "@jest/source-map" "^29.6.0" + "@jest/test-result" "^29.6.2" + "@jest/transform" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.6.2" + jest-message-util "^29.6.2" + jest-mock "^29.6.2" + jest-regex-util "^29.4.3" + jest-resolve "^29.6.2" + jest-snapshot "^29.6.2" + jest-util "^29.6.2" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.6.2.tgz#9b431b561a83f2bdfe041e1cab8a6becdb01af9c" + integrity sha512-1OdjqvqmRdGNvWXr/YZHuyhh5DeaLp1p/F8Tht/MrMw4Kr1Uu/j4lRG+iKl1DAqUJDWxtQBMk41Lnf/JETYBRA== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.6.2" + "@jest/transform" "^29.6.2" + "@jest/types" "^29.6.1" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.6.2" + graceful-fs "^4.2.9" + jest-diff "^29.6.2" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.6.2" + jest-message-util "^29.6.2" + jest-util "^29.6.2" + natural-compare "^1.4.0" + pretty-format "^29.6.2" + semver "^7.5.3" + +jest-util@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.6.2.tgz#8a052df8fff2eebe446769fd88814521a517664d" + integrity sha512-3eX1qb6L88lJNCFlEADKOkjpXJQyZRiavX1INZ4tRnrBVr2COd3RgcTLyUiEXMNBlDU/cgYq6taUS0fExrWW4w== + dependencies: + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.6.2.tgz#25d972af35b2415b83b1373baf1a47bb266c1082" + integrity sha512-vGz0yMN5fUFRRbpJDPwxMpgSXW1LDKROHfBopAvDcmD6s+B/s8WJrwi+4bfH4SdInBA5C3P3BI19dBtKzx1Arg== + dependencies: + "@jest/types" "^29.6.1" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.4.3" + leven "^3.1.0" + pretty-format "^29.6.2" + +jest-watcher@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.6.2.tgz#77c224674f0620d9f6643c4cfca186d8893ca088" + integrity sha512-GZitlqkMkhkefjfN/p3SJjrDaxPflqxEAv3/ik10OirZqJGYH5rPiIsgVcfof0Tdqg3shQGdEIxDBx+B4tuLzA== + dependencies: + "@jest/test-result" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.6.2" + string-length "^4.0.1" + +jest-worker@^27.4.5: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest-worker@^29.4.3, jest-worker@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.6.2.tgz#682fbc4b6856ad0aa122a5403c6d048b83f3fb44" + integrity sha512-l3ccBOabTdkng8I/ORCkADz4eSMKejTYv1vB/Z83UiubqhC1oQ5Li6dWCyqOIvSifGjUBxuvxvlm6KGK2DtuAQ== + dependencies: + "@types/node" "*" + jest-util "^29.6.2" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.6.2.tgz#3bd55b9fd46a161b2edbdf5f1d1bd0d1eab76c42" + integrity sha512-8eQg2mqFbaP7CwfsTpCxQ+sHzw1WuNWL5UUvjnWP4hx2riGz9fPSzYOaU5q8/GqWn1TfgZIVTqYJygbGbWAANg== + dependencies: + "@jest/core" "^29.6.2" + "@jest/types" "^29.6.1" + import-local "^3.0.2" + jest-cli "^29.6.2" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== + +json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^2.1.2, json5@^2.2.2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +launch-editor@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.6.0.tgz#4c0c1a6ac126c572bd9ff9a30da1d2cae66defd7" + integrity sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ== + dependencies: + picocolors "^1.0.0" + shell-quote "^1.7.3" + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lilconfig@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" + integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +loader-runner@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== + +loader-utils@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c" + integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-7.2.0.tgz#69cb1779bd90b35ab1e771e1f2f89a202c2a8a8a" + integrity sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA== + dependencies: + p-locate "^6.0.0" + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.truncate@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" + integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== + +lodash@^4.17.11, lodash@^4.17.20, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +make-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +mdn-data@2.0.28: + version "2.0.28" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.28.tgz#5ec48e7bef120654539069e1ae4ddc81ca490eba" + integrity sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g== + +mdn-data@2.0.30: + version "2.0.30" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc" + integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +memfs@^3.4.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.6.0.tgz#d7a2110f86f79dd950a8b6df6d57bc984aa185f6" + integrity sha512-EGowvkkgbMcIChjMTMkESFDbZeSh8xZ7kNSF0hAiAN4Jh6jgHCRS0Ga/+C8y6Au+oqpezRHCfPsmJ2+DwAgiwQ== + dependencies: + fs-monkey "^1.0.4" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +micromatch@^4.0.2, micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mini-css-extract-plugin@^2.7.6: + version "2.7.6" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz#282a3d38863fddcd2e0c220aaed5b90bc156564d" + integrity sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw== + dependencies: + schema-utils "^4.0.0" + +minimalistic-assert@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multicast-dns@^7.2.5: + version "7.2.5" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.5.tgz#77eb46057f4d7adbd16d9290fa7299f6fa64cced" + integrity sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg== + dependencies: + dns-packet "^5.2.2" + thunky "^1.0.2" + +nanoid@^3.3.6: + version "3.3.6" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" + integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + +node-forge@^1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" + integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.13: + version "2.0.13" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" + integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +nth-check@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" + integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== + dependencies: + boolbase "^1.0.0" + +object-inspect@^1.9.0: + version "1.12.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +open@^8.0.9: + version "8.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" + integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + +optionator@^0.9.1: + version "0.9.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-limit@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-4.0.0.tgz#914af6544ed32bfa54670b061cafcbd04984b644" + integrity sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ== + dependencies: + yocto-queue "^1.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-6.0.0.tgz#3da9a49d4934b901089dca3302fa65dc5a05c04f" + integrity sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw== + dependencies: + p-limit "^4.0.0" + +p-retry@^4.5.0: + version "4.6.2" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16" + integrity sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ== + dependencies: + "@types/retry" "0.12.0" + retry "^0.13.1" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +param-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" + integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parseurl@~1.3.2, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascal-case@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" + integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-exists@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-5.0.0.tgz#a6aad9489200b21fab31e49cf09277e5116fb9e7" + integrity sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pirates@^4.0.4: + version "4.0.6" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +pkg-dir@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-7.0.0.tgz#8f0c08d6df4476756c5ff29b3282d0bab7517d11" + integrity sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA== + dependencies: + find-up "^6.3.0" + +postcss-calc@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-9.0.1.tgz#a744fd592438a93d6de0f1434c572670361eb6c6" + integrity sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ== + dependencies: + postcss-selector-parser "^6.0.11" + postcss-value-parser "^4.2.0" + +postcss-colormin@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-6.0.0.tgz#d4250652e952e1c0aca70c66942da93d3cdeaafe" + integrity sha512-EuO+bAUmutWoZYgHn2T1dG1pPqHU6L4TjzPlu4t1wZGXQ/fxV16xg2EJmYi0z+6r+MGV1yvpx1BHkUaRrPa2bw== + dependencies: + browserslist "^4.21.4" + caniuse-api "^3.0.0" + colord "^2.9.1" + postcss-value-parser "^4.2.0" + +postcss-convert-values@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-6.0.0.tgz#ec94a954957e5c3f78f0e8f65dfcda95280b8996" + integrity sha512-U5D8QhVwqT++ecmy8rnTb+RL9n/B806UVaS3m60lqle4YDFcpbS3ae5bTQIh3wOGUSDHSEtMYLs/38dNG7EYFw== + dependencies: + browserslist "^4.21.4" + postcss-value-parser "^4.2.0" + +postcss-discard-comments@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-6.0.0.tgz#9ca335e8b68919f301b24ba47dde226a42e535fe" + integrity sha512-p2skSGqzPMZkEQvJsgnkBhCn8gI7NzRH2683EEjrIkoMiwRELx68yoUJ3q3DGSGuQ8Ug9Gsn+OuDr46yfO+eFw== + +postcss-discard-duplicates@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.0.tgz#c26177a6c33070922e67e9a92c0fd23d443d1355" + integrity sha512-bU1SXIizMLtDW4oSsi5C/xHKbhLlhek/0/yCnoMQany9k3nPBq+Ctsv/9oMmyqbR96HYHxZcHyK2HR5P/mqoGA== + +postcss-discard-empty@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-6.0.0.tgz#06c1c4fce09e22d2a99e667c8550eb8a3a1b9aee" + integrity sha512-b+h1S1VT6dNhpcg+LpyiUrdnEZfICF0my7HAKgJixJLW7BnNmpRH34+uw/etf5AhOlIhIAuXApSzzDzMI9K/gQ== + +postcss-discard-overridden@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-6.0.0.tgz#49c5262db14e975e349692d9024442de7cd8e234" + integrity sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw== + +postcss-merge-longhand@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-6.0.0.tgz#6f627b27db939bce316eaa97e22400267e798d69" + integrity sha512-4VSfd1lvGkLTLYcxFuISDtWUfFS4zXe0FpF149AyziftPFQIWxjvFSKhA4MIxMe4XM3yTDgQMbSNgzIVxChbIg== + dependencies: + postcss-value-parser "^4.2.0" + stylehacks "^6.0.0" + +postcss-merge-rules@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-6.0.1.tgz#39f165746404e646c0f5c510222ccde4824a86aa" + integrity sha512-a4tlmJIQo9SCjcfiCcCMg/ZCEe0XTkl/xK0XHBs955GWg9xDX3NwP9pwZ78QUOWB8/0XCjZeJn98Dae0zg6AAw== + dependencies: + browserslist "^4.21.4" + caniuse-api "^3.0.0" + cssnano-utils "^4.0.0" + postcss-selector-parser "^6.0.5" + +postcss-minify-font-values@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-6.0.0.tgz#68d4a028f9fa5f61701974724b2cc9445d8e6070" + integrity sha512-zNRAVtyh5E8ndZEYXA4WS8ZYsAp798HiIQ1V2UF/C/munLp2r1UGHwf1+6JFu7hdEhJFN+W1WJQKBrtjhFgEnA== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-minify-gradients@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-6.0.0.tgz#22b5c88cc63091dadbad34e31ff958404d51d679" + integrity sha512-wO0F6YfVAR+K1xVxF53ueZJza3L+R3E6cp0VwuXJQejnNUH0DjcAFe3JEBeTY1dLwGa0NlDWueCA1VlEfiKgAA== + dependencies: + colord "^2.9.1" + cssnano-utils "^4.0.0" + postcss-value-parser "^4.2.0" + +postcss-minify-params@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-6.0.0.tgz#2b3a85a9e3b990d7a16866f430f5fd1d5961b539" + integrity sha512-Fz/wMQDveiS0n5JPcvsMeyNXOIMrwF88n7196puSuQSWSa+/Ofc1gDOSY2xi8+A4PqB5dlYCKk/WfqKqsI+ReQ== + dependencies: + browserslist "^4.21.4" + cssnano-utils "^4.0.0" + postcss-value-parser "^4.2.0" + +postcss-minify-selectors@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-6.0.0.tgz#5046c5e8680a586e5a0cad52cc9aa36d6be5bda2" + integrity sha512-ec/q9JNCOC2CRDNnypipGfOhbYPuUkewGwLnbv6omue/PSASbHSU7s6uSQ0tcFRVv731oMIx8k0SP4ZX6be/0g== + dependencies: + postcss-selector-parser "^6.0.5" + +postcss-modules-extract-imports@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" + integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== + +postcss-modules-local-by-default@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz#b08eb4f083050708998ba2c6061b50c2870ca524" + integrity sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA== + dependencies: + icss-utils "^5.0.0" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.1.0" + +postcss-modules-scope@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" + integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg== + dependencies: + postcss-selector-parser "^6.0.4" + +postcss-modules-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" + integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== + dependencies: + icss-utils "^5.0.0" + +postcss-normalize-charset@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-6.0.0.tgz#36cc12457259064969fb96f84df491652a4b0975" + integrity sha512-cqundwChbu8yO/gSWkuFDmKrCZ2vJzDAocheT2JTd0sFNA4HMGoKMfbk2B+J0OmO0t5GUkiAkSM5yF2rSLUjgQ== + +postcss-normalize-display-values@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.0.tgz#8d2961415078644d8c6bbbdaf9a2fdd60f546cd4" + integrity sha512-Qyt5kMrvy7dJRO3OjF7zkotGfuYALETZE+4lk66sziWSPzlBEt7FrUshV6VLECkI4EN8Z863O6Nci4NXQGNzYw== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-positions@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-6.0.0.tgz#25b96df99a69f8925f730eaee0be74416865e301" + integrity sha512-mPCzhSV8+30FZyWhxi6UoVRYd3ZBJgTRly4hOkaSifo0H+pjDYcii/aVT4YE6QpOil15a5uiv6ftnY3rm0igPg== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-repeat-style@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.0.tgz#ddf30ad8762feb5b1eb97f39f251acd7b8353299" + integrity sha512-50W5JWEBiOOAez2AKBh4kRFm2uhrT3O1Uwdxz7k24aKtbD83vqmcVG7zoIwo6xI2FZ/HDlbrCopXhLeTpQib1A== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-string@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-6.0.0.tgz#948282647a51e409d69dde7910f0ac2ff97cb5d8" + integrity sha512-KWkIB7TrPOiqb8ZZz6homet2KWKJwIlysF5ICPZrXAylGe2hzX/HSf4NTX2rRPJMAtlRsj/yfkrWGavFuB+c0w== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-timing-functions@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.0.tgz#5f13e650b8c43351989fc5de694525cc2539841c" + integrity sha512-tpIXWciXBp5CiFs8sem90IWlw76FV4oi6QEWfQwyeREVwUy39VSeSqjAT7X0Qw650yAimYW5gkl2Gd871N5SQg== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-unicode@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.0.tgz#741b3310f874616bdcf07764f5503695d3604730" + integrity sha512-ui5crYkb5ubEUDugDc786L/Me+DXp2dLg3fVJbqyAl0VPkAeALyAijF2zOsnZyaS1HyfPuMH0DwyY18VMFVNkg== + dependencies: + browserslist "^4.21.4" + postcss-value-parser "^4.2.0" + +postcss-normalize-url@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-6.0.0.tgz#d0a31e962a16401fb7deb7754b397a323fb650b4" + integrity sha512-98mvh2QzIPbb02YDIrYvAg4OUzGH7s1ZgHlD3fIdTHLgPLRpv1ZTKJDnSAKr4Rt21ZQFzwhGMXxpXlfrUBKFHw== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-whitespace@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.0.tgz#accb961caa42e25ca4179b60855b79b1f7129d4d" + integrity sha512-7cfE1AyLiK0+ZBG6FmLziJzqQCpTQY+8XjMhMAz8WSBSCsCNNUKujgIgjCAmDT3cJ+3zjTXFkoD15ZPsckArVw== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-ordered-values@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-6.0.0.tgz#374704cdff25560d44061d17ba3c6308837a3218" + integrity sha512-K36XzUDpvfG/nWkjs6d1hRBydeIxGpKS2+n+ywlKPzx1nMYDYpoGbcjhj5AwVYJK1qV2/SDoDEnHzlPD6s3nMg== + dependencies: + cssnano-utils "^4.0.0" + postcss-value-parser "^4.2.0" + +postcss-reduce-initial@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz#7d16e83e60e27e2fa42f56ec0b426f1da332eca7" + integrity sha512-s2UOnidpVuXu6JiiI5U+fV2jamAw5YNA9Fdi/GRK0zLDLCfXmSGqQtzpUPtfN66RtCbb9fFHoyZdQaxOB3WxVA== + dependencies: + browserslist "^4.21.4" + caniuse-api "^3.0.0" + +postcss-reduce-transforms@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.0.tgz#28ff2601a6d9b96a2f039b3501526e1f4d584a46" + integrity sha512-FQ9f6xM1homnuy1wLe9lP1wujzxnwt1EwiigtWwuyf8FsqqXUDUp2Ulxf9A5yjlUOTdCJO6lonYjg1mgqIIi2w== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5: + version "6.0.13" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz#d05d8d76b1e8e173257ef9d60b706a8e5e99bf1b" + integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-svgo@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-6.0.0.tgz#7b18742d38d4505a0455bbe70d52b49f00eaf69d" + integrity sha512-r9zvj/wGAoAIodn84dR/kFqwhINp5YsJkLoujybWG59grR/IHx+uQ2Zo+IcOwM0jskfYX3R0mo+1Kip1VSNcvw== + dependencies: + postcss-value-parser "^4.2.0" + svgo "^3.0.2" + +postcss-unique-selectors@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-6.0.0.tgz#c94e9b0f7bffb1203894e42294b5a1b3fb34fbe1" + integrity sha512-EPQzpZNxOxP7777t73RQpZE5e9TrnCrkvp7AH7a0l89JmZiPnS82y216JowHXwpBCQitfyxrof9TK3rYbi7/Yw== + dependencies: + postcss-selector-parser "^6.0.5" + +postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + +postcss@^8.4.21, postcss@^8.4.24: + version "8.4.27" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.27.tgz#234d7e4b72e34ba5a92c29636734349e0d9c3057" + integrity sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +pretty-error@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-4.0.0.tgz#90a703f46dd7234adb46d0f84823e9d1cb8f10d6" + integrity sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw== + dependencies: + lodash "^4.17.20" + renderkid "^3.0.0" + +pretty-format@^29.0.0, pretty-format@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.6.2.tgz#3d5829261a8a4d89d8b9769064b29c50ed486a47" + integrity sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg== + dependencies: + "@jest/schemas" "^29.6.0" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +punycode@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +pure-rand@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.2.tgz#a9c2ddcae9b68d736a8163036f088a2781c8b306" + integrity sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ== + +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +range-parser@^1.2.1, range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" + integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + +readable-stream@^2.0.1: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.0.6: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +rechoir@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22" + integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ== + dependencies: + resolve "^1.20.0" + +regenerate-unicode-properties@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" + integrity sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.13.4: + version "0.13.11" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== + +regenerator-runtime@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45" + integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA== + +regenerator-transform@^0.15.2: + version "0.15.2" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz#5bbae58b522098ebdf09bca2f83838929001c7a4" + integrity sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg== + dependencies: + "@babel/runtime" "^7.8.4" + +regexpp@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +regexpu-core@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.2.tgz#11a2b06884f3527aec3e93dbbf4a3b958a95546b" + integrity sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ== + dependencies: + "@babel/regjsgen" "^0.8.0" + regenerate "^1.4.2" + regenerate-unicode-properties "^10.1.0" + regjsparser "^0.9.1" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.1.0" + +regjsparser@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.9.1.tgz#272d05aa10c7c1f67095b1ff0addae8442fc5709" + integrity sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ== + dependencies: + jsesc "~0.5.0" + +relateurl@^0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog== + +renderkid@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-3.0.0.tgz#5fd823e4d6951d37358ecc9a58b1f06836b6268a" + integrity sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg== + dependencies: + css-select "^4.1.3" + dom-converter "^0.2.0" + htmlparser2 "^6.1.0" + lodash "^4.17.21" + strip-ansi "^6.0.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve.exports@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" + integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== + +resolve@^1.12.0, resolve@^1.14.2, resolve@^1.20.0: + version "1.22.4" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.4.tgz#1dc40df46554cdaf8948a486a10f6ba1e2026c34" + integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +retry@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.1.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +schema-utils@^3.0.0, schema-utils@^3.1.1, schema-utils@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" + integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +schema-utils@^4.0.0, schema-utils@^4.0.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.2.0.tgz#70d7c93e153a273a805801882ebd3bff20d89c8b" + integrity sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.9.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.1.0" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg== + +selfsigned@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.1.1.tgz#18a7613d714c0cd3385c48af0075abf3f266af61" + integrity sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ== + dependencies: + node-forge "^1" + +semver@^5.6.0: + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + +semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.2.1, semver@^7.3.5, semver@^7.3.8, semver@^7.5.3: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + +send@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serialize-javascript@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c" + integrity sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w== + dependencies: + randombytes "^2.1.0" + +serve-index@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw== + dependencies: + accepts "~1.3.4" + batch "0.6.1" + debug "2.6.9" + escape-html "~1.0.3" + http-errors "~1.6.2" + mime-types "~2.1.17" + parseurl "~1.3.2" + +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shell-quote@^1.7.3: + version "1.8.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" + integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +sockjs@^0.3.24: + version "0.3.24" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce" + integrity sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ== + dependencies: + faye-websocket "^0.11.3" + uuid "^8.3.2" + websocket-driver "^0.7.4" + +source-map-js@^1.0.1, source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== + dependencies: + debug "^4.1.0" + detect-node "^2.0.4" + hpack.js "^2.1.6" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" + +spdy@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" + integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== + dependencies: + debug "^4.1.0" + handle-thing "^2.0.0" + http-deceiver "^1.2.7" + select-hose "^2.0.0" + spdy-transport "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +"statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +style-loader@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.3.tgz#bba8daac19930169c0c9c96706749a597ae3acff" + integrity sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw== + +stylehacks@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-6.0.0.tgz#9fdd7c217660dae0f62e14d51c89f6c01b3cb738" + integrity sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw== + dependencies: + browserslist "^4.21.4" + postcss-selector-parser "^6.0.4" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +svgo@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-3.0.2.tgz#5e99eeea42c68ee0dc46aa16da093838c262fe0a" + integrity sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ== + dependencies: + "@trysound/sax" "0.2.0" + commander "^7.2.0" + css-select "^5.1.0" + css-tree "^2.2.1" + csso "^5.0.5" + picocolors "^1.0.0" + +table@^6.0.9: + version "6.8.1" + resolved "https://registry.yarnpkg.com/table/-/table-6.8.1.tgz#ea2b71359fe03b017a5fbc296204471158080bdf" + integrity sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA== + dependencies: + ajv "^8.0.1" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + +tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +terser-webpack-plugin@^5.3.7, terser-webpack-plugin@^5.3.9: + version "5.3.9" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz#832536999c51b46d468067f9e37662a3b96adfe1" + integrity sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.17" + jest-worker "^27.4.5" + schema-utils "^3.1.1" + serialize-javascript "^6.0.1" + terser "^5.16.8" + +terser@^5.10.0, terser@^5.16.8: + version "5.19.2" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.19.2.tgz#bdb8017a9a4a8de4663a7983f45c506534f9234e" + integrity sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA== + dependencies: + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" + commander "^2.20.0" + source-map-support "~0.5.20" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +thunky@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" + integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^2.0.3: + version "2.6.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410" + integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typescript@^4.9.5: + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== + +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz#cb5fffdcd16a05124f5a4b0bf7c3770208acbbe0" + integrity sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" + integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +update-browserslist-db@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" + integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +url-loader@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-4.1.1.tgz#28505e905cae158cf07c92ca622d7f237e70a4e2" + integrity sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA== + dependencies: + loader-utils "^2.0.0" + mime-types "^2.1.27" + schema-utils "^3.0.0" + +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +utila@~0.4: + version "0.4.0" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" + integrity sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +v8-to-istanbul@^9.0.1: + version "9.1.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz#1b83ed4e397f58c85c266a570fc2558b5feb9265" + integrity sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +watchpack@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" + integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + +webpack-cli@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.4.tgz#c8e046ba7eaae4911d7e71e2b25b776fcc35759b" + integrity sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg== + dependencies: + "@discoveryjs/json-ext" "^0.5.0" + "@webpack-cli/configtest" "^2.1.1" + "@webpack-cli/info" "^2.0.2" + "@webpack-cli/serve" "^2.0.5" + colorette "^2.0.14" + commander "^10.0.1" + cross-spawn "^7.0.3" + envinfo "^7.7.3" + fastest-levenshtein "^1.0.12" + import-local "^3.0.2" + interpret "^3.1.1" + rechoir "^0.8.0" + webpack-merge "^5.7.3" + +webpack-dev-middleware@^5.3.1: + version "5.3.3" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz#efae67c2793908e7311f1d9b06f2a08dcc97e51f" + integrity sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA== + dependencies: + colorette "^2.0.10" + memfs "^3.4.3" + mime-types "^2.1.31" + range-parser "^1.2.1" + schema-utils "^4.0.0" + +webpack-dev-server@4.13.3: + version "4.13.3" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.13.3.tgz#9feb740b8b56b886260bae1360286818a221bae8" + integrity sha512-KqqzrzMRSRy5ePz10VhjyL27K2dxqwXQLP5rAKwRJBPUahe7Z2bBWzHw37jeb8GCPKxZRO79ZdQUAPesMh/Nug== + dependencies: + "@types/bonjour" "^3.5.9" + "@types/connect-history-api-fallback" "^1.3.5" + "@types/express" "^4.17.13" + "@types/serve-index" "^1.9.1" + "@types/serve-static" "^1.13.10" + "@types/sockjs" "^0.3.33" + "@types/ws" "^8.5.1" + ansi-html-community "^0.0.8" + bonjour-service "^1.0.11" + chokidar "^3.5.3" + colorette "^2.0.10" + compression "^1.7.4" + connect-history-api-fallback "^2.0.0" + default-gateway "^6.0.3" + express "^4.17.3" + graceful-fs "^4.2.6" + html-entities "^2.3.2" + http-proxy-middleware "^2.0.3" + ipaddr.js "^2.0.1" + launch-editor "^2.6.0" + open "^8.0.9" + p-retry "^4.5.0" + rimraf "^3.0.2" + schema-utils "^4.0.0" + selfsigned "^2.1.1" + serve-index "^1.9.1" + sockjs "^0.3.24" + spdy "^4.0.2" + webpack-dev-middleware "^5.3.1" + ws "^8.13.0" + +webpack-merge@^5.7.3: + version "5.9.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.9.0.tgz#dc160a1c4cf512ceca515cc231669e9ddb133826" + integrity sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg== + dependencies: + clone-deep "^4.0.1" + wildcard "^2.0.0" + +webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack@^5.88.2: + version "5.88.2" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.88.2.tgz#f62b4b842f1c6ff580f3fcb2ed4f0b579f4c210e" + integrity sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ== + dependencies: + "@types/eslint-scope" "^3.7.3" + "@types/estree" "^1.0.0" + "@webassemblyjs/ast" "^1.11.5" + "@webassemblyjs/wasm-edit" "^1.11.5" + "@webassemblyjs/wasm-parser" "^1.11.5" + acorn "^8.7.1" + acorn-import-assertions "^1.9.0" + browserslist "^4.14.5" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.15.0" + es-module-lexer "^1.2.1" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.9" + json-parse-even-better-errors "^2.3.1" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.2.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.3.7" + watchpack "^2.4.0" + webpack-sources "^3.2.3" + +websocket-driver@>=0.5.1, websocket-driver@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wildcard@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" + integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + +ws@^8.13.0: + version "8.13.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" + integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.3.1: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +yocto-queue@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251" + integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==